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 なことをやっている。本格的に作るにはちょっと骨が折れそう。