第1回 とりあえず書き始めることに

なにか突然書きたくなって、書き始めることにしました。題名もその間はEmacs-Lispの初歩日記としておきます(でも日記じゃないです。内容もEmacs-Lispから脱線することが多くなる予感もします)。


と言ってもそんなすごい事が書けるわけでもなく、正確かどうかも分からず、しかもすぐネタがなくなってしまう気もしますが、自分がへぼいので初心者向けの事がかけるんじゃないかと。超しょぼいことから書いていきたいと思います。まぁC-h i で、Emacs Lisp Intro: (eintr)があればそれを読めば十分なんですが…(このinfoは日本語で読めますし、ぜひ手に入れておきたいところです)。

本でいうなら、

図解でおぼえるMuleの使い方

図解でおぼえるMuleの使い方

がいいんじゃないかと。Emacs-19ベースで、OSはUNIXを対象にしてますが、UNIXに関係あるのは最初の30ページほどで、主に編集コマンドに関しては、それほど今のversionと変わりはないです。この本はEmacsへの愛が感じられるところがいいです。面白いのはキャプチャしたEmacsの画面の写真の中に文章が書いてあるんですが、これが作者の本音だとか愚痴だとか書いてあって、またいいです。

ともあれ、一応このページの対象読者は、Emacs(特にMeadow)をエディターとして使い始めて、デフォルトじゃ使いにくすぎると思ってカスタマイズをある程度して、なんかEmacs-Lisp覚えなきゃだめなのかと思い始めたというくらいの人までとしておきます。書いている僕はといえば、2年ほど前までMeadowC言語のプログラムを書いていました。Meadowは今も使っています。バージョンは家のPCでMeadow-1.15とMeadow-2.10、会社のPCでMeadow-3.00-devです。


とりあえずEmacsはデフォルトはしょぼいんですが、まわりにあるWindowsのエディターと同じくらいの事は調べさえすればできるようになります(Cygwinは絶対必要です)。また「こんな事できたらいいのになー」と思ったときも、たいてい調べれば「自分程度が思いつくことくらいすでに考えている人がいて、しかも実装している」という事が分かると思います。自分がやりたいと思った事が、簡単にできるようになる快感を一度覚えてしまうと、「どんなに調べても出てこねー」となった時には、もう「そのまま使うなんて耐えられない。自分でどうにかしてやる」と思うようになるでしょう。


まずはEmacsについて書きたいと思います。超初歩です。Emacsは全てのコマンド実行がEmacs-Lispの関数を一つ実行する事に当たります(たしか"全て"でよかったはず…)。関数といってぴんと来ない人には、さすがに説明するのは難しいですが、まぁプログラミングをしたことのある人なら、聞いた事のない人はいないと思います。とりあえず、ある機能を持ったプログラムの構成単位です。コマンド=対話的に呼び出せる関数です(Emacsには対話的に呼び出せない関数もあります。これらも他の関数の中からは呼び出す事ができます)。


対話的に呼び出せる関数の呼び出し方について書きますと、

  1. M-x hogehogeM-xEscを押して離してからx、またはAlt押しながらxです一応)というのを打った事があると思いますが、このhogehogeが関数名です(こうやって呼び出せると言う事が対話的ということです)。C-h f hogehogeC-hCtrlを押しながらhです一応) と打てば*Help*バッファが開きその関数のヘルプが読めます。Tabを押すと下線がついたところにカーソルが飛ぶと思いますが、そこでEnterを押せば関数の定義されたファイルが開き関数が見れます(built-in functionと書いてなく、Lisp functionと書いてあるものの場合です。英語はとりあえず読んでくださいです)。
  2. M-xで始まらないキー操作もあります。C-x C-sなどを使った事があると思います。これはC-h kと押してからC-x C-sと押すと、これまた*Help*が開き、C-x C-ssave-bufferというコマンドを走らせていると言う事が分かると思います。関数定義も読めます。この関数がこのキー操作にバインドされていると言う事です。矢印キーやEmacsを終了もコマンドになっています。それどころかC-h kを使えば一文字入力するのもコマンドである事が分かるでしょう。
  3. Emacsはメニューから操作することもできますが、これもC-h kを押してからメニューを選べば、同じくコマンドを走らせている事が分かると思います。
  4. 最後にちょっとプログラミングっぽい呼び出し方を。この場合は対話的に呼び出せる関数以外も呼び出せます。まずM-x switch-to-buffer*scratch*バッファに行ってください。そこで例えば(shell-command "ls -l")と入力して(UNIXを使った事のない人にはls -lはなじみがないかもしれませんが、どうせMeadowをつかうならCygwinが不可欠ですので、覚えておいて損はないでしょう)、その後ろでC-jと打ちます。もしくはC-x C-eです(C-jなんかはインタプリタっぽい見た目ですよね。事実Emacsインタプリタなのです)。この2つのコマンドは少し動作が違いますし、C-x C-e*scratch*バッファ以外でも使えます。この呼び出し方では対話的でない関数も呼び出せるので、(+ 2 3)とか、(* (+ 2 3) 4)なんて式も実行できます。M-:の後に式を入力しても実行できます。これらC-j, C-x C-e, M-xのコマンド名には全部evalという単語が入っていますが、これはevaluateの意味で、Lispで式を実行する事を"評価"するというのは、ここから来てるんだと思います。例えばbuffer-file-nameのような変数も前述の方法で評価する事ができます(ファイルを開けた状態で評価してみるといいと思います)。

