startshipでゲーミングプロンプトにしてみた
完成図
こういうのを作ります。リソースの無駄
やることざっくり
starshipを使ってカラフルなプロンプトを作る
starshipの設定ファイルを操作するPythonスクリプトを作る
.zshrcを使って1コマンドごとにPythonを走らせる
原理的なところでいうと別にstarshipである必要性もPythonである必要性もありませんが、starshipの使い方の練習を兼ねて遊んでみました。
starshipの導入と設定
starshipとは
シェル用のプロンプトツールです。
軽量でカスタマイズ性が高いことをウリにしているようですね。
インストール
上のリンク先に従ってインストールします。
私の環境はArch Linuxなのでパケマネから直接入れましたが、Rustがインストールされているならcargoでインストールするのが手っ取り早いかもしれません。
cargo install starship --locked
インストールしたらシェルのrcファイルに必要なものを追記します。zshの場合
eval "$(starship init zsh)"
です。
プリセットのダウンロード
Configurationを頼りにゼロから設定をするほどの知識とスキルはないので、プリセットをダウンロードして改造します。
私はTokyo Nightがいいと思ったのでそれにしました。
設定ファイルのダウンロードも各プリセットのページ内のコードを実行するだけでできます。
starship preset tokyo-night -o ~/.config/starship.toml
(必要に応じて)ターミナルのフォントを変更する
TokyoNightのプリセット紹介ページのスクリーンショットには頭にりんごの絵文字が表示されていますが、ターミナルのフォントの設定によってはユニコードの絵文字が正常に表示されないことがあると思います。
調べてみたところNerd Fontsというフォント群が絵文字対応に力を入れているようなので、必要であればダウンロードしてターミナルのフォントを変更します。
Arch Linuxの場合、パケマネでインストールできます。
starshipの設定
上のプリセットダウンロードスクリプトからもわかるように、startshipは~/.config/starship.tomlファイルで各種設定をします。
(環境変数STARSHIP_CONFIGで設定ファイルのパスを変えることもできます)
ファイルを編集すれば特に何もしなくても次のプロンプトは設定が反映されるので、ログインしなおしたり「source .zshrc」する手間はありません。
TokyoNightの場合次のようになっています。
format = """
[░▒▓](#a3aed2)\
[ ](bg:#a3aed2 fg:#090c0c)\
[](bg:#769ff0 fg:#a3aed2)\
$directory\
[](fg:#769ff0 bg:#394260)\
$git_branch\
$git_status\
[](fg:#394260 bg:#212736)\
$nodejs\
$rust\
$golang\
$php\
[](fg:#212736 bg:#1d2230)\
$time\
[ ](fg:#1d2230)\
\n$character"""
[directory]
style = "fg:#e3e5e5 bg:#769ff0"
format = "[ $path ]($style)"
truncation_length = 3
truncation_symbol = "…/"
[directory.substitutions]
"Documents" = " "
"Downloads" = " "
"Music" = " "
"Pictures" = " "
[git_branch]
symbol = ""
style = "bg:#394260"
format = '[[ $symbol $branch ](fg:#769ff0 bg:#394260)]($style)'
[git_status]
style = "bg:#394260"
format = '[[($all_status$ahead_behind )](fg:#769ff0 bg:#394260)]($style)'
[nodejs]
symbol = ""
style = "bg:#212736"
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
[rust]
symbol = ""
style = "bg:#212736"
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
[golang]
symbol = ""
style = "bg:#212736"
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
[php]
symbol = ""
style = "bg:#212736"
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
[time]
disabled = false
time_format = "%R" # Hour:Minute Format
style = "bg:#1d2230"
format = '[[ $time ](fg:#a0a9cb bg:#1d2230)]($style)'
私はtomlのフォーマットをそもそもよくわかっていないので理解するのに時間がかかってしまいましたが、およそ次のような法則になっているようです。
[]と():クォーテーションの中に入っている[ ]と( )はそれぞれ「入力内容」と「スタイル(見た目)」を指定するための記号になっているので、文字として出力するにはエスケープしなければなりません。
一番上のformat:プロンプト全体の順番や構成要素を指定します。
[ ]で囲まれた項目:プロンプト内の各要素の詳細をオプションを使って個別にで設定します。
各要素にどんなオプションがあってどんな値を取れるかはconfigurationページを参考にします。
例えばformatの
[](bg:#769ff0 fg:#a3aed2)\
の部分は「」という文字列リテラルを背景の色#769ff0、文字色#a3aed2で表示させています。繰り返しになりますが、[]と()は表示されません。
また、この設定ファイルのformatは""" """で囲まれているため内部の改行をそのままプロンプトとして表示させてしまうので、行末にバックスラッシュを付けて防止しています。試しに「\」を消してみると、プロンプトが改行されてることが確認できると思います。
「」はプロンプトの見た目を整えるためだけの文字列リテラルなのでスタイルをformat内で指定していますが、ユーザー名やホスト名などのオプションはそれぞれ個別の設定のところでスタイルも一緒に設定しています。
[directory]
style = "fg:#e3e5e5 bg:#769ff0"
format = "[ $path ]($style)"
truncation_length = 3
truncation_symbol = "…/"
例えばdirectoryオプションの場合、styleに"fg:#e3e5e5 bg:#769ff0"を指定して、[directory]の中のformatで文字列にスタイルを適用させています。
他にもいくつかオプションが指定されており、これらはconfigurationページで解説されています。
ゲーミングにする
設定の仕方があらかた把握できたので、ゲーミングにします。
カスタムプロンプトを作る
TokyoNightでは色調が青系で統一されていますが、ゲーミング色といえば全色相を一周するものなので、各オプションの色の色相を少しずつずらします。
また、私はgitやphpなどを使わないのでそれらをすべて削除して、メモリ使用量などを加えて作ったものが以下の設定になります。
format = """
[░▒▓](#cccc65)\
[ 🦀 ](fg:#757500 bg:#cccc65)\
[](fg:#cccc65 bg:#65cc65)\
$username\
$hostname\
[](fg:#65cc65 bg:#65cccc)\
$directory\
[](fg:#65cccc bg:#6565cc)\
$memory_usage\
[](fg:#6565cc bg:#cc65cc)\
$time\
[ ](fg:#cc65cc)\
\n$character"""
[username]
disabled = false
style_user = "fg:#3842b7 bg:#65cc65"
show_always = false
format = '[ $user]($style)'
[hostname]
disabled = false
style = "fg:#4238b7 bg:#65cc65"
ssh_only = true
format = '[ @ $hostname ]($style)'
[directory]
disabled = false
style = "fg:#793e3e bg:#65cccc"
format = "[ $path ]($style)"
truncation_length = 3
truncation_symbol = "…/"
[directory.substitutions]
"Documents" = " "
"Downloads" = " "
"Music" = " "
"Pictures" = " "
"dev" = "💻 "
[memory_usage]
disabled = false
threshold = -1
symbol = ' RAM'
style = "fg:#fec1e0 bg:#6565cc"
format = '[$symbol $ram]($style)'
# format = '[ $ram \($ram_pct\)]($style)'
[time]
disabled = false
time_format = "%R" # Hour:Minute Format
style = "bg:#ffffff"
format = '[[ $time ](fg:#650ac1 bg:#cc65cc)]($style)'
[character]
disabled = false
success_symbol = "[>>>](fg:#ffffff bg:#6ddb00)"
error_symbol = "[<<<](fg:#24190e bg:#006ddb)"
vimcmd_symbol = "[vIn](fg:#021130 bg:#00db24)"
format = '$symbol '
安全のために、設定ファイルはシンボリックリンクにする
生成した新しいファイルで~/.config/starship.tomlを上書きしてもいいですが、そうすると別のファイルに差し替えるときうっかりバックアップを忘れたりすることもあるかもしれません。なので、設定ファイルは一か所に集めて、シンボリックリンクを生成した方が安全です。
ln -sf /path/to/file ~/.config/starship.toml
色相を回す方法
色んな色が並んでるだけでもゲーミングと言えなくはないですが、やっぱりゲーミングといえばやかましく動いてこそだと思うので、設定ファイルの色相を回せるようにします。
今回Pythonを使って
設定ファイルの全文を取得する
正規表現を使ってカラーコードの箇所を取得する
colorsysパッケージでRGBをHSLやHSVに変換
H(色相)を回す
colorsysパッケージでRGBに変換
カラーコードの文字列にして元のコードと置換
という力業ですることにしました。
他にもっと上手いやり方があるかもしれませんが、私には思いつかなかったので。
import colorsys
import re
def irgb2hex(r, g, b):
# RGBの整数値(0~255)からカラーコードを生成
return f"#{r:02x}{g:02x}{b:02x}"
def hex2rgb(hexstr):
# カラーコードから整数のRGBを生成
if len(hexstr) == 7:
hexstr = hexstr[1:]
elif len(hexstr) != 6:
raise ValueError("Invalid input string")
return tuple(int(hexstr[i:i + 2], 16) for i in (0, 2, 4))
def turn_hue_of_hex(hexstr, degree, absolute=False):
# RGBをHSVに変えてHを変更してRGBに戻したカラーコードを生成
# absoluteがFalseだと相対値、Trueだと絶対値
r, g, b = hex2rgb(hexstr)
h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255)
if absolute:
h = degree / 360
else:
h = h + degree / 360
r, g, b = tuple(int(i*255) for i in colorsys.hsv_to_rgb(h, s, v))
return f"#{r:02x}{g:02x}{b:02x}"
if __name__ == "__main__":
# ファイル編集
fpath = "/path/to/file"
with open(fpath, "r") as f:
body = f.read()
matches = re.findall(r"#[0-9a-fA-F]{6}", body)
for m in set(matches):
hex_new = turn_hue_of_hex(m, 25, absolute=False)
body = body.replace(m, hex_new)
with open(fpath, "w") as f:
f.write(body)
コマンド実行ごとにpythonを実行する
シェルで何かを実行するごとにプロンプトを変えたいのでいい方法がないかChatGPTに聞いてみたところ、新しいプロンプトが表示される直前に毎回実行される「precmd」という関数があると教えてくれたので、.zshrcに追記します。
precmd(){
python /path/to/python/script
}
そして.zshrcをsourceすれば、冒頭の動画のような状態になります。
所感
配色が難しい。時々文字が見にくくなる
ファイルの書き換え途中にパソコンが落ちたりするかもしれないし安全性が心配
裏で重い作業回したりするとまともに動かなくなるんじゃないか?
書き換えスクリプトは別の言語でもっと軽く作れると思うけど得るものがなさすぎる
受け狙いの一発ネタとしてはいいかもしれない