普段何気なくGitのブランチ名などをzshの現在のカーソルの右側に表示していたのですが、最近Terraformのworkspaceを利用する事になり、同じ様に表示したいなと思い設定方法などを少し調べました。

そもそもzshrcをサボってコピペなどで運用していたので、何の機能で実装されているかよくわかっていなかったのですが、少しzshrcを眺めたり設定方法を検索していた所、どうやら環境変数の PROMPTRPROMPT の値を変更する事で表示の切り替えを行っているようです。

自分の場合は手抜きですが、補完が効き過ぎ感のある zsh の設定を公開してみるをベースに明らかに必要のなさそうな設定だけを削った設定を使っていたので、今回はこの設定をベースにTerraformのworkspaceをRPROMPTに表示できるようにしました。

# ベースの設定

### vsc_info の設定
autoload -Uz vcs_info
zstyle ':vcs_info:*' enable git svn hg
zstyle ':vcs_info:*' formats '(%s)[%b] '
zstyle ':vcs_info:*' actionformats '(%s)[%b|%a] '
zstyle ':vcs_info:svn:*' branchformat '%b:r%r'
precmd () {
    psvar=()
    LANG=en_US.UTF-8 vcs_info
    [[ -n "$vcs_info_msg_0_" ]] && psvar[1]="$vcs_info_msg_0_"

    [[ -t 1 ]] || return
    [ $EMACS ] && return
    case $TERM in
      *xterm*|rxvt|(dt|k|E)term)
      print -Pn "\e]2;localhost\a"
      ;;
    esac
}
if is-at-least 4.3.10; then
  zstyle ':vcs_info:git:*' check-for-changes true
  zstyle ':vcs_info:git:*' stagedstr "+"
  zstyle ':vcs_info:git:*' unstagedstr "-"
  zstyle ':vcs_info:git:*' formats '(%s)[%b]%c%u'
  zstyle ':vcs_info:git:*' actionformats '(%s)[%b|%a]%c%u'
fi
function _update_vcs_info_msg() {
    psvar=()
    LANG=en_US.UTF-8 vcs_info
    [[ -n "$vcs_info_msg_0_" ]] && psvar[1]="$vcs_info_msg_0_"
}
add-zsh-hook precmd _update_vcs_info_msg
zstyle ':vcs_info:bzr:*' use-simple true

function toon {
  echo -n ""
}

### プロンプト設定
if [ $EMACS ]; then
    export TERM=xterm-256color
    PROMPT="%F{green}%~%f %{$fg[red]%}>%{$reset_color%} "
else
    PROMPT="%F{green}%~%f %{$fg[white]%}$(toon)%{$reset_color%} "
fi
PROMPT2="%_%% "
SPROMPT="%r is correct? [n,y,a,e]: "
RPROMPT="%1(v|%F{yellow}%1v%f|)%F{red}%T%f"

今回変更を行った部分は具体的には3箇所です。

  1. Terraformのworkspaceを取得する関数の作成
    初めは自作しようと思っていましたが、ググっているとoh-my-zshにいい感じの実装があったのでそちらを使う事にしました。
function tf_prompt_info() {
    # dont show 'default' workspace in home dir
    [[ "$PWD" == ~ ]] && return
    # check if in terraform dir
    if [ -d .terraform ]; then
      workspace=$(terraform workspace show 2> /dev/null) || return
      echo "(tf)[${workspace}]"
    fi
}
  1. _update_vcs_info_msg()関数
    自分の設定では、add-zsh-hook を使って、プロンプトを表示する直前に _update_vcs_info_msg を呼ぶ仕組みになっていたので、1で作った関数を呼び、値を表示直前に更新するようにしました。
    psvarという配列の変数に値を格納する事で後述する設定で、格納した値を使い回すことができるようになります。
function _update_vcs_info_msg() {
    psvar=()
    LANG=en_US.UTF-8 vcs_info
    tf_workspace_info=$(tf_prompt_info)
    [[ -n "$vcs_info_msg_0_" ]] && psvar[1]="$vcs_info_msg_0_"
    [[ -n "$tf_workspace_info" ]] && psvar[2]="$tf_workspace_info"
}
  1. RPROMPT RPROMPTを実際に更新する事で表示する値を変更する。
    記法が少し特殊で、%1(v|hoge|fuga) は、if psvar[1] then hoge else fuga と同じ処理を意味するらしい。
    文字色の変更は %F{} の中に、背景色の変更は %K{} の中にカラーネームを入力する事で色も変えることができる。
RPROMPT="%1(v|%F{yellow}%1v%f|)%2(v|%F{cyan}%2v%f|)%F{red}%T%f"

というわけで、こんな感じで設定するとRPROMPTに現在のworkspaceを表示する事ができた。 今回はとりあえず動く事優先で設定を行ったためコードがあまり綺麗ではないので、モチベーションが上がった時にきちんと全体を理解して直していきたい所…
zshの設定は難しい。


参考記事