Emacsのカスタマイズとは、まずは、すでにあるような機能を有効にするために.emacsなどで既存の関数を呼び出す、または既存の変数の値を設定して、望みどおりの動作をさせるようにするというような(分かりさえすれば)簡単なものもありますが、それ以上のことをしようとするとたいていは関数を自分で作って、その中ですでにある関数などを呼び出すようにプログラミングして、それを手動で呼び出す。または決められたタイミングで自動に呼び出すように設定する。と言う事になると思います。


ともかく自作の関数を作れば、その中で今までやってきた操作(=対話的な関数)はすべて呼び出せますし、これまで簡単に利用できなかった対話的に呼び出し可能でない関数も呼べるようになります。そしてその自作の関数を自分で呼び出せばいいのです。Emacsは拡張性が高いということが、このことから分かっていただけると思います。あと重要なのは正規表現を理解することですね。これを書き換えることでかゆいところに手が届かなかった機能が、自分の思うように動くようになることが多いです。正規表現についてはとりあえず後回しにします(うまくまとめて書くのも難しそうですし)。


とりあえず.emacsを見てみてください。まぁこんな文書をここまで読んでくれた人は()がたくさんあって頭いてーと思う人がほとんどだと思いますが、この何重にもなった括弧のいちばん外の括弧の開き括弧のすぐ右に書かれているのが基本的に関数であると思ってください(関数でないものもあるのですが、今のところ僕はその違いを理解できないままですが、特に困った事はないです。)。関数は関数名の上にカーソルを置いてC-h fと押せばヘルプが読めます。.emacsの中にはsetqloaddefine-keyrequiredefunなどが書いてあると思います(setqdefunは関数でないですがC-h fでヘルプが読めて、そこに書いてあるとおりに使えばいいと言うのは同じです)。


この括弧の中に色々と並んでいるものをリストと言います。リストの先頭にある関数等はそれに続く要素を引数としてとります(引数も初めて聞く人には難しい言葉ですね。まぁ関数の振る舞いを決めるパラメータという事ですね)。ちょっともう日記が長すぎかもしれませんが、自分が最初に作った関数でも書いてみたいと思います。"ls -l (今開いているファイル名)"の出力を一番下のミニバッファに表示します。


(defun my-ls ()
"Run \"ls -l (buffer-file-name)\""
(interactive)
(shell-command (concat "ls -l \"" (concat buffer-file-name "\""))))

です。defun, interactive, shell-command, concatは、C-h fでヘルプが見れます。defunのヘルプを見ると(defun name arglist [docstring] body...)と使うと書いてありますのでもう分かると思いますので特に書きませんが一点だけ。(interactive)の一行はこの関数をコマンドとして対話的に呼び出せるようにするために必要です。buffer-file-nameは変数です。これは上にカーソルをおいてC-h vと押せばヘルプが読めます。


この関数の使い方は、これを.emacsの中に書いてM-x my-lsと打つか、さらに
(define-key global-map "\C-cl" 'my-ls)
と書いてmy-lsC-c lにバインドしてC-c lと打つかです。


ファイルを開いた状況で、実行すれば分かると思いますが、ミニバッファに

-rwx------+ 1 Administrator なし 84 Dec 7 2003 d:/home/***/.emacs*

のように表示されます。


取りあえず今日のところは

  • C-h f 関数のヘルプを見る
  • C-h k キーバインドされた関数のヘルプを見る
  • C-h v 変数のヘルプを見る
  • defun 関数を作る
  • interactive 関数を対話的に呼び出し可能にする
  • define-key 関数をキー操作にバインドする

ということですね

あ、global-mapの説明をしていませんでしたね。これはまた今度と言う事で。

→■第2回 復習してみよう
http://d.hatena.ne.jp/lightcyan/20060929/1159539556