iTerm2からTerminal.appに戻ろうとして断念した

最近Vimとターミナル環境をリニューアルしている。
これまでずっとiTerm2を使っていたけど特に理由はなかった。最初にMac環境を色々構築した時に「iTerm2がナウいよ」って記事を読んで、良く分からないまま適当に入れただけだった。
標準のTerminal.appに出来なくてiTerm2じゃないと出来ないこと(使う理由)も良く分かっていない。

「背景画像を設定できる」のと「縦分割ができる」というのを良く見かけるが、僕は背景画像を設定しないし、縦分割はtmuxで出来るので必要ない。

そんなわけでiTerm2をやめてTerminal.appに戻ろうとしたんだけど、日本語を入力した時の挙動が気になってしまった。

f:id:kanno_kanno:20181213035929g:plain

入力中の日本語に応じて右にずれていく。撮り忘れたけど確定すると元の表示位置に戻る。
ちなみにGifでは縦分割だが、1ペインで入力中も時刻など右側に表示しているものがずれていく。
iTerm2だと再現しない。

調査する時間は持てず、結局iTerm2に戻ってきた。

さよならVim

これはVim大好きだったプログラマVim情報を追わなくなり、メインで使わなくなって、また帰ってくるまでの5年間の記録です。

Vimの情報を追わなくなった

それまでVimの情報を追い続けて、面白そうなプラグインは試して、自分でVimプラグインを作っていた僕がその手を止め始めたのは、転職をした2014年だと思う。
友人に誘われてフリークアウトに転職した時の僕は、フリークアウトが扱っているアドテクもPerlも一切知らなかった。

さらにフリークアウトのエンジニアはみんなレベルが高くて、入社してすぐに僕は自分が下から数えた方が早い技術力だと自覚した。
新卒のレベルですら非常に高いことに驚いた。その前の会社では僕を含め、新人といえばプログラミング未経験だったので衝撃は大きかった。
しかも新卒の人たちは広告に興味があって入ってきているわけで、業務知識は彼らの方が遥かにあった。現状に甘えたらすぐに追い抜かれる焦りを感じた。

エディタは自由なので当然Vimを使ったが、Vimをいじりたおす余裕はなかった。
入社してしばらくは自分が望む進捗を出せずに悶々としていた気がする。

唯一の活動としてprevimは使ってくださるユーザーさんがいたので、出来る範囲でサポートを続けてきた。

1年が経つ頃には業務にも慣れてきたけど、同時に「Vimの情報を追わない」ことにも慣れてしまっていた。
入社した段階で「自分のVim環境」は出来上がっていたので、無理に追う必要もなかった。それよりは仕事を進めたり、他の技術的な興味を追っかけたりする方が楽しくなっていた。
広告分野にしろ技術的なことにしろフリークアウトで学べることはたくさんあって、そちらを優先する方が大事に思えた。


フリークアウトに入って2年が経ち、2016年に僕はフリーランスになった。

請け負って一人で開発したのも含めるとRuby, Python, PHPなど色々な環境を経験できた。
直近の仕事を除き全てVimで開発してきた。Vimがあれば十分だった。

でも.vimrcの設定の多くは2014年の状態で止まったままで、少しだけフリークアウト時に修正したものが残っている程度。
プラグインの更新もほとんどしていない。更新して動かなくなることが嫌だから。
僕の中でVimが単なるツールに成り下がっていた。

Vimは楽しい」という感覚はこの頃に失っていたと思う。これまでの習慣で身についた「Vimの操作性」から離れられず、惰性で使っていたに過ぎない。

Vimをメインで使わなくなった

フリーランスになって少しして、僕は自分のサービスを作ることに目覚めた。
僕は本が好きで、本屋が好きだから、今の出版不況を何とかしようと燃えていた。初めて生き甲斐を見つけたと興奮した。
(リトルスタッフ開発者の自己紹介)

自分のサービスを開発するのもVimを使っていた。当時はまだ。
サービス開発に熱中していたし出版業界を知るので精一杯だったから、Vimに限らず技術的なキャッチアップもほとんどしなくなった。開発以外に企画やら営業やら新しい作業は山積みにある。使える時間は限られている以上、何かを切り捨てないといけなかった。

一方で生活費が必要な僕はフリーランスの仕事も続けた。友人に誘ってもらって2017年12月からPHPの現場で働き始めた。

