I have noticed that zsh has a lot of things I see in emacs. I can make a selection with ctrl+space and selecting a region. I can make copies just like in emacs while I stay inside zsh. In emacs I'm able to use my system clipboard (previously with some additional configuration needed but this works out of the box now in emacs). In zsh I can't seem to paste from my clipboard using C-y and copying from zsh to my system cliipboard has the same issue. Is there a way around this?
4 Answers
Zsh's has a built-in clipboard that doesn't communicate with other applications. Since it's very scriptable, you can make it communicate with a few lines in your ~/.zshrc
. You'll need xclip or xsel. See Pasting from clipboard to vi-enabled zsh or bash shell for a proof-of-concept in vi mode. Here's the corresponding code for emacs mode (you'll probably want to do something similar to other kill-*
widgets).
x-copy-region-as-kill () {
zle copy-region-as-kill
print -rn $CUTBUFFER | xsel -i -b
}
zle -N x-copy-region-as-kill
x-kill-region () {
zle kill-region
print -rn $CUTBUFFER | xsel -i -b
}
zle -N x-kill-region
x-yank () {
CUTBUFFER=$(xsel -o -b </dev/null)
zle yank
}
zle -N x-yank
bindkey -e '\ew' x-copy-region-as-kill
bindkey -e '^W' x-kill-region
bindkey -e '^Y' x-yank
This uses the X11 clipboard (typically accessed with Ctrl+C/Ctrl+V); remove the -b
option to use the X11 primary selection instead (automatic copy on select, and paste with the middle mouse button).
-
If you use vi mode, simply replace
kill-region
withvi-delete
andyank
withvi-put-after
etc. Similarly wrapvi-yank
, and others. (I haven't found a way to do it more centrally) Commented Sep 5, 2017 at 15:19 -
-
@alper
xsel -o
corresponds topbpaste
andxsel -i
corresponds topbcopy
. There's no equivalent to-b
since macOS doesn't have multiple selections. Commented Jul 20, 2020 at 12:09 -
I tried
ctrl-k
seems like it does not copy the cutted line , is it a normal behavior?– alperCommented Jul 20, 2020 at 12:17 -
1@alper It one of the other
kill-*
widgets for which you need to write similar code. Commented Jul 20, 2020 at 12:18
I had been wanting to integrate Zsh's cut buffer with the X clipboard. I tried the aforementioned http://stchaz.free.fr/mouse.zsh but I found I disliked having all my Zsh operations populate the clipboard. For instance, sometimes I would copy something in a browser, and then go to a shell and edit the command line and then paste. But often editing the command line - deleting a word, for instance - modifies the Zsh cut buffer. For better or worse, X just has a clipboard, not a kill ring, so when a Zsh editing operation overwrites the clipboard, the thing I wanted to paste is lost - I can't yank-pop it (C-y M-y) as I could do in Zsh or Emacs.
So what I did instead is create new special keybindings to interact with the X clipboard through zsh. Turns out "^Xw" and "^Xy" are unused in both Emacs and Zsh, so I can get a consistent interface by binding them in both applications. This way the normal editing operations, cutbuffer, and kill ring are left alone. If I want to copy something to the clipboard I set the region and do "^Xw" (or if I've already killed it and the region is inactive I can just do "^Xw" to copy the cut buffer). Pasting from the clipboard is done with "^Xy".
# define commands to copy and paste x clipboard
# ^Xw - copy region, or cut buffer
# ^Xy - paste x clipboard
# in both cases, modifies CUTBUFFER
copy-to-xclip() {
[[ "$REGION_ACTIVE" -ne 0 ]] && zle copy-region-as-kill
print -rn -- $CUTBUFFER | xclip -selection clipboard -i
}
zle -N copy-to-xclip
bindkey "^Xw" copy-to-xclip
paste-xclip() {
killring=("$CUTBUFFER" "${(@)killring[1,-2]}")
CUTBUFFER=$(xclip -selection clipboard -o)
zle yank
}
zle -N paste-xclip
bindkey "^Xy" paste-xclip
You may want to have a look at http://stchaz.free.fr/mouse.zsh which in addition to add mouse support also tries to interact with the X Clipboard.
For macOS users: here is how to make ESC-w (a.k.a. Meta-w or Option-w) copy to the macOS pasteboard as well as the zsh built-in clipboard.
pb-copy-region-as-kill () {
zle copy-region-as-kill
print -rn $CUTBUFFER | pbcopy
}
zle -N pb-copy-region-as-kill
bindkey -e '\ew' pb-copy-region-as-kill
For completeness: here is code for Ctrl-u and Ctrl-k too
pb-backward-kill-line () {
zle backward-kill-line
print -rn $CUTBUFFER | pbcopy
}
zle -N pb-backward-kill-line
bindkey -e '^u' pb-backward-kill-line
pb-kill-line () {
zle kill-line
print -rn $CUTBUFFER | pbcopy
}
zle -N pb-kill-line
bindkey -e '^k' pb-kill-line