【NYAGOS】プロンプトで使える特殊文字と ANSI エスケープシーケンスを Lua でラップする
2018/12/01 追記
- シンタックスハイライトを適用しました。
前書き
前回の記事でプロンプトをごにょごにょしていたんですが、プロンプトだけで使える特殊文字だとか、ANSI エスケープシーケンスだとかをいちいち文字列で書くのが面倒になりました。
そもそもぱぱっと書けませんし読めませんよそんなもん。ゆとり教育では学びませんでした。
しかし、現代では教育だけでなくマシンの CPU やメモリもゆとりが出てきています。可読性を高めるため、全部 Lua でラップしてしまいましょう。
プロンプトだけで使える特殊文字
色々探していたらMSDNに一覧がありました。ここには転記しません。かわりに今回使うコードを載せます。
share.prompt = { eq='$q', -- equal '=' dollar='$$', -- dollar '$' time='$t', -- current time date='$d', -- current date path='$p', -- current path (with drive letter) ver='$v', -- windows version drive='$n', -- current drive letter gt='$g', -- greater than '>' lt='$l', -- less than '<' pipe='$b', -- pipe '|' crlf='$_', -- line break esc='$e', -- escape bs='$h', -- backspace amp='$a', -- ampersand '&' l_par='$c', -- left parenthesis '(' r_par='$f', -- right parenthesis ')' space='$s', -- space }
ちなみに$
の後の文字は大文字・小文字を区別しないそうです。
また、$h
(backspace)は$t
(time)とか$d
(date)とかでとってきた文字列を頑張って削る時に使うそうです。全くもってゆとりがありません。
ANSI エスケープシーケンス
ANSI エスケープシーケンス自体についてはこの記事が非常にわかりやすかったです。歴史的経緯や古き良き C 言語のサンプルもちょこっと書いてあるので、暇な人は読んでみましょう。
細かい一覧は英語版 Wikipediaを読むのが一番いいんですが、何をどれだけ読もうとも、Nyagos で使えるのはansicolorに書いてあるやつだけです。なので、ここだけラップします。
ANSI エスケープシーケンスのラップ
ANSI エスケープシーケンスはプロンプト以外でも普通に使えるので、先ほど作ったshare.prompt
テーブルにぶちこむのは流石に乱暴です。
別途share.escape_sequence
と言うテーブルを作ります。
share.escape_sequence = { -- attribute attr = { off='0', bold='1', bold_off='21', underline='4', underline_off='24', blink='5', blink_off='25' }, -- foreground fg = { black='30', red='31', green='32', yellow='33', blue='34', magenta='35', cyan='36', white='37', default='39', -- prefix 'l' is 'Light' l_gray='90', l_red='91', l_green='92', l_yellow='93', l_blue='94', l_magenta='95', l_cyan='96', l_white='97' }, -- background bg = { black='40', red='41', green='42', yellow='43', blue='44', magenta='45', cyan='46', white='47', default='49', -- prefix 'l' is 'Light' l_gray='100', l_red='101', l_green='102', l_yellow='103', l_blue='104', l_magenta='105', l_cyan='106', l_white='107' }, }
ANSI エスケープシーケンスの文法
厳密にはANSI エスケープシーケンスにおける色付けの文法ですが…。
基本的には\x1b[(該当するコード)m
と言う文字列を作成します。例えば、赤字にしたいなら\x1b[31m
ですね。
「ここからここまでの文字列に適応する」と言った指定はできないため、適用させた後は再度 ANSI エスケープシーケンスを作って元に戻す必要があります。(そのためにdefault
とかoff
と言った要素がある。)ちなみにこれを忘れるとその後の標準出力がずっと真っ赤になったりします。怖いですね。
また、複数の要素を一気に指定したい場合は\x1b[(該当するコード);(該当するコード);...m
と記述することができます。例えば、文字色は赤字、背景色は灰色、ついでに下線も引いてやろう、って場合は、\x1b[31;100;4m
となります。指定するコードの順番に制限はないです。(つまり、\x1b[4;100;31m
でも同じ効果を得られる。)
ANSI エスケープシーケンスを作成する関数
上記の内容を踏まえ、share.escape_sequence
に各コードのテーブルを渡すと ANSI エスケープシーケンスを作ってくれる関数を作ります。
share.escape_sequence = { -- ...省略... create_sequence = function(...) local attrs = {...} local joined_attrs = '' for n, v in pairs(attrs) do local val = tostring(v) if val ~= nil then joined_attrs = joined_attrs ~= '' and joined_attrs .. ';' .. val or val end end return string.format('\x1b[%sm', joined_attrs) end }
呼び出しはこんなイメージです。何をやっているのか大分わかりやすくなったと思いませんか?
local esc = share.escape_sequence -- colorに'\x1b[2;31;49m'が返ってくる local color = esc.create_sequence(esc.attr.bold, esc.fg.red, esc.bg.default)
実践
実践って言うか、単に私の.nyagos
の中身から抜粋しただけですが…。
share.org_prompter=nyagos.prompt nyagos.prompt = function(this) local prompt = share.prompt local esc = share.escape_sequence -- add dir name (with drive letter) local c_dir = esc.create_sequence(esc.attr.bold, esc.fg.red) local prompt_message = string.format('%s[%s]', c_dir, prompt.path) -- check git branch local git_branch_name = nyagos.eval('git rev-parse --abbrev-ref HEAD 2>nul') if (git_branch_name ~= '') then -- add git branch name local c_branch = esc.create_sequence(esc.fg.l_yellow) prompt_message = string.format(prompt_message .. ' %s[%s]', c_branch, git_branch_name) end -- add line break prompt_message = prompt_message .. prompt.crlf -- add dollar local c_dollar = esc.create_sequence(esc.fg.red) prompt_message = prompt_message .. c_dollar .. prompt.dollar -- add input command color local c_input_command = esc.create_sequence(esc.fg.white) prompt_message = string.format(prompt_message .. ' %s', c_input_command) return share.org_prompter(prompt_message) end
元々が冗長な仕組みなので仕方ないんですが、どうしても長くなってしまいますね。
まとめ
プロンプトの方はともかく、ANSI エスケープシーケンスの方は何かに応用できるかもしれません。(エラーメッセージに色を付ける、とか…。)
現状は全くのノーアイデアです。何か思いついたらまた作りましょう。