そこでPCを支給してもらい開発環境のセットアップを始めた僕は、もちろんVim環境を構築した。
ただここで問題が起きた。まともに開発するには「何か挙動がおかしい」感じだった。
すごく漠然とした書き方になっているのは、ほとんど調査をしなかったからだ。

.vimrcを読み込まずに素のまま立ち上げたら問題なかったので、.vimrcの設定か、プラグインがおかしいことは明らかだった。
そこまで分かったとき僕はVimにイラッとした。(正確にはVimそのものじゃなくて自分の設定やプラグイン側の話だが)
面倒くさいと強く思った。

当時「Vimはツール」という感覚まで冷めていた僕は、「こんなことでハマるくらいならIDEを使う」と気持ちを切り替える。
PhpStormに馴染むには時間がかかったけど、慣れてしまえばすごく便利だった。
(Vimキーバインド以外で開発など無理な体になっているので、もちろんIdeaVimは入れた)

Vimとの比較でいえば「定義ジャンプ」と「ブレークポイントによるデバッグ」がダントツで便利だった。
以前の僕なら「それVimでも出来るよ」とか「別にそこまで必要じゃない」と思っていたけど、体験すると価値観が変わった。
Java + Eclipseで長いこと開発してきた経験もあるからそれらの便利さはもちろん知っていたけど、長らく使っていなかったせいか、こんなに効率違ったかと反省した。今までだったら関数定義をgrepしてファイルを開いていた操作が、PhpStormならショートカットキー1発で正確に飛べる。
特にこの現場での作業は調査寄りのことが多かったので、定義ジャンプとデバッガの有無は大きく影響した。
(それまでの現場のように追加開発がメインだったら、感想は違ったかもしれない)

そして自分のサービス開発もVimからPhpStormに切り替えた。

Vimへの熱がなくなり、自分のサービスに専念したい僕はprevimも有志のメンテナさんへ引き継ぎをお願いした。
快く引き受けてくださる方が数名いて、非常に助けられました。ありがとうございます。
(previmを他の方にお譲りしたい)

僕は開発において、完全にVimを使わなくなった。

それでもVimに帰ってきた

メインでVimを使わなくなって約1年が過ぎたが、最近「Vimをまたいじろうかな」という気持ちが芽生えていた。
きっかけは分からない。技術的なキャッチアップから遠のいている焦りかもしれないし、今の生活へのマンネリかもしれない。

技術的なキャッチアップをしなくなってから、つまりここ数年はTwitterのメインTLを見ていない。
それがここ最近は少しずつリハビリした方がいいかもと思い始めていて、たまにTwitterを開くようになっている。
そんな中、たまたま開いたらVimConf 2018のリアルタイム実況が流れてきた。めちゃくちゃ楽しそうだった。

TLを追いながら、そうだVimは楽しいんだった、ということを思い出していた。
最初にVimへ興味を持ったのは「Vimを覚えたら効率が上がるかもしれない」というツール的側面だったけど、学ぶうちに「Vimを使うこと」や「Vimを使っている自分」が楽しくて、その体験が目的になっていた。それが大事だった。

Vimが楽しいからプログラミングにも意欲的になれる。プログラマとしての自分を楽しめる。僕はそういうタイプのはずだった。

PhpStormの便利さは変わらないから引き続き使い続けるかもしれない。ライセンス更新のタイミングでどうするかはまだ決めていない。

今はただ、Vimの楽しさを思い出そう。僕はVimの情報を追い始めている。

ファイルが変更されたら特定のコマンドを実行するentrというシンプルなツール

あるファイルが変更されたら特定のコマンドを実行したいというケースは良くある。例えばテストの自動実行とかブラウザの自動リロードとかサンプルコードを走らせたいとか。
これらを解決する手段としてguardが有名だしgulpで解決している人も多い。

entrはそんな「ファイルの変更を検知してコマンドを実行する」ツールの一つ。

こちらの動画で使用されているのを見て知った。entrの登場は開始50秒くらいから。


Goライブコーディング: go-switchgen(2倍速)

コンセプトは上記の公式サイトに書いてある。

entr is a zero-configuration tool with no external build or runtime dependencies.

guardやgulpと違い、entrは設定ファイルも依存ライブラリもいらない。実装はC言語で書かれている。

macならhomebrewで簡単に入る。他のOSはREADMEを読む限り普通にmake installだと思う。

$ brew install entr

説明が不要なくらい使い方はシンプル。変更を監視したいファイルをパイプで渡してあげるだけ。/_は変更があったファイルを指す。

f:id:kanno_kanno:20181208144744p:plain
(1ファイルなのでfindじゃなくechoで十分だった)


キャプチャでは1ファイルだけ指定しているけど、もちろんgrepによる複数指定が可能。ファイル一覧を渡せばいいのでgrepじゃなくてagとかackとかでももちろんOK。

// 公式サイトより
$ ag -l | entr make

使い方 - オプション

man entrで確認できるオプションについて僕なりの理解。

-c
デフォルトだと実行結果は標準出力にどんどん追加されていく。
f:id:kanno_kanno:20181208145848p:plain
-cを付けると実行のたびに画面がclearされる。watchコマンドの実行結果みたいなもの。

-d
指定したディレクトに新しい追加があった時にexitされる。
fooディレクトリを作ってfind foo | entr -d go run /_を実行したあと、新しくファイルを作ったら「entr: directory altered」というメッセージとともに確かにexitされた。
ちなみに追加ではなく削除してみたら「entr: cannot open 'foo/a.go': No child processes」というメッセージとともにexitされた。(落ちた)

-n
このオプションを付けると「非インタラクティブモード」で動く。デフォルトだと後述するようにentr実行中にキーボード入力を受け付けるが、-nだと無反応になる。どういう時に使うのかは分からない。

-p
デフォルトだとentrを実行した段階でまずコマンドを実行する。-pを付けるとファイルに変更があるまで実行しない。Postpone(後回し)のpだ。

-r
コマンド実行の度に子プロセスを作り直す。
デフォルトではプロセスツリーはこうなっていて、コマンド実行は同じプロセスで実行される。
f:id:kanno_kanno:20181208160324p:plain

それが-rを付けると子プロセスを作って実行され、再実行のたびに子プロセスは生まれ変わる。
f:id:kanno_kanno:20181208160452p:plain
examplesだとentr -r node app.jsのようなサーバー再起動などで使われているので、リソースをちゃんと解放させたいとかそういう時に指定する感じかな。

-s
引数で指定したコマンドを$SHELLに対して実行する。簡単に言えば指定したコマンドを実行するだけ。
公式の例にある$ ag -l | entr -s 'make && make test'のように、&&とかをちゃんと解釈させて動かしたい時に使うのだと思う。

使い方 - コマンド

entr実行中に受け付けているキーボード操作は2つ。

スペース
即座にコマンドを実行する。

q
entrから抜け出す。

例: SQLファイルを更新するたびにMySQLへ即実行

man entrに載っているexamplesを見ていたらこんなのがあった。

Clear the screen and run a query after the SQL script is updated:

      $ echo my.sql | entr -p psql -f /_

sqlファイルを編集したら即座にPostgreSQLに実行するというサンプル。面白いなと思った。
psqlだとサンプルそのままなので、MySQLで試してみた。

$ echo sample.sql | entr -c -p -s "mysql sample < sample.sql"
  • -cで実行の度に画面をクリア
  • -pで初回は実行しない。何か怖いので
  • -sでコマンドを指定
    • リダイレクト(<)を使うせいか、デフォルトのままでは動かなかった
    • -sを使っているため/_(変更があったファイル)の記述を使えなかった
      • コードを読む限り-sを使っていると無理っぽい

一応これで実行できた。Vimでファイルを編集したら即座に結果が出力される。ただ普段はGUIツールを使っているので実際に使うことはないだろう。

監視対象のファイルが多いとエラー

何も考えずディレクトリを指定したらエラーが発生。

Too many files listed; the hard limit for your login class is 4864

扱えるファイルディスクリプタのソフトリミットを超えたので当然。特に意識したことないけど、guardとか他のツールも同様の制御があるんだろうか。制御がなくてもソフトリミット超えたら落ちるはずだから一緒か。

おまけ

動画を見たのは少し前だったので今日導入したいと思った時にentrという名前を思い出せず、当初の目的はgoで書かれたcespare/reflexを入れて解決した。
そのあとに元動画を思い出して、entrのmanやリポジトリを見たら小さかったので勉強のために出来る範囲で読み解いた。C言語、雰囲気でしか分からないな。ファイルやプロセス周りだから、C言語というよりシステムプログラミングが分かっていないのか。でも「分からないけどちょっと分かる」みたいなレベルを追いかけている時って面白い。

Vim - 開いているファイルや選択しているコード行をGithubで開く

チーム開発をしている時など、「選択しているコード行のGithub URLが欲しい」ケースは多い。
URLで指定した行番号をハイライトしてくれる、こういうURL。
https://github.com/previm/previm/blob/12226fa0e3e807a6498cd6bd6de8af70278203fe/autoload/previm.vim#L64-L65
レビュー時やチャット上で共有する時に使う。

Vim上でサクッとやるには以下のどちらかのプラグインで実現できる。

vim-fugitive + vim-rhubarb

vim-fugitiveを入れるとgit管理下において:Gbrowseコマンドが使えるようになる。
このコマンドはg:fugitive_browse_handlersに設定されたハンドラを使用してURLを開く。
開きたいコードを行選択してから:GbrowseすればOK。もちろん行指定が不要なら引数なしでそのまま:Gbrowseを実行すればいい。

このg:fugitive_browse_handlersはもちろん自分で設定できるけど、vim-rhubarbを入れると勝手に設定してくれる。
(vim-rhubarbはhubを利用するためのプラグイン)

なお:Gbrowse実行時に「fugitive: "origin' is not a supported remote」というエラーが出る場合はプラグインが古いので更新すること。
g:fugitive_browse_handlersが空の場合は「fugitive: No Gbrowse handler found for '...'」といったエラーになる。

open-browser.vim + open-browser-github.vim

これは作者のtyruさんが紹介記事を書かれているのでそちらを参考に。
基本的な使い方は:Gbrowseと変わらない。
http://tyru.hatenablog.com/entry/20130125/useful_vim_commands_for_getting_along_with_github

どっちを使う?

どちらも素晴らしいのでお好きな方でいいと思う。
hubを良く使う人はvim-rhubarbを入れておくと便利なのかもしれない。僕はほとんど使っていないので便利度は分からない。
open-browser-github.vimのtyruさんは日本人なので、困った時に質問しやすいかもしれない。

この記事のきっかけ

今回のケースに対応するコードを、僕は.vimrcに書き捨てで設定していた。
Vim環境を整理するにあたってそのコードを消して、:Gbrowseが動くように四苦八苦した。
(最初はプラグインが古くて動かず、次にg:fugitive_browse_handlersがなくて動かなかった)

あとになって「そういえばopen-browser-github.vimがあったな」と思い出して結局そっちを使うことにしたのだけど、せっかくなので調べたことを残しておくことにした。

Laravelのセッションに関するテストでSession name cannot be emptyが出て落ちる場合の対応

軽い気持ちでcomposer updateしたらテストが落ちて、その調査と暫定対応をしたのでメモ。

エラーログ

PHPUnit\Framework\Exception: [2017-12-04 00:44:41] testing.ERROR: Session name cannot be empty, did you forget to call "parent::open()" in "Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler"?.

原因

AbstractSessionHandlerの2ヶ月前の変更による。

[HttpFoundation] Make sessions secure and lazy · symfony/http-foundation@55ca8d8 · GitHub

かつ、もう一つ。

テストケースにphpunit@runInSeparateProcessを付けていると落ちる。
ちゃんと原因を追っていないですが、別プロセスゆえにparent::open()parent::destory()がバラバラになっているのかな。分かりませんが。

なんでこのアノテーションを付けているかというと、依存ライブラリのStaticファサードをモックにしたかったから。
PHPUnitで静的(static)メソッドのモック - Qiita

なお StaticMethods をモッククラスとして定義するので、別のテストで StaticMethods を呼ぶと意図しない結果になります。例えば、次のようなテストケースだと test1 の実行時に StaticMethods がモックとして定義されるので test2 のテストは通りません。 @runInSeparateProcess アノテーションを使えば test1 は別プロセスになるので回避できます。

前も@runInSeparateProcessの挙動でハマったから、これ使いたくない。
その場合はStaticファサードをラップするクラスを自分で用意する必要がある。

対応

ちゃんとやっている余裕はないので暫定対応。
上記のコードを読むとsession.use_cookiesを使っていることが分かるので一時的にoffっている。

# これをテストコードの適当なところに書く
ini_set('session.use_cookies', false);

結論

テスト大事。
とはいえ、今回は「テストでしか落ちない」ケースではあるんだけど。