【CLIファイルファインダー】yazi

/darallium/です！ご覧いただきありがとうございます． 😊

これから1週間をかけて「CLI初心者でも感動するような，それでいて汎用性・拡張性の高いCLIツール」を以下の通り紹介していくのでよろしければ見ていってください 🙇

# yazi
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196553/0b364dff-6187-3fb0-f102-a9ec0016fa91.png)

yaziとは，viっぽい操作で使えるCLIファイルファインダーである．カレントディレクトリを飛び回れて非常に楽しい．

MacOS/Linux/Windowsすべてに対応しているため，dotfilesで管理するとどこでも同じ環境が手に入るのが魅力的だ．

しかも，Rustで作られているためデフォルトのファイルファインダよりも高速に動作する．imgcatとかで画像プレビューしてみたり，tmuxと連携できたり，fzfで検索してみたり云々できてしまうため，GUIのファイルファインダを置き換えることができるのだ．

# installation

## dependencies

- ffmpegthumbnailer
- unarchiver
- jq
- poppler
- fd
- ripgrep
- fzf
- [windows]git
    - 正確にはgit for windowsのfileコマンド
- nerdfont
    - おすすめはFiraCode NF
## mac

```bash
$ brew install yazi ffmpegthumbnailer unar jq poppler fd ripgrep fzf
```

## windows

