2015年、Atom に乗り換えた。そして vim-mode-plus をリリースした。

  • 149
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

2015年、Atom に乗り換えた。そして vim-mode-plus をリリースした。

今年は Vim から Atom に乗り換えた。
Vim はいくつかプラグインもつくって、思うように操作したり、機能追加出来る程度にまで習熟してたけど、色々と嫌な点も出てきていたのと、Web フロントエンド技術の勉強も兼ねられるかなという思いもあり、Atom に乗り換える事にした。

最初 Light Table, Sublime Text, Brackets, Atom をそれぞれ試す。
→ Light Table 未来だな。むずいな。ちょっと今はパスだな!
→ Bracketsいいな。インラインエディット、リアルタイムプレビューいけてるな!
→ Sublime Text いいな、速いな。みんな使ってるしな!
→ Atom はおそいな、、
→ うーん Sublime Text に決めた!
→ というところで、tomoya さんのエイプリルフール記事を読む。
→ やっぱ Atom や!

ということで Atom に乗り換えた。

4月末頃に乗り換えて、ゴールデンウィークもはさんでいくつかパッケージもリリースした。
ちなみにその後もパッケージをリリースして、今は 20 個になっている。

https://atom.io/users/t9md/packages

全部メンテしている訳ではなく、放置気味のものもある。
Atom は バージョン 1.0 後の API フリーズの後も、「バージョンアップの度にメンテしているパッケージ機能が壊れる」という事が結構発生しており、気持ちが弱っているときは、しゅんとして嫌になって、「もうAtomやめたろか〜っ!」ってなる時もあります。
Public APIの機能しか使っていなくても結構こわれます。なので無理やり機能実現している paner とかは案の定壊れて、直してもまた壊れるだろうからモチベーションが上がらず、放置気味になっています。

本題、vim-mode-plus をリリースしました。

vim-mode-plus

2015年8月1日頃 リファクタリングの実験を色々やってみようと思い、vim-mode を fork していろいろ書き換え始めました。
最初は vim-mode 自体に contribute するつもりでしたが、リファクタの支援機構となる introspection の機能とその機能を使用した operation-stack のリアルタイムデバッグ機能をつけようと
試みるも、introspection の Pull Req 自体が 取り込まれなそう、、、、やり取りしていても、非常に responsive ではなく、
レスを待っている間に自分の commit もどんどん進むわ、他の人の commit も slack の vim-mode channel でメンテナの maxbrunsfeld に直接言うと動いてくれる、とか、そんなんフェアじゃねーじゃん!
とかいろいろ思うところがあり、
そうこうしているうちに私の vim-mode fork も取り込んでもらうには変更量が大きくなりすぎ、
英語の問題もあり、細かく説明して一つ一つ取り込んでもらうのは相当大変そうだ、、
もたもたやっているとこれはこれで、、

無理だな、、、

という事で本家に contribute するのは諦め気味になっていきました。

Atom を使い始めた4月末ごろ、思い切って text-object paragraph を追加する Pull Req をしてみて、取り込まれた時は、「やった!GitHub の人がコード見てくれて取り込んでくれた!」とかキャーキャー言って喜んでいたのですが、分からんもんです。
慣れてくると、不満もどんどん出てきて、自分でまるごと書き換えてやろう、みたいな心境、勢いになって来たのでした。

2ヶ月後の 9月30日に vim-mode-plus として リリースをしました。本家から何か反応あるかとドキドキするも、全然反応ナッシングでした。そういうもんよね。。。

どれぐらい変えたのか?

以下は、現在(2015.12.22) の vim-mode-plus の コミットグラフ (vim-modeとしての commit は fork した時点(2015.8.1)の 1321 )です。

  • 私が fork した時点(2015.8.1)の vim-mode の commits 数: 1321
  • 現在の(2015.12.22) vim-mode の commit 数: 1446
  • 現在の(2015.12.22) vim-mode-plus の commit 数: 2405

Contributors_to_t9md_atom-vim-mode-plus.png

