真面目に仕事しようとしたら、私のプロンプトがエライことになってた。
長いわ!流石に長いわ!こんなんじゃ仕事できん!
-
${PWD}
が長い- プロジェクトを整理しようと階層的にしたら、長くなった
- Python の仮想環境の名前が長い
- poetry の設定をいじって、pyenv の仮想環境と同じように扱えるようにした
- プロジェクトのディレクトリに行くだけで仮想環境に入れるので、poetry の仮想環境を pyenv と同様に扱うのは(私にとって)必要不可欠
- 仮想環境の名前を出すのも、どの仮想環境にいるか一目で分かるので、必要不可欠
- poetry が仮想環境名として unique ID 的なものや Python のバージョンを勝手に付けるので、poetry が悪い
- でも poetry の仮想環境の名前の付け方を変更する方法は分からない
これまでの PROMPT の設定
こんな感じの設定にしてた。
autoload colors
colors
local p_cdir="%B%F{blue}[%~]%f%b"$'\n'
local p_info="%n@%m${WINDOW:+[$WINDOW]}"
local p_mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"
PROMPT=" $p_cdir$p_info $p_mark "
一応解説する。
-
%B...%b
- 囲まれている中身の文字を Bold にする
-
%F{color}...%f
- 囲まれている中身の文字の色を color にする
- color として使える名前は、
black
,red
,green
,yellow
,blue
,magenta
,cyan
,white
- 頑張れば256色とかを指定できるけど、ここで頑張らないで color schema の設定を頑張る方針
-
%~
-
${HOME}
の下にいるなら${HOME}
を~
に置き換えて、それ以外なら root (/
)からの絶対パスで、${PWD}
を表示する
-
-
$'\n'
- 改行
- ダブルクォーテーション(
"
)だとダメ
- ダブルクォーテーション(
- 改行
-
%n
- username
-
%m
- hostname
-
${WINDOW}
- screen に入っていると、そのウィンドウ番号が入る
- screen に入っていない場合は、定義されれない
-
${HOGE:+moge}
-
${HOGE}
という変数に何か値が入っている場合、moge
という文字列になる -
${HOGE}
という変数に値が入っていない場合、そのまま空になる
-
- (ちなみに)
${HOGE:-moge}
-
${HOGE}
という変数が無いか空の場合に、moge
という文字列になる -
${HOGE}
という変数に値が入っている場合は、その値
-
-
%(?,hoge,moge)
- 直前のコマンドの返り値(
$?
)が 0 (正常終了)ならば、hoge
- 直前のコマンドの返り値が 0 でない(異常終了)ならば、
moge
- 直前のコマンドの返り値(
-
%(!,hoge,moge)
- ユーザーが root(id==0)ならば、
hoge
- ユーザーが root でないならば、
moge
- ユーザーが root(id==0)ならば、
${PWD} が長い問題
これは %~
自体に if else みたいな機能があるので、それを使えば簡単に設定できる。
-
%(5~|hoge|moge)
-
%~
で、表示されるディレクトリの数が5個以上だったらhoge
、それ以外ならmoge
になる
-
-
%(5~|.../%2~|%~)
-
%~
で、表示されるディレクトリの数が5個以上だったら、.../
という文字に続きディレクトリの最後の2つを表示、それ以外なら%~
を全部表示
-
-
%(5~|%-2~/.../%1~|%~)
-
%~
で、表示されるディレクトリの数が5個以上だったら、ディレクトリの最初の2つと、/.../
という文字、そしてディレクトリの最後の1つを表示
-
これで解決。あとは自分の好みに設定すれば良い。
Python の仮想環境名が長い問題
まず、PROMPT に何も設定していないのに、プロンプトに仮想環境名がついてしまっているのだが、これは pyenv の機能。いつもお世話になってます。助かってます。
今回はそれじゃダメなので、無効化する。
export VIRTUAL_ENV_DISABLE_PROMPT=1
これを設定しておけば良い。後は自分で設定する。
pyenv の仮想環境に入ると、${VIRTUAL_ENV}
という変数に仮想環境名、正確には、仮想環境が置かれているディレクトリの絶対パスが入る。
例えば hogehoge
という名前の仮想環境ならば、${HOME}/.pyenv/versions/hogehoge
。
(pyenv を ${HOME}/.pyenv
にインストールした場合)
欲しいのは最後のディレクトリ名だけ。これを変数内の文字列置換でさくっと取り出そう。
変数内の文字列置換
置換したいなって時に毎回ググるので、ここでまとめてしまう。
- 文字列先頭からの最短マッチで該当部分を削除
-
${HOGE#pattern}
- 使わない
-
- 文字列先頭からの最長マッチで該当部分を削除
-
${HOGE##pattern}
- basename, 拡張子の抽出
-
- 文字列最後からの最短マッチで該当部分を削除
-
${HOGE%pattern}
- dirname, 拡張子を取り除く
-
- 文字列最後からの最長マッチで該当部分を削除
-
${HOGE%%pattern}
- 最も使わない
-
- 例)
HOGE="/hoge/moge/fuga.fuga.ext"
-
${HOGE##*/}
→fuga.fuga.ext
:basename -
${HOGE##*.}
→ext
:拡張子の抽出 -
${HOGE%/*}
→/hoge/moge
:dirname -
${HOGE%.*}
→/hoge/moge/fuga.fuga
:拡張子を取り除く -
${${HOGE##*/}%.*}
→fuga.fuga
-
cut と rev の活用
余談が長かったが、要するに ${VIRTUAL_ENV##*/}
で仮想環境名が取れる。
しかしこの値は textcnn-gradcam-WPG28PJj-py3.9
のように poetry が勝手に付けた ID や Python バージョンが入っている。
これを取り除きたい。
poetry が仮想環境名として付ける形は (プロジェクトのディレクトリ名の _ を - に置き換えたもの)-(IDっぽいもの)-(Python バージョン)
ということは分かっているので、「文字列を -
で分割した最後の2つを取り除いたもの」を作れば良い。
分割すると言えば cut
である。
例えば以下のようにすると、一見取り出せたかのように見える。
echo ${VIRTUAL_ENV##*/} | cut -d- -f-2
→ textcnn-gradcam
cut
の -d-
オプションで -
を区切り文字とすると指定して、-f-2
オプションで区切られた文字列の最初から2つ目までを取得する(-f1-2
と同じ)。
しかしこれではダメだ。プロジェクトのディレクトリ名に _
もしくは -
が何個入っているかは決まっていない。「最後から2つ」を取り除きたいのだが、cut
には「最後から数える」という機能は備わっていない。
そこで rev
である。rev
は文字をひっくり返すコマンド。
だから、ひっくり返す → 最初から3つ目以降を取得 → またひっくり返す、とやれば良い。
echo ${VIRTUAL_ENV##*/} | rev | cut -d- -f3- | rev
→ textcnn-gradcam
これで完璧。
更新するタイミング
しかしまだ終わりではない。
${WINDOW}
ならば、screen で新しい WINDOW に入る時に .zshrc
を読み込むので、ただ .zshrc
に ${WINDOW}
と書いておけば意図したとおりに設定される。
しかし今回はディレクトリを移動する毎に値を変更して欲しい。
.zshrc
にただ書いただけでは、シェル(ターミナル)を起動した瞬間にしか読み込まれず、ディレクトリを移動してもプロンプトは変わらない。
そこで、ZSH の add-zsh-hook
というモジュールをロードして、プロンプトが呼び出される前のタイミングの hook である precmd
に関数をぶら下がらせて、その関数の中で PROMPT
を更新させれば良い。
結果
最終的には、.zshrc
のプロンプトの設定部分は以下のようになった。
export VIRTUAL_ENV_DISABLE_PROMPT=1
autoload -Uz colors
colors
autoload -Uz add-zsh-hook
local p_cdir="%B%F{blue}[%(5~|.../%2~|%~)]%f%b"$'\n'
local p_info="%n@%m${WINDOW:+[${WINDOW}]}"
local p_mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"
local p_base=" $p_cdir$p_rhost$p_info $p_mark "
function __precmd_virtual_env() {
local p_penv="%B%F{cyan}${VIRTUAL_ENV:+(`echo ${VIRTUAL_ENV##*/}|rev|cut -d- -f3-|rev`)}%f%b"
PROMPT="$p_penv$p_base"
}
add-zsh-hook precmd __precmd_virtual_env
自分で設定したので、仮想環境名に色が付けられるようになった。
で、こうなる。
とりあえず満足である。
まとめ
「俺はなんで未だに screen を使おうとしてるんだろう」と疑問に思ってきたので、tmux の設定をしたい気分になっている。(仕事はまだしてない)