snippet.l をごにょごにょしてみた

とりあえず snippet てのはテンプレートを展開した後で部分的に書き換えたりできるような、そんな感じ。
なんともタイムリーに中の人が ScreenCast なぞしてくれてる。
http://white.s151.xrea.com/wiki/index.php?diary%2F2007-01-18%2Fsnippet%20screencast
url のリンクじゃなくて、その下にある「ここからどうぞ」ってやつ。

んで、~/.abbrev_defs に

("function" "function${1/./ }${1:name}(${2:arg}){
    $0;
};" nil 0)

なんてのを書いとけばその通り展開して ${n:hoge} んとこを書き換えたりできるのだが

var myObj = {
    method: func! //<-ここで展開
};

とかしたときは

var myObj = {
    method: function(arg){ //<-まずは name を入力できるんで消して、その次 arg
        ! //<-展開終わったらここへ
    };
};

となって欲しいのだが

var myObj = {
    method: function(arg){ 
    ! //<-インデントがそのまま
};
};

とインデントが ~/.abbrev_defs に書いてあるままになっちゃうんで

ごにょごにょしてみた

改行+なにか*1で mode-specific-indent-command するように。

; snippet.l の 410 行目くらい(コメント入れすぎて元のがわからん
; (defun snippet-expand () の割と頭付近
		 (setf *snippet-end* (point)) ;*snippet-end* にカーソル位置を代入
		 (goto-char *snippet-begin*) ;*snippet-begin* へカーソルを移動

		 ;;+ \n の後は mode-specific-indent-command でインデント
		 (while (scan-buffer "[^\\]\\(\n\\).+" :regexp t :limit *snippet-end*)
		   (let ((head (match-end 1)) indent-end)
			 (goto-char head)
			 (funcall mode-specific-indent-command)
			 (setf indent-end (point))
			 (setf *snippet-end* (+ *snippet-end* (- indent-end head)))
		   ))
		 (clear-undo-boundary)
		 (goto-char *snippet-begin*)
		 ;ここまでインデントの
		 
		 (while (scan-buffer "\\(?:[^\\]\\|^\\)\\($\\(?:\\([0-9]\\)\\|{\\([0-9]\\)\\(?::\\([^}]+\\)\\)?}\\)\\)"

problems

javascript-mode では '$0' が書いてある状態でそれ以降のインデントがずれる。$0${0/./;}って書いといたらだいじょぶっぽい。
py-mode は mode-specific-indent-command が定義されてないんでエラーになる。定義して py-indent-line にしといたら今んとこ動いてる。

; py-mode.l の 560 行目あたり
; (defun py-mode () の中
    (setq keyword-hash-table *py-keyword-hash-table*))
  (make-local-variable 'indent-tabs-mode)

  ;;+ mode-specific-indent-command に py-indent-line を設定
  (make-local-variable 'mode-specific-indent-command)
  (setq mode-specific-indent-command 'py-indent-line)

  (setq indent-tabs-mode *py-indent-tabs-mode*)

javascript-mode と py-mode しか見てなくて他のモードはテストもしてない。きっとエラー出るんだ。そうに決まってる。

感想

とりあえずがーっとソース読んでみたら、今んとこなんとか理解はできてる。半分くらいしか読めてないけど。何してるかはっきりわかってないんで *snippet-end* いぢってるのがちょっと怖い。
${n:hoge} の hoge を全部消したときがなんかおかしいんだが、中の人も苦労してるようだ。ガンバレ。
lisp はなんかおっかないイメージあったけど javascript とか python とかと比べて思ってたほど違うもんではないようだ。熱帯魚と秋刀魚くらいの違い。どっちもよくわかってないが。
html+-mode で "<div>!" から "<div id='[id]' class='[class]'>" とか展開できればなーと思うのだが、"<" がダメっぽい。これは abbrev の方をいぢらなきゃならなそう。


追記 21/jan/2007 12:50

中の人が実装してくれた!
http://white.s151.xrea.com/wiki/index.php?diary%2F2007-01-20%2Fsnippet4
ありがたく使わせて頂きます。

*1:空行は放置