最新情報

2016年2月23日記事更新情報
M-x suspend-daily-emacs
2016年2月22日Emacs
#22 auto-insert-mode でファイル新規作成を迅速に (Software Design 2016年2月号掲載記事) Emacs yatemplate yasnippet インストール 設定 使い方
2016年2月21日Emacs
#21 定型文を瞬時に入力 yasnippet の実力 (Software Design 2016年1月号掲載記事) Emacs auto-yasnippet インストール 設定 使い方
2016年2月20日Emacs
#20 標準機能からyasnippetまで Emacs の入力支援 (Software Design 2015年12月号掲載記事) Emacs yasnippet インストール 設定 使い方
2016年2月19日Emacs
#19 同時押し&リピート 少し特殊なキー設定 (Software Design 2015年11月号掲載記事) Emacs key-chord smartrep インストール 設定 使い方

このエントリーを含むはてなブックマーク Buzzurlにブックマーク livedoorクリップ Yahoo!ブックマークに登録

M-x suspend-daily-emacs

病気のため、本日よりサイトの更新を一時停止します。
Software Design連載と るびきち塾(メルマガ) にエネルギーを注ぎ込みます。
治りましたら更新を再開しますのでそれまでお待ちください。

連載『るびきち流Emacs超入門』の先月号までの草稿を置いておきます。

タグ

#22 auto-insert-mode でファイル新規作成を迅速に (Software Design 2016年2月号掲載記事) Emacs yatemplate yasnippet インストール 設定 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

 特定の拡張子やファイル名のファイルを新規作成したとき、テンプレートが自動で挿入されると便利ですよね。今回はそれを可能にするauto-insert-modeを紹介します。既存の auto-insert-alistを変更する方法、yatemplateを使って新しく設定を追加する方法、2 つのアプローチを解説します。

2016年!

ども、るびきちです。
新年を迎えましたがあなたのEmacsの調子はいいですか?
おかげさまで本連載ももうすぐ2年になろうとしています。
Emacsの世界はとてつもなく広大で、これまで書いてきたことは氷山の一角に過ぎません。
まだまだあなたに伝えなければならないことは、山程残っています。
しかもEmacs自身も絶え間なく進化していて、今年中にEmacs25がリリースされるのは間違いありません。
Emacs25は、webkit埋め込み機能とダイナミックリンク(拡張ライブラリ)がサポートされます。
前者はたとえばグラフィカルなWebブラウザをEmacsのバッファで表示させることができます。
後者はユーザがC言語でEmacsの関数を記述できるようになり、elispだと遅くて実用的でなかったことが実現できるようになります。
将来的には「標準拡張ライブラリ」という形で標準関数が充実するでしょう。
また、パッケージシステムも拡張ライブラリ対応になり、高速な拡張ライブラリとelispの混成パッケージも登場することでしょう。
PerlのCPANやRubyのRubyGemsと同じような道になるのではないでしょうか。
Emacs24ではパッケージシステムにより、開発者・ユーザともに一気にelispの世界が開けましたが、Emacs25も大きな動きとなるのは間違いありません。
楽しみですね!

ファイル作成時に予め内容を用意しておく

テンプレートとスニペット

今回は新規ファイルの作成を迅速に行う方法をお話します。
ここで用語を明確に定義させてください。
yasnippetの解説において「テンプレート」と「スニペット」を同じ意味の言葉として使ってきましたが、今回は明確に区別することにいたします。
どちらも定型文、とくに穴埋めが含まれる文字列の雛型を意味しますが、対象が異なります。
テンプレートとは、ファイル全体の雛型で新規作成時に予め展開(挿入)されるべき内容を意味することにします。
今回は「テンプレート」が話題の中心になります。
スニペットとは、任意のタイミングで展開される定型文を意味することにします。
当然、yasnippetのスニペットは「スニペット」であり、スケルトンの類もスニペットになります。
テンプレートはスニペットを使って定義されるので、スニペットの使用例のひとつと言えます。

新規ファイルのテンプレート

新規ファイルのテンプレートを扱うには、Emacs標準のauto-insert-modeを使います。
グローバルマイナーモードなので、以下の1行を設定に加えればテンプレートが使用可能になります。

(auto-insert-mode 1)

テンプレートを定義する変数auto-insert-alistには予め以下のテンプレートが用意されています。

  • C / C++ヘッダ
  • C / C++コード
  • HTML
  • LaTeX
  • Ada
  • Man page
  • elisp
  • Texinfo

Emacsユーザにとって一番身近な例はelispのヘッダではないでしょうか。
elispを公開する場合、セミコロンの数も合わせて以下のテンプレートに従うよう規約に定められているのですが、毎回手作業で入力するのは馬鹿げています。
そういう決まり文句は*.elを新規作成したときにauto-insert-modeによって自動的に入力されるのが一番です。

;;; ファイル名 --- 説明

;; Copyright (C) 年 著者

;; Author: 著者 <メールアドレス>
;; Keywords: キーワード

;; This program is free software; you can redistribute it and/or modify
;; (略)

;;; Commentary:

;;; Code:

(provide 'ファイル名から拡張子を取り除いた文字列)
;;; ファイル名 ends here

auto-insert-alistを詳しく見てみる

auto-insert-alistは各要素が

(条件 . アクション)
あるいは
((条件 . 説明) . アクション)

の形をしたリストです。
条件はファイル名の正規表現かメジャーモードです。
また、自動挿入される内容に対して説明文をつけることもできます。
デフォルトの設定における条件・説明を抜き出すと、このようになります。

(("\\.\\([Hh]\\|hh\\|hpp\\)\\'" . "C / C++ header")
 ("\\.\\([Cc]\\|cc\\|cpp\\)\\'" . "C / C++ program")
 ("[Mm]akefile\\'" . "Makefile")
 html-mode plain-tex-mode bibtex-mode latex-mode
 ("/bin/.*[^/]\\'" . "Shell-Script mode magic number")
 ada-mode
 ("\\.[1-9]\\'" . "Man page skeleton")
 ("\\.el\\'" . "Emacs Lisp header")
 ("\\.texi\\(nfo\\)?\\'" . "Texinfo file skeleton"))

アクションはスケルトン、自動挿入されるファイルのファイル名、あるいは実行される関数を指定します。
ベクタ(配列)を指定すれば立て続けにアクションを実行できます。

auto-insert-alistを変更する

auto-insert-modeを愛用するようになると、当然auto-insert-alistを変更せざるを得なくなります。
多くの場合はauto-insert-alistに新しい設定を追加することになると思いますが、それは次節に回します。
ここではauto-insert-alistにすでに登録されている内容を変更する方法です。
実際デフォルトのauto-insert-alistに登録されているEmacs Lisp Headerはスケルトンでありながらも出来がよいからです。
しかしながら、*.elを新規作成するたびにわざわざEmacs Lisp Headerを展開しますかと聞かれるのは煩わしいものです。
ヘッダが要求されるのはあくまでも公開用elispのみであり、個人設定では不要です。
多くの場合、新規作成されるのは個人設定ファイルです。
そこでEmacs Lisp Headerを展開するのを「*.el」から「src/*.el」に変更し、公開用elispはsrcディレクトリに置けば解決できます。

(require 'autoinsert)
(dolist (x auto-insert-alist)
  (when (equal "\\.el\\'" (car-safe (car x)))
    (setcar (car x) "/src/.+\\.el\\'")))

この設定内容を詳しく説明するのは少し難しいですが、setcar関数によって auto-insert-alist 中の “\\.el\\'” をピンポイントで “src.+\\.el\\'” に変更してします。

ファイル作成時にスニペットを展開させる

扱いづらいauto-insert-alist

<f1> v auto-insert-alistでその値を表示してみると、紙面に掲載しきれないほどとてつもなく長くなります。
そのため前節では概略を説明するにとどめました。
auto-insert-modeを実用化するにあたってはauto-insert-alistを直接変更するのは賢明ではないからです。
auto-insert-alistで指定できるのは、スケルトン・穴埋めなしテンプレートファイル・関数のいずれかであり、どれも中途半端です。
スケルトンは表現力こそあれど可読性が低く、スニペット展開機能としてyasnippetに取って代わられました。
テンプレートファイルを指定しても、そのファイルの内容を字面通り挿入することしかできません。
関数定義は一般ユーザには荷が重すぎます。
そのままでは、せいぜい穴埋めなしテンプレートファイルで我慢するのが精一杯でしょう。

yasnippetをテンプレートにできないか!?

もしyasnippetファイルをテンプレートにできればとても嬉しいのではないでしょうか。
auto-insert-alistでアクションにベクタを指定すれば立て続けにアクションを実行できるので、yasnippetファイルの内容を挿入してからそれをyasnippetスニペットとして展開すれば可能です。
ファイル名に規約を設ければauto-insert-alistの設定も自動化できるでしょう。
ユーザ側がauto-insert-alistをいじらないでyasnippetをテンプレートにしてくれるパッケージはないでしょうか?
それを行うのがMELPAにあるyatemplateパッケージです。
M-x package-install yatemplateでインストールしてください。

yatemplateファイル名規約

yatemplateをインストールすると ~/.emacs.d/templates 以下に配置しているyasnippetファイルをテンプレートファイルとしてauto-insert-alistに登録します。
ファイル名は「数字 コロン 正規表現」のように指定します。
たとえば、Pythonのテンプレートならば以下のようになります。

00:test_.*.py
01:.*.py

数字は若い方が優先度が高くなります。
内部的には

(".*.py" . ACTION)
("test_.*.py" . ACTION)

の順にauto-insert-alistに登録されます。

yatemplateを使う

yatemplateを使うには以下の設定をします。

(yatemplate-fill-alist)
(auto-insert-mode 1)

新しくyatemplateファイルを追加すると、自動的にauto-insert-alistに反映されます。
これでauto-insert-alistをいじることなく手軽に高機能テンプレートを設定できるようになりました。

終わりに

筆者のサイト「日刊Emacs」は日本語版Emacs辞典を目指すべく日々更新しています。
手元でgrep検索できるよう全文をGitHubに置いています。
またEmacs病院兼メルマガのサービスを運営しています。
Emacsに関すること関しないこと、わかる範囲でなんでも御答えします。
「こんなパッケージ知らない?」「挙動がおかしいからなんとかしてよ!」はもちろんのこと、自作elispプログラムの添削もします。
集中力を上げるなどのライフハック・マインド系も得意としています。
登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#21 定型文を瞬時に入力 yasnippet の実力 (Software Design 2016年1月号掲載記事) Emacs auto-yasnippet インストール 設定 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

 今回は前回少し紹介した、穴埋め式で定型文を入力できるパッケージ「yasnippet」について深堀りしていきます。スニペット作成のチュートリアルから、auto-yasnippet パッケージによる即席スニペットの使い方までを解説します。

スニペット展開の王道yasnippet

ども、るびきちです。
11/8にJohn Wiegley氏がEmacsのメンテナに就任し、Emacs25リリースへ向けての動きで盛り上がっています。
彼は前世紀からたくさんのelispプログラムに関わっていて、長年熱心に活動しているのでこれからのEmacs界が楽しみです。
執筆時点で25.1への仕様凍結がされたので、そう遠くない日にリリースされるでしょう。

前回は基本的な入力支援機能に触れてから、yasnippetという強力なスニペット(テンプレート)展開パッケージを紹介しました。
yasnippetはMELPAダウンロードランキングのベスト10入りするほど定番になってきました。
これを使えば穴埋め式で定型文を確実に入力できるので、コーディングや文書作成が捗ります。

(yas-global-mode 1)
;;; スニペット名をidoで選択する
(setq yas-prompt-functions '(yas-ido-prompt))

スニペットを定義する

yasnippetはインストールした時点で各メジャーモード用にスニペットが用意されていますが、やはり自分で定義してこそyasnippetを使いこなしていると言えます。

特にコーディングの場面においては定型文入力の繰返しになります。
関数・クラス・メソッドにはイディオムのような決まった使い方があります。
それを登録することで確実に効率よく入力できます。

スニペット登録例

スニペット登録例として、前回登場したアドバイス定義のコードにします。
前回は完成形スニペットをスニペットの例として示しましたが、そこに到達するまでの道のりを解説します。

以下は筆者が実際に使っている設定です。
C-x v lでバージョン管理システムのログを表示し、そこでdを押したらM-x log-view-diffが実行されて前回のコミットとのdiffが表示ます。
しかしその後diffを表示しているウィンドウを選択してしまうのが不満なのでそれを解消するアドバイスを書きました。

(defun log-view-diff--noselect (&rest them)
  (other-window -1))
(advice-add 'log-view-diff :after 'log-view-diff--noselect)

アドバイスを定義するには、アドバイスの内容となる関数を定義し、advice-addでその関数を登録します。
関数名は任意ですが、どの関数に対するアドバイスかを明確にするため、筆者は「元の関数名–アドバイス名」の形式にしています。

その骨格だけを抜き出すと、次のようになります。

(defun log-view-diff--noselect (&rest them)
  )
(advice-add 'log-view-diff :after 'log-view-diff--noselect)

3つのdirective

手始めに、これをスニペットにしましょう。
M-x yas-new-snippetを実行します。
すると、*new snippet*バッファに切り替わり、name、key、bindingという3つのdirectiveが表示されます。
この時点で新規スニペット登録用スニペットが展開されています。

# -*- mode: snippet; require-final-newline: nil -*-
# name: 
# key: 
# binding: direct-keybinding
# --

nameはスニペット名なのですが、実際はスニペットの1行説明文で何を定義しているかを書きます。
略語(key)を思い出せなくてもM-x yas-insert-snippetを使えばnameを手がかりにスニペットを展開できます。
そのため、スニペットに使われているキーワードをスペースで区切って羅列するのは良いアイデアです。

keyはスニペットを展開する略語です。
特に使用頻度の高いスニペットに対しては短くて覚えやすいものを設定しておくことで劇的に使い勝手が向上します。
使用頻度が低いものについては忘却の彼方へ追い遣られるので適当に考えてもよいでしょう。

bindingはそのスニペットを展開するキーバインドです。
たとえばC-x C-i C-iを指定すれば、そのキーでスニペットを展開できます。
使わない場合はC-dで入力をキャンセルしてください。

スニペット本体を記述する

スニペット本体は「# –」以下の行に記述します。
基本的にはここに記述した文字列がそのままスニペットになるのですが、スニペット展開の指令に使われる「$」と「`」、そして「\」そのものについてはそれぞれ「\$」、「\`」、「\\」とエスケープする必要があります。
この例ではエスケープ不要なのでそのまま貼り付ければいいです。
nameとkeyはそれぞれadvice-add、adviceと指定し、bindingは無指定にしました。

# -*- mode: snippet; require-final-newline: nil -*-
# name: advice-add
# key: advice
# --
(defun log-view-diff--noselect (&rest them)
  )
(advice-add 'log-view-diff :after 'log-view-diff--noselect)

スニペットをテストする

ここでC-c C-tを押せばスニペットが正しく展開されるかテストができます。
そのまま貼り付けた場合であってもエスケープ漏れの可能性があるので、テストすることをおすすめします。

場合によってはスニペット自体は正しくてもテスト展開でエラーになることがあります。
スニペットにはelispの式を埋め込めるのですが、テスト時と実運用時では環境が異なるためです。
たとえばファイル名を表す変数・関数の buffer-file-name はテストバッファではnilとなるため、elisp式展開部分ではerrorと表示されます。
それでも、他の部分ではテストができるので役立たずではありません。
テストでエラーが起きたときには、元のバッファで展開してください。
これでうまくいったのであれば問題ありません。

スニペットを登録する

無事にテストがうまくいったらスニペットのバッファに戻り、C-c C-cで登録します。
すると、「Choose or enter a table」というプロンプトが出て登録するメジャーモードを尋ねてきます。
多くの場合M-x yas-new-snippetを実行したバッファのメジャーモードとなるので、そのままRETで確定します。
次に新規作成したスニペットについては「Looks like a library or new snippet. Save to new file」と尋ねてきますが、これもそのままyで確定します。
これでスニペットの登録が終わり、元のバッファに戻ります。

穴埋めを設定する

この時点でadvice TABと入力することで貼り付けたスニペットがそのまま展開されます。
これはこれで使用例を貼り付けたことになるので役立つのですが、機能的には略語展開となんら変わりありません。
スニペットがスニペットらしくあるためには穴埋めを設定してナンボです。

とはいえ穴埋めを設定するかどうかは、そのスニペットの使用頻度と相談すべきです。
あまりにも使用頻度が低いと、穴埋め設定が面倒に感じてしまいyasnippetに悪い印象を与えかねないからです。
使用例を貼り付けただけのスニペットでも、十分な場合があることも事実です。
今回のアドバイスのスニペットのようにこれからも使用されることが予想される場合は迷わず穴埋めを設定してください。

穴埋めは「$数字」($1、$2〜)あるいはデフォルト値付きで「${数字:デフォルト値}」と指定します。
スニペットを展開すると、数字の順番でカーソル位置が穴埋め位置に移動し、入力できるようになります。
圧巻は同じ番号の穴埋めを複数個置いたときで、入力するたびに同時に該当する穴埋めの文字列が変化することです。
スニペット登録時にnameを入力すると同時にkeyにも同じ文字列が入力されたのも、この現象です。

「$0」は特別な意味があり、スニペット展開終了後に置かれるカーソル位置を示します。

これらをふまえた上で穴埋めを設定しましょう。
コードから生まれたスニペットの場合はデフォルト値はそのまま保持しておくと記憶をたどりやすいです。
$1と$2は同じ文字列になるので、2度目の登場以降はデフォルト値なしで記述します。

# -*- mode: snippet; require-final-newline: nil -*-
# name: advice-add
# key: advice
# --
(defun ${1:log-view-diff}--#{2:noselect} (${3:&rest them})
  $0)
(advice-add '$1 :${4:after} '$1--$2)

他にも「`」で囲んでelisp式を埋め込んだり「${数字:$$(yas-choose-value 文字列リスト)}」で文字列の選択肢を表示できたりします。

即席スニペットでもっと身近に!

普段の文字入力で起こる同じパターンの入力

yasnippetは入力をとても効率よくしてくれますが、それだけでは予め定義されたスニペットでしか有効ではありません。
普段の文字入力でも同じようなパターンを入力することはよくあります。
たとえば以下の3行を入力する場合を考えてみましょう。
これは僕が関わったelispプログラムの一部です。

(key (plist-get args :key))
(switch (plist-get args :switch))
(before (plist-get args :before))

おそらく共通部分だけを書いてコピーして異なる部分を後で入力することを真っ先に思い付くことでしょう。

( (plist-get args :))

と書いてから一旦C-a C-k C-kでカットし、C-yを3回押せば3つになります。

( (plist-get args :))
( (plist-get args :))
( (plist-get args :))

その後でkey/switch/beforeを埋め込みむのですが、少しEmacsに慣れているならばC-x C-n (set-goal-column)を使うと便利です。
これを実行すると、C-p/C-nで行移動したときに、現在位置の真上/真下ではなくて実行したときの桁に移動するというものです。
「:」の後にカーソルを移動した後にC-x C-nを押してからkeyと入力します。
次にC-nを押すと次の行の:の後に移動するのでswitch、さらに下のbeforeと入力します。

( (plist-get args :key))
( (plist-get args :switch))
( (plist-get args :before))

そして、1行目の最初の括弧に移動しC-x C-nを押して、key/switch/beforeと埋めていけばおしまいです。
入力が終わったらC-u C-x C-nでgoal columnを解除しておきます。
なぜ後の方を最初に入力したかというと、前の方を入力すると桁がずれてしまうからです。

キーボードマクロを使うの方法の方が楽です。
予め以下のように入力しておきます。

key
switch
before

そして、C-kでカットし、その単語が現れる部分をC-yで貼り付けながら入力して次の行に移動するところまでをキーボードマクロにすれば楽にいけます。

auto-yasnippetを使う

こういう場合にyasnippetの展開が使えれば便利ですが、たった1度の入力のためにスニペットを定義するのはあまりにも大袈裟すぎます。
そこでauto-yasnippetパッケージによる即席スニペットを使えば普段の文字入力においてもyasnippetの展開の恩恵が受けられます。
「M-x package-install auto-yasnippet」でインストールしましょう。
ついでにmykieパッケージもインストールしておけば対になるコマンドを1つのキーに割り当てられて便利です。
以下の設定をしましょう。

(setq aya-create-with-newline t)
(mykie:global-set-key "C-x C-y"
  :default aya-expand :C-u! aya-create)

yasnippetのスニペットは読みやすいですが即席で使うにはいささか煩雑です。
そこでauto-yasnippetではより入力しやすいシンプルな構文を採用し、内部でスニペットに変換しています。

お手軽1行即席スニペット

auto-yasnippetには2つのタイプの即席スニペットがあります。
お手軽タイプは現在行を即席スニペットにする機能限定版です。
regionが設定されていない状態で、かつ穴埋め部分が1つ、かつその行に「~」が含まれていないときに使えます。
先程のplist-getの場合がまさにこれが使えるケースです。
お手軽タイプは穴埋め部分を「$」と入力して使います。

($ (plist-get args :$))

行末にてC-u C-x C-y (aya-create)を実行すると「$」が消えスニペット展開状態になるのでkey TABと入力すればいいです。
すでにこの状態で即席スニペットが登録されたので、次の行にてC-x C-y (aya-expand)で展開します。
同じように展開されるのでswitchと入力し、同様にbeforeも入力します。

フルバージョン即席スニペット

お手軽タイプは確かに便利ですがキーボードマクロに毛が生えた程度のものに過ぎません。
穴埋め部分が複数個ある場合や即席スニペットが複数行にわたる場合はフルバージョンを使う必要があります。
フルバージョンは穴埋め部分の前に「~」を付けるか「`〜’」で囲みます。
「~」の後は英数字・ハイフン・アンダーバーまでが穴埋め部分とみなされます。
それら以外を含む場合は「`〜’」を使うことになります。

plist-getをフルバージョンにすると、下記のどれかになります。

(~key (plist-get args :~key))
(`key' (plist-get args :`key'))

C-u C-x C-yを押すと穴埋め部分を指定する記号が削除され、即席スニペットが登録されます。
あとは同様にC-x C-yで展開していきます。

このように穴埋め部分の文字列が同じ場合は同じものとみなされます。
フルバージョンでは穴埋め部分を複数個指定できるようになった代償として、同じ文字列を入力する必要があります。
明らかに穴埋め部分が1つの場合はお手軽タイプが楽です。

フルバージョンが本領発揮するのは、複数行にわたる即席スニペットです。
この場合はregionを指定してからC-u C-x C-yで登録してください。

終わりに

筆者のサイト「日刊Emacs」は日本語版Emacs辞典を目指すべく日々更新しています。
手元でgrep検索できるよう全文をGitHubに置いています。
またEmacs病院兼メルマガのサービスを運営しています。
Emacsに関すること関しないこと、わかる範囲でなんでも御答えします。
「こんなパッケージ知らない?」「挙動がおかしいからなんとかしてよ!」はもちろんのこと、自作elispプログラムの添削もします。
集中力を上げるなどのライフハック・マインド系も得意としています。
登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#20 標準機能からyasnippetまで Emacs の入力支援 (Software Design 2015年12月号掲載記事) Emacs yasnippet インストール 設定 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

Emacs の操作性アップシリーズ、今回は入力支援編です。Emacsに標準で備わる、動/静的略語展開、スケルトンといったEmacs 標準の入力支援についておさらいしたあと、これらを統合したパッケージとも言える「yasnippet」を紹介します。

確実なテキスト入力を

ども、るびきちです。
先々月、先月と操作性を高めるためにはキーボードでの操作をしっかりと整えることだとお伝えしました。
キーバインドを適切に設定しておけば、いつでも素早くコマンドが呼び出せるからです。
それと同時に、入力支援機能を活用しミスタイプなく確実に目的の入力する方法を確立すれば一気に使いやすくなります。

標準的な入力支援

動的略語展開

まず真っ先に使うべき入力支援機能はdabbrev(動的略語展開)です。
長い文字列の入力を省力化する重要な機能です。
この機能がないテキストエディタは正直、使いものになりません。

テキストエディタを使っていると、どうしても同じ単語を何度もタイプすることが多くなります。
しかし、毎回馬鹿正直にタイプすると、時間かかるしタイプミスが起こりやすくなります。
Emacsではその問題に対する解決策が用意されています。
最初の数文字をタイプしてからM-/を押してみましょう。
すると「魔法」が発動し、その数文字から始まる単語に補完されます。

たとえば、interの後にM-/を押すとinternet、interesting、interactive、interactivelyなどの単語に変化します。
再度M-/を押すと別な単語になります。

カラクリはというと、入力された文字列から始まる単語をカーソルに近い方から順次探索していくことです。
カレントバッファで見付からない場合は他のバッファからも探索します。
知ってしまえば当たり前に思える仕組みも、初めて使うとあたかも魔法が発動したかのような感動を覚えることでしょう。

入力支援基本のキとしてM-/は常用しましょう。

略語展開

動的略語展開が動的ならば、静的な略語展開もあるのではないか?もちろんあります。
略語展開はシンプルに略語から長い文字列を展開する機能です。
動的略語展開が動的なのは、変化する単語の結果がバッファの内容に依存するからです。
対して略語展開は変化する単語の結果が決まっています。

たとえばinetからinternetに展開されるように略語展開の設定ができます。
その上でM-x abbrev-modeでマイナーモードを有効にし、inetとタイプし、スペースやカンマなどの単語区切り文字を入力すれば、internetと展開されます。

この機能は後で紹介するyasnippetに完全に置き換わってしまうので、詳しくは述べません。

もし日本語入力にSKKを使っているのならば、アスキー文字から変換する機能があります。
たとえば「/file」→「ファイル」のように変換できます。
SKKは単語登録中心主義であるため、よく使う略語をガンガン登録すれば快適に入力できます。
そう考えればSKKそれ自体が略語展開の機能を持っているといえます。
筆者は長年この機能を略語展開として使っています。

hippie-expand

M-x hippie-expandは動的略語展開、略語展開、ファイル名補完、シンボル補完などを統合した単語補完の十徳ナイフです。
M-/よりも高機能である反面、望みの補完をしてくれないことがあるのが玉に瑕です。

そこで筆者はhippie-exp-extパッケージにてhippie-expandの機能性を活かしつつ補完の目的に沿ったコマンドを作成しました。
M-x hippie-expand-dabbrev-limited-charsは、1バイト文字限定の動的略語展開及び、「-」あるいは「_」から入力した場合に限り長い文字列を途中から補完できるようにしました。
たとえば「-li」から「hippie-expand-dabbrev-limited-chars」と補完できます。
M-x hippie-expand-file-nameはファイル名補完に限定したコマンドです。

スケルトンによる定型文入力

コンピュータの世界におけるスケルトンとは骸骨…ではなくてコードの骨格を意味します。
Emacsにおけるスケルトンとはパラメータを対話的に入力することで定型文を入力するコマンドです。
スケルトンのコマンドを実行することを「スケルトンを展開する」といいます。

たとえば、以下のコードを挿入するスケルトンを考えます。

(defun find-file--my-advice (&rest them)
  )
(advice-add 'find-file :around
            'find-file--my-advice)

これはEmacs 24.4から使える新しいアドバイス定義法で、関数を再定義せずに関数の挙動を変更できます。
そのうち、以下の情報が必要なのでミニバッファから入力を求めます。

説明 変数名 具体的な文字列
元の関数名 symbol find-file
場所 where around
アドバイス名 name my-advice

これをスケルトンで表現すると以下のようになります。
入力が複数なのでスケルトンそのものではなく、コマンド定義とスケルトン展開の合わせ技です。

(defun emacs-lisp-insert-advice-add (symbol where name)
  (interactive "s元の関数名: \ns場所: \nsアドバイス名: ")
  (skeleton-insert
   '("" nil                             ;おまじない
     "(defun " symbol "--" name " (&rest them)" > \n
     _ ")" > \n
     "(advice-add '" symbol " :" where > \n
     " '" symbol "--" name ")" > \n)))

スケルトン定義において「> \n」がインデントして改行するという指定で、「_」が展開後のカーソル位置です。

M-x emacs-lisp-insert-advice-addを実行し、必要な情報を入力すれば上記のコードが挿入されます。
しかし、わかりづらいですよね。

真打yasnippet

略語展開とスケルトンの融合

略語展開は単に略語と展開結果の対応を表したもので、大した機能ではありません。
入力作業全体から見てみれば略語→単語の略語展開による恩恵は微々たるものです。

一方で、略語展開の結果に関数(コマンド)を渡すことができます。
スケルトンはコマンドなので略語展開の結果にスケルトンを割り当てられます。
それをうまくやっているのがEmacs標準添付のpython.elによるpython-modeです。
以下の設定を加え、if/while/for/try/def/classの後にスペースを押せばスケルトンが展開されます。

(setq python-skeleton-autoinsert t)

スケルトンの問題

メジャーモード側で略語展開+スケルトンの設定をしてくれているのは、ユーザからすれば親切といえます。
しかし、スケルトンはS式であるため、細かい指定こそできるものの可読性が低いという欠点があります。
穴埋めが複数あるスケルトンを定義するには、emacs-lisp-insert-advice-addのようにコマンドを定義しなければなりません。
テンプレート展開はテキストエディタを効率よく使いたい一般ユーザとしては是非とも身に付けておきたいところですが、elispプログラミングを要求するのは敷居が高すぎます。
読みづらいのはともかくとして、高々定型文のテンプレートを登録するのになぜelispの知識が必要なのでしょうか!!!

yasnippet登場

スケルトンの使いづらさからか、テンプレート展開のelispは数多く存在します。
スケルトンのようにS式ベースのテンプレート展開elispもありますが、やはりelispの知識を要求するので一般ユーザにはおすすめできません。
elispがわかる人にとっても可読性の問題があり、おすすめできません。
elispにはヒアドキュメントなどの高可読性の文字列表現がサポートされていないので、文字列を表現するには常に文字列リテラルを使う必要があります。
elispの言語としての限界がそこにあります。

そうなると、必然的にテンプレートを独立したファイルに記述する方式が望まれます。
この方式のelispもいくつか登場してきましたが、今ではyasnippetが定番です。

スニペットの例

先程のアドバイス定義のテンプレート(yasnippetではスニペットという)をyasnippetで定義すると、このようになります。
暗号的なスケルトンと比較すれば可読性は明らかに上です。

# -*- mode: snippet -*-
# name: advice-add with function
# key: advice
# --
(defun ${1:symbol}--${2:name} (${3:&rest them})
  $0)
(advice-add '$1 :${4:where}
  '$1--$2)

冗長になっていますが、定義時(M-x yas-new-snippet)に予め雛型が用意されるので丸暗記する必要はありません。
スニペットの先頭から「#」で始まる行はコメントです。
nameはスニペットの1行説明文、keyはそのスニペットに展開する略語です。
スニペットの内容は「# –」行の後に記述します。

スニペットの実体は、穴埋め部分を含むことができる定型文です。
穴埋め部分が存在しない場合は、普通の略語展開と同じ機能です。

穴埋め部分は「${1:symbol}」のように、数字と表示文字列を指定します。
数字は穴埋めされる順番で、表示文字列は穴埋めの説明の役割とデフォルト値の役割を果たします。
スケルトンとの対比のため「${4:where}」と書いていますが、aroundと指定するケースが多いのならば「${4:around}」と書いてデフォルト値として使いましょう。
スニペット展開時はこの部分で文字列を入力することになります。

表示文字列を書いていない「$1」のような指定は、穴埋め部分で入力されたのと同じ文字列に置き換わります。

最後に「$0」はスニペット展開後に移動するカーソル位置です。

インストールと設定

yasnippetはMELPAに登録されているのでM-x package-installからインストールできます。
パッケージをインストールするとyasnippet.el本体だけでなく、数多くのスニペットも同時にインストールされます。
そして、以下の設定をします。

(yas-global-mode 1)
;;; スニペット名をidoで選択する
(setq yas-prompt-functions '(yas-ido-prompt))

スニペットの置き場は yas-snippet-dirs で指定しますが、デフォルトはこうなっています。

("~/.emacs.d/snippets" yas-installed-snippets-dir)

~/.emacs.d/snippets は自分で定義したスニペットを置くディレクトリです。
yas-installed-snippets-dir はパッケージによってインストールされたスニペットディレクトリの変数です。
他のスニペットも使いたい場合は yas-snippet-dirs を適宜設定してください。

スニペットを展開する

スニペットを展開するには、略語(key)を入力してTABを押します。
穴埋め部分が存在する場合はそこにカーソルが移動し、入力できるようになるので入力したらTABで次の穴埋め部分に移動します。
穴埋め部分を空白にするにはC-dです。
すべての穴埋めが終われば展開終了です。
ミニバッファで情報を入力するスケルトンと違い、穴埋め部分にカーソルが移動するので、入力するべきテキストが明らかになるのが強みです。

略語が思い出せない場合はM-x yas-insert-snippetで展開します。
またM-x yas-describe-tablesでスニペットを一覧します。

終わりに

今回は基本的な入力支援をおさらいしてから、yasnippetという強力なテンプレート入力の入口を紹介しました。
yasnippetはそのまま使うだけでも入力を省力化できますが、可読性が高いフォーマットなので自分でスニペットを定義すれば面白いです。
次回はスニペット定義・テスト方法から始まり、いろいろな応用技を見ていきます。

筆者はサイト「日刊Emacs」を運営し、毎日パッケージの紹介記事を書いています。
マイナーなものも紹介しているので、新たなパッケージを求めている人の役に立てば幸いです。

また、EmacsユーザのQOLを上げるための厳選した情報を週間メルマガで配信しています。
Emacsについてはもちろんのこと、ライフハックなどいろいろな分野について書いています。
登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#19 同時押し&リピート 少し特殊なキー設定 (Software Design 2015年11月号掲載記事) Emacs key-chord smartrep インストール 設定 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

 前回に引き続き、Emacs の操作性を決定づけるキーバインド設定についてお話します。前半では「同時押し」というEmacsには今までなかった操作を導入するパッケージ「key-chord」を、後半では繰り返し入力するようなコマンドを短くできるパッケージ「smartrep」を紹介します。

操作性を高めよう

ども、るびきちです。
「Emacsの使い勝手は操作性で決まる」という流れで先週はキーバインドの設定を中心にお話してきました。
Emacsはキーボード操作が中心なので、いかに賢くキーバインドを設定するかが操作性を決定付けます。

言うまでもありませんが、よく使うコマンドはキーに割り当てて然るべきです。
そのためには、標準でglobal-set-keyとdefine-key関数が用意されています。
ですが、個人的にキーバインドの設定をする際にはbind-keyパッケージの同名のマクロを使用する方が賢明です。
短く記述でき、モードに上書きされない強制設定(bind-key*)ができ、個人用キーバインドの列挙(M-x describe-personal-keybindings)もできるからです。

キーバインドの資源は有限なので、なんでもかんでもキーに割り当てるわけにはいきません。
regionやC-uの有無で挙動を変化させるコマンドを定義するmykieパッケージはキーバインドを有効活用してくれます。
これを使えばたとえばC-u C-wやregion無しのC-wに機能を割り当てられるからです。
mykieで設定できる「状況」はとても多いので、突き詰めていけば1つのキーにたくさんの機能を割り当てられます。

あまり使用頻度が高くないコマンドはキーバインドよりも名前で覚えるでしょう。
M-xを非常に使いやすくするsmexパッケージを使えば、そういうコマンドをすぐに呼び出せます。
また、長い名前のコマンドや押しづらいキーバインドのコマンドはdefaliasで短い別名を付けるとM-xから呼び出しやすくなります。

今回は一風変わったキーバインド設定方法を紹介します。

同時押し・連打にキーを割り当てるkey-chord

キーボード同時押しという新たな境地

割り当てられるキーを増やすには、自分用のプレフィクスキーを用意するのがEmacs的に最も自然な方法です。
複数個プレフィクスキーを用意したり、あまり割り当てられていないプレフィクスキー(M-sやM-g)を使えばかなりの数のコマンドをキーに割り当てられます。

そんな中、ちょっと変わったキー割り当て方法を提供するのがMELPAのkey-chordパッケージです。
chordとは和音であり、key-chordとはキー同時押しを意味します。
たとえばkとlを同時に押すことでview-modeを実行する…なんてことができるようになります。
当然、同時押しによるコマンド発動はEmacs的にはまったく新しい発想であり、どのパッケージにも使われていません。
同時押し対象の2つのキーを自由に選べばいいのです。
マウスジェスチャーがクリックとドラッグしか能がないマウスに新しい風を吹き込んだように、key-chordは新たな操作性を提供します。

本当の「同時押し」はない

少し考えてみればわかることですが、本当に寸分の狂いもなく同時にキーを押すことは不可能です。
どうしても0.01秒単位のタイムラグが生じます。
そこで、2つのキーが押された間隔が一定時間よりも短いときに「同時押し」とみなされます。
その間隔の設定は実際に使ってみて試行錯誤する必要があります。
間隔が短すぎれば同時押ししたつもりでもコマンドが発動しません。
逆に長すぎれば別々のキーのつもりが同時押しとみなされてコマンドが誤爆してしまいます。

たとえばjとkの同時押しはホームポジション上なので押しやすいです。
通常のローマ字入力では使わないのできわめて有効な選択となります。
しかし、拡張ローマ字AZIKでは「じん」「くん」と入力するときに使うので誤爆の可能性が出てきます。
AZIKユーザはvや@を使えば誤爆しにくくなります。

素早く連打する

2つのキーは同一のキーを選択することもできます。
そのときは同時押しではなくて、素早く連打することでコマンドを発動させます。
この場合でも当然、誤爆のリスクと背中合わせです。
2つのキー(文字)が立て続けに登場する確率が低くなるキーを選択する必要があります。
間隔も適度に短く設定しなければなりません。

さらに、文字キーを連打キーに設定した場合、入力してから表示されるまでのタイムラグが生じます。
連打によるコマンド発動を待っているのだから当然です。
次の文字を素早く打てば問題ありません。

key-chord.elの導入

(require 'key-chord)
;;; タイムラグを設定
(setq key-chord-two-keys-delay 0.04)
(setq key-chord-one-key-delay 0.15)
(key-chord-mode 1)
;;; 設定例
(key-chord-define-global "kl" 'view-mode)
(key-chord-define emacs-lisp-mode-map "df" 'describe-function)
(key-chord-define-global "vv" 'find-file)

それではkey-chordの設定例を示しましょう。
タイムラグの設定は必須です。
ここでは同時押しで0.04秒、連打で0.15秒に設定しています。
連打は本気で素早く打たないと発動しません。

関数名から推測されるようにグローバルマップに作用する key-chord-define-global と任意のキーマップに作用する key-chord-define があります。
それぞれglobal-set-keyと define-key に相当します。

リピートを活用する

立て続けに実行されるコマンドは1ストロークで

Emacsのコマンドには立て続けに実行されうるものと、そうでないものがあります。
カーソル移動やウィンドウのリサイズは連続的に実行されやすいです。
そういうコマンドは1ストロークであればとても実行しやすいです。
C-fやM-fは連打するだけで移動を繰り返せます。

一方、ウィンドウのリサイズを行うC-x {やC-x }は連続的に実行されうるにもかかわらず2ストロークです。
ウィンドウの大きさを視覚的に確認しながらリサイズするにはC-x {を繰り返す必要があって面倒です。

よって、連続して実行されうるコマンドは1ストロークのキーに割り当てることが望ましいです。
「M-英大文字」は会いているのでそういうコマンドを割り当てるとよいでしょう。

また、グローバルマップではM-pとM-nにはコマンドを割り当てていません。
それはメジャーモードにとって相応しいカーソル移動コマンドを割り当てられる余地を残しています。

repeatを活用する

C-x {のように繰り返し実行される複数ストロークコマンドにも救済措置が用意されています。
それはC-x zに割り当てられているrepeatコマンドです。
C-x zは直前のコマンドを繰り返します。
さらに繰り返すにはプレフィクスキーC-xは不要でzを押すだけです。
C-x zは次項で紹介するsmartrep的なコマンドです。
これによりC-x {を3回実行する場合はC-x { C-x z zと、1ストローク節約できます。

とはいえ「立て続けに実行されるコマンドは1ストロークに割り当てる」という原則にならえば、repeatも1ストロークのキーに割り当て直した方が快適です。
たとえば、「C-,」に割り当てたとすれば、C-x {×3はC-x { C-, C-,と、2ストローク節約できます。

M-x repeatをC-,に割り当てる設定はこうなります。

(global-set-key (kbd "C-,") 'repeat)

または

(require 'bind-key)
(bind-key* "C-," 'repeat)

プレフィクスキーを省略させるsmartrep

特定のコマンドを繰り返し実行するときにプレフィクスキーを省略させるsmartrepパッケージがMELPAにあります。
smartrepはsmart repeatの略で、繰り返しを快適にします。
repeatを1ストロークに割り当てれば、直前のコマンドのみのプレフィクスキーを省略できますが、smartrepを導入すれば省略対象のコマンドを複数個持てます。
hydraという類似品が最近登場しましたが、本稿の対象読者を考慮して日本人作かつユーザ数の多いsmartrepを紹介します。

smartrepを使うにはrequireした後にsmartrep-define-key関数を使います。
それでは2つ具体例からsmartrepの使い方を見ていきましょう。

org-modeで見出し移動を快適にする

org-modeには見出し移動コマンドがたくさん用意されています。
一度見出し移動コマンドを実行したら、次も見出し移動コマンドが実行される可能性があります。

C-c C-n 次の見出しへ
C-c C-p 前の見出しへ
C-c C-u 上の見出しへ
C-c C-f 同じレベルの次の見出しへ
C-c C-b 同じレベルの前の見出しへ

これらのコマンドを実行中にC-cを省略できるようにするには、以下の設定をします。

(require 'smartrep)
(require 'org)
(smartrep-define-key org-mode-map "C-c"
  '(("C-n" . org-next-visible-heading)
    ("C-p" . org-previous-visible-heading)
    ("C-u" . outline-up-heading)
    ("C-f" . org-forward-heading-same-level)
    ("C-b" . org-backward-heading-same-level)))

これによりC-c C-u C-c C-f C-c C-nがC-c C-u C-f C-nのように操作できます。
実際にやってみると、見出し移動がとても快適になることがわかります。
smartrep状態を解除するにはC-gを押すか、登録されていないキーを押します。
登録されていないキーを押すと、元のコマンドが実行されます。
たとえばaを押すとaが入力されます。

ウィンドウ操作をひとまとめにする

ウィンドウを操作する代表的なコマンドはC-xをプレフィクスキーにしています。
ウィンドウの分割状態を作成するには、分割したりリサイズするコマンドを連続的に使う必要があります。
そういう場合にsmartrepはとても威力を発揮します。

ここでは以下のウィンドウ操作コマンドをsmartrepで扱えるようにします。
ついでにC-x -でウィンドウを縦方向に縮めるコマンドにしておきます。
元々はそのウィンドウの行数に合わせてウィンドウを縮めますが、ここではC-x ^の対になるコマンドが欲しいからです。

C-x o 隣のウィンドウに切替える
C-x 0 ウィンドウを削除する
C-x 1 他のウィンドウをすべて削除する
C-x 2 上下分割する
C-x 3 左右分割する
C-x { ウィンドウを横方向に縮める
C-x } ウィンドウを横方向に広げる
C-x + ウィンドウの大きさをそろえる
C-x ^ ウィンドウを縦方向に広げる
C-x – ウィンドウを縦方向に縮める
(require 'smartrep)
(smartrep-define-key global-map "C-x"
  '(("o" . other-window)
    ("0" . delete-window)
    ("1" . delete-other-windows)
    ("2" . split-window-below)
    ("3" . split-window-right)
    ("{" . shrink-window-horizontally)
    ("}" . enlarge-window-horizontally)
    ("+" . balance-windows)
    ("^" . enlarge-window)
    ("-" . shrink-window)))

使ってみればわかりますが、この設定を施した後はウィンドウを適切な大きさに分割させることが楽しくなることうけあいです。

その他の方法

 操作性を快適にする方法は他にもいろいろあります。
 key-comboパッケージは同じキーを連続的に使用したときの挙動を変えられます。C-a 2回でバッファ先頭に移動したりできます。
 mag-menuパッケージは強力なメニューインターフェースを提供します。メニューを経由して複数の機能をひとまとめにできます。

終わりに

今回も前回に引き続きキーバインド特集でしたが、今回は一風変わった方法を紹介しました

筆者はサイト「日刊Emacs」を運営し、毎日パッケージの紹介記事を書いています。
マイナーなものも紹介しているので、新たなパッケージを求めている人の役に立てば幸いです。

また、EmacsユーザのQOLを上げるための厳選した情報を週間メルマガで配信しています。
Emacsについてはもちろんのこと、ライフハックなどいろいろな分野について書いています。
登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#18 操作性アップ! スマートなキーバインド設定 (Software Design 2015年10月号掲載記事) Emacs mykie bind-key smex インストール 設定 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

キーバインドを設定するいろいろな方法

ども、るびきちです。
本連載も18回目、連載開始から1年半が経過しました。
今までいろいろなテーマについて書いてきましたが、重要なことを書き忘れていました。
それは、「Emacsの使い勝手は操作性で決まる」ということです。
操作性を大きく左右する要因は、やはりキーバインドを賢く設定することです。
今回はキーバインドを設定するあらゆる方法を紹介します。

標準の方法

global-set-key

まずはキーバインドを設定する標準の方法を紹介します。
Emacs全体で使えるキーバインドを設定するには、global-set-key関数を使います。
この関数はこれまでの連載記事でのパッケージの設定で何度も出て来ましたが、改めて述べておきます。

global-set-keyは、グローバルキーマップ(global-map)にてコマンドをキーに割り当てます。
すでにコマンドが割り当てられている場合は新たなコマンドに置き換わります。
キーの指定方法はいくつかありますが、kbd関数を使ってEmacs記法で指定するのが一番わかりやすいです。
<f1> cでそのキーのEmacs記法と現在割り当てられているコマンドがわかります。

以下の例では、C-tにother-windowを割り当てています。
デフォルトではC-tにはtranspose-charsが割り当てられていますが、other-windowに取って代わられます。

(global-set-key (kbd "C-t") 'other-window)

global-mapは優先度が低いことに注意してください。
global-mapに割り当てられているキーにメジャーモードでキーを割り当てている場合はメジャーモード側が優先されます。
さらに有効なマイナーモードで割り当てられている場合は、マイナーモード側が優先されます。
diredでpやnを押せば文字入力されるかわりにカーソルが上下移動するのはdired側がキーを割り当てているからです。

常にC-tをother-windowにしたい場合、上記の設定ではうまくいきません。
diredでのC-tはimage-dired関係のプレフィクスキーになっているため、diredでC-tを押してもother-windowは実行されません。

define-key

キーバインドを設定する汎用的な関数はdefine-keyです。
define-keyはキーマップ、キー、コマンドの順に指定します。
キーマップをglobal-mapにしたとき、global-set-keyと等価になります。

メジャーモードのキーマップは慣習的にモード名に「-map」をつけた変数になります。
たとえば、emacs-lisp-modeならばemacs-lisp-mode-mapです。
メジャーモードはM-: major-modeを実行すればわかります。
emacs-lisp-modeと出たのならば、M-: emacs-lisp-mode-mapを実行してみてください。
そこで長々とした出力があるならば、そのメジャーモードに対するキーマップだとわかります。
もしキーマップの名前が違う場合は「void」というエラーが出ます。

また、コマンドにnilを指定すればそのキーマップにおけるキー割り当てを解除します。
たとえばdiredでもC-tをother-windowにしたいのならば上の設定に加えてこうします。
この時点でC-tはdired-mode-mapから消えたのでglobal-mapを読みに行きます。

(require 'dired)
(define-key dired-mode-map (kbd "C-t") nil)

新しいコマンドに割り当て直す

global-set-keyやdefine-keyには、元のコマンドを新しいコマンドに割り当て直す機能があります。
この機能をうまく活用しているわかりやすい例がdiredです。
C-nは通常はnext-lineですが、diredにおいてはdired-next-lineに割り当てられています。
dired-next-lineはdiredに特化した「次の行へ移動」コマンドです。

dired.elを読むと、次のように書かれています。
(わかりやすくするために少しアレンジしています)

(define-key dired-mode-map [remap next-line] 'dired-next-line)

これはdired-mode-mapにおいてnext-lineに割り当てられているすべてのキーにdired-next-lineを割り当てるという意味です。

「next-lineに割り当てられているすべてキー」というのがポイントです。
本来はC-nですがユーザ側が別なキーにnext-lineを割り当て直していても違和感なくdired-next-lineが使えるようになります。
下カーソルキーも同じくdired-next-lineになります。

一方、ffap(find-file-at-point)では直接C-x C-fに割り当てています。
これだとC-x C-f以外にfind-fileを割り当てている場合は、そのキーがfind-file-at-pointになってくれません。

(global-set-key (kbd "C-x C-f") 'find-file-at-point)

自分用プレフィクスキーを探せ

Emacsの操作性を上げるには、やはり自分用の押しやすいプレフィクスキーを持つことが大事です。
他で使われないプレフィクスキーがひとつあれば何十ものコマンドを自由に割り当てられるからです。
とくにホームポジションにあるC-;とC-:は端末(emacs -nw下)では使えませんが、何も割り当てられていません。
C-l、C-q、C-t、C-zあたりもおすすめです。

個人用キー割り当てパッケージbind-keyを使う

簡単・お手軽に個人用キーバインド管理

キーバインドを設定するだけならば普通にglobal-set-keyやdefine-keyを使えばいいだけです。
しかし、Emacsのカスタマイズが進んでいくにつれて、自分が割り当てたキーを管理したくなります。
そこでMELPAのbind-keyパッケージが登場します。

以下の特徴があります。

  • 短く簡潔に記述できる
  • モードに左右されずに常に同じコマンドを割り当てられる
  • 自分が割り当てたキーバインドをリストできる

とても簡単なのでぜひとも使ってみてください。

パッケージの設定を1つのS式にまとめて記述できるuse-packageパッケージにもbind-keyが使われています。

kdb不要でスマートに記述

bind-keyパッケージはキーバインドを定義するbind-keyマクロが定義してあります。
これはユーザカスタマイズに特化したdefine-key相当物です。
global-set-keyやdefine-keyからkbdを取り去った短い記述でキーバインドを定義できます。

書式

(global-set-key (kbd "キー") 'コマンド)
↓
(bind-key "キー" 'コマンド)

(define-key キーマップ (kbd "キー") 'コマンド)
↓
(bind-key "キー" 'コマンド キーマップ)

bind-keyマクロはautoloadされないので、使う際にはrequireする必要があります。

ここで、さきほど登場したglobal-set-keyとdefine-keyをbind-keyに置き換えてみましょう。

(require 'bind-key)
(require 'dired)
(bind-key "C-t" 'other-window)
(bind-key "C-t" nil dired-mode-map)

いたって簡単です。
しかし、この短い記述の裏では管理のための複雑なカラクリが仕掛けてあります。

メジャーモード・マイナーモードに上書きされない強制設定

自分用のキーバインドを設定したつもりが、時として意図した通りに動作しないことがあります。
それは、キーマップ探索の優先順位が低いキーマップにキーとコマンドを割り当てているため、より高い優先順位のキーマップに割り当てられたコマンドが有効になっているためです。
global-mapよりもメジャーモードの方が優先され、メジャーモードよりもマイナーモードの方が優先されます。
そのため、global-mapのC-tにother-windowを割り当ててもdired-mode-mapでC-tが使われているため、diredではother-windowが動作しないことになります。

bind-keyの亜種bind-key*マクロは最高優先度のキーマップにキーを割り当て、常に意図したコマンドが実行されるようにします。
メジャーモードはおろかマイナーモードでさえも阻むことはできません。

(require 'bind-key)
(bind-key* "C-t" 'other-window)

これは「劇薬」というほど強力な方法なので、注意する必要があります。
メジャーモード・マイナーモードでそのキーに割り当てられたコマンドが使えなくなるからです。
そのキーに割り当てられたコマンドが重要なコマンドである場合は、改めてそのコマンドを別なキーに割り当てる必要があります。

個人用キーバインドを列挙する

bind-keyには、自分が設定したキーバインドを列挙する機能があります。
それこそがカスタマイズ用に特化したdefine-keyである所以です。

bind-key・bind-key*を実行したら、割り当てたキーバインドと元のキーバインドを内部的に記憶しています。
そして、M-x describe-personal-keybindingsでそれらをリストできます。

たとえば、C-tにother-windowを割り当てたときには、以下のような表示になります。

Key name   Command         Comments
---------- --------------- ---------------------
C-t        `other-window'  was `transpose-chars'

デフォルトのtranspose-charsを上書きしてother-windowに割り当てていることがわかります。
ここではglobal-mapの変更しか書いていませんが、他のキーマップの変更点も表示されます。

よってinit.elでのキーバインドの設定をbind-keyに置き換えることで、自分が割り当てたキーバインドを一覧できます。
標準のEmacsのキーバインドからどれだけ離れているかもわかります。
新しく割り当てるべきキーを見出すきっかけにもなるでしょう。

状況で挙動を変更させるmykieパッケージ

コマンドと「状況」

Emacsのコマンドは、動作するための条件が必要な場合があります。
たとえばC-wやM-wはregionが設定されている場合のみ動作します。
regionが設定されていない場合はバッファに変更を及ぼしません。

一方で、C-uを付けることでまったく別の挙動をするコマンドも存在します。
たとえばC-SPCはマークをするコマンドですが、C-u C-SPCで過去にマークされた位置に移動します。
C-uにより、ひとつのコマンドに複数の機能を持たせられることを意味します。

Emacsにはすでに無数のコマンドがキーに割り当てられていて、新たに割り当てるキーを探すのは一苦労です。
操作性や記憶力の限界がくるからです。

そこで状況に応じて挙動を変化するコマンドをキーに割り当てれば、キーバインドの資源を有効活用できます。
標準コマンドで使っているキーを多機能コマンドに割り当て直せば、記憶を圧迫することなく自然に新しい機能が使えるようになります。

たとえば、C-wはC-uを付けても付けなくても挙動が変わらないので、C-u C-wに別なコマンドを割り当てる余地があります。
regionが設定されていないときには変化がないので、現在行をkillするように設定できます。

これを容易にするのがMELPAのmykieパッケージです。

C-wに挙動を追加する

mykieパッケージを使うにはmykie:global-set-keyとmykie:define-keyという2つのマクロを知っていればいいです。
これらは名前の示す通りmykie定義に基づく挙動をキーに割り当てます。
mykie定義とは、状況とコマンドを対応させるキーワード引数です。

書式
(mykie:global-set-key "キー(Emacs記法)" mykie定義...)
(mykie:define-key キーマップ "キー(Emacs記法)" mykie定義...)

それでは実例を示しましょう。
C-wはデフォルトの状態ではregionが有効のときのみ使えるコマンドです。
また、C-uを付けても挙動が変わりません。
よって、regionが無効なときとC-uをつけたときの挙動を追加させられます。
そこで、regionなしのときはkill-whole-line、region有のときはkill-region、region有かつC-uをつけた場合にfold-thisを実行させたければ、以下のようになります。

なお、fold-thisコマンドはregionを一時的に隠すもので、fold-thisパッケージをインストールして使えます。
見かけ上regionが消えるのでC-u C-wに割り当てても違和感を感じません。

(mykie:global-set-key "C-w"
  :default kill-whole-line
  :region kill-region
  :region&C-u fold-this)

S式をコマンド化する

上のmykie定義ではコマンド名を指定しましたが、S式を指定することもできます。
そのときはそのS式を実行します。

以下の例ではC-@を押したときに「Pressed C-@」と表示します。

(mykie:global-set-key "C-@"
  :default (message "Pressed C-@"))

同様の働きを通常のglobal-set-keyで定義するには以下のような面倒な記述が必要になります。

(global-set-key (kbd "C-@")
                (lambda ()
                  (interactive)
                  (message "Pressed C-@")))

これは、elisp開発に役立つことでしょう。

あらゆるキーワード引数

mykieはregionやC-uだけでも使えればとても便利ですが、他にも多数のキーワードが使用可能です。
mykieで複雑な設定をする前に、どのコマンドが実行されるのかを確認するといいです。
筆者は以下のようにmykie:testerマクロを定義して使っています。

(defmacro mykie:tester (&rest args)
  `(mykie:global-set-key "C-x C-z"
     ,@(cl-loop for a in args
                for msg = `(message "%sが実行されます" ,a)
                append (list a msg))))

このマクロを

(mykie:tester :C-u :default)

として呼び出した場合、以下のように展開されます。

(mykie:global-set-key "C-x C-z"
  :C-u (message "%sが実行されます" :C-u)
  :default (message "%sが実行されます" :default))

つまり、C-u C-x C-zで「:C-uが実行されます」と表示され、C-x C-zで「:defaultが実行されます」と表示されます。

使えるキーワードはhelmを導入した上でM-x helm-show-mykie-keywordsを実行すれば調べられます。

M-xを有効活用する

あえてキーに割り当てない選択

Emacsユーザは新しいコマンドが使えるようになったとき、ついついキーに割り当てたくなるものです。

プレフィクスキーのおかげで理論上は無限にキーに割り当てられます。
たとえばC-:を自分用プレフィクスキーにしたとき、C-: C-:やC-: C-: C-:もプレフィクスキーにできます。
しかし、それではプレフィクスキーが長くなってしまい、コマンドの発動に時間がかかります。
使い勝手を考えるとせいぜいプレフィクスキーは2ストローク…つまりキーシーケンスは3ストローク…が限界です。

そして、もう一つの限界が記憶力です。
人間の儚い記憶力では長いキーシーケンスと対応するコマンドを覚えるのは困難です。
何個も自分用プレフィクスキーを用意する方法でも記憶力の限界に到達します。
割り当てるコマンドとキーシーケンスの関連がない場合は、とても覚えにくいです。

いずれにせよ現実的にはキーマップは有限な資源になります。
そう何個も何個もキーに割り当てられません。

そういう場合は無理にキーに割り当てず、コマンド名で覚えてM-xで呼び出せばいいです。

コマンドに別名をつける

キーバインドが狂っていたり、コマンド名が長かったり、覚えにくかったりする場合は、自分で勝手に別名をつけるといいです。
たとえば、C-M-% (query-replace-regexp)をそれなりの頻度で使う場合、無理にC-M-%を押さずにM-x qrrで呼び出せばいいです。

(defalias 'qrr 'query-replace-regexp)

筆者は文章を書くときにはolivetti-modeというマイナーモードを使い、画面中央に文章を表示させて執筆に集中します。
しかしolivetti-modeという名前がどうしても覚えられないので、勝手にwriting-modeと名付けています。

(defalias 'writing-mode 'olivetti-mode)

また、常に別名を使っていれば実体が変わっても同じ名前を使い続けられます。
筆者は今はqrrをvr/query-replaceにしています。
vr/query-replaceはvisual-regexpパッケージで定義されているquery-replace-regexpの進化形です。
re-builderのように正規表現を確認しつつ置換を行うコマンドです。

(defalias 'qrr 'vr/query-replace)

olivetti-modeには類似品writeroom-mode、tabula-rasaがあります。
乗り換える場合はwriting-modeの別名を付け替えるだけで済みます。

シェルでは別名が当たり前ですが、元々の動機はコマンドを呼び出しやすくすることです。
同様の発想でEmacsのコマンドにおいても別名を使ってみてください。

M-xを超強化するsmexパッケージ

コマンドを名前で呼び出す頻度が多くなれば、必然的にM-xの使用頻度も上がります。
そうなると、より進化したM-xが欲しくなるでしょう。
MELPAのsmexはまさに「スーパーM-x」にふさわしい強力なパッケージです。
smexは過去に使用したコマンドを列挙しつつ、コマンド名を曖昧検索・選択できるようにします。

類似品であるhelm-M-x(helm版M-x)よりも動作が軽く、しかも賢いです。
smexはコマンドの使用頻度や履歴に基いて最初に提示するコマンドを適切に選択しています。
使用頻度のデータベースは保存されるのでEmacsを再起動しても受け継がれます。

smexはidoインターフェースなので、MELPAのido-vertical-modeと併用すると縦に候補が表示されて見やすくなります。

(setq ido-max-window-height 0.75)
(setq ido-enable-flex-matching t)
(ido-vertical-mode 1)
(setq ido-vertical-define-keys 'C-n-and-C-p-only)
(smex-initialize)
(require 'bind-key)
(bind-key "M-x" 'smex)
(bind-key "M-X" 'smex-major-mode-commands)

20150106055458.png

図ではM-x fifiでfind-fileなどが出ていることに注目してください。
idoの曖昧検索によりfifiという入力が正規表現f.*i.*f.*iに変換されるからです。
つまり、各文字間に任意の文字が入ったコマンドにもマッチします。
よって、長いコマンドも少ない打鍵数で呼び出せるようになります。
しかも一度呼び出したら次に呼び出せるように最初の候補に登ってきます。

候補選択はhelm同様C-p/C-nで直感的に行えます。

メジャーモードに関連するコマンドはM-Xで呼び出せるようになります。

しかも素晴しいことにRETでコマンド実行するかわりに他のキーを押せば実行以外のこともできます。
C-h wでそのコマンドの説明を表示(describe-function)し、C-h wで割り当てられたキーを表示(where-is)し、M-.でコマンドの定義(find-function)を開きます。
smexはひとつのコマンドでありながら複数のアクションを持つ、まさにhelm的なコマンドといえます。

終わりに

今回はキーバインド特集ということで、基本からその進化形を紹介しました。
キーバインドの方法は他にもあるのですが、残念ながら紙面が足りなくなってしまっため、来月にまわします。

筆者はサイト「日刊Emacs」を運営し、毎日パッケージの紹介記事を書いています。
マイナーなものも紹介しているので、新たなパッケージを求めている人の役に立てば幸いです。

また、EmacsユーザのQOLを上げるための厳選した情報を週間メルマガで配信しています。
Emacsについてはもちろんのこと、ライフハックなどいろいろな分野について書いています。
登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#17 “手遅れ”を防ぐ Emacsのセーフガードシステム (Software Design 2015年9月号掲載記事) Emacs undo redo 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

Emacsのセーフガードシステム

Emacsが歴史のあるソフトウェアであることは今更言うまでもありません。
歴史があるということは、それだけ多くの人に使われていて、長年にわたるノウハウが蓄積されていることを意味します。
昔から多くの人が不満に思っている点はたいてい解決されています。

今回はEmacsで使える多くのセーフガードシステムを標準・外部パッケージ問わず紹介していきます。
人間は操作ミスをする生き物なので、Emacsではその被害をなくしたり最小限に抑えるための方法が多くあります。
昔からよく「保存し忘れたからフリーズしたときにデータが飛んだ」とかの悲鳴を聞きますが、Emacsならばそんなことは太古の昔に解決されているのです。
Emacsの状態を元に戻す機能も大切なセーフガードです。
けれども、せっかくセーフガードシステムが用意されていても知らなかったのでは意味がありません。
ここでは以下のテーマを採り上げます。

  • 間違った編集を元に戻す
  • 迷子になったカーソルを戻す
  • ウィンドウ構成を戻す
  • 自動保存でデータ消失をなくす

編集を元に戻す

標準のundo

通常、Emacsのバッファは作成時からの編集履歴を記憶しています。
間違った編集をしてバッファの内容がめちゃくちゃになったとしても、あわてずにC-/ (undo)を押してください。
直前の編集状態に戻ります。
もっと前に戻したい場合は引き続きC-/を押します。
もし、戻しすぎてしまった場合はC-fなど編集しないコマンドを実行後、C-/を押します。

undoをカイゼンするredo+パッケージ

標準のC-/は戻しすぎてしまった場合の挙動が使いやすくありません。
というのは、過去方向だけでなく未来方向に進むことがあるからです。
redo+パッケージはundoを過去方向のみ遡れるように再定義し、未来方向に進むM-x redoを定義します。
MELPAに登録されているのでM-x package-install redo+でインストールして設定を加えてください。
この設定を加えた場合、C-/を押しすぎてしまった場合にC-M-/で戻せるようになります。

(require 'redo+)
(global-set-key (kbd "C-M-/") 'redo)

編集履歴を永続化するundohistパッケージ

通常は編集履歴はバッファ作成時に初期化されます。
つまり、バッファを削除したり、ファイルを開き直したり、Emacsを終了したときに失われてしまいます。
undohistパッケージはバッファを削除する際に編集履歴をディスクに保存し、再びファイルが開かれるときにそれを復元します。
これもMELPAに登録されているのでM-x package-install undohistでインストールしてください。

(require 'undohist)
(undohist-initialize)
;;; 永続化を無視するファイル名の正規表現
(setq undohist-ignored-files
      '("/tmp/" "COMMIT_EDITMSG"))

編集履歴をツリー状に可視化するundo-tree

C-/で編集を戻して新しく編集しなおすと、編集履歴は分岐することになります。
つまり、戻った時点から見て間違った古い履歴と、次の編集で作られる新しい履歴ができます。
新しい履歴が作られたとき、通常のC-/では古い履歴にアクセスできません。
せっかく編集履歴のデータには古い履歴も保持してるのに、もったいないですね。

そこでundo-treeパッケージを使って編集履歴の木構造を「見える化」します。
元々undoはC-x uとC-/に割り当てられていますが、undo-treeを導入すると両者に別の役割が与えられます。
C-/にはundo-tree版undoであるM-x undo-tree-undoが、C-x uには編集履歴の木構造にアクセスするM-x undo-tree-visualizeが割り当てられます。
木構造には直観的に操作でき、C-p/C-nで履歴を時系列順にたどり(上下)、C-b/C-fで分岐を選択(左右)します。
なお、M-x redoをキーに割り当てている場合は、そのキーにM-x undo-tree-redoが割り当てられます。

(setq undo-tree-mode-lighter "")
(global-undo-tree-mode 1)

20150712233729.png
Fig1: C-x uで編集履歴にアクセス

カーソル位置を戻す

C-u C-SPCでマークを戻す

Emacsには様々なカーソル移動コマンドがありますが、長距離を移動するコマンドを実行した場合にすぐに元の位置に復帰できる仕組みになっています。
つまり、行きはよくても帰り方がわからない…つまりカーソルが迷子になる…ことがないようなセーフガードが設けられています。
本節の内容は以前の連載でも触れましたが、セーフガードの観点から再び採り上げることにします。

長距離移動とは、バッファ先頭・末尾への移動(M-<, M->)やインクリメンタルサーチ(C-r, C-s)や関数単位の移動(C-M-a, C-M-e)などが該当します。
これらのコマンドを実行するとき、予め「暗黙のマーク」によって元のカーソル位置を記憶します。
そして、C-u C-SPCを押せば元の位置に戻れます。
たとえばバッファ先頭を見てからすぐ戻る場合、M-<の後にC-u C-SPCを押せばいいだけです。
C-SPC M-<と明示的にマークする必要はありません。

暗黙のマークの存在を知っていればとても楽になります。
たとえばソースコードにrequire(必要なライブラリの宣言)を書き加える場合、requireまでインクリメンタルサーチで移動し、書き加え、C-u C-SPCで戻れるのです。

何かしらの理由でカーソル位置が思いもよらない場所に移動してしまった場合、暗黙のマークがしてあればC-u C-SPCを押せば元の位置に戻れるのです。

マークは複数個記憶しているので、C-u C-SPCを繰り返せばどんどん過去のマークへ移動できます。
何度もC-uを付けるのが面倒であれば以下の設定を加えるとよいです。
これによりC-u C-SPC C-SPC…とC-SPCを連打して遡れます。

(setq set-mark-command-repeat-pop t)

カーソル位置を戻すpoint-undoパッケージ

C-u C-SPCはカーソル迷子の万能薬ではありません。
C-v/M-vなどの画面スクロールは暗黙のマークを設定しません。
また、外部パッケージによるコマンドも必ずしも暗黙のマークを設定するとは限りません。
MELPAにある拙作point-undoパッケージは、すべてのカーソル移動を記憶することで、暗黙のマークに関係なくカーソル位置を戻します。
見た目上違和感のないようにカーソル位置だけでなくウィンドウの表示位置も復元します。

以下の設定ではf7でカーソル位置を過去方向に戻し、M-f7で戻しすぎたカーソル位置を未来方向へ進めます。
お使いの環境によってはf7がEmacsで使えないこともあるので、そのときは他のキーに割り当ててください。
そのときはf7とM-f7のように対になるキーバインドをおすすめします。

(require 'point-undo)
(global-set-key [f7] 'point-undo)
(global-set-key [M-f7] 'point-redo)

編集履歴からカーソル位置をたどるgoto-chgパッケージ

前節で示したように、Emacsは編集履歴を記憶しています。
編集履歴とは変更された場所とその内容の集まりです。
MELPAにあるgoto-chgパッケージは、編集履歴の中の変更された場所にアクセスすることで、変更された位置をさかのぼります。

これは慣れるまで動作がイメージしづらいかもしれませんが、バッファに変更を加えた時点で自動的に編集履歴に記録されることを理解すればよいです。
手動のC-SPCに対して、自動のgoto-chgです。

goto-chgは別な場所を編集してから元の場所を編集するときに効果を発揮します。
たとえば文章を書いていて、ふと誤字脱字が目に付いて、そこを修正した後、再び元の位置に戻って文章の続きを書くといったケースです。

以下の設定ではf8で編集履歴に記憶された場所を過去方向にたどり、M-f8で未来方向です。

(require 'goto-chg)
(global-set-key [f8] 'goto-last-change)
(global-set-key [M-f8] 'goto-last-change-reverse)

ウィンドウ構成を戻す

以前のウィンドウ構成に戻す標準機能winner

Emacsを使っているとウィンドウ構成がめまぐるしく変わります。
ウィンドウ構成とは、画面の分割状態とバッファの配置のことです。
ウィンドウを分割したり、大きさを変更したり、別なバッファを表示させたときにウィンドウ構成が変更されます。

たとえばf1 f(関数の説明表示)などのヘルプを表示した場合、ヘルプバッファの内容を読んだ後にしたいことは、元のウィンドウ構成に戻すことです。
ヘルプバッファはGUIにたとえればメッセージダイアログボックスがポップアップすることに相当します。
ダイアログボックスは元の画面に重なるように表示され、「閉じる」を押せば消滅します。

M-x winner-undoは「閉じる」ボタンに相当するコマンドで、直前のウィンドウ構成に戻します。
他の「戻す」系パッケージ同様に逆方向のM-x winner-redoもあります。
マイナーモードwinner-modeが有効のときのみ動作するので、設定を記述する必要があります。

(winner-mode 1)
(global-set-key (kbd "C-z") 'winner-undo)
(global-set-key (kbd "C-M-z") 'winner-redo)
;;; 後述のESC ESC ESCで使う場合
(setq buffer-quit-function 'winner-undo)

Emacsにポップアップウィンドウという概念を導入するpopwinパッケージが人気ですが、筆者はwinnerの方が応用範囲が広いと感じています。
popwinではpopwinで表示されたウィンドウのみを閉じますが、winnerはすべてのウィンドウが対象です。
popwinではC-gでポップアップウィンドウを閉じられるようになっていますが、それを実現するためにはかなり複雑な仕組みになっています。
ウィンドウを閉じることくらい、標準機能でも間に合います。

特殊状態を「取り止め」るにはESC(C-[)を3回叩け!

あなたは、ESC ESC ESCに割り当てられたコマンドを知っていますか?
Emacs的に意外なキーに割り当てられたkeyboard-escape-quitというコマンドはマルチな機能を発揮します。
コマンド名からしてC-g (keyboard-quit)に似ていることは想像できますが、共通点と相異点があります。

C-g とESC ESC ESCの共通点は以下の通りです。
これらの用途では素直にC-g で間に合います。

  • regionをキャンセルする
  • ミニバッファから抜ける
  • 前置引数をキャンセルする

ESC ESC ESCの独自機能は以下の通りです。

  • 再帰編集から抜ける
  • バッファを閉じる(閉じ方は設定可能)
  • ウィンドウが分割されているときは分割を解除する

そのうち「バッファを閉じる」アクションにwinner-undoを指定すれば、ESC ESC ESCでウィンドウ構成を戻せるようになります。
バッファを閉じる関数はbuffer-quit-functionに指定します。
デフォルトではnilになっていて、そのときはウィンドウ分割を解除、または隠しバッファ(バッファ名がスペースから始まる)を閉じるようになります。

再帰編集とは、コマンド実行中にバッファを編集できるようにする機能です。
代表的な再帰編集は置換で起こります。
M-%やC-M-%の途中でC-rを押せば置換は中断されて再帰編集に入り、ESC ESC ESCで抜けるまで任意のEmacsの操作ができます。
再帰編集を抜けると、実行中のコマンドが再開されます。
再帰編集は、モードラインのモード名が[]で囲まれているかどうかで判別できます。

前項でbuffer-quit-functionをwinner-undoに設定しているので、ESC ESC ESCは再帰編集から抜けるか、ウィンドウ構成を戻すコマンドになります。
単に前のバッファに戻りたいのであれば、buffer-quit-functionにprevious-bufferを設定してください。

ESC ESC ESCを定義はとてもシンプルなもので、cond式一発で構成されています。
condは他言語でいうif〜elseif〜elseif〜elseに相当する構文で、条件式を次々にチェックしていき、最初に一致した条件式にマッチする挙動を行います。
elispが読める方はM-x find-function-on-key ESC ESC ESCでコードを読んだ方が確実に理解できます。
なお、標準添付のlispソースコードがインストールされていない環境ではエラーになるので、Emacsについて深く学びたい方はインストールしてください。
Debian系列ではemacs24-elパッケージが必要です。

ウィンドウ構成を記憶させるいろいろな方法

Emacsであらゆるタスクを同時進行させている人ならば、ウィンドウ構成を戻すよりも、記憶させたくなると思います。
ウィンドウ構成を記憶させる方法はいろいろあり、そのためのパッケージもたくさん存在します。
本稿はあくまでもセーフガードを主題としているので軽く触れておくにとどめます。

標準の方法はレジスタにウィンドウ構成を記憶させることです。
C-x r wで記憶し、C-x r jで復元します。

ウィンドウ構成を記憶する無難なパッケージはelscreenです。
GNU Screenを模倣して作られていて、ウィンドウ構成をscreenに見立てて、切替えられるようになっています。
helmにもelscreenに関するアクションが存在します。
elscreen-persistパッケージでEmacsを終了してもscreenの状態を復元できます。
elscreen-separate-buffer-listパッケージでscreenごとに独立したバッファリストを持てるようになります。
elscreen + elscreen-persist + elscreen-separate-buffer-list と似たパッケージとしてpersp-modeパッケージがあります。

大昔からあるwindows.el(未パッケージ化)は20年以上にわたっていまだにメンテナンスされています。
ウィンドウ構成の情報や開いたバッファも永続化されます。

ウィンドウ構成に名前をつけるだけならばspacesパッケージやwindataパッケージがあります。

ぜひとも好みに応じてパッケージを選んでみてください。
パッケージを自由に選べるのもEmacsの魅力です。

自動保存によりデータ消失を防ぐ

標準のauto-save-mode

最後のテーマはデータ消失を防ぐ方法についてです。
まさに「セーフガード」にぴったりな話題です。

Emacsでは標準でauto-save-modeという自動保存機能が有効になっています。
この自動保存は編集中のファイルに直接保存するのではなく、別のファイルに保存されます。

一般に自動保存のファイル名は元のファイル名を「#」で囲んだものになります。
たとえば、foo.cならば#foo.c#となります。
diredを使っていると、もしかしたらこのようなファイルを見掛けたことがあるかもしれません。
普通のファイルならばカレントディレクトリに作られますが、Trampによるリモートファイル(sshやftpやsudo等)は/tmpに置かれます。

自動保存ファイルはC-x C-sなどで明示的に保存されたときに消去されます。
保存せずにバッファを削除しようとしたり、Emacsを終了しようとしたときは本当に削除・終了するかわざわざ訊いてくるので、保存忘れによる最低限のセーフガードはできています。
もし保存せずにバッファを削除した場合、自動保存ファイルが残っているので、そこからある程度の内容を復元できます。
そのため、保存忘れに対しては二重のセーフガードになっています。

そして何より嬉しいのがEmacsやOSがフリーズしたときに自動保存に助けられます。
自動保存ファイルが残っているファイルを開いたとき、

ファイル名 has auto save data; consider M-x recover-this-file

と教えてくれます。
内容が古い場合はM-x recover-this-fileを実行してみましょう。

また、一度に複数のファイルを復元したい場合はM-x recover-sessionを実行します。
自動保存ファイル名を記録したファイルがdiredで列挙されるので、C-c C-cを押せば復元できます。

自動保存の間隔が頻繁であればあるほど、データ消失を防げます。
今では以下のように事実上即自動保存しても問題ないです。

;;; 4ストロークごとに自動保存(デフォルト300)
(setq auto-save-interval 4)
;;; 1秒のアイドルで自動保存(デフォルト30)
(setq auto-save-timeout 1)

バックアップファイル

標準に備わっているもうひとつのデータ消失対策セーフガードは自動バックアップファイルの作成です。
バッファが作成され、最初に保存したときのみにバックアップファイルが作成されます。
バックアップファイル名はファイル名の後に「~」が付きます。
デフォルトでは、バージョン管理システム管理下のファイルや一時ファイルのディレクトリ(/tmp等)は対象外となります。

バックアップファイルはしばしば過保護で余計なファイルが混入されるから嫌がられます。
それならば、ファイルをバージョン管理システム管理下に置くのが一番です。
きちんとコミットされている限り、いつでも全てのリビジョンを取り出せるからです。
バージョン管理システムと比べれば、バックアップファイルは原始的な仕組みでしかありません。

バックアップファイルを作成しないのであれば、以下の設定を加えればいいです。
しかし、その分セーフガードがゆるんでいるので自己責任でお願いします。

(setq make-backup-files nil)

ファイルに直接自動保存!

標準のauto-saveは別のファイルに保存しますが、より過激なアプローチとしてファイルに直接自動保存をさせるMELPAパッケージもあります。
自動保存の間隔をコンマ数秒〜数秒に設定すれば、手動でC-x C-sする必要がなくなります。
つまり「ファイルを保存する」という概念を消し飛ばしてしまいます。
手動で保存するのが面倒と考えているならば導入の価値はあります。
「きりのいいところで保存するのではなく、きりのいいところでバージョン管理システムにコミットする」という考えを持っているなら、受け入れやすいです。

ただ、先月お話したように「利便性には代償が伴う」ことに注意してください。
意図せずにファイルを変更してしまった場合、それに気付きにくくなることです。
バッファが変更されたならばモードラインに「**」という修正された印が表示されますが、自動保存であれファイルが保存されたのならば常に無修正とみなされます。
undohistやバージョン管理システムとの連携させればよいです。

MELPAに登録されているauto-save-buffers-enhancedパッケージが古くから使われています。
*scratch*バッファも自動保存・復元します。
初回起動時はscratchファイルが存在しないのでエラーになりますが、*scratch*バッファに何か書き込むか~/.emacs.d/scratchファイルを予め作成すれば問題ありません。

(require 'auto-save-buffers-enhanced)
;;; 自動保存の対象外となるファイル名正規表現のリスト
(setq auto-save-buffers-enhanced-exclude-regexps
      '("Org Src"))
;;; *scratch*バッファも保存対象にする
(setq auto-save-buffers-enhanced-save-scratch-buffer-to-file-p t)
;;; *scratch*バッファ保存時のファイル名
(setq auto-save-buffers-enhanced-file-related-with-scratch-buffer
      (locate-user-emacs-file "scratch"))
;;; 自動保存時にWroteというメッセージを出さないようにする
(setq auto-save-buffers-enhanced-quiet-save-p t)
;;; 3秒後に自動保存
(setq auto-save-buffers-enhanced-interval 3.0)
;;; 有効にする!
(auto-save-buffers-enhanced t)

シンプルで新しい実装としてreal-auto-saveパッケージも存在します。
こちらの方はマイナーモードとして実装されているので、有効無効を切替えたり、特定のモードのみで有効にしたりできます。

保存時に自動スナップショット!

標準のバックアップファイルは最初の保存時に作られるものですが、MELPAにあるbackup-each-saveパッケージはより積極的なアプローチです。
標準とは異なり、別ディレクトリに日付を含むファイル名で保存時に毎回バックアップファイルとして書き出します。
たとえば /tmp/test.txt ならば /backup/backup-each-save/tmp/test.txt-150719_025939 のようなファイル名になります。
履歴を見たり復元したければ C-x d /backup/backup-each-save/tmp/test.txt-* のようにdiredを開けばいいです。

前項のauto-save-buffers-enhancedと組み合わせると度が過ぎるほど冗長になりますが、現在のストレージ容量を考えれば高々Emacsで編集する程度のテキストファイルがいくつあっても問題ありません。
データ消失に対して、まさに鉄璧の守りになります!

(require 'backup-each-save)
;;; バックアップ先
(setq backup-each-save-mirror-location "/backup/backup-each-save")
;;; 日付の形式を指定
(setq backup-each-save-time-format "%y%m%d_%H%M%S")
;;; 元のメジャーモードで開くように設定する
(add-to-list 'auto-mode-alist '("-[0-9]\\{6\\}_[0-9]\\{6\\}$" nil t))

終わりに

 今回はセーフガード特集ということで、元に戻すことやデータ保護について触れました。
「備えあれば憂いなし」というように、いざというときに役立つ知識をまとめました。

 筆者は「日刊Emacs」以外にもEmacs病院兼メルマガのサービスを運営しています。Emacsに関すること関しないこと、わかる範囲でなんでも御答えします。「こんなパッケージ知らない?」「挙動がおかしいからなんとかしてよ!」はもちろんのこと、自作elispプログラムの添削もします。集中力を上げるなどのライフハック・マインド系も得意としています。登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#16 Emacsと長く付き合っていくために (Software Design 2015年8月号掲載記事)

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

Emacsは小宇宙

 ども、るびきちです。
ここ3ヶ月は基本に立ち帰り、標準コマンドに光を当ててみました。
やはりさすがEmacsは奥が深く、標準コマンドにちょっと触れるだけでも3ヶ月かかってしまいました。
これまで当たり前に思ってきた標準コマンドの機能性を再発見できれば幸いです。

 でも、標準コマンドで終わるEmacsではありません。
Emacsユーザは当然、Emacsを自分好みの色に染めたいものですよね。
個々のユーザの要望にとことん応えてくれるのがEmacsの魅力です。

 Emacsは単なるテキストエディタではなく、テキストエディタの顔をしたLispマシンです。
Lispというプログラミング言語の比類なき柔軟性により、ありとあらゆるタスクがEmacsで実現できます。
Lispは実行中にプログラムそのものを変更できるので、あなたの意のままの形態を変化します。
変数を設定したり、関数を定義したり、Lispファイルをロードすれば、その時点で「世界で1つ、あなただけのためのEmacs」なのです。
elispのおかげで日常的なテキスト編集がより快適になり、突き詰めれば統合開発環境になりますし、ゲームソフトにすらなってしまいます。

 人体は小宇宙と言われていますが、筆者はEmacsも小宇宙であると考えています。
Emacsは人間によって書かれた一プログラムにしか過ぎませんが、あたかも生き物ではないかと思えるときがあります。
生き物は食物を摂取しますが、Emacsにとってはelispパッケージが食物(や薬)に相当します。
健康を維持するには何を食べるかが重要であるように、快適なEmacsもどんなパッケージを使うかが重要です。
薬の飲み合わせがあるように、お互い相性の悪いパッケージのせいで無用なトラブルに巻き込まれることもあります。

 Emacsは標準添付のパッケージも充実していますが、Emacs24からはパッケージシステムが導入されたので、世界中の外部パッケージを簡単に導入できます。
誰もが簡単に外部パッケージを導入し、設定すればすぐにあなたのEmacsに反映されます。
門は開かれました。
あなたのEmacsをデザインしてください。

 こういう話をしていて、いつも頭をよぎるのが筆者の少年時代に遊んだミニ四駆です。
電池2本で一直線にしか走れない玩具の車ですが、当時はいかに速くコースを走るか競われていました。
ミニ四駆本体を買って組み立て電池を入れて電源を入れればすぐに走ります。
しかし、より速く走らせるためにはより強力なモーターに交換したり、軽量化などの改造を施します。
取り換えられるパーツは多くのメーカーが生産していて、選択は多岐に渡ります。
「これは」と思ったパーツに取り換え、自分オリジナルのミニ四駆を構築したものでした。
そして大人になった今、このノリがGNU/Linuxマシン構築やEmacs環境構築に活かされています。

拡大と収縮

 筆者はEmacsを使い始めた途端、いきなり魅了され、数ヶ月しないうちにelispを書くようになりました。
そして、「こんなコマンドあったらいいな」を自分で実装していました。
右も左もわからず、試行錯誤の日々が何年も続きました。

 当時はパッケージシステムという便利な代物は存在せず、公開されているelispは少ないものでした。
お手本となるelispもない中、自分なりに学んでいました。
ネット上でelispを見付けても手動でダウンロードして手動インストールでした。
暗中模索の中だったとはいえ、ミニ四駆の魔改造のようにEmacsにいろいろな機能を追加する作業はとても楽しいものでした。

 一気に大量にelispコードを書いては、しばらく時間がたてばその機能の存在すら忘れてしまうことを繰り返して10年以上になりました。
その間、コードを書いては捨て、書いては捨てという感じでinit.elの総行数は15000行を突破していました。
自作・外部問わずありとあらゆるelispを突っ込みまくり、筆者のEmacsはモンスターのように肥大化しました。

 現在はパッケージシステムがあり、検索すれば何かしら見つかる時代に入り、自分でコードを書く必要性がめっきり減りました。
それに日々使うelispはほんの一部に過ぎないことにも気付きました。
せっかく書いたコードも今となっては役立たないものも多くなりました。
init.elをスリムにした結果、現在は5000行くらいに落ち着いています。
さらにしぼせば数千行くらいになるかもしれませんが、あいにく時間が取れていません。

 このように、筆者のEmacs遍歴は拡大と収縮の繰り返しです。
サイト「日刊Emacs」を更新するために、毎日パッケージをインストールしていますが、実運用しているものは少ないです。
膨大なelispを見てきた中で、システムに対する洞察力が身に付きelispそれぞれの性格、及びトラブルの臭いを嗅ぎ分けられるようになりました。
今回は長年のEmacs歴で学んだ教訓をお伝えしていきます。

外に開かれたEmacs

 今Emacsを始める人はとても恵まれています。
なぜならパッケージシステムにより、世界中の数千ものelispパッケージを簡単にインストールして試せるからです。
パッケージシステムが登場する前はEmacsWikiというEmacs情報集積場にノウハウやelispが集められていましたが、パッケージシステムほど使いやすいものではないので、elisp開発者はパッケージへと移行しました。
なにかパッケージが欲しいと思ったらM-x list-packagesからインクリメンタルサーチやoccurでキーワード検索すればいいだけです。
他の人にも使ってもらいたいとの思いでパッケージを作成した開発者はMELPAに登録しないわけがありません。
パッケージシステムはEmacsの標準機能なので、一度MELPAに登録したら、世界中のEmacsユーザに知れ渡るのです。
とても便利な時代になりました。

 RPGをプレイしたことがあるならば、船や飛空艇などの乗り物を得たときの開放感は忘れられないでしょう。
これまで徒歩のみの移動で世界のごく一部しか行けなかったのが、乗り物によって新しい大陸へ自由に行けるようになったときにものすごくワクワクしたことでしょう。
筆者も夢中になって新しい街や洞窟を見付けに世界を探険したものでした。
今のEmacsは、RPGでいえば飛空艇で世界中のいたるところに行ける状態です。
Emacsは子供の頃のあの楽しかった思い出を想起させてくれます。

 Emacs歴が短いのならば、ぜひともいろいろなパッケージを試してみてください。
パッケージを実際に使うことによってEmacsの経験値が増えます。
新たな角度から問題を眺められるようになり、より便利な方法が見えてきます。

 とはいえインストールするとトラブルが怖いと思うのはよくわかります。
けれどもパッケージからインストールするだけでは、すぐにコマンドが使えるようになるだけで勝手に機能が有効になったりはしません。
筆者は「日刊Emacs」のために毎日新規パッケージをインストールしていますが、インストールしたことによるトラブルは経験したことがありません。
インストールは無害です。

 筆者が知る限り唯一の例外はbetter-defaultsパッケージで、インストールするだけで変数を変更してしまいます。
しかしそれは「よりよりデフォルト設定を提供する」という動機でわざとやっています。
MELPA登録はpull requestによって人力チェックが入るので、その他のパッケージでこのような『不作法』はないでしょう。

円熟してくると

 これは筆者の経験ですが、Emacsに魅了され常にいじくり回し、多くのパッケージを使っていれば、次第にいろいろな事が見えてきました。
ちょうど熱愛から円熟に差し掛かってきます。

 既存のパッケージもそうですが、実現させたい機能が見付からない場合は自分で実装していました。
首尾よく実装できると、最初は作った機能に満足します。
しかし、たいていの場合は次第に使わなくなり、しまいにはその機能の存在すら忘れてしまうようになりました。
見方によっては時間の無駄のように思えますが、プログラミングした経験により学びが得られます。

 昔は機能が欲しければ真っ先に手が動いてプログラミングを始めていましたが、今では以下のように自問しています。これらがNoであれば自分でコードは書いていません。

  • この機能は本当に必要なのか?
  • 自分で実装する必要はあるのか?
  • すでに誰かが実装していないか?

 パッケージを実運用する際も慎重になるようになりました。
「果たしてパッケージを導入してどれくらい操作性が上がるのか?」と自問するようにしています。
なるべく多くの局面で操作性が上がるのならば、そのパッケージを導入すればよいです。
プログラムの最適化ではボトルネックの最適化に集中するのと同じように、Emacsの操作性のボトルネックを改善するパッケージならば導入すべきです。
いわゆる「プロファイリング思考」です。

 すると、無闇に外部パッケージや自前の実装に頼ることが減り、標準機能に回帰するようになりました。
外部パッケージは真新しい実装よりも標準機能を拡張するものを好むようになりました。

 このことははあなたに「外部パッケージに頼るな。標準機能だけを使え」と言っているわけではありません。
Emacsの経験が少ないのならば多くのパッケージを経験するべきです。
ちょうど海外旅行を多く経験して初めて日本のありがたみがわかるように、標準機能がそれなりによく出来ていると悟るようになります。

機能は適切に管理しよう

 スマホを始めとする多くの電化製品は機能性をアピールしています。
そういうセールストークに筆者はうんざりしています。
普通の人は「こんなこともできるんだ!すご〜い」という感じで機能性に魅入られます。
そしていざ購入したとき、アピールされた機能を使いこなしているでしょうか?
多くはNoだと思います。
機能性の感動は一時のものに過ぎず、結局は基本的な機能+αくらいしか使わないことでしょう。

 筆者はEmacsについても同じように感じています。
長年Emacsを使っていて、数多くのパッケージの設定を組み込んでいますが、結局常用している機能はごくごく一部でしかないことに気付きました。
せっかく設定していても長い間使っていないと設定したことすら忘れてしまいます。

 このことから
「できることが多いことが偉大なのではない。要は適切にコントロールすることが大事だ。」
という教訓を得ました。
パッケージを入れまくればいいわけではありません。
せっかく導入しても使い方を忘れているのでは意味がありません。
機能志向は結局は機械に使われるハメになります。

利便性には必ず代償を伴う

 筆者の座右の銘を紹介します。
それは「利便性には必ず代償を伴う」ということです。

 たとえば、インターネットの普及によって人間関係をネットで済ませるような人が出てきました。
常時接続されたインターネットは距離に関係なくいくらでも相手と交信できる利便性を生みました。
しかし、同時に人間関係スキルが磨かれなくなり、リアルでは希薄な関係に終わってしまう傾向になりました。

 携帯電話やスマホの普及により、コンピュータを使っていなくてもいつでもどこでも誰かとリアルタイムに交信できるようになりました。
筆者が初めて携帯メールを使ったときには、あまりの利便性に感動し、一日に何十通のメール交換するようになるほど中毒になってしまいました。
ガラケー時代でもメール中毒になってしまうのに、高機能化されたスマホはさらに中毒性が高いです。
このスマホ中毒というのは現代社会に大きな弊害をもたらしています。
まわりを見渡してみてください。
スマホとにらめっこしている人、人、人…常にスマホが気になり「今」という瞬間に集中できなくなりました。
心がスマホに奪われてしまっているのです。
せっかく人と会っているのに相手がスマホばかり見ていたらいい気分はしませんよね。
スマホは大きな利便性を提供しましたが、同時に精神の退廃を招きました。

 セキュリティと利便性はトレードオフであることが多々あります。
sshのパスフレーズを毎回入力するならばセキュリティは強固ですが、面倒ですね。
そこでkeychainを使ってパスフレーズ入力の手間を省けますが、ちょっとした不注意でスキを与えてしまいます。

 これらの事例を見てわかるように、便利なものにはダークサイドがあるということです。
何か便利なものを発見したときには、単に魅了されるのはきわめて危険です。
きちんとリスクを把握した上で適切にコントロールしておきましょう。

 普段のEmacsの使い勝手を大きく変えるパッケージにはよくよく注意が必要です。
便利だが仕組みが複雑なパッケージは、いざトラブルが起きたときには自分で問題解決することが困難です。
筆者は、パッケージはその利便性の代償を受け入れられる人だけが使うべきだと考えています。
エラーで使えなくなった場合は、その問題を自分で解決するか、代替の手段を講じなくてはなりません。
これがEmacsにおける利便性の代償です。
「特定のパッケージがなきゃ生きていけない」というのは、内部構造を熟知して、すばやく問題解決できるようになって初めて言えることです。

 自分が理解できないパッケージは使わない方がいいです。
自分が何をやっているのかがわからない状態は、機械の奴隷に成り下がっています。

トラブルの少ないパッケージの選び方

 トラブルの少ないパッケージの選び方の指針は、なるべく通常のEmacsからかけ離れないようにすることだと考えています。
「Emacs的に自然」であるということです。

 まず標準パッケージで実現できることであれば標準パッケージで済ませるのが一番です。
なぜなら、Emacs本体とともに継続的にメンテナンスされているからです。
将来のバージョンアップでも間違いなくその機能が使えるからです。

 確かに標準パッケージそのものがobsoleteになってしまうことはありますが、その場合は新しい手段が用意されているものです。
Emacs 24.4ではiswitchbがobsoleteになり、以前からあるidoやicompleteに取って代わられたのは記憶に新しいです。
obsoleteになってもしばらくの間は削除されないので、時間のあるときにゆっくりと移行していけばよいです。

 外部パッケージは放置されて新しいEmacsでは動作しなくなるリスクが伴うことを留意してください。
もっともelispは互換性を重視しているので、昔に書かれたelispもそのまま動くことが多いです。
それでも放置リスクについては頭の片隅に置いてください。

 編集コマンドのみが定義されているのは安全です。
そういうコマンドはいくらあってもいいです。
Emacsが新しいコマンドを学習しただけで、他の影響がないからです。
たとえばzop-to-charパッケージはM-x zop-to-charを実行するだけで使用できます。
そしてそれを便利に感じて初めてM-zに割り当てればいいです。

 特定のファイルの編集を快適にしてくれるメジャーモードも安全です。
なぜなら、対象のファイルを開いたときに初めて有効になるだけだからです。
その他の局面では影響は及びません。
ファイル名とメジャーモードの関係を定義するauto-mode-alistもパッケージをインストールした時点で設定されることが多いです。
たとえば、lua-modeパッケージをインストールすると、その時点で*.luaに対してlua-modeになるように設定されます。
編集したいファイルに対してメジャーモードが標準で存在せずに外部パッケージになっている場合は安心して導入してください。
あまり知られていませんが、 (require ‘generic-x) を設定に加えれば、多くの設定ファイル用のメジャーモードが定義されます。

 Emacsの挙動を変更するパッケージは注意が必要です。
そういうのはフックやアドバイスを定義しているので、影響が広範囲に及ぶことがあるからです。
また、他のパッケージとの相性が悪いことがあります。

 自動で動作する機能は、かなり注意して使う必要があります。
Emacsには「タイマー」と「各コマンド実行前後に行うアクション」が定義できます。
前者は、一定時間後に自動で関数を実行します。
後者は、pre-command-hookとpost-command-hookです。
これらの機能はEmacsをとても便利にしてくれる超強力な機能ですが、代償を伴います。
自動実行される関数でエラーが起きた場合、わかりづらいです。
タイマーでのエラーはエコーエリアにerrorと出るだけなので見落とされがちです。
2つのフックでのエラーは自動的にその関数がフックから外されます。
開発者側にとってもこれらの関数のデバッグは困難を極めます。
よって、派手な自動実行に過度に依存しないようにするのもEmacs的処世術です。

 マイナーモードは干渉の恐れがあります。
特にキーバインドを定義しているマイナーモードは、マイナーモードの有効順によっては動作しないことがあります。
うまく解決できない場合はそのマイナーモードを無効にしてください。

 最後に、開発がとても活発なパッケージはしばしば非互換な変更がなされます。
以前のバージョンでは動いてもバージョンアップしたら名称が変更されたり削除された場合は、元の設定では動作しません。

helmは複雑さのコストを上回る利便性

 Emacsの操作性を大きく改善した大人気パッケージhelmは、以前の連載で紹介しました。
ミニバッファにクエリを入力して絞り込み検索を行い、複数の情報源(バッファ、最近開いたファイル、ブックマーク、カレントディレクトリのファイルなど)から多くのアクションが実行できます。
内部はとても複雑ですが、影響範囲は各種helmコマンド(M-x helm-mini, M-x helm-for-filesなど)を実行している間のみなのでEmacs全体にまで及んでいません。
仮にhelm使用時にエラーが起きて使えなくなっても、元の標準コマンドやido(バッファやファイル名を絞り込み選択する標準パッケージ)でしのげばいいです。
よって、利便性が複雑さのコストを上回っていると筆者は考えています。

 ただ、helmのありがたみはEmacs初心者にはわからないものです。
標準コマンドを使っていてそれで不便さを感じるようになって、改めてhelmのよさが実感できるものです。
中級者になればhelmは手放せなくなるでしょう。

キー割り当てを変更するのは安全

 新たなパッケージを模索よりも、なるべく標準コマンドでうまくやりくりする方が賢明と考えます。
前述したように標準機能はずっとメンテナンスされるので安心して使えます。
デフォルトの設定では不便に感じた場合、キー割り当てを変更することで劇的に操作性が上がることがしばしばあります。

 たとえば別ウィンドウに切替える(other-window)にはC-x oと2ストローク必要です。
フレームを3分割以上している場合、C-x oを繰り返すかC-x zでリピートする必要がありストレスがたまります。
頻繁にウィンドウを切替えるのならば、1ストロークのキーに割り当て直すのが無難です。
これはswitch-windowパッケージなどを導入するよりも手軽です。

(global-set-key (kbd "C-t") 'other-window)

 直前のウィンドウ構成に戻すことは標準パッケージのwinnerを使えば可能です。
別のバッファに切替えて後に元のバッファに戻したり、ウィンドウ分割状態を戻すことはよくやります。
winner-undoを1ストローク化してしまえば、それだけでpopwinと同等の操作性を亨受できます。

(winner-mode 1)
(global-set-key (kbd "C-q") 'winner-undo)

 連続して実行されうるコマンドはsmartrepやhydraを導入すればプレフィクスキーを省略できて便利です。
repeat(C-x z)を1ストロークに割り当て直すのもお手軽かつ強力な方法です。

一日の作業の終わりにEmacsを閉じる

 筆者がいつもやっている習慣をお教えします。
無駄なバッファやデータが増えるとEmacsが重くなりますが、そういう場合はEmacsを再起動をすることで軽快さを取り戻します。
よって一日の作業が終わったら、お疲れ様と言ってEmacsを終了しています。
tempbufパッケージはしばらく使っていないバッファを自動的に削除しますが、一日ごとにEmacsをリセットすればそれも不要です。
パッケージも最新版が使われるようになります。
ちょうど使ったものを片付けるようにEmacsを閉じ、明日は新しい気持ちで作業が始められる心理的なメリットもあります。
あなたも試してみては?

Emacsは人生

 Emacsはいくらでも強くなれます。
しかし強力な機能はそれなりの代償が伴うので、あくまでもあなたの理解の範囲内に限られます。
理解を超えたパッケージは、逆に機械に使われてしまいます。

 なので、便利なパッケージに惚れ込んだ場合「もっと早く出会いたかった」と後悔する必要はありません。
Emacs力が未熟な段階で出会っても受け入れ態勢ができていなかったことでしょう。
「今、その便利なパッケージを使っている」…この事実に満足しましょう。

 これは、算数と数学の関係と同じです。
方程式を使えばあっさり解けてしまう算数の難問奇問がありますが、限られた知識の範囲内で悪戦苦闘したからこそ、方程式という飛び道具のありがたみを感じるものです。
いきなり方程式を教えられても、小学生当時のあなたは理解できたでしょうか。

 Emacsは人生です。
洞察力を深めるには多くのパッケージに触れて理解に努めましょう。
欲しいパッケージが存在しなければ、自分でelispを書きましょう。

終わりに

 いかがだったでしょうか?
今回は総論的な話題で退屈していたかもしれません(笑)

 筆者は「日刊Emacs」以外にもEmacs病院兼メルマガのサービスを運営しています。Emacsに関すること関しないこと、わかる範囲でなんでも御答えします。「こんなパッケージ知らない?」「挙動がおかしいからなんとかしてよ!」はもちろんのこと、自作elispプログラムの添削もします。集中力を上げるなどのライフハック・マインド系も得意としています。登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#15 知っておくと必ず役立つニッチな標準コマンド (Software Design 2015年7月号掲載記事) Emacs 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

地味な標準コマンドその亜種・仲間

M-zで特定の文字までを削除する

 M-z (zap-to-char)は、標準編集コマンドの中でかなり目立たないコマンドです。カーソル位置からM-zを押した後に入力した文字までを削除し、kill-ringに入れます。たとえば、abcdという文字列があり、カーソル位置がaだとしてM-z cとすると、abcが削除されます。その状態でC-yを押せばabcが貼り付けられます。「カーソル位置から特定の文字までを削除したい」と思ったらM-zの出番です。

abcd
↓M-z c
d

M-zの亜種M-z zap-up-to-char

 実はM-zにはM-x zap-up-to-charという亜種があります。M-zは入力した文字も削除されますが、M-x zap-up-to-charは入力した文字の直前までが削除されます。これは英文やプログラミング言語などスペースで区切られたテキストに対して特に有効で、「特定の文字の直前までを削除してくれ」とEmacsに命令できます。これをM-zで行うとスペースを入力することになり、目的の場所まで削除されず、不便です。

abcd
↓M-x zap-up-to-char c
cd
The quick brown fox
↓M-z SPC
quick brown fox
↓M-z SPC
brown fox

The quick brown fox
↓M-x zap-up-to-char b
brown fox

 けっこう便利なコマンドですが、このコマンドに知名度がない最大の原因は「標準コマンドなのにそのままじゃ使えない」ことに原因があります。misc.elを読み込む必要があります。このファイルには、日常使っているコマンドの亜種などが登録されています。もし、M-zの代わりとして日常的に使いたいならば、以下のように設定します。

(require 'misc)
(global-set-key (kbd "M-z") 'zap-up-to-char)

M-zを見える化するzop-to-char.el

 M-zを使うようになると、今度は削除したい場所の文字が直前の方に現れてしまう不満にさらされることになります。たとえば、「I love Emacs」を「Emacs」に書き換えようとM-z e (zap-up-to-charに再定義済み)と押しても「e Emacs」になってしまい、再度実行する羽目になります。zap-to-char/zap-up-to-charは数引数を指定すればN番目に登場した文字を指定できますが、わかりづらいです。そこでMELPAに登録されている外部パッケージzop-to-char.elの出番となります。今回は標準コマンドに焦点を当てていますが、関連しているので紹介しておきます。

(global-set-key (kbd "M-z") 'zop-up-to-char)

 M-x zop-up-to-charはM-x zap-up-to-charの進化形で、削除対象をハイライトしてくれます。ハイライトされている間は文字入力を受け付け、カーソル位置の次に登場する入力文字までハイライトを広げ、RETでを押した後に削除します。筆者も愛用しています。

 zap-to-charに対応するM-x zop-to-charもあります。

20150422071350.png
Fig1: M-z e

20150422071447.png
Fig2: さらにeを押すと次のeへ進む

単語移動の亜種

 M-f (forward-word)とM-b (backward-word)にはそれぞれforward-to-wordとbackward-to-wordという亜種があります。どれも単語単位の移動ですが、移動先が先頭・末尾になるという違いがあります。forward-wordは末尾に移動しますが、forward-to-wordは先頭に移動します。backward-wordは先頭ですが、backward-to-wordは末尾です。細かい挙動の違いですが、デフォルトの挙動が微妙にしっくりこない方は試してみる価値があるでしょう。

 双方ともmisc.elにて定義されており、M-f/M-bを置き換えればいいです。

(require 'misc)
(global-set-key (kbd "M-f") 'forward-to-word)
(global-set-key (kbd "M-b") 'backward-to-word)

上の行を複製する

 現在のすぐ上の行を複製するには通常はコピー&ペーストが使われると思いますが、misc.elにはM-x copy-from-above-commandというコマンドが用意されています。数引数をつけると、先頭からその文字数だけ複製します。気に入ったのならばキーに割り当てるとよいです。

123456
↓M-x copy-from-above-command RET
123456
123456
↓C-3 M-x copy-from-above-command
123456
123456
123

行をソートする

アルファベット順にソートする

 Emacsにはregion内の行をソートするコマンドがいくつか用意されています。最も簡単なのがM-x sort-linesでアルファベット順にソートします。C-uをつけると逆順にします。

c
x
a

↓M-x sort-lines

a
c
x

↓C-u M-x sort-lines

x
c
a

数値でソートする

 数値でソートするM-x sort-numeric-fieldsもあります。逆順にするには、ソートの直後M-x reverse-regionを実行してください。

8
10
2

↓M-x sort-numeric-fields

2
8
10

↓M-x reverse-region

10
8
2

 M-x sort-numeric-fieldsの数引数は、ソートするフィールドを表します。フィールドとは空白文字で区切られた部分です。これらの行の2番目のフィールドの数値でソートしたい場合です。

ジュース 110
チョコ 20
ポテトチップス 140

↓C-2 M-x sort-numeric-fields

チョコ 20
ジュース 110
ポテトチップス 140

C-u M-|でsortプログラムを呼び出す

 これらのソートコマンドはそれなりに役立ちますが、あまり強力ではありません。もっと複雑なソートをしたいときはUnixツールのsortシェルコマンドに頼るといいです。たとえM-x sort-numeric-fieldsの使い方を忘れてしまったとしても、sortシェルコマンドさえ知っていればC-u M-|で呼び出せます。シェルコマンドはEmacsの外でも使える知識なので極論すればC-u M-|さえ知っていればM-x sort-linesさえ知らなくていいです。

 M-| (shell-command-on-region) はregionを標準入力としてシェルコマンドを実行します。C-uをつけない場合は出力結果を別ウィンドウで表示し、C-uをつけた場合はregionを置き換えます。M-|は「困ったらとりあえず使え」というほど万能なのでぜひとも知っておくべきです。

 :で区切られた行の2番目のフィールドを数値でソートするにはGNU Coreutilsのsortコマンドではsort -k2 -t: -nを使います。他にも多数のオプションがあるので興味ある方はM-x man sortで使い方を見てみるとよいでしょう。

ジュース:110
チョコ:20
ポテトチップス:140

↓C-u M-| sort -k2 -t: -n

チョコ:20
ジュース:110
ポテトチップス:140

elispを評価する

C-x C-eでカーソル直前のelispを評価する

 Emacsには多くの標準コマンドがありますが、C-x C-e (eval-last-sexp)は能力を過小評価されていると思います。このコマンドはカーソル直前のelispの式を評価して、その結果をエコーエリアに表示します。

 機能の説明からすると、一見elispプログラミング中しか使えないと誤解されがちです。しかし、プレフィクスキーがC-xであることから、すべての場面で使えるコマンドだと分かります。任意のバッファで「(+ 3 4)」と入力し、C-x C-eを押してください。7とエコーエリアに表示されます。

 C-x C-eはポイント直前の式を評価するので、ネストした式の内部で使えば、内部の式を評価します。

(+ (* 3 5)
   (- 10 7)
   3)

の1行目ならば15、2行目ならば3となります。3行目は対応する括弧が1行目なので式全体が評価されて21となります。

 C-u C-x C-eで式の評価結果をカレントバッファに挿入します。

ハイパーリンクとしてelispを使う

 C-x C-eがすべてのバッファで使えるということは、いつでもelispの式を評価できることに他なりません。また、コマンド呼び出しは式としても記述できます。このことは、任意のテキストファイルにelispを埋め込んで評価できるということを意味します。

 プログラミング言語や設定ファイルにはコメントが記述できますが、その中にelispを書けば、C-e C-x C-eで即座に評価できます。行末移動+評価ですが、exe(execute、実行)となっているのは面白い偶然です。

 筆者のxmodmap (X Window Systemのキーボード設定プログラム)の設定ファイルはこのように書いてあります。行頭の「!」はコメントです。普段いじらないファイルなので、いざ修正するときはそれに関連する知識を忘れてしまいます。こんな場合には関連情報を開くelispを書いていれば助かります。

! xmodmapのマニュアルページを開く
!   (man "xmodmap")
! xmodmap -pkeを実行し、キーコード一覧を表示する
!   (shell-command "xmodmap -pke")
! ファイルを別ウィンドウで開き、キーの名前を調べる
!   (find-file-other-window "/usr/include/X11/keysymdef.h")
keycode 49 = Escape
...

 これはまさしくelispによるハイパーリンクに他なりません。しかもファイルを開く以外の任意の関数が呼び出せるのでelispでできることなら何でもできます。elispの括弧まみれの構文だからこそ、何も小細工せずに優れたハイパーリンクシステムになったのです。Wikiのような機能を導入しなくても、ハイパーリンクされるのは嬉しいことではないでしょうか。

一連のelispを評価する

 1つのelispの式を評価するならばC-x C-eで十分ですが、複数の式をまとめて評価したいことがあります。M-x eval-regionはregionをelispのコードとして評価し、M-x eval-bufferはバッファ全体を評価します。これらはキーにこそ割り当てられていませんが、いつでもどこでも使えるコマンドです。

 特にeval-regionはelispのコードを含むバッファから直接実行できるので便利です。Emacsについて書いてあるメール・ドキュメントから使えます。Emacs 24.4で標準装備となったWebブラウザEWWでEmacsについて書いてあるサイトを開いたときにも威力を発揮します。EWWはemacs-w3mよりも数倍高速に動作するので、普段のネットサーフィンにはきついですが、Emacsについての調べ事をする際にはとても便利に使えます。

電卓として使う

 Emacsは電卓になります。簡単な計算をするくらいで別なアプリケーションを立ち上げたり、電卓を横に置いておく必要はありません。Emacsの機能を使ってください。

elispで計算する

 M-: (eval-expression)はelispの式を評価してエコーエリアに結果を表示します。C-u M-:とすれば、結果をカレントバッファに挿入します。

 elispはれっきとしたプログラミング言語なので四則計算や数学関数が一通り揃っています。そのため、M-:はelispプログラミングにおいて変数の値や関数呼び出しの結果を見る以外に、普通に関数電卓としても使えます。筆者は簡単な計算をするときは必ずM-:を使っています。

 もちろんelispなのでLispの記法で式を書く必要がありますが、使っていくにつれて慣れます。四則演算(+-*/)と剰余(%)は他言語と同じですが、累乗はexptという関数を使う必要があります。

 たとえば、「30+3^3-4×5」を計算するには、「M-: (+ 30 (expt 3 3) (* -4 5))」と入力し、37という答えを得ます。四則演算は引数を3つ以上取れるので、日常使っている中置記法よりも簡潔になることがあります。

 「(30−4)×5」は「M-: (* (- 30 4) 5)」と入力し、130を得ます。慣れないうちは次のように入力すればよいです。括弧の前後のスペースは省略できます。

