feat(clipboard): add OSC 52 clipboard support

This is opt-in as not all terminal emulators support OSC 52, so it is up
to the user to enable it explicitly.
This commit is contained in:
Gregory Anders 2023-10-30 13:23:55 -05:00
parent 3ca967387c
commit 748bc4d22d
3 changed files with 69 additions and 0 deletions

View File

@ -208,6 +208,9 @@ The following new APIs and features were added.
• The |TermResponse| autocommand event can be used with |v:termresponse| to
read escape sequence responses from the terminal.
• A clipboard provider which uses OSC 52 to copy the selection to the system
clipboard is now bundled by default. |clipboard-osc52|
==============================================================================
CHANGED FEATURES *news-changed*

View File

@ -253,7 +253,35 @@ For Windows WSL, try this g:clipboard definition:
\ },
\ 'cache_enabled': 0,
\ }
<
*clipboard-osc52*
Nvim bundles a clipboard provider that allows copying to the system clipboard
using OSC 52. OSC 52 is an Operating System Command control sequence that
writes the copied text to the terminal emulator. If the terminal emulator
supports OSC 52 then it will write the copied text into the system clipboard.
This is most useful when using Nvim remotely (e.g. via ssh) as Nvim does not
have direct access to the system clipboard in that case.
Because not all terminal emulators support OSC 52, this provider must be opted
into explicitly by setting the following |g:clipboard| definition: >lua
vim.g.clipboard = {
name = 'OSC 52',
copy = {
['+'] = require('vim.clipboard.osc52').copy,
['*'] = require('vim.clipboard.osc52').copy,
},
paste = {
['+'] = require('vim.clipboard.osc52').paste,
['*'] = require('vim.clipboard.osc52').paste,
},
}
<
Note that not all terminal emulators support reading from the system clipboard
(and even for those that do, users should be aware of the security
implications), so using OSC 52 for pasting may not be possible.
<
==============================================================================
Paste *provider-paste* *paste*

View File

@ -0,0 +1,38 @@
local M = {}
function M.copy(lines)
local s = table.concat(lines, '\n')
io.stdout:write(string.format('\x1b]52;;%s\x1b\\', vim.base64.encode(s)))
end
function M.paste()
local contents = nil
local id = vim.api.nvim_create_autocmd('TermResponse', {
callback = function(args)
local resp = args.data ---@type string
local encoded = resp:match('\x1b%]52;%w?;([A-Za-z0-9+/=]*)')
if encoded then
contents = vim.base64.decode(encoded)
return true
end
end,
})
io.stdout:write('\x1b]52;;?\x1b\\')
vim.wait(1000, function()
return contents ~= nil
end)
-- Delete the autocommand if it didn't already delete itself
pcall(vim.api.nvim_del_autocmd, id)
if contents then
return vim.split(contents, '\n')
end
vim.notify('Timed out waiting for a clipboard response from the terminal', vim.log.levels.WARN)
return 0
end
return M