Emacsクイズ - かいとう編
風邪でダウンしていたので、更新がおそくなってしまいましたが、回復してきたのでまとめることにします。解答してもらった方には、わかる範囲でトラックバックさせてもらってます。
解答は、問題作成時に考えていた解答例です。いろいろな人の解答を見ておもしろいものなどはコメント、解説で触れることにします。
きほん編
- q1. 一般的に"カーソル"と呼ばれる、タイプされた文字やテキストの挿入が行われる位置のことをEmacsでは何と言う?
- A. ポイント
知ってるようで意外と知らない豆知識。入門 GNU Emacs 第3版 の6ページにもちゃんと書いてあったりします。
特にEmacsに詳しい人々は、カーソルのことをポイントと読んでいます。この用語は、オンラインヘルプシステムでも統一して使用されていますので覚えておいてください。
- q2. split-window-horizontally(ウィンドウを水平に2分割)するキーバインドは何?
- A. C-x 3
C-x 3だって!なにー!horizontallyって普通C-x 2的な分割のことをいうんじゃないのか!!!だまされた!!!!!まぁ、実際使う時は間違えないからいいけどw
フヒヒ、サーセンwww 水平、垂直って結構まちがいやすいので、図解も問題と一緒にのせておけばよかったかも。C-x 2とC-x 3が使えていれば何も問題はないと思います。
- q3. C-x C-t というキーバインドが、どのコマンドに割り当てられているかを調べる方法は?また、調べた結果は?
- A. C-h k C-x C-t, C-x C-t は transpose-lines
Emacs クイズ - odz bufferとかEmacs クイズ - とりあえず暇だったし何となくはじめたブログとかで挙げられている C-h c (describe-key-briefly) は知らなかったですね。勉強になりますです。
q3. うちだと F1-k が describe-key になっている。で transpose-lines というのは始めて知った。使わなさげ…
使ったことないキーバインドを適当に叩いてみたら、たまたまtranspose-linesだったんでつwww
おうよう編
- q4. "カーソル"の手前の1文字を削除する方法を、Back spaceをタイプする以外の方法で行うにはどうすればよい?
- A. M-x backward-delete-char, または M-: (delete-region (max 1 (- (point) 1)) (point))
豆知識: Back spaceにbindされているのはbackward-delete-charではなく、backward-delete-char-untabify。Back Spaceでタブを消すと、タブがスペースに変換されて、1文字幅ずつ消せるようになってるんですよ。知ってた?
なので、back spaceでは厳密に言うと、"ポイントの手前の1文字を削除"できないです。
問題の定義が曖昧なのがアレだけど、ポイントがバッファの先頭にあるとき、ポイントの手前に文字は無いので何も削除しないのが"正しい"振舞いだとします。すると、C-b C-dではちょっとだけ間違い。
M-x backward-delete-char は正解です。
そしてさらにその先を考えてみると、backward-delete-charでも役不足な場合があったりなかったり。例えば、ポイントの手前のN文字を削除したい場合のことを考える。(backward-delete-char N) でOKな気もするけど、バッファの先頭とポイントの間にN-1個以下の文字しか無い場合、backward-delete-charは1文字も削除してくれません。
これはあんまり嬉しくないよねー、という場合は、(delete-region (max 1 (- (point) N)) (point)) とやってあげればOK。
なんというか、emacs lispばっかり書いてるとこういう下らないことばっかり考えてしまいます。
- q5. "hello"という文字列が名前に含まれるコマンドの一覧を取得する方法は?
- A. C-h a hello
M-x apropos でも良いけれど、C-h a (apropos-command)のほうが検索範囲をコマンドのみに絞れて便利ですよん。aproposはインターンされているシンボル全部が対象になっているはず。
aproposを使わない方法としては、Emacs クイズ - (new Hatena).blog()の方法が興味深いです。
(mapatoms (lambda (s) (if (and (string-match "hello" (symbol-name s)) (interactive-form s)) (insert (format "%s\n" s)))))いちおう参考のために説明させていただきますと、mapatoms はインターンされている全シンボルを枚挙する関数です。
で、シンボルが特定パタン (正規表現) にマッチするか、そしてそれがコマンド (interactive な関数) かどうかをテストし、バッファに書き出しています。
(中略)
ちなみに、特定の文字列を含む「変数」を得たければ boundp、「関数」一般を得るには fboundp を用います。
mapatomsにfboundpを組み合わせれば、apropos-functionが作れそう。デフォルトでapropos-functionが無いのはなんでだろう。
- q6. 一度 "pneumonoultramicroscopicsilicovolcanoconiosis" (珪性肺塵症という意味の単語) と打った後に、再び同じ単語を入力する必要に迫られた。kill&yank以外の方法では、どのように"pneumonoultramicroscopicsilicovolcanoconiosis"を入力するのがよいだろうか?
- A. M-/ (dabbrev-expand)
これは特に言うこともないかな。ちょっと調べてみたら、C-M-/ (dabbrev-completion) なんてのもあったので試してみるのもよいかと思いますよ。ちなみに個人的には、dabbrev-expandはC-SPCにバインドするのがお気に入り。
- q7. マウスでクリックすると http://hayamin.com/ をブラウザで開くようなテキストをバッファに挿入する方法は?
- A. uriという名前のテキスト属性で、"http://hayamin.com/"を文字列に付加してinsertする。その後、クリックしたテキストがuriというテキスト属性を持っていた場合に、そのURIをbrowse-urlで開く。
(let ((str "this is a linked text.")) (add-text-properties 0 (- (length str) 1) `(mouse-face highlight uri "http://hayamin.com/") str) (insert str)) (defun emacs-quiz-click () (interactive) (let ((uri (get-text-property (point) 'uri))) (if uri (browse-url uri)))) (local-set-key [mouse-1] 'emacs-quiz-click)
ちなみに、mouse-faceというテキスト属性にhighlightという値を設定すると、マウスをそのテキストの上にのせたときに色が変わってよりリンクっぽくなる。
さすがに誰も完答してくれなかった(^ω^;) Emacs Lisp Referenceを目を皿のようにして読めばわかるけど、知らなくてもきっと困らない知識っすね。メジャーモード作者ならば知っておきたい。
いみふ編
- q8. foo-bar<1>, foo-bar<2>, foo-bar<3>, ... , foo-bar<1000> という名前の1000個のバッファを開いているとする。これらのバッファを全てkillする方法は?
- A. cl-macs.elで定義されているdoマクロを使う
(require 'cl) (do ((i 1 (+ i 1))) ((> i 1000) t) (let ((buf (get-buffer (format "foo-bar<%d>" i)))) (if buf (kill-buffer buf))))
(dolist (b (buffer-list)) (if (string-match "^foo-bar" (buffer-name b)) (kill-buffer b)))
うあーこっちのほうがスマートだー。わざわざget-bufferして、ifでバッファが存在しているか確認する手間もないし。すばらしい。
どう考えてもq8よりq7のほうがイミフです。本当にありがとうございました。
また気がむいたらEmacsクイズやるかもしれません。そのときはよろしく。