hitode909の日記

以前はプログラミング日記でしたが、今は子育て日記です

OS Xのクリップボードを定期的に監視してEmacsのkill-ringに入れる

OS Xクリップボードを監視して,なにかコピーされていればEmacsのkill-ringに記録していくEmacs Lispを作った.

kill-ring

Emacsにはkill-ringという機能があって,過去にコピーした文字列が記録されている.
メニューから,以前にコピーした文字を選んで貼り付けられたり,いいEmacs Lispを入れると,リストから絞り込んで選んだりできる.
http://dl.dropbox.com/u/8270034/g/dcba095342ae5fa6b3b8310af3da22f8.png
http://dl.dropbox.com/u/8270034/g/c640e3c99ead1b07fe67927f7d80ceec.png
便利なので使ってないひとは使えばよいと思う.以下のキーワードで検索するとたぶん見つかる.

OS Xクリップボードとkill-ringの関係

Ctrl-y を押して何か貼り付けすると,OS Xクリップボードに何か入っているか調べて,そうでなければ kill-ringから,最後にEmacs内でコピーした文字列が出てくる.
逆に,Emacsで何かコピーするとOS Xクリップボードにもコピーされる.
OS Xクリップボードとkill-ringはだいたい同期して使えるようになっているけど,OS Xのアプリケーションでコピーしたものは,kill-ringに記録されないので,たまに困ることがある.
さっきメールからコピーしたURLをkill-ringから検索して貼り付けようとしても,うまくいかない.
なにをどこからコピーしたか人間が覚えておく必要があってつらい.

作った

タイマーで1秒ごとにOS Xクリップボードを監視して,なにかコピーされていれば,Emacs内でコピーされた文字列と同じように扱えるように,kill-ringに記録していく,というEmacs Lispを作った.

;;; clipboard-to-kill-ring.el

;;; * 概要
;;; OS Xクリップボードを定期的に監視してkill-ringに入れます
;;; deferred.elが必要です
;;;
;;; * 使い方
;;; (clipboard-to-kill-ring t)
;;; で監視を始めます
;;; clipboard-to-kill-ring:interval を設定するとポーリングの間隔を変えられます.
;;; デフォルトで1秒です.

(require 'deferred)

(defcustom clipboard-to-kill-ring:interval 1.0
  "ポーリング間隔")

(defvar clipboard-to-kill-ring:timer nil)

(defun clipboard-to-kill-ring:observe ()
  (let ((clip (x-cut-buffer-or-selection-value)))
    (when (and clip (not (string= (car kill-ring) clip)))
      (kill-new clip)
      (message clip))))

(defun clipboard-to-kill-ring (enable)
  "enableがtrueのときクリップボードの監視を始めます"
  (if (and enable clipboard-to-kill-ring:timer)
      (clipboard-to-kill-ring nil))
  (if enable
      (setq clipboard-to-kill-ring:timer (run-with-timer
                                              clipboard-to-kill-ring:interval
                                              clipboard-to-kill-ring:interval
                                              'clipboard-to-kill-ring:observe))
    (when clipboard-to-kill-ring:timer
      (cancel-timer clipboard-to-kill-ring:timer)
      (setq clipboard-to-kill-ring:timer nil))))

(provide 'clipboard-to-kill-ring)

https://gist.github.com/1239121

使い方

clipboard-to-kill-ring をrequireして, clipboard-to-kill-ring tを呼ぶ.

(require 'clipboard-to-kill-ring)
(clipboard-to-kill-ring t)

あとは,普通にEmacsを使うだけで,ユーザー体験が向上する.
クリップボードマネージャみたいなやつを入れなくても,Emacsだけでクリップボードの履歴を取ることができる.

おまけ

1秒ずつクリップボードを監視するRubyスクリプト,内容が変わってたら標準出力に表示する.
なにかコピーするとすぐに表示されてちょっとおもしろい.
これはpbpasteを呼んでるけど,Emacsからは,ns-winにあった関数を呼んでる.

#! /usr/bin/env ruby

last = nil

loop {
  current = `pbpaste`
  if last != current
    puts current
    last = current
  end
  sleep 1
}

https://gist.github.com/1239124

追記

ウィンドウズのemacs-w32でも動くようです.便利ですね.