bashのプロンプトにブランチ名を右寄せ表示する

.bashrcとかで以下のように設定

function length()
{
  echo -n ${#1}
}

function init-prompt-git-branch()
{
  git symbolic-ref HEAD 2>/dev/null >/dev/null &&
  echo "($(git symbolic-ref HEAD 2>/dev/null | sed 's/^refs\/heads\///'))"
}

if which git 2>/dev/null >/dev/null
then
  export PS1_GIT_BRANCH='\[\e[$[COLUMNS]D\]\[\e[1;31m\]\[\e[$[COLUMNS-$(length $(init-prompt-git-branch))]C\]$(init-prompt-git-branch)\[\e[$[COLUMNS]D\]\[\e[0m\]'
else
  export PS1_GIT_BRANCH=
fi
export PS1="\[\e[32;1m\]\u@\H \[\e[33;1m\]\w $PS1_GIT_BRANCH\n\[\e[36;1m\]\t \[\e[0m\]\$ "

gitリポジトリ外では通常のプロンプト,

notogawa@hostname ~/path/to/working/dir
12:12:31 $

gitリポジトリ内に入ると,

notogawa@hostname ~/path/to/working/dir                         (master)
12:12:31 $

のようにブランチ名を右寄せ表示するプロンプトになる.

bashのプロンプトに何かを右寄せ表示する場合,一応コツみたいなものがある.必ず見た目通り,

  1. 左寄せ表示する文字列
  2. 右寄せ表示する文字列
  3. 改行
  4. 以下繰り返し

となるようにプロンプト(PS1)を組むのがいい.この左先の順番では,

  1. 左寄せ文字列の表示
  2. 左いっぱい(=行数分動かしちゃう)に移動
  3. (行数)-(右寄せ表示文字列長)の位置へ移動
  4. 右寄せ文字列の表示

となる.対して,推奨しない右先の順番では,

  1. 左いっぱい(=行数分動かしちゃう)に移動
  2. (行数)-(右寄せ表示文字列長)の位置へ移動
  3. 右寄せ文字列の表示
  4. 左いっぱいに移動
  5. 左寄せ文字列の表示

とする必要があるが,世の中echo -nのようにtrailing newlineの無い出力はたくさんあるので,右先でプロンプトを表示してしまうと,左寄せ文字列が直前コマンドの最終行(改行無し)を上書くように表示されてしまうことがある.現在のカーソル位置を知っていればその限りでは無いが,直前コマンド出力がtrailing newlineかorどれだけの長さ出ているかがbashにはわからないので,おとなしくまずは左寄せ文字列部分を表示すれば,(クソ長い右寄せ表示文字列でない限りは)直前コマンドの出力を隠してしまうことは無い.