14
votes

In GNU Emacs for OSX, how can I keep the kill ring and OSX clipboard separate? (Such that I essentially have two separate kill rings.)

With desired behavior, this would work:
1. C to copy text from the web to OSX clipboard.
2. controlk to kill a line in Emacs.
3. controly to yank killed text from Emacs kill ring to current Emacs buffer.
4. v to paste original web text from OSX clipboard to current Emacs buffer.

This works out of the box in Aquamacs. How to make work in GNU Emacs?

This question was discussed as it pertains to Windows here: Emacs: How to separate the kill ring from the system clipboard?

and here: http://lists.gnu.org/archive/html/help-emacs-windows/2010-02/msg00001.HTML

...but this solution does not work in OSX. I would like a solution for Mac OSX.

6

6 Answers

11
votes

The solution in Emacs: How to separate the kill ring from the system clipboard? does work, though not complete. You may call pbcopy yourself to get clipboard pasting right. For instance, try the following in your .emacs. Note that s-v is for Cmd+V in an OS X window system. Same goes for s-c.

;;; Tested on:
;;; 1.  GNU Emacs 24.3.1 (x86_64-apple-darwin13.0.0)
;;;     of 2013-12-22 on tennine-slave.macports.org
;;;     (MacPorts [email protected]_1)
;;;
;;; 2.  GNU Emacs 24.3.1 (x86_64-apple-darwin, NS apple-appkit-1038.36)
;;;     of 2013-03-12 on bob.porkrind.org
;;;     (Emacs For Mac OS X)

(defun isolate-kill-ring()
  "Isolate Emacs kill ring from OS X system pasteboard.
This function is only necessary in window system."
  (interactive)
  (setq interprogram-cut-function nil)
  (setq interprogram-paste-function nil))

(defun pasteboard-copy()
  "Copy region to OS X system pasteboard."
  (interactive)
  (shell-command-on-region
   (region-beginning) (region-end) "pbcopy"))

(defun pasteboard-paste()
  "Paste from OS X system pasteboard via `pbpaste' to point."
  (interactive)
  (shell-command-on-region
   (point) (if mark-active (mark) (point)) "pbpaste" nil t))

(defun pasteboard-cut()
  "Cut region and put on OS X system pasteboard."
  (interactive)
  (pasteboard-copy)
  (delete-region (region-beginning) (region-end)))

