offside-trap.el : for Haskell block indentation
前回までのあらすじ:
Haskell など OCaml に毛が生えたようなもの、ふふん、と、転職した俺様だったが、なんということだ、Haskell が、というか、インデントが読めない。深すぎて。どうしたらいいんじゃー!!
「この一週間で TAB を 3000回叩きました」、とか、そんなことをレポートしていては試用期間中に解雇されるかもしれない、と焦った訳ではありませんが、あまりにも空しい。ブログや呟きでいろいろとネガティブな事ばかり言っていてもしょうがねぇ。Cry baby なのは駱太郎だけで十分。俺は、大人だし、この状況をなんとなくなんとかするぜ!! てな訳で、なんとなくなんとかする elisp を書きました。offside-trap.el と言います。
offside-trap.el は haskell-indentation.el の offside ルール用のインデントサイクル変更関数の呼び出しを文字通り(ト)ラップして、カーソルから下のなんとなく文脈上くっついている行も一緒の幅でインデントします。
この elisp は Haskell を全く理解していません。ごくごく単純なアルゴリズムで動いています。カーソルのある行よりインデントが深ければその行はカーソル行に「くっついている」と判定します。「くっついている」行の下にある、やはりインデントが深い行もやはり「くっついて」います。くっついてない行が出てきたところで、インデント対象になるブロックの探索終了です。例えばこんな感じ:
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
あと、そんなの既にあるとか言う人は、どうしてもっと早く教えてくれなかったですか〜という反応になると思います。