3

I've added some keyboard shortcuts in my Zsh to enable selecting words.

In order for the selection to do something, I would like to use Ctrl + C to copy it. However I would also like to use Ctrl + C to interrupt programs, when the Zsh Line Editor (ZLE) isn't active.

Is this possible and how can I do this? I tried to declare a function TRAPINT to hook Ctrl + C, however when I'm in the ZLE and hit Ctrl + C, this function doesn't appear to be called.

1 Answer 1

4

The following code allows us to use the usual shortcuts Ctrl + X, Ctrl + C, Ctrl + V to cut/copy/paste, to both Zsh's as well as X.org's clipboard.

Ctrl + C functions as interrupt as usual, when we aren't in ZLE. To do this, we insert our hook into Zsh's precmd_functions & preexec_functions, to know when we start editing with ZLE, and when we finish editing it when we press Enter.

In order to set/unset Ctrl + C as the interrupt signal, we use stty.

The front part of the script below defines our copy/cut/paste clipboard functions.

The latter part is a slightly modified code from the excellent answer shell - Zsh zle shift selection - Stack Overflow, which binds keys to these functions.

function zle-clipboard-cut {
  if ((REGION_ACTIVE)); then
    zle copy-region-as-kill
    print -rn -- $CUTBUFFER | xclip -selection clipboard -in
    zle kill-region
  fi
}
zle -N zle-clipboard-cut

function zle-clipboard-copy {
  if ((REGION_ACTIVE)); then
    zle copy-region-as-kill
    print -rn -- $CUTBUFFER | xclip -selection clipboard -in
  else
    # Nothing is selected, so default to the interrupt command
    zle send-break
  fi
}
zle -N zle-clipboard-copy

function zle-clipboard-paste {
  if ((REGION_ACTIVE)); then
    zle kill-region
  fi
  LBUFFER+="$(xclip -selection clipboard -out)"
}
zle -N zle-clipboard-paste

function zle-pre-cmd {
  # We are now in buffer editing mode. Clear the interrupt combo `Ctrl + C` by setting it to the null character, so it
  # can be used as the copy-to-clipboard key instead
  stty intr "^@"
}
precmd_functions=("zle-pre-cmd" ${precmd_functions[@]})

function zle-pre-exec {
  # We are now out of buffer editing mode. Restore the interrupt combo `Ctrl + C`.
  stty intr "^C"
}
preexec_functions=("zle-pre-exec" ${preexec_functions[@]})

# The `key` column is only used to build a named reference for `zle`
for key     kcap    seq           widget              arg (
    cx      _       $'^X'         zle-clipboard-cut   _                     # `Ctrl + X`
    cc      _       $'^C'         zle-clipboard-copy  _                     # `Ctrl + C`
    cv      _       $'^V'         zle-clipboard-paste _                     # `Ctrl + V`
) {
  if [ "${arg}" = "_" ]; then
    eval "key-$key() {
      zle $widget
    }"
  else
    eval "key-$key() {
      zle-$widget $arg \$@
    }"
  fi
  zle -N key-$key
  bindkey ${terminfo[$kcap]-$seq} key-$key
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .