Personal tools
You are here: Home 原稿・資料 Software Design連載記事「Emacsのトラノマキ」の原稿 コピーアンドペーストを使いこなす(松山智大)
Document Actions

コピーアンドペーストを使いこなす(松山智大)

「Emacsのトラノマキ」連載第四回「コピーアンドペーストを使いこなす」

コピーアンドペーストを使いこなす

Emacsをちゃんと使いこなせるようになるためにはいくつかの大きな壁を越えなくてはなりません。今回説明するコピーアンドペーストは初心者がEmacsを使い初めて最初にぶつかる大きな壁の一つでしょう。一般的なエディタでは、マウスやキーボードで範囲を選択してCtrl+C(コピー)し適当な場所でCtrl+V(ペースト)という標準的な操作でコピーアンドペーストができます。そしてその動作は単純かつ明快で誰にでも簡単に理解できるものです。しかし、Emacsにおいてはそうはいかないのです。EmacsではCtrl+CCtrl+Vといった標準的な操作は提供されておらず、そもそもクリップボードという概念も存在しません。クリップボードの代わりとしてkill-ringと呼ばれる(操作上)環状のデータ構造を使用してコピーアンドペーストを実現しますが、このkill-ringというのがクリップボードのような単純な構造でなく、しばしばユーザーの期待を裏切ることがあるのです。例えば(信じられないかもしれませんが)クリップボードの内容がいつのまにか書き変わっているというケースです。このkill-ringというのはイメージとしてはデータを何個も保持できるクリップボードという感じで、聞こえはいいのですが、(僕はEmacsのUIの問題だと思っていますが)使いこなすのにある程度知識が必要です。しかしながら、慣れの問題だとも言えますし、Emacsの設計思想的には使いにくい部分は自分で改造すればいいのです。今回はコピーアンドペーストなどの範囲操作の基礎となるリージョンの概念とコピーアンドペーストがなぜ難しいのか、そして楽にコピーアンドペーストするための方法を説明します。

リージョンとは

リージョンとは、一般的のエディタで言う選択範囲のことをいいます。一般的なエディタでは選択範囲の開始位置と終了位置の明確な規定がなく、単純に選択した範囲を色を変えて表示し、その範囲に対して操作ができるということを示しています。一方、Emacsの範囲選択、つまりリージョンというのは、開始位置と終了位置が明確な意味を持っています。実際のところ、リージョンというのは実体的な存在ではなく(つまりリージョンというデータがあるわけではない)、リージョンを意味付けているのはこの開始位置と終了位置になっています。開始位置は現在のカーソルの位置で、終了位置は一番最後に設置されたマークになります。これはelispによる単純なデータ操作のみでリージョンを表現しえるということを意味しています。抽象的で小難しい話になりましたが、リージョンを理解するのはとても重要なので、もうすこし我慢して読んでください。

先程、リージョンの終了位置は「一番最後に設置されたマーク」と言いましたが、マークとは一体何なのでしょう。マークは、おそらく一般的なエディタは持っていない機能で誤解を恐れずに言えば、カーソルの位置を記憶するブックマーク的な機能と言うことができます。もちろんデータ構造上はもっと一般的な位置付けで、相対的に位置を記憶するポジションと表現することができ、elispで特定の関数を呼び出すことによりマークを生成することができます。ただ、今回はEmacsの操作の説明をしたいので、マークはカーソルの位置を記憶するブックマークと考えておいてください。

ユーザーはC-SPCで現在のカーソルの位置に自由にマークを設置することができます(上限が許す限りいくらでも設置できます)。最後に設置された直近のマークはリージョンの終了位置になります。つまりC-SPCを押した時点で、カーソルの位置とそのマークとの間でリージョン操作が可能になるわけです。ただ、Emacsではデータとしてリージョンが存在するかどうかとリージョンがユーザーに見えるかどうかを明確に分離しているため多少の混乱が生じます。マークを設置した時点で直ちにリージョンが見えるようになるかどうかはtransient-mark-modeという変数で制御されます。transient-mark-modetの場合は、直ちにリージョンが見えるようになり、nilの場合はもう一度C-SPCを押すことでリージョンが見えるようになります。最新開発版であるEmacs23ではデフォルトでtransient-mark-modetになっており、これは僕も含め多くの人にとって直感的です。残念ながら最新安定板であるEmacs22ではデフォルトでnilになっています。そのため次のコードを~/.emacsに書くかM-x customize-variabletransient-mark-modetに変更してください。

(setq transient-mark-mode t)

これでC-SPCを押した時点でリージョンが見えるようになります。ちなみにリージョンが見える状態でC-gを押すとリージョンが見えなくなりますが、データ上はリージョンは常に存在しつづけることを覚えておいてください。つまりリージョンが見えなくなっても、リージョン操作が可能ということです。

C-SPCでマークを設置後カーソルを移動した図

コラム: リージョン選択の解除

一般的なエディタではShiftキーを離した状態でカーソルを移動すれば範囲選択が解除されます。一方、Emacsではリージョン選択を解除するには明示的に何らかのコマンドを発行する必要があります。通常は、分からなくなったときの伝家の宝刀C-gを押してリージョン選択を解除しますが、これには一つ問題があります。その問題というのは、マクロ定義が意図せずに中断されてしまうことです。前回の記事にもある通り、マクロ定義中にC-gするとマクロ定義が中断されてしまいます。それはたとえ、isearchの文字列を戻すためのC-gであっても、リージョン選択を解除するためのC-gであっても同じです。そういった場合に利用するのがM-ESC ESC (keyboard-escape-quit)で、このコマンドはC-g (keyboard-quit)より弱い脱出コマンドです。これは人によってはESC ESC ESCと押したほうが楽かもしれませんが、どちらにしても押すのが面倒臭いので~/.emacsに次のように書いておくと良いでしょう。

(global-set-key (kbd "C-M-g") 'keyboard-escape-quit)

keyboard-escape-quitは要約すれば「状態を脱出する」コマンドで、次のような状態を脱出するために使用します。

  • query-replaceなどのインタラクティブコマンドの実行状態
  • リージョン選択状態
  • ミニバッファでの入力状態
  • ウィンドウの分割状態

keyboard-escape-quitを利用すれば、マクロ定義を中断することなくリージョン選択を解除することができます。ただし、厄介なことにkeyboard-escape-quitでマクロ定義が中断することもあります。例えば、マクロ定義中にM-x blahしてM-ESC ESCするとマクロ定義が中断されてしまいます。そのため現状ではユーザーがkeyboard-escape-quitを慎重に利用してマクロ定義を行わざるを得ません。Emacsでマクロを定義するにはとんでもない集中力が必要になります。

蛇足ですがマクロ定義中かどうかはモードラインにDefという文字列があるかどうかで分かります。

マクロ定義中のモードラインの図

リージョン選択時にC-gでリージョン選択を解除したらこのDefという文字列が消えること、M-ESC ESCで解除したら消えないことを確認してみましょう。

コピーアンドペースト

それではコピーアンドペーストのやり方を説明しましょう。コピーアンドペーストのやり方を説明しないとならないというのがEmacsぽくて個人的に好きです。ともかくできるだけ退屈しないように説明したいと思います。

リージョンが選択できるようになると、Emacsで数多く用意されているリージョン操作を使えるようなります。コピーアンドペーストもリージョン操作の一つです。ただ、言うまでもないかもしれませんがペーストはリージョン操作ではありません。しかしコピーだけ説明するのはバランスが悪いので一緒に説明したいと思います。今回、分かりやすさのため「コピーアンドペースト」という用語を使っていますが、もちろん「カットアンドペースト」もこれに含まれます。どちらも似たようなもので、これは一般的なエディタと変わりありません。

Emacsにおける「コピー」というのは、リージョン選択したテキストをkill-ringの先頭に挿入することを意味します。コピーを行うにはコピーしたいテキストをリージョン選択してM-wを押します。

                           kill-ring 
                  M-w    +-----------+
"Emacs"をコピー    =>    | Emacs     |
                         +-----------+
                         |    ...    |

                           kill-ring 
                  M-w    +-----------+
"GNU"をコピー      =>    | GNU       |
                         +-----------+
                         | Emacs     |
                         +-----------+
                         |    ...    |

「カット」を行う場合はC-wを押します。その場合、リージョン選択されたテキストは削除されます。なお、Emacsではカットすることをkillすると言います。

Emacsにおける「ペースト」というのは、kill-ringの先頭のテキストを貼り付けるすることを意味します(*)。ペーストを行うにはC-yを押します。Emacsではペーストすることをyankすると言うので、その頭文字のyでC-yだと覚えておくとよいでしょう。kill-ringが次のようになっている状態でペーストを行うと、kill-ringの先頭のテキストである"GNU"が貼り付けられます。

(*) 厳密には現在のポインタの位置から貼り付けるする。詳細は後述。

  kill-ring 
+-----------+   C-y
| GNU       |    => "GNU"がペーストされる
+-----------+
| Emacs     |
+-----------+
|    ...    |

ここまでが基本的な操作方法になります。各操作をまとめると次のようになります。

コピーアンドペースト

  1. リージョン選択
  2. M-w
  3. 移動
  4. C-y

カットアンドペースト

  1. リージョン選択
  2. C-w
  3. 移動
  4. C-y

ここからはコピーアンドペーストがなぜ難しいかを説明します。

コピーの難しさ

Emacsにおけるコピーの難しさというのは一言で言えば想定していないテキストも勝手にコピーされてしまうところにあります。EmacsではM-wC-wなどkill-ringへの操作がメインになっているコマンドの他に、C-k (kill-line)M-d (kill-word)などkill-ringへの操作が副次的に行われるコマンドが存在します。具体的にはコピーアンドペーストの一連の操作の途中で、kill-ringへの操作が副次的に行われるコマンド(一般的にkillの付くコマンド)を無意識に実行してしまった場合に、ペーストしようとした内容が別の変わってしまうことがあるわけです。次に例を示します。

  1. "GNU Emacs"をM-wでコピー
  2. ペーストする箇所に移動する途中で不要な行"The most complex editor"を発見したのでC-k (kill-line)で削除
    • この時、"The most complex editor"がkill-ringの先頭に挿入されてしまう(意図していない!)
  3. 目的の箇所でC-yでペーストしたら"GNU Emacs"ではなく"The most complex editor"がペーストされた

この問題を回避するために、計画的にコピーアンドペーストしろとか慎重にコピーアンドペーストしろというのは不毛な議論になるので、ここではその問題の解決策を示したいと思います。解決策には大きく分けて二つあります。

  1. コピーを工夫する
  2. ペーストを工夫する

(2)については次の節で説明するので、ここでは(1)について考えてみます。

まず最初に思いつく、そして唯一思いつく解決策は変動しやすく予測の付かないkill-ringを使わないというものです。Emacsではカーソルの位置やテキストを一時的に格納して後から利用することのできるレジスタという機能が用意されており、kill-ringの代替としてレジスタを用いることにより問題を解決することができます。レジスタにテキストを格納するには、格納したいテキストをリージョン選択してC-x r s <文字>を押します。<文字>となっている部分には適当な文字を入力します。例えばaを入力した場合はレジスタaにそのテキストを格納したことになります。格納したテキストをペーストするにはC-x r i <文字>を押します。前のコピーアンドペーストの例をレジスタを使って示します。

  1. "GNU Emacs"をC-x r s aでレジスタaにコピー
  2. ペーストする箇所に移動する途中で不要な行"The most complex editor"を発見したのでC-k (kill-line)で削除
    • この時、"The most complex editor"がkill-ringの先頭に挿入される
  3. 目的の箇所でC-x r i aでレジスタaの内容"GNU Emacs"をペーストすることができる

一応問題は解決できていますが、言うまでもなくキー操作が面倒臭いし覚えられません。そこで、M-wC-wが二回連続で押された場合にレジスタ@に格納するようにして、レジスタへのコピーが簡単にできるようにしてみます。

(defvar clipboard-register ?@)

(defadvice kill-region (before clipboard-cut activate)
  (when (eq last-command this-command)
    (set-register clipboard-register (car kill-ring))
    (message "Copy to clipboard")))

(defadvice kill-ring-save (before clipboard-copy activate)
  (when (eq last-command this-command)
    (set-register clipboard-register (car kill-ring))
    (message "Copy to clipboard")))

さらにレジスタ@からテキストをペーストするコマンドを作成してC-M-yに割り当てます。

(defun clipboard-paste ()
  (interactive)
  (insert-register clipboard-register)
  (message "Paste from clipboard"))

(global-set-key (kbd "C-M-y") 'clipboard-paste)

上記のコードを~/.emacsに書いておきましょう。この機能を使って、前のコピーアンドペーストの例を示すと次のようになります。

  1. "GNU Emacs"をM-w M-wでクリップボード(レジスタ@)にコピー(kill-ringにも挿入される)
  2. ペーストする箇所に移動する途中で不要な行"The most complex editor"を発見したのでC-k (kill-line)で削除
    • この時、"The most complex editor"がkill-ringの先頭に挿入される
  3. 目的の箇所でC-M-yでクリップボード(レジスタ@)の内容"GNU Emacs"をペーストすることができる

最初に比べれば十分使いやすくなったはずですが、やはり煩雑なのは否めません。実際のところ、C-k (kill-line)M-d (kill-word)kill-ringに挿入されたテキストをペーストしたくなることも頻繁にあるので、どこかで妥協点を見つけてEmacsを全体的に使いやすく保つのが必要になります。著者は、Emacsが秘めているこのようなUIの改善のチャンスこそが最大の魅力だと思っています。

ペーストの難しさ

Emacsにおけるペーストの難しさというのは一言で言えばUIが直感的でないところにあります。前述したようにEmacsではkill-ringを利用してクリップボードのようなものを実現しています。しかし、このkill-ringはともすればすぐに変化してしまい、ユーザーの期待を裏切ってしまう傾向にあります。表面的にはそのような事態をフォローする機能(M-y (yank-pop))が用意されていますが、このUIは初心者には(時には上級者にすら)使いにくいもので、実質的にその機能が利用されないという実態があります。多くのユーザーは標準では入っていない拡張を利用することによりこの不都合を回避しており、本記事でも標準機能ではなく拡張を利用することを推奨します。とはいってもひとまずは知識として、このkill-ringからペーストする標準的な方法を説明します。

C-y (yank)M-y (yank-pop)

kill-ringからのペーストはC-y (yank)M-y (yank-pop)を用いて行います。C-ykill-ringの先頭のテキストをペーストします。例えば、kill-ringが次のようになっている場合にC-yを押すとkill-ringの先頭のテキスト"GNU"がペーストされます。

  kill-ring 
+-----------+   C-y
| GNU       |    =>    "GNU"をペースト
+-----------+
| Emacs     |
+-----------+
| an Editor |
+-----------+

ここでkill-ring内の二番目のテキスト"Emacs"をペーストしたいとします。そのためにはM-yを使います。kill-ring内の二番目以降のテキストをペーストするには、まずC-yを押してからM-yを必要な回数押します。例えば上記の例の二番目のテキスト"Emacs"をペーストするにはC-y M-yと押します。

  kill-ring 
+-----------+   C-y
| GNU       |    =>    "GNU"をペースト
+-----------+
| Emacs     |
+-----------+
| an Editor |
+-----------+

  kill-ring 
+-----------+
| GNU       |
+-----------+   M-y
| Emacs     |    =>    "GNU"を"Emacs"に置きかえる
+-----------+
| an Editor |
+-----------+

C-yした図

次にM-yした図

M-yが押されたときにkill-ringを参照する際の内部的なポインタが一つ進みます。このポインタはC-yM-yに影響し、先ほどの「kill-ringの先頭」という表現は実はkill-ringのリストの最初ではなく、このポインタに指されているテキストになります。このポインタはM-wC-wが押されたときにリセットされます。なお、現在このポインタが指しているテキスト(killと言います)は(current-kill 0)を評価することで取得できます。上記の例のkill-ringの最終的な状態は次のようになります。

  kill-ring 
+-----------+
| GNU       |
+-----------+
| (*) Emacs |
+-----------+
| an Editor |
+-----------+

*はポインタ

この状態でC-yを押すと"Emacs"がペーストされ、さらにM-yを押すと"Emacs"が"an Editor"に置きかわります。そのことが理解できていればC-yM-yによるコピーアンドペーストはとりあえず問題ないでしょう。kill-ringがいまいち理解できなくても、基本的には前にコピーしたテキストをペーストするにはC-y M-y...すれば良いということを覚えておけばよいでしょう(ちゃんと理解して使わないと色々大変なことになりますが)。

browse-kill-ring.el

Emacsの標準的なペースト方法を上で説明してきました。しかし多くの人はC-yM-yのUIは直感的でないと感じるでしょう。特性さえ理解してしまえばそのようなUIでも便利だと思う場面は多数あるのですが、やはり全体的に見てユーザーフレンドリーであるとは言い難いです。そこで紹介したいのがbrowse-kill-ring.elという拡張で、この拡張を導入することにより直感的かつ容易にペーストを行うことができます。

インストールするには次のURLからbrowse-kill-ring.elをダウンロードして、load-pathの通ったディレクトリに置いてください。

http://www.emacswiki.org/emacs/download/browse-kill-ring.el

次に以下のコードを~/.emacsに書きます。

(require 'browse-kill-ring)
(browse-kill-ring-default-keybindings)

browse-kill-ringを実行するにはM-x browse-kill-ringとするかM-yを押します。(browse-kill-ring-default-keybindings)によりM-y (yank-pop)の関数がadvice(*)されて、C-y (yank)の後にM-yした場合は従来通りの動作になり、それ以外の場合はM-ybrowse-kill-ringを実行できるようになります。M-yではなく他のキーに割り当てたい場合は(browse-kill-ring-default-keybinds)の代わりに次のようなコードを書きましょう。

;; C-x C-yをbrowse-kill-ringに割り当てる
(global-set-key (kbd "C-x C-y") 'browse-kill-ring)

(*) Emacsにおけるadviceというのは既存の関数に任意のコードを注入して動的に拡張する機構のことで、簡単に言えばいわゆるAOPを実現するための機構です。ユーザーはadviceにより関数を再定義せずに既存の関数を拡張して使いやすくしたり問題を修正したりすることができます。

browse-kill-ringを実行するとウィンドウが分割されて*Kill Ring*というバッファが表示されます。

browse-kill-ringを実行した図

このバッファでは次の操作が可能です。

| キー | 説明                             |
|------+----------------------------------|
| RET  | 選択中のkillをペーストして終了   |
| d    | 選択中のkillを削除               |
| e    | 選択中のkillを編集               |
| i, y | 選択中のkillをペースト           |
| n    | 次のkillを選択                   |
| p    | 前のkillを選択                   |
| s    | 前方検索(C-sも可)                |
| r    | 後方検索(C-rも可)                |
| l    | 正規表現で絞り込み               |
| q    | 終了                             |

基本的にはn/pkillを選択してRETkillをペーストして終了という使い方になると思います。また、上記の操作表を見ても分かるように、browse-kill-ringkillを削除したり編集したりしてkill-ringを整理する機能も持っています。kill-ringがごちゃごちゃになったときに使ってみると良いでしょう。

なおbrowse-kill-ringには他にも紹介していない機能があります。詳しくは*Kill Ring*バッファでhを押すか、M-x describe-modeを実行してください。余談ですが、このdescribe-modeは現在のモードのヘルプを出すコマンドです。キーバインドが分からなくなったり、どのような機能が提供されているか調べるときに大変便利です。

anything.el

この連載でも過去に取り上げてきた、そしてこれからも取り上げるであろう万能機能拡張であるanything.elでも実は容易にペーストを行うことができます。比較的最近に入った機能なので古いanything.elを使っている人は次のURLから最新のanything.elanything-config.elをインストールしておいてください。

次にkill-ringを扱うためのanything-c-source-kill-ringという情報源(*)をanything-sourcesに追加します。

(setq anything-sources '(<他の情報源>
                         anything-c-source-kill-ring))

(*) anythingは情報源(あるいはソース)という一種のプラグインを用いてデータを抽出し統合されたUIでそのデータを操作する機能をユーザーに提供します。ここではkill-ringという情報を抽出するプラグインanything-c-source-kill-ringを利用することによりanythingでkill-ringのデータを操作できるようにしています。anythingについてはhttp://dev.ariel-networks.com/Members/matsuyama/open-anything-emacsを参照するか「emacs anything」で検索してください。

これでanythingを実行すると次のようになります。

ユーザーはC-nC-pkillを選択できるほか、文字入力による絞り込みが可能になります。さらにanything-migemo.elというanythingプラグインを使うことにより、日本語もローマ字で絞り込んでペーストすることができます。このあたりはanythingの強力さを垣間見る感じがしますね。

なお、今回は例示のために文字数の少ないkillも表示されるようanything-kill-ring-thresholdという変数を0にしています。

;; すべてのkillを表示
(setq anything-kill-ring-threshold 0)

この変数は文字数の少ないkillを表示しないようにするフィルタ変数で、値が大きいほど表示される数が少なくなります。デフォルトでは10になっており、ほとんどの場合はこれぐらいが最適なので特に変更する必要はないでしょう。

ところで、anythingには一つの問題があります。それはanything-sourcesに設定された情報源が増えすぎて操作感が落ちてしまうという問題です。特に今回の例のように何をやりたいか(ペースト)が明確に分かっている場合には、その情報源だけを使用してanythingを実行するようにすれば、anything-sourcesに情報源を追加しなくて済みます。それにより、普段使うanythingを軽く保つことができます。それでは情報源を限定してanythingを実行する方法を示します。

まず、どの情報源を限定するか決めます。今回の場合はanything-c-source-kill-ringですね。次にその情報源を用いて次のようなコマンド(*)を定義します。

(*) defunで定義された関数の先頭に(interactive)という魔法があれば、それはコマンドだと思ってください

(defun anything-kill-ring ()
  (interactive)
  (anything 'anything-c-source-kill-ring nil nil nil nil "*anything kill ring*"))

この形は情報源を限定してanythingを実行するコマンドの雛形になります。独自にanythingのコマンドを作りたい場合は上記のコードのkill-ringの部分を適当に置き換えれば良いです。

上記のコードを~/.emacsに書いたらEmacsを再起動するか(*)、defunの最後の括弧の後にカーソルを移動してC-x C-e (eval-last-sexp)を押しましょう。C-x C-eはカーソルの直前のS式を評価します。

(*) Emacsは基本的に再起動するものではありません。全てを動的に変更することができるのです。

これでanything-kill-ringというコマンドが定義されました。M-x anything-kill-ringして情報源がanything-c-source-kill-ringのみに限定されてanythingが実行されていることを確認してください。

後はこのコマンドを適当なキーに割り当てるだけです。

(global-set-key (kbd "M-y") 'anything-kill-ring)

あるいはbrowse-kill-ring.elのように、C-yを押した後にM-yを押した場合は従来通りの動作で、それ以外はanything-kill-ringを実行する、という動作にしたい場合は次のコードを書いてください。

(defadvice yank-pop (around anything-kill-ring-maybe activate)
  (if (not (eq last-command 'yank))
      (anything-kill-ring)
    ad-do-it))

このコードは次のように読むことができます。

  • yank-popという関数にadviceを設定する(コードを注入する)
  • コードの注入の仕方はラップである(around)
  • 最後に実行したコマンド(last-command)がyankじゃなければ((not (eq ... ...)))
  • anything-kill-ringという関数を呼び出し
  • そうでなければ元の関数(yank-pop)を実行する

defadviceで実装したこの動作は前のglobal-set-keyM-yanything-kill-ringに割り当てるより便利だと思います。使ってみたいという人はanything-kill-ring関数のコードと上記のdefadivceのコードを~/.emacsに書いておきましょう。


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.