TL;DR
I spend a majority of my development in terminal: from my Mac which acts as a thin development client, I stay over
ssh
intotmux
on my main Linux workstation and numerous other boxes, with my main IDE a.k.a.neovim
running remotely. Sometimes, from thattmux
I connect over anotherssh
and firetmux
on a box over two hops from my cosy Mac.This worked smoothly with one common caveat: I need to be able, from time to time, to select-and-copy into my local clipboard (either to copy into some GUI for demos, or to copy into an
ssh
-over-ssh
connected VM) – keeping my local clipboard an ulimate source of copy-paste storage.This short post was born as a consequence of “shell user’s block” – reading numerous posts on the topic which make things look quite pessimistic in terms of the complexity, thus dicouraging me to give it a try. It all turned out to be quite trivial. So here, I aggregate a working set of steps – and keep all the credits with the developers of the plugins mentioned in the course of the story.
Outline
(UPD 2023-12)
As of
neovim 10.0
, per the claim of the plugin creators, the below plugins are not needed anymore. Though, quick skimming over the web seems to report that the10.0
is still sluggish/unstable.Another note is that the usage of the
vim-OSCYank
, (notnvim-osc52
) seemed to produce issues on MacOS for me, where yanking whole line (yy
) with subsequent pasting it resulted in pasting it into the cursor’s line, not on the new line. Swiching tonvim-osc52
fixed the problem, below I post the Lua config as well.
Out of scope
As mentioned, we’ll be setting up the ability to copy things downstream, i.e. over one or several tmux
/ssh
hops
into the local clipboard. It stays out of scope to operate the remote clipboards, primarily because this has never
popped up in my (quite intense) development activity – it has always been enough to have things in my local clipboard
and paste them in INSERT
mode into remote, if needed.
OSC52 and OSCYanc
I was a happy user of a terminal that supports OSC52, an ANSI Operating System Command set of escape sequences that, provided the support of the receiving terminal emulator, allow to copy text into the local buffer.
Another bit, vim-OSCYank
(and its Lua rewrite by the same author, nvim-osc52
) is a wonderful plugin
that trivializes sending the OSC52-enriched messages to the local terminal emulator.
Recipe
Set up the vim-oscyank
In your init.lua
or equivalent, you’d need to add the vim-oscyank
plugin see here, and set it up along
the following lines:
{
"ojroques/vim-oscyank",
config = function()
-- Should be accompanied by a setting clipboard in tmux.conf, also see
-- https://github.com/ojroques/vim-oscyank#the-plugin-does-not-work-with-tmux
vim.g.oscyank_term = "default"
vim.g.oscyank_max_length = 0 -- unlimited
-- Below autocmd is for copying to OSC52 for any yank operation,
-- see https://github.com/ojroques/vim-oscyank#copying-from-a-register
vim.api.nvim_create_autocmd("TextYankPost", {
pattern = "*",
callback = function()
if vim.v.event.operator == "y" and vim.v.event.regname == "" then
vim.cmd('OSCYankRegister "')
end
end,
})
end,
}
(added 2023-12, see UPD) For the Lua version of the plugin (see UPD above), the config would be the following
{
"ojroques/nvim-osc52",
config = function()
require("osc52").setup {
max_length = 0, -- Maximum length of selection (0 for no limit)
silent = false, -- Disable message on successful copy
trim = false, -- Trim surrounding whitespaces before copy
}
local function copy()
if ((vim.v.event.operator == "y" or vim.v.event.operator == "d")
and vim.v.event.regname == "") then
require("osc52").copy_register("")
end
end
vim.api.nvim_create_autocmd("TextYankPost", { callback = copy })
end,
}
Set up the tmux
To enable interoperation of tmux
with the clipboard, set in your .tmux.conf
:
# Allow clipboard with OSC-52 work, see https://github.com/tmux/tmux/wiki/Clipboard
set -s set-clipboard on
Additionally, I prefer to set y
in tmux
scroll mode for copying:
# Use vim keybindings in copy mode
setw -g mode-keys vi
unbind -T copy-mode-vi MouseDragEnd1Pane
# Make `y` copy the selected text, not exiting the copy mode. For copy-and-exit
# use ordinary `Enter`
bind -T copy-mode-vi y send-keys -X copy-pipe # Only copy, no cancel
Bonuses, mouse selection in neovim
and tmux
Don’t forget to set the mouse selection in init.lua
vim.opt.mouse = "a"
It is annoying that when selecting things with mouse in tmux
scroll mode, this selection sticks
until you select something else – common UX is to drop selection on a single click anywhere:
# Clear selection on single click
bind -T copy-mode-vi MouseDown1Pane send-keys -X clear-selection \; select-pane
Want to discuss anything? Comments are welcome via e-mail alexey@gronskiy.com, Telegram @agronskiy or any other social media.