% ~/p/m/b/src % ~ › p › src zshプロンプトのパス表示を
短縮して見やすくする
(PROMPT)

深い階層で作業していると、プロンプトに表示されるパスが長くなってコマンドを打つスペースが狭くなります。
/Users/taro/projects/myapp/backend/src/controllers のような長いパスが毎回表示されると、実際に入力する部分が右端に追いやられて見づらくなります。

この記事では、zshの標準機能を使ってパスを短縮表示する方法を紹介します。
最終的には ~/p/m/b/s/controllers のように、末尾以外を頭文字化して表示できるようになります。

関連記事

1. zsh標準のホームディレクトリ省略

まず基本として、zshには %~ という表示形式があります。

PROMPT='%~ %# 'Code language: JavaScript (javascript)

これはホームディレクトリを ~ で省略してくれる標準機能です。
たとえば /Users/taro/projects/myapp/src~/projects/myapp/src と表示されます。

1.1. 末尾のディレクトリ名だけ表示する

もっと短くしたい場合、末尾のディレクトリ名だけを表示する方法があります。

PROMPT='%1~ %# 'Code language: JavaScript (javascript)

この設定では /Users/taro/projects/myapp/srcsrc だけになります。
数字の部分は階層の深さを指定していて、%2~ にすると myapp/src のように2階層分を表示します。

2. ディレクトリ名を頭文字化して短縮する

パス全体の構造は見えつつ表示を短くする方法として、末尾以外を頭文字にする方法があります。

/Users/taro/projects/myapp/backend/src
→ ~/p/m/b/src

/Users/taro/workspace/another-project/lib/utils
→ ~/w/a/l/utilsCode language: JavaScript (javascript)

これを実現するには、zshの関数とプロンプト置換という機能を組み合わせます。
まず .zshrc に以下を追加してプロンプト置換を有効にします。

setopt prompt_subst

この設定により、プロンプト内でコマンド置換や変数展開が使えるようになります。
次に、パスを短縮する関数を定義します。

prompt_dir() {
  local dir
  local -a parts
  local i

  # %~ をプロンプト展開して ~ を含む形にする
  dir=${(%):-%~}

  # パスをスラッシュで分割して配列にする
  parts=(${(s:/:)dir})

  # 最後の要素以外を頭文字化
  for (( i = 1; i < ${#parts[@]}; i++ )); do
    # 空要素や ~ はそのまま残す
    [[ -n ${parts[$i]} && ${parts[$i]} != "~" ]] && parts[$i]=${parts[$i][1,1]}
  done

  # 配列をスラッシュで結合して出力
  print -r -- ${(j:/:)parts}
}

PROMPT='$(prompt_dir) %# 'Code language: PHP (php)

少し長いコードですが、やっていることは単純です。

  1. dir=${(%):-%~} の部分は、zshのプロンプト展開記法を使ってホームディレクトリを ~ に置き換えています。
    ${PWD/#$HOME/~} という書き方もありますが、シンボリックリンク経由でディレクトリに入った場合などに正しく置換れないことがあり、%~ を使う方が確実です。
  2. parts=(${(s:/:)dir}) はパスをスラッシュで分割して配列にする処理です。
    (s:/:) というのはsplitを意味していて、区切り文字としてスラッシュを指定しています。
    ~/projects/myapp/src('~' 'projects' 'myapp' 'src') という配列になります。
  3. for文では、配列の最後の要素以外をループで処理します。
    ${#parts[@]} が配列の要素数なので、i < ${#parts[@]} とすることで最後の要素を除外しています。
    最後の要素は現在作業しているディレクトリ名なので、可読性のためにフルで表示したいからです。
  4. parts[$i]=${parts[$i][1,1]} は各要素の先頭1文字だけを取り出す処理です。
    zshでは [1,1] という書き方で文字列の1文字目から1文字目までを指定できます。
    ただし ~ や空文字列はそのまま残すように条件分岐を入れています。
  5. 最後の print -r -- ${(j:/:)parts} で、配列をスラッシュで結合して出力します。
    (j:/:) はjoinを意味していて、配列要素を指定した区切り文字で連結します。

3. 既存のテーマを使う選択肢

自分で関数を書くのが面倒な場合、powerlevel10kのような既存のプロンプトテーマを使う方法もあります。
これらのテーマには、パス短縮機能が最初から組み込まれています。
ターミナルで作業する時間が長いほど、プロンプトの見やすさは重要になります。