-
Notifications
You must be signed in to change notification settings - Fork 1
/
clipboard.lua
199 lines (169 loc) · 6.39 KB
/
clipboard.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
--[[
A simple script that provides some extremely low-level clipboard commands for users and other script writers.
Available at: https://github.com/CogentRedTester/mpv-clipboard
`script-message set-clipboard <text>`
saves the given string in the clipboard
`script-message get-clipboard <script-message>`
sends the contents of the clipboard to the given script-message
`script-message clipboard-command <command> <arg1> <arg2> ...`
Runs the given command substituting %clip% for the contents of the clipboard.
`%%` will be escaped into a single `%` character.
]]
local mp = require 'mp'
local msg = require 'mp.msg'
-- this code was taken from mpv's console.lua:
-- https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua
local function detect_platform()
local o = {}
-- Kind of a dumb way of detecting the platform but whatever
if mp.get_property_native('options/vo-mmcss-profile', o) ~= o then
return 'windows'
elseif mp.get_property_native('options/macos-force-dedicated-gpu', o) ~= o then
return 'macos'
elseif os.getenv('WAYLAND_DISPLAY') then
return 'wayland'
end
return 'x11'
end
local platform = detect_platform()
-- this is based on mpv-copyTime:
-- https://github.com/Arieleg/mpv-copyTime/blob/master/copyTime.lua
local function get_command()
if platform == 'x11' then return 'xclip -silent -selection clipboard -in' end
if platform == 'wayland' then return 'wl-copy' end
if platform == 'macos' then return 'pbcopy' end
end
-- an error handler to pass to xpcall
local function error_handler(err)
msg.warn(debug.traceback("", 2))
msg.error(err)
end
--resumes a coroutine and prints an error if it was not sucessful
local function co_resume_err(...)
local success, err = coroutine.resume(...)
if not success then
msg.warn(debug.traceback( (select(1, ...)) ))
msg.error(err)
end
return success
end
-- run the given function in a coroutine
local function co_run(fn, ...)
local co = coroutine.create(fn)
co_resume_err(co, ...)
end
-- escapes a string so that it can be inserted into powershell as a string literal
local function escape_powershell(str)
return '"'..string.gsub(str, '[$"`]', '`%1')..'"'
end
-- runs the given command.
-- if run in a coroutine then yield, otherwise block
local function subprocess(args)
local cmd = {
name = 'subprocess',
args = args,
playback_only = false,
capture_stdout = true
}
local success, res, err
local co, main = coroutine.running()
if main or not co then
res, err = mp.command_native(cmd)
success = res
else
mp.command_native_async(cmd, function(...) return co_resume_err(co, ...) end)
success, res, err = coroutine.yield()
end
-- something pretty drastic has to happen for this to error
if not success then error(err) end
res.error = res.error_string ~= '' and res.error_string or nil
return res
end
-- Returns a string of UTF-8 text from the clipboard
local function get_clipboard()
if platform == 'x11' then
local res = subprocess({ 'xclip', '-selection', 'clipboard', '-out' })
if not res.error then
return res.stdout
end
elseif platform == 'wayland' then
local res = subprocess({ 'wl-paste', '-n' })
if not res.error then
return res.stdout
end
elseif platform == 'windows' then
local res = subprocess({ 'powershell', '-NoProfile', '-Command', [[& {
Trap {
Write-Error -ErrorRecord $_
Exit 1
}
$clip = ""
if (Get-Command "Get-Clipboard" -errorAction SilentlyContinue) {
$clip = Get-Clipboard -Raw -Format Text -TextFormatType UnicodeText
} else {
Add-Type -AssemblyName PresentationCore
$clip = [Windows.Clipboard]::GetText()
}
$clip = $clip -Replace "`r",""
$u8clip = [System.Text.Encoding]::UTF8.GetBytes($clip)
[Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)
}]]
})
if not res.error then
return res.stdout
end
elseif platform == 'macos' then
local res = subprocess({ 'pbpaste' })
if not res.error then
return res.stdout
end
end
return ''
end
local function substitute(str, clip)
return string.gsub(str, '%b%%', function(text)
if text == '%clip%' then return clip end
if text == '%%' then return '%' end
end)
end
-- sets the contents of the clipboard to the given string
local function set_clipboard(text)
msg.verbose('setting clipboard text:', text)
if platform == 'windows' then
mp.commandv('run', 'powershell', '-NoProfile', '-command', 'set-clipboard', escape_powershell(text))
-- this is based on mpv-copyTime:
-- https://github.com/Arieleg/mpv-copyTime/blob/master/copyTime.lua
else
local pipe = io.popen(get_command(), 'w')
if not pipe then return msg.error('could not open unix pipe') end
pipe:write(text)
pipe:close()
end
end
--runs the given mpv command, substituting %clip% for the contents of the clipboard
local function clipboard_command(...)
msg.verbose('received clipboard command:', ...)
local args = {'osd-auto', ...}
local function command()
local clip = get_clipboard()
for i, str in ipairs(args) do
args[i] = substitute(str, clip)
end
mp.command_native(args)
end
-- if the first command prefix is sync then run synchronously, otherwise run
-- in a corooutine which allows the get_clipboard command to yield.
if select(1, ...) == 'sync' then xpcall(command, error_handler)
else co_run(command) end
end
-- sends the contents of the clipboard to any script that requests it
-- sends the response to the given response string
local function clipboard_request(response)
msg.verbose('received clipboard request - sending response to:', response)
co_run(function()
mp.commandv('script-message', response, get_clipboard())
end)
end
mp.register_script_message('set-clipboard', set_clipboard)
mp.register_script_message('get-clipboard', clipboard_request)
mp.register_script_message('clipboard-command', clipboard_command)