Quantcast
Channel: いげ太の日記
Viewing all articles
Browse latest Browse all 26

F# Interactive を独自ビルドしてプロンプトにカレント ディレクトリを表示する

$
0
0

F# Advent Calendar 2012 19日目の記事です。前日のご担当は nomurabbit さんです。

昨年の F# Advent Calendar で「F# コンパイラをビルドする」という記事を書いたものの、一向にコンパイラを弄ろうという人が増えなくて残念な気持ちのいげ太です。確かに、ただビルドするだけでは、あまりおもしろくはないかもしれませんですが。はい。

というわけで、今年も懲りずに独自ビルドなネタで行こうと思います。今年は、去年よりもみなさんの興味を引ける記事になればと思っております。よろしくお願いします。

ちなみに、本記事の更新が遅れましたのは、やんごとなき理由でも年末進行で残業をしていたわけでもなく、Wii U を購入してはじめての本体更新を行っていたためであり、GamePad に向かって「がんばれ」「ありがとう」「ドラミちゃーん」などと話しかけてみたものの更新は遅々として進まず、このような時間のブログ更新となりました次第です。

石を投げられても文句は言えませんが、VBA の仕事は投げて来ないでください。

で、今回行うのは、source drops に少しばかり手心を加えて独自ビルドしてみようというもので、表題の通り、F# Interactive Console のプロンプト文字列にカレント ディレクトリを表示するべく改造を施します。なんとなくシェルっぽくなって、より実用的な fsi.exe になること請け合いです。本当です。いろいろ捗るのでぜひ。

F# コンパイラのビルド方法については、前述した昨年の記事内容と変わりありません。ただし、現在の最新版ソースは compiler\3.0\Sep2012 になっていますので、その点だけは読み替えてください。

コンパイラ、というか対話型シェルを改造するというと大げさに聞こえるかもしれませんが、「プロンプト文字列を変える」ぐらいのお題であればかんたんで、compiler\3.0\Sep2012\src\fsharp\fsi\fsi.fs の700行目あたりにある、FsiConsolePrompt なるこじんまりとした型をほんのすこし変更するだけで済みます。まずは対象のソースを引用します。

//----------------------------------------------------------------------------
// Prompt printing
//----------------------------------------------------------------------------

type FsiConsolePrompt(fsiOptions: FsiCommandLineOptions, fsiConsoleOutput: FsiConsoleOutput) =

// A prompt gets "printed ahead" at start up. Tells users to start type while initialisation completes.
// A prompt can be skipped by "silent directives", e.g. ones sent to FSI by VS.
let mutable dropPrompt = 0
// NOTE: SERVER-PROMPT is not user displayed, rather it's a prefix that code elsewhere
// uses to identify the prompt, see vs\FsPkgs\FSharp.VS.FSI\fsiSessionToolWindow.fs
let prompt = if fsiOptions.IsInteractiveServer then "SERVER-PROMPT>\n" else "> "

member __.Print() = if dropPrompt = 0 then fsiConsoleOutput.uprintf "%s" prompt else dropPrompt <- dropPrompt - 1
member __.PrintAhead() = dropPrompt <- dropPrompt + 1; fsiConsoleOutput.uprintf "%s" prompt
member __.SkipNext() = dropPrompt <- dropPrompt + 1
member __.FsiOptions = fsiOptions

prompt 変数に ">"なるプロンプト文字列が設定されていることがすぐにわかるでしょう。まずはこれを "$ "あたりに書き変えましょう。たった1文字、これを変えてリビルドするだけでも、オレオレ fsi が手に入って割とテンション上がります。みなぎってきた。はいそこ、プロンプト文字列くらい実行時に変更可能なよう作られているべきとか言わない。

カレント ディレクトリを表示させるには、prompt を実際に print する箇所、すなわち Print および PrintAhead メソッドにそれぞれ1行追加します。Directory.GetCurrentDirectory() を print すればよいだけですね。

そこで、fsiConsoleOutput.uprintf "%s" prompt を習って、fsiConsoleOutput.uprintf "%s" (Directory.GetCurrentDirectory()) のような1行をその手前に書き足せばよい、のですが、文字色を変えた方が断然見やすいですので、ここは fsiConsoleOutput.uprintf の代わりに fsiConsoleOutput.ucprintf を使っておくのが粋ってもんでしょう。

とすると、まとめて、FsiConsolePrompt はだいたい以下のように書き換わります。

//----------------------------------------------------------------------------
// Prompt printing
//----------------------------------------------------------------------------

type FsiConsolePrompt(fsiOptions: FsiCommandLineOptions, fsiConsoleOutput: FsiConsoleOutput) =

// A prompt gets "printed ahead" at start up. Tells users to start type while initialisation completes.
// A prompt can be skipped by "silent directives", e.g. ones sent to FSI by VS.
let mutable dropPrompt = 0
// NOTE: SERVER-PROMPT is not user displayed, rather it's a prefix that code elsewhere
// uses to identify the prompt, see vs\FsPkgs\FSharp.VS.FSI\fsiSessionToolWindow.fs
let prompt = if fsiOptions.IsInteractiveServer then "SERVER-PROMPT>\n" else "$ "
let cd () = Directory.GetCurrentDirectory()

member __.Print() =
if dropPrompt = 0 then
fsiConsoleOutput.ucprintf ConsoleColor.Green "%s" (cd ())
fsiConsoleOutput.uprintf "\n%s" prompt
else
dropPrompt <- dropPrompt - 1
member __.PrintAhead() =
dropPrompt <- dropPrompt + 1
fsiConsoleOutput.ucprintf ConsoleColor.Green "%s" (cd ())
fsiConsoleOutput.uprintf "\n%s" prompt
member __.SkipNext() =
dropPrompt <- dropPrompt + 1
member __.FsiOptions = fsiOptions

めんどくさければこれをコピペしましょう。そしてビルドです。むずかしいところは何もありませんよね。

あ、ついでですが、compiler\3.0\Sep2012\src\fsharp\fsi\FSIstrings.txt という文字列リソースがあるのですが、この中の最終行、fsiProductName に起動時に表示される製品名・バージョン情報が設定されていまして、これにちょこっと追記して、自分の名前なんかいれちゃったりしても、オレオレ感が増してよいかと思われます。

てな感じで、コンパイラを弄るとか言ってもパーサーに手を入れるんでもなければ、ぜんぜんこわくないので、ゆるふわな気持ちでどんどん独自ビルドにチャレンジしちゃいましょう。すごい人になれた気分を味わえますおすすめ。

F# Advent Calendar 2012、続いてのご担当は Arigata さんです。F# と農業のコラボを見逃すな!


Viewing all articles
Browse latest Browse all 26

Trending Articles