ledit-1.10

ちょっと前にgoshのコマンドラインエディットの為に入れてみた ledit。INRIAご謹製ということで、もしかして、とか思っていたのだけれど、予想通り中身は Ocamlで書いてあって、caml苦手なぼくにはちょっと大変そう。しかも拾ってきてコンパイルしようとするといきなり、

File "pa_local.ml", line 24, characters 2-10:
Parse error: Deprecated syntax, the grammar module is expected

え〜、なによそれ古いってまったくー。って感じで途方に暮れてつぶやいたら id:camlspotter が助け舟くれた。

ありがたや。という状態で止まってた。その後 camlp5を入れてみたんだけど、一筋縄ではいかず、なんか$rec:...$とかなっているところを直したりとかいろいろ。パーサ定義っぽいんだけどまだ調べきれていない。とりあえず対処療法でなんとかコンパイルは成功。
で、本来の目的の補完は、、というと実は既にオリジナルのleditにもabbrevコマンドが実装されていて、ヒストリの内容から動的補完は可能だったりする。

 ;; ledit.ml 
  set_char_command '\175' (* M-/   *) Expand_abbrev;

というわけで、このI/Fををそのまままねすれば良い感じ。こんなのを入れてで補完する。

  set_char_command '\009' (* ^i    *) Complete_word;

さらに -c オプションを追加して

*** 42,47 ****
--- 43,49 ----
      arg_loop
        (match argv.(i) with
         [ "-h" -> do { histfile.val := get_arg (i + 1); i + 2 }
+        | "-c" -> do { compfile.val := get_arg (i + 1); i + 2 }
         | "-l" ->
             let x = get_arg (i + 1) in
             do { try set_max_len (int_of_string x) with _ -> usage (); i + 2 }
***************

スロット足してメソッド書いて

*** 170,175 ****
--- 172,179 ----
      last_comm : mutable command;
      histfile : mutable option out_channel;
      history : mutable Cursor.t string;
+     compfile : mutable option out_channel;
+     complete : mutable Cursor.t string;
      abbrev : mutable option abbrev_data }
  ;
***************
*** 665,670 ****
--- 669,694 ----
    }
  ;
  
+ value complete_output st =
+   let ad =
+         let len = get_word_len st in
+         let abbr = String.sub st.line.buf (st.line.cur - len) len in
+         let line_beg = String.sub st.line.buf 0 (st.line.cur - len) in
+         let line_end =
+           String.sub st.line.buf st.line.cur (st.line.len - st.line.cur)
+         in
+         {hist = [line_beg :: Cursor.get_all st.complete @ [line_end]];
+          rpos = 0; clen = len; abbr = abbr; found = [abbr]}
+   in
+   do {
+     for i = 1 to ad.clen do {
+       st.line.cur := st.line.cur - 1; delete_char st
+     };
+     back_search st ad.hist st.ad.rpos;
+     update_output st
+   }
+ ;
+ 

とかしたら、なんとか動いた。なんかまだ挙動がおかしいんだけどとりあえずおk。
とりあえずテストは動いたので共通部分をくくりだしたりとかしてリファクタしてみよう。その後で complete後の文字列の末尾に ^ " "するなど、気の利いた事をしてみよう。しかし需要はなさそうな気が ... orz
しかしやっぱりぼくは ocaml苦手だなあ。なんとなく体に合わない。正直この文法を一瞬で読み解ける人たちが神に思えて仕方が無い。