|
| 1 | +# This file is a part of Julia. License is MIT: https://julialang.org/license |
| 2 | + |
| 3 | +# clipboard copy and paste |
| 4 | + |
| 5 | +if Sys.isapple() |
| 6 | + function clipboard(x) |
| 7 | + open(pipeline(`pbcopy`, stderr=STDERR), "w") do io |
| 8 | + print(io, x) |
| 9 | + end |
| 10 | + end |
| 11 | + clipboard() = read(`pbpaste`, String) |
| 12 | + |
| 13 | +elseif Sys.islinux() || Sys.KERNEL === :FreeBSD |
| 14 | + _clipboardcmd = nothing |
| 15 | + const _clipboardcmds = Dict( |
| 16 | + :copy => Dict( |
| 17 | + :xsel => Sys.islinux() ? |
| 18 | + `xsel --nodetach --input --clipboard` : `xsel -c`, |
| 19 | + :xclip => `xclip -silent -in -selection clipboard`, |
| 20 | + ), |
| 21 | + :paste => Dict( |
| 22 | + :xsel => Sys.islinux() ? |
| 23 | + `xsel --nodetach --output --clipboard` : `xsel -p`, |
| 24 | + :xclip => `xclip -quiet -out -selection clipboard`, |
| 25 | + ) |
| 26 | + ) |
| 27 | + function clipboardcmd() |
| 28 | + global _clipboardcmd |
| 29 | + _clipboardcmd !== nothing && return _clipboardcmd |
| 30 | + for cmd in (:xclip, :xsel) |
| 31 | + success(pipeline(`which $cmd`, DevNull)) && return _clipboardcmd = cmd |
| 32 | + end |
| 33 | + pkgs = @static if Sys.islinux() |
| 34 | + "xsel or xclip" |
| 35 | + elseif Sys.KERNEL === :FreeBSD |
| 36 | + "x11/xsel or x11/xclip" |
| 37 | + end |
| 38 | + error("no clipboard command found, please install $pkgs") |
| 39 | + end |
| 40 | + function clipboard(x) |
| 41 | + c = clipboardcmd() |
| 42 | + cmd = get(_clipboardcmds[:copy], c, nothing) |
| 43 | + if cmd === nothing |
| 44 | + error("unexpected clipboard command: $c") |
| 45 | + end |
| 46 | + open(pipeline(cmd, stderr=STDERR), "w") do io |
| 47 | + print(io, x) |
| 48 | + end |
| 49 | + end |
| 50 | + function clipboard() |
| 51 | + c = clipboardcmd() |
| 52 | + cmd = get(_clipboardcmds[:paste], c, nothing) |
| 53 | + if cmd === nothing |
| 54 | + error("unexpected clipboard command: $c") |
| 55 | + end |
| 56 | + read(pipeline(cmd, stderr=STDERR), String) |
| 57 | + end |
| 58 | + |
| 59 | +elseif Sys.iswindows() |
| 60 | + # TODO: these functions leak memory and memory locks if they throw an error |
| 61 | + function clipboard(x::AbstractString) |
| 62 | + if containsnul(x) |
| 63 | + throw(ArgumentError("Windows clipboard strings cannot contain NUL character")) |
| 64 | + end |
| 65 | + systemerror(:OpenClipboard, 0==ccall((:OpenClipboard, "user32"), stdcall, Cint, (Ptr{Cvoid},), C_NULL)) |
| 66 | + systemerror(:EmptyClipboard, 0==ccall((:EmptyClipboard, "user32"), stdcall, Cint, ())) |
| 67 | + x_u16 = cwstring(x) |
| 68 | + # copy data to locked, allocated space |
| 69 | + p = ccall((:GlobalAlloc, "kernel32"), stdcall, Ptr{UInt16}, (UInt16, Int32), 2, sizeof(x_u16)) |
| 70 | + systemerror(:GlobalAlloc, p==C_NULL) |
| 71 | + plock = ccall((:GlobalLock, "kernel32"), stdcall, Ptr{UInt16}, (Ptr{UInt16},), p) |
| 72 | + systemerror(:GlobalLock, plock==C_NULL) |
| 73 | + ccall(:memcpy, Ptr{UInt16}, (Ptr{UInt16},Ptr{UInt16},Int), plock, x_u16, sizeof(x_u16)) |
| 74 | + systemerror(:GlobalUnlock, 0==ccall((:GlobalUnlock, "kernel32"), stdcall, Cint, (Ptr{Cvoid},), plock)) |
| 75 | + pdata = ccall((:SetClipboardData, "user32"), stdcall, Ptr{UInt16}, (UInt32, Ptr{UInt16}), 13, p) |
| 76 | + systemerror(:SetClipboardData, pdata!=p) |
| 77 | + ccall((:CloseClipboard, "user32"), stdcall, Cvoid, ()) |
| 78 | + end |
| 79 | + clipboard(x) = clipboard(sprint(print, x)::String) |
| 80 | + function clipboard() |
| 81 | + systemerror(:OpenClipboard, 0==ccall((:OpenClipboard, "user32"), stdcall, Cint, (Ptr{Cvoid},), C_NULL)) |
| 82 | + pdata = ccall((:GetClipboardData, "user32"), stdcall, Ptr{UInt16}, (UInt32,), 13) |
| 83 | + systemerror(:SetClipboardData, pdata==C_NULL) |
| 84 | + systemerror(:CloseClipboard, 0==ccall((:CloseClipboard, "user32"), stdcall, Cint, ())) |
| 85 | + plock = ccall((:GlobalLock, "kernel32"), stdcall, Ptr{UInt16}, (Ptr{UInt16},), pdata) |
| 86 | + systemerror(:GlobalLock, plock==C_NULL) |
| 87 | + # find NUL terminator (0x0000 16-bit code unit) |
| 88 | + len = 0 |
| 89 | + while unsafe_load(plock, len+1) != 0; len += 1; end |
| 90 | + # get Vector{UInt16}, transcode data to UTF-8, make a String of it |
| 91 | + s = transcode(String, unsafe_wrap(Array, plock, len)) |
| 92 | + systemerror(:GlobalUnlock, 0==ccall((:GlobalUnlock, "kernel32"), stdcall, Cint, (Ptr{UInt16},), plock)) |
| 93 | + return s |
| 94 | + end |
| 95 | + |
| 96 | +else |
| 97 | + clipboard(x="") = error("`clipboard` function not implemented for $(Sys.KERNEL)") |
| 98 | +end |
| 99 | + |
| 100 | + |
| 101 | +""" |
| 102 | + clipboard(x) |
| 103 | +
|
| 104 | +Send a printed form of `x` to the operating system clipboard ("copy"). |
| 105 | +""" |
| 106 | +clipboard(x) |
| 107 | + |
| 108 | +""" |
| 109 | + clipboard() -> AbstractString |
| 110 | +
|
| 111 | +Return a string with the contents of the operating system clipboard ("paste"). |
| 112 | +""" |
| 113 | +clipboard() |
0 commit comments