rangesource ハック
以前から、バッファ中のテキストの一部を vimscript として実行する関数が欲しかったので、実装してみようと思った。
要は、範囲指定して:so か :exe をしたいのだが、どちらがよりふさわしいだろうか?おそらく :exe なのだろうけど、スクリプト以外では :so の方が使い慣れているので、:so で範囲指定できるようにしてみた。
まず以下は最初にやってみた方法。
--- ../src.orig/ex_cmds.h 2006-06-23 04:30:41.001000000 +0900 +++ ex_cmds.h 2006-08-21 09:43:38.000000000 +0900 @@ -846,7 +846,7 @@ EX(CMD_snoremenu, "snoremenu", ex_menu, RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_source, "source", ex_source, - BANG|FILE1|TRLBAR|SBOXOK|CMDWIN), + RANGE|BANG|FILE1|TRLBAR|SBOXOK|CMDWIN), EX(CMD_sort, "sort", ex_sort, RANGE|DFLALL|WHOLEFOLD|BANG|EXTRA|NOTRLCOM|MODIFY), EX(CMD_split, "split", ex_splitview,
--- ../src.orig/ex_cmds2.c 2006-04-17 19:19:07.001000000 +0900 +++ ex_cmds2.c 2006-08-21 10:15:38.703125000 +0900 @@ -2627,6 +2627,15 @@ ex_source(eap) exarg_T *eap; { + if (eap->addr_count > 0) { + int i; + + for (i=eap->line1; i<=eap->line2; i++) { + do_cmdline(ml_get(i), NULL, NULL, DOCMD_NOWAIT); + } + return; + } + #ifdef FEAT_BROWSE if (cmdmod.browse) {
しかしこれだと範囲内に :function があるとき、次の行の入力待ちに入ってしまうのでダメ。
そこでテンポラリファイルを使う美しくない方法。
--- ../src.orig/ex_cmds2.c 2006-04-17 19:19:07.001000000 +0900 +++ ex_cmds2.c 2006-08-21 10:32:27.218750000 +0900 @@ -2627,6 +2627,24 @@ ex_source(eap) exarg_T *eap; { + if (eap->addr_count > 0) { + FILE* fp = NULL; + int i; + char_u* fname = "/tmp/tmp.vim"; + + fp = fopen(fname, "w"); + + if (fp) { + for (i=eap->line1; i<=eap->line2; i++) { + fprintf(fp, "%s\n", ml_get(i)); + } + + fclose(fp); + cmd_source(fname, eap); + } + return; + } + #ifdef FEAT_BROWSE if (cmdmod.browse) {
スクリプトを読み込んで実行する関数 do_source() の中では次行を読み込むのにコールバックを使ったり、しかもそのコールバックを特定の関数と比較したりと大分 hairy なことをやっている。本格的に作るにはちょっと骨が折れそう。