Pasting from clipboard to vi-enabled zsh or bash shell

17,151

Solution 1

Zsh doesn't support anything but internal registers, and bash doesn't support register at all as far as I know. By and large, shells support vi commands, not vim commands.

In zsh, here's a proof-of-concept for accessing the X selection from command mode. For real use you'd want to elaborate on these techniques. I use the xsel program, you can use xclip instead; see How to copy from one vim instance to another using registers. You'll find the features I used in the zle manual.

vi-append-x-selection () { RBUFFER=$(xsel -o -p </dev/null)$RBUFFER; }
zle -N vi-append-x-selection
bindkey -a '^X' vi-append-x-selection
vi-yank-x-selection () { print -rn -- $CUTBUFFER | xsel -i -p; }
zle -N vi-yank-x-selection
bindkey -a '^Y' vi-yank-x-selection

The function vi-append-x-selection inserts the current X selection after the cursor (similar to p or P). The function vi-yank-x-selection copies the last killed or yanked text to the X selection. zle -N declares the functions as zle widgets (i.e. edition commands). bindkey -a sets bindings for vi command mode.

Solution 2

Here is a solution for zsh (vi mode) that wraps the original widgets so the clipboard always is synchronized

Replace xclip with your preferred clipboard tool.

function x11-clip-wrap-widgets() {
    # NB: Assume we are the first wrapper and that we only wrap native widgets
    # See zsh-autosuggestions.zsh for a more generic and more robust wrapper
    local copy_or_paste=$1
    shift

    for widget in $@; do
        # Ugh, zsh doesn't have closures
        if [[ $copy_or_paste == "copy" ]]; then
            eval "
            function _x11-clip-wrapped-$widget() {
                zle .$widget
                xclip -in -selection clipboard <<<\$CUTBUFFER
            }
            "
        else
            eval "
            function _x11-clip-wrapped-$widget() {
                CUTBUFFER=\$(xclip -out -selection clipboard)
                zle .$widget
            }
            "
        fi

        zle -N $widget _x11-clip-wrapped-$widget
    done
}


local copy_widgets=(
    vi-yank vi-yank-eol vi-delete vi-backward-kill-word vi-change-whole-line
)
local paste_widgets=(
    vi-put-{before,after}
)

# NB: can atm. only wrap native widgets
x11-clip-wrap-widgets copy $copy_widgets
x11-clip-wrap-widgets paste  $paste_widgets

Solution 3

Selection and clipboard are different things under X Window, and IMHO "desktop environments" tend to make the issue even more murky than it was.

Does shift-insert work for you? On bare X applications, it is bound to pasting the selection when such a binding is made.

Solution 4

There's a ZSH plugin I'd recommend: https://github.com/kutsan/zsh-system-clipboard . To install it, run:

git clone https://github.com/kutsan/zsh-system-clipboard ~/.zsh/plugins/zsh-system-clipboard

And then source the file in your .zshrc:

source "$HOME/.zsh/plugins/zsh-system-clipboard/zsh-system-clipboard.zsh"

The plugin supports using Tmux' buffers to locate where the clipboard is saved, and you can even configure alternative keybindings for the functions that cut / paste / copy.

One slight detail the plugin has taken care of, which the other answers suggested don't, is differentiating between system clipboard contents with and without new lines (see PR). This small checks of the clipboard input, should ensure the experience of pasting any type of content is identical to that of Vim/Neovim.

Solution 5

This solution works if you have installed oh-my-zsh and enabled the vi-mode plugin.

Gilles' xsel and zle based solution didn't work for me. However, since I have configured vim to use my system clipboard by default (set clipboard=unnamedplus in ~/.vimrc), I simply type v in terminal normal mode to open the current command in vim and then I can copy it to the X-clipboard with any of the vim yank commands.

Share:
17,151

Related videos on Youtube

Dalker
Author by

Dalker

Updated on September 18, 2022

Comments

  • Dalker
    Dalker over 1 year

    I'd like to be able to paste from the system clipboard (or text selection) into my "vi-like" shell prompt using the keyboard. I normally use zsh and sometimes bash. In both cases, I have the shell set up with vi-like behaviour (bindkey -v / set -o vi).

    In vim, the behaviour I'm looking for is available with the key sequence "+p. This particular key sequence doesn't work as expected in a vi-enabled shell prompt, though. Is there any way to either enable this or a similar behaviour, using keyboard only, while remaining with vi-like keybindings in a zsh or bash shell prompt?

    -- edit --

    Usage case: I often navigate between Firefox with the Pentadactyl addon, a terminal emulator and vim itself - using the Xmonad window manager with custom keys to move around. All three programs have vi-like keybindings, which is very efficient (for "finger memory") so it would be ideal communicate text between them using vim syntax (or a very similar syntax) only.

  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 12 years
    Selection and clipboard being different is not really relevant here, a solution that works with one would be easy to adapt to the other. Desktop environments don't change a thing; their spread has accompanied a shift in the balance of power away from selection and towards the clipboard.
  • Dalker
    Dalker over 12 years
    shift-insert does work in my environment, and it's definitely good to know, for use when in a different system. I'm looking however for something closer to actual vim keybindings for yank and/or paste between terminals, vim itself and other programs
  • Rotareti
    Rotareti over 6 years
    This works like a charm in xterm-termite.
  • Doron Behar
    Doron Behar over 5 years
    How is this related to ZSH? Are you talking about the embedded :term available in the new versions of Neovim and Vim?
  • joelostblom
    joelostblom over 5 years
    @DoronBehar If you have vi-mode enabled in zsh, you can type v in normal mode to edit the currently typed command inside vim instead of at the terminal prompt.
  • joelostblom
    joelostblom over 5 years
    @DoronBehar I am not talking about :term. However, I did discover that the functionality I am referring to is actually provided by oh-my-zsh. I have updated the answer accordingly.
  • Eric Duminil
    Eric Duminil over 3 years
    I added it as a oh-my-zsh plugin, and it worked directly. Excellent, thanks!
  • Admin
    Admin almost 2 years
    Many thanks for your answer @Gilles 'SO- stop being evil'. I tried to implement your answer without success. I posted a question with what I tried so far: unix.stackexchange.com/questions/703946/… . Do you have any idea about what am I doing wrong?
  • Admin
    Admin almost 2 years
    Seems to work great and also with tmux!