2

I added Mac clipboard integration to my emacs -nw using the following code, adapted from here:

(defun copy-from-osx ()
  (shell-command-to-string "pbpaste"))

(defun paste-to-osx (text &optional push)
  (let ((process-connection-type nil))
    (let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
      (process-send-string proc text)
      (process-send-eof proc))))

(setq interprogram-cut-function 'paste-to-osx)
(setq interprogram-paste-function 'copy-from-osx)

However, this creates some undesirable behavior in step 4 of the following situation:

  1. I kill the text abc.
  2. I kill the text def.
  3. I press C-y, which brings back def.
  4. I press M-y, which should replace def with abc but instead does nothing.
  5. I press M-y again, which now properly replaces def with abc.
  6. Further invocations of M-y will function as expected, yanking kills from earlier on the kill ring.

(Having just the above code as my init.el reproduces the problem.)

Here is what I think is happening:

When I kill some text, it's saved to the Emacs kill ring but also (via interprogram-cut-function) to the system clipboard. Then, when I yank with C-y, I first get the contents of the system clipboard (via interprogram-paste-function). Pressing M-y after that gets me the first entry in the Emacs kill ring, which is the same thing. Only by pressing M-y a second time can I get to older entries in the kill ring.

I'm not sure what the best resolution to this problem is. Can Emacs be told to skip yanking from the system clipboard if its contents are identical to the first entry in the kill ring? Or is there another way to be able to C-y M-y instead of C-y M-y M-y to get the second-most-recent thing I killed?

2
  • The GUI version of Emacs built --with-ns comes with OSX clipboard integration out of the box -- i.e., no need to use pbcopy. If this question relates only to using Emacs in the terminal, or some other unspecified usage, then please consider editing the question and/or title so that future forum and Google searchers are not confused.
    – lawlist
    Aug 22, 2016 at 23:15
  • 1
    @lawlist: Thanks for the heads-up. I edited the title and first sentence of the question as per your suggestion. For future visitors, note that the windowed version of Emacs from emacsformacosx.com (which is what I'm using) appears indeed to have system clipboard integration built in. Aug 22, 2016 at 23:30

2 Answers 2

1

I think the docstring from interprogram-paste-function describes the problem and a possible solution:

Note that the function should return a string only if a program other than Emacs has provided a string for pasting; if Emacs provided the most recent string, the function should return nil. If it is difficult to tell whether Emacs or some other program provided the current string, it is probably good enough to return nil if the string is equal (according to `string=') to the last text Emacs provided.

So you could do this:

  • create a variable (initially nil) to save the last text pasted-to-osx,

  • make paste-to-osx save its text argument to the variable,

  • make cut-from-osx compare the obtained string with the one saved in the variable, and return either the string or nil.

0

Based on the suggestions in @JeanPierre's answer, I worked out the following:

(setq last-paste-to-osx nil)

(defun copy-from-osx ()
  (let ((copied-text (shell-command-to-string "pbpaste")))
    (unless (string= copied-text last-paste-to-osx)
      copied-text)))

(defun paste-to-osx (text &optional push)
  (let ((process-connection-type nil))
    (let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
      (process-send-string proc text)
      (process-send-eof proc)))
  (setq last-paste-to-osx text))

(setq interprogram-cut-function 'paste-to-osx)
(setq interprogram-paste-function 'copy-from-osx)

(for additional context see my init.el, commit fff29ffe)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.