Humanity

Edit the world by your favorite way

skk.vimの構造について

まだ肝心のコードを書いていないので、
こういった構造は変わっていくと思いますが、
フィルタとモードのあたりは採用していきたいと思ってます。
skk.vimも多分こういう処理をしてると思うのですが、あまり追えてない...


このメモは開発中のものであるので、了承なく変更する可能性があるのでご了承ください。
このエントリが追記されなくなったら、 skk7.vimの仕様が固まったということです。
嘘みたいだろ・・・全部iPod touchで書いたんだぜ、これ・・・



この記事は僕のネタ帳みたいになってきてるので、現在の実装とは違っています。
現在の構造についてはいつかskk7.vimの構造が落ち着いてきたらエントリにします...

あとそういえば全部iPod touchはさすがに嘘でした。
いくつかPCでも書いてますが、もはやどの部分かは忘れました。


(2月1日)

ファイル

autoload/skk7.vim

いろいろ。
ここから始まる。

autoload/skk7/util.vim

色んなヘルパー関数。

autoload/skk7/event.vim

autocmd的なもの。

autoload/skk7/debug.vim

デバッグ時のみ読み込まれる。

autoload/skk7/compat.vim

skk.vimの設定をskk7.vim用にロードしたり、互換性のための関数など。
オプションで読み込まれる。

autoload/skk7/complete.vim

補完用。
Shougoさんに補完は書いてもらうつもりなのですが、
どういったAPIがいいんだろう。
補完のことよく分からない。

