putty上のEmacsのkill-ringとWindowsのクリップボードを同期する

puttyでサーバにアクセスしてEmacsを使っているとどうしても不便なのはクリップボードにコピーしにくいことです。
マウスでドラッグすればコピーできますが、画面分割しているとうまくできずにいらっとします。
Emacsに慣れるとクリップボードに入れるつもりで自然にM-wしてしまうこともよくあります。

puttyの機能を調べていたらputtyからWindowsクリップボードを操作する方法(puttyclip)があることを発見!
これを使ってEmacsのkill-ringとWindowsのクリップボードを同期*1させます。

用意するもの

シェルスクリプト(winclip)

#!/bin/sh
OUT=$SSH_TTY
echo -n "\033[5i" > $OUT
cat $* | sed 's/\x1B\[\([0-9]\)\{0,2\}m//g' | nkf -Lu -s > $OUT
echo -n "\033[4i" > $OUT

puttyclipにあるwinclipに少し変更を加えています。パスを通すか.emacsでフルパスで設定してください。

  • 標準出力ではなく$SSH_TTYに出力しているのはEmacsから標準出力に出すとバッファ出力になってしまうためです*2
  • sedANSIエスケープシーケンスを削除しています
  • nkfは-sでS-JISで出力しています。-LuでUnix改行コードとなっているのはputtyが勝手に改行コードを変更してくれているようなので。

.emacsの設定

(defun putty-windows-select-text (text &optional push)
  (with-temp-buffer
    (insert text)
    (when (executable-find "winclip")
      (call-process-region (point-min) (point-max) "winclip" nil nil))
    ))
(setq interprogram-cut-function 'putty-windows-select-text)

winclipにクリップボードに送る機能があるのでEmacsからはほぼ実行するだけです。

  • interprogram-cut-functionに関数をセットするとkill-ringの内容をとれます
    • 逆にinterprogram-paste-functionというのもあります
  • 処理内容としては一時バッファにテキストをはき出してからcall-process-regionでバッファの内容を入力としてwinclipを実行しています
    • start-processをつかってパイプで流す方法もありますが、それだとEmacsのメッセージまでクリップボードに入ってしまいます
  • putty clipboard patchが適用されていないputtyでこれを使うとひどいことになります

使ってみる

puttyの設定でTerminal(端末)のRemote-controlled printing(遠隔操作の印刷)でWindows clipboardを選択して起動します。

コマンドラインからwinclipを通してクリップボードに入るか確認します。
文字化けとかエスケープシーケンスが残ってたら、適当にwinclipを修正してください。

$ ls -l | winclip

あとはEmacsを起動してM-wやC-kでkill-ringの内容とクリップボードを確認してみてください!

その他

*1:タイトルは同期としてますが、実際にはEmacs=>Windows方向のみです。インタフェースさえあれば双方向にもできます。

*2:他に良い方法があれば教えて下さい