LoginSignup
2
0

More than 1 year has passed since last update.

Zshのコマンドプロンプトを七色に輝かせるまで🌈

Last updated at Posted at 2023-06-04

概要

あなたのキーボードは光りますか?
もちろん光りますよね。その方がかっこいいからです。

ではあなたのコマンドプロンプトは光りますか?
もし光らないのであれば、この記事を読んで光らせてみませんか?

以下では、chameleonという七色に輝くコマンドプロンプトを開発するまでの道のりをまとめていきます。

asciicast

対象読者

  • コマンドプロンプトの自作に興味があって、手ごろな実装例を探している方
  • コマンドプロンプトを輝かせたい方

開発までの道のり

最小構成

ボトムアップに作り始めましょう。コマンドプロンプトを設定するために必要なファイルは、prompt_chameleon_setupというファイルのみです(chameleonの部分は任意の名前だから適宜読み替えてください)。実際はchameleon.zshのようなファイルを用意してシンボリックリンクを張ることが多いようです1

chameleon.zsh
prompt_chameleon_setup() {
  typeset -g prompt_chameleon_color='#FF0000' # 赤!
  PROMPT='%F{$prompt_chameleon_color}❯ %f' # プロンプトの文字や色の指定
  prompt_opts=(percent subst) # これがないと上記のPROMPTが展開されず文字通り解釈される
}
prompt_chameleon_setup "$@"

シンボリックリンクも作成すると、このcommitの状態になります。このディレクトリで以下を実行すると、chameleonが有効化され赤いのプロンプトが表示されます。ひとまず動きました。

fpath+=($(pwd))
autoload -U promptinit; promptinit
prompt chameleon

再描画

さて、色を徐々に変えるにはどうしたらよいでしょうか?コマンドを実行する度に色を変えるなら、precmdというhookを使うことができます。ただし今回はコマンド入力中も徐々に色を変えたいから不採用です。

TMOUTを利用するハックなら、この条件をクリアできます。ただ、更新間隔を1秒より短くできないという問題があり微妙です2

最終的に今回の要件に合致したのは、zsh-asyncというライブラリでした。.zshrcに以下を追記すると、まだの場合にインストールしてくれます。

.zshrc
if ! [[ -d ~/.zsh/zsh-async ]]; then
  git clone https://github.com/mafredri/zsh-async.git "$HOME/.zsh/zsh-async"
fi
source $HOME/.zsh/zsh-async/async.zsh

async_init async_start_worker async_register_callback async_jobなどが使えるようになるので、先ほどのスクリプトに追記をしましょう。これで0.5秒おきにプロンプトが再描画されるようになります。

chameleon.zsh
prompt_chameleon_gradation() {
  prompt_chameleon_color='#000000' # 黒!
}

prompt_chameleon_refresh() {
  prompt_chameleon_gradation
  zle reset-prompt # 再描画
  async_job chameleon sleep $prompt_chameleon_interval # 0.5秒待つだけのjobを再度積む
}

prompt_chameleon_setup() {
  typeset -g prompt_chameleon_color='#FF0000'
  PROMPT='%F{$prompt_chameleon_color}❯ %f'
  prompt_opts=(percent subst)

  typeset -g prompt_chameleon_interval=0.5
  async_init # 初期化
  async_start_worker chameleon # cameleonというworkerを用意
  async_register_callback chameleon prompt_chameleon_refresh # job実行の度にprompt_chameleon_refresh
  async_job chameleon sleep $prompt_chameleon_interval # 0.5秒待つだけのjobを積む
}
prompt_chameleon_setup "$@"

ここまで作業するとこのcommitの状態になります。先ほどと同様の方法でcameleonを有効化すると一瞬赤いプロンプトが表示されてすぐに黒くなることが確認できると思います。

グラデーション

先ほどは赤いプロンプトを黒く変えるだけでしたが、本来の目的は七色に輝かせることでした。そのためのprompt_chameleon_gradationは以下です。先ほどの実装を置き換えてください。

2023/06/06 @ko1nksm さんのコメントを参考に修正

chameleon.zsh
prompt_chameleon_gradation() {
  local temp=$prompt_chameleon_color

  local -A rgb
  rgb=(
    r 0x${temp:1:2}
    g 0x${temp:3:2}
    b 0x${temp:5:2}
  )

  local increment=30
  if (( rgb[r] == 255 )) && (( rgb[g] < 255 )) && (( rgb[b] == 0 )); then
    # red -> yellow
    rgb[g]=$((rgb[g] + increment))
    rgb[g]=$((rgb[g] < 255 ? rgb[g] : 255))
  elif (( rgb[r] > 0 )) && (( rgb[g] == 255 )) && (( rgb[b] == 0 )); then
    # yellow -> green
    rgb[r]=$((rgb[r] - increment))
    rgb[r]=$((rgb[r] < 0 ? 0 : rgb[r]))
  elif (( rgb[r] == 0 )) && (( rgb[g] == 255 )) && (( rgb[b] < 255 )); then
    # yellow -> aqua
    rgb[b]=$((rgb[b] + increment))
    rgb[b]=$((rgb[b] < 255 ? rgb[b] : 255))
  elif (( rgb[r] == 0 )) && (( rgb[g] > 0 )) && (( rgb[b] == 255 )); then
    # aqua -> blue
    rgb[g]=$((rgb[g] - increment))
    rgb[g]=$((rgb[g] < 0 ? 0 : rgb[g]))
  elif (( rgb[r] < 255 )) && (( rgb[g] == 0 )) && (( rgb[b] == 255 )); then
    # blue -> purple
    rgb[r]=$((rgb[r] + increment))
    rgb[r]=$((rgb[r] < 255 ? rgb[r] : 255))
  elif (( rgb[r] == 255 )) && (( rgb[g] == 0 )) && (( rgb[b] > 0 )); then
    # purple -> red
    rgb[b]=$((rgb[b] - increment))
    rgb[b]=$((rgb[b] < 0 ? 0 : rgb[b]))
  fi

  for key in ${(k)rgb}; do
    printf -v "rgb[$key]" "%02x" $rgb[$key]
  done
  prompt_chameleon_color='#'${rgb[r]}${rgb[g]}${rgb[b]}
}

この状態のcommitがこれです。ようやく七色に輝きました。

仕上げ

あとは何かエラーが生じた場合にworkerを再起動する設定を足したり、zsh-asyncが未インストールの場合の対応を追記したら完成です。これについてはmainブランチの実装を見てください。

最後に

ちゃんと実用的にするならカレントディレクトリやGitの情報も表示するべきですが、今回は自由研究程度のつもりだったのでそこまではやりませんでした。とはいえせっかく実装したので、興味があればREADMEを見てインストールして遊んでみてください。

いつか時間があるときに、最強の輝くコマンドプロンプトを作ってみたいものですね。

  1. 例えばpure

  2. chameleonでは、この方法をフォールバックとして採用しています。

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0