简体   繁体   English

emacs 终端模式:如何高效复制粘贴

[英]emacs terminal mode: how to copy and paste efficiently

I'm having a hard time making this emacs -nw work effectively under the terminal mode (emacs -nw).我很难让这个 emacs -nw 在终端模式 (emacs -nw) 下有效工作。 Some setup information: The working server is connected via SSH, and emacs is running on the server.一些设置信息: 工作服务器通过 SSH 连接,并且 emacs 正在服务器上运行。 Usually I'm connecting using SSH and "emacs -nw" to work on my files.通常我使用 SSH 和“emacs -nw”连接来处理我的文件。

The emacs config is picked up from: https://hugoheden.wordpress.com/2009/03/08/copypaste-with-emacs-in-terminal/ emacs 配置取自: https : //hugoheden.wordpress.com/2009/03/08/copypaste-with-emacs-in-terminal/

;; make mouse selection to be emacs region marking
(require 'mouse)
(xterm-mouse-mode t)
(defun track-mouse (e)) 
(setq mouse-sel-mode t)

;; enable clipboard in emacs
(setq x-select-enable-clipboard t)

;; enable copy/paste between emacs and other apps (terminal version of emacs)
(unless window-system
 (when (getenv "DISPLAY")
  ;; Callback for when user cuts
  (defun xsel-cut-function (text &optional push)
    ;; Insert text to temp-buffer, and "send" content to xsel stdin
    (with-temp-buffer
      (insert text)
      ;; I prefer using the "clipboard" selection (the one the
      ;; typically is used by c-c/c-v) before the primary selection
      ;; (that uses mouse-select/middle-button-click)
      (call-process-region (point-min) (point-max) "xsel" nil 0 nil "--clipboard" "--input")))
  ;; Call back for when user pastes
  (defun xsel-paste-function()
    ;; Find out what is current selection by xsel. If it is different
    ;; from the top of the kill-ring (car kill-ring), then return
    ;; it. Else, nil is returned, so whatever is in the top of the
    ;; kill-ring will be used.
    (let ((xsel-output (shell-command-to-string "xsel --clipboard --output")))
      (unless (string= (car kill-ring) xsel-output)
        xsel-output )))
  ;; Attach callbacks to hooks
  (setq interprogram-cut-function 'xsel-cut-function)
  (setq interprogram-paste-function 'xsel-paste-function)
  ;; Idea from
  ;; http://shreevatsa.wordpress.com/2006/10/22/emacs-copypaste-and-x/
  ;; http://www.mail-archive.com/help-gnu-emacs@gnu.org/msg03577.html
 ))

The reason to have:拥有的理由:

 (require 'mouse)
 (xterm-mouse-mode t)
 (defun track-mouse (e)) 
 (setq mouse-sel-mode t)

is to enable mouse selection over text such that the text region is highlighted just as "Cx SPC" marking the region.是在文本上启用鼠标选择,以便文本区域突出显示,就像“Cx SPC”标记区域一样。 Then I can use "Mx w" to copy and "Cx y" to paste text within emacs and between emacs and other apps.然后我可以使用“Mx w”来复制和“Cx y”在 emacs 内以及 emacs 和其他应用程序之间粘贴文本。

All look perfect except that any operations related to X are REALLY SLOW!一切看起来都很完美,只是与 X 相关的任何操作都非常慢! My connection to the remote server is smooth -- the latency is usually under 100ms.我与远程服务器的连接很流畅——延迟通常低于 100 毫秒。 But to kill one line of text using "Cx k", it takes ~5 seconds!但是要使用“Cx k”杀死一行文本,大约需要 5 秒! To paste it, it takes another 5 seconds!要粘贴它,还需要 5 秒钟!

When copy/paste is frequent sometimes, this becomes really annoying.当复制/粘贴有时很频繁时,这会变得很烦人。 I think this is related to the X sever messaging, but not sure if there is good way to fix this.我认为这与 X 服务器消息传递有关,但不确定是否有解决此问题的好方法。

Any ideas?有任何想法吗? Thanks!谢谢!

This is not an ideal solution per se, but i figured out a way that I feel better than the previous one.这本身并不是一个理想的解决方案,但我想出了一种比前一个更好的方法。

The idea is to get rid of X which causes heavy latency issues, ie keep only the following:这个想法是摆脱导致严重延迟问题的 X ,即只保留以下内容:

;; enable clipboard in emacs
(setq x-select-enable-clipboard t)

The results are:结果是:

  1. copy/paste within Emacs is straightforward and fast.在 Emacs 中复制/粘贴既简单又快速。

  2. copy from other apps to Emacs: Ctrl+Shift+v从其他应用复制到 Emacs:Ctrl+Shift+v

  3. copy from Emacs to other apps: mouse selection is now on X Selection, so right-click and copy shall copy the text into the Selection.从 Emacs 复制到其他应用程序:鼠标选择现在位于 X 选择上,因此右键单击并复制应将文本复制到选择中。 Note that 'Mw" now won't copy anything into Selection or system clipboard.请注意,“Mw”现在不会将任何内容复制到选择或系统剪贴板中。

This is again a compromise rather than a solution, but considering the fact that i copy/paste more often than inter-app operations, this is acceptable at the moment.这又是一种妥协而不是解决方案,但考虑到我复制/粘贴的频率比应用间操作更频繁,目前这是可以接受的。

Still looking forward to a good solution!仍然期待一个好的解决方案!

You can accomplish this by using a terminal escape code!您可以通过使用终端转义码来完成此操作! There is a unique category of terminal escape codes called "Operating System Controls" (OSC) and one of these sequences ( \\033]52 ) is meant for interacting with the system clipboard.有一类独特的终端转义码称为“操作系统控制”(OSC),其中一个序列( \\033]52 )用于与系统剪贴板进行交互。 The great thing is that your terminal doesn't care where the code came from so it will work in remote sessions as well.很棒的事情是你的终端不关心代码来自哪里,所以它也可以在远程会话中工作。

Most terminal emulators support it (iTerm2, OS X Terminal, and I think all Linux terminals besides GNOME).大多数终端模拟器都支持它(iTerm2、OS X 终端,我认为除了 GNOME 之外的所有 Linux 终端)。 You can test if your terminal supports this sequence by simply running:您可以通过简单地运行来测试您的终端是否支持此序列:

$ printf "\033]52;c;$(printf "Hello, world" | base64)\a"

Then paste from your system clipboard.然后从系统剪贴板粘贴。 If it pastes "Hello, world" then your terminal supports it!如果它粘贴“Hello, world”,那么您的终端支持它!

I have this function in my init.el so when I call yank-to-clipboard Emacs will yank the value from my kill ring into the system clipboard:我的init.el有这个函数,所以当我调用yank-to-clipboard Emacs 会将值从我的 kill ring 中init.el系统剪贴板中:

(defun yank-to-clipboard ()
"Use ANSI OSC 52 escape sequence to attempt clipboard copy"
  (interactive)
  (send-string-to-terminal
    (format "\033]52;c;%s\a"
      (base64-encode-string 
        (encode-coding-string 
          (substring-no-properties 
            (nth 0 kill-ring)) 'utf-8) t))))

As I type this, I stumbled upon an almost-identical script supported by Chromium community: https://chromium.googlesource.com/apps/libapps/+/master/hterm/etc/osc52.el当我输入这个时,我偶然发现了一个由 Chromium 社区支持的几乎相同的脚本: https : //chromium.googlesource.com/apps/libapps/+/master/hterm/etc/osc52.el

For those running Emacs inside Tmux: Tmux consumes the sequence, so you'll need to pipe the sequence to the Tmux active tty for this to work.对于那些Tmux 中运行 Emacs 的人: Tmux 使用序列,因此您需要将序列通过管道传输到 Tmux 活动 tty 以使其工作。 I have a solution in my blog post here: https://justinchips.medium.com/have-vim-emacs-tmux-use-system-clipboard-4c9d901eef40我在我的博客文章中有一个解决方案: https : //justinchips.medium.com/have-vim-emacs-tmux-use-system-clipboard-4c9d901eef40

To extend on @justinokamoto's answer for use in tmux, it works great and is truly amazing.为了扩展@justinokamoto 在 tmux 中使用的答案,它非常有效,而且真的很棒。 I haven't debugged it with eg tramp or other fancy emacs settings but to get it to work我还没有用例如tramp 或其他花哨的emacs 设置调试它,而是让它工作

  1. Follow https://sunaku.github.io/tmux-yank-osc52.html great instructions, modifying your tmux.conf and ~/bin/yank按照https://sunaku.github.io/tmux-yank-osc52.html很好的说明,修改你的tmux.conf~/bin/yank
  2. Make sure terminal access to your clipboard is enabled on your terminal确保在您的终端上启用了对剪贴板的终端访问

Then to pull into emacs you can use a function like:然后要进入 emacs,您可以使用如下函数:

(Caveat emptor, I am very new to elisp. This writes to a temporary file in /tmp/yank) (注意空客,我对 elisp 很陌生。这会写入 /tmp/yank 中的临时文件)

(defun custom-terminal-yank (&rest args)
  (message "-> CLIP")

  ;; FOR EVIL MODE: UNCOMMENT SO FIRST YANKS TO KILL RING
  ;; need to yank first, with all those args
  ;; ;; https://emacs.stackexchange.com/questions/19215/how-to-write-a-transparent-pass-through-function-wrapper
  ;; (interactive (advice-eval-interactive-spec
  ;;               (cadr (interactive-form #'evil-yank))))
  ;; (apply #'evil-yank args)
  
  ;; https://stackoverflow.com/questions/27764059/emacs-terminal-mode-how-to-copy-and-paste-efficiently
  ;; https://sunaku.github.io/tmux-yank-osc52.html
  (f-write-text (nth 0 kill-ring) 'utf-8 "/tmp/yank")
  (send-string-to-terminal (shell-command-to-string "~/bin/yank /tmp/yank"))
  )

If anyone else uses evil mode as well (just to make things complicated) you can uncomment those lines and use something like (define-key evil-visual-state-map "Y" 'jonah-terminal-yank) So that normal "y" is for normal yanking in visual mode, but "Y" is for cross-clipboard yanking如果其他人也使用邪恶模式(只是为了使事情复杂化),您可以取消注释这些行并使用类似的内容(define-key evil-visual-state-map "Y" 'jonah-terminal-yank)这样正常的 "y " 用于视觉模式下的正常猛拉,但 "Y" 用于跨剪贴板猛拉

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM