F# で command-line predictor を書いてる Part 13
0.9.0
krymtkts/SnippetPredictor の v0.9.0 をリリースした。
前回の日記では、存在しない group identifier のまま Enter してコマンド実行エラーにしてしまう話を書いた。
Enter での補完機能をつけてこの事故の頻度は減らしたが、本当はこういう入力は AcceptLine で処理せず、 history へ残さないようにしたかった。
ただ、ユーザへの通知方法を決めてなかったので、前回リリースではそこまで実装しなかった。
今回は -AcceptChord の handler が未登録の group identifier を検出すると accept 処理を止め、 bell を鳴らすようにした。
誤入力がそのまま command として実行されるのを防げる。
bell の出し方には少し工夫が必要だった。
PSReadLine で Get-PSReadLineOption の BellStyle が Visual の場合だけ、 [Console]::Write([char]7) で直接 BEL を送る。
何故このような周りくどいことをするのかというと、 PSReadLine の Visual bell は現状空の実装になっており、フィードバックを表示しないからだ。
2025 年の起票から今までどうするか進んでないみたいなので、自前で workaround を使うのが妥当と判断した。
それ以外の BellStyle は PSReadLine でも正しく動くようなので [Microsoft.PowerShell.PSConsoleReadLine]::Ding() を呼ぶ。
多分一般的な terminal で期待される実装は、 terminal へ [Console]::Write([char]7) を送って、 terminal の振る舞いに任せることだろう。
ただ PSReadLine の流儀に沿うため、このような形にした。
他にも細かい修正を色々入れている。
例えば group identifier の候補順は ordinal order にした。
前は dictionary の列挙順だったので、表示順に決まりがなかった。
補完候補では :snp が先頭で、その後に group identifier が並ぶ。snippet 自体の候補順は変えていない。
設定まわりも少し整えた。
SNIPPET_PREDICTOR_CONFIG が空白だけなら未設定として扱う。
元々テスト用途だったが undocumented な正規機能として残ってるのだけど、折角なので丁寧に扱うことにした。
設定の Snippet が欠落、null、空、空白だけの場合や、要素自体が null の場合は JSON path を含む診断を出す。
Tooltip は省略や null を空文字として扱い、設定ファイルを読めない場合も parse error とは別に診断する。
NextChord と PreviousChord に null、空、空白だけの値を指定した場合も拒否する。
changelog に載っていない細かい修正だと、 suggestion cache の状態を 1 つの Snapshot にまとめたのが大きい変更か。
前は snippets や group 一覧をそれぞれ更新していたので、 refresh 中に一部だけ新しい状態になる可能性があった。
今は新しい状態を組み立ててから一括で差し替えるので、候補を作る側が更新途中の状態を見ることがない。
原子性が保たれるようになったということ。
今回は細かい修正が中心で、比較的小さい release になった。普段使いで困るところを少しずつ潰せている。 当面は他にもやりたい細かい修正があるから、少しずつ進めて好みの感じに仕上げていくつもり。