まあ、置換とかは replace-buffer とかで一発なんだが、もちょっと凝ったことをしたいときがある。
今まではバッファを1行づつ処理するときは、
(while (null (eobp))
(let* ((beg (save-excursion (goto-bol) (point)))
(end (save-excursion (goto-eol) (point)))
(s (buffer-substring beg end)))
(dbg-msgbox s) ; やりたい処理
(forward-line)))
とかやっていた。
すごく冗長に感じていたし、カーソルを動かしたりするのがやるせなかった。行頭と行末のポイントが欲しいだけなのに、save-excursion するのとか、不必要に let* 使うのもちょっと変だと思っていた。まあ、いろいろキモかった。
もうちょっと読みやすいのを考えてみた。今回はマクロで。
;;; バッファを1行ずつ処理する
;;; e.g. (loop-at-buffer (line)
;;; (dbg-msgbox line))
(defmacro loop-at-buffer ((var &optional buffer) &body body)
(let ((gbuf (gensym))
(gstream (gensym)))
`(let* ((,gbuf (cond ((null ,buffer) (selected-buffer))
((bufferp ,buffer) ,buffer)
(t (find-buffer ,buffer))))
(,gstream (if ,gbuf (make-buffer-stream ,gbuf)
(error "\"~A\"という名前のバッファが見つかりません" ,buffer))))
(loop
(let ((,var (read-line ,gstream nil)))
(unless ,var (return nil))
,@body)))))
これを使うと、上の例は↓こう書けるようになる。
(loop-at-buffer (line)
(dbg-msgbox line))
わりといい感じになった。
パラメータは下記の2つ。
- 第1パラメータは、バッファの1行を取り出した文字列を入れる変数を指定する。省略不可。
- 第2パラメータは、回すバッファを指定する。省略時は現在のバッファになる。
ちなみに、マクロ内で使ってる make-buffer-stream は xyzzy の関数なんだが、引数に nil を渡すと適当になんかのバッファ(selected-buffer か?)に紐づいたストリームを返すみたいで、具合が悪い。その対策を入れてある。
・・・とここまでやっておいて、実は with-input-from-buffer があったことに気づく。
また車輪やってしまった。
0 コメント :
コメントを投稿