Emacsをカスタマイズするための初歩的なステップ (特に初心者やEmacsを使ったことのない方に向けて)


前置き

Emacsでは M-x shell1によるシェル起動ができますが、この機能をEmacsの起動時に自動的に利用可能な状態にするという(非常に)シンプルな設定を施したいと思います。その過程でEmacsのカスタマイズとは切っても切り離せないEmacs Lispに関連するノウハウをいくつかお伝えしたいと思います。

1. EmacsのM-xで起動できるコマンドは全てLisp言語の関数です

ここでいう関数とは数学的な用語というよりは、C/C++言語等でサブルーチンを関数と呼ぶのと同じケースに該当します。
Emacsの機能のハイレベルな部分は広範囲にわたってLisp言語で書かれている・・・つまり、Emacs Lispの関数の集まりとして定義されています。

ただし、Emacsの基本機能を構成する全ての関数M-xを使って呼び出せるわけではありません。(また、その方が安全で使いやすいはずです) M-x shell のshellをコマンド名とするならば、Emacsの全てのコマンドは(インタラクティブ2な)関数です。

関数とインタラクティブの説明が長くなりましたが、Emacs Lisp関数の呼び出し方について説明しておきましょう。
C/C++言語では funcname(引数1, 引数2) という風に呼び出しますが Lisp言語では (funcname 引数1 引数2) という風にします。関数名も括弧の中に入ってしまいます。それと関数名と引数の間、引数と引数の間には空白が入ります。カンマはマクロ定義(この記事では取り扱いません)で特別な意味を持つ記号ですので書いてはいけません。

また、M-x で呼び出せる(インタラクティブな)関数の多くは、引数なしで呼び出せます
コマンドとしての役割を果たすインタラクティブな関数は、キーボードのキーシーケンスやマウスイベントに割り当てたりできますが、プログラムのソースコード内に現れているわけではないので、引数は渡せません3。M-x shell を起動することは (shell) というLispコードを実行することと同じです。

2. 一番簡単な方法として、Emacsのコマンドライン引数を使ってLisp関数を起動してみましょう。

引数なしで呼び出せる関数は、Emacsをシェルから起動する際のコマンドライン引数で指定して起動できます。
(shell)関数を呼び出すには、bashプロンプトから次のように入力します。(-nwはウィンドウモードを抑制してコンソール内でEmacsを実行するための指定です。Emacsを実際に使うまではあまり意識しなくて構いません)

$ emacs -f shell

または

$ emacs -nw -f shell

3. シェルウィンドウ単独で起動したい

ことにします。Emacsに習熟している方なら知っていると思いますが、他のウィンドウが表示されないようにするには C-x 14 というキー操作を使います。上の説明で M-x はコマンドを起動し、コマンド=Lisp関数であると説明しましたが、C-x 1というキー操作も(実は)コマンド(つまりLisp関数)を実行しているのです。

キーシーケンスが一体どんな(何という名前の)Lisp関数を起動するのかを調べなくてはなりません。Emacsのカスタマイズを(Lispを使って)行うための第一歩(と私が思うこと)は、キー操作に該当するLisp関数名を調べたり覚えたりすることです。ここで重要なことはコマンド名(Lisp関数名)が分かれば、キー操作でできることを M-x を使ってもできるようになるということです。

キー操作(キーバインディング)もありますが、逆に覚えやすい(またはキー操作の設定を変更しても対応できる)ことから、M-x による起動方法を説明しておきます。M-x describe-key と入力して ENTER を押します。

Describe key (or click or menu item):と表示されますので、C-x 1と入力します。

4. M-x shell に続けて M-x delete-other-windows を実行すれば良い

わけですから、これをシェルから起動する際のコマンドライン引数で指定してみましょう。-f では一つの関数名しか指定できませんので(実は技があります。後述)、--eval '任意のLispコード'を使うことにします。Lispで複数の関数を連続して実行するにいは(progn (関数名1) (関数名2))というコードを書けば実現できます。ということで、bashプロンプトで以下のように実行します。(ウィンドウモードで起動する場合には-nwは不要です)

$ emacs -nw --eval '(progn (shell) (delete-other-windows))'

5. なぜか今頃・・・.emacsをいじってみる

emacs -nw --eval '(progn (shell) (delete-other-windows))'なんて長ったらしいし、手入力するのはとても困難です。
-f では一つの関数名を指定できますから関数作っちゃいましょう!

後から、コマンドにすることも考えてmy-shell-onlyという名前にしてみます。関数定義の中では(progn)を使わなくても複数のコマンド(=Lisp関数)を続けて呼び出すことができます。以下は .emacs を編集しているところです。

.emacs に my-shell-only 関数を定義したら保存して、Emacsを終了します。bashに戻ったら次のようにします。シェルウィンドウ単体でEmacsが起動するのが確認できます。

$ emacs -nw -f my-shell-only

6. M-x my-shell-only で起動できるようにする

にはどうしたら良いでしょう。上述の(interactive)という記述を関数定義にいれます。ついでに改行とインデントもいれましょう。

7. Emacsを終了しないで .emacs の設定を試す

とりあえず .emacs の保存はしておきましょう。M-x eval-bufferを実行します。

8. my-shell-only をキー操作に割り当てる

9. 実は -f を複数使えば良かった

Emacsを終了してbashプロンプトから以下のようにして起動してみましょう。

$ emacs -nw -f shell -f delete-other-windows

これなら手打ちもできそう(?)ですね!

追記(2017/05/03)

おっと「ユニバーサル引数」を紹介するのを忘れていました。検索していただければ見つかると思いますので、M-x shell に対してユニバーサル引数を適用するとどうなるかだけ説明しておきます。通常 M-x shell では *shell* という名前のバッファが作られます。そして、(この点を不便に思われている方もいると思いますが) もう一度 M-x shell を起動しても2個目のシェルバッファ(シェルウィンドウ)は作成されず、既存の *shell* バッファが選択されるだけです。2つ以上のシェルを使うことはできないのでしょうか? 実は使えます。

C-u M-x shell として (Alt-X)の前にCtrl-Uを入力する) 起動すると下図のようにバッファ名を聞いてきます。デフォルトのバッファ名は必ずユニークな名前になっていますので、そのまま ENTER を押せば2つ目以降のシェルバッファを使うことができます。このときに、即座に ENTER を押さないで、find-python-source ENTERのように、何のために用いるのかが分かるようにしておけば、後で C-x b や C-x C-b 等でバッファを切り替える場合に便利な場合があります。


脚注


  1. Emacsのバッファの中でシェル(コマンドプロンプト)を実行できる機能Windows環境では Alt-X shellで起動できます。 

  2. 「対話的」。(defun)の中に(interactive)という宣言を書くことでインタラクティブな関数であるとEmacsが自動的に判断する。キーボードから M-x を入力した後にTABキーを押すと候補が出てきますが、それらのコマンドは(interactive)宣言付きのLisp関数です。 

  3. 実は、ユニバーサル引数というものを渡す操作があります。 

  4. Emacsの操作説明で C-x という記述がありますが、これは Ctrl-X を入力することを意味しています。