これは、Emacs Lispの入門チュートリアルです。
主な参考文献は、以下の記事になります。
参考文献というか、ほぼこの記事を日本語翻訳したに近いです...
はじめに
ここでは、まだEmacsを入れたことがない人向けにEmacsのインストール方法を紹介します。
インストール
以下のサイトからインストールすることができます。
以下もおすすめ
また、macOSの場合、以下のサイトでインストールをすることをお勧めします。
このままでも良いのですが、以下の記事を参考に、簡単な設定をすると良いかもしれません。
Emacsの操作方法
Emacsでは基本操作をEmacsの中で学ぶことができます。
Control(以下、C)を押しながら、hを押し、次にtを押す、つまりCtrl-h + tと入力すると、チュートリアルに移動します。
最初はここから、基本的な操作を学ぶと良いでしょう。
また、英語が苦手な方には、Esc + xを押して、help-with-tutorial-spec-language Japanese を実行すると、日本語のチュートリアル記事を読むことができます。
また、それでも不安という方は、Webサイトがあるので、こちらを参考にすると良いでしょう。
scratch バッファ
Emacsを起動したら、ウェルカムメッセージが開くと思ういます。こちらを q key を押して閉じてください。
ウィンド下部のグレーの行を見てください。"scratch"とあれば、成功です。
"scratch" は現在あなたがいる編集スペースの名前です。
この編集スペースを「バッファ」と呼びます。
scratchバッファは、Emacs起動時のデフォルトバッファです。
ここでは、Emacs Lisp(以下、Elisp)を手で書き、コマンドを使って評価することができます。
多くのEmacsユーザーは、この画面で簡単な計算やコードの確認を行う(らしい)。(参考:podcast Vim-jp radio)
本題
ここからは実際に ELisp を触っていきます。
コメントアウト
セミコロンで、行のどこからでもコメントを開始できます。
;; コメントアウト
S式(sexp)
Elisp プログラムは、S式(sexp / S-expression) で構成されます。
S式はシンボリック式(symbolic expression)とも呼ばれます。
以下のS式は「2 + 2」を意味します。
(+ 2 2)
S式はカッコで囲まれ、ネストすることもできます。
(+ 2 (+ 1 1))
S式は、アトム(原子) か、他のS式を含みます。
上の例では 1 と 2 がアトム、(+ 2 (+ 1 1)) と (+ 1 1) がS式です。
評価
lisp-interaction-mode からS式を評価できます。
閉じカッコのすぐ後ろにカーソルを置き、C-j(Control + j)を押します。
-
C-jは評価結果をバッファに挿入します。 -
C-x C-eは、Emacs 下部のミニバッファに結果を表示します。
setq
setq は変数に値を格納します。
(setq my-name "Alice")
;; my-name に "Alice" が格納される
insert
insert はカーソル位置にテキストを挿入します。
(insert "Hello!")
insert は複数の引数を取れます。
(insert "Hello" " " "world!")
変数を扱うこともできます。
(setq my-name "Alice")
(insert "Hello I am " my-name)
;; Hello I am Alice
関数
関数は defun で定義します。
(defun hello (name)
(insert "Hello " name "!"))
(hello "Bob")
;; Hello Bob!
別のウィンドウに切り替えることもできます。
(switch-to-buffer-other-window "*test*")
C-x C-e を実行すると、新しいウィンドウが開き *test* バッファに移動します。
元のウィンドウには、マウスまたは C-x C-o で戻れます。
複数のS式を progn でまとめる
ここまでのコードを1つにまとめてみましょう。
(defun hello (name)
(insert "Hello " name " !"))
(progn
(switch-to-buffer-other-window "*test*")
(hello "you"))
C-x C-e を実行すると、*test* バッファに「Hello you !」が挿入されます。
次に、バッファの内容を事前に削除する処理を追加しましょう。
(defun hello (name)
(insert "Hello " name " !"))
(progn
(switch-to-buffer-other-window "*test*")
+ (erase-buffer)
(hello "you"))
さらに、実行後に元のウィンドウへ戻るようにしましょう。
(defun hello (name)
(insert "Hello " name " !"))
(progn
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(hello "you")
+ (other-window 1))
let を使うと、ローカル変数に値を束縛できます。
(defun hello (name)
(insert "Hello " name " !"))
(let ((local-name "World"))
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(hello local-name)
(other-window 1))
format を使うと、文字列をフォーマットできます(C 言語の printf と同様の使い方です)。
(format "Hello %s!\n" "visitor")
format を使って hello 関数を改良しましょう。
(defun hello (name)
(insert (format "Hello %s!\n" name)))
(hello "you")
C-x C-e を実行すると、「Hello you!」が挿入されます。
関数をリストの各要素に適用する
以下の関数を作成して呼び出します。
(defun greeting (name)
(let ((your-name "Bob"))
(insert (format "Hello %s!\n\nI am %s.\n" name your-name))))
(greeting "you")
;;; 出力結果:
;;
;; Hello you!
;;
;; I am Bob.
変数のリストを作成します。
(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
car でリストの先頭要素を取得できます。
(car list-of-names)
C-x C-e で確認すると、"Sarah" が出力されます。
cdr は先頭以外の要素を返します。
(cdr list-of-names)
C-x C-e で確認すると、("Chloe" "Mathilde") が出力されます。
push でリストの先頭に要素を追加しましょう。
(push "Stephanie" list-of-names)
C-x C-e で確認すると、("Stephanie" "Sarah" "Chloe" "Mathilde") が出力されます。
注意:
carとcdrはリストを変更しませんが、pushはリストを変更することに注意してください。
mapcar を使うと、hello 関数をリストの各要素に適用できます。
(mapcar 'hello list-of-names)
まとめて実行してみましょう。
(progn
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(mapcar 'hello list-of-names)
(other-window 1))
*test* バッファに、list-of-names の各名前に対して hello 関数が実行された結果が表示されます。
色々アレンジしてみる
search-forward と replace-match を使って、「Hello」を「こんにちは」に置き換えます。
(defun hello-to-konnichiwa ()
(switch-to-buffer-other-window "*test*")
(erase-buffer)
;; list-of-names の各名前に挨拶する
(mapcar 'hello list-of-names)
(goto-char (point-min))
;; "Hello" を "こんにちは" に置き換える
(while (search-forward "Hello" nil t)
(replace-match "こんにちは"))
(other-window 1))
(hello-to-konnichiwa)
名前を太字にしてみましょう。
(defun boldify-names ()
(switch-to-buffer-other-window "*test*")
(goto-char (point-min))
(while (re-search-forward "こんにちは \\(.+\\)!" nil t)
(add-text-properties (match-beginning 1)
(match-end 1)
(list 'face 'bold)))
(other-window 1))
(boldify-names)
この関数では re-search-forward を使っています。
search-forward が文字列をそのまま検索するのに対し、re-search-forward は正規表現(regular expression / regex) を使ってパターンを検索します("re-" はその略称です)。
add-text-properties は、フォントフェイスなどのテキストプロパティを追加します。
最後に
今回の記事でカバーした主な概念をまとめます。
| 概念 | 説明 |
|---|---|
sexp |
S式(S-expression)。シンボリック式とも呼ばれる。Elispの基本的な単位 |
setq |
変数への値の代入 |
defun |
関数定義 |
let |
ローカル変数への値の束縛 |
progn |
複数のS式をまとめて順番に実行 |
mapcar |
リストの各要素に関数を適用 |
car / cdr
|
リストの先頭 / 先頭以外を取得 |
push |
リストの先頭に要素を追加 |
while |
ループ |
search-forward |
文字列検索 |
re-search-forward |
正規表現検索 |
format |
文字列フォーマット |

