Zshプラグイン管理の変遷

September 26, 2014

oh-my-zshからprezto、zgen、zinitへの移行手順やpeco/fzf活用によるスニペット管理・ディレクトリ移動の効率化を解説

oh-my-zshが重いのでpreztoに乗り換える

install

yum -y install ncurses-devel git
wget http://downloads.sourceforge.net/project/zsh/zsh/5.0.5/zsh-5.0.5.tar.gz
tar xvzf zsh-5.0.5.tar.gz
cd zsh-5.0.5
./configure && make && make install

既にzshやoh-my-zshの設定がある場合は退避

cd ~/
mkdir zsh_orig
mv .zlogin .zlogout .zprofile .zshenv .zshrc zsh_orig

zsh起動

zsh
git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
setopt EXTENDED_GLOB
for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do
  ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"
done
chsh -s `which zsh`

Updating

cd ~/.zprezto
git pull && git submodule update --init --recursive

pecoとzshでかんたんスニペット管理

手順

たまに使うコマンドなどをあらかじめ~/.snippetsに一行ずつ書いておきます。

cut -d' ' -f1,3
dig -x 1.1.1.1
tcpdump -nn src host 1.1.1.1 and port not 22
find . -type f -regextype posix-basic -regex ".*.(log|txt)" ! -regex ".*./foo/bar/.*"
:
:

その上で~/.zshrcに以下を追加。

: "peco snippet" && {
  function peco-select-snippet() {
    BUFFER=$(cat ~/.snippets | peco)
    CURSOR=$#BUFFER
    zle -R -c
  }
  zle -N peco-select-snippet
  bindkey '^x^r' peco-select-snippet
}

私は<C-X><C-R>にスニペット呼び出しを割り当ててます。

所感

はじめはプラグインやCLIの導入を検討してたんですが、あまり高機能にしたところで使いこなせるイメージもなく(オプションなど覚えていられないし)、ニーズもシンプルだったので薄く自作しました。

私はこのスニペットファイルをdotfiles管理下において、日々育てて(?)います。便利です。

powered_cdをもうちょっと便利にする

ディレクトリが既に削除されている場合はcdせずにログから削除します。

