Copy/paste with emacs in terminal

I often run emacs in a terminal window. The following is a way to get copy-paste “working” to and from other applications. Note that it requires xsel, “a command-line program for getting and setting the contents of the X selection”. See also http://shreevatsa.wordpress.com/2006/10/22/emacs-copypaste-and-x/

;; https://hugoheden.wordpress.com/2009/03/08/copypaste-with-emacs-in-terminal/
;; 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)
(setq x-select-enable-clipboard t)

;; If emacs is run in a terminal, the clipboard- functions have no
;; effect. Instead, we use of xsel, see
;; http://www.vergenet.net/~conrad/software/xsel/ -- "a command-line
;; program for getting and setting the contents of the X selection"
(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
 ))

Thanks to Nikolaj Schumacher and Miles Bader on the help-gnu-emacs mailing list for helping out.


32 Comments on “Copy/paste with emacs in terminal”

  1. robinzoni says:

    This is a great hack and it works perfectly. I’ve been looking for similar solution for months. Thank you so much for sharing it. You made my day. 🙂

    Cheers,
    rbz

  2. […] clipboard into Emacs. In some of the comments below, Richard Lewis had the idea of using xsel, and Hugo Heden completed it further. Possibly related posts: (automatically generated)Using EmacsclientEditing TEXTAREAs in an external […]

  3. Tim says:

    Thanks, I’ve been looking for this for a long time, very nice. I suppose the correct way of loading the functions is by putting a line in my `.emacs’ file, this worked for me:
    (load "~/copypaste/copypaste.el")

  4. Hugo Heden says:

    Yes, thanks for mentioning that, that looks reasonable. (You could also just paste the whole piece of code into .emacs, but your version seems cleaner.) More about loading files: http://www.gnu.org/software/emacs/emacs-lisp-intro/html_node/Loading-Files.html

  5. Mohamad Alrawashdeh says:

    Excellent Post! Outstanding 🙂 The best in this month 🙂 Have been searching for this for a while.

    With this post, copy-paste works in my emacs/putty/cygwin. I had to replace the xsel with putclip and getclip commands (for cygwin). And voila, it worked!

  6. giulio says:

    Thanks that worked great!

    I am using emacs-nox in a xfce4-terminal in xubuntu. I had to remove –output from the definition of xsel-output

    Otherwise I would get “/bin/bash: –output command not found” at the end of the string copied.

    • Hugo Heden says:

      Ok, so instead of

      (let ((xsel-output (shell-command-to-string "xsel --clipboard --output")))

      you are using just

      (let ((xsel-output (shell-command-to-string "xsel --clipboard")))

      – is that correct? Not sure how that can work, but it’s useful info for others that may find their way here, thanks!

      • giulio says:

        Correct.

        It works fine when I am using emacs on the desktop locally. It breaks down when I am using emacs remotely over ssh. The first yank produces “xsel: can’t open display (null): Invalid argument” M-y then pastes the copied text.

        Cheers
        giulio

      • Hugo Heden says:

        Aah.. I hadn’t thought about that. I guess you’ve found a limitation in the code above.

        If you log in on a remote machine using ssh you’ll have to use ssh -X for this whole thing to work, so that the remote shell you’re using (specifically the xsel program) has “access” to the X-server on your local machine.

        Putting it another way: this trick requires a graphical environment — an X-server (or a Windows equivalent — see the comment from Mohamad Alrawashdeh) — whose “clipboard” we use to copy to and from, with the help from the xsel program (or putclip/getclip).

        Without ssh -X (using just plain ssh) the code above is pointless.. It’s like logging in to a completely non-graphical environment — it’s just a terminal — there’s no “global clipboard” that can be used to copy and paste from.

        You should be able to verify this on the command line on the remote machine: xsel should not work at all without -X:


        $ xsel --clipboard
        xsel: Can't open display: (null)

        So the “script” above should probably detect if there’s no display, and in that case revert to regular emacs behaviour. Contributions welcome 🙂

        Another issue with this code, I believe, is handling new emacs --daemon mode; Nowadays, the same “emacs process” (the daemon) can run in a GUI-window and in a terminal, often simultaneously. This code does not handle that — I guess it performs the check for whether emacs is run in terminal or GUI-window at emacs start-up.. Hmm.

  7. lehooo says:

    Thank you so much for this! It is so unusual to find a solution that just works perfectly like this!

  8. Winarm says:

    I may be late in posting this but I have been looking for a long time for something like this. I am a student and new to emacs and programming. My professor is unwilling or unable to provide me any guidance in this matter and I just need to know how to actually accomplish the procedure.

    My assignments consist of editing large C++ files in order to complete a program. The instructor provides the basic source code in a text file which we are supposed to edit in emacs and then compile. I access emacs remotely through VNC and cannot figure out how to copy the text files into the emacs editor window. The source code is too large to just type into the editor although that is what I have been doing.

    Where and how would I enter the following code:
    (setq x-select-enable-clipboard t)

    Thank you kindly.

    • Hugo Heden says:

      Sorry, can’t help you.. How about starting with just transferring the instructor’s source-file to the remote computer (on which emacs runs) and then just open the file with emacs?

      Also, in some configurations and cases, middle-clicking works as paste.

  9. Mike says:

    This. Is. Sicknasty. Exactly what I was looking for. Well ‘effing done.

  10. jjj says:

    Thank you for this, it’s been bothering me for quite some time. I guess to ought to add Emacs Lisp to the ever-growing list of things to learn.

  11. Daniel says:

    Fix to not add hooks if DISPLAY is unset:

    http://pastebin.com/NSZgWLLQ

    • Hugo Heden says:

      Thanks Daniel. That’s useful. I’ve added your additions to the code above: The two lines the check the $DISPLAY variable early in the script (currently colored in green), and the two extra parantheses right at the end.

  12. Ilya says:

    I am guessing it is better/faster to use (getenv “DISPLAY”) instead spinning a new process and relying on “echo” being there with (shell-command-to-string “echo $DISPLAY”)
    And so it now becomes:

    (when (getenv "DISPLAY")
    (defun xsel-cut-function
    ...))

  13. kgaipal says:

    Thnx Hugo a ton. This makes the work flow so less painful!

  14. […] 参考:https://hugoheden.wordpress.com/2009/03/08/copypaste-with-emacs-in-terminal/ 此条目由 vancel1 发表在 2012-03 分类目录,并贴了 emacs 标签。将固定链接加入收藏夹。 […]

  15. Tom Bless says:

    Thank you! Emacs’ complete takeover of my computing life is one step closer.

  16. nicek says:

    非常感谢,我找了很长时间,很多网上说的pbpaste和pbcopy都是在mac上的,linux上根本用不了,太感谢了!

  17. […] 终端下的 Emacs 访问系统剪切板,方便不同程序间的复制粘贴,fromhttps://hugoheden.wordpress.com/2009/03/08/copypaste-with-emacs-in-terminal/ […]

  18. […] 终端下的 Emacs 访问系统剪切板,方便不同程序间的复制粘贴,fromhttps://hugoheden.wordpress.com/2009/03/08/copypaste-with-emacs-in-terminal/ […]

  19. […] 终端下的 Emacs 访问系统剪切板,方便不同程序间的复制粘贴,fromhttps://hugoheden.wordpress.com/2009/03/08/copypaste-with-emacs-in-terminal/ […]

  20. EdwardHoids says:

    добродушный ресурс http://4xcasino.ru

  21. amiga23 says:

    This is really great! Thank you very much for this script.


Leave a comment