vim-mode は 2013.6.21 から start した様です。
変更の内容はさておき、直近4ヶ月の私の変更(1087 commit, 54004行追加/49844削除)が"ちょっとしたもの"ではないのが分かると思います。
※ 行数が多いのは、test spec 含むほぼ全てのコードを書き換えたのに加え、分割されたファイルを一つにまとめたというのも関係している。

  • @t9md: 私
  • @mcolyer: GitHub の人。現在 Atom コアで積極的に活動している benogle と共に、Easel を立ち上げた人で、Easel が GitHub に買収されたので、GitHub の人になった。彼が初期の vim-mode をつくったっぽい。
  • @maxbrunsfeld: GitHub の人。現在の vim-mode のメンテナ。主に Atom Core や、もっとベースの text-buffer に精力的に contribute している。vim-mode には時間避けてないっぽい。
  • @bhuga: GitHub の人。初期 vim-mode に精力的に contribute していたぽい。
  • @jacekkopecky: github の人以外では最も精力的に PR を送っていた。仕事上、季節的に無理な時期もあるようで今はお休み中。

具体的に何をやったのか?

自分としては 内部的な改善(リファクタリング)一番大きい。
vim-mode は一つ一つの機能は単純(例えば、l を押した時にカーソルを右に移動させる機能とか)で、機能追加も部分的にやれるため、いろんな人がいろんな書き方で、機能を追加して、今に至るのだと思う。
そのせいもあってか、重複したコードや、分かりにくいコード、意味のないコードがあり、なかなかのカオスだった。
このカオスを頑張って取り除いたのが私がやった一番大きなことと自分では思っている。
機能追加もしたけど、それは膨大なリファクタリングの集積の上に浮かんだ上澄みみたいなもんで、オマケみたいなもんです。

  • vimState から mode シフト機能を modeManager として分離。deactivateInsertMode とか、deactivateVisualMode とかの Mode deactivation を Disposable として activation 時に返し、モードシフト時は単に Disposable::dispose() を呼ぶことで、既存 mode の後処理をするようにした。

  • Prefix.Repeat は単にカウントを渡すためだけに複雑な compose をしていて不要、複雑、難しい、事になってたのでまるごと削除

  • Prefix.Register は単にレジスタを読み取るためだけに複雑な compose をしていて不要、複雑、難しい、事になってたのでまるごと削除

  • MotionWithInput はユーザー入力を読み取るためだけに、複雑な継承関係を導入していて、不要、複雑、混乱する、のでまるごと削除

  • dd, yy 等をサポートするのに、特別な linewiseAliasedOperator という wrapper function をかましているが、これは単に operation-stack に同一の Operator が Push されたら MoveToRelativeLine と compose したら良いのでは?というひらめきを得て、そうした。結果、gUgUとか、どんな Operater でも 2 回連続で stack に積まれるといい感じで動作するように出来た。

  • Atom Command としての登録は class から自動的に register されるようにした。明示的にコマンド登録する必要なし。MoveRight(lの機能) class なら - 文字化(dasherize) した vim-mode-plus:move-right が自動登録される。

  • Operation を実行可能か判断するための、isComplete はかなりの部分自動判断出来るのに、個別に @complete = true とか設定してマニュアルコントロールしていたのが不要なので削除

  • 0 はカウントの 0 としての機能と、MoveToBeginningOfLine としての機能の2つの機能を実現する必要があって、MoveToBeginningOfLine 内で、どちらとして動作すべきか判断しており、2つの事を同時にやっていて、'名は体を表す' 状態になっていなかった。 これは単に count が指定された時に、with-count selector を editorElement の css class として設定すれば、後は、selector scope を絞った keymap で分けられるので、そうした。

  • 各 Operation に渡している引数の殆どが使われていないが、いちいちチェックするのが辛いので、不要なもの消す → いろいろ治す → 最終的に各 Operation は vimState instance のみを唯一の引数として受け取る、というように統一した。こういう convention(規約、ルール)の導入はすごく重要と思う。規約を信頼して、色々な例外ケースを考慮しくてよくなったのでメンテが大分楽になった。

  • ファイルが色々を分かれているのを一人でメンテするのは大変なので、ディレクトリ階層フラットにして、一つのファイルにまとめた。(Motion だけで、6個に分かれていたのを 1ファイルにしたとか)

  • Test spec の文字の多さ(冗長さ)が一人でメンテするときに大変になって来たので、mini DSL 的なものをつくって、単純に文字数、行数を減らしてより宣言的にテストを書けるようにした。test code の抽象度をあげようとするのには問題もあって、案の定、私もこの mini DSL のバグで、テストしているつもりが、 単に object の field 名の typo でテストがすっ飛ばされており、気づくまでに随分時間がかったとかはあった。(こういう不安を解消しようと、DSL に渡される object の key の validate をした時に案の定発覚)

