Subscribed unsubscribe Subscribe Subscribe

F# Monkey

about

インテリセンスを150行で作ってみた!

Summary

F#Compiler Servicesというのを使って

インテリセンス(というか補完)をやってみました!

今回はF#側での補完の話です。Vim側の補完の話はこちらです。

callmekohei00.hatenablog.com

おおまかな動作

辞書(ConcurrentDictionary)に下記をあらかじめキャッシュしておきます。

01. file名
02. Systemのメソッド
03. Collection5のメソッド( Array, Seq, Set, Map, List )
04. Optionのメソッド

コードはこんな感じになります

// 最初にファイル名他を辞書にキャッシュします
if      Seq.isEmpty dic.Keys
then    asyncInit ()   |> Async.RunSynchronously


// もしファイルを変えた場合は
// ファイル名とSystemをキャッシュし直します
// この場合は非同期(Start)で動作します
elif    dic.Item( "filePath" ) <> postData.FilePath
then    asyncReInit () |> Async.Start 


// ドットでの補完かどうかで処理を分けます
if      postData.Line.Contains(".")
then    dotHint ()
else  
        postData.Line.Split(' ')
        |> Array.filter ( fun s -> s <> "" )
        |> fun ary ->
            if    Array.contains "[<" ary  && not ( Array.contains ">]" ary )
            then  attributeHint ( Array.last ary |> fun s -> s.Replace( "[<","" ) )
            else oneWordHint ( Array.last ary )

インテリセンスというか補完のコアになるコード

なぜこう書くのかとかわかりません。

マイクロソフトのホームページに書いてあったからですwww

let private asyncGetDeclarationListInfo ( checker:FSharpChecker) ( ps:PostData ) (arr:(string array * string)) : Async<FSharpDeclarationListInfo> = async {

    let! (projOptions : FSharpProjectOptions) =
        checker.GetProjectOptionsFromScript( ps.FilePath , ps.Source )

    // Perform parsing and type checking 
    let! (parseFileResults : FSharpParseFileResults) , (checkFileAnswer: FSharpCheckFileAnswer) =
        checker.ParseAndCheckFileInProject( ps.FilePath, 0, ps.Source, projOptions )

    let checkFileResults = 
        match checkFileAnswer with
        | FSharpCheckFileAnswer.Succeeded(res) -> res
        | res -> failwithf "Parsing did not finish... (%A)" res

    return! checkFileResults.GetDeclarationListInfo ( Some parseFileResults, int(ps.Row) , int(ps.Col) , ps.Line, (fst arr) |> Array.toList, (snd arr), fun _ -> false )
}

課題

上記のコードasyncGetDeclarationListInfo

いかにリアルタイムで呼び出さないかがポイントになるかと思います。

事前にキャッシュしてない補完項目は通常は気にならないスピードなのですが、

type providerが入ってるコードになると

途端に遅くなります。(2秒から5秒くらい?)

コード

コードは下記に置いてますっ!

こんな感じで作り直したらいいんじゃない?という提案ありましたら

どんな手段でも結構ですので言っていただけると嬉しいです!

github.com

参考のページ

fsharp.github.io

fsharp.github.io

callmekohei00.hatenablog.com

Remove all ads