GA

2022/02/28

MySQL Shellのプロンプトをゼロからカスタマイズしてみんとす(classとsegment)

TL;DR


前回作ったところから。


$ mysqlsh -S /usr/mysql/8.0.28/data/mysql.sock -uroot --database d1

root@150-95-141-50 [d1] (READ_WRITE)>

root@150-95-141-50 [d1] (READ_WRITE)> SHOW TABLES;
SyntaxError: Unexpected identifier

( ゚д゚) そう、何も指定していないのでこれはJavaScriptモードなのである。

メインで使う時はSQLモードなので、「SQLモードの時はこのまま、それ以外のモードの時はなんか出したい」と思う。

$ cat ~/.mysqlsh/prompt.json
{
  "variables":
  {
    "read_only_str":
    {
      "match":
      {
        "pattern": "OFF",
        "value": "%sysvar:read_only%"
      },
      "if_true": "READ_WRITE",
      "if_false": "READ_ONLY"
    },
    "base_prompt":
    {
      "match":
      {
        "pattern": "",
        "value": ""
      },
      "if_true": "%user%@%sysvar:hostname% [%schema%] (%read_only_str%)"
    },
    "mode_based_prompt":
    {
      "match":
      {
        "pattern": "SQL",
        "value": "%Mode%"
      },
      "if_true": "%base_prompt%> ",
      "if_false": "%base_prompt%\n%Mode%> "
    }
  },
  "prompt": { "text": "%mode_based_prompt%" }
}

$ mysqlsh -S /usr/mysql/8.0.28/data/mysql.sock -uroot --database d1
root@150-95-141-50 [d1] (READ_WRITE)
JS> \py
Switching to Python mode...
root@150-95-141-50 [d1] (READ_WRITE)
Py> \sql
Switching to SQL mode... Commands end with ;
Fetching table and column names from `d1` for auto-completion... Press ^C to stop.
root@150-95-141-50 [d1] (READ_WRITE)>

うん、想像通りに動いてはいそう。
はい次、 READ_ONLY の場合は赤文字とかにしたい。

$ cat ~/.mysqlsh/prompt.json
{
  "variables":
  {
    "read_only_str":
    {
      "match":
      {
        "pattern": "OFF",
        "value": "%sysvar:read_only%"
      },
      "if_true": "READ_WRITE",
      "if_false": "READ_ONLY"
    },
    "read_only_color":
    {
      "match":
      {
        "pattern": "OFF",
        "value": "%sysvar:read_only%"
      },
      "if_true": "green",
      "if_false": "red"
    },
    "base_prompt":
    {
      "match":
      {
        "pattern": "",
        "value": ""
      },
      "if_true": "%user%@%sysvar:hostname% [%schema%] (%read_only_str%)"
    },
    "mode_based_prompt":
    {
      "match":
      {
        "pattern": "SQL",
        "value": "%Mode%"
      },
      "if_true": "%base_prompt%> ",
      "if_false": "%base_prompt%\n%Mode%> "
    }
  },
  "prompt": { "text": "%mode_based_prompt%", "fg": "%read_only_color%" }
}

長くなってきた…。

$ mysqlsh -S /usr/mysql/8.0.28/data/mysql.sock -uroot --database d1 --sqlc

Error loading prompt theme '/home/yoku0825/.mysqlsh/prompt.json': Error loading prompt theme: Invalid color value %read_only_color%

あれ、食えない…。
固定文字列で “red” とか “green” って入れると通るんだけどなあ。

色々納得はいかないけれど、何パターンかトライアンドエラーで頑張ってようやく classsegment の招待に行きついた。

classは俺が思っているclassとはちょっと違って textfg とかの要素を全部持たせてしまうものみたいな気がする(他のサンプルを見るに)

ということは、表示用の要素がそのまま詰まった変数みたいなものってことになる。まあ、そういうものだと思うことにしよう。。

そして segments の方は、理屈はわからないけれどどうも「 segments に列挙されたものを順番に並べて、最後に prompt に指定されたものを添えることでプロンプトを作る」みたいになっている。

たとえば segments から先だけを

  "segments":
  [
    { "classes": ["%read_only_str%"] },
    { "text": "%mode_based_prompt%" },
    { "text": "hogehoge" },
  ],
  "prompt": { "text": "pro" }

みたいにすると、

$ mysqlsh -S /usr/mysql/8.0.28/data/mysql.sock -uroot --database d1 --sqlc
READ_ONLY root@150-95-141-50 [d1] (READ_ONLY)>  hogehogepro

みたいになる。

こういうものだとわかれば、まあ、

  • class に表示したいものを詰める
  • segments にそれを列挙する
  • 今までさんざん頑張ってきたけど、 prompt はたぶんおまけ
    こういう風になるだろうか…。

話がひっくり返るけれど、 segments の中で class を展開するには

    { "classes": ["%read_only_str%"] },

こんな風にすると、カスタム変数 "class": "read_only_str" に対応する要素が展開される、っぽい。

$ cat ~/.mysqlsh/prompt.json
{
  "variables":
  {
    "read_only_str":
    {
      "match":
      {
        "pattern": "OFF",
        "value": "%sysvar:read_only%"
      },
      "if_true": "READ_WRITE",
      "if_false": "READ_ONLY"
    },
    "base_prompt":
    {
      "match":
      {
        "pattern": "",
        "value": ""
      },
      "if_true": "%user%@%sysvar:hostname% [%schema%] "
    },
    "mode_based_prompt":
    {
      "match":
      {
        "pattern": "SQL",
        "value": "%Mode%"
      },
      "if_true": "%base_prompt% ",
      "if_false": "%base_prompt%\n%Mode% "
    }
  },
  "classes":
  {
    "READ_ONLY":
    {
      "text": "(READ_ONLY)",
      "fg": "red"
    },
    "READ_WRITE":
    {
      "text": "(READ_WRITE)",
      "fg": "green"
    }
  },
  "segments":
  [
    { "text": "%mode_based_prompt%" },
    { "classes": ["%read_only_str%"] },
  ],
  "prompt": { "text": "> " }
}

というわけでこうすると

こうなった。

0 件のコメント :

コメントを投稿