narrow つくった

# [narrow](https://atom.io/packages/narrow)

これは僕が最近かなりパワーを注いで開発していた、narrow という Atom package の宣伝記事です。  
めちゃくちゃ良いです。ぜひ使ってください.( lazy-motion 作った時もそう思ってたけど結局使わななくなったが、今回は違うはず！ )

基本的なドキュメントは [wiki](https://github.com/t9md/atom-narrow/wiki) にアップデートしていく予定。  
ですので、この記事の情報は古くなっていきます。  

- 絞込み UI 自体は目新しくもない。Vim なら ctrlP や unite.vim( denite ), Emacs なら anything, helm があるし、CLI ツールでもそういうの( percol, peco, fzf ...) がある。
- 因みに僕は Emacs の頃に anything を、Vim の頃に unite.vim を使っていた。
- そもそも僕が最初に作ったのも、Vim の時に使っていた unite 的なものを Atom でも作れないかと実験的に作ったのだった。
- 2016年5月頃になんとなく作って、リリースした後、ずっと放置していた。僕自身は出来に満足しておらず、全く使っていなかった。
- 当時は vim-mode-plus でやることが沢山あり、narrow にかけている時間はなかった。
- 今年(2017年)になって、vim-mode-plus も年末一段落したのと、飽きてきたので、narrow の実験を本格的に再開することにした。
- 2ヶ月間ぶっ通しで narrow ばかりやっていた。お陰で自分自身はかなり気に入る出来になった。

![commit-graph.png](https://qiita-image-store.s3.amazonaws.com/0/30758/14b27db6-9752-85f5-e0da-39a783d0ded2.png)

# 概要

## 用語と役割達

- `narrow-provider`: アイテムを提供する。アイテムを決定するとそのアイテム(ファイル/ポジション)が開く。
- `narrow-ui`: 殆どの文脈で、`narrow-editor` とイコール。
  - ユーザーの絞込みクエリに応じて、アイテムリストを更新する。
  - `narrow-editor` や `control-bar` やシンタックスハイライト( Grammar で提供 ) を管理する
- `narrow-editor`: アイテムが表示されるテキストエディタ。クエリは最初の行に入力する。

## active-editor と narrow-editor の関係

![overview](https://raw.githubusercontent.com/t9md/t9md/1654820b1f064aa11e087c7b3c1d6ce14ab03449/img/atom-narrow/overview.png)

## コントロールバー( Control bar )

それぞれショートカットが用意されていて、マウスオーバーするとツールチップ上にショートカットが表示されるが、覚えるまではマウスが便利です.

![control-bar](https://raw.githubusercontent.com/t9md/t9md/37f70896cb383f455f7a18a04d559e8adb05502c/img/atom-narrow/control-bar.png)

# 特徴

- helm や unite のような絞り込み UI を提供
- コードナビゲーションに重点を置いている
- 単一ファイルと紐づく provider は アクティブなテキストエディタが変わるとアイテムリストも自動更新される
  - このお陰で、`symbols` は常に現在アクティブなエディタのシンボルが表示されるので minimap 的、table of content for current code 的に使える.
- アクティブエディタのカーソル位置と、`narrow-editor` の "選択中アイテム" を自動同期
  - まず `narrow:next-item`, `narrow:previous-item` で `narrow-editor` にフォーカスがなくても、次、前のアイテムに移動できる様にしている
  - この時 `narrow` 以外のコマンドでカーソル移動しても、"次のアイテム"、"前のアイテム" が現在のカーソル位置を考慮して "次"、"前" を選んでくれる
  - 複数のファイルをまたいで検索、編集している時に「あれ、今何やってたっけ？」とか「いまアイテムリスト中のどこにいるんだっけか？」とならないように
- 直編集・反映機能( Direct edit )
  - `narrow-editor` で編集して、保存すると、実際のファイルを更新
  - 編集用に別の専用バッファを開かないで済むようにしている。直接編集、保存、反映の最短フローになる様に.
- キーボードナビゲーション
  - `narrow-editor` にフォーカスしていない状態で、`tab`, `shift-tab` で次、前のアイテムに移動したり、`narrow-editor` を閉じたり出来る
- 作者(僕)が拡張性にモチベーションがない
  - 最近「それほんとに必要？」という考えになってきた。少数の組み込み provider がいい感じにちゃんと動けば、それで僕はとりあえず満足。

# 組み込みの provider

僕が普段使いしているのは `scan`, `search`, `symbols`, `git-diff-all` です。

概要と画像は以下にまとまっている

https://github.com/t9md/atom-narrow/wiki/Provider

- `scan`: 現在のエディタをスキャン( 最初 `narrow:lines` がこの役割を担っていたが、こっちの方が良いので `lines` は削除した )
- `search`: `ag` の検索結果を提供( `ag` は自分で入れる必要ある )
- `atom-scan`: `search` と一緒だが、Atom の `atom.workspace.scan` を使って同じことをやっている。ちょっと遅いけど、`ag` 入れずに使える。
- `fold`: Fold の開始行をアイテムとして提供
- `git-diff`: 現在アクティブなエディタの git-diff が情報元。コアパッケージの `git-diff` の情報を利用
- `git-diff-all`: git-diff をプロジェクト全体で。( こっちはあとから作った。結果、単なる `git-diff` は僕は使わなくなった。)
- `bookmarks`: コアパッケージの `bookmarks` が情報元. なんちゃって provider であんまり便利じゃない。( 僕は `bookmarks` 機能使ってない )
- `symbols`: ctags で取れる関数定義箇所をアイテムとして提供. コアパッケージの `symbols-view:toggle-file-symbols` の narrow 版。
- `project-symbols`: プロジェクト全体の `tags` ファイルからアイテムを提供
- `linter`: [linter](https://atom.io/packages/linter) パッケージの情報を利用

# ユースケース

[Use case and flow of keystrokes](https://github.com/t9md/atom-narrow/issues/75) にも幾つか例がある

### minimap 的、 table of content for code 的な使い方( 常に開いておく )

![atom-narrow-minimap-like.gif](https://qiita-image-store.s3.amazonaws.com/0/30758/c61a76c3-5d2c-58eb-53d2-479e890cf738.gif)

### 関数の引数を一括で変更

![narrow-direct-save-practical.gif](https://qiita-image-store.s3.amazonaws.com/0/30758/0be1f1aa-2498-73da-eb96-eeac577be1a5.gif)


### 同一ファイル内の関数の使用箇所、定義箇所を quick preview

![helm-swoopish.gif](https://qiita-image-store.s3.amazonaws.com/0/30758/b9a6dae9-bc51-98a1-34e7-83a4093fe20b.gif)


### やっぱり使わなくなった関数の削除

保存するとアイテムリストが変更されるので最初に検索しておいて、検索結果の `narrow-editor` を見ながら
編集、保存、`ctrl-cmd-n`( or `tab` )で次のアイテムに移動を繰り返し、`narrow-editor` のアイテムリストが空になれば DONE!

![usecase-remove-unused-function.gif](https://qiita-image-store.s3.amazonaws.com/0/30758/4858de84-c4b7-f136-2c6e-85108cb0f3df.gif)

# 仕様( 作った後からかんがえた )

- Provider はアイテムを提供する
- 各アイテムは必ずファイルと、ポジションに紐付いていなければならない
  - つまり "どのファイルのどのポジションを開く" という形式でオープンで出来る必要がある。
  - "絞込UIでコマンド絞り込んで実行" みたいなのは対象外。やらない。
- ２種類の Provider ( boundToSingleFile vs Not boundToSingleFile )がある。
- 単一ファイルに紐付けられる( boundToSingleFile ) provider
  - e.g. `scan`, `fold`, `symbols`.
  - プロジェクトや、ファイル名のヘッダ行は表示しない( 不要だから ).
  - 基本的にこのプロバイダはバッファの内容が変更されるとアイテムリストが更新される( 保存の必要なし ).
    - `symbols` は例外。保存しないと更新されない
- 複数ファイルに紐付けられる( Not boundToSingleFile ) provider
  - e.g. `search`, `atom-scan`, `git-diff-all`.
  - プロジェクトヘッダやファイルヘッダを表示する
  - 基本的にアイテムリストの更新はファイルの保存時に行われる. 保存の必要あり.
- 各 provider はそれ専用の( dedicated ) `narro-ui` インスタンスを持つ。つまり Ui インスタンスは共有しない。
- `narrow-ui` は **常に** 現在アクティブ( focus されている )なテキストエディタに紐付けられる( bound to editor).
  - そして、アクティブなエディタのカーソル移動を検知して、"選択中アイテム"をアップデートする( 自動同期 ).
- `narrow-editor` は **普通の** エディタでなければならない
  - 通常のエディタで利用できている移動・編集コマンドやパッケージの機能を例外なく使える為にとても重要
  - e.g. [vim-mode-plus](https://atom.io/packages/vim-mode-plus) のコマンドが `narrow-editor` でも使えるように.
  - これまでに narrow-editor の Uiの改善や query-area と item-area の分離を試みて数回トライして毎回失敗したので学んだ.
    - https://github.com/t9md/atom-narrow/pull/89
    - https://github.com/t9md/atom-narrow/pull/133
  - 本当は、query-editor と アイテムレンダリング用エディタを分けたかった。だがチャレンジして何度も負けて諦めた。
  - Atom では エディタは pane-item で HTMLElement ならなんでもマウントできるので、Custom Element を作り、そこに Query input 用のミニエディタと、アイテムレンダリング用の mini じゃないエディタを埋め込んで、pane-item として pane に追加することもできて、実際やってみたら内部的には実装がスッキリするし、良い面もたくさんあった。しかし、これをやると、もう `narrow-editor` は **普通のエディタ** としては扱われない。具体的には `atom.workspace.observeTextEditors` とかで observe できなくなるので、これを監視している vim-mode-plus や他の多くのパッケージが `narrow-editor` 上で有効にならない。

# スタートアップの流れ

1. `narrow:scan` を実行
2. `Scan` が実体化( instantiation ) され、専用の Ui も実体化される
3. `narrow-editor`が開く