diff options
author | Gregory Anders <8965202+gpanders@users.noreply.github.com> | 2023-11-07 08:47:27 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-07 08:47:27 -0600 |
commit | cd31a72f9b22741c6ece1c47a91d990e2df218fa (patch) | |
tree | 3ace882e09a99a03b3eb91f74de9917c84c6f4ba | |
parent | 3ca967387c49c754561c3b11a574797504d40f38 (diff) | |
parent | a14c7809181c11f859dd8560dd65d366411a08bc (diff) | |
download | rneovim-cd31a72f9b22741c6ece1c47a91d990e2df218fa.tar.gz rneovim-cd31a72f9b22741c6ece1c47a91d990e2df218fa.tar.bz2 rneovim-cd31a72f9b22741c6ece1c47a91d990e2df218fa.zip |
Merge pull request #25872 from gpanders/osc52
feat(clipboard): add OSC 52 clipboard support
-rw-r--r-- | runtime/doc/news.txt | 3 | ||||
-rw-r--r-- | runtime/doc/provider.txt | 30 | ||||
-rw-r--r-- | runtime/lua/vim/clipboard/osc52.lua | 38 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 10 |
4 files changed, 76 insertions, 5 deletions
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index fa77e8d086..985adb5b0d 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -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* diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt index 9e70ff8945..1b49ee3a3d 100644 --- a/runtime/doc/provider.txt +++ b/runtime/doc/provider.txt @@ -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* diff --git a/runtime/lua/vim/clipboard/osc52.lua b/runtime/lua/vim/clipboard/osc52.lua new file mode 100644 index 0000000000..0e8f9d378f --- /dev/null +++ b/runtime/lua/vim/clipboard/osc52.lua @@ -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 diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 1f659264c5..4ebf9177de 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -11,7 +11,6 @@ #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/charset.h" -#include "nvim/eval.h" #include "nvim/event/defs.h" #include "nvim/log.h" #include "nvim/macros.h" @@ -31,6 +30,7 @@ #include "nvim/event/rstream.h" #include "nvim/msgpack_rpc/channel.h" +#define READ_STREAM_SIZE 0xfff #define KEY_BUFFER_SIZE 0xfff static const struct kitty_key_map_entry { @@ -153,7 +153,9 @@ void tinput_init(TermInput *input, Loop *loop) termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS); // setup input handle - rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff); + rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE); + termkey_set_buffer_size(input->tk, rbuffer_capacity(input->read_stream.buffer)); + // initialize a timer handle for handling ESC with libtermkey time_watcher_init(loop, &input->timer_handle, input); } @@ -758,9 +760,9 @@ static void handle_raw_buffer(TermInput *input, bool force) RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) { size_t consumed = termkey_push_bytes(input->tk, ptr, MIN(count, len)); // termkey_push_bytes can return (size_t)-1, so it is possible that - // `consumed > input->read_stream.buffer->size`, but since tk_getkeys is + // `consumed > rbuffer_size(input->read_stream.buffer)`, but since tk_getkeys is // called soon, it shouldn't happen. - assert(consumed <= input->read_stream.buffer->size); + assert(consumed <= rbuffer_size(input->read_stream.buffer)); rbuffer_consumed(input->read_stream.buffer, consumed); // Process the keys now: there is no guarantee `count` will // fit into libtermkey's input buffer. |