目的ディレクトリに一発でcdできるコマンドcda

ターミナルで目的のディレクトリにエイリアス名で`cd`できるコマンド`cda`を公開しました。

# cda
cda v1.5.0 (2018-07-16)
[https://github.com/itmst71/cda](https://github.com/itmst71/cda)

# DEMO
[v1.4.0 DEMO in YouTube](https://www.youtube.com/watch?v=T4o_Q7HlBYw)<a href="https://www.youtube.com/watch?v=T4o_Q7HlBYw">
<img src="https://github.com/itmst71/cda/wiki/images/demo_youtube_thumbnail.png" width="500" title="v1.4.0 DEMO in YouTube">
</a>

# 概要
`cda`はブックマーク系の`cd`高速化ツールです。あらかじめエイリアス名とパスをセットで登録しておき、実行時はエイリアス名だけを指定します。

エイリアス名は一意に識別できるだけの入力があれば完全名でなくても認識されます。複数件候補がある場合は`percol`や`peco`などのインタラクティブフィルタで絞り込むことができ、`bash-completion`での補完にも対応しています。


# 特徴
* Bash関数として実装
* エイリアス名でcdを実行
* データをテキストファイルで管理
* `peco`, `percol`, `fzf`, `fzy`などのインタラクティブフィルタ対応
* `Bash-Completion`対応


# 必要環境
* Bash 3.2+ / Zsh 5.0+
* いくつかの POSIX コマンド

# インストール

**gitの場合**

```console:カレントディレクトリにcloneする例
$ git clone https://github.com/itmst71/cda.git
```

```bash:~/.bashrcまたは~/.zshrcに追記
[[ -f "/path/to/cda/cda.sh" ]] && . /path/to/cda/cda.sh
```

補足：以下のように設定ファイルと同じディレクトリに`clone`することもできます。

```console:設定ファイルと同じディレクトリにcloneする例
$ git clone https://github.com/itmst71/cda.git ~/.cda
```


**Homebrewの場合**

```console
$ brew install itmst71/tools/cda
```

```bash:~/.bashrcまたは~/.zshrcに追記
 [[ -f "$(brew --prefix cda)/cda.sh" ]] && . "$(brew --prefix cda)/cda.sh"
```

# アンインストール

**gitの場合**
`~/.bashrc`または`~/.zshrc`に追記したコードを削除し、`git clone`したディレクトリと`~/.cda`を削除して下さい。

**Homebrewの場合**
`~/.bashrc`または`~/.zshrc`に追記したコードを削除し、以下のコマンドを実行して下さい。

```
$ brew uninstall cda
$ brew untap itmst71/tools
```

# 使用方法
## 基本操作

`-a`または`--add`でエイリアスを追加します。

```console:エイリアスfooを追加
$ cda -a foo /baz/bar/foo
```

```console:エイリアスfooでcd実行
$ cda foo
$ pwd
/baz/bar/foo
```

前方一致検索で一意になれば完全名を入力する必要はありません。

```console:不完全な入力で実行
$ cda f
$ pwd
/baz/bar/foo
```

`bash-completion`対応なので`TAB`キーでエイリアス名を補完できます。

```console:TABキーによるエイリアス名の補完
$ cda f<TAB>
$ cda foo
```

`-l`または`--list`でリストを表示します。

```console:エイリアスリストの表示
$ cda -l
foo         /baz/bar/foo
```

エイリアス追加時にパスを省略するとカレントディレクトリが対象になります。

```console:パスを省略して追加
$ pwd
/baz/bar
$ cda -a bar
$ cda -l
bar         /baz/bar
foo         /baz/bar/foo
```

`-r`または`--remove`で削除できます。

```console:エイリアスbarを削除
$ cda -r bar
$ cda -l
foo         /baz/bar/foo
```

パスから逆引きで削除することもできます。

```console:パスを渡してエイリアスbarを削除
$ cda -l
bar         /baz/bar
foo         /baz/bar/foo
$ cda -r /baz/bar
$ cda -l
foo         /baz/bar/foo
```

`-e`または`--edit`でリストファイルをテキストエディタで直接編集できます。

```console:テキストエディタで直接編集
$ cda -e
```

`-h`または`--help`で簡易ヘルプを表示します。

```console:簡易ヘルプ表示
$ cda -h
```

## 設定ファイル
`~/.cda/config`が設定ファイルです。`--config`オプションで開くことができます。

```console:設定ファイルをテキストエディタで編集
$ cda --config
```

```console:現在の設定や変数を表示
$ cda --show-config
```

```console:--reload-configで変更した設定を反映
$ cda --reload-config
```

```console:--reset-configで設定を初期化
$ cda --reset-config
```

## インタラクティブフィルタ
エイリアス名の絞り込みに外部のインタラクティブフィルタコマンドが使用できます。
デフォルトでは`CDA_CMD_FILTER`という変数に、コロン区切りで複数の代表的なフィルタコマンドが設定されています。このうち利用可能な最初のコマンドが使用されます。

```console:デフォルト
CDA_CMD_FILTER=peco:percol:fzf:fzy
```

入力されたエイリアス名で1件に絞り込めなかった場合、利用可能なフィルタが存在すれば自動的に起動します。
以下の例ではエイリアス名をまったく入力しなかったのでリスト全体がフィルタに渡されています。

```console:引数がない場合リスト全体がフィルタに渡される
$ cda
QUERY>                                       (1/5) [1/1]
:bar         /baz/bar
:baz         /baz
:foo         /baz/bar/foo
:foo2        /qux/baz/bar/foo
:foo2_2      /quux/qux/baz/bar/foo
```

入力したエイリアス名に複数件ヒットした場合はヒットしたものだけがフィルタに渡されます。

```console:fで始まるエイリアスだけがフィルタに渡されている
$ cda f
QUERY>                                       (1/3) [1/1]
:foo         /baz/bar/foo
:foo2        /qux/baz/bar/foo
:foo2_2      /quux/qux/baz/bar/foo 
```
        
部分一致するエイリアスが複数あったとしても、完全一致するエイリアスがあればそれが優先されるのでフィルタは起動しません。

```console:完全一致エイリアスが優先される
$ cda foo2
$ pwd
/qux/baz/bar/foo
```

`-f`または`--filter`を使用すると完全一致するエイリアスがある場合でもフィルタを起動します。

```console:-fオプションで完全一致エイリアスがあってもフィルタを起動
$ cda foo2 -f
QUERY>                                       (1/2) [1/1]
:foo2        /qux/baz/bar/foo
:foo2_2      /quux/qux/baz/bar/foo
```

`-F`または`--cmd-filter`オプションで`CDA_CMD_FILTER`変数を一時的にオーバーライドできます。

```console:一時的にfzfを使用する
$ cda -F fzf
  :foo2_2      /quux/qux/baz/bar/foo
  :foo2        /qux/baz/bar/foo
  :foo         /baz/bar/foo
  :baz         /baz
> :bar         /baz/bar
  5/5
> 
```

### 内部簡易フィルタ
* `cda`自体も簡易フィルタを内蔵しており、このフィルタで１件に絞れなかった場合に外部フィルタコマンドを起動します。   
***第一引数は常に前方一致検索に使用されます。***  

```console
$ cda --list-names       # エイリアス名だけ表示
lindows
linux
linuxmint
lubuntu
macosx
manjarolinux

$ cda --list-names l     # 第一引数 "l" は常に前方一致検索に使用
lindows
linux
linuxmint
lubuntu
```

* 第二引数以降は順番に部分一致検索に使用されます。  

```console
$ cda --list-names l u t   # l で始まり後に u t の順で出現するのは2件
linuxmint
lubuntu

$ cda --list-names l t u   # lで始まり後に t u の順で出現するのは1件
lubuntu
```

* 変数`CDA_MATCH_EXACT_ORDER`を`false`に設定すると第二引数以降は順不同部分一致検索に使用されます。  
これは`v1.3.0`以下のバージョンと同じ動作です。  

```console
$ cda --list-names l u t   # lで始まり後に u t が順序を問わず両方出現するのは2件 
linuxmint
lubuntu

$ cda --list-names l t u　　# lで始まり後に t u が順序を問わず両方出現するのは2件
linuxmint
lubuntu
```

## その他の機能
**ここから先は知らなくても通常の使用で困ることはありません。**

### 特殊エイリアス "`-`"
`cd`コマンドと同様に "`-`" は最後に`cda`で移動したディレクトリのパスを指します。
パスは `~/.cda/lists/.lastpath` に保存されており、他のプロセスとデータを共有しています。`tmux`などのターミナルマルチプレクサを使用している際に有用かもしれません。

```console
$ cda foo
$ pwd
/baz/bar/foo
$ cd /qux
$ cd /quux/qux 
$ cda -
$ pwd
/baz/bar/foo
```

### リストファイル
リストファイルは`~/.cda/lists/*`にテキストファイルとして保存されていて、デフォルトでは`default`という名前のリストを使用しています。`-U`または`--use`でデフォルトで使用するリストファイルを変更することができます。

```console:デフォルトリストをmylistに変更する(存在しない場合は新規作成)
$ cda -U mylist                            # デフォルトリストを変更
Using: /Users/itmst/.cda/lists/mylist
$ cda -L                                   # リストファイルの一覧表示
  default
* mylist
```

`-u`または`--use-temp`で一時的にリストを切り替えることも可能です。

```console:同じfooというエイリアスを別のリストに別のパスで追加
$ cda -a foo /baz/bar/foo                  # デフォルトリストに追加
$ cda -a foo /qux/baz/bar/foo -u mylist    # mylistに追加
$ cda foo -u mylist                        # mylistのfooを参照
$ pwd
/qux/baz/bar/foo
$ cda foo                                  # デフォルトリストのfooを参照
$ pwd
/baz/bar/foo
```


### リストのメンテナンス
**データの健全性チェック**
`-c`または`--check`でリストデータに対して以下の項目のチェックが実行できます。

* 壊れたデータがないか
* パスが存在しているか
* パスはディレクトリか
* フォーマットが正しいか
* cd可能なパーミッションか
* パスが重複したエントリがあるか
* 名前が重複したエントリがあるか
* 名前もパスも重複したエントリがあるか

```console:現在のデフォルトリストの全エイリアスに対してcheckを実行
$ cda -c
```

```console:mylistという名前のリストの全エイリアスに対してcheckを実行
$ cda -c -u mylist
```

特定のエイリアスだけをチェックしたい場合は完全名で指定します。

```console:エイリアスfooとbarだけをチェックする
$ cda -c foo bar
```

**異常データのクリーン**
`-C`または`--clean`で以下の処理を実行します。

|状態|処理|補足|
|:-:|:-:|:-:|
|データが壊れている|<font color="Red">削除</font>|名前とパスの組データではない<br />ユーザの手動編集時のミス|
|パスが存在しない|<font color="Red">削除</font>|-|
|ディレクトリではない|<font color="Red">削除</font>|-|
|cd不可なパーミッション|何もしない|-|
|フォーマットが正しくない|再フォーマット|CDA_ALIAS_MAX_LENを変更した場合など|
|パスの重複|何もしない|動作上は問題なし|
|名前の重複|何もしない(できない)|ユーザの手動編集時のミス|
|名前もパスも重複|マージ|ユーザの手動編集時のミス|

意図しないエイリアスの削除を避けるために、先に`-c`または`--check`で処理の対象と内容を確認することを推奨します。

```console:現在のデフォルトリストの全エイリアスに対してcleanを実行
$ cda -C
```

```console:mylistという名前のリストの全エイリアスに対してcleanを実行
$ cda -C -u mylist
```

特定のエイリアスだけをクリーンしたい場合は完全名で指定します。

```console:エイリアスfooとbarだけをクリーンする
$ cda -C foo bar
```

### パイプ入力
パイプ入力をサポートしています。
ただし**パイプ経由の入力で実際のディレクトリ移動が可能なのはZshのみ**です。

```console:エイリアスfooのパスにcdする(Zshでのみ動作)
% echo foo | cda
```

```console:Bashでもカレントシェルで実行する必要のないものは機能する
$ printf -- "%s\n" -a foo "/baz bar/foo" | cda  # エイリアスfooを追加
$ echo foo | cda -p                             # エイリアスfooのパスを表示
/baz bar/foo
```

### サブディレクトリモード
エイリアス名ではなくディレクトリパスを指定すると、そのサブディレクトリを外部インタラクティブフィルタで絞り込んで`cd`できます。サブディレクトリには番号が振られるので番号での絞り込みも可能です。

```console:サブディレクトリに番号を振って外部フィルタに渡す
$ cda /path/to/langs
QUERY>                                       (1/7) [1/1]
:0       /path/to/langs    # カレントディレクトリ
:1       ..
:2       অসমীয়া 
:3       Հայերեն
:4       한국어
:5       عربي
:6       English
:7       日本語
```


サブディレクトリモードでは一番上のフルパスで表示されているカレントディレクトリを選択し、パスを確定させるまで再帰的に呼び出されます。

```console:-v,--verboseでフィルタによる再帰選択結果を表示
$ cda / -v
7                /home
2                /home/itmst
4                /home/itmst/.cda
2                /home/itmst/.cda/lists
0                /home/itmst/.cda/lists/.
$ pwd
/home/itmst/.cda/lists
```
サブディレクトリ番号を第二引数または`-n`または`--number`に渡すと選択を自動化できます。
カンマ区切りで複数の番号を指定でき、深い階層までフィルタを起動することなく選択を自動化できます。  

```console:-n,--numberでサブディレクトリ選択を自動化
$ cda / -n 7,2,4,2,0
$ pwd
/home/itmst/.cda/lists
```
`-n 7,2,4,2,0`の最後の`0`がない場合は`/home/itmst/.cda/lists`でフィルタが起動した状態になります。

パスではなくエイリアス名を渡した場合も`-s`または`--subdir`オプションを使用するとフィルタコマンドを利用したサブディレクトリモードで実行できます。この場合エイリアスパス下のサブディレクトリが対象になります。

```console:エイリアスfooのパス下のサブディレクトリのリストを外部フィルタに渡す
$ cda foo -s
:0       /path/to/foo    # カレントディレクトリ
:1       ..
:2       subdir_1
:3       subdir_2
:4       subdir_3
```

```console:-nでサブディレクトリ番号の指定も可能
$ cda foo -sn 4,0
$ pwd
/path/to/foo/subdir_3
```

`-a` `--add`によるエイリアス追加時のパス指定にもサブディレクトリモードを利用できます。

```console:新規追加するエリアスfooのパスをサブディレクトリモードで選択する
$ cda -a foo -s
```

```console:サブディレクトリモードの起点パスを指定する場合
$ cda -a foo -s /path/to
```

### ファイルマネージャで開く
`-o`または`--open`オプションでエイリアスパスを`open`または`xdg-open`コマンドに渡します。これにより通常、Macなら`Finder`が、Linuxデスクトップ環境ならデフォルトのファイルマネージャが起動します。

```console:エイリアスfooのパスをファイルマネージャで開く
$ cda foo -o
```

`CDA_CMD_OPEN`変数でデフォルトのオープンコマンドが設定でき、`-O`または`--cmd-open`でこの値を一時的にオーバーライドできます。

```console:エイリアスfooのパスをrangerで開く
$ cda foo -oO ranger
```

外部GUIアプリケーションを開く場合、`setsid`コマンドを経由して端末とは別のセッションで起動した方が都合がいいことが多いかもしれません。別セッションにすることで実行後すぐに制御が端末に戻ります。この動作は`xdg-open`や`open`で開いた場合と同じです。

```console:エイリアスfooのパスをsetsidを経由してThunarで開く
$ cda foo -oO 'setsid thunar'
```
`setsid`は最近の`macOS`ではコマンドとしては提供されていないので必要なら[tzvetkoff/setsid-macosx](https://github.com/tzvetkoff/setsid-macosx)を利用できます。


# 設定変数
## 仕様
デフォルトでは変数は以下のファイルで設定できます(`CDA_DATA_ROOT`で変更可能)。

```bash:設定ファイルのパス
~/.cda/config
```

コマンドを指定する変数はコロン区切りで複数のコマンド候補を指定できます。

```bash:コロン区切りで複数のコマンド候補を指定
CMD_VAR=cmd1:cmd2:cmd3
```

左から順に利用可能か試行します。このためコマンド検索のオーバーヘッドが発生するので利用可能なコマンドが分かっている場合はそれだけを指定することを推奨します。

コマンドをフルパスで指定したい場合や、何かオプションを付けたい場合は`'"..."'`という書式で設定して下さい。

```bash:フルパス指定やオプションの記述例
CMD_VAR='"/the path/to/cmd" -a --long="a b"'
```

真偽値として以下が有効な値です。大文字小文字は問いません。

|真偽|有効な値|
|:-:|---|
|真|true, yes, y, enabled, enable, on|
|偽|false, no, n, disabled, disable, off|

## 変数
**CDA_DATA_ROOT**
ユーザデータの保存ディレクトリを指定します。
この変数の役割上**`source cda.sh`する前に設定**してある必要があるので、この変数に限り`~/.bashrc`または`~/.zshrc`に追記しなければいけません。

```bash:デフォルト値
CDA_DATA_ROOT=$HOME/.cda
```

**CDA_EXEC_NAME**
cdaの実行コマンド名を指定します。
より少ないタイプ数で実行したい場合や、名前の衝突を避けたい場合などに有用です。aliasコマンドで別名を設定するのに似ていますが、シェル関数として定義されることや、Bash-Completionの設定にも使用されるなどの違いがあります。

```bash:デフォルト値
CDA_EXEC_NAME=cda
```

**CDA_BASH_COMPLETION**
`Bash-Completion`を使用するかどうかを真偽値で指定します。

```bash:デフォルト値
CDA_BASH_COMPLETION=true
```

**CDA_MATCH_EXACT_ORDER**
[内部簡易フィルタ](#内部簡易フィルタ)に渡された2番目以降の検索ワードをその順番通りにマッチさせるかどうかを真偽値で指定します。

```bash:デフォルト値
CDA_MATCH_EXACT_ORDER=true
```


**CDA_CMD_FILTER**
複数のエイリアスの候補を絞り込むためのインタラクティブフィルタコマンドを指定します。
この値は`-F`または`--cmd-filter`で一時的にオーバーライドできます。

```bash:デフォルト値
CDA_CMD_FILTER=peco:percol:fzf:fzy
```

**CDA_CMD_OPEN**
`-o`または`--open`でディレクトリパスを開くコマンドを指定します。 
この値は`-O`または`--cmd-open`で一時的にオーバーライドできます。

```bash:デフォルト値
CDA_CMD_OPEN=xdg-open:open:ranger:mc
```

**CDA_CMD_EDITOR**
`-e`または`--edit`でのリストファイル編集時や、`--config`での設定ファイル編集時に使用するテキストエディタを指定します。
この値は`-E`または`--cmd-editor`で一時的にオーバーライドできます。

```bash:デフォルト値
CDA_CMD_EDITOR=vim:vi:nano:emacs
```

**CDA_FILTER_LINE_PREFIX**
外部フィルタコマンドに渡すリストの各行の先頭に`:`(コロン)を付加するかどうかを真偽値で指定します。
行頭マッチング機能のないフィルタコマンドでも絞込時に`:`から入力することでエイリアス名の先頭に簡単にマッチさせることができます。

```bash:デフォルト値
CDA_FILTER_LINE_PREFIX=true
```

**CDA_BUILTIN_CD**
`cd`を実行する際に`builtin cd`のように明示的に組み込みの`cd`コマンドを実行するかどうかを真偽値で指定します。外部`cd`拡張ツールの影響を受けたくない、または影響を与えたくない場合は有効にして下さい。
`-B`または`--builtin-cd`で一時的に有効にすることもできます。

```bash:デフォルト値
CDA_BUILTIN_CD=false
```

**CDA_COLOR_MODE**
エラーメッセージやエイリアスリストなどの出力テキストを着色するかどうかを判断するモードを指定します。
この値は`--color`で一時的にオーバーライドできます。

|モード|解説|
|:-:|---|
|**auto**|メッセージ出力の接続先がTTY(端末)か否かによってメッセージを着色するか自動で判断します。 たとえば出力先がパイプの場合は着色しません。|
|**never**|常に着色しません。|
|**always**|常に着色します。|

```bash:デフォルト値
CDA_COLOR_MODE=auto
```

**CDA_LIST_HIGHLIGHT_COLOR**
リストのハイライト色をANSIカラーコードの値部分で指定します。
たとえば`\033[4;1;32m`というカラーコードの場合は`4;1;32`だけを指定します。セミコロンを含むので必ずクォートが必要です。

```bash:デフォルト値
CDA_LIST_HIGHLIGHT_COLOR="0;0;32"
```

**CDA_ALIAS_MAX_LEN**
エイリアス名の最大長を自然数で指定します。
変更後に`-C`または`--clean`を実行すると新しい値を使ってリストを再フォーマットできます。

```bash:デフォルト値
CDA_ALIAS_MAX_LEN=16
```


# ライセンス
MIT


随時編集・追記します