diff --git a/README-ja_JP.md b/README-ja_JP.md index 0ec2a9d5..50f3ccfe 100644 --- a/README-ja_JP.md +++ b/README-ja_JP.md @@ -346,6 +346,7 @@ ble-face -s syntax_default none ble-face -s syntax_command fg=brown ble-face -s syntax_quoted fg=green ble-face -s syntax_quotation fg=green,bold +ble-face -s syntax_escape fg=magenta ble-face -s syntax_expr fg=26 ble-face -s syntax_error bg=203,fg=231 ble-face -s syntax_varname fg=202 diff --git a/README.md b/README.md index 9dc2fd8c..173b3c2f 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,7 @@ ble-face -s syntax_default none ble-face -s syntax_command fg=brown ble-face -s syntax_quoted fg=green ble-face -s syntax_quotation fg=green,bold +ble-face -s syntax_escape fg=magenta ble-face -s syntax_expr fg=26 ble-face -s syntax_error bg=203,fg=231 ble-face -s syntax_varname fg=202 diff --git a/blerc b/blerc index 4ee659d5..78d04c0e 100644 --- a/blerc +++ b/blerc @@ -563,6 +563,7 @@ # ble-face -s syntax_command fg=brown # ble-face -s syntax_quoted fg=green # ble-face -s syntax_quotation fg=green,bold +# ble-face -s syntax_escape fg=magenta # ble-face -s syntax_expr fg=navy # ble-face -s syntax_error bg=203,fg=231 # ble-face -s syntax_varname fg=202 diff --git a/lib/core-syntax-ctx.def b/lib/core-syntax-ctx.def index a39c70be..1fe300f1 100644 --- a/lib/core-syntax-ctx.def +++ b/lib/core-syntax-ctx.def @@ -33,6 +33,7 @@ CTX_EXPR 8 # context,attr: in arithmetic expression ATTR_ERR 6 # attr: error ATTR_VAR 7 # attr: variable ATTR_QDEL 9 # attr: delimiters for quotation +ATTR_QESC 81 # attr: \q ATTR_DEF 10 # attr: default (currently not used) ATTR_DEL 12 # attr: delimiters ATTR_HISTX 21 # 履歴展開 (!!$ など) diff --git a/lib/core-syntax.sh b/lib/core-syntax.sh index 092412d0..e6c51678 100644 --- a/lib/core-syntax.sh +++ b/lib/core-syntax.sh @@ -1885,6 +1885,19 @@ function ble/syntax/highlight/vartype { fi } +function ble/syntax:bash/check-plain-with-escape { + local rex='^('$1'|\\.)' is_quote=$2 + [[ $tail =~ $rex ]] || return 1 + if [[ $BASH_REMATCH == '\'? && + ( ! $is_quote || $BASH_REMATCH == '\'[$'\\`$\n'] ) ]]; then + ((_ble_syntax_attr[i]=ATTR_QESC)) + else + ((_ble_syntax_attr[i]=ctx)) + fi + ((i+=${#BASH_REMATCH})) + return 0 +} + function ble/syntax:bash/check-dollar { [[ $tail == '$'* ]] || return 1 @@ -2015,7 +2028,7 @@ function ble/syntax:bash/check-quotes { fi if ((ctx!=CTX_QUOT)); then - if rex='^(\$?")([^'"${_ble_syntax_bash_chars[CTX_QUOT]}"']|\\.)*("?)' && [[ $tail =~ $rex ]]; then + if rex='^(\$?")([^'"${_ble_syntax_bash_chars[CTX_QUOT]}"']*)("?)' && [[ $tail =~ $rex ]]; then local rematch1=${BASH_REMATCH[1]} # for bash-3.1 ${#arr[n]} bug if [[ ${BASH_REMATCH[3]} ]]; then # 終端まで行った場合 @@ -2040,11 +2053,30 @@ function ble/syntax:bash/check-quotes { fi fi return 0 - elif rex='^\$'\''([^'\''\]|\\(.|$))*('\''?)' && [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=aqdel, - _ble_syntax_attr[i+2]=aquot, - i+=${#BASH_REMATCH}, - _ble_syntax_attr[i-1]=${#BASH_REMATCH[3]}?aqdel:ATTR_ERR)) + elif rex='^\$'\''(([^'\''\]|\\(.|$))*)('\''?)' && [[ $tail =~ $rex ]]; then + ((_ble_syntax_attr[i]=aqdel,i+=2)) + local t=${BASH_REMATCH[1]} rematch4=${BASH_REMATCH[4]} + + local rex='\\[abefnrtvE"'\''\?]|\\[0-7]{1,3}|\\c.|\\x[0-9a-fA-F]{1,2}' + ((_ble_bash>=40200)) && rex=$rex'|\\u[0-9a-fA-F]{1,4}|\\U[0-9a-fA-F]{1,8}' + local rex='^([^'\''\]*)('$rex'|(\\.))' + while [[ $t =~ $rex ]]; do + local m1=${BASH_REMATCH[1]} m2=${BASH_REMATCH[2]} + [[ $m1 ]] && ((_ble_syntax_attr[i]=aquot,i+=${#m1})) + if [[ ${BASH_REMATCH[3]} ]]; then + ((_ble_syntax_attr[i]=aquot)) + else + ((_ble_syntax_attr[i]=ATTR_QESC)) + fi + ((i+=${#m2})) + t=${t:${#BASH_REMATCH}} + done + [[ $t ]] && ((_ble_syntax_attr[i]=aquot,i+=${#t})) + if [[ $rematch4 ]]; then + ((_ble_syntax_attr[i++]=aqdel)) + else + ((_ble_syntax_attr[i-1]=ATTR_ERR)) + fi return 0 fi fi @@ -2318,10 +2350,7 @@ function ble/syntax:bash/starts-with-histchars { _BLE_SYNTAX_FCTX[CTX_QUOT]=ble/syntax:bash/ctx-quot function ble/syntax:bash/ctx-quot { # 文字列の中身 - local rex - if rex='^([^'"${_ble_syntax_bash_chars[CTX_QUOT]}"']|\\.)+' && [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[CTX_QUOT]}]+" 1; then return 0 elif [[ $tail == '"'* ]]; then ((_ble_syntax_attr[i]=ATTR_QDEL, @@ -2379,9 +2408,7 @@ function ble/syntax:bash/ctx-globpat/get-stop-chars { function ble/syntax:bash/ctx-globpat { # glob () の中身 (extglob @(...) や case in (...) の中) local chars; ble/syntax:bash/ctx-globpat/get-stop-chars - if local rex='^([^'$chars']|\\.)+'; [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + if ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then return 0 elif ble/syntax:bash/check-process-subst; then return 0 @@ -2484,9 +2511,7 @@ function ble/syntax:bash/ctx-bracket-expression { ((_ble_syntax_attr[i]=${force_attr:-ctx}, i+=${#BASH_REMATCH})) return 0 - elif rex='^([^'$chars']|\\.)+' && [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=${force_attr:-ctx}, - i+=${#BASH_REMATCH})) + elif ctx=${force_attr:-$ctx} ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then return 0 elif ble/syntax:bash/check-process-subst; then return 0 @@ -2603,10 +2628,7 @@ function ble/syntax:bash/ctx-param { } function ble/syntax:bash/ctx-pword { # パラメータ展開 - word 部 - local rex - if rex='^([^'"${_ble_syntax_bash_chars[ctx]}"']|\\.)+' && [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}]+"; then return 0 elif ((ctx==CTX_PWORDR)) && [[ $tail == '/'* ]]; then ((_ble_syntax_attr[i++]=CTX_PARAM,ctx=CTX_PWORD)) @@ -2782,9 +2804,7 @@ function ble/syntax:bash/ctx-expr { elif rex='^0[xX][0-9a-fA-F]*|^[0-9]+(#[0-9a-zA-Z@_]*)?'; [[ $tail =~ $rex ]]; then ((_ble_syntax_attr[i]=ATTR_VAR_NUMBER,i+=${#BASH_REMATCH})) return 0 - elif rex='^([^'"${_ble_syntax_bash_chars[ctx]}"'a-zA-Z_0-9]|\\.)+'; [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}a-zA-Z_0-9]+" 1; then return 0 elif [[ $tail == ['][()}']* ]]; then local char=${tail::1} ntype @@ -2952,9 +2972,7 @@ function ble/syntax:bash/ctx-brace-expansion { local chars=",${_ble_syntax_bash_chars[CTX_ARGI]//'~:'}" ((ctx==CTX_BRACE2)) && chars="}$chars" ble/syntax:bash/cclass/update/reorder chars - if local rex='^([^'$chars']|\\.)+'; [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + if ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then return 0 elif ble/syntax:bash/check-process-subst; then return 0 @@ -3057,9 +3075,9 @@ function ble/syntax:bash/check-tilde-expansion { fi ((_ble_syntax_attr[i]=attr,i+=${#str})) else + ((_ble_syntax_attr[i]=ctx,i++)) # skip tilde local chars=${_ble_syntax_bash_chars[CTX_ARGI]} - local rex='^~([^'$chars']|\\.)*'; [[ $tail =~ $rex ]] - ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + ble/syntax:bash/check-plain-with-escape "[^$chars]+" # 追加(失敗してもOK) fi return 0 @@ -3888,7 +3906,7 @@ function ble/syntax:bash/ctx-command { local flagConsume=0 if ble/syntax:bash/check-variable-assignment; then flagConsume=1 - elif local rex='^([^'${_ble_syntax_bash_chars[CTX_ARGI]}']|\\.)+'; [[ $tail =~ $rex ]]; then + elif local rex='^([^'${_ble_syntax_bash_chars[CTX_ARGI]}']+|\\.)'; [[ $tail =~ $rex ]]; then local rematch=$BASH_REMATCH local attr=$ctx if ((attr==CTX_FARGI1)); then @@ -3898,6 +3916,8 @@ function ble/syntax:bash/ctx-command { else attr=$ATTR_ERR fi + elif [[ $BASH_REMATCH == '\'? ]]; then + attr=$ATTR_QESC fi ((_ble_syntax_attr[i]=attr,i+=${#rematch})) flagConsume=1 @@ -4156,9 +4176,7 @@ function ble/syntax:bash/ctx-values { if ble/syntax:bash/check-variable-assignment; then return 0 - elif local rex='^([^'${_ble_syntax_bash_chars[CTX_ARGI]}']|\\.)+' && [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[CTX_ARGI]}]+"; then return 0 elif ble/syntax:bash/check-process-subst; then return 0 @@ -4245,9 +4263,7 @@ function ble/syntax:bash/ctx-conditions { if ble/syntax:bash/check-variable-assignment; then return 0 - elif local rex='^([^'${_ble_syntax_bash_chars[CTX_ARGI]}']|\\.)+' && [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[CTX_ARGI]}]+"; then return 0 elif ble/syntax:bash/check-process-subst; then return 0 @@ -4331,10 +4347,7 @@ function ble/syntax:bash/ctx-redirect { # 単語開始の設置 ble/syntax:bash/ctx-redirect/check-word-begin - local rex - if rex='^([^'${_ble_syntax_bash_chars[CTX_ARGI]}']|\\.)+' && [[ $tail =~ $rex ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[CTX_ARGI]}]+"; then return 0 elif ble/syntax:bash/check-process-subst; then return 0 @@ -6012,6 +6025,7 @@ function ble/syntax/faces-onload-hook { ble/color/defface syntax_command fg=brown ble/color/defface syntax_quoted fg=green ble/color/defface syntax_quotation fg=green,bold + ble/color/defface syntax_escape fg=magenta ble/color/defface syntax_expr fg=26 ble/color/defface syntax_error bg=203,fg=231 # bg=224 ble/color/defface syntax_varname fg=202 @@ -6085,6 +6099,7 @@ function ble/syntax/faces-onload-hook { ble/syntax/attr2iface/.define ATTR_ERR syntax_error ble/syntax/attr2iface/.define ATTR_VAR syntax_varname ble/syntax/attr2iface/.define ATTR_QDEL syntax_quotation + ble/syntax/attr2iface/.define ATTR_QESC syntax_escape ble/syntax/attr2iface/.define ATTR_DEF syntax_default ble/syntax/attr2iface/.define ATTR_DEL syntax_delimiter ble/syntax/attr2iface/.define CTX_PARAM syntax_param_expansion diff --git a/memo/ChangeLog.md b/memo/ChangeLog.md index 395a4d53..20f964f3 100644 --- a/memo/ChangeLog.md +++ b/memo/ChangeLog.md @@ -47,6 +47,7 @@ - util (`blehook`): hide internal hooks by default and support option `-a` - util, color: fix argument analysis of `bleopt`, `blehook`, and `ble-face` (fixup c94d292) `#D1571` bb53271 - progcomp: support quoted commands and better `progcomp_alias` `#D1581` `#D1583` 0000000 +- syntax: highlight quotes of the `\?` form `#D1584` 0000000 ## Changes diff --git a/note.txt b/note.txt index 5cdbfdc3..389fe5a3 100644 --- a/note.txt +++ b/note.txt @@ -1442,7 +1442,7 @@ bash_tips 2021-05-29 - * syntax: \q を着色したい + * syntax: 単語が sabbrev に一致する場合には着色するのが親切だ 2021-05-28 @@ -1459,12 +1459,12 @@ bash_tips * declare -p -A として見たら contra の状態が壊れた。何だろうか。 * やはり source_if() { source "$@"; } 等とすると引数が一つしかない場合に、自 - 分自身が引数であると誤認してロードがキャンセルされる。これは実は簡単に判定 - できるのではないだろうか。 + 分自身が引数であると誤認してロードがキャンセルされる。 - % つまり引数が唯一つでしかも自分自身を指している場合には関数内で無引数で - % source されたのであると判定できる。と思ったが違う。これで見えているのは外 - % 側の関数の引数なのだから、必ずしもそういう形になっている訳ではない。 + % これは実は簡単に判定できるのではないだろうか。つまり引数が唯一つでしかも + % 自分自身を指している場合には関数内で無引数でsource されたのであると判定で + % きる。と思ったが違う。これで見えているのは外側の関数の引数なのだから、必 + % ずしもそういう形になっている訳ではない。 2021-05-24 @@ -4692,6 +4692,16 @@ bash_tips 2021-05-29 + * syntax: \? を着色したい [#D1584] + + 色は magenta で良い。\q が現れる箇所はコマンド、"..." である。それぞれ規則 + は異なる。特に後者については規則が分かりにくいので色を付ける対象にしたい。 + + $'...' も別枠で着色する様にしたい。これもちゃんと実装した。これで + $'...' を書く時にどのようなシーケンスが有効でどの様なシーケンスが + 無効か分かる。所で bash version 依存性はどうなっているのか確認する + 必要がある。 + * complete: quote されているコマンド名に対しても補完関数を適切に探索 [#D1583] quote していると補完関数が認識されない。例えば git co とすると OK だが