インターネッツの海を泳ぎまくっても解決しなかったので自分なりの対応を考えここにまとめておく。
もし、何かアホな事を書いていて、もっと簡単にできるねんで!とかあったら教えていただけると大変ありがたいです。
モチベーション
dtsmを使う時に、何で検索するべきかわからない時が結構ある。
例えば、dtsm install angular
とかやると、angular could not be identified. found: 38
とか言われてしまいます※1。
こうなると、dtsm search angular
などとして候補一覧を確認し、dtsm install angularjs/angular.d.ts
とする必要があります。
だるいですね。
そこで、pecoを使ってインクリメンタルにファイルの指定を行えるようにしたいな!となるわけです。
※1 これは、DefinitelyTyped上でangularjs/angular.d.ts
というファイル名になっているためです。jqueryの場合はjquery/jquery.d.ts
という名前なので、dtsm install jquery
でファイルを同定することができます。
簡単な実装(ただし動かない時がある)
var spawn = require("child_process").spawn;
var cmd = spawn("peco");
var result = [];
cmd.stdout.on("data", function (data) {
var str = data.toString();
var newResult = str.split("\n").filter(function (str) { return !!str; });
result = result.concat(newResult);
});
cmd.stdout.on("end", function () {
console.log(result);
});
cmd.stdin.write("abc\ndef\nghi\n");
これでOKです。
pecoが存在している環境では、これで正しく動きます。
pecoが存在しない場合の対応
pecoが導入されていない環境では以下のようなエラーになります。
events.js:72
throw er; // Unhandled 'error' event
^
Error: write EPIPE
at errnoException (net.js:905:11)
at Object.afterWrite (net.js:721:19)
厄介なのが、このエラーはtry-catchで復帰するのが難しい点です。
めんどくさいので深くは追っていませんが、on("error", ...)
などでも捕まえることができません。
エラーの原因として、pecoが存在しないため、ENOENT
が発生します(こちらはon("error", ...)
でハンドリングできる)。
その状態でcmd.stdin.write(...);
を実行すると、EPIPE
が発生します。
これを上手くハンドリングする方法はありません。
単純に考えると、とりあえずpecoをspawnしてみてENOENTが発生したら処理を失敗させる、という流れが良さそうです。
しかし、spawnが成功したか、起動したプロセスの標準入力に書き込みができるか、プログラムから確かめる方法がないようなのです。
起動成功確認→標準入力にデータ書き込み ができなくて、とりあえずガッと書くしかない、という状態です。
これを防ぐには、ENOENT
が発生しないように取り計らうしかないな!
というわけで、whichを使ってpecoが存在するか調べてから実行します。
whichのAPIはこんな感じで、こういう風に使うことができます。
まとめ
存在しないコマンドを実行した後にリカバリするの大変だから存在するかしないか先にチェックしてから実行しろ。