2023-12-17

F# でコマンドレットを書いてる pt.27

krymtkts/pocof の開発をした。

ずっと積んでた property の入力補完機能を作った。 #93

まだあんま使えてないが結構お気に入りの機能になった。 だけど、今の実装は引数の取り回しだったり煩雑さが気に入ってなくて、どうにかリファクタリングできないものかと今も思ってる。


pocof では以下の流れでキー入力から実行コマンドを得て処理を行う。

  1. 入力キーを取得する
  2. 入力キーを文字入力・ショートカット・制御キーに選り分ける
  3. 選り分けたキーを実行コマンドに変換する
  4. 実行コマンドに引数を与えて実行する

今回の対応では、 4 のところでプロパティの一覧から候補のプロパティを導出するようにした。 なので ↓ のように 4 の関数にはプロパティ一覧の引数を持つのだけど、この引数を使うのがプロパティ補完コマンドのみのため、そこがモヤっている。 このへん

    let invokeAction (state: InternalState) (pos: Position) (props: string list) =

この最後の引数がなあ...

3 の実行コマンドへ変換するときに bind してもいいんじゃないかという気がせんでもない。 でも今度はそこにプロパティ一覧の引数が増えるだけで、問題を別の場所に押し付けただけになってしまう。 結局どっかのタイミングでプロパティ一覧を bind しないといけないし、 pocof 起動後はプロパティ一覧が変わることはないから起動したタイミングで bind すべきだったのかも... bind したとて引数の数減らんけどな。

悩みは多いが、プロパティ補完自体は上記でクリアした。

プロパティを補完したあとは、補完前の入力キーワードにマッチする候補を TAB とかで切り替えられるのが一般的なので、その実装もしている。

プロパティ補完の仕組み自体は大したことなくて、以下のような判別共用体を用意してそれぞれの状況に応じた処理を match で行うだけにしている。 非補完時は NonSearch 1 、 プロパティ検索時は Search 、 候補切り替え用に Rotate がある。

Search にはキーワードを保持していて、そのキーワードで始まるプロパティに絞り込んだ結果をクエリ入力の下の行に表示している。これは既存の実装。 Rotate にはキーワード、選択中の index 、候補のリストを保持していて、これらを使えばマッチする候補を TAB 押下時に順繰り出力できる。これが今回追加した実装。

    type PropertySearch =
| NonSearch
| Search of string
| Rotate of string * int * string list

文で書いたらシンプルだけど、この補完機能を担う関数がちょっとデカくて(これ)見た目にも分かりづらいかもなと思ってたりする。なんかスリムにしたい... debug log を仕込んだ事もあって余計に見にくい。


前回 Linux 用ビルドができたら alpha 外したリリースしたいな~といってたけどもうあんま年内時間残ってないし、この補完機能が組めたのもあるから、今の状態でリリースしたいお気持ちに変わった。 コピペ時の動作が改善されておりかつ補完機能があるから、はよ自分の他の PC でも使いたい、という欲望に駆られての判断。

ひとまず #95 でリファクタリングはじめて、こまいバグも見つかってるから、いい感じに進めて 2023 年末リリースしよ。


  1. この名前も今思えばイマイチで NoopNormal でいいんじゃないかな。