(if window-system
    (progn
      (isolate-kill-ring)
      ;; bind CMD+C to pasteboard-copy
      (global-set-key (kbd "s-c") 'pasteboard-copy)
      ;; bind CMD+V to pasteboard-paste
      (global-set-key (kbd "s-v") 'pasteboard-paste)
      ;; bind CMD+X to pasteboard-cut
      (global-set-key (kbd "s-x") 'pasteboard-cut))

  ;; you might also want to assign some keybindings for non-window
  ;; system usage (i.e., in your text terminal, where the
  ;; command->super does not work)
  )

If you ever run into problems with UTF-8, consider the following possible solution:

;; handle emacs utf-8 input
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(setenv "LANG" "en_US.UTF-8")
1
votes

After much fiddling around, I'm pretty sure that the only way to make this work is to override the x-select-text method. Check out my answer here for all the details: https://stackoverflow.com/a/23254771/71522

1
votes

NOTE:  This draft solution is not meant to be an Emacs system-wide modification separating the clipboards -- instead, this is a custom solution designed to keep the clipboards separated on an interactive basis only when specifically using these custom functions. Other functions within Emacs that use the kill-ring can be modified using a similar method -- the variables interprogram-cut-function and interprogram-paste-function can be made let-bound to a nil value for the duration of the specific functions (either through advice, or modification of the source itself, or creating new functions and/or using a defalias). However, the latter is beyond the scope of this limited example.


HISTORY

First Draft (December 23, 2014):  This is a first draft, which is based on the idea that the OSX clipboard may be accessed only when using C-u before calling either the copy or paste functions. If C-u is called first, then the OSX clipboard is utilized. As I use the functions more on a daily basis, I may have additional revisions to this code and I will update same from time to time:

EDIT (December 24, 2014):  Removed * from the interactive command statement as to lawlist-copy-selected-region -- that was a read-only check needed for pasting, but not copying. Added a statement regarding the general nature of this example.

EDIT (December 28, 2014):  Revised code to better handle when the user forgot to select a region before calling lawlist-copy-selected-region. Small revisions to make the code more concise.


(defun lawlist-copy-selected-region (&optional arg)
(interactive "P")
  (let* (
      (interprogram-cut-function
        (when (equal arg '(4)) interprogram-cut-function))
      (interprogram-paste-function
        (when (equal arg '(4)) interprogram-paste-function))
      (region-active-p (region-active-p))
      (beg (when region-active-p (region-beginning)))
      (end (when region-active-p (region-end)))
      (copied-string
        (when region-active-p (buffer-substring-no-properties beg end))) )
    (unless region-active-p
      (let ((debug-on-quit nil))
        (signal 'quit `("No region has been selected!"))))
    (copy-region-as-kill beg end)
    (when (not (active-minibuffer-window))
      (message "%s"
        (concat
          (if (and interprogram-cut-function interprogram-paste-function)
            "OSX+Emacs:  "
            "Emacs:  ")
          (truncate-string-to-width copied-string 40)
          (when (> (length copied-string) 40)
            " . . .")))) ))

(defun lawlist-yank (&optional arg)
  (interactive "*P")
  (unless arg (setq arg 1))
  (setq yank-window-start (window-start))
  (setq this-command t)
  (push-mark (point))
  (insert-for-yank
    (lawlist-current-kill
      (cond
        ((listp arg)
          arg)
        ((eq arg '-)
          -2)
        (t
          (1- arg) ))))
  (if (consp arg)
      (goto-char (prog1 (mark t)
       (set-marker (mark-marker) (point) (current-buffer)))))
  (if (eq this-command t)
      (setq this-command 'yank))
  (when (region-active-p)
    (setq mark-active nil))
  nil)

(defun lawlist-current-kill (n &optional do-not-move)
  (let ((interprogram-paste
          (and
            (equal n '(4))
            interprogram-paste-function
            (funcall interprogram-paste-function))))
    (cond
      (interprogram-paste
        (let ((interprogram-cut-function nil))
          (if (listp interprogram-paste)
            (mapc 'kill-new (nreverse interprogram-paste))
            (kill-new interprogram-paste)))
        (car kill-ring))
      ((and (equal n '(4)) (not interprogram-paste))
        (car kill-ring))
      (t
        (or kill-ring 
          (let ((debug-on-quit nil))
            (signal 'quit `("The kill-ring is empty."))))
        (let (
            (ARGth-kill-element
              (nthcdr
                (mod (- n (length kill-ring-yank-pointer)) (length kill-ring))
                kill-ring)))
          (unless do-not-move
            (setq kill-ring-yank-pointer ARGth-kill-element)
            (when
                (and
                  yank-pop-change-selection
                  (> n 0)
                  interprogram-cut-function)
              (funcall interprogram-cut-function (car ARGth-kill-element))))
        (car ARGth-kill-element))))))
0
votes
(global-set-key (kbd "C-x M-y")
              (lambda ()
                (interactive)
                (insert-string (ns-get-pasteboard))))

(global-set-key (kbd "C-x M-w")
              (lambda ()
                (interactive)
                (when (region-active-p)
                  (ns-set-pasteboard
                   (buffer-substring (region-beginning)
                                     (region-end))))))
0
votes

simpleclip might be helpful -

Simplified access to the system clipboard in Emacs.

simpleclip-mode radically simplifies clipboard handling: the system clipboard and the Emacs kill ring are made completely independent, and never influence each other.

The super keybindings are friendly for OS X: super is generally mapped to the "command" key ie ⌘.

Tested on OS X, X11, and MS Windows

https://github.com/rolandwalker/simpleclip

-2
votes

Does this help:

(setq x-select-enable-clipboard nil)

This will only separate the two clipboards, and for Cmd+c and Cmd+v to work like mentioned you will have to rebind them to clipboard-kill-ring-save and clipboard-yank.

I am using this Emacs: https://github.com/railwaycat/emacs-mac-port