無限人がやってるPowerLineのあのパンくずリスト型の表示が格好いいアレです。
最近は色々なshがあるしプラグイン的な形でサクッと導入できる中、わざわざbashでひいこらやる必要も無いと思うけど、他のshを導入するのは面倒くさいし、それはともかく自分用にカスタマイズしたいなと思ったので頑張りました。
作ってる途中で色々知見を得たので、備忘録的な。
格好いい画像
筆者環境
WindowsTerminal (fontには@tawara_氏のHackGenNerd35 Consoleを利用)
WSL2 (Ubuntu 18.04.5)
bash 4.4.20
これと完全一致じゃなくても別にどうにかなるとは思います
HackGen35の場合全角文字が絡むとカーソル位置がおかしくなるので、そのときはHackGenNerd Consoleの方を選んであげてください。
三角が行の高さと合わないときは文字サイズを調整してください。(12とか?)
とにかくソースコード
#!/bin/bash
set -euC # bash option
declare -l DSPCOLOR="reset"
COLORCHANGE() {
echo -e -n "${ESC}"
if [ "$1" = "back" ]; then
# background color
printf "\033[4"
else
# charactor color
printf "\033[3"
fi
case "$2" in
"red" ) printf "8;2;255;0;15m";;
"green" ) printf "8;2;0;145;64m";;
"yellow" ) printf "8;2;250;191;20m";;
"blue" ) printf "8;2;0;0;255m";;
"purple" ) printf "8;2;146;7;131m";;
"cyan" ) printf "8;2;0;160;233m";;
"gray" ) printf "8;2;229;229;229m";;
"white" ) printf "8;2;255;255;255m";;
"black" ) printf "8;2;0;0;0m";;
* ) printf "9m";;
esac
}
COLORCHANGEFROMBACK() {
case "$1" in
"white" | "gray")
COLORCHANGE "chara" "black";;
* )
COLORCHANGE "chara" "white";;
esac
}
# make bar like powershell
TOPICCHANGE() {
# > color
local isUsed=true
if [ "$DSPCOLOR" = "reset" ]; then
echo -n ""
isUsed=false
else
echo -n " "
fi
# > background color
COLORCHANGE "back" "$1"
# > color
COLORCHANGE "chara" "$DSPCOLOR"
# >
if "${isUsed}"; then
echo -n ""
COLORCHANGE "chara" "reset"
fi
echo -n " "
COLORCHANGEFROMBACK "$1"
DSPCOLOR="$1"
}
export VIRTUAL_ENV_DISABLE_PROMPT=1 # pythonのvenv仮想環境でPS1を書き換えさせない
nerdPS1() {
local userName="$1"
# if userName yourname, use short name
# [TODO] Change YOUR-USER-NAME
if [[ $userName == "YOUR-USER-NAME" ]]; then
userName="🥦" # terminalによってはカラーフォント絵文字も使える。自分っぽいものに置き換えよう
fi
local hostName="$2"
# if hostName ..
# [TODO] Change YOUR-HOST-NAME
if [[ $hostName == "YOUR-HOST-NAME" ]]; then
hostName="" # \uf878 nf-mdi-monitor 一番ホストっぽかった
fi
local pwdInfo="$3"
# chroot
# とりあえず書き足しておいたけどvenvと関係なかった。ここのは動作検証してないので……
if [[ -v debian_chroot ]]; then
TOPICCHANGE "purple"
echo -e -n "\uf306 $debian_chroot" # nf-linux-debian
fi
# (optional) python venv
if [[ -v VIRTUAL_ENV ]]; then
local PYTHON_VER="$(python -V)"
local PYTHON_ENVNAME="$(basename $VIRTUAL_ENV)"
TOPICCHANGE "cyan"
# for remove uniquename (pipenv hoge-{uniquename})
echo -e -n "\ue235 ${PYTHON_VER#Python } ${PYTHON_ENVNAME%-*}" # nf-fae-python 一番見やすいPythonロゴ
fi
# host
TOPICCHANGE "blue"
echo -n "$userName@$hostName"
# pwd
TOPICCHANGE "gray"
echo -e -n "\ue5ff $pwdInfo" # nf-custom-folder フォルダアイコン
# (optional) git
# [TODO] `source git-prompt.sh` (you have to download or find)
if [[ "$(uname -r)" == *microsoft* && "$pwdInfo" =~ ^/mnt/ ]]; then
# Git is too slow in WSLdir
:
else
if git status --ignore-submodules &>/dev/null; then
# You Use Git
local gitps1="$(__git_ps1)"
if [[ $gitps1 =~ [*+?%] ]]; then
TOPICCHANGE "yellow"
else
TOPICCHANGE "green"
fi
echo -e -n "\ue725 $gitps1" # nf-dev-git_branch 一番見やすかったGitぽいアイコン
fi
fi
TOPICCHANGE "reset" # 忘れずに
}
# 右端に時刻を表示
# コピペ https://orebibou.com/ja/home/201810/20181002_001/
__command_rprompt() {
local rprompt=$(date "+%Y/%m/%d %H:%M:%S")
local num=$(($COLUMNS - ${#rprompt} - 2))
printf "%${num}s$rprompt\\r" ''
}
set +e # これが無いと、プロンプトで実行したコマンドにエラーが有った時に動かなくなる
PS1='$(nerdPS1 \u \h \w)\n\$ '
PROMPT_COMMAND=__command_rprompt
# ...
if [ -e ~/nerdps1.sh ]; then
source ~/nerdps1.sh
fi
source ~/.git-prompt.sh
GIT_PS1_SHOWDIRTYSTATE=true
GIT_PS1_SHOWUPSTREAM=true
GIT_PS1_SHOWUNTRACKEDFILES=true
GIT_PS1_SHOWSTASHSTATE=true
GIT_PS1_COMPRESSSPARSESTATE=true # 増えた
GIT_PS1_STATESEPARATOR=' '
# ...
説明
プロンプトの表示の変更
一般に見えているホスト名とか書いてある部分は環境変数PS1
で指定されています。この内容は1行実行ごとに解釈して都度都度実行されます。
後述のC
関数を1つのパンくずごとに実行させたかったのですが、これをそのままC
に埋め込むと思うように動かない(同時に処理される?)ので、今回その内容について全て関数に投げています。
Nerdfonts
powerline用のフォントを始めとする様々なアイコンフォントが含まれたフォントです。外字領域を利用しているいて、Nerdfontsと他の一般的なfontを合成することもできるため、様々な派生があります。
パンくずの仕組み
そもそもあのパンくずは、Nerdfontsに含まれるnf-pl-left_hard_divider
という文字を、文字色をそれ以前の背景色にすることで表現しています。
今回DSPCOLOR
という変数で以前の色を管理し-C
-TOPICCHANGE
という変数で、背景色の変更とnf-pl-left_hard_divider
の表示を行っています。
一元管理しているので、好きなようにパンくずを生やしたり消したりできます。
-変数名の汚染は少し心配-
追記(2020/09/14) 変数名変えておきました。ついでに色を処理する関数COLORCHANGE
を別に用意しました。
色を変える仕組み
\e[{hoge}m
の形で入力する(制御文字を使うためecho
には-e
オプションが必要)することで、{hoge}
に応じた色変更が行えます。具体的な記入例は詳しい説明がいくらでも他の人の記事にあるので任せます。
\e
と\033
は同じ意味ですが、後者のほうが互換性が良いみたいです
ユーザ名とホスト名のアイコン化
長ったるいのは嫌だけど非表示にするのも何かあった時アレだな、ということで、普段のものに一致していたら1字に書き換えるようにしておきます。
python venv実行中の表示
pythonにはバージョン管理を司るvenvという機能がありますが、デフォルトだと環境名をPS1
に埋め込みやがります。埋め込むかどうかは環境変数VIRTUAL_ENV_DISABLE_PROMPT
で指定できるし、仮想環境名はbasename $VIRTUALENV
で取得できます。
pipenvを使う時、環境作成時のユニークな値がこれの後ろに付いてきてしまうので、ハイフン以後を削除する設定しています。
git の表示
色々細々した項目について場合分けするのが大変そうですが、公式のgit-prompt.sh
というのがいい感じに処理してくれるので、これを見つけてきて読み込みましょう。ブランチ名と状況を出力してくれる関数__git_ps1
を含んでいます。
これの出力で変更の有る無しを判断しています。
他の記事ではあまり書いてませんでしたが、最近ではGIT_PS1_COMPRESSSPARSESTATE
についても設定する必要があるようです。
ただ、WSLにおいて、通常のWindowsのファイルにこれを実行しようとすると明らかに時間がかかるようになってしまいます。__git_ps1
の仕業です。いつか改善されることを期待して。
追記(2020/09/14)
試しに使っててあまりの遅さに耐えられなくなったので、/mnt/
以下で動かないようにしました。そもそもmnt
以下でgit status
が激重でした。
右端に時刻を表示
bashでPROMPT_COMMANDを利用して右プロンプトを出力させるという記事のものが今回文句なく動いてくれたのでこれをそのまま使用しました。
もうちょっと飾っても良いかもしれない。
やらかしたとき
これで遊んでると.bashrc
にバグを埋め込んで起動できなくなることが有るので、気をつけましょう。
WSLの場合は、cmdなりPowerShellなりからWSL内部のbashをrcを読みこまずに実行することができます。
wsl.exe -e bash --norc
.bashrcでsourceを埋め込む前にとりあえずテストして確認しましょう。(先達の知恵)
最後に
パンくず(そういう言い方で良いのか?)再現の記事は多いけど、このスクリプトでは割と楽に好きな色のパンくずを追加できるので、色々各々の状況に応じた形にカスタムしやすいと思います。作ってる内に互換性への意識がおざなりになっちゃったけど……
参考
-
Git のための最強 Bashプロンプト!
__git_ps1
も自作したくなったら役立つかも - シェルスクリプトのechoで”問題なく”色をつける(bash他対応) 色について詳しく
- Pythonのvenvのプロンプト表示をカスタマイズする venvの書き換えについて
- bashでPROMPT_COMMANDを利用して右プロンプトを出力させる 右端の時刻表示について
- NERD FONTS チートシートが有るので好きなアイコンを探してみてください。
- Ricty を神フォントだと崇める僕が、フリーライセンスのプログラミングフォント「白源」を作った話 NerdFonts合成バージョンも配布中