Keep remote clipboard paste fast and cover provider transports

This commit is contained in:
David Heinemeier Hansson committed 2026-09-13 17:46:10 +02:00
1 parent db5f3791c5
commit c095aa4ccc
3 files changed
+177 -19

No files matched your search

@@ -1,9 +1,8 @@
-- Clipboard for sessions whose yanks may need to reach another machine:
-- every copy is emitted as OSC 52 (inside tmux this becomes a tmux buffer,
-- rebroadcast to every attached client, local or SSH). Paste prefers the
-- local Wayland clipboard when one is available, so content copied in other
-- apps remains pasteable; without a display, paste is an OSC 52 query that
-- tmux (or the terminal) answers.
-- Copies reach the local Wayland clipboard and attached terminals. Reads use
-- Wayland or tmux's buffer, falling back to this Neovim's last copy. Never query
-- the terminal with OSC 52: support for writes does not imply permission to read,
-- and an unanswered query blocks ordinary paste for ten seconds. To insert new
-- text from the host when no readable clipboard exists, use terminal paste.
local M = {}
local function proc_lines(pid, file)
@@ -54,10 +53,15 @@ function M.setup()
and vim.fn.executable("wl-copy") == 1
and vim.fn.executable("wl-paste") == 1
local has_tmux = in_tmux and vim.fn.executable("tmux") == 1
local last_copy = {}
local function copy(register)
local emit = osc52.copy(register)
return function(lines)
return function(lines, regtype)
last_copy[register] = { vim.deepcopy(lines), regtype }
if has_wayland then
local cmd = { "wl-copy", "--sensitive", "--type", "text/plain" }
if register == "*" then
@@ -67,36 +71,60 @@ function M.setup()
end
if vim.g.omarchy_remote_clipboard_osc52 ~= false then
if has_tmux and register == "+" then
-- Let tmux emit OSC 52, avoiding its input parser's payload size limit.
vim.fn.system({ "tmux", "load-buffer", "-w", "-" }, lines)
if vim.v.shell_error == 0 then
return
end
end
emit(lines)
end
end
end
local function paste(register)
if not has_wayland then
return osc52.paste(register)
end
return function()
local cmd = { "wl-paste", "--no-newline" }
if register == "*" then
cmd[#cmd + 1] = "--primary"
local cmd
-- tmux's buffer is shared between Neovim instances in the session. Over
-- SSH, prefer it to the remote machine's unrelated graphical clipboard.
if has_tmux and register == "+" and (in_ssh or not has_wayland)
and vim.g.omarchy_remote_clipboard_osc52 ~= false then
cmd = { "tmux", "save-buffer", "-" }
elseif has_wayland then
cmd = { "wl-paste", "--no-newline" }
if register == "*" then
cmd[#cmd + 1] = "--primary"
end
end
local lines = vim.fn.systemlist(cmd, "", 1)
return vim.v.shell_error == 0 and lines or {}
if cmd then
local lines = vim.fn.systemlist(cmd, "", 1)
if vim.v.shell_error == 0 then
-- An empty clipboard is valid; only failed reads use the fallback.
if last_copy[register] and vim.deep_equal(lines, last_copy[register][1]) then
return vim.deepcopy(last_copy[register])
end
return lines
end
end
return vim.deepcopy(last_copy[register] or { {}, "v" })
end
end
-- LazyVim disables clipboard syncing over SSH; our provider supports it.
vim.opt.clipboard = "unnamedplus"
vim.g.clipboard = {
name = "OmarchyRemoteClipboard",
copy = { ["+"] = copy("+"), ["*"] = copy("*") },
paste = { ["+"] = paste("+"), ["*"] = paste("*") },
cache_enabled = 0,
}
-- LazyVim clears this over SSH. Users can opt out before setup or override
-- the option afterward in config/options.lua.
if vim.g.omarchy_remote_clipboard_sync ~= false then
vim.opt.clipboard:append("unnamedplus")
end
end
return M
+123
View File
@@ -0,0 +1,123 @@
local provider = assert(vim.env.TEST_PROVIDER)
local real_system, real_systemlist = vim.fn.system, vim.fn.systemlist
local real_executable, real_readfile = vim.fn.executable, vim.fn.readfile
local writes, reads, emitted, read_result, failed, write_failed
local function setup(env, options)
for _, key in ipairs({ "SSH_CONNECTION", "SSH_TTY", "TMUX", "HERDR_PANE_ID", "WAYLAND_DISPLAY" }) do
vim.env[key] = nil
end
for key, value in pairs(env) do vim.env[key] = value end
vim.g.clipboard = nil
vim.g.omarchy_remote_clipboard_sync = options and options.sync
vim.g.omarchy_remote_clipboard_osc52 = options and options.osc52
vim.opt.clipboard = options and options.clipboard or ""
writes, reads, emitted = {}, {}, {}
read_result, failed, write_failed = nil, false, false
vim.fn.readfile = function(path, ...)
if path:match("^/proc/") then return {} end
return real_readfile(path, ...)
end
vim.fn.executable = function(cmd)
if cmd == "tmux" or cmd == "wl-copy" or cmd == "wl-paste" then return 1 end
return real_executable(cmd)
end
vim.fn.system = function(cmd, lines)
writes[#writes + 1] = { cmd, vim.deepcopy(lines) }
real_system({ "sh", "-c", write_failed and "exit 1" or "exit 0" })
return ""
end
vim.fn.systemlist = function(cmd)
reads[#reads + 1] = cmd
real_system({ "sh", "-c", failed and "exit 1" or "exit 0" })
return vim.deepcopy(read_result or {})
end
vim.api.nvim_ui_send = function(data) emitted[#emitted + 1] = data end
-- A clipboard read must never reach Neovim's synchronous OSC 52 query.
require("vim.ui.clipboard.osc52").paste = function() error("OSC 52 read attempted") end
dofile(provider).setup()
vim.cmd("unlet! g:loaded_clipboard_provider")
vim.cmd("runtime autoload/provider/clipboard.vim")
end
local function equal(actual, expected)
assert(vim.deep_equal(actual, expected), vim.inspect(actual) .. " != " .. vim.inspect(expected))
end
local function put_yank()
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "probe" })
vim.cmd("normal! gg0yy")
-- Unnamed clipboard writes are deferred until the command loop returns.
vim.cmd("redraw")
local start = vim.uv.hrtime()
vim.cmd("normal! p")
assert((vim.uv.hrtime() - start) / 1e6 < 1000, "paste blocked")
equal(vim.api.nvim_buf_get_lines(0, 0, -1, false), { "probe", "probe" })
end
setup({})
assert(vim.g.clipboard == nil and vim.o.clipboard == "", "local config changed")
for _, env in ipairs({ { SSH_CONNECTION = "test" }, { SSH_TTY = "test" }, { HERDR_PANE_ID = "test" } }) do
setup(env)
assert(vim.o.clipboard == "unnamedplus")
put_yank()
assert(#emitted > 0 and emitted[1]:find("\27]52;c;", 1, true))
assert(#reads == 0)
equal(vim.g.clipboard.paste["*"](), { {}, "v" })
for _, regtype in ipairs({ "v", "V", "\22" .. "3" }) do
vim.g.clipboard.copy["*"]({ "abc" }, regtype)
equal(vim.g.clipboard.paste["*"](), { { "abc" }, regtype })
end
end
print("ok - local, SSH, SSH_TTY and Herdr setup; real yy/p; no OSC 52 reads; register types")
setup({ SSH_CONNECTION = "test" }, { sync = false, clipboard = "unnamed" })
assert(vim.o.clipboard == "unnamed")
setup({ SSH_CONNECTION = "test" }, { clipboard = "unnamed" })
assert(vim.o.clipboard:find("unnamedplus", 1, true) and vim.o.clipboard:find("unnamed,", 1, true))
vim.opt.clipboard = ""
assert(vim.o.clipboard == "", "user override must win")
setup({ SSH_CONNECTION = "test" }, { osc52 = false })
put_yank()
assert(#emitted == 0)
print("ok - sync and OSC 52 opt-outs; existing clipboard flags and subsequent overrides")
setup({ SSH_CONNECTION = "test", TMUX = "test" })
local large = { string.rep("x", 1024 * 1024 + 1) }
vim.g.clipboard.copy["+"](large, "v")
equal(writes[1], { { "tmux", "load-buffer", "-w", "-" }, large })
assert(#emitted == 0)
read_result = { "external buffer" }
equal(vim.g.clipboard.paste["+"](), read_result)
equal(reads[1], { "tmux", "save-buffer", "-" })
failed = true
equal(vim.g.clipboard.paste["+"](), { large, "v" })
write_failed = true
vim.g.clipboard.copy["+"]({ "retry" }, "v")
assert(#emitted == 1)
print("ok - tmux large yanks, shared buffer reads, failed read and write fallbacks")
setup({ TMUX = "test" }, { osc52 = false })
put_yank()
assert(#writes == 0 and #reads == 0 and #emitted == 0)
setup({ TMUX = "test" })
failed = true
put_yank()
print("ok - tmux-only yanks and paste; opt-out does not read a stale tmux buffer")
setup({ HERDR_PANE_ID = "test", WAYLAND_DISPLAY = "test" })
vim.g.clipboard.copy["*"]({ "primary" }, "v")
equal(writes[1][1], { "wl-copy", "--sensitive", "--type", "text/plain", "--primary" })
read_result = { "from another app" }
equal(vim.g.clipboard.paste["*"](), read_result)
equal(reads[1], { "wl-paste", "--no-newline", "--primary" })
read_result = {}
equal(vim.g.clipboard.paste["*"](), {})
failed = true
equal(vim.g.clipboard.paste["*"](), { { "primary" }, "v" })
setup({ SSH_CONNECTION = "test", WAYLAND_DISPLAY = "test", TMUX = "test" })
vim.g.clipboard.copy["+"]({ "both" }, "v")
assert(#writes == 2)
read_result = { "both" }
equal(vim.g.clipboard.paste["+"](), { { "both" }, "v" })
equal(reads[1], { "tmux", "save-buffer", "-" })
print("ok - Wayland primary, external, empty and failed reads; SSH prefers tmux")
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
set -euo pipefail
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
export TEST_PROVIDER="$root/pkgbuilds/omarchy-nvim/lua/config/remote_clipboard.lua"
export NVIM_LOG_FILE=$(mktemp)
trap 'rm -f "$NVIM_LOG_FILE"' EXIT
nvim --clean -n --headless -i NONE -l "$root/tests/neovim-remote-clipboard.lua"