Search code examples
copy-pastetmux

How to emulate Emacs-like registers in Tmux?


I've long been using Emacs registers and they are a blessing in many sophisticated editing scenarios (e.g. editing multiple inter-related configuration files, using multiple code snippets, juggling paragraphs and expressions around, etc.). Their versatility is virtually limitless. I've also had a glimpse at Vim registers and for most uses they are largely equivalent. I've encountered some use scenarios when I wished Tmux had a similar feature. The question is: can this be used in Tmux and how to do it?


Solution

  • At first I said to myself: I'll just go and have a look at the Tmux source code. I'll learn how it handles copy/paste and replicate the behavior for some number of predefined registers, say 26 for each letter of the Latin alphabet. So I did that and, to my surprise, discovered that the functionality is already there, though not very well-advertised.

    The concept is called buffers there and affords a simple interface of set-buffer, delete-buffer and paste-buffer. So I thought I'd create two bindings in my .tmux.conf - one to replace a user-selected buffer with the selected text (by doing delete-buffer first and then set-buffer) and another to paste from a user-selected buffer. This almost did the trick, save for the fact that for some reason delete-buffer did not handle non-existent buffers gracefully. My then-idea was to initialize 26 buffers under corresponding letters and be done. Today I've tried my approach without the buffers initialized and it still worked. Perhaps newer versions of Tmux handle this better. Anyway, below I'm pasting the relevant configuration snippet:

    # Initialize alphabetic registers to avoid the problem with 'delete-buffer'
    # This might *not* be necessary in newer versions of Tmux
    run "tmux set-buffer -b a \"$(echo ' ')\""
    run "tmux set-buffer -b b \"$(echo ' ')\""
    run "tmux set-buffer -b c \"$(echo ' ')\""
    run "tmux set-buffer -b d \"$(echo ' ')\""
    run "tmux set-buffer -b e \"$(echo ' ')\""
    run "tmux set-buffer -b f \"$(echo ' ')\""
    run "tmux set-buffer -b g \"$(echo ' ')\""
    run "tmux set-buffer -b h \"$(echo ' ')\""
    run "tmux set-buffer -b i \"$(echo ' ')\""
    run "tmux set-buffer -b j \"$(echo ' ')\""
    run "tmux set-buffer -b k \"$(echo ' ')\""
    run "tmux set-buffer -b l \"$(echo ' ')\""
    run "tmux set-buffer -b m \"$(echo ' ')\""
    run "tmux set-buffer -b n \"$(echo ' ')\""
    run "tmux set-buffer -b o \"$(echo ' ')\""
    run "tmux set-buffer -b p \"$(echo ' ')\""
    run "tmux set-buffer -b q \"$(echo ' ')\""
    run "tmux set-buffer -b r \"$(echo ' ')\""
    run "tmux set-buffer -b s \"$(echo ' ')\""
    run "tmux set-buffer -b t \"$(echo ' ')\""
    run "tmux set-buffer -b u \"$(echo ' ')\""
    run "tmux set-buffer -b v \"$(echo ' ')\""
    run "tmux set-buffer -b w \"$(echo ' ')\""
    run "tmux set-buffer -b x \"$(echo ' ')\""
    run "tmux set-buffer -b y \"$(echo ' ')\""
    run "tmux set-buffer -b z \"$(echo ' ')\""
    
    # Copy to user-selected register
    bind -T copy-mode r command-prompt -1 -p '(register)' 'delete-buffer -b %1 ; send -X copy-pipe "tmux set-buffer -n %1"'
    
    # Paste from user-selected register
    bind -T prefix C-] command-prompt -1 -p '(register)' 'paste-buffer -b %1'
    

    The way to use this setup is as follows:

    • to put text in a register you mark it in copy-mode, hit r and answer the prompt for register name
    • to paste hit C-b C-] and answer the prompt - buffer content will get pasted at point