19
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Fishの色設定をターミナルだけで完結する

Last updated at Posted at 2020-05-22

Fishの魅力のひとつに「ブラウザからカラーテーマが変更できる」というものがあります。
私も使い始めた頃はこの恩恵に預かっていたものの、次第にこんな悩みが出てきました。

  • Vimのターミナルで正常な色が出てこない
  • コマンドラインと出力の色が一致しない
  • 別環境での再現が面倒だし、dotfilesで管理もできない
  • そもそもブラウザが開けない環境では設定すらできない

これらが結構致命的だったため過去にこんなプラグインを作ったものの、いろいろあって以下の方法にすることにしました。

要約

  • fish_configでの色変更 = ただの変数定義
  • base16-shellを使おう
  • Fish バージョン 3.1.2 での話

入力の色設定

fish_configコマンドをPythonの存在しない環境下で実行すると以下の表示が出ます。

Cannot launch the web configuration tool:
fish_config requires Python.
Installing python2 or python3 will fix this, and also enable completions to be
automatically generated from man pages.

To change your prompt, create a fish_prompt function.
There are examples in $__fish_data_dir/tools/web_config/sample_prompts.

You can tweak your colors by setting the $fish_color_* variables.

つまりfish_color_で始まる変数を設定することでブラウザレスに色設定ができるというわけですね。

設定項目

まずは対象となる変数名を確認しておきましょう。公式に書いてありました。

変数名 (コマンドライン用) 対象 備考
fish_color_normal デフォルト1
fish_color_command コマンド
fish_color_quote クォートを含む文字列全体
fish_color_redirection リダイレクト >/dev/null など
fish_color_error エラーになる箇所
fish_color_end コマンド末端につけるもの
- コマンド終端 ;
- バックグラウンド実行 & など
fish_color_param コマンドの引数
fish_color_comment コメント
fish_color_match カーソル位置に対応する括弧
fish_color_selection viモード時visualでの選択箇所 -bもしくは-rによる背景色変更のみ可能
fish_color_search_match 履歴検索時の一致箇所
Fishでのデフォルト履歴検索は矢印キー上下
-bもしくは-rによる背景色変更のみ可能
fish_color_operator Fish内で使用する特殊記号
- $HOME ~
- ワイルドカード * など
fish_color_escape エスケープ文字 \n \x70など
fish_color_autosuggestion コマンドライン右側に出てくるコマンドや引数の入力候補
fish_color_cwd カレントワーキングディレクトリ デフォルトのプロンプトでのみ使用
fish_color_user ユーザー名 デフォルトのプロンプトでのみ使用
fish_color_host ホスト名 デフォルトのプロンプトでのみ使用
fish_color_host_remote リモートホスト名 デフォルトのプロンプトでのみ使用
fish_color_cancel killシグナル ^C
変数名 (ページャー2用) 対象 備考
fish_pager_color_progress ページャー下部にある行数表示部分
fish_pager_color_background ページャーの背景 -bもしくは-rによる背景色変更のみ可能
fish_pager_color_prefix 一致部分
fish_pager_color_completion 補完部分
fish_pager_color_description 説明文
fish_pager_color_secondary_X 非選択箇所の色を上書き。
以下の要素がXに入る。
- background
- prefix
- completion
- description
未指定の場合はそれぞれの
fish_pager_color_X を継承する
fish_pager_color_selected_X 選択箇所の色を上書き。
以下の要素がXに入る。
- background
- prefix
- completion
- description
未指定の場合はそれぞれの
fish_pager_color_X を継承する

設定方法

つぎに設定方法ですね。ソースコードを読むと以下のことがわかります。

  • 色設定の方法は2通り
    • RGB形式による指定
    • 色名による指定
  • その他 set_color のオプションも一部使用可能
    • -b , --background
      背景色の指定。set_colorと違って = でつなげる必要あり
      ただしこのオプションが反映されてない不具合がいくつか確認されているので気休め程度に。
    • -d , --dim
      色を暗くする。
    • -i , --italics
      斜体にする。
    • -o , --bold
      太字にする。
    • -r , --reverse
      文字色を背景色にして抜き文字で表示する。

色設定について、前者は以下の形式ができるとのこと。

// We support the following style of rgb formats (case insensitive):
// #FA3
// #F3A035
// FA3
// F3A035

対して後者はこんな感じ。接頭辞のbrbrightを意味するものと思われます。

色名 ANSIカラー インデックス
black 0
red 1
green 2
yellow
brown
3
blue 4
magenta
purple
5
cyan 6
white
grey
7
brblack
brgrey
8
brred 9
brgreen 10
bryellow
brbrown
11
brblue 12
brmagenta
brpurple
13
brcyan 14
brwhite 15

問題はどちらを採用するかですが、私は後者の色名指定にしました。
GNOME-terminalやiTerm2しか使わない理想的環境下であれば前者でもいいのですが、それ以外の状況下では常に指定した色を確実に出力してくれる保証もなければ後述する理由で細かい色指定をする必要がないこともあり、いかなる環境下でも最低限「だいたいの色ルール」を維持しておきたいということでこうなりました。

できたもの

というわけで私のconfig.fishには以下の記述が入っています。
brだらけなのは視認性向上のため。

config.fish
# 色配置は次のコマンドの出力に基づいています
# fish-vimcolor onedark

# commandline
set fish_color_normal         brwhite
set fish_color_autosuggestion brblack
set fish_color_cancel         brcyan
set fish_color_command        brpurple
set fish_color_comment        brblack
set fish_color_cwd            brred
set fish_color_end            brwhite
set fish_color_error          brred
set fish_color_escape         brcyan
set fish_color_host           brgreen
set fish_color_host_remote    bryellow
set fish_color_match          brcyan --underline
set fish_color_operator       brpurple
set fish_color_param          brred
set fish_color_quote          brgreen
set fish_color_redirection    brcyan
set fish_color_search_match   --background=brblack
set fish_color_selection      --background=brblack
set fish_color_user           brblue