その他細かい名前の変更とかは大量にやっている。書き換えていないコードは全体の 5%以下ぐらいじゃないだろうか。上記のような改善、改良を挙げていけばきりがないが、もはや全部思い出せない。
このエントリはいつか自分が振り返る為に書いている。

随分とつかれた。この4ヶ月 猛ダッシュで、マラソンしているような感じだったので、あとちょっとできりつけたらジョギングペースに落としたいと思う。

ではゼロから vim-mode をつくれたか?

これはまた別の問題。
難しいと思う。
土台となる根本の Concept は私が考えた訳ではない。すでにあったものだ。
Vim の操作を Operation と Target(Motion or TextObject)の Composition として実現し、その処理は OpertionStack への push, pop, process でやるぜ、みたいなのは vim-mode の初期から備えていた機能で、こういう実装の根本戦略というかアイデアを自分がゼロからつくれるかはまた別の話だ。

あくまでも既存のものを書き換えたに過ぎない。

test spec があったのも大変、大きい。
ガシガシ変更しても、test spec が fail すると、何かを壊したと気づくことができるので、安心して トライアンドエラーを繰り返しながら進んでいくことが出来た。
test spec で早期に degradation に気づくことが出来るので、後で大変な選択ミスに気づいて、苦労しながらコード中に散らばった選択ミスを元に戻す、とかしなくて済んだのだと思う。

vim-mode-plus の 今後の課題、超えられない壁

linewise(V) でのカーソル移動

これは超えられない壁だ。pure Vim では linewise でも カーソルが表示されており、l, h, $, w 等で移動可能だ。
characterwise にシフトした時に、ちゃんと linewise 時に移動したカーソル位置が考慮される。
Atom では selection と独立してカーソルを動かす事は出来ない。selection はカーソルについてくるので。
実現するためには、visual-lineiwse スペシャルに、仮想カーソル(virtual cursor) みたいなもんを用意して、擬似的にユーザーを騙して、移動しているように見せ、仮想カーソル位置をアップデートし、characterwise にシフト時に、仮想カーソルのカラム位置を real cursor に反映させる、とかせにゃならん気がする。Too Much 過ぎて負ける気しかしませんな。。

↑ [ 2015.12.24 追記 ]
これ越えられない壁じゃなかった。出来た。仮想カーソルとか大げさなものも必要なし。
v0.11.0 以降利用可能。細かい corner case の改善は今後

Make cursor movable in visual-linewise mode

マルチバイト文字のケア

visual-block モードではマルチバイト文字を考慮していない。visual-mode でのカーソル表示も同様。
私はコードに日本語混じるような仕事をしていないので、優先度は低い。
が、出来るもんなら改善したい。

vim-mode-plus の新機能

いろいろある。自分で判断して気楽につけたり消したりできるので、あまり確信がなくても、実験的に気楽に入れてしまったりしている。

Surround(map-surround とか新種の surround もある)、VisualBlock、visual モードでのカーソル表示、text-object-function, text-indentation とか結構色々組み込んでいる。
ドキュメントをまとめては書いていない。情報は以下のWikiに散らばっている。

おまけ

Facebook React チームの人っぽい、@jordwalke 氏が BountySource やってみたら? という Issue を立て、だいぶ時間立ってから立てた。

これ。atom-vim-mode-plus

そして、@bronson 含む 2名の人が bounty をくれたので、$25(3000円位) を GET した。初めて OSS で金稼いだぜ!ありがとう!

この Jordwalke の同僚の Cheng Lou さんが、要チェキラッ! 的なツイートをしてくれた。これを機に スターや、ダウンロード数がガッ増えた気がする。

この Tweet のやりとりで Jordwalke 氏は vim-mode-plus に '2015 Vim emulator Rookie of the Year Award' をくれるといっている。なんじゃそりゃ。でもうれしいよ!

この投稿は ATOM-editor Advent Calendar 201522日目の記事です。