aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Anders <8965202+gpanders@users.noreply.github.com>2023-11-07 08:47:27 -0600
committerGitHub <noreply@github.com>2023-11-07 08:47:27 -0600
commitcd31a72f9b22741c6ece1c47a91d990e2df218fa (patch)
tree3ace882e09a99a03b3eb91f74de9917c84c6f4ba
parent3ca967387c49c754561c3b11a574797504d40f38 (diff)
parenta14c7809181c11f859dd8560dd65d366411a08bc (diff)
downloadrneovim-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.txt3
-rw-r--r--runtime/doc/provider.txt30
-rw-r--r--runtime/lua/vim/clipboard/osc52.lua38
-rw-r--r--src/nvim/tui/input.c10
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.