offside-trap.el : for Haskell block indentation

前回までのあらすじ:

Haskell など OCaml に毛が生えたようなもの、ふふん、と、転職した俺様だったが、なんということだ、Haskell が、というか、インデントが読めない。深すぎて。どうしたらいいんじゃー!!

http://d.hatena.ne.jp/camlspotter/20100520/1274369338

http://d.hatena.ne.jp/camlspotter/20100521/1274446264

「この一週間で TAB を 3000回叩きました」、とか、そんなことをレポートしていては試用期間中に解雇されるかもしれない、と焦った訳ではありませんが、あまりにも空しい。ブログや呟きでいろいろとネガティブな事ばかり言っていてもしょうがねぇ。Cry baby なのは駱太郎だけで十分。俺は、大人だし、この状況をなんとなくなんとかするぜ!! てな訳で、なんとなくなんとかする elisp を書きました。offside-trap.el と言います。

offside-trap.el は haskell-indentation.el の offside ルール用のインデントサイクル変更関数の呼び出しを文字通り(ト)ラップして、カーソルから下のなんとなく文脈上くっついている行も一緒の幅でインデントします。

この elispHaskell を全く理解していません。ごくごく単純なアルゴリズムで動いています。カーソルのある行よりインデントが深ければその行はカーソル行に「くっついている」と判定します。「くっついている」行の下にある、やはりインデントが深い行もやはり「くっついて」います。くっついてない行が出てきたところで、インデント対象になるブロックの探索終了です。例えばこんな感じ:

hoge = case hoge of
                 ■Foo -> hogehoge             <= カーソルがあると思いねぇ
                   Bar -> let x = hogehoge  in <= くっついている
                          poo poo              <= くっついている
                   _ -> error "bang"           <= くっついている
huga = 2  <= くっついていない

(ほんとは空行とか、コメントとか、もうちょっと賢く扱います)

カーソルのあるところで TAB を押すと、haskell-indentation.el のインデント機能を使ってカーソルのある行のインデントがサイクルします。その時、くっついている行も一緒にくっついてくる。元のプログラムが正しく(ただしインデントが汚い)、そして一行目のリインデントが正しければ、くっついている行のリインデントも正しいはず!! なのです。で、これで結構使えます。一度押すと、

hoge = case hoge of
       ■Foo -> hogehoge
         Bar -> let x = hogehoge  in <= くっついている
                poo poo              <= くっついている
         _ -> error "bang"           <= くっついている
huga = 2  <= くっついていない

がひょん!! っと一発でこうなる。なんとなくなのに。嬉しい。特にくっついている行が十行以上あると大いに嬉しい。まあ、この嬉しさは綺麗にインデントしている人と仕事してる人にはわからんでしょうが、、、

Enter でも出来ますよ:

hoge =case hoge of
           Foo -> hogehoge
           Bar -> let x = hogehoge  in 
                  poo poo              
           _ -> error "bang"           
huga = 2

ぽちっとな ===>

hoge =case hoge of
    Foo -> hogehoge
    Bar -> let x = hogehoge  in 
           poo poo              
    _ -> error "bang"           
huga = 2

しみじみと嬉しい。

あまりテストしてないから、トラップミスによる失点やオウンゴールは自己責任でよろしく。

レポはここ: http://bitbucket.org/camlspotter/offside-trap

  • TAB でなんとなくブロックインデントサイクル
  • Enter でなんとなく改行+ブロックインデント => TAB でサイクル
  • Ctrl-TAB, Ctrl-Enter で haskell-indentation.el の普通の TAB, Enter

あと、そんなの既にあるとか言う人は、どうしてもっと早く教えてくれなかったですか〜という反応になると思います。

追記

Gnome系のターミナル gnome-terminal, xfce4-terminal, rxvt などでは Ctrl-Enter, Ctrl-TAB など押してもただの Enter, TAB としてしか伝えてくれません。そんなターミナルは捨ててしまいましょう。