私は日頃シェルに fish を愛用しています。デフォルトでシンタックスハイライトが効く上に入力補完が優秀だったり、alias よりも遥かに優秀な abbreviation を使用することができたり、vi モードが bash などよりも優秀である等、使っている理由は多数あります(と同時に POSIX 非互換で開発者のオレオレ開発思想を感じることが多々あるのがご愛嬌)。
使ってるシェルをこだわるならプロンプトの表示もこだわりたいよね。ってことで fish を使ってるんだし長らく bob the fish を特にカスタムもせずそのまま利用していました。最近は zsh でも bash でも使える starship なんかが流行っているようですね。そのデザインを見てみていると bob the fish のデフォルトでなんとなく不満に思っていたことが表出してきたので、一旦ちゃんと bob the fish をカスタマイズしてみることにしました。
(bob the fish の三角背景で並べるデザインが好きなので乗り換えではなくカスタマイズです。)
現状の不満点
↑これは fish をインストールしたときの記事にも載せてた当初の見た目ですね。この時は vi モードを使ってなかったのでその辺の表示がありませんがこれの不満点(というか他のでいいなと思った点)をまとめると、
- ファイルパスの背景が黒いせいでターミナルが暗い背景の時に非常に見ずらい。
- 背景付きのせいで見た目に狭い印象がある。
- ファイルパスの長さに応じてコマンド入力欄がズレて見にくい。
- 実行時間の表示などプロンプト右側に寄っている表示がどの行のものなのかわかりにくい。
というような感じです。まあ何を変えたいのか言われてもわかりにくいと思うので完成形をまず見せますドン
やった点は以下です。
- カラーテーマを変更
- プロンプトの前後に改行を追加
- 実行時間などを左に寄せて表示されるように修正
- vi モードのインジケータをおしゃれなアイコンに
基本設定の変更
カラーテーマなどは config.fish で環境変数を変更するだけでパパッと変えてしまえるのでサクッとドキュメントを読みながらやります。
カラーテーマは bobthefish_display_colors –all コマンドで名前と見た目を確認できます。めっちゃズラズラ長く出てくるので注意。私は有名なカラーテーマの一つである dracula にしてみました。ターミナルとして使ってる Hyper の vivid で pastel な感じと合っていい感じだったので。その他の設定は以下です。
# カラーテーマを dracula に
set -g theme_color_scheme dracula
# vi モードのインジケータを常に表示する
set -g theme_display_vi yes
# ユーザ名とホスト名を常に表示する
set -g theme_display_user yes
set -g theme_display_hostname yes
# 日付の表示書式を変更する
set -g theme_date_format "+[%H:%M:%S]"
# プロンプトから入力欄の前に改行をする
set -g theme_newline_cursor yes
# 改行後入力欄の前に表示する文字を設定する(Nerd Font が文字化けしてます)
set -g theme_newline_prompt "\e[32m\e[m "
theme_newline_prompt の中には Nerd Font のアイコンを設定しています。Nerd Font のアイコン検索から好きなアイコンを検索して copy>icon でユニコードアイコンをコピーできるのでそのまま貼り付ければ表示可能。自分は f054 番のアイコンを2個繰り返しました。
プロンプトのパーツの表示箇所の変更
さて、ここがめんどくさかったポイントです。
プロンプトの表示前に改行を入れて直前の実行結果と1行空けることで見やすくしたいと思いました。
fish でプロンプトの表示を定義できる設定ファイルは3種類あって、全て functions ディレクトリ以下の fish_prompt.fish、fish_mode_prompt.fish、fish_right_prompt.fish です。このうち fish_prompt.fish が基本となる表示の場所、fish_mode_prompt.fish は vi モードのインジケータの表示、fish_right_prompt.fish は行の右側に寄って表示される部分の表示です(長いので以下それぞれ prompt、mode_prompt、right_promptとします)。
表示順序としては mode_prompt > prompt > (入力欄) > right_prompt なわけなので、プロンプト全体の前に改行をしたいならば mode_prompt の前に改行を追加すればいいわけです。
そんなことで mode_prompt のファイルを開き function fish_mode_prompt を定義している中の最初に echo を追加して改行するようにすれば解決…しませんでした。
function fish_mode_prompt -d 'bobthefish-optimized fish mode indicator'
echo # 追加
[ "$theme_display_vi" != 'no' ]
or return
なぜと思って検索をしてみると Newline above prompt that includes fish_mode_prompt という完全に同じ趣旨の質問があったのですが、その回答として「mode_prompt は改行を取り除く仕様になってるよ!なんで改行いれたいのかは知らんけど mode_prompt を空にして、全く同じ処理を prompt の方に書き直せば動くよ!」とのことのようです。なんでやねん。
ですがとりあえず解決法はわかったので、 fish_mode_prompt.fish を全てコメントアウトし、function の内容を fish_prompt.fish にコピーします。その後、ファイル最下部の function fish_prompt 内に以下のように追記します。
function fish_prompt -d 'bobthefish, a fish theme optimized for awesome'
# Save the last status for later (do this before anything else)
set -l last_status $status
# 以下2行を追加。必ず last_status の取得より後にすること。
echo
__vi_mode_prompt
fish_mode_prompt という関数名で定義してしまうと重複してしまう恐れがあったので、__vi_mode_prompt という関数名に変更して定義しています。注意点として、 fish_prompt 関数内で一番最初に呼び出される処理は last_status 変数の定義である必要があります。これより先になんらかの処理をしてしまうと、存在しないコマンドを実行するなどして実行が失敗したステータスが返ってきた時の表示(!のやつ)がうまく表示されなくなります。
これで望んでいた挙動が再現できました。実装方法に納得感はないけど。mode_prompt で改行を出力できない仕様はなんのためなんだろう。
あ、自分はついでにモードの表示が I, N, V とか表示しなくても色で分かるしダサいやん?って思ったので Nerd Font に中身を変えました。
サクッと他のものも設定してしまいます。そう right_prompt の内容が右側だと見にくいので prompt に持ってきちゃいましょう。
同じ要領で right_prompt ファイルの中身を全てコメントアウトします。そして __bobthefish_cmd_duration、__bobthefish_pretty_ms、__bobthefish_timestamp 関数を prompt ファイルにコピーします。
表示場所としてはプロンプトの一番最後、newline で改行がされる直前に挿入したいので、theme_newline_cursor で改行が行われている部分を探します。すると __bobthefish_finish_segments 関数の中に追加すればよさそうなことが分かりますね。ということで theme_newline_cursor で分岐する直前に実行時間、タイムスタンプを表示する処理を追加します。
set_color $fish_color_autosuggestion
echo -n (__bobthefish_cmd_duration)
echo -n (__bobthefish_timestamp)
set_color normal
if [ "$theme_newline_cursor" = 'yes' ]
以上!
まとめ
会社に入って研修受けてたら同期から starship というのが最近イケてると聞いて、実行結果との間に空行挟むことで縦の区切りがわかりやすくて読みやすかったり、入力欄の前に改行していることでカーソル位置を見失わない等の点がいいなと思った(改行しか評価してないな俺?)。
一方、git の状態を絵文字で表すのが自分的には分かりにくい&オシャレじゃないと思ったのと元々の bobthefish の見た目を気に入っていたので、両方を組み合わせた感じになるようにカスタマイズした。
fish のいいところは大してカスタマイズしないでも便利だからコストが低いことで、それにかまけて今まで基本的なことすらなんも勉強してなかったので今回楽しかった。どれがプラグインで作られたファイルなのかとかわかってなかったし。次は fish_greeting.fish とかをちゃんと弄って楽しい感じにしたい。
今回の変更とかもしてある私の dotfiles はここにあります。