[elisp] simple.elを読む

emacs標準で入ってるsimple.el. transient-mark-modeとかkill-wordとかの実装がなされていることが分かりました。

読んでいると、ふむふむと納得させられるようなコードが多くためになりました(`・ω・´)。

例として、kill-wordをとりあげてみてみます。kill-wordはデフォルトだと、M-dにキーバインディングされています

ソースは以下のようになっていました
(defun kill-word (arg)
  "Kill characters forward until encountering the end of a word.
With argument, do this that many times."
  (interactive "p")
  (kill-region (point) (progn (forward-word arg) (point))))
ちょっとだけ解説してみます。

argは引数です。あるコマンドを実行する前にC-u 数値 とコマンドを入力をすると関数の引数を設定することができます


(interactive "p")は対話モード+pオプションなのですが、pオプションが何をやっているのかしらなかったので調べたところ、以下のようなことが分かりました

この関数では、式(interactive "p")は、要素2個のリストである。 "p"は、前置引数を関数に渡すことをEmacsに指示するもので、その値を関数への引数として使う。

via bookshelfです。 ようするに引数を関数に渡すって事を宣言しているってわけです


次にkill-regionなのですが、これはstarとendを指定し、startからendの間の領域を消去する関数です。


kill-regionのサンプル
(kill-region (point-min) (point-max)) ;全てを消し去る
(kill-region (point) (point-max))     ;現在位置から最後まで消し去る
(kill-region (progn (backward-word(point)) (progn (forward-word) (point))) ; 現在位置にある単語を消し去る
prognは特殊な関数で、以下のように定義されています
 -- Special Form: progn forms...
     This special form evaluates all of the FORMS, in textual order,
     returning the result of the final form.

          (progn (print "The first form")
                 (print "The second form")
                 (print "The third form"))
               -| "The first form"
               -| "The second form"
               -| "The third form"
          => "The third form"

用は、全ての式を順番に評価し、最後に評価した値を返り値として返す関数って事です。


同じような関数に、progn1とかもあります。これは返り値として最初に評価した値を返します。pop関数の実装の時とかにprogn1は使われていた気がします。


まぁつまり(forward-word arg)でarg文だけwordを移動した位置をpointに入れているってわけです。


以上のことをまとめると、現在の位置から、引数指定したforward argの位置までの領域を消去するということをkill-wordはやりのけているということがわかります。


説明としてはこんな感じになります。なんか間違えているかもしれませんが(ノ∀`)

ついでにbackword-kill-wordも
(defun backward-kill-word (arg)
  "Kill characters backward until encountering the end of a word.
With argument, do this that many times."
  (interactive "p")
  (kill-word (- arg)))

ふもっふ(`・ω・´)backwordのほうは、思いっきり、kill-wordを使った仕様となってますね。

これを利用してvimの検索機能*は実現できないものかと思案中(´・ω・`)

おまけ: 次のような関数を作ってみました。現在指している単語を消し去る関数です。
(defun kill-this-word ()
  "kill a word now pointed to"
  (interactive)
  (kill-region (progn (backward-word)(point)) (progn (forward-word) (point)))
)

結構使えます。kill-wordの2倍ぐらい便利です。

ちなみに自分は.emacsの中で

(define-key global-map "\C-cd" 'kill-this-word)

という風にして、登録しています。