爆速 Zsh フレームワーク Zim のインストールとチートシート

![zim-demonstration.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67627/e974351d-f92b-91c3-2c93-b0e2a475b914.gif)
この記事は朝日新聞社 Advent Calendar 2022 の19日目の記事です。
本日は、朝デジ事業センターの土田が、爆速に起動する Zsh フレームワークである Zim を macOS にインストールする方法とそのチートシートについてまとめました。

本稿ではさくっとインストールして、チートシートを見ながらさくっと使い始めることをゴールにしています。設定の詳細については、[Zim フレームワークで Zsh 環境を構築する](https://takuyatsuchida.com/build-zsh-environment-by-zim-framework/)を参考にしていただけたらと思います。

# Zim とは？

[Zim](https://zimfw.sh/) はモジュール方式・カスタマイズ可能・爆速な Zsh フレームワークです。頻繁に立ち上げるターミナルのことを考えると、ほかの Zsh フレームワークと比較して遜色ない機能を備えながらも、シェルの起動が「爆速」であることが重要になってきます。[zimfw/zimfw](https://github.com/zimfw/zimfw) に掲載されている下記のベンチマーク結果によると、Zim は主流の [Oh My Zsh](https://ohmyz.sh) や [Prezto](https://github.com/sorin-ionescu/prezto) と比較しても高速なようです。
![zsh-framework-benchmark.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67627/18ca4ecf-2e37-bb3c-8d00-856387add45a.png)
また、主要な Zsh プラグインが Zim モジュールとして提供されており、インストール直後からイケてるデフォルト設定になっています。なので、まずはインストールしてみて、そのまま使ってみて、ちょっとチートシートを眺めてみて、不満があるところを [Zim のドキュメント](https://zimfw.sh/docs/)や [Zsh の拙著ブログ記事](https://takuyatsuchida.com/build-zsh-environment-by-zim-framework/)、[Zsh の書籍](https://gihyo.jp/book/2009/978-4-7741-3864-0)などを読みながらカスタマイズしていくという形でステップアップしやすいのも Zim のよいところです。

# Zim をインストールする

まず、Zim をインストールする前に下記コマンドで既存の .zshrc ファイルを .zshrc.old ファイルとしてバックアップしておきましょう。

```shell-session
% cp ~/.zshrc ~/.zshrc.old
```

その上で、Zim を下記コマンドでインストールします。

```shell-session
% curl -fsSL https://raw.githubusercontent.com/zimfw/install/master/install.zsh | zsh
```

これでターミナルを再起動すれば、それなりにイケてる Zsh 環境ができあがります。本稿冒頭の GIF アニメーションのような見た目を期待する場合は、下記の追加インストールと設定をします。設定の詳細は [Zim フレームワークで Zsh 環境を構築する](https://takuyatsuchida.com/build-zsh-environment-by-zim-framework/)で解説しています。（なお、カラーも合わせたい場合は、[Iceberg for macOS](https://cocopon.github.io/iceberg.vim/#macosTerminalApp) をターミナルのデフォルトプロファイルにしてください。）

いくつかのコマンドとフォントを Homebrew でインストールします。

```shell-session
% brew install bat exa fd fzf safe-rm
% $(brew --prefix)/opt/fzf/install --key-bindings --completion --update-rc --no-bash --no-fish
% brew tap homebrew/cask-fonts
% brew install font-sf-mono-for-powerline
```

インストールするコマンドをすこし説明しておきます。[exa](https://the.exa.website) コマンドは ls コマンドを下記のようなイケてるコマンドにしてくれます。
![zim-exa-module.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67627/ab46adc0-b58d-d641-34d1-a85e1ef47879.png)
[bat](https://github.com/sharkdp/bat#readme) コマンド、[fd](https://github.com/sharkdp/fd#readme) コマンド、[fzf](https://github.com/junegunn/fzf#readme) コマンドは、下記 GIF アニメーションのような機能を実現するためにインストールしています。
![fzf-demonstration.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67627/15c1ead3-d64b-7e82-490d-0d3c3a0c476b.gif)
これは、コマンドの途中で ** と入力した上で Tab キーを押下したり、Control + T キーを押下したりするとインクリメンタル検索が起動するという例です。また、インクリメンタル検索を起動するショートカットキーの一覧は下記のとおりです。

| キー			| 検索対象
|---------------|-----------------------
| Control + T	| ファイル（プレビュー付き） 
| Control + R	| ヒストリ
| Esc + C		| ディレクトリ

[safe-rm](https://launchpad.net/safe-rm) コマンドは、rm をすこし安全にしたコマンドです。[font-sf-mono-for-powerline](https://github.com/Twixes/SF-Mono-Powerline#readme) はイケてる [eriner](https://github.com/zimfw/eriner#readme) テーマを利用する上で必要になるフォントです。

このフォントを利用するためには、ターミナルのプロファイルから SF Mono Powerline フォントを設定します。なお、私はデフォルトプロファイルとして [Iceberg](https://cocopon.github.io/iceberg.vim/) を利用していますが、ご利用のデフォルトプロファイル（Basic や Pro など）でフォントを設定するようにしてください。
![terminal-profiles.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67627/d74c4c93-16f4-2920-8edb-f4aba1b38915.png)
あとは、.zshrc ファイルと .zimrc ファイルを下記のように修正します。必要に応じて、既存の .zshrc ファイルをバックアップした .zshrc.old ファイルにある設定も追加してください。

```zsh:.zshrc
fpath+=$(brew --prefix)/share/zsh/site-functions
WORDCHARS=${WORDCHARS//[\/]}

zstyle ':zim:input' double-dot-expand yes

[[ ~/.zimrc -nt ~/.zim/init.zsh ]] && source ~/.zim/zimfw.zsh init -q
source ~/.fzf.zsh
source ~/.zim/init.zsh

bindkey $terminfo[kcuu1] history-substring-search-up
bindkey $terminfo[kcud1] history-substring-search-down
bindkey -M emacs '^P' history-substring-search-up
bindkey -M emacs '^N' history-substring-search-down
```

```zsh:.zimrc
zmodule archive
zmodule environment
zmodule eriner
zmodule fzf
zmodule git
zmodule git-info
zmodule homebrew
zmodule input
zmodule utility
zmodule exa # sourced after utility
zmodule zsh-users/zsh-completions --fpath src
zmodule completion # sourced after all modules that add completion definitions
zmodule zsh-users/zsh-syntax-highlighting # sourced after completion
zmodule zsh-users/zsh-history-substring-search # sourced after zsh-syntax-highlighting
zmodule zsh-users/zsh-autosuggestions # sourced last
```

これでターミナルを再起動すれば、かなりイケてる Zsh 環境のできあがりです。便利な使い方を知りたいよという方は、次節に掲載しているチートシートを眺めながら様々な操作を試してみてください。

# Zim チートシート

[Zim Docs](https://zimfw.sh/docs/) にある [Cheatsheet](https://zimfw.sh/docs/cheatsheet/) の一部を翻訳しています。ライセンスは「Website by [Michael Thomas](https://github.com/michaelhthomas). This website's content is licensed [CC BY NC SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/).」とページ末尾にある記載に準拠します。

## 式

### ヒストリ展開

| 式	| 例		| 説明
|-------|-----------|-----
| !!	| sudo !!	| 最後のコマンドライン
| !*	| vim !*	| 最後のコマンドの引数
| !^	| vim !^	| 最後のコマンドの最初の引数
| !$	| vim !$	| 最後のコマンドの最後の引数
| !ls	| sudo !ls	| ls で始まる最後のコマンドライン
| !ls:*	| rm !ls:*	| ls で始まる最後のコマンドの引数

### Glob 修飾子

| 式		| 例		| 説明
|-----------|-----------|-----
| *(.)		| ls *(.)	| 通常ファイル
| *(/)		| ls *(/)	| ディレクトリ
| *(m0)		| ls *(m0)	| 本日最終更新
| *(m-4)	| ls *(m-4)	| 4日以内最終更新

## プロセス置換

| 式			| 例													| 説明
|---------------|-------------------------------------------------------|-----
| <(COMMAND)	| tar xzf <(curl https://start.spring.io/starter.tgz)	| コマンド出力を読取専用の名前付きパイプ (FIFO) にして引数を置換する
| =(COMMAND)	| unzip =(curl https://start.spring.io/starter.zip)		| コマンド出力を書込可能なファイルにして引数を置換する

※ 上記のコマンド例を実行する場合は、新規作成したディレクトリ内で実行すると後片付けが楽です。

## タブ補完

下記のようなコマンドで、オプションの説明も充実したタブ補完ができます。

* `ls -`(tab)
* `cap `(tab)
* `rake `(tab)
* `ssh `(tab)
* `sudo umount `(tab)
* `kill `(tab)
* `unrar `(tab)

## ls

* `ls` ディレクトリが最初になるように（GNU のみ）色付きで一覧表示する（以下のすべてのエイリアスに適用される）
* `ll` 詳細形式かつ人間が読みやすいサイズ表記で一覧表示する（以下のすべてのエイリアスに適用される）
* `l` すべてのファイルを一覧表示する
* `lm` ページャーを使用してすべてのファイルを一覧表示する
* `lr` 再帰的に一覧表示する
* `lx` 拡張子でソートして一覧表示する（GNU のみ）
* `lk` ファイルサイズでソートして一覧表示する
* `lt` 更新日時でソートして一覧表示する
* `lc` 作成日時でソートして一覧表示する

## ユーティリティ

* `get` 指定された URL を aria2c、axel、wget または curl を使用してダウンロードする
* `mkcd` 指定されたディレクトリを作成し、そのディレクトリに移動する
* `mkpw` 指定された文字列長と文字集合からランダムなパスワードを生成する

## アーカイブ

* `archive` ファイルの拡張子に基づいてアーカイブを生成する
* `unarchive` ファイルの拡張子に基づいてアーカイブを展開する
* `lsarchive` ファイルの拡張子に基づいてアーカイブの内容を一覧表示する

## Git

* `G` `git` の短縮コマンド

### ブランチ

* `Gb` ブランチの一覧表示、作成、名前変更、削除を実行する
* `Gbc` 新しいブランチを作成する
* `Gbd` 現行もしくは指定されたブランチの先頭で HEAD をデタッチする
* `Gbl` ブランチとそれらのコミットを一覧表示する
* `GbL` ローカルブランチとリモートブランチ、そしてそれらのコミットを一覧表示する
* `Gbm` ブランチ名を変更する
* `GbM` 新しいブランチ名がすでに存在する場合でも、ブランチの名前を変更する
* `GbR` ブランチ名がすでに存在する場合でも、ブランチをリセットする
* `Gbs` ブランチとそれらのコミットを先祖グラフで表示する
* `GbS` ローカルブランチとリモートブランチ、そしてそれらのコミットを祖先グラフで表示する
* `Gbu` 現行もしくは指定されたブランチのリモート追跡情報を解除する
* `GbG` なくなったリモートブランチを追跡しているすべてのローカルブランチを削除する
* `Gbx` ブランチを削除する
* `GbX` マージ状態に関わらずブランチを削除する

### コミット

* `Gc` リポジトリへの変更を記録する
* `Gca` 修正および削除されたすべてのファイルをコミットする
* `GcA` 修正および削除されたすべてのファイルを対話的にコミットする
* `Gcm` 指定されたメッセージでコミットする
* `Gco` ブランチやパスをワーキングツリーへチェックアウトする
* `GcO` インデックスやツリーから塊を対話的にチェックアウトする
* `Gcf` HEAD と同じログメッセージを再利用して現行ブランチの先頭を修正する
* `GcF` 現行ブランチの先頭を修正する
* `Gcp` 既存のコミットによってもたらされた変更を適用する
* `GcP` 既存のコミットによってもたらされた変更をコミットなしで適用する
* `Gcr` 元に戻すパッチと新しいコミットの記録によって既存のコミットをリバートする
* `GcR` HEAD コミットを除去する
* `Gcs` ブロブやツリー、タグ、コミットなど、ひとつまたは複数のオブジェクトを表示する
* `GcS` GPG 署名付きでコミットする
* `Gcu` 指定されたコミットを使用し fixup メッセージ付きでコミットする
* `GcU` 指定されたコミットを使用し squash メッセージ付きでコミットする
* `Gcv` コミットの GPG 署名を検証する

### コンフリクト

* `GCl` マージされていないファイルを一覧表示する
* `GCa` マージされていないファイルをインデックスに追加する
* `GCe` マージされていないすべてのファイルに対してマージツールを実行する
* `GCo` マージされていないパスについて自分側の変更をチェックアウトする
* `GCO` マージされていないすべてのパスについて自分側の変更をチェックアウトする
* `GCt` マージされていないパスについて相手側の変更をチェックアウトする
* `GCT` マージされていないすべてのパスについて相手側の変更をチェックアウトする

### データ

* `Gd` インデックスとワーキングツリーにあるファイルに関する情報を表示する
* `Gdc` キャッシュされた (cached) ファイルを一覧表示する
* `Gdx` 削除された (deleted) ファイルを一覧表示する
* `Gdm` 修正された (modified) ファイルを一覧表示する
* `Gdu` 追跡されていない (untracked) ファイルを一覧表示する
* `Gdk` 抹消された (killed) ファイルを一覧表示する
* `Gdi` 無視された (ignored) ファイルを一覧表示する

### フェッチ

* `Gf` ほかのリポジトリからオブジェクトや参照をダウンロードする
* `Gfc` リポジトリを新しいディレクトリにクローンする
* `Gfm` ほかのリポジトリやローカルブランチからフェッチしてマージする
* `Gfr` ほかのリポジトリやローカルブランチからフェッチして先頭にリベースする
* `Gfu` 古くなったリモート追跡ブランチを削除し、すべてのリモートをフェッチしてマージする

### Grep

* `Gg` パターンに一致する行を表示する
* `Ggi` 大文字小文字を無視したパターンに一致する行を表示する
* `Ggl` パターンに一致するファイルを一覧表示する
* `GgL` パターンに一致しないファイルを一覧表示する
* `Ggv` パターンに一致しない行を表示する
* `Ggw` 単語境界でパターンに一致する行を表示する

### インデックス

* `Gia` ファイルの内容をインデックスに追加する
* `GiA` ファイルの内容をインデックスに対話的に追加する
* `Giu` 既知の更新されたファイルの内容をインデックスに追加する
* `Gid` インデックスと名前付きコミットの間の行単位の変更差分を表示する
* `GiD` インデックスと名前付きコミットの間の単語単位の変更差分を表示する
* `Gir` 現在の HEAD を指定された状態にリセットする
* `GiR` 現在のインデックスを対話的にリセットする
* `Gix` インデックスからファイルを再帰的に削除する
* `GiX` インデックスからファイルを再帰的かつ強制的に削除する

### ログ

* `Gl` ログを表示する
* `Gls` 統計ログを表示する
* `Gld` 差分ログを表示する
* `Glf` 指定されたファイルの名前変更以前にも継続した差分ログを表示する
* `Glo` 一行ログを表示する
* `GlO` 著者と日付を含む一行ログを表示する
* `Glg` グラフログを表示する
* `GlG` 著者と日付を含むグラフログを表示する
* `Glv` コミットのGPG署名を検証してログを表示する
* `Glc` 各コントリビューターのコミットカウントを降順で表示する
* `Glr` リフログ情報を管理する

### マージ

* `Gm` 2つ以上の開発履歴をマージする
* `Gma` コンフリクトの解消を中止し、マージ前の状態を再構築する
* `Gmc` コンフリクトが解消された後、マージを継続する
* `GmC` コミットせずにマージを実行する
* `GmF` マージをファストフォワードとして解決できる場合でもマージコミットを作成する
* `GmS` マージを実行し、その結果のコミットに GPG 署名する
* `Gmv` マージされる側のブランチの先頭コミットの GPG 署名を検証する
* `Gmt` コンフリクトを解決するためにマージコンフリクト解決ツールを実行する

### プッシュ

* `Gp` 関連するオブジェクトと一緒にリモート参照を更新する
* `Gpf` 安全にプッシュを強制する
* `GpF` プッシュを強制する
* `Gpa` すべてのブランチをプッシュする
* `GpA` すべてのブランチとタグをプッシュする
* `Gpt` すべてのタグをプッシュする
* `Gpc` 現行ブランチをプッシュし、それに対応する上流の参照として origin を追加する
* `Gpp` 現行ブランチを origin から origin へプル＆プッシュする

### リベース

* `Gr` ローカルコミットを更新された上流の先頭へ前方移植する
* `Gra` リベースを中止し、元のブランチをチェックアウトする
* `Grc` コンフリクトが解消された後、リベースを継続する
* `Gri` リベースするコミットの一覧を作成し、エディターを起動する
* `Grs` 現在のパッチをスキップする
* `GrS` リベースし、コミットに GPG 署名する

### リモート

* `GR` 追跡されたリポジトリを管理する
* `GRl` リモート名とその URL を一覧表示する
* `GRa` 新しいリモートを追加する
* `GRx` リモートを削除する
* `GRm` リモートを名前変更する
* `GRu` リモートの更新をフェッチする
* `GRp` 古くなったリモート追跡用ブランチをすべて削除する
* `GRs` 指定されたリモートについての情報を表示する
* `GRS` リモートの URL を変更する

### スタッシュ

* `Gs` ダーティなワーキングディレクトリの変更を保存する
* `Gsa` スタッシュに記録された変更をワーキングディレクトリに適用する
* `Gsx` スタッシュされた状態を削除する
* `GsX` スタッシュされたすべての状態を削除する
* `Gsl` スタッシュされた状態を一覧表示する
* `Gsd` スタッシュとその元の親との間の変更を表示する
* `Gsp` スタッシュ一覧からひとつのスタッシュされた状態を適用してから削除する
* `Gsr` スタッシュされた状態を回復する
* `Gss` 追跡されていないファイルを含むワーキングディレクトリの変更を保存する
* `GsS` ワーキングディレクトリの変更を対話的に保存する
* `Gsw` インデックスを保持したままワーキングディレクトリの変更を保存する
* `Gsu` 適用された変更を元に戻す

### サブモジュール

* `GS` サブモジュールの初期化、更新、検査を実行する
* `GSa` 指定されたリポジトリをサブモジュールとして追加する
* `GSf` チェックアウトされた各サブモジュールでシェルコマンドを評価する
* `GSi` サブモジュールを初期化する
* `GSI` サブモジュールを再帰的に初期化し、クローンする
* `GSl` すべてのサブモジュールのコミットを一覧表示する
* `GSm` サブモジュールを移動する
* `GSs` サブモジュールのリモート URL を .gitmodules で指定された値に同期する
* `GSu` すべてのサブモジュールについて、最新のリモート変更をフェッチし、マージする
* `GSx` サブモジュールを削除する

### タグ

* `Gt` GPG 署名されたタグオブジェクトを作成、一覧表示、削除、検証する
* `Gts` GPG 署名されたタグを作成する
* `Gtv` タグの GPG 署名を検証する
* `Gtx` 指定された名前のタグを削除する

### メインワーキングツリー

* `Gws` ワーキングツリーの状態を簡潔な形式で表示する
* `GwS` ワーキングツリーの状態を表示する
* `Gwd` ワーキングツリーとインデックスの間の行単位の変更差分を表示する
* `GwD` ワーキングツリーとインデックスの間の単語単位の変更差分を表示する
* `Gwr` インデックスや作業ツリーに影響を与えずに、現在の HEAD を指定された状態にリセットする
* `GwR` 現在の HEAD、インデックス、ワーキングツリーを指定された状態にリセットする
* `Gwc` ワーキングツリーから追跡されていないファイルを消去する（ドライラン）
* `GwC` ワーキングツリーから追跡されていないファイルを消去する
* `Gwm` ファイルを移動ないしは名前変更する
* `GwM` ファイルを強制的に移動ないしは名前変更する
* `Gwx` ワーキングツリーとインデックスからファイルを再帰的に削除する
* `GwX` ワーキングツリーとインデックスからファイルを再帰的かつ強制的に削除する

### その他

* `G..` 現在のディレクトリをワーキングツリーの最上位に変更する
* `G?` 上記で定義されたエイリアスを指定の正規表現で検索する

※ Git エイリアス定義の詳細は [zimfw/git の init.zsh](https://github.com/zimfw/git/blob/master/init.zsh) を参照してください。

## Homebrew

* `brewc` キャッシュを消去する
* `brewC` 最新バージョンのダウンロードを含めキャッシュを消去する
* `brewd` システムに潜在的な問題がないかを点検する
* `brewe` 指定されたフォーミュラを編集する
* `brewi` 指定されたフォーミュラについての情報を表示する
* `brewI` 指定されたフォーミュラをインストールする
* `brewl` インストール済みフォーミュラを一覧表示する
* `brewL` ほかのインストール済みフォーミュラに依存していないインストール済みフォーミュラを一覧表示する
* `brewo` 古くなったインストール済みフォーミュラを一覧表示する
* `brewr` 指定されたフォーミュラを再インストールする
* `brews` フォーミュラ名の検索を実行する
* `brewS` macOS の launchctl デーモンマネージャーでバックグラウンドサービスを管理する
* `brewu` Homebrew とすべてのフォーミュラを更新する
* `brewU` 古くなったフォーミュラや固定されていないフォーミュラをアップグレードする
* `brewx` 指定されたフォーミュラをアンインストールする
* `brewX` 指定されたフォーミュラのすべてのインストール済みバージョンを削除する

### Homebrew Cask

* `caske` 指定されたカスクを編集する
* `caski` 指定されたカスクについての情報を表示する
* `caskI` 指定されたカスクをインストールする
* `caskl` インストール済みカスクを一覧表示する
* `casko` 古くなったインストール済みカスクを一覧表示する
* `caskr` 指定されたカスクを再インストールする
* `casks` カスク名の検索を実行する
* `caskU` 指定されたカスク、指定がない場合はすべてのカスクをアップグレードする
* `caskx` 指定されたカスクをアンインストールする
* `caskX` 指定されたカスクが存在しないように見えてもアンインストールする
* `caskz` 指定されたカスクに関連するすべてのファイルを消去する

※ Homebrew エイリアス定義の詳細は [zimfw/homebrew の init.zsh](https://github.com/zimfw/homebrew/blob/master/init.zsh) を参照してください。

# おまけ：Anaconda 環境を表示する

Eriner テーマには Python 仮想環境を表示する機能があります。しかし、Anaconda 環境を表示する機能はありません。Python 仮想環境と同様に Anaconda 環境を表示するように Eriner テーマを改造してみましょう。

下記のコマンドで Eriner テーマの zsh-theme ファイルを修正します。

```shell-session
% sed -i '' -e '/VIRTUAL_ENV:t}"$/a\'$'\n  if [[ -n ${CONDA_DEFAULT_ENV} ]] segment+=" %F{cyan}${CONDA_DEFAULT_ENV}"\n' ~/.zim/modules/eriner/eriner.zsh-theme
```

ターミナルを再起動すると Eriner 風に Anaconda 環境が表示されるようになっているはずです。しかし、Anaconda が追加する環境表示と重複して表示されてしまっています。Anaconda が環境表示を追加しないように下記のコマンドで Anaconda を設定しましょう。

```shell-session
% conda config --set changeps1 False
```

そうすると下記のようにイケてる感じで Anaconda 環境を表示できます。
![eriner-theme-with-conda-environment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67627/92604b57-2202-c8ba-4118-7a27cbda0c52.png)

---

本稿では、爆速 Zsh フレームワークである Zim のインストール方法とそのチートシートについてまとめました。Zim は日本語の情報が少ない Zsh フレームワークですが、ぜひご自身の環境で試してみてもらえたらと思います。

なお、朝日新聞社では、技術職の中途採用を強化しています。
ご興味のある方は下記リンクから希望職種の募集ページに進んでください。
皆様からのご応募、お待ちしております！

https://www.asahishimbun-saiyou.com/information/career

# 参考文献

[Zim: Modular, customizable, and blazing fast Zsh framework](https://zimfw.sh)
[Zim フレームワークで Zsh 環境を構築する](https://takuyatsuchida.com/build-zsh-environment-by-zim-framework/)
[zsh の本](https://gihyo.jp/book/2009/978-4-7741-3864-0)