ターミナルEmacsと
macOSクリップボードをつなぐ
(interprogram-cut-function)

macOSのターミナルでEmacsを使っていると、「Emacsで編集している文字列を、そのまま他のアプリに貼り付けたい」というときに、不便さを感じます。

GUI版のEmacsでは意識しない問題ですが、emacs -nw や ssh 越しのEmacsでは話が変わります。

関連記事

1. ターミナルEmacsで感じた違和感

参考にした設定は、次のようなものでした。

(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)

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

(setq interprogram-paste-function 'copy-from-osx)Code language: JavaScript (javascript)

M-w でコピーした内容は、SafariやSlackに貼り付けられません。
Emacsの中ではコピーできていても、kill-ring という独自の仕組みがあり、macOS全体のクリップボードとは別物でした1

interprogram-cut-function という変数 コピー時(M-w) interprogram-cut-function kill-ring → pbcopy macOS クリップボード ペースト時(C-y) interprogram-paste-function pbpaste → Emacs

1.1. pbcopy / pbpaste に目を向ける

一方、macOSには pbcopypbpaste というコマンドがあります2
ターミナルの標準入力を、macOSのクリップボードに流し込んだり、逆に取り出したりするためのものです。

つまり、やっていることはとても素直です。
Emacsでコピーした文字列(kill-ring)を pbcopy に渡します。
反対に、貼り付けるときは pbpaste の内容をEmacsに戻しています3

1.2. interprogram-cut-function という変数

この関数を使うタイミングを決めるのが、interprogram-cut-function4interprogram-paste-function5 という関数です。
Emacsでテキストを kill(コピーやカット)したときに呼ばれる関数を指定する変数です。

2. おわりに

この設定を入れた瞬間から、M-wC-y が macOS のクリップボードと自然につながりました。
Emacsの標準操作をそのまま使えるので、特別なキー操作を覚える必要もありません。

terminal Emacs と macOS のクリップボード連携は、小さな設定で体験が大きく変わります。
最初は少し分かりにくいですが、一度仕組みを理解すると応用も効きます。

  1. kill-ring は Emacs 独自のコピー/カット履歴で、OS のクリップボードとは別に管理されます。GUI 環境では内部的に同期される場合がありますが、terminal Emacs では自動連携されません。 – The Kill Ring (GNU Emacs Manual)
  2. pbcopy / pbpaste は macOS 標準のコマンドラインツールで、標準入力・標準出力を macOS のシステムクリップボードと接続する役割を持ちます。GUI アプリと同じクリップボードを共有します。 – pbcopy(1) Manual Page
  3. start-process を使うことで、Emacs をブロックせずに外部コマンドへ文字列を送信できます。process-connection-type を nil にするのは、macOS で不要な pty を作らないための定石です。 – Asynchronous Processes (GNU Emacs Manual)
  4. interprogram-cut-function は、Emacs が kill-ring にテキストを追加した直後に呼ばれる関数を保持する変数です。引数として文字列と push フラグを受け取る仕様になっています。 – Clipboard Support (GNU Emacs Lisp Reference)
  5. interprogram-paste-function は、Emacs が外部プログラム側のクリップボード内容を取得する際に呼び出される関数です。戻り値として文字列を返す必要があります。 – Clipboard Support (GNU Emacs Lisp Reference)