peco+AppleScriptで作業効率化

#pecoって？

とりあえず[本家リポジトリのデモ](https://github.com/peco/peco/blob/master/README.md)をご覧ください。
渡した標準出力をインクリメンタルサーチして更に渡せます。便利ですよね、peco。
パイプラインや正規表現を活用することでコマンドベースの作業における様々なショートカットやジャンプ機能が実現できます。

#使ってみる

##`git grep`した結果からエディタで開く

作業中、gitリポジトリ内ソースの調査や確認でよくやる操作です。ワンライナーだとこんな具合でしょうか。

```
git grep 'hogehoge' | peco | sed -E 's/^([a-zA-Z0-9\./_]+):.*$/\1/' | xargs open
```
shellに仕込むとこんな感じ。

```shell:~/.bashrc
function grepo() {
  command git grep $1 | peco | sed -E 's/^([a-zA-Z0-9\./_]+):.*$/\1/' | xargs open
}
```
これで`grepo {検索文字列}`で呼び出し、ファイルを選んでEnterするとそのファイルを標準出力で開けます。早速いい感じですね。

`git grep`で正規表現を使いたければオプション`-e`を、openで開くエディタを変えたいときはオプション`-a`を使ってよしなにすればよいです。

## 該当行までジャンプ

でもこういう「検索した上でそのファイルを開く」という作業の場合、実際はそのHit行を見に行きたいはずです。

私が使用しているエディタはSublimeText3なのですが、その際に行フォーカスする操作が以下のようになっています。

1. ctrl+Gで行サーチ（Goto Line...）をアクティブにする
2. 行数を半角英数で入力する[^1]
3. Enterでその行にカーソルを移動する

しかしこの操作はターミナルからの操作範疇を超えています。pecoだと開くところまででしょうか。

### １コマンドでSublimeText側での操作までやる

ここで**AppleScript**を使ってみます。
詳しい実態説明は先人の記事に譲りますが、Mac専用のアプリケーションスクリプトであり、MacOSでサポートするあらゆるアプリケーションをGUI的な感覚で命令を実装・実行することができます。

先ずAppleScriptの前に、`git grep`に行数を含めるオプションを張ります。

```~/.gitconfig
[grep]
        lineNumber = true
```

次にSublimeTextを開いた後の挙動をAppleScriptで…

と行きたいところですが、先程のコマンドでは常にopen実行のため、**現在開いているウィンドウの別タブで開く**ということができません。
平素の作業に沿わせると、こちらのほうが実用的です。AppleScript側に「SublimeTextを開いてファイルを開く」の操作を配備することで、ついでに解消してしまいましょう。

以下のAppleScriptをホームディレクトリに実装・コンパイルしておきます。

```AppleScript:~/sublime_text.applescript
on run argv
	tell application "Sublime Text"
	activate -- Sublime Textを起動
		tell application "System Events"
			tell process "Sublime Text"
				set frontmost to true -- 画面を最前面にする
				keystroke "o" using command down -- ファイルマネージャの表示
				delay 0.5
				keystroke "g" using (command down, shift down) -- パス入力の表示
				delay 0.5
				keystroke item 1 of argv -- ファイルパスの入力
				delay 0.8
				keystroke return -- Return key（ファイルパスの決定）
				delay 0.5
				keystroke return -- Return key（OPEN命令）
				delay 0.5
				keystroke "g" using control down -- LineSearch起動
				keystroke item 2 of argv -- 行数の入力
				keystroke return -- Return key（行フォーカス）
			end tell
		end tell
	end tell
end run
```

```
osacompile -o ~/sublime_text.scpt ~/sublime_text.applescript
```

仕上げにshellです。grepのオプションも変更しているので、それも踏まえて修正します。

```shell:~/.bashrc
function grepoo() {
    target_line=$(git grep $1 | peco)
    relative_path=$(echo $target_line | sed -E "s/^([a-zA-Z0-9\./_]+):([0-9]+):.*$/\1/")
    line_number=$(echo $target_line | sed -E "s/^([a-zA-Z0-9\./_]+):([0-9]+):.*$/\2/")
    if [ -n "$line_number" ]; then
        osascript ~/sublime_text.scpt $(echo `pwd`)/$relative_path $line_number
    fi
}
```

スクリプト実行前のifは誤実行防止です。

`grepoo {検索文字列}`でファイルを選択すると、今度はファイルを既に開いているウィンドウでOPEN（開いていなければ起動）し、該当行までジャンプしてくれるコマンドになっています。

##おわり

pecoは、シェルやAppleScriptを併用することで、更に機能を連結して圧縮したり、幅をもたせることができます。途中にはインクリメンタルサーチが挟まり、比較的ユーザにも優しいです。

ただ、AppleScriptによる制御はコードの通り、ところどころディレイをかけないと機能保証ができないことがありました。GUI操作は若干の時間を要する上、実行中に画面操作するとスクリプトの動作と競合する（**実質操作不能**）ので、触感としてはややモッサリ感が…
あくまでウィンドウはopenコマンドで開いて行フォーカスのみAppleScriptで実行したほうが、手元の感覚だと馴染みやすいかもしれないですね。

私はこの他にも、

- `git blame`結果をpecoでサーチし、選択した行のcommitをビューするURLをブラウザで開く
- 同様のサーチで、選択した行を修正した案件管理システムの該当チケットURLへジャンプ

等、普段から活用しています。

コマンドベースでの業務は種々の環境に依存する側面が少ないはずなので、まだまだお世話になるシーンは多そうです。
最早しゃぶり尽くされたコマンドかもしれませんが、実践編ということでご容赦ください。おすすめです。

[^1]: SublimeTextにおいて行サーチはインクリメンタルサーチなので、入力終了の段階で行の表示は実現します