mikutterの最新の情報は、mikutter blogに引っ越しました。

2012年5月28日月曜日

GUIプラグイン書き直してる話

久しぶりにやってることを書く。Twitterで小出しにして言ってたことをちゃんとまとめてみた。

GUIプラグインといえば、Gtkを使って諸々のUIを全て管理しているプラグイン。これを追加したことで、mikutterはbotからTwitterクライアントに進化したんだね。
ただ、最初にこれを書いてから三年くらい経ってるわけで、最初は200行くらいの超大規模()プラグインだったわけだけど、今では400行弱あって、これ関係が入ってるmuiディレクトリでwc -l *.rbやったら4700とか出てきて合わせたら5000行を超えますね。200行で大規模とか若かったな

現在問題になっていることが数点あって、それを解決するためにはもういっそ再設計したほうがいいんじゃないかと思って今回書きなおしてます。一応最低限動くようになってこれでいけるんじゃねって思ったので今回ブログを書きました。今回問題にしたのは

  • タブとかペインを扱うmikutterコマンド作るのがしんどい
  • プラグインのGtk依存を除去したい
  • タイムラインにイベントを引っ掛けられたら便利
の3点。

mikutterコマンドのほうの話は、そもそも俺がそんなことをしたいと思ってなかったのでそんな設計ではなかったんだけど、確かにできると便利。具体的には、キーを押せば左右のタブにフォーカスが移るという事ができる。ユーザ層的にキーボード大好きな人が多いので、できるとよさそう。ただ、今のguiプラグインだと、RubyGtkの知識がめっちゃ無いとそういうものは作れない。

もし完全にプラグインのGtk依存をなくせば、まずGtk以外のUIツールキットでmikutterのUIを書くことが理論上できるようになる。というのは、guiプラグインだけすげ替えればよくなるので。Gtkがうまく使えないプラットフォームでは、プラグインを書けばなんとかなるということがあるかもしれない。
それから(実はこっちがメイン)、イベントがGtkオブジェクトをやりとりしないようになるという事は、UIに影響を与えるようなプラグインでも別プロセス化しやすくなる。そもそも特定のプラグインのプロセス分けるのをまだやってないんだけど、その理由がほとんどのプラグインはタブ作ってるからあまり意味ないというもの。
ちなみにGtk依存は完全には無くせないと思ってます。理由は後述。

あとは、特定のタイムラインにだけ通知、フィルタなどをかけられるといいなと思ってるんだけど、これをするには今のタブの管理方法では不可能。大幅な書き換えがいるけれど、嬉しいことに三年で俺のスキルが上がったらしく、guiプラグインをいじっているとSAN値直葬されるので、書きなおすしかなくなってしまったわけです。

内部処理については端折るけれど、タブとかに固有ID(スラッグ)を持たせたら通知の鳴り分けができるし、その名前を指定して直接タブオブジェクトとかにアクセスできたら、ショートカットキーで左右のタブに移動するのもできるようになる。あとはちゃんと設計して前よりは読みやすくする。更に、gtkプラグインを新設することで、guiプラグインにgtkの話が一切入らないようにした。この2つのプラグインは、mikutterのイベント機能を使って通信しているので、ほかのプラグインで気軽にちょっかいを出せる。

多分多くの人にとっては、具体的にプラグインの書き方がどう変わるかが関心ごとだと思います。とりあえず今移植した中で一番簡単なfriend_timeline改めhome_timelineプラグインのコードがこんな感じです。



タイムライン作ってるらしい処理があるけどGtkの文字はどこにも出てこないようになりました。2-4行目が、タブを作ってアイコンを当てはめ、タブの中にタイムラインを入れるという一連の処理。
実際にツイートを入れるのは7行目ですね。これはスラッグを指定してインスタンスをわざわざ得ていること以外は特に変わらない。ところどころ出てきてるシンボルが識別名です。プラグイン、タブ、タイムラインで同じ名前使ってるから若干わかりづらいけど。スラッグさえ指定すれば別のプラグインから別のタブにちょっかいを出せます。

あとタイムライン以外に必要なパーツといえば、フォロイーリストとかで使ってるようなユーザリストと、アクティビティなどで使ってるCRUDビューくらいかな。もちろんプラグイン開発者が望めばGtkを使えるようにします。プロフィール画面をこの調子で作れるようにしようとおもったらwxWidgetsを再発明するハメになってしまいかねない。やり過ぎはよくないのだよ

以上でやりたかったことは全て解決できそうです。
しかし、guiプラグインならまだしも、gtkプラグインに依存するプラグインが出てきてしまうという新たな問題が顕在化しました。これじゃあ別のツールキットで実装が出来なくなるし、マルチプロセスの夢も遠のいてしまいます。というわけで、先延ばしにしていた、プラグインのメタ情報を書くことができる「プラグインメタファイル(仮名)」の実装を検討しています。
これは、yamlとかで、プラグイン名や想定するmikutterのバージョンなどを書いておくファイルです。別ファイルになっているので、実際にプラグインをロードするまえに動作条件を満たしているかどうかが分かります。ロード完了してからバージョンが違って動かないということがわかっても手遅れなので、ソースコード内に書くのはボツになりました。
この中に依存するプラグインを書いておけば、想定するプラグインがないというエラーを出せますし、同じプロセス上で実行するといった配慮もできそうです。

これは今のところ0.1.2のメインになるであろう変更でもあります。今のところ前のタイムラインやタブの作り方と互換性を取るのに苦労していて(タイムライン、タブにスラッグがない等)、mikutterとしては初の互換性がないリリースになる恐れがあります。(メジャーバージョン上げて0.2にしようかな。え?最初の0がどうしたって?)とはいえ、多少の書き換えで済むので、把握してるぶんについては、pull requestを送ることもできそうです。

丁度仕事も落ち着いてきて今月は時間が取れそうなので、あまり風呂敷を広げすぎないようにしつつ、8月はじめまでにはリリースしたいです。アレがあるからね