autoload/skk7/mode/*

モードについては後述。

autoload/skk7/test.vim

テスト用。TAP*1的なもの。

:call skk7#test#run()

だけでテストが走る。というのを目指すつもり。
これ別ライブラリにしちゃってもいいかな?と一瞬思ったけど
それがインストールされてなきゃテストできないのはうざいのでやめた。

イベント (autoload/skk7/event.vim)

  • 入力して字が表示される前
  • InsertChanged的な
    • それInsertChangedでできないの?
  • 変換する前
  • イベントで通知するより、モード固有でやれることはモードのautoload関数を呼ぶ形でやった方がいいかもしれない
  • ここは悩むところ

マッピング

  • 一文字打つごとにイベント投げたり処理を挟もうと思ったら自前でテーブル持ってないとダメじゃん keymap使えないじゃん
  • key"map"だからマッピングが完結するまでブロッキングされてしまう
  • lnoremap a lnoremap用関数('a')

フィルタ

  • 何らかのキーが押される度にフィルタを通して挿入される文字列を決めていく
  • フィルタ用関数の返り値は変換した文字列
    • lnoremap用関数でディスパッチされるためにlnoremap用関数が文字列を返せばいいのだけど、シンプルさのため
  • 変換キーが押されたらskkservなりgoogle suggestなり*2なんらかの関数に渡す
    • フィルタ関数の呼び出し元がめんどくさい変換部分の書き換えなどをやってくれる
    • 右側のみ更新されたら右側のみ(差分のみ)アップデートとか
    • 文字列検索でこういう後ろから検索していくアルゴリズムなかったっけ
  • 仮に大文字の英字やsticky keyなどを押すなどして変換中のことを「フィルタ待ち」と呼ぶ
    • フィルタ待ちかどうか確認する場合はskk7#...()で確認できる
  • それぞれの引数はorig_str, filtered_str, char, henkan_count, is_async
    • orig_str: フィルタ待ちの場合でない場合は"", フィルタ待ちの場合ここにバッファ文字列が入れられていく。この文字列はフィルタされた文字列ではなくてすべて英字である
    • filtered_str: 上と同じでバッファ文字列だが、フィルタがかけられた文字列が入れられていく
    • char: キー入力された文字列 ("o")
    • is_async: vimprocを使って非同期でフィルタ用関数が実行されているかどうか
モード
  • 各種フィルタ用関数を置くネームスペースと考える
  • あとフィルタ用関数は毎回呼び出される*3ので、毎回のフィルタごとに消えてなくならない変数*4、あるいはフィルタごとにやり取りするための変数なんかを決めておく
  • あとなんかフィルタ間でやり取りするための変数
    • そこら辺のことは次項の「ディスパッチ用関数/フィルタ用関数/での間のやり取りについて」で説明する
    • skk7#mode#...#filter_rom()
    • skk7#mode#...#filter_hira()
  • フィルタをかけて必要があれば他のステートに移る
  • autoload/skk.vim内で、ステートはs:skk7_state、モードs:skk7_modeとして表される
  • フィルタなどからモードやステートを見たり変更する場合は、操作用関数を通して操作する。
    • モードは変更できなくてもいい気がするけど、一応用意しておく
  • 例えばs:skk7_modeが"hira"、s:skk7_stateが"rom"であればskk7#mode#hira#filter_rom()が呼び出される
  • とは言え一から書くのはめんどくさい
  • _defaultというモードは使えなくなるけど、他のモードのためのヘルパー関数は次の通り
  • 引数などは変わるかもしれない
    • skk7#mode#_default#from_rom_to_hira(char, is_async)
      • ローマ字をうっていくとひらがなになる
      • charが大文字の英字だった場合やsticky keyだった場合は"▽"を返してskk7#mode#...#()などを呼び出してくれたり
    • skk7#mode#_default#from_rom_to_kanji()
      • ローマ字が入力されると同時に変換結果が表示されるAnthy逐次変換のような動作をする
    • skk7#mode#_default#from_rom_to_kana()
      • qのカタカナモード用
    • skk7#mode#_default#from_kanji_to_hira()
      • 再変換用
    • skk7#mode#_default#from_hira_to_kanji()
      • モード固定で変換
  • 特定の範囲をフィルタにかけるoperatorなんてのもあればかなりいいよね
  • xxxからyyyに変換 みたいな
  • モードが存在しなかった場合は、存在すればskk7#mode#...#unknown_mode()、存在しないならskk7#mode#_default#unknown_mode()が呼び出される
  • ステートについても同じでunknown_state()が呼び出される
    • フック可能な訳は主にデバッグのため
    • あと「未実装です!!」とか言える
  • 入力したら別スレッドを起動するようにフィルタをかけて、入力をブロッキングしないようにしたい
  • 例えばid:mattnさんのgoogle-suggest.vimをskk7.vimで実現するなら、Googleへのリクエストを投げて、次のキー入力が来たら現在のリクエストをキャンセルしてまた新たにリクエストを投げる、など。普通だったらこれはGoogleからサジェスト結果が来るまで待っていなければならない。
    • vimprocがインストールされていればGoogleへのリクエストを別スレッドで行いたい
    • それだとDOS攻撃っぽくなるので、その他リクエストを投げるまでの時間(ms)などグローバル変数で指定できるといい
    • これはフィルタ関数内部で判断する
      • キー入力を受け付けた後に、skk7.vim側でフィルタ関数の呼び出しまで待っているのは意味がない
    • となるとそこらへんの同期処理をするautoload関数を書く必要が出てくる
    • 同期処理難しいのでこれもvimprocでできればうれしい
    • vimprocの辺りは非同期処理をした後のフィルタされた文字列の受け取りやそこら辺のイメージが曖昧なのでもっと考える

ディスパッチ用関数/フィルタ用関数での間のやり取りについて

  • フィルタ用の変数*5については、skk7#mode#...#の中に置いておけばいい?
    • まだニーズが分からないけど、モード間でやり取りしたい場合は変数をautoload化して公開すればできる

プラグイン

  • 全部autoload化してあるのでプラグインを作る時は楽?
    • 新しいモード
    • 新しいフィルタ用関数
      • 他のフィルタ用関数のヘルパー関数となるようなものを作りたい時はskk7#mode#_hoge#...()のように下線(_)をつけておく


(2月3日追記)

変換フェーズにおけるモード切り替えキーの扱い

  • skk.vimでは
    • 子音、つまりsなどの後にqが来た場合でも、sを消してモードを切り替えてしまう
    • 変換フェーズにおいては変換バッファ文字列を消すだけ
  • というかSKKというのはそういうもの
  • でも例えばqなどを、変換フェーズの時のみ変換のキーに割り当てられれば嬉しいんでしょう?
  • なにそれうれしい
  • 戸惑う人がいるだろうし、やるならオプションで
  • 詳しくは次項

特定の期間だけ有効なキー

  • マッピングを切り替えるのではなく、全てはディスパッチ関数で切り替える
  • skk.vimはここらへんモード切り替えキーのみ別々の関数だったりして流れが掴みにくかった

モードのキー割り当てについて

  • <と>と?にもまだなんか割り当てられそう
  • zはモードに割り当てた文字を入力したい時のエスケープみたいなものとして働く
    • もちろんキーはカスタマイズ可能
  • じゃあ@とかもz@で入力するようにすればモードに割り当てることはできるわけだ
  • でもそうやってどんどんモードを割り当てていくと、「z + 文字」が「文字」になることは個々のモードのテーブルに依存してるわけで、そうなると誰かが新しいモードを作ってくれた時とかは、そのキーを入力するために全てのモードのテーブルを書き換えなきゃならない
  • zをエスケープ文字列として、ディスパッチ関数側でz@は@にする
    • 全角の@を入力したい時は?
    • 現在のモードのテーブルにたずねて、なかったら半角の@にフォールバックする?
      • やっぱりテーブルの構造についても仕様化しないとダメだ
      • autoload/skk7/table/...

テーブルの構造の仕様

とりあえず現状では、YAML風に書くと

a:
  map_to:あ
sa:
  map_to:さ
xx:
  map_to:っ
  rest:x

テーブルを操作するコマンドマクロ

各テーブルの定義ファイル(autoload/skk7/table/*.vim)は下のような感じにすることを目標にする。
これは autoload/skk7/table/rom_to_hira.vim だとする。
またSkkTableMapにbangを付けると、例えばユーザ側で.vimrcで定義されていたとしても上書きする。

SkkTableMap -table=rom_to_hira          a   あ
SkkTableMap -table=rom_to_hira          sa  さ
SkkTableMap -table=rom_to_hira -rest=x  xx  っ

rom_to_hiraとテーブルを指定しているのはコマンドには呼び出されたファイルは分からないため。
どうせ同じテーブルの定義が一度に指定されるのだし、事前に知らせておくのはいいかもしれない。

SkkTable    rom_to_hira

SkkTableMap          a   あ
SkkTableMap          sa  さ
SkkTableMap -rest=x  xx  っ
迷っていること
  • 構文
  • これらのコマンドをローカルにするかグローバルにするか

ローカルにする場合は、テーブルの定義ファイルの先頭に次のようにする。

call skk7#table#define_macro()

ディスパッチ関数で(特別に?)処理すべきキー入力

まだ多分いろいろ追加・削除されてくと思う。

  • モードの切り替え (q Q l L /)
  • Sticky key
  • 大文字の英字
  • モード切り替えのためのキーのエスケープ用キー (z)
  • IMを有効にするキー (C-j)

ディスパッチ関数内の流れ

  • (上で挙げた)特殊なキーの処理
  • フィルタの処理
  • 補完の処理
  • 変換キーを押した時の処理は特に特別扱いしない
  • 変換キーがスペースキーだったとしたら、変換キーを押した時にスペースが挿入されるか文字列が更新されるかはフィルタ次第
    • 一応キーが変換キーかどうかを判断する関数を作る
    • 単純に変換キーがグローバル変換に保存されてるんだったらそれ見ればいいけど、マッピングの対応をグローバル変数にどのように保存するかは決めてないし
    • これもテーブルの構造と同じにする?
    • 変換キーはマッピングに割り当てておけばいいんじゃない?
    • 変換キーを押された回数はモードが持ってるべき
      • 必要があればその変数へアクセスするautoload関数なんかも
  • 変換を確定する関数作る

モードのコールバック

  • 特定のモードのみに送りたい場合はイベント発生よりもモードのautoload関数呼び出しのが効率や分かりやすさの点で優れている
    • 分かりやすさ、というのは主にモード側のイベント登録などの処理の話。コールバック呼び出しなら関数を定義しておくだけ
  • モードが変わった時
    • 変わる前のモードのコールバック呼び出し
      • 変わった後のモードを引数に渡す
    • 変わった後のモードのコールバック呼び出し
      • 変わる前のモードを引数に渡す
  • モード用のキーを押した時

イベント

  • あれ?要らない子じゃね?
  • 一番よく書けたと思ったコードだったのに...ギリギリ
  • モード以外にイベント的な処理するとこないしなぁ
  • まぁautoloadなので置いておいても損はないけど、使わなくなるかも

大文字の英字とSticky keyの扱い

  • Aは(skk7-sticky-key)aと同じ

その他いろいろ

変換フェーズとそうでない場合にフィルタ用関数が返す文字列が、全部の文字列を返すのか一部の文字列を返すのか違う
  • フィルタ用関数は「確定した」文字列を返す
  • ディスパッチ関数が文字列の差分のみアップデートするなど工夫する
現在フィルタ側がバックスペースのキーコードを生成してるけど、これをディスパッチ関数にやらせる
  • 具体的には、フィルタ用関数は返り値(skk7#返り値を抽象化する関数を用意)として「削除する文字数」と「挿入する文字列」をディスパッチ関数に返すことが求められる
  • こうすることで、統一した文字列の更新が可能になる
  • Anthyでは、変換フェーズにたくさんの文字列を入力すると、いちいち全ての入力が書き換えられてるように見えて、それが結構遅かったのでイライラしてた

予測変換

一文節だけならできる



(2月4日追記)


マッピング

  • キーボード上の全てのキーはディスパッチ関数にマッピングされる
  • どのような動作をするかは独自のテーブルを持つ
    • マッピングを弄る専用関数作る
      • マッピングの引数などはarpeggioのマップ用関数を真似る
    • いずれコマンドマクロつくりたい

マッピングのコマンドマクロ

Skk7Map ; sticky
Skk7Map z escape
Skk7Map q zenei

これじゃ特殊なキーとモードの区別がつかない。

Skk7Map -type=sticky ;
Skk7Map -type=escape z
Skk7Map -type=mode q zenei

指定する引数はwordのみにすれば、次のように特殊なキーを保存することができる。

;: sticky
z: escape
q: mode-zenei
Skk7MapSticky ;
Skk7MapEscape z
Skk7MapMode q zenei

テーブル用にはSkk7TableMap。詳しくは前回の追記を参照。


テーブル用コマンド

  • ステートを持ってたり(前回ので言えばrom_to_hira)ややこしいので、テーブルの定義ファイル内の最後で削除するコマンドを実行する
  • いやステートを上書きすれば問題ないよ
  • ようするにテーブルの定義の前にちゃんと
Skk7Table table_name

とすれば問題ないという話

  • それともやっぱり明示的にテーブル名を指定させる?

フィルタ関数が返す値

まだ完全に実装のイメージがつかめてない。
多分補完関数についてよく知らないからだと思うので調べる。

  • 補完関数を見習う
    • つまり返り値は文字列か詳しく指定する辞書型か
  • 補完関数の返り値も含める?
  • 遅い場合も考えて、遅延できるようにする
    • 分けて処理することを伝えるキーと値を含める

メッセージキュー (autoload/skk7/msgqueue.vim)

  • ディスパッチ関数を非同期にする場合のみ読み込まれる
    • 有効ならdispatch_key()はそっちのがマッピングされる
    • 実際の処理はskk7.vim側のdispatch_key()がする
    • やるのはspawnする処理
  • これ実現できたらfuzzyfinder.vimでも対応してほしい
    • キー入力を非同期に受け付けて、素早く入力した時の誤爆をなくしてほしいということ
  • いくつかの実装方法
    • vimproc
      • 不安定で現実的でない
      • こういう外部インターフェースに頼る方法は、Vim側が非同期に通知を受け取れないので、スクリプト側からvimproc側にポーリングしてやる必要がある
    • CursorHoldI
      • CursorHoldIでメッセージキューをデキューしていくイメージ?
    • いっそ外部コマンドでやったらどうなんだろうか・・・
    • +clientserver
      • id:mattnさんのpureirc.vimがいい例
      • Emacsってサーバとemacsclientっていう風に分けて起動できたような
        • あれは何が便利なんだろう
      • コマンドはSkk7Serverだとskkservっぽい
        • それでもいいような気がする
        • 片方のVimがサーバ的な役割は全て担う形
  • 処理のキューイングはどうする?
    • autoload/skk7/event.vim
      • 要らない子じゃなかった!

abbrevモードでスニペット機能を実現

  • 色んなスニペットプラグイン*6見る限り、専用の記法を導入してるみたい
  • 前回のメモの一時的なマッピングで、スニペットを挿入した直後だけ有効なマッピングも定義できる
  • xptみたいにで次の引数の場所に移り、で関数のブロックの中に移るとかしたい
    • あれってどうやってスニペットファイルでそういうのを指定してたんだっけ
    • xpt自体は使ってるとVimが目に見えるほど遅くなるから使うのやめたけど...
    • コミット権もらったのにsvn分かんなくて結局一回もコミットしなかった...
    • そのうちコミットはなくなり...
    • そして誰もいなくなった
    • オーブンソースソフトウェアはニーズがあればふとしたことで生き返ることもあるんじゃないかな、skk.vimみたいに
  • これは「一時的なマッピング」と「特定の期間だけ有効なキー」で言ってるような感じで実装する

一時的なマッピング

  • フィルタ関数でマッピングテーブルいじるだけ・・・だとその前のマッピングが復元できなかったりする
  • 前回のマッピングだけ覚えていてくれればいい
  • 一時的なマッピングを作る専用関数を作る
    • 現在の値を保存してから値をセット
    • 一部あるいは全部復元
      • 復元する値がなかった場合はget()関数のようなデフォルトの値を指定させればそれを返す
      • 今の s:call_if_exists() と同じ
    • ちょうどやってること(値を復元する)は今の s:option_*() な関数と同じ
    • event.vimも s:option_*() な関数も、処理を指定した時に先延ばしさせるもの
    • 一緒にできないか

一緒にしてみた

  • まず処理の登録と同時にIDとなる値を返す
  • そのIDを保存しておき、指定したい時間にそのIDを渡して実行
  • event.vimを少し弄ればできるはず
  • 名前はqueue.vimのがいいかも
  • 似てると勘違いされないようにmsgqueue.vimもasync.vimとかにする?

一時的なマッピングについてもう少し

  • マッピングが変わってしまっても、ユーザに「これをすればリセットされる」みたいなコマンドを提供したい
  • ディスパッチテーブルをリセットする
    • コマンド
    • マッピング
      • IMが有効ならでいいような
      • をトグルするマッピング( (skk7-toggle) )に割り当てたいユーザは?
      • (skk7-reset-keys) みたいなマッピングを用意する
      • 初期化用のコードはそれに割り当てる関数に置いとけばいいかな?
      • じゃ (skk7-init-keys) にするか

決め事

  • ブランチのフォーマットは/<タイプ>/<好きな名前>
  • タイプは機能修正なら頭にfix、機能追加ならhack、それ以外なら何もつけない

ステート

  • 活用の仕方が分からない
  • せめて特定の文字はこっちのフィルタ関数で処理、とかそういうことができればうれしいんじゃないか
    • skk7#register_filter_fn(mode, fn, chars)
    • これじゃフィルタ関数は登録しないと呼ばれないみたい
    • まぁデフォルトでfilter_main()以外は呼ばれないんだし合ってると言えば合ってるか
    • 引数を辞書型にして、例えばabcdefgをfilter_abcdefg()で処理したいんだったら
mode: hira
fn: abcdefg
handle: abcdefg

みたいなのを渡すとか?
キーのおかげで分かりやすそう

  • でも結局それmainからやればいいじゃん
    • 無駄にディスパッチの処理を増やすのはしたくない
  • 結論:ステート廃止?
  • いや待てモードの中で変数にステートを保存しておくよりは関数で分けられるのは地味に便利なんじゃないの?
    • いやだからそれmainからやればいいじゃん
    • うーーーーーん
  • 「入力中の処理の流れ/状態」の項の流れをディスパッチ関数で分けてくれるのはうれしい?
    • そうでもない
    • 例えば変換キーを押してひらがなから漢字に変換する場合はfilter_convert()でやりたいとする
    • その場合 filter_main() でそれが変換キーかどうか見て、それからステートをいじって、一回目は自分で

filter_convert() を呼び出す必要がある

    • だったら filter_main() でそのキーを見てからそれぞれのステート用の関数にディスパッチした方が分かりやすい
  • とりあえず先延ばしにしておくか

フィルタ用ディスパッチテーブル

  • 上で言ったようなステートの遷移をどのように表せばいいのか
state_a:
  b: state_b
state_b:
  a: state_a
  • モードなどは気が向いた誰かに追加していってほしい部分
  • なのでこういうステートの遷移などが便利なようならヘルパー関数書いとく

変換フェーズ

フェーズとかステートとかモードとか、一応使い分けるよう注意してるんですよ。
決してかっこつけたいとかそういう訳じゃないです。決して(ry

  • SKKには3つのフェーズがある
    • ノーマルフェーズ
    • 変換フェーズ
    • 送り仮名の変換フェーズ
  • とにかく変換フェーズか、そうでないか、では判断材料が足りない
  • それぞれのステートを定数で表す

入力中の処理の流れ/状態

これはフローチャートにした方が分かりやすいな。
いろいろ見落としてる気がする。

  • モードの中で行われるフェーズ
    • 英字からひらがな等に変換中
    • 変換後
  • sticky keyや英字を押して変換する文字列の入力フェーズ
  • もしもう一回sticky keyや大文字の英字キーを押した場合
    • 送り仮名入力待ちフェーズ
    • マッチしたので変換候補選択フェーズ
      • あれ?それともいきなり確定されるっけ?
  • 変換キーが押されて変換候補選択フェーズ

補完にもフェーズというかモードというかステートがある気がしてきた

  • というかなんか:helpにそう書いてある
  • autoload/skk7/complete/ に色んな補完関数を置く
  • その中のスクリプトは、モードと同じでコールバックやいくつかの関数を用意する必要がある
  • なかったら_default.vimにフォールバック?
  • モードと補完は一対一であるべきか
  • いや、googleでsuggestしたいじゃん
    • それは変換キーが押された時のモードのコールバックとして用意すればいいんじゃない?
  • 補完でもgoogle suggestありかも、DOS攻撃っぽくなるけどね

変換用API

  • autoload/skk7.vimに実装
  • フィルタは変換用のキーを自分自身でハンドルするべきか
  • 次の文字列をそれぞれ相互に変換
    • 英字
    • ひらがな
    • カタカナ
    • 漢字
  • n * (n - 1) 通りの変換関数を用意する必要がある?
  • いや文字の種類はそうそう変わらんだろ、アホか
  • 12個全部は実装無理っぽいかもしれない

ディスパッチ関数に渡す引数

  • どこから呼び出したか
  • キーは大文字か

その他

最近全然眠れてない。



(2月5日追記)


だんだんとイメージがつかめてきた。
どうやらちょっと難しく考えすぎてたようで、
プラガブルにしようと意識するあまり
テーブルとモードの対応をどうするか、
補完とモードの対応をどうするか、
などいろんなことを考えていた。
それは全部モードがグローバル変数でやればいいことで、
それでもしほしいAPIなどが定まってきたら
後々しかるべき場所に実装してけばいいことだった。
文字列の更新や非同期な呼び出しなどはディスパッチ関数でやりたいけど、
それ以外は全部モードに丸投げしたっていい。
モードは他の人に書いてもらいたい部分だったから
あまりモードを複雑にしない方がいいんじゃないかと考えていたが、
それはまだ今考えるべきことではなかった。反省。


ディスパッチ関数の引数

  • 大文字かどうか
  • 現在の状態をキーとともに保存するか
    • Aの場合はAで保存しといて、aの時は保存しない

フィルタ関数

  • 変換キーが押された時は別のフィルタ関数を呼び出す
  • 現在のステートを廃止し、固定の名前でフィルタ関数を呼び出す

モードがcb_now_working()でtrueを返す場合の特殊なキーの挙動

  • フィルタ関数にそのまま渡す
  • 挙動がちょっと違うけど、各モードで使えるキーは最大限使わせる
  • qでカタカナに変換するのはhira.vimがやればいいよね

フィルタ関数に渡す引数

  • 現在のcolとline( getpos() ?)
  • 引数が多ければ...で省略すればいいじゃん
  • autoload関数で取得させるのは実質その変数はグローバルなのであんまりよくない

フィルタ関数の戻り値

  • 現在のバックスペースによる返り値も許容する
  • 長い文字列を置き換える場合
    • 返り値に挿入でなく置き換えであることを明示する値
    • replaceってキーに始点のgetpos()の結果を保存しとく

コールバック

  • skk7#sticky_key()から呼び出す
  • skk7#init_keys()から呼び出す

補完

  • 現状はとりあえず全部モードの中でやることにする
  • モード固有のグローバル変数とかあってもいいんじゃないかな
  • モードはEmacsでいうメジャーモードみたいな感じ?

モード

  • qなどのバッファ文字列を操作するキーはまとめておくといい
  • asciiモードはreturnするだけなので楽
  • モード起動のためのキーはもしマッピングされてなかったらマッピングする

マッピングテーブル

  • skk7/maptable.vimにわける?
  • Vimのと同じ操作ができるといい
    • maparg()
    • mapcheck()
    • hasmapto()
      • マッピングにマップされたかどうかのフラグを持たせる

非同期

  • CursorMovedI
  • CursorHoldI
  • vimproc
  • +clientserver
    • 制限について調べる
  • Vimサーバ

グローバル変数

  • skk7_pre_load_files
    • 全てのautoloadファイルにload()って何もしない関数を持たせる


(2月6日追記)


keymap

  • 一文字が一文字と対応してるテーブルにはkeymapが使えるな
  • でも対応する意味あるの?
  • keymapの設定はめんどうというか慣れてない人が多い
    • keymapファイルを書くのは対応する文字を書けばいいから楽だけど
  • keymapの定義を切り替えられるだけでも便利
  • でもkeymapを読み込んだらマッピングを上書きされてしまう
  • リセットするキーとかはmapmode-icでマッピングする
    • メタキーと一緒のキーのみでいいような

補完はモード側でやるかディスパッチ関数側でやるか

  • これは実際Shougoさんにコードを見てもらって、どの時点で補完関数を呼び出せばいいのか訊く

変換候補

  • 候補は数字で選択できる
    • 数字を入力するときは?
  • prompt.vimがインストールされていれば、プロンプトでも選べる

変換用関数

  • 変換用関数もモード側にあればそっち使うべき?

ギャル文字変換テーブル

  • ・・・

「多く」「大く」

  • 「大ku」と辞書に書けないんだろうか
  • 動詞は活用の種類も保存できるといいんじゃ?
  • 活用の種類が保存されていたら送り仮名の母音の部分も見る
  • これSKKの辞書からYahooのAPIなりWeb上の辞書サービス使って変換できないかな
  • 辞書の形式はどうしよう
  • やっぱり変換や辞書の読み込みなどは別ファイルに分けるといいのかな
    • autoload/skk7/henkan.vim

独自マッピングテーブルはやめる

  • 引数でどこから起動したか判断すれば、独自のマッピングテーブル持つことないような
  • 補完関数のfindstartみたいな感じ
  • そもそもarpeggio使えないじゃん!

(2月7日追記)


変換フェーズ・変換バッファテーブル

  • 変換フェーズごとにバッファを持っている
  • (正確ではないけど)Sticky keyなどを押すたびに変換フェーズが変わる
  • バッファはテーブルで分けられてるので大文字で保存する必要はない
  • 変換する時は変換関数にテーブルごと渡せばいい
    • 変換関数はデフォルトでg:skk#henkan_buf_tableを使う
    • モードのがあればそっち使う
      • どんなケース?
  • 現在の変換フェーズの状態をstatuslineに表示できたらいいかも
  • 送り仮名は母音が入力されたら変換関数に渡す
  • 他にも変換キーが押されたら変換する
  • これらの処理はfilter_henkan()で行われる

#cb_ってプレフィックスいらなくね?
#フィルタ関数だってコールバックだし

  • ディスパッチ関数でバッファテーブルに入れていって、マッチしたらクリアの方がシンプルな気がする
  • それに再描画も簡単
  • 文字列の削除なども簡単
  • バッファテーブルを弄って、マッチしたらクリア
    • これっきゃない
  • フィルタ関数の返り値はどうする?
    • 関数で抽象化
      • throwしたっていい
    • 具体的には次のことが返り値か例外で知らせることができればいい
      • バッファテーブルの再描画する部分
      • 挿入する文字列
    • フィルタ関数実行中に変更されたバッファテーブルを監視していれば挿入する文字列だけでもいい
    • 返り値か例外って言ったけど、返り値は一切無視して関数で伝えてもいいんだよね
  • 辞書登録モードもバッファテーブルを用意して同じようにできたらいいな
  • 一応マーカーも設定できるように
  • それぞれのバッファテーブルは配列の辞書型にする
  • 文字列の他に位置も覚えておく必要がある
    • 前の追記でgetpos()とか言ってたやつ
    • フィルタされた文字列も含める

モードの再確認

  • 各モードは英字から何かへの変換、何かからまた違う何かへの変換をするもの
  • hiraモードだったら英字からひらがな、ひらがなから漢字
  • 最初の変換はシームレスに行われ、次の変換はSticky keyか大文字の英字を押すことで文字列を受け付ける
  • 2回目の変換の時に入力される文字列は最初の変換で入力される文字列と同じ
  • そこで変換キーが押されるか、新たにSticky keyか大文字の英字を押して送り仮名の母音を入力するとfilter_henkan() が呼ばれる
    • 現在はどの変換フェーズでもfilter_main()を呼び出してるけど、今後どうするか
    • もういっそfilter_main()はfilter()にして、変換キーが押されたらhenkan()を呼ぶのはどうか
    • 引数は同じ?
      • バッファテーブルを渡した方がいいんじゃないか
  • skk7.vimのバッファテーブルがグローバルなのはどうなんだろう
  • ローカルにして、それぞれゲッターとセッターを用意する
  • テーブルはモード固有のがあれば使う?
    • どういうケース?

モード固有のマッピング

  • 例えばhiraモードでqがカタカナへの変換になるとか
  • ユーザがいじれるとうれしい
  • 変わる前と変わった後にユーザが特定のコマンドを実行できればいいのか
    • モードに入ったらarpeggioでマッピングとか
    • モードを去る時にちゃんと後始末するコードも書く必要がある
    • それくらい単純な方がユーザにとっても分かりやすいような気がする

ユーザが登録できるイベント

  • フィルタが呼び出されるコールバックとは別
  • event.vim使い回す?
  • autocmd likeなコマンドマクロ
  • 投げるイベントはmode-モード名-enterとかにすればいいんじゃないか

モード側がやるべきこと

  • やっぱりplugin/の方で自分の名前を登録する
    • skk7#register_mode('hira')
    • その方がリスト表示してモードを決めたりできる
  • 補完
    • asciiモードなどは補完の必要がないため
    • 細かい制御などはモード固有のグローバル変数
  • 使うテーブルの指定

モードから呼び出す補完について

  • モードの補完関数はグローバル変数で決め、ローカルな値
  • CursorHoldIよりCursorMovedI的な挙動の方がうれしいらしい
  • 引数はVimのomnifuncで設定する関数と同じでいいんだろうか
  • neocomplcacheとの連携

変換フェーズ

  • ちゃんと名前があったみたい
  • ノーマルモードが■モード
  • 変換モードが▽モード
  • 送り仮名モードが▼モード
    • Qをひらがなの最初の位地で押せば▽モードに入れるらしい
    • ▽モードを抜けるてマーカーを消すには
    • ▽モードを抜けてかつマーカーもマーカー以後の文字も消すには

変換文字列などのシンタックスハイライト

  • それぞれの文字列にシンタックスハイライトができるといい
  • マーカーが設定されてれば楽そうだけど、マーカーが空文字の場合は動的にシンタックスグループを作る必要がある

q
「かなモード」、「カナモード」間をトグルする。
l
「かなモード」または「カナモード」から「アスキーモード」へ。
L
「かなモード」または「カナモード」から「全英モード」へ。
C-j
アスキーモード」または「全英モード」から「かなモード」へ。

特殊なキーとして実装するんじゃなくて、モードのローカルなマッピングとして実装した方がいい気がする。
もちろんarpeggio対応!


辞書を編集

  • もちろんVimはエディタなので辞書編集にも最適な機能を発揮する

独自のマッピングテーブル

  • 要はマッピングマッピングできればいいんだから、アプローチ自体はいいと思う
  • でもモードローカルなマッピングにする場合、autocmd的なものと合わせた方がいいのか、合わせるとしたらインターフェースはどういうものにしたらいいのか悩む。
  • というか今ここで悩んでる。

ドキュメント

  • skk7.vim
  • モードごと

SKKって中国語とかハングルとかも変換できないかな?

  • ノーマルフェーズで部首を表す漢字に変換
  • 変換フェーズではその部首を組み合わせた漢字にする
  • SKK最強じゃね?
    • さらに言うなら、skk7.vim最強じゃね?
    • 中国とか韓国でもSKK流行らせればよくね?
    • そして世界中に広まるSKKの輪
    • いや部首だけで何個あると思って(ry
    • 実際どういう入力方法なんだろうね?
  • ノーマルフェーズで細かい文字(ひらがな等)を入力、変換フェーズやその他のフェーズで複雑な文字に変換
  • 英字からの変換はテーブルを使って、それじゃ表現しきれない文字についてはどっかにリクエスト送ったりほげほげして複雑な文字にすると
    • 複雑な文字からより複雑な文字へ変換することも考えられるけど、そんな複雑な文字地球上に存在するの・・・?
    • 宇宙言語対応
  • 中国語のこととか考えてみると
    • ひらがなからカタカナへの変換なんかは別のテーブルに書く?
    • スペースを含んではいけないっていう現行のSKKのルールはない方がいい
      • 実装が複雑になるけど、今のskk7.vimらしく、現在のフェーズは自分で持っておく
      • 要するにマーカーに頼らない
      • skk7.vimではid:thincaさんがneocomplcacheでの併用で誤爆したってことからそういう実装にしたけど、これは良かったんじゃないか

(2月12日追記)

複数のモードを併用するとかしたい

  • 例えば
    • モードをdvorak|hiraにするとqweytyからdvorakへの変換が行われてからhiraモードに送られるだとか
    • ShougoさんのSticky Shiftの設定みたいなのだとか
  • ディスパッチ関数を再帰的に呼び出す
    • いややっぱり一つのモードごとに文字列の再描画とかしてたら遅いので、順番にモードのフィルタを適用していくだけ
  • モードに引数も与えるには:を使う
    • table:dvorak|hira
    • 1文字が1文字に対応してるならtable.vimとかいうモード作ってテーブル名を引数として渡せばいい
    • zeneiモードとかかな入力だとか
  • 引数の受け取り方
    • フィルタ関数に渡す
    • モードのautoloadの変数に代入する
    • 基本的に何か渡したかったらこの2つが速度的に速い
    • autoload/skk7.vim側の変数や関数はあまり増やしたくはない
  • statuslineの表示が長くなるな
    • 表示を省略する
    • ユーザは自分でモード文字列を定義して、それぞれに表示する文字列や切り替えのマッピングを決められるとか
      • 既存のSKKのモード切り替えのキーなどについては?
    • 表示するのはメジャーモードのみ(後述)
  • 現在のモード切り替えのマッピングでskk7#set_mode()するとtable:dvorakが解除されてしまう
    • 1つのメジャーモードといくつかのマイナーモード
      • 置き換えられるのはメジャーモードだけ
      • skk7#set_major_mode()
  • 補完とかもモードの後ろか前にくっつければいいんじゃないか
    • 補完のメニューを出すだけで、文字は変更しない
  • 各モードは「環境」と思っていたけど、こうするとモードは独立した機能をそれぞれ提供してパイプのように挿入する文字列などを決めていくことになる
    • 各モード間でやりとりしたいときは?
      • それはどんなケースか
    • 小さい機能をそれぞれやっていくのはUNIXコマンドライン文化だけど、EmacsPerlなど例外はある
    • Vimの中でシェルを動かす時代ですよ
    • こういう「小さいことはいいことだ」のアプローチの利点は選択肢がかけ算的に増えて行くこと
    • Perlみたいにいくつかの機能をまとめるならその時一つのモードにまとめればいいじゃない
    • 非同期処理(spawn)はコマンドラインの&みたいなもんか
      • 非同期処理もモードでやるとか?
      • もしモード文字列に複数のモードを設定できるようにするなら、そうした方がいい
      • (今考えてる形だと)ディスパッチ関数側でやると一つのモードごとにspawnしてしまうから

メジャーモード・マイナーモード

  • Emacsと同じで現在のメジャーモードは一つのみ
  • マイナーモードはキー配列の切り替えや補完など補助的な機能
  • メジャーモードの切り替えはskk7#set_major_mode()
  • 変換キーなどいくつかの処理はメジャーモードにのみ任される?
    • モード文字列の順番でフィルタが実行されるんだったら変換キーやスティッキーキーすらも変換して次のフィルタに渡すことができる
    • Shougoさんのスティッキーシフトの設定みたいに全てのキー入力を変えることも可能
      • 例外を使って現在のフィルタ処理を脱出し、次の入力を待つ
    • やっぱりスティッキーキーなどの処理はそれぞれのモードが処理するほうがいいね
      • plugin/skk7.vimにあるマッピングの設定を削除
      • スティッキーキーや変換キーも全てまずはディスパッチ関数に送られる
      • 送るキーはArpeggioなどで決めることができる
      • 何をスティッキーキーとするかはマッピングテーブルの中で決めること
  • メジャーモードはmajormode、マイナーモードはminormodeでそれぞれautoload分ける

モード

  • 別言語と協力するモード
    • Vimスクリプトなんて変態的なもの覚えなくてもフィルタ関数が書けるよ
    • if_*は貧弱なものが多かったり
    • 外部コマンドを呼び出す?
    • いちいち呼び出すのもあれなので、サーバとか
    • やっぱ通信と非同期が鍵になってくるなぁ
  • もう組み込みのモードとしては、テーブルを使うモードはhiraモードだけで、あとは色んなテーブルを書けばいいんじゃ

キー配列

その他

  • マッピングテーブルになかったらfeedkeys()で元のコマンド実行したりできない?
  • モードを選択するコマンドの補完
  • znを「ん」に割り当てたら結構nが続く場合でも押しやすい気がする
  • バッファ文字列もフィルタ関数に読み取り専用で渡す
    • :lockvar
    • 現在は関数で取得したりしてるけどそれよりも引数で渡した方が速度やスコープの範囲の点でいい
  • マイナーモードはEmacsではどのように設定されるのか
    • メジャーモードに「設定してもらう」?
    • それともメジャーモードになった場合の「イベント」?

(2月15日追記)

スティッキーキーの扱い

  • モードによって違うのでskk7.vimマッピングテーブルでマッピングでFA?
  • arpeggioの内部フェーズ見る
    • フックできないか
    • できないならforkする?
    • そういえばarpeggioはよくどのモードでも代わりなくマッピングを実行できるな
  • まぁ後からでもできる気がする
    • ディスパッチ関数にキーとarpeggioから入力したことを伝えるフラグを渡す

TAP

  • コマンドの出力のテスト
    • コマンドはデバッグでメッセージを出力したりしてくれればテストできる?
  • subtestっている?
  • 再帰的にテストのファイルを取得(glob)

event.vimのOO化

  • ユーザがイベントを定義できるように
  • Emacsのモードの...-hookみたいなもの

予測変換の補完

  • それぞれomniで表示
    • 変換した部分のみ
    • 送り仮名まで
    • その後のひらがな全部
      • 一文字ずつ全部リストアップする?
  • ノーマルフェーズで打ち込んだ文字も保存しておく?
    • モードが保存する?
      • 補完関数のモードとのやりとりが面倒
    • autoload/skk7.vimが持つ

確定

  • バッファテーブルを書き出す処理
  • 例えば「s」を押すとノーマルフェーズのバッファ文字列に貯められ、asciiモードならそのまま「確定」され、hira モードならrom_to_hira.vimのテーブルにマッチしないのでそのまま
  • 挿入する文字列はテーブルの別の要素か別の領域として実装した方がいい
    • モードは複数あるので*7、その後のモードのことを考えると書き換えてほしくない
  • 複数のモードのフィルタ関数に順にテーブルを渡していって、ディスパッチ関数で現在表示している文字列を書き換える
    • 挿入する(ディスパッチ関数で書き換える)文字列はモードからも取得できるといい
    • メソッドとして実装
    • テーブルの内容が同じならキャッシュを返す

テーブルが持つ要素

  • それぞれのフェーズが開始された位置
    • 書き換える時マーカーに頼らない
  • 変換フェーズの文字列
  • 送り仮名
  • フィルタされた文字列?
  • 挿入する文字列
    • マーカーなども含めるべきか
      • 補完のモードのことを考えるとそうすべきじゃない
      • 含めてないのと両方持つべき?
  • これに加えて「描画するけど変換などのためではないバッファ」もあるといい
    • かな入力の濁点とかは直前の文字を変化させる。だったら直前の文字を調べるより、「作業中」ということでテーブルの上に置いとけばいい
    • 直前の文字列なんかも調べる関数があればいい
    • もちろん位置も保存する必要がある

テーブルが持つバッファが持つ情報

  • 文字列
  • 描画する最初の位置
  • 描画するか否か

テーブルは配列で、これらの各要素は辞書型。


ードの順番の構造

  • 配列
  • マイナーモードは文字列
  • メジャーモードは数値
  • 順番はs:modes_order
  • メジャーモードはs:major_modes
  • マイナーモードはs:minor_modes
  • s:modes_orderの中でメジャーモードはs:major_modesの添字である数値で、マイナーモードはそのままの文字列で保存される

モードの登録

  • メジャーモードとマイナーモードで分けるべき
    • そうしないとautoloadのパスの解決に失敗する

マッピングテーブル

  • arpeggioなどのことも考えてオプションなどを取れる余地を残す

補完用のモード

  • すでに補完を表示してるかどうかはpumvisible()で取得できる?
    • ポップアップが表示されるのは関数を出てから(のはず)なので、もしかしたら正しく取得できないかもしれない...
  • 補完を出したかどうかのフラグを有効にさせるために補完のインターフェース必要?
    • autoload/skk7/complete.vim
    • autoload/skk7/minormode/complete.vim
    • そこまでする必要はない気がする...

モード

その他

  • インクリメンタル検索の途中なんかだと「▽」などのマーカーはうざい
    • モードごとにマーカー文字列は指定できるようにする?
    • デフォルト値とモードに特化した文字列(辞書型)
  • 携帯風の配列にすれば片手でキーボードが操作できる・・・!

(3月1日追記)

確認用。

いくつか確認

  • 関数は挿入する文字列をいじるとその文字列が挿入される
  • ノーマルモードじゃなかったらフィルタされた文字列を保存する
  • バッファしてる文字列をモードがローカルに持つとマイナーモードが補完などをできない
    • でもバックスペース時に英字とフィルタされた文字列の両方を「一文字」削除するのはどこまですればいいのか曖昧などといった問題があるため、次のようにする
    • 補完はフィルタされた文字列に対して行う
      • 子音などのまだひらがなに変換されてないものはモードが管理する
    • 「フィルタされた文字列」はバッファテーブルが持つ

何をバッファすればいいのか

  • ひらがなに変換中のローマ字
  • 漢字に変換中のひらがな
    • スティッキーキーが押されたら保存する
    • 補完に使えるはず

ただモードのバッファ用にするんじゃなくて、補完用のマイナーモードで使えるためにバッファの用途を仕様化する必要がある。
ひらがなを見るモードもあればローマ字を見るモードも作れる。

「ひらがな」「ローマ字」の順に表示される。
2つはバッファ文字列が持っていて、それぞれのフェーズごとに用意される。
テーブル上で現在のフェーズより小さい添字の全てのバッファ文字列が、間にマーカーなどを置かれて挿入される。
また2つに分かれているのはモードがいじりやすいため。

hiraモードでは、ひらがなに変換中の文字列はローマ字のバッファに入れられて、変換されたひらがなはひらがな用バッファに入れられる。
asciiモードでは、ローマ字のバッファしか使われない。

ノーマルモードだったらひらがなのバッファは挿入された後finallyでクリアされる。
これはoptにクリアするかのフラグを持たせて、モードにフラグを立たせる。

それかもっと汎用的にfinallyで実行する関数とかexコマンドを入れてくとか。
ただ難点はクロージャが使えないので、元の値を「参照」して変更することができない。
と思ったけど、C++0xクロージャの実装みたく、変数とそれに束縛されている値(つまり環境)を実行する時に復元すればいいのか。
Vimクロージャってできるかも。C++の参照はポインタの糖衣構文で、コンパイラの助けがいるのでできないとしても、ポインタは1要素のリストとして代用できる。

文字列を書き換える

例えば「さ」を入力したい時、aがフィルタ関数に送られた時に、直前に挿入された「s」を削除する必要がある。
この場合「s」はバッファ文字列にあるので、バッファ文字列の「s」を削除したあと、その文字数分だけバックスペースのキーコードを送ればいい。

バックスペースキーの仕事

  • 現在のバッファ文字列
    • ローマ字
    • ひらがな
  • 下位フェーズのバッファ文字列
    • ....

と見ていって、文字列が空でなかったらその文字列の最後の文字を削除して、挿入された最後の文字も削除するためにバックスペースのキーコードを返す。
全部空文字だったらただバックスペースのキーコードを返すだけ。

バックスペースなどの処理はautoload/eskk.vimのデフォルトフィルタの関数に戻す。

バッファ文字列

  • マーカー?
    • スティッキーキーによってセットされる
  • ひらがな
  • ローマ字
  • 変更されたかのフラグ

バッファテーブル

  • フェーズごとのバッファ文字列
  • バッファ文字列が変更されたり、まだ作られていなかった場合は、挿入する文字列を生成する
    • 挿入する文字列はfinallyでクリアされる
  • 変更された点を見つけるためのテーブルの複製

モードが(最低限)すること

  • ローマ字→ひらがな
  • 変換の処理

あとはモード側で変換フェーズを見て、ノーマルフェーズでなかったらデフォルトフィルタを呼び出す。

マイナーモード?

  • 'pre_filter'とか'post_filter'とかってメジャーモードの前後に実行するフィルタ関数のモードを登録できる形にする

その他

  • 「バッファ」という言葉は分かりにくい
    • 表示される文字列なのにそういう印象を受けない
  • その前に割り当てられていたマッピングを``なマッピングテーブルに割り当ておく

(3月2日追記)

だんだんと記録用になってきた気がする...

ディスパッチ側: 文字列の書き換え

  • 文字列が変更されていたら先頭に戻り表示されている文字列を書き換える
  • 改行を含んでいる場合、``で削除できるかは`&backspace`に依存する
    • `setline()` ?

バッファテーブル: 操作の抽象化

  • 現在のバッファ文字列が空文字で、セットする文字列が空文字じゃなかったらgetpos()する
  • 補完との協調
    • バッファ文字列の先頭の位置は補完関数が使える形にする
  • 確定(?)のための関数名
    • バッファ文字列
      • `clear()`
    • バッファテーブル
      • `clear_all()`
  • モードから簡単には変更できなくする
    • (モードに渡している間は)lockvarされるべきもの
      • バッファ文字列の先頭の位置
      • バッファテーブル(配列か辞書)
    • メソッドはunlockvarしてから操作を加える

(3月4日追記)



モード

マイナーモードとかメジャーモードとか区別しない。

  • 現在のモードの前に呼び出すモード
  • 現在のモード
  • 現在のモードの後に呼び出すモード

ってな風に呼び出していって、補完を出すなり、文字列の変換なりすればいい。
あと例としてだけど、capslock機能とか。


前後に呼び出すモードはどうやって指定するか

関数のがあとで構造変えられるからいいかな。


文脈を判断したautofill

実装するかはともかく、実装可能にしたい。
入力中に折り返されても(改行が入っても)変換を可能にしたい。

  • 表示する時に挿入する文字とその位置を指定できるようにする
  • バッファ文字列のローマ字やひらがなへの削除や追加の情報はバッファ文字列が持って、書き換えの際にそれらの変更が挿入する文字列に加えられる

ローマ字からひらがなへ変換する際の挙動

  • 「さ」と打ち込む時の「s」を全角にする
  • 「ss」とした段階で「っs」にするのか、「ss」ではまだ「ss」のままで「ssa」とした時に「っさ」とするのか
    • テーブルの定義を弄ればできる
    • テーブルもグローバル変数で定義を決めるとか
    • ユーザ側でちょっとした追加、削除をしたい

ローマ字からひらがなへ変換する際の挙動 2

  • ローマ字からひらがなへの変換で、候補が存在しなかった場合はそのまま挿入するようにしたい
  • というか今どうなってたっけ
    • skk.vim: 直前のローマ字を置き換える
    • MS IME: 挿入し続ける
    • 直前のローマ字を後ろから見て、変換可能だったらひらがなに変換
    • バッファ文字列の中では文字列がローマ字からひらがなへ移される
  • ddskkではどっち?
  • テーブルのAPIは後方から比較する関数を用意するべき
    • 前方から比較するのも残すべき
  • 後でTRIEで実装できるようにテーブルへのアクセスは関数で抽象化すべき

statuslineに表示するモードの文字列

  • モード名じゃつまらない

変換のAPI

  • ユーザがグローバル変数いじるだけでskkservでの変換をするようにしたいので、変換用のAPIは辞書をそのまま使うのとskkservを介するのと分けない方がいい

マッピング

漢字の意味をプレビューウインドウで表示

プレビューウインドウやポップアップは一度のキー入力に対して一つのモードしか使えない。
プレビューウインドウなら出力が複数行に渡った場合、:vsplitしてそれぞれ異なった行を見せることでスペースを稼げる。
でもプレビューウインドウってバッファみたいに分割できるんだろうか。
そもそもどういうものなのかもあまりよく知らないので調べる。

バッファでいい気がする。
バッファなら上みたいに複数ウインドウを作れば何個でも情報を表示できる。
確かpythonのomni補完がそんな感じで情報を表示してたような気がする。


他言語インターフェース

ソケット使って他言語でもモードを書けるようにする。
フォーマットはJSONYAMLどっちにしよう。
と思ったけどHTTPで通信するならヘッダでフォーマットを指定すればいいのか。

あと値を変更したら、その値を返してくれないと困る。
Vimでパースの簡単さを考えるとJSONだろうか。
(JSONVimスクリプトとの親和性が高いってid:mattnさんが言ってたけどeval()すれば読み込めるんだろうか(辞書とリストだけなら))
現状モードの仕様はフィルタ関数に引数で渡したものをいろいろ変更して処理を進めていくので、Vimスクリプトの場合は辞書とリストは「参照」なのでいいけども、JSONなどにデコードしてしまったら当然元の変数は「参照」されない。

あとバッファテーブルやバッファ文字列をいじるための関数はそれ自身に含めない方がいいな。
関数群は別に作って、new()の時にバッファテーブルを保存するといいかも。

あとあとやっぱりキーの名前は下線付きでない方がいい。
他の言語でもいじるんなら。
もともと関数から操作してほしいって意図でそうしたけど。

この機能といいvimprocが実用段階になったら色々できるのでvimprocの開発にも参加したいところ。
とりあえずskk.vimの機能をある程度実装できたら参加することにしよう。
ただ今LLに浸かりきってるのでCいじったら脳が爆発する気がする。


Google IME

多くのIMEは、ユーザーの入力から学習して、文節の区切りや単語のランクを変更する。ところが、この学習が愚直で、大昔にただ一度だけ入力した変な変換結果を、そのまますべての変換に適用し、その結果、学習すればするほど、おバカになっていくということが、ままある。

SKKにはあまり関係のないことかもしれないけど、
例えば補完で候補を選択するならその候補を削除とかできるとうれしいのかも。

*1:http://blog.livedoor.jp/dankogai/archives/51024711.html http://en.wikipedia.org/wiki/Test_Anything_Protocol

*2:id:mattnさんのgoogle-suggest.vimみたいに

*3:Win32 APIのウインドウプロシージャ的な

*4:static変数みたいに

*5:例えば変換中の文字列、送り仮名など

*6:xptemplate.vim, snippetsEmu.vim

*7:前回の「メジャーモード・マイナーモード」の項参照