[公式リポジトリ](https://github.com/sxyazi/yazi/releases)からダウンロードしてインストーラを実行

若しくは

```bash
$  scoop install yazi unar jq poppler fd ripgrep fzf zoxide
```
ただし，注意点としてyaziはscoopから入れると若干古いです．最新の機能を使いたい場合は公式から落としてくるようにしてください．
## linux

git cloneして`cargo build --release`

若しくは[公式リポジトリ](https://github.com/sxyazi/yazi/releases)からダウンロード

### [optional]zsh/bash

以下を.zshrc/.bashrcに入れるとディレクトリ変更が気持ちよくなる．yaziを閉じた時にそのカレントディレクトリへ移動するのだ．

```bash
function ya() {
	tmp="$(mktemp -t "yazi-cwd.XXXXX")"
	yazi --cwd-file="$tmp"
	if cwd="$(cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
		cd -- "$cwd"
	fi
	rm -f -- "$tmp"
}
```

# できること

1. どこでも動く(linux mac win)
2. 自由にテーマをいじれる
3. 自由にキーバインドをいじれる

# チュートリアル

## 移動・検索

- h/j/k/l: :arrow_left: :arrow_up: :arrow_down: :arrow_right: の方向にカレントディレクトリが動く．
- gh: ~/に移動
- H/L: 履歴的にundo/redoの方向でカレントディレクトリを移動
- q/<Esc>: 閉じる
- /: 全文検索
- Z: fzfを起動
- 「;」 : 一時的にシェルコマンドを実行；裏でgit操作など

## ファイル操作

- v: ヴィジュアルモードに移行して複数選択してみる
- y: コピー，x: 切り取り, p: 貼り付け
- d: 削除
- r: リネーム
- a: フォルダ作成
- o/\<Enter\>: ファイルを"開く"
- O/\<C-Enter\>: 方法を指定してファイルを開く
    - reveal: そのファイルの親フォルダを開く
    - open: 既定の方法で開く
- -: シンボリックリンクを作成

## 情報取得

- a: ファイルorディレクトリの作成
- c+[c/d/f/n]: 絶対パス/親のパス/ファイル名/ファイル名拡張子抜き をクリップボードにコピー
- d: 選択しているファイルを削除
- ,+[a/c/m/n/s]: 辞書/作成日/編集日/ナチュラル/大きさ で表示ファイルをソート．2文字目を大文字で指定すると逆順になる．

# テーマを導入してみる

今回のチュートリアルでは，筆者の大好きなcatppuccin mochaテーマを導入する．

linuxユーザの場合は`~/.config/yazi/`,windowsユーザの場合は`%appdata%\yazi\config`に設定ファイルがある．これを編集することでカラースキームやらキーバインドをいじることができる．

しかし，これらのフォルダは存在しない．yaziはデフォルトコンフィグを持たないのである．全ての編集を加える前にデフォルトを用意する必要がある．デフォルトの設定をコンフィグファイルに書き起こしたものが[公式リポジトリ](https://github.com/sxyazi/yazi/releases)にあるので，以下のパスに存在するすべてのファイルをダウンロードしよう．

 **[yazi](https://github.com/sxyazi/yazi/tree/main)**/[yazi-config](https://github.com/sxyazi/yazi/tree/main/yazi-config)/****preset****/

## 既存テーマの導入

以下のリポジトリにcatppuccinのテーマがあるのでありがたく頂戴することにする．

[GitHub - yazi-rs/themes: Some Yazi themes maintained by community.](https://github.com/yazi-rs/themes)

 **[themes](https://github.com/yazi-rs/themes/tree/main)** /[catppuccin](https://github.com/yazi-rs/themes/tree/main/catppuccin)/****mocha.toml**** に設定ファイルが落ちている．今回はデフォルト設定とマージすることを目標としよう．

始めに，2つのファイルの相違点を見てみよう．

<details><summary>diff</summary><div>    
以下はdiffコマンドの結果．

```diff

@@ -3,36 +3,32 @@
 # : Manager {{{

 [manager]
-cwd = { fg = "cyan" }
+cwd = { fg = "#94e2d5" }

 # Hovered
-hovered = { fg = "black", bg = "lightblue" }
+hovered = { fg = "#1e1e2e", bg = "#89b4fa" }
 preview_hovered = { underline = true }

 # Find
-find_keyword  = { fg = "yellow", italic = true }
-find_position = { fg = "magenta", bg = "reset", italic = true }
+find_keyword  = { fg = "#f9e2af", italic = true }
+find_position = { fg = "#f5c2e7", bg = "reset", italic = true }

 # Marker
-marker_selected = { fg = "lightgreen",  bg = "lightgreen" }
-marker_copied   = { fg = "lightyellow", bg = "lightyellow" }
-marker_cut  = { fg = "lightred",bg = "lightred" }
+marker_selected = { fg = "#a6e3a1", bg = "#a6e3a1" }
+marker_copied   = { fg = "#f9e2af", bg = "#f9e2af" }
+marker_cut  = { fg = "#f38ba8", bg = "#f38ba8" }

 # Tab
-tab_active   = { fg = "black", bg = "lightblue" }
-tab_inactive = { fg = "white", bg = "darkgray" }
+tab_active   = { fg = "#1e1e2e", bg = "#89b4fa" }
+tab_inactive = { fg = "#cdd6f4", bg = "#45475a" }
 tab_width= 1

 # Border
 border_symbol = "笏・
-border_style  = { fg = "gray" }
+border_style  = { fg = "#7f849c" }

-# Offset
-folder_offset  = [ 1, 0, 1, 0 ]
-preview_offset = [ 1, 1, 1, 1 ]
-
 # Highlighting
-syntect_theme = ""
+syntect_theme = "~/.config/bat/themes/Catppuccin-mocha.tmTheme"

 # : }}}

@@ -42,42 +38,32 @@
 [status]
 separator_open  = "薰ｶ"
 separator_close = "薰ｴ"
-separator_style = { fg = "darkgray", bg = "darkgray" }
+separator_style = { fg = "#45475a", bg = "#45475a" }

 # Mode
-mode_normal = { fg = "black", bg = "lightblue", bold = true }
-mode_select = { fg = "black", bg = "lightgreen", bold = true }
-mode_unset  = { fg = "black", bg = "lightmagenta", bold = true }
+mode_normal = { fg = "#1e1e2e", bg = "#89b4fa", bold = true }
+mode_select = { fg = "#1e1e2e", bg = "#a6e3a1", bold = true }
+mode_unset  = { fg = "#1e1e2e", bg = "#f2cdcd", bold = true }

 # Progress
-progress_label  = { bold = true }
-progress_normal = { fg = "blue", bg = "black" }
-progress_error  = { fg = "red", bg = "black" }
+progress_label  = { fg = "#ffffff", bold = true }
+progress_normal = { fg = "#89b4fa", bg = "#45475a" }
+progress_error  = { fg = "#f38ba8", bg = "#45475a" }

 # Permissions
-permissions_t = { fg = "lightgreen" }
-permissions_r = { fg = "lightyellow" }
-permissions_w = { fg = "lightred" }
-permissions_x = { fg = "lightcyan" }
-permissions_s = { fg = "darkgray" }
+permissions_t = { fg = "#89b4fa" }
+permissions_r = { fg = "#f9e2af" }
+permissions_w = { fg = "#f38ba8" }
+permissions_x = { fg = "#a6e3a1" }
+permissions_s = { fg = "#7f849c" }

 # : }}}

-# : Select {{{
-
-[select]
-border   = { fg = "blue" }
-active   = { fg = "magenta" }
-inactive = {}
-
-# : }}}
-
-
 # : Input {{{

 [input]
-border   = { fg = "blue" }
+border   = { fg = "#89b4fa" }
 title= {}
 value= {}
 selected = { reversed = true }
@@ -85,25 +71,20 @@
 # : }}}

-# : Completion {{{
+# : Select {{{

-[completion]
-border   = { fg = "blue" }
-active   = { bg = "darkgray" }
+[select]
+border   = { fg = "#89b4fa" }
+active   = { fg = "#f5c2e7" }
 inactive = {}

-# Icons
-icon_file= "・・
-icon_folder  = "・・
-icon_command = "・・
-
 # : }}}

 # : Tasks {{{

 [tasks]
-border  = { fg = "blue" }
+border  = { fg = "#89b4fa" }
 title   = {}
 hovered = { underline = true }

@@ -113,12 +94,12 @@
 # : Which {{{

 [which]
-mask= { bg = "black" }
-cand= { fg = "lightcyan" }
-rest= { fg = "darkgray" }
-desc= { fg = "magenta" }
+mask= { bg = "#313244" }
+cand= { fg = "#94e2d5" }
+rest= { fg = "#9399b2" }
+desc= { fg = "#f5c2e7" }
 separator   = " 鈼・"
-separator_style = { fg = "darkgray" }
+separator_style = { fg = "#585b70" }

 # : }}}

@@ -126,11 +107,11 @@
 # : Help {{{

 [help]
-on  = { fg = "magenta" }
-exec= { fg = "cyan" }
-desc= { fg = "gray" }
-hovered = { bg = "darkgray", bold = true }
-footer  = { fg = "black", bg = "white" }
+on  = { fg = "#f5c2e7" }
+exec= { fg = "#94e2d5" }
+desc= { fg = "#9399b2" }
+hovered = { bg = "#585b70", bold = true }
+footer  = { fg = "#45475a", bg = "#cdd6f4" }

 # : }}}

@@ -141,173 +122,24 @@

 rules = [
# Images
-   { mime = "image/*", fg = "cyan" },
+   { mime = "image/*", fg = "#94e2d5" },

# Videos
-   { mime = "video/*", fg = "yellow" },
-   { mime = "audio/*", fg = "yellow" },
+   { mime = "video/*", fg = "#f9e2af" },
+   { mime = "audio/*", fg = "#f9e2af" },

# Archives
-   { mime = "application/zip", fg = "magenta" },
-   { mime = "application/gzip",fg = "magenta" },
-   { mime = "application/x-tar",   fg = "magenta" },
-   { mime = "application/x-bzip",  fg = "magenta" },
-   { mime = "application/x-bzip2", fg = "magenta" },
-   { mime = "application/x-7z-compressed", fg = "magenta" },
-   { mime = "application/x-rar",   fg = "magenta" },
-   { mime = "application/xz",  fg = "magenta" },
+   { mime = "application/zip", fg = "#f5c2e7" },
+   { mime = "application/gzip",fg = "#f5c2e7" },
+   { mime = "application/x-tar",   fg = "#f5c2e7" },
+   { mime = "application/x-bzip",  fg = "#f5c2e7" },
+   { mime = "application/x-bzip2", fg = "#f5c2e7" },
+   { mime = "application/x-7z-compressed", fg = "#f5c2e7" },
+   { mime = "application/x-rar",   fg = "#f5c2e7" },

-   # Documents
-   { mime = "application/doc",   fg = "green" },
-   { mime = "application/pdf",   fg = "green" },
-   { mime = "application/rtf",   fg = "green" },
-   { mime = "application/vnd.*", fg = "green" },
-
# Fallback
-   # { name = "*", fg = "white" },
-   { name = "*/", fg = "blue" }
+   { name = "*", fg = "#cdd6f4" },
+   { name = "*/", fg = "#89b4fa" }
 ]

-[icons]
-
-"Desktop/" = "・・
-"Documents/"   = "・・
-"Downloads/"   = "・・
   ...
```

</div></details>

大枠で見ると項目の有無があることがわかる．いかに列挙してみたので眺めてみてほしい．

- \[manager]
    - Offsetの有無
    - Highlightingの指定；batコマンドと共通のsyntax highlightを利用している．入れたほうが気持ちよいだろうから今回のチュートリアルでは導入している前提で進める．入れていない場合は[公式リポジトリ](https://github.com/catppuccin/bat)からダウンロードしよう．windowsユーザの場合はパスを適当に書き換えるとよい．
- \[completion]の有無
- \[icons]の有無

これらをデフォルトから引用しながらmocha.tomlを書き換えよう．そしてファイル名をtheme.tomlに変更すれば完成である．

# コンフィグをいじってみる

例のごとく **[yazi](https://github.com/sxyazi/yazi/tree/main)**/[yazi-config](https://github.com/sxyazi/yazi/tree/main/yazi-config) /[preset](https://github.com/sxyazi/yazi/tree/main/yazi-config/preset)/****theme.toml****を編集して遊んでみる．大枠としては以下のようになっている．特徴的な設定項目の設定方法も記述する．

- \[manager]: yazi全体でのデフォルトソートなど汎用的な設定
- \[preview]: 右側のプレビューの幅やキャッシュの位置など
- \[opener]: [open]で使う命令をここに記述する．云わばaliasのようなものだと思ってもらってよい．
    - 選択されたファイル名は以下のようにして取得できる
    
    |  | windows | unix |
    | --- | --- | --- |
    | 選択されたもののi番目 | $i | %i |
    | 選択されたもの全部 | $@ | %* |
    - block[T/F]: yaziからopenしたときにyaziを上塗りして表示するか
    - orphan[T/F]: yaziが死んだときに同時に殺すか(sub proc化するか)
    - for[”unix”/”macos”/”linux”/”windows”]:ターゲットOS
- \[open]: ファイルを”open”する規則．[opener]で定義した方法で起動できる．
    - name[strings]: ファイル名をglob exprでマッチさせて指定できる．*.extで拡張子を指定してみたり，src/ts/**でディレクトリを指定してみたり
    - mime[strings]: application/text的なことで記述できる．
    - use[strings]: [opener]上の名前を指定する
- \[input]: ファイル名などの入力領域の位置をいじれる．
- \[select]: same as the input.(原文ママ)

筆者も試しに設定してみたので一部を掲載する．

```diff
@@ -7,8 +7,8 @@
-linemode       = "none"
-show_hidden    = false
+linemode       = "natural"
+show_hidden    = true

 [preview]
@@ -19,7 +19,8 @@
 [opener]
 edit = [
        { exec = '$EDITOR "$@"', block = true,  for = "unix" },
-       { exec = 'code "%*"',    orphan = true, for = "windows" },
+#      { exec = 'code "%*"',    orphan = true, for = "windows" },
+       { exec = 'nvim "%*"',    block = true, for = "windows" },
 ]
 open = [
        { exec = 'xdg-open "$@"',             desc = "Open", for = "linux" },
@@ -33,7 +34,7 @@
 ]
 extract = [
        { exec = 'unar "$1"', desc = "Extract here", for = "unix" },
-       { exec = 'unar "%1"', desc = "Extract here", for = "windows" },
+       { exec = 'start "%1"', desc = "Extract /UNZIP/", for = "windows" },
 ]
 play = [
        { exec = 'mpv "$@"', orphan = true, for = "unix" },
```

# キーバインドをいじってみる

例のごとく **[yazi](https://github.com/sxyazi/yazi/tree/main)**/[yazi-config](https://github.com/sxyazi/yazi/tree/main/yazi-config) /[preset](https://github.com/sxyazi/yazi/tree/main/yazi-config/preset)/****keymap.toml****を編集して遊んでみる．大枠としては以下のようになっている．

各画面に対して幾つかコマンドが用意されていて，それらを実行するキーバインドを割り当てることができる．詳細については紹介しないので[公式ドキュメント](https://yazi-rs.github.io/docs/configuration/keymap#tasks-1)を見てほしい． 

- \[manager]: yaziの開いたときの画面の設定
- \[tasks]: 今回は紹介しないが，taskを動かす機能があり，そこでの設定．

```toml
[対象の画面]
keymap = [
	{on = [バインドするキーを列挙，escなどは"<Esc>"とするなどvimに準拠], exec="command", desc = "表示される説明"},

```

- \[input]: 文字入力画面の上でのキーバインド．

# あとがき
yaziは既存のGUIファイルファインダ―で出来ることを包括的にカバーする．Windowsであれば「右クリックで...」と思うことを，CLI上では「: \<commands>」で操作できる．右クリックでは単一スニペットとして，決まりきった操作をすることしかできないがyaziではコマンドラインオプションを設定するなど，自分好みの操作へ広げることができるだろう．

また，yaziは「CLIですべてを完結させる」喜びを感じさせるデザインになっている．CLI上でファイルを探し，CLI上でファイルを操作し...
CLI初心者の諸君は「大量のウィンドウが開いてだるい」と思わなくなっただろうし，CLIに染まり切った皆様方は「lfやranger,nnnより使いやすい」と思うかもしれない．

最近のトレンドとしてCLIツールをRust製に置き換えるというものがある．今回はRust製で筆者のお気に入りツールを紹介した．読者の皆様方も良ければ環境ガチャガチャの喜びを楽しんでほしい．

ここまでお読み頂きありがとうございました。


# references

https://yazi-rs.github.io/