(- 30 4)
↓C-aの後に(*と入力
(*(- 30 4)
↓C-eの後に5)と入力
(*(- 30 4)5)

 ただし、除算については注意が必要です。整数どうしで除算をすると答えが整数になるので、小数点以下を求めるならば小数を含める必要があります。

(/ 10 3)     ; => 3
(/ 10.0 3)   ; => 3.333333

 exptの別名を定義すれば「^」や「**」で累乗演算子として使えます。

(defalias '^ 'expt)
(defalias '** 'expt)
(+ 30 (expt 3 3) (* -4 5))  ; => 37
(+ 30 (^ 3 3) (* -4 5))     ; => 37
(+ 30 (** 3 3) (* -4 5))    ; => 37

Calcを使う

 Emacsにはelispで書かれた数学関数ライブラリ・関数電卓アプリケーションCalcが標準でついてきます。ものすごく多機能で複雑な計算ができます。しかし、関数電卓としてはM-:で間に合っているし、複雑な計算には他のプログラミング言語を使うので筆者は使っていません。

 CalcにはC-x * (calc-dispatch)というプレフィクスキーからアクセスします。

C-x *  (Type ? for a list of Calc options)

と出てくるので?を押すと以下のように表示されます。もう一度?を押すと*Help*に詳細が一覧されます。

Calc options: Calc, Keypad, Quick, Embed; eXit; Info, Tutorial; Grab; ?=more

 とりあえずC-x * qで普通の計算式で計算してエコーエリアに表示できます。C-x * q (30-4)*5と入力すれば130と出ます。

 興味ある人はC-x * iでCalcのinfoが見られます。

カラーテーマ

面倒なフェイス設定

 今更言うまでもありませんが、Emacsは文字に色をつけることができます。Emacsでの文字の表現方法をフェイスと呼びます。フェイスは背景色、文字色、文字の大きさ、太さ、アンダーラインなどの設定項目があります。そして、M-x list-faces-displayからフェイスをカスタマイズできます。

20150508083838.png
Fig3: M-x list-faces-display

20150508083923.png
Fig4: isearchでRETを押しカスタマイズ画面

 しかし、1つのフェイスをカスタマイズしても色の相性が悪いと、かえって文字が読みづらくなってしまいます。それに伴い、他のフェイスも変更する必要が出てきて、それの繰り返しになってしまいます。その結果、自分の望んだ色設定になるまで長期間を要してしまいます。

カラーテーマ登場

 個々のフェイスの設定レベルで色を変更しているようでは、なかなかゴールにたどり着けません。そこで先人たちが試行錯誤の末に見付けた色設定集がたくさん用意されています。これをカラーテーマ(color theme)といいます。

 カラーテーマを使えばその開発者の色設定があなたのEmacsに一発で反映されるのであなたは色の相性問題から解放されます。あなたはお気に入りのテーマを選べばいいだけです。

 では、それぞれのテーマはどういう色使いになるのか前もって見ておきたいものです。幸いテーマのスクリーンショットを公開しているサイトがありますので、お気に入りのテーマがありましたら、インストール・設定してください。
https://github.com/emacs-jp/replace-colorthemes/
にたくさんのテーマが集められており、スクリーンショットは
https://github.com/emacs-jp/replace-colorthemes/blob/master/screenshots.md
で見られます。
 また、MELPAにもたくさんのテーマが登録されています。M-x list-packagesからM-s o themeとoccurを実行すれば120以上マッチします。

テーマを設定する

 テーマを設定するにはGUIから行うか、init.elに設定を加えます。

 GUIならばM-x customize-themesでテーマ一覧が出てくるので、望みのテーマでRETを押して選択し、C-x C-sで設定を恒久化します。

 init.elに加える場合は、themeを定義しているelispファイルのファイル名から-theme.el、パッケージ名から-themeを抜いた文字列をload-theme関数に設定します。たとえばcalmer-forest-themeならば

(load-theme 'calmer-forest t)

と記述します。

 Emacsをあなた色に染めてください。

まとめ

Table1: misc.elのコマンドたち

M-x zap-up-to-char 入力した文字の直前までをkill
M-x forward-to-word 次の単語の先頭まで移動
M-x backward-to-word 前の単語の末尾まで移動
M-x copy-from-above-command 上の行を複製

Table2: ソート

M-x sort-lines アルファベット順に昇順ソート
C-u M-x sort-lines アルファベット順に降順ソート
M-x sort-numeric-fields 数値順に昇順ソート
C-u N M-x sort-numeric-fields N番目のフィールドを数値順にソート
M-x reverse-region 行を逆順に並べる
M-| regionを標準入力にしてシェルコマンド実行
C-u M-| regionを標準入力にしてシェルコマンド実行結果に置換

Table3: elisp評価

C-x C-e カーソル直前のelispを評価
C-u C-x C-e カーソル直前のelispの評価結果を挿入
C-e C-x C-e 現在行のelispを評価(ハイパーリンク)
M-: elisp式を評価
C-u M-: elisp式の評価結果を挿入
M-x eval-region regionのelispコードを評価
M-x eval-buffer バッファ全体のelispコードを評価

Table4: Calc

C-x * Calcへの入口
C-x * q 「ふつうの記法」による関数電卓
C-x * i Calcのinfoを開く

終わりに

 いかがだったでしょうか?パッケージ全盛時代でつい外部パッケージに目が行ってしまいがちな今日この頃ですが、あえて標準コマンドに立ち帰ってみました。意外な発見がありましたでしょうか?

 筆者は「日刊Emacs」以外にもEmacs病院兼メルマガのサービスを運営しています。Emacsに関すること関しないこと、わかる範囲でなんでも御答えします。「こんなパッケージ知らない?」「挙動がおかしいからなんとかしてよ!」はもちろんのこと、自作elispプログラムの添削もします。集中力を上げるなどのライフハック・マインド系も得意としています。登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

#14 地味だけどあなどれない標準コマンドたち (Software Design 2015年6月号掲載記事) Emacs 使い方

Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

ちょっと影が薄い標準コマンドたち

 ども、るびきちです。先回はキーに割り当てられた標準コマンドの全体像を示しました。今回もちょっと地味な標準コマンドに光を当てていきます。意外な発見があるかもしれません。

マーク関係

 Emacsにおいてマークは超基本的な機能です。C-SPC でマークし、M-wでコピー、C-wでカット、C-yでペーストというのが基本です。C-y直後にM-yを押せば過去のコピー履歴(kill-ring)に置き換えます。ここではいわゆる普通のコピペ以外の機能を紹介します。マークをもう少し活用してみませんか?

マーク履歴をたどる

 現在のEmacsでは、C-SPCでマークしてカーソルを移動させると、マーク・カーソル間(region)はハイライトされます。そして、たまにカーソルとマークのを入れ替えたいことがあります。それにはC-x C-x (exchange-point-and-mark)あるいはC-u C-SPCを使います。

 実は過去にマークした場所はすべてmark-ringという変数に記憶されています。C-u C-SPCを繰り返せば、過去のマークをどんどん遡れます。

 このことは、regionを作成する以外にも一時的に場所を記憶するためにマークを活用できることを意味します。この目的ではハイライトは不要なのでC-SPC C-SPCでハイライトなしでマークしてください。C-u C-SPCでその場所に戻れます。もちろん、bm.elを使ってもいいです。

 とはいえ、マークを遡るのにC-u C-SPC C-u C-SPC …と繰り返すのは面倒です。そこで、以下の設定を加えればC-u C-SPC C-SPC …とC-SPC連打でどんどん遡れるようになって便利です。

(setq set-mark-command-repeat-pop t)

 マークを遡れるC-u C-SPC対し、C-x C-xは単にマークとカーソル位置を入れ替えるだけのコマンドです。

 明示的にするマーク以外にも、コマンド実行後に自動的にマークされる「暗黙のマーク」もあります。isearchやM-< (beginning-of-buffer)、M-> (end-of-buffer)、C-M-a (beginning-of-defun)、C-M-e (end-of-defun)等、長距離を移動するコマンドは暗黙のマークがなされます。このおかげでisearchで遠い場所に移動してもC-u C-SPCを押せば一瞬で元の場所に戻れるようになります。

 プログラミングにおいてライブラリをrequireしたいときは暗黙のマークを使うといいです。M-<やC-r requireでrequireの羅列に移動し、requireを書き加え、C-u C-SPC で元の場所に戻る、という操作が可能になります。

グローバルマーク

 「暗黙のマーク」含めマークし、かつ別のバッファに切り替えた際には通常のmark-ring以外にもglobal-mark-ringにも記憶されます。これは、マークしたバッファの履歴を辿れることを意味します。

 set-mark-command-repeat-popを設定すればC-x C-SPC C-SPC …と次々とバッファを切り替えられます。ただ、少し挙動が理解しづらいので筆者は使っていません。

単語やS式やバッファ全体をマークする

 regionを作るためには基本的にはC-SPCでマークしてからカーソルを移動させます。しかし、単語とS式については一発でマークするコマンドが用意されています。それぞれM-@ (mark-word)、C-M-SPC (mark-sexp)です。また、連続して使えば次々と単語やS式のregionを広げていきます。C-SPC→M-f、C-M-fと比べると1ストローク差ですが、かなり便利に感じます。筆者は好んでC-M-SPC を多用します。

 C-x h (mark-whole-buffer)はバッファ全体をマークし、カーソルをバッファの先頭に移動します。使用頻度は多くないですが、regionを渡すコマンドに対してバッファ全体を渡したいときには便利です。

矩形regionモード

 Emacs 24.4では矩形regionが導入され、矩形のコピペがとても使いやすくなりました。C-x SPCの後にC-w/M-w/C-yを使うと、矩形のコピペになります。もう煩わしい旧来の矩形コマンドを無理して使う必要はありません。

 C-x SPCを押すタイミングは2通りあります。マーク開始時点かマーク終了時点です。C-x SPCをC-SPCの代わりに使うと、regionは矩形方向に広がります。C-SPCでマークした後にregionを設定してC-x SPCを押すと、その間の矩形を選択してくれます。そのため、使い勝手はかなり良いです。

キーボードマクロ

 キーボードマクロは一連のキー操作を記憶し、後で何度でも呼び出せるようにする機能です。同じ操作を繰り返す場合において確実に手早く処理させられます。Emacsのコマンドをたくさん知っていれば知っているほどキーボードマクロでできることが増えていきます。

 キーボードマクロはプログラミングと異なり、実際にコマンドを実行しながら定義するのでわかりやすいです。繰り返し処理の1回目でキーボードマクロを定義し、以後はキーボードマクロを呼び出せばいいです。

 キーボードマクロは<f3>で定義を開始し、<f4>で定義を終了します。キーボードマクロ実行も<f4>を使います。

 キーボードマクロで繰り返し処理を効率的に行うコツは、定義終了時点において次の繰り返し開始位置に移動することです。そうすることで繰り返し回数が少ない場合に<f4>を連打するだけで次々と実行できるようになります。

 繰り返し回数が多い場合は3つの実行方法があります。

  • C-u 回数 <f4> で回数を指定する
  • C-u 0 <f4> でエラー(バッファ末尾など)が出るまで繰り返す
  • C-x C-k rでregion各行に対してマクロを実行する

 文字列の長さが異なる場合は単語、S式単位の移動やisearchを使ってください。

 キーボードマクロを複数個同時に使いたいならばcentimacroパッケージが便利です。著者の筆者のサイト http://rubikitch.com/2015/03/31/centimacro/ で紹介しています。

地味なコマンドたち

 使用頻度こそ低いものの、知っておくと便利な標準機能を紹介します。

制御文字を入力する

 C-q は次にタイプする文字をそのまま入力します。表示文字以外の制御文字も含まれます。たとえばタブを入力するときはC-q TAB あるいはC-q C-iと操作します。あまりないですがC-aを文字として入力する場合はC-q C-aと操作します。すると別な色で「^A」と表示されます。

 ミニバッファに改行を入力するときはC-q C-jと操作します。たとえばM-%で改行を含む文字列に置換しようとするときにはこの知識が必要となります。

大文字小文字変換

 大文字化・小文字化・キャピタライズ(単語の先頭文字を大文字、その後を小文字にする)のコマンドも揃っています。それぞれ、単語・regionに対応しています。

 M-uは単語を大文字化、M-lは小文字化、M-cはキャピタライズします。これらのコマンドで注意する必要があるのは、カーソル位置から単語の境界までが適用範囲であることです。たとえば「word」のwの位置にカーソルがあるときにM-cを押せば「Word」になりますが、dの後にあるときは変化しません。oの位置ならば「wOrd」になります。

 C-x C-u、C-x C-l、M-x capitalize-regionはそれらのregion版です。C-x C-cはEmacs終了コマンドなので、capitalize-regionはキーに割り当てられていません。

 これらのコマンドはクセがあります。文字入力してから変換するには、単語先頭に戻るか負引数をつける必要があります。たとえば直前の単語を大文字化するにはM-b M-uあるいはM– M-uと操作する必要があります。直前3単語ならばM– M-3 M-uです。あるいは、「ここから変換するよ」という意味でC-SPCでマークし、後でC-x C-uと操作する方法もあります。

 筆者はそれがあまりにも我慢できなかったので、2009年にsequential-commandというパッケージを作成し、M-u/M-l/M-cをデフォルトで直前の単語に作用するように置き換えています。連続的に使った場合はもっと前の単語に作用するようになっています。MELPAに登録してあるので「M-x package-install sequential-command」を実行後、「(sequential-command-setup-keys)」と設定を加えれば使えます。もはやC-x C-uなどを使うことはなくなりました。

Fig1: sequential-command.elでのM-uの挙動

this is a pen.
↓.の後にカーソルを置いてM-u
this is a PEN.
↓M-u
this is A PEN.
↓M-u
this IS A PEN.
↓M-u
THIS IS A PEN.

情報取得コマンド

 バッファやregion、現在位置の情報を表示するコマンドがいくつかあります。

region・バッファの単語数、行数、文字数を表示する

 M-= (count-words-region)は名前とはうらはらにregionの単語数だけでなく行数と文字数も表示します。

 C-u M-=はバッファ全体が対象になります。エコーエリアに「Buffer has 102 lines, 1073 words, and 3639 characters.」などと表示されます。

ページ(バッファ)の行数、現在行を表示する

 Emacsには「ページ」という概念があります。ページとは改ページ文字(^L)で区切られた区間です。改ページ文字が含まれない場合はバッファ全体で1ページとなります。改ページ文字はC-q C-lで入力できます。

 C-x l (count-lines-page)は現ページの行数、及びページ先頭からの行数、末尾への行数を表示します。エコーエリアに「Page has 104 lines (68 + 37)」などと表示されます。この場合、ページ先頭から68行目で、末尾まで73行の計104行ということです。末尾までの行数には現在行もカウントされ、現在行がだぶって数えられるので合計行数が1異なります。

 改ページ文字が含まれない場合はバッファ全体が対象になるので、現在行がバッファのどれくらいに位置するかがわかります。

カーソル位置の情報を得る

 C-x = (what-cursor-position)は現在のカーソル位置の文字についての情報(文字コード・コードポイント)、バッファ内での位置、バッファサイズ、現在桁を表示します。行頭の「#」で実行するとエコーエリアに「Char: # (35, #o43, #x23) point=3151 of 4077 (77%) column=0」などと表示されます。「#」という文字の文字コードは十進数で35、8進数で43、16進数で23です。バッファサイズが4077で現在位置が3151で、バッファの77%に位置します。行頭なので桁は0です。

 C-u C-x =はそれだけでなく、文字の詳しい情報やフォント、テキストプロパティ、オーバーレイの情報も表示します。表示関係のデバッグでも重宝するコマンドです。

表示関係

 カーソル位置、ウィンドウ・フォントのリサイズ、特定行を隠すなどの表示系のコマンドたちです。

カーソルの画面内での位置

 C-l (recenter-top-bottom)は、元々カーソル位置を画面中央に持っていくコマンドですが、現在では拡張されています。C-lを連続的に実行することで画面上部、画面下部に表示させられます。

20150410073220.png
Fig2: 初期位置

20150410073225.png
Fig3: C-lで画面中央

20150410073333.png
Fig4: さらにC-lで画面上部

20150410073339.png
Fig5: さらにC-lで画面下部

ウィンドウの大きさを自動調整

 C-x + (balance-windows)は、ウィンドウのサイズを揃えるコマンドです。C-x 2やC-x 3で画面分割をすると現在のウィンドウを半分にするので大きさが不釣合いになりますが、C-x +で幅や高さが揃います。

 C-x – (shrink-window-if-larger-than-buffer)もウィンドウの高さを調整します。バッファの内容よりもウィンドウが大きくて余白がある場合は、バッファの内容すべてがすっぽり収まるようにウィンドウを縮めます。余白が多すぎて画面がもったいないと思ったら使ってください。

20150410073653.png
Fig6: 不揃いなウィンドウも

20150410073703.png
Fig7: C-x +で均等な大きさに!

20150410073808.png
Fig8: C-x -でウィンドウの余白を除去!

フォントの大きさを変更する

 C-x C-0、C-x C-+、C-x C– (どれもtext-scale-adjust)は、カレントバッファのフォントの大きさを変更するモードに入ります。以後、+で大きく、-で小さく、0で元の大きさに戻ります。それら以外のキーを押すと大きさ変更モードは解除され、元の挙動をします。フォントの大きさが不適切で画面が見辛い場合に使ってみてください。

字下げしている行を隠す(選択的な表示)

 Emacsにはバッファの内容の一部を隠せることはorg-modeで見てきた通りです。org-modeでは見出しと本文の関係性が定義されていて、本文や子見出しを隠せるのでした。実はこのような構文的な要素ではなく、もっと原始的な基準で行を隠す標準コマンドが存在します。

 C-x $ (set-selective-display)は数引数で指定した以上インデントしている行を隠します。このコマンドを使えば、プログラムのアウトラインを簡単に概観できます。メジャーモードの機能を知らなくても、プログラムの全体像が分かります。たとえば、メジャーモードとしてサポートされていないプログラミング言語や設定ファイルであっても、インデントさえしてあれば使えるということです。

 たとえば、インデントされていない行のみ、すなわち1桁目から始まるトップレベルの式・文を表示するにはC-1 C-x $ とします。もう少し深く見たいときはC-3 C-x $ などとします。行を隠すことをやめるには引数なしのC-x $を使います。

 ここで注意していただきたいのは、C-x $はあくまでも行頭のスペースの数のみで判断していることです。改行を含む文字列リテラルの2行目以降はC-1 C-x $しても表示されます。

 なお、数引数ではなくて現在の桁を基準に「選択的な表示」を使うにはMELPAに登録されているcn-outlineパッケージを使います。

20150410073936.png
Fig9: 元の表示

20150410073942.png
Fig10: C-1 C-x $で概観表示

まとめ

 今回採り上げたコマンドを表にまとめます。

Table1: コピペの基本

C-SPC マークをする set-mark-command
M-w コピー kill-ring-save
C-w カット kill-region
C-y ペースト yank
M-y 過去のコピー履歴に置き換える yank-pop

Table2: マーク間の移動

C-x C-x カーソルとマークを入れ替える exchange-point-and-mark
C-u C-SPC 過去にマークした位置に移動 set-mark-command
C-x C-SPC 過去にマークしたバッファへ切り替え pop-global-mark

Table3: 暗黙のマークをする長距離移動コマンド

C-s インクリメンタルサーチ isearch-forward
C-r インクリメンタルサーチ isearch-backward
M-< バッファ先頭へ移動 beginning-of-buffer
M-> バッファ末尾へ移動 end-of-buffer
C-M-a 関数定義の先頭へ移動 beginning-of-defun
C-M-e 関数定義の末尾へ移動 end-of-defun

Table4: 単位ごとのマーク

M-@ 単語をマーク mark-word
C-M-SPC S式をマーク mark-sexp
C-x h バッファ全体をマーク mark-whole-buffer

Table5: 矩形region

C-x SPC 矩形regionモードへの移行 rectangle-mark-mode

Table6: キーボードマクロ

<f3> 定義開始 kmacro-start-macro-or-insert-counter
<f4> 定義終了・実行 kmacro-end-or-call-macro
C-x C-k r 各行で実行 apply-macro-to-region-lines
C-u 回数 <f4> 指定した回数だけ実行  
C-u 0 <f4> エラーが出るまで繰り返し実行  

Table7: 制御文字を入力

C-q 次に入力する文字を直接入力 quoted-insert
C-q C-i タブを入力  
C-q C-j ミニバッファで改行を入力  

Table8: 大文字小文字変換

M-u 単語を大文字化 upcase-word
M-l 単語を小文字化 downcase-word
M-c 単語をキャピタライズ capitalize-word
C-x C-u regionを大文字化 upcase-region
C-x C-l regionを小文字化 downcase-region
  regionをキャピタライズ capitalize-region

Table9: 情報取得コマンド

M-= regionの行数、単語数、文字数を表示 count-words-region
C-u M-= バッファの行数、単語数、文字数を表示 count-words-region
C-x l ページの行数を表示 count-lines-page
C-x = 現在位置の文字、位置、バッファサイズ、現在行の表示 what-cursor-position
C-u C-x = 別バッファによる、より詳細な表示 what-cursor-position

Table10: 表示関係

C-l カーソル表示位置を画面中央・上部・下部に移動 recenter-top-bottom
C-x + ウィンドウのサイズを均等に揃える balance-windows
C-x – 余白をなくすようウィンドウの高さを調節 shrink-window-if-larger-than-buffer
C-x C-0 フォントの大きさを変更 text-scale-adjust
C-x C-+ フォントの大きさを変更 text-scale-adjust
C-x C– フォントの大きさを変更 text-scale-adjust
C-数 C-x $ その数よりインデントしている行を隠す set-selective-display
C-x $ 隠された行を表示する set-selective-display

Table11: 電卓

M-: elisp式を評価してエコーエリアに結果表示 eval-expression
C-u M-: elisp式を評価してカレントバッファに挿入 eval-expression
C-x * Calcへの入口 calc-dispatch
C-x * q 「ふつうの記法」による関数電卓 quick-calc
C-x * i Calcのinfoを開く calc-info

終わりに

 いかがだったでしょうか?パッケージ全盛時代でつい外部パッケージに目が行ってしまいがちな今日この頃ですが、あえて標準コマンドに立ち帰ってみました。意外な発見がありましたでしょうか?

 筆者は「日刊Emacs」以外にもEmacs病院兼メルマガのサービスを運営しています。Emacsに関すること関しないこと、わかる範囲でなんでも御答えします。「こんなパッケージ知らない?」「挙動がおかしいからなんとかしてよ!」はもちろんのこと、自作elispプログラムの添削もします。集中力を上げるなどのライフハック・マインド系も得意としています。登録はこちら→http://www.mag2.com/m/0001373131.html

タグ

このページの先頭へ