akermu / emacs-libvterm

Emacs libvterm integration
GNU General Public License v3.0
1.71k stars 136 forks source link

Killing lines does not add to the kill ring #304

Open plattfot opened 4 years ago

plattfot commented 4 years ago

Having an issue when killing text in the vterm mode (not the VTermCopy), that it's not adding it to the kill ring.

To reproduce the issue: Run emacs -Q Then in the scratch buffer evaluate these two lines to load vterm

(add-to-list 'load-path "~/.emacs.d/elpa/vterm-20200418.1610")
(require 'vterm)

Type in foo in the scratch buffer then killed that. Open a vterm using M-x vterm and type cd

$ cd|

then C-a

$ |cd

C-k

$ |

C-y

$ foo|

Expected behavior: Should yank cd to the prompt not foo.

Sbozzolo commented 4 years ago

Thanks for the report. A possible workaround is this:

(defun vterm-send-C-k ()
  "Send `C-k' to libvterm."
  (interactive)
  (kill-ring-save (point) (vterm-end-of-line))
  (vterm-send-key "k" nil nil t))

The problem with this workaround is that all the times C-k is sent, the text is copied, even if C-k was not supposed to kill/copy (eg, you are in a TUI that captures C-k).

At the moment, I don't know how to do better.

plattfot commented 4 years ago

Thanks for the workaround. I'm not using programs with TUI that much so that shouldn't be a problem for me.

may commented 2 years ago

I ended up wrapping this in a eval-after-load, otherwise it would stop working after I restarted emacs (because I had previously C-x C-e'd it to get it working when I first installed it.)

(eval-after-load "vterm"
  '(defun vterm-send-C-k ()
     "Send `C-k' to libvterm."
     (interactive)
     (kill-ring-save (point) (vterm-end-of-line))
     (vterm-send-key "k" nil nil t)))
e-hoarder commented 1 year ago

wouldn't it make more sense to handle that sort of thing in the shell itself? I have this in my .zshrc for example:

_kill_line_to_clip(){
    zle .set-mark-command
    zle .end-of-line
    zle .exchange-point-and-mark
    zle .copy-region-as-kill
    echo -n "${CUTBUFFER}" | pbcopy
    zle .kill-line
}
zle -N kill-line-to-clip _kill_line_to_clip
bindkey '^k' kill-line-to-clip

_backward_kill_word_to_clip() {
  zle .set-mark-command
  zle .backward-word
  zle .exchange-point-and-mark
  zle .copy-region-as-kill
  echo -n "${CUTBUFFER}" | pbcopy
  zle .backward-kill-word
}
zle -N backward-kill-word-to-clip _backward_kill_word_to_clip
bindkey '^w' backward-kill-word-to-clip
eswierk commented 9 months ago

I use @e-hoarder 's solution with one tweak: instead of pbcopy, which works only on the local machine, use the magic ANSI OSC 52 sequence, which writes to the clipboard from anywhere.

e-hoarder commented 9 months ago
* Replace the two `echo` commands with `printf "\033]52;c;$(printf "%s" "${CUTBUFFER}" | base64)\a"`

* Enable OSC 52 by setting `(setq vterm-enable-manipulate-selection-data-by-osc52 t)`

That is awesome, I wish I had known about this earlier, thanks. I spend most of my work day in ssh sessions.

e-hoarder commented 9 months ago

I implemented @eswierk 's suggestion like so

 osc-copy(){
  if test "$#" -gt 0 ; then
    printf "\033]52;c;%s\a" "$( printf "$*" | base64 )"
  elif test ! -t 0 ; then
    printf "\033]52;c;%s\a" "$( </dev/stdin base64 )"
  fi
}

Which should be a drop-in replacement at least for the most basic uses of wl-copy/pbcopy or whatever

eswierk commented 9 months ago

@e-hoarder Good idea... but I think that inner printf needs to be printf "%s" "$*". Passing "$*" straight to printf will do strange things if the argument itself happens to contain a format sequence like %s.

e-hoarder commented 4 months ago

I just started using tmux more and I finally got around to updating this function

escape-if-tmux(){
  if test -n "$TMUX" -o -z "${TERM##screen*}" ; then
    printf "\033Ptmux;\033%s\a" "${1}"
  else
    printf "%s" "${1}"
  fi
}

osc-52-printf(){
  printf "\033]52;c;%s\a" "${1}"
}

osc-copy(){
  if test "$#" -gt 0 ; then
    input="$( printf "%s" "$*" | base64 --wrap=0 )"
  elif test ! -t 0 ; then
    input="$( </dev/stdin base64 --wrap=0 )"
  fi
  escape-if-tmux "$( osc-52-printf ${input} )"
}