# pager
set fish_pager_color_progress              brblack --italics
set fish_pager_color_secondary_background  # null
set fish_pager_color_secondary_completion  brblack
set fish_pager_color_secondary_description brblack
set fish_pager_color_secondary_prefix      brblack
set fish_pager_color_selected_background   --background=brblack
set fish_pager_color_selected_completion   bryellow
set fish_pager_color_selected_description  bryellow
set fish_pager_color_selected_prefix       bryellow

出力の色設定

つづいて出力の色設定です。 ls -al --color=alwaysなどの色をコマンドで変えられます。

本来はターミナルの設定画面を開くなりしないと変えられないアウトプットカラーですが、コマンドラインから変更する方法もないわけではないためどの環境でも常に同じ色を瞬時に出力できるのです。

加えて出力のカラーパレットを上書きすることは前述の色名で指定したコマンドラインの色も連動的に変えられることも意味しています。これによりブラウザからの設定では絶対に実現し得ない100%のカラースキーム統一が実現できるのです。

出力の色はどうやって変えるのか

ここでは以前紹介したことのあるbase16-shellを使ってみます。
私としてはこんな理由があって使っています。

  • Fishにも対応している
  • プリセットが豊富
  • プリセットからの書き換えも楽
  • 10ミリ秒弱という実行コストの低さ
  • 1000超のスター数とIssuesの活発さによる安心感
  • そもそもbase16というプロジェクトが好き

以前はまだFishに対応もしていなかったり理解が足りていなかったこともあり雑なプラグインを作ってしまいましたが、久々に本家を見てみたらかなり進化していました。お気に入りのOneDarkもあって使わない手はないな、と。

使い方

公式の説明をまとめてconfig.fishに書くならこんな感じです。

config.fish
# base16-onedarkを設定したい
if status --is-interactive
    set -l BASH16_DIR ~/.config/base16-shell
    if test ! -d $BASH16_DIR
        git clone https://github.com/chriskempson/base16-shell.git $BASE16_DIR
    end
    source $BASE16_DIR/profile_helper.fish
    base16-onedark
end

しかしこのままだと問題がいくつか。

まず起動がほんのり遅くなります。timeコマンドで調べると私の環境では100 〜 200ミリ秒ほどかかっていました。anyenvほどじゃないけどやや重めといったところか。
調べてみるとprofile_helper.fishというもの、基本的にはテーマの数だけforで回してshスクリプトを呼び出すFish関数を作成するだけのものだったので、使いたいテーマが決まっていればそのshスクリプトを実行するだけで済むということがわかりました。

続いてわかったのが特定のターミナル環境だと上手くいかないということ。たとえばVim/NeovimのターミナルなどはFish側では何をやっても色はつかない……なので環境変数にVIMがあるときはbase16-shellの実行を回避してVim側で色設定3する必要があります。
こんな感じでうまくいかない場面はけっこうあるので、設定中にbegin; ...; endを作っておいてパスすればshを実行、とするといいでしょう。

というわけで上記を踏まえて書き換えたのが以下の通り。

config.fish
# base16-onedarkを設定したい
if status --is-interactive
    set -l BASH16_DIR ~/.config/base16-shell
    if type -q git; and test ! -d $BASH16_DIR
        git clone https://github.com/chriskempson/base16-shell.git $BASE16_DIR
    end

    begin
    	test -d $BASH16_DIR
        and not set -qx VIM    # Vim/Neovim
        and not set -qx VSCODE # VSCode with terminal.integrated.env.linux
    end
    if test $status -eq 0
        # POSIX準拠ではないらしいのでBashを強制
        bash $BASE16_DIR/scripts/base16-onedark.sh
    end
end

profile_helperなしでコマンドひとつでカラースキームを変えたい場合はこんなものを付け加えてみてはいかがでしょうか。

config.fish
# base16_theme -t monokai でテーマ変更が可能
function base16_theme -V BASE16_DIR -d "set base16 theme"
    argparse -n=base16_theme 't/transparent' -- $argv; or return
    test -z "$argv"; and return

    set -l theme $argv[1]
    set -lq _flag_transparent
        and set -x BASE16_SHELL_SET_BACKGROUND false # clear
        or  set -x BASE16_SHELL_SET_BACKGROUND true  # non-clear

    sh $BASE16_DIR/scripts/base16-$theme.sh
end

function pick_themes -V BASE16_DIR -d "list themes to complete base16_theme argument" 
    find $BASE16_DIR/scripts/*.sh -type f -printf '%f\n' \
        | string replace -ar '^base16-(.*)\.sh$' '$1' \
        | string join ' '
end

complete -c base16_theme -s t -l transparent -d "make transparent background"
complete -c base16_theme -xa (pick_themes)
functions -e pick_themes

カスタマイズ

以前紹介した通りこのshスクリプトはRGB形式で宣言した色コードを加工しprintfすることでターミナルのカラーパレットを上書きする手法を採っています。

printfによる上書きの原理こそややこしいですが、シェルスクリプトとしてはとても簡単なものになっているのでカスタマイズもそう難しくないと思います。

まとめ

以前書いた色コードの記事がほぼすべて無駄になり、おかげで様々なしがらみからも解放され、bcコマンドの勉強もできました。

皆様もぜひFishを使いましょう。

  1. これが適用されるところは見たことがないが、念の為設定しておくといいはず。

  2. Tabを2回押すと出てくる補完候補を一覧してくれるやつのこと。

  3. それぞれ Vimのターミナル色設定Neovimのターミナル色設定

19
11
0

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
19
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?