: "powered_cd" && {
  function chpwd() {
    powered_cd_add_log
  }
  function powered_cd_add_log() {
    local i=0
    cat ~/.powered_cd.log | while read line; do
    (( i++ ))
    if [ i = 30 ]; then
      sed -i -e "30,30d" ~/.powered_cd.log
    elif [ "$line" = "$PWD" ]; then
      sed -i -e "${i},${i}d" ~/.powered_cd.log
    fi
  done
  echo "$PWD" >> ~/.powered_cd.log
  }
  function powered_cd() {
    if (which tac > /dev/null); then
      tac="tac"
    else
      tac="tail -r"
    fi
    if [ $# = 0 ]; then
      local dir=$(eval $tac ~/.powered_cd.log | fzf)
      if [ "$dir" = "" ]; then
        return 1
      elif [ -d "$dir" ]; then
        cd "$dir"
      else
        local res=$(grep -v -E "^${dir}" ~/.powered_cd.log)
        echo $res > ~/.powered_cd.log
        echo "powerd_cd: deleted old path: ${dir}"
      fi
    elif [ $# = 1 ]; then
      cd $1
    else
      echo "powered_cd: too many arguments"
    fi
  }
  _powered_cd() {
    _files -/
  }
  compdef _powered_cd powered_cd
  [ -e ~/.powered_cd.log ] || touch ~/.powered_cd.log
  alias c="powered_cd"
}

元ネタはこちら;

zgenをzinitに置き換えたらzshの起動時間が500msから100msに改善した

zgenであまり困ってはいなかったのですがzinitでもうちょっと速く出来そう、ということなので。

zgenの場合

setupのおさらい

git clone https://github.com/tarjoilija/zgen.git ~/.zgen

zgen時代のzshrc設定例

: "zgen" && {
  source "${HOME}/.zgen/zgen.zsh"
  if ! zgen saved; then
    echo "Creating a zgen save..."

    zgen oh-my-zsh
    zgen oh-my-zsh plugins/git

    zgen load aws/aws-cli bin/aws_zsh_completer.sh
    zgen load zsh-users/zsh-syntax-highlighting
    zgen load zsh-users/zsh-completions
    zgen load lukechilds/zsh-better-npm-completion
    zgen load docker/cli contrib/completion/zsh/_docker
    zgen load docker/compose contrib/completion/zsh/_docker-compose

    zgen save
  fi
}

# 以下略 / export,aliasなど

元のプラグインロード周りは上記の状態でした。 zgen oh-my-zsh がクセモノで、oh-my-zsh全体をフルロードしてくれる便利な記述で、起動にやや時間がかかる直接的な原因はこの処理ではなかったのですが、 一方で普段使ってる 設定/キーバインド/エイリアス がoh-my-zsh内のどのファイルに依存するのかをわかりにくくしてしまっていました。

これを調査するのに少し時間がかかりました。

そして、調査・確認しながら移行した結果が以下です。

zinitに変える

setup

mkdir ~/.zinit
git clone https://github.com/zdharma/zinit.git ~/.zinit/bin

zinitを使ったzshrcの設定例

: "zinit" && {
  source ~/.zinit/bin/zinit.zsh

  # https://zdharma.org/zinit/wiki/Example-Minimal-Setup/
  # ここは公式の推奨設定を参考に
  zinit wait lucid light-mode for \
    atinit"zicompinit; zicdreplay" \
      zdharma/fast-syntax-highlighting \
    blockf atpull'zinit creinstall -q .' \
      zsh-users/zsh-completions

  # oh-my-zshのファイルをスニペットとして同期的にバルクロード
  # is-snippet for でまとめて読み込む
  zinit is-snippet for \
      OMZL::completion.zsh \
      OMZL::key-bindings.zsh \
      OMZL::directories.zsh


  # oh-my-zshのファイルをスニペットとして非同期でバルクロード
  zinit wait lucid is-snippet for \
      OMZL::git.zsh \
      OMZP::git

  # .zshでないファイルをcompletionファイルとして認識させつつバルクロード
  zinit wait lucid is-snippet as"completion" for \
      OMZP::docker/_docker \
      OMZP::docker-compose/_docker-compose \
      OMZP::rust/_rust \
      OMZP::cargo/_cargo \
      OMZP::rustup/_rustup

  zinit cdclear -q

  # 同期的に呼ばないとうまく保管されないのでiceは使わない
  zinit snippet https://github.com/aws/aws-cli/blob/v2/bin/aws_zsh_completer.sh
  zinit light lukechilds/zsh-better-npm-completion
}

: "color" && { # promptに色付けする部分だけoh-my-zshから抜き出し
  setopt promptsubst
  autoload -U colors
  colors
}

: "extra up and down key-binding" && { # ctrl+p, ctrl+n の挙動が思い通りでなかったので修正しつつ抜き出し
  autoload -U up-line-or-beginning-search
  autoload -U down-line-or-beginning-search
  zle -N up-line-or-beginning-search
  zle -N down-line-or-beginning-search
  bindkey "^p" up-line-or-beginning-search
  bindkey "^n" down-line-or-beginning-search
}

# 以下略 / export,aliasなど

zinit基本設定をかいつまんで説明

# 必須
source ~/.zinit/bin/zinit.zsh      # zshrc行頭に入れること

# snippet形式
zinit snippet <URL>                # 読み込みたいzshファイルを直接指定できる
zinit snippet OMZ::path/to/file    # oh-my-zshリポジトリのショートハンド
zinit snippet PZT::path/to/file    # preztoリポジトリのショートハンド
zinit snippet OMZT::gnzh           # oh-my-zsh themeを使う場合のショートハンド
zinit snippet OMZL::git.zsh        # oh-my-zsh lib以下を使う場合のショートハンド
zinit snippet OMZP::git            # oh-my-zsh plugins以下を使う場合のショートハンド

# zinit load/light形式
# zgenやzplugと同じような書き心地で設定できる、最も基本的な呼び方
# load  ... tracking report有り、それでも差はごくわずか
# light ... tracking report無し、通常はこちらで
zinit light lukechilds/zsh-better-npm-completion # githubリポジトリを指定できる
zinit light zsh-users/zsh-completions

# ice
# 直後のlight/loadに任意オプションを適用できる 記述が長くなりがちなときに便利
zinit ice wait'0' lucid
zinit light zsh-users/zsh-completions

# オプションいろいろ
# wait              ... 非同期モード。waitはwait'0'と同義で、非同期実行時の待ち時間を指す。依存関係の定義等もできる
# lucid             ... 非同期読み込み時のmessage出力を抑制
# as"completion"    ... zshでないファイルをzsh completionとして読み込む
# src"path/to/file" ... 対象リポジトリ内の特定のファイルを読み込ませたい場合使う
# light-mode for    ... lightをオプションと同時に設定する書き方で使う
# is-snippet for    ... snippetをオプションと同時に設定する書き方で使う
zinit wait'0' lucid light-mode for zsh-users/zsh-completions
zinit wait lucid is-snippet as"completion" for OMZP::docker/_docker
zinit ice src'bin/aws_zsh_completer.sh'
zinit light aws/aws-cli

前述の設定例ではOhMyZshプリインの機能のうち有効にしているのはごく一部ですので、追加でほしいものがある場合はショートハンドを活用して個別にloadするといいと思います。

その他syntaxの解説はこちらのWiki等を参照

パフォーマンス計測してみる

# 素の状態
% time zsh -i -c exit
zsh -i -c exit  0.01s user 0.01s system 83% cpu 0.023 total

# zgen
$ time zsh -i -c exit
zsh -i -c exit  0.13s user 0.09s system 39% cpu 0.557 total

# zinit
time zsh -i -c exit
zsh -i -c exit  0.03s user 0.04s system 80% cpu 0.085 total

だいぶいいんじゃないかなぁと。

zinitの使い方

zinit self-update   # zinitのupdate
zinit update        # snippet, plugin, completionのupdate
zinit cclear        # 使われてない補完設定の掃除
zinit delete <name> # snippet, plugin, completionの削除
zinit times         # snippet, plugin, completionごとの速度計測

さほど手間もかからずに移行できてよかった。


2022/02/18 追記

zinitが不安なのでやめてsheldonに移行しました。



Recent blog posts


zsh centos shell peco cli-tools performance


(c) Copyright 2026 Kotaro Yoshimatsu