From 41faa4945ce55443b4109200e84fb8734980fe58 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Wed, 8 Mar 2023 10:32:56 +0900 Subject: [PATCH] sabbrev: apply sabbrev to right-hand sides of variable assignments * complete (source:argument): fallback to rhs completion also for "name+=rhs" * syntax: fix unrecognized variable assignment of the form "echo arr[i]+=rhs" * global: normalize to "_a-zA-Z[0-9]" for bracket expressions --- docs/ChangeLog.md | 8 ++++-- lib/core-complete.sh | 38 +++++++++++++++++++------- lib/core-syntax-def.sh | 33 ++++++++++++----------- lib/core-syntax.sh | 55 ++++++++++++++++++++----------------- lib/init-term.sh | 2 +- lib/vim-airline.sh | 2 +- make_command.sh | 12 ++++----- note.txt | 61 ++++++++++++++++++++++++++++++++++++++++++ src/util.hook.sh | 4 +-- src/util.sh | 4 +-- 10 files changed, 155 insertions(+), 64 deletions(-) diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index 8550a37d..7a602336 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -26,7 +26,7 @@ - prompt: support multiline `prompt_rps1` `#D1502` 4fa139a - canvas: fix wrong coordinate calculation on linefolding (reported by telometto) `#D1602` 9badb5f - prompt: fix coordinates after `prompt_rps1` `#D1972` e128801 - - prompt: clear remaining SGR after `prompt_rps1` (reported by linwaytin) `#D2003` xxxxxxx + - prompt: clear remaining SGR after `prompt_rps1` (reported by linwaytin) `#D2003` ea99d944 - syntax: support tilde expansions in parameter expansions `#D1513` 0506df2 - decode: support `ble-bind -m KEYMAP --cursor DECSCUSR` (motivated by jmederosalvarado) `#D1514` `#D1515` `#D1516` 79d671d - decode: reflect changes after `ble-bind --cursor` `#D1873` 39efcf9 @@ -50,7 +50,7 @@ - prompt (`contrib/prompt-git`): do not use `ble/util/idle` in Bash 3 `#D1606` 959cf27 - util (`bleopt`): add new option `-I` to reinitialize user settings on reload `#D1607` 959cf27 - vi (vi_cmap): fix wrong prompt calculations by the outdated initial values `#D1653` 2710b23 - - vim-airline: measure separator widths and fix layout of status line `#D1999` 1ce0d1ad xxxxxxx + - vim-airline: measure separator widths and fix layout of status line `#D1999` 1ce0d1ad 478c9a10 - util, color: refactor configuration interfaces (`bleopt`, `blehook`, `ble-face`) `#D1568` c94d292 - color: support new face setting function `ble-face` - util (`bleopt`): support option `-r` and `-u` and wildcards in option names @@ -241,6 +241,8 @@ - color: rearrange color table by `ble palette` (suggested by stackoverflow/caoanan) `#D1961` bb8541d - util (`ble/util/idle`): process events before idle sleep `#D1980` 559d64b - keymap/vi (`decompose-meta`): translate S-a to A `#D1988` 600e845 +- sabbrev: apply sabbrev to right-hand sides of variable assignments `#D2006` xxxxxxxx +- complete (`source:argument`): fallback to rhs completion also for `name+=rhs` `#D2006` xxxxxxxx ## Fixes @@ -370,6 +372,7 @@ - keymap/vi (`expand-range-for-linewise-operator`): fix the end point being not extended `#D1994` bce2033 - keymap/vi (`operator:filter`): do not append newline at the end of line `#D1994` bce2033 - highlight: fix shifted error marks after delayed `core-syntax` `#D2000` f4145f16 +- syntax: fix unrecognized variable assignment of the form `echo arr[i]+=rhs` `#D2007` xxxxxxxx ## Documentation @@ -565,6 +568,7 @@ - util: replace builtin `readonly` with a shell function (requested by mozirilla213) `#D1985` 8683c84 e4758db - global: avoid directly using `/dev/tty` `#D1986` a835b83 - util: add `ble/util/message` `#D2001` 2a524f34 +- global: normalize bracket expressions to `_a-zA-Z` / `_a-zA-Z0-9` `#D2006` xxxxxxxx ## Contrib diff --git a/lib/core-complete.sh b/lib/core-complete.sh index 5f417052..9ac7f82d 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -3799,7 +3799,7 @@ function ble/complete/progcomp/.split-alias-words { done # skip assignments/redirections - local i=0 rex_assign='^[a-zA-Z_0-9]+(\['$_ble_syntax_bash_simple_rex_element'*\])?\+?=' + local i=0 rex_assign='^[_a-zA-Z0-9]+(\['$_ble_syntax_bash_simple_rex_element'*\])?\+?=' while ((i<${#words[@]})); do if [[ ${words[i]} =~ $rex_assign ]]; then ((i++)) @@ -4759,7 +4759,7 @@ function ble/complete/mandb:help/generate-cache { } cfg_usage { - if (NR <= 20 && (g_usage_start || $0 ~ /^[a-zA-Z_0-9]|^[^-[:space:]][^[:space:]]*(: |:)/) ) { + if (NR <= 20 && (g_usage_start || $0 ~ /^[_a-zA-Z0-9]|^[^-[:space:]][^[:space:]]*(: |:)/) ) { g_usage_start = 1; usage_parse($0); } else if (/^[[:space:]]*$/) @@ -5260,7 +5260,7 @@ function ble/complete/source:argument { #---------------------------------------------------------------------------- # 3. Attempt rhs completion - if local rex='^/?[-_a-zA-Z0-9.]+[:=]|^-[^-/=:]'; [[ $COMPV =~ $rex ]]; then + if local rex='^/?[-_a-zA-Z0-9.]+\+?[:=]|^-[^-/=:]'; [[ $COMPV =~ $rex ]]; then # var=filename --option=filename /I:filename など。 local prefix=$BASH_REMATCH value=${COMPV:${#BASH_REMATCH}} local COMP_PREFIX=$prefix @@ -5688,7 +5688,7 @@ function ble/complete/candidates/.filter-word-by-prefix { function ble/complete/candidates/.initialize-rex_raw_paramx { local element=$_ble_syntax_bash_simple_rex_element local open_dquot=$_ble_syntax_bash_simple_rex_open_dquot - rex_raw_paramx='^('$element'*('$open_dquot')?)\$[a-zA-Z_][a-zA-Z_0-9]*$' + rex_raw_paramx='^('$element'*('$open_dquot')?)\$[_a-zA-Z][_a-zA-Z0-9]*$' } ## 候補フィルタ (candidate filters) は以下の関数を通して実装される。 @@ -8369,16 +8369,36 @@ function ble/complete/sabbrev/locate-key { ble/complete/context:syntax/generate-sources for src in "${sources[@]}"; do ble/string#split-words asrc "$src" - [[ ${asrc[0]} =~ $rex_source_type ]] && - ((asrc[1]} の時は末尾の @* を個別に読み取る。 @@ -2053,7 +2053,7 @@ function ble/syntax:bash/check-dollar { ble/syntax/parse/nest-push "$CTX_CMDX" '$(' ((i+=2)) return 0 - elif rex='^\$([-*@#?$!0_]|[1-9]|[a-zA-Z_][a-zA-Z_0-9]*)' && [[ $tail =~ $rex ]]; then + elif rex='^\$([-*@#?$!0_]|[1-9]|[_a-zA-Z][_a-zA-Z0-9]*)' && [[ $tail =~ $rex ]]; then local rematch=$BASH_REMATCH rematch1=${BASH_REMATCH[1]} ((_ble_syntax_attr[i++]=CTX_PARAM)) @@ -2578,7 +2578,7 @@ function ble/syntax:bash/ctx-bracket-expression { ((_ble_syntax_attr[i++]=ctx,is_assign=1)) elif [[ $tail == ']+'* ]]; then ble/syntax/parse/set-lookahead 2 - [[ $tail == ']+=' ]] && ((_ble_syntax_attr[i]=ctx,i+=2,is_assign=1)) + [[ $tail == ']+='* ]] && ((_ble_syntax_attr[i]=ctx,i+=2,is_assign=1)) fi if [[ $is_assign ]]; then @@ -2884,7 +2884,7 @@ function ble/syntax:bash/ctx-expr/.count-brace { function ble/syntax:bash/ctx-expr { # 式の中身 local rex - if rex='^[a-zA-Z_][a-zA-Z_0-9]*'; [[ $tail =~ $rex ]]; then + if rex='^[_a-zA-Z][_a-zA-Z0-9]*'; [[ $tail =~ $rex ]]; then local rematch=$BASH_REMATCH local ret; ble/syntax/highlight/vartype "$BASH_REMATCH" readvar:expr:global ((_ble_syntax_attr[i]=ret,i+=${#rematch})) @@ -2892,7 +2892,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 ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}a-zA-Z_0-9]+" 1; then + elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}_a-zA-Z0-9]+" 1; then return 0 elif [[ $tail == ['][()}']* ]]; then local char=${tail::1} ntype @@ -3225,7 +3225,7 @@ function ble/syntax:bash/check-variable-assignment { # パターン一致 (var= var+= arr[ のどれか) local suffix='[=[]' ((_ble_bash>=30100)) && suffix=$suffix'|\+=?' - local rex_assign="^([a-zA-Z_][a-zA-Z_0-9]*)($suffix)" + local rex_assign="^([_a-zA-Z][_a-zA-Z0-9]*)($suffix)" [[ $tail =~ $rex_assign ]] || return 1 local rematch=$BASH_REMATCH local rematch1=${BASH_REMATCH[1]} # for bash-3.1 ${#arr[n]} bug @@ -4056,7 +4056,7 @@ function ble/syntax:bash/ctx-command { if ((ctx==CTX_FARGI1)); then # for var in ... の var の部分は変数名をチェックして着色 - local rex='^[a-zA-Z_][a-zA-Z_0-9]*$' attr=$ATTR_ERR + local rex='^[_a-zA-Z][_a-zA-Z0-9]*$' attr=$ATTR_ERR if ((i0==wbegin)) && [[ ${text:i0:i-i0} =~ $rex ]]; then local ret; ble/syntax/highlight/vartype "$BASH_REMATCH" global; attr=$ret fi @@ -4769,6 +4769,8 @@ function ble/syntax:bash/find-end-of-array-index { ## @param[in] opts ## element-assignment ## 配列要素の場合にも変数代入の形式を許します。 +## long-option +## --long-option= の形式にも強制的に対応します。 ## @var[out] ret ## 右辺の開始位置を返します。 ## 変数代入の形式でない時には単語の開始位置を返します。 @@ -4783,15 +4785,18 @@ function ble/syntax:bash/find-rhs { local rex= if ((wtype==ATTR_VAR)); then - rex='^[a-zA-Z0-9_]+(\+?=|\[)' + rex='^[_a-zA-Z0-9]+(\+?=|\[)' elif ((wtype==CTX_VALI)); then if [[ :$opts: == *:element-assignment:* ]]; then # 配列要素に対しても変数代入の形式を許す - rex='^[a-zA-Z0-9_]+(\+?=|\[)|^(\[)' + rex='^[_a-zA-Z0-9]+(\+?=|\[)|^(\[)' else rex='^(\[)' fi fi + if [[ :$opts: == *:long-option:* ]]; then + rex=${rex:+$rex'|'}'^--[-_a-zA-Z0-9]+=' + fi if [[ $rex && $word =~ $rex ]]; then local last_char=${BASH_REMATCH:${#BASH_REMATCH}-1} @@ -5329,7 +5334,7 @@ function ble/syntax/completion-context/.add { ## @fn ble/syntax/completion-context/.check/parameter-expansion ## @var[in] text istat index ctx function ble/syntax/completion-context/.check/parameter-expansion { - local rex_paramx='^(\$(\{[!#]?)?)([a-zA-Z_][a-zA-Z_0-9]*)?$' + local rex_paramx='^(\$(\{[!#]?)?)([_a-zA-Z][_a-zA-Z0-9]*)?$' if [[ ${text:istat:index-istat} =~ $rex_paramx ]]; then local rematch1=${BASH_REMATCH[1]} local source=variable @@ -5444,7 +5449,7 @@ function ble/syntax/completion-context/.check-prefix/ctx:next-command { ble/syntax/completion-context/.add command "$istat" # 変数・代入のチェック - if local rex='^[a-zA-Z_][a-zA-Z_0-9]*(\+?=)?$' && [[ $word =~ $rex ]]; then + if local rex='^[_a-zA-Z][_a-zA-Z0-9]*(\+?=)?$' && [[ $word =~ $rex ]]; then if [[ $word == *= ]]; then if ((_ble_bash>=30100)) || [[ $word != *+= ]]; then # VAR=: 現在位置から argument 候補を生成する @@ -5710,7 +5715,7 @@ function ble/syntax/completion-context/.check-prefix/ctx:param { ## 数式中の変数名を補完する文脈 _ble_syntax_bash_complete_check_prefix[CTX_EXPR]=expr function ble/syntax/completion-context/.check-prefix/ctx:expr { - local tail=${text:istat:index-istat} rex='[a-zA-Z_]+$' + local tail=${text:istat:index-istat} rex='[_a-zA-Z]+$' if [[ $tail =~ $rex ]]; then local p=$((index-${#BASH_REMATCH})) ble/syntax/completion-context/.add variable:a "$p" @@ -5791,7 +5796,7 @@ function ble/syntax/completion-context/.search-last-istat { ## @var[in] index ## @var[out] sources function ble/syntax/completion-context/.check-prefix { - local rex_param='^[a-zA-Z_][a-zA-Z_0-9]*$' + local rex_param='^[_a-zA-Z][_a-zA-Z0-9]*$' local from=${1:-$((index-1))} local ret diff --git a/lib/init-term.sh b/lib/init-term.sh index b39160bf..394e559d 100644 --- a/lib/init-term.sh +++ b/lib/init-term.sh @@ -66,7 +66,7 @@ function ble/init:term/define-sgr-param { builtin eval "$name=" fi - if [[ $name =~ ^[a-zA-Z_][a-zA-Z_0-9]*$ ]]; then + if [[ $name =~ ^[_a-zA-Z][_a-zA-Z0-9]*$ ]]; then ble/init:term/register-varname "$name" fi } diff --git a/lib/vim-airline.sh b/lib/vim-airline.sh index 721a2dbf..e35164a1 100644 --- a/lib/vim-airline.sh +++ b/lib/vim-airline.sh @@ -132,7 +132,7 @@ function ble/lib/vim-airline/convert-theme/.setface { } function ble/lib/vim-airline/convert-theme { local file=$1 - sed -n 's/let s:airline_\([a-zA-Z_0-9]\{1,\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\).*/\1 \2 \3/p' "$file" | + sed -n 's/let s:airline_\([_a-zA-Z0-9]\{1,\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\).*/\1 \2 \3/p' "$file" | while ble/bash/read face fg bg; do ble/lib/vim-airline/convert-theme/.setface "$face" "$fg" "$bg" done diff --git a/make_command.sh b/make_command.sh index c81056d5..f30ecca4 100755 --- a/make_command.sh +++ b/make_command.sh @@ -1144,14 +1144,14 @@ function sub:scan/bash300bug { echo "--- $FUNCNAME ---" # bash-3.0 では local arr=(1 2 3) とすると # local arr='(1 2 3)' と解釈されてしまう。 - grc 'local [a-zA-Z_]+=\(' --exclude=./{test,ext} --exclude=./make_command.sh --exclude=ChangeLog.md + grc 'local [_a-zA-Z]+=\(' --exclude=./{test,ext} --exclude=./make_command.sh --exclude=ChangeLog.md # bash-3.0 では local -a arr=("$hello") とすると # クォートしているにも拘らず $hello の中身が単語分割されてしまう。 grc 'local -a [[:alnum:]_]+=\([^)]*[\"'\''`]' --exclude=./{test,ext} --exclude=./make_command.sh # bash-3.0 では "${scalar[@]/xxxx}" は全て空になる - grc '\$\{[a-zA-Z_0-9]+\[[*@]\]/' --exclude=./{text,ext} --exclude=./make_command.sh --exclude=\*.md --color | + grc '\$\{[_a-zA-Z0-9]+\[[*@]\]/' --exclude=./{text,ext} --exclude=./make_command.sh --exclude=\*.md --color | grep -v '#D1570' # bash-3.0 では "..${var-$'hello'}.." は (var が存在しない時) "..'hello'..." になる。 @@ -1295,7 +1295,7 @@ function sub:scan/eval-literal { function sub:scan/WA-localvar_inherit { echo "--- $FUNCNAME ---" - grc 'local [^;&|()]*"\$\{[a-zA-Z_0-9]+\[@*\]\}"' + grc 'local [^;&|()]*"\$\{[_a-zA-Z0-9]+\[@*\]\}"' } function sub:scan/mistake-_ble_bash { @@ -1323,9 +1323,9 @@ function sub:scan/word-splitting-number { \Z^[^#]*(^|[[:space:]])#Zd \Z^([^"]|"[^\#]*")*"[^"]*([& (]\$)Zd \Z^[^][]*\[\[[^][]*([& (]\$)Zd - \Z\(\([a-zA-Z_0-9]+=\(\$Zd - \Z\$\{#[a-zA-Z_0-9]+\}[<>?&]Zd - \Z \$\{\#[a-zA-Z_0-9]+\[@\]\} -gt 0 \]\]Zd + \Z\(\([_a-zA-Z0-9]+=\(\$Zd + \Z\$\{#[_a-zA-Z0-9]+\}[<>?&]Zd + \Z \$\{\#[_a-zA-Z0-9]+\[@\]\} -gt 0 \]\]Zd \Zcase \$\? inZd \Zcase \$\(\(.*\)\) inZd g' diff --git a/note.txt b/note.txt index 7610f6c9..1cf40f95 100644 --- a/note.txt +++ b/note.txt @@ -6630,6 +6630,67 @@ bash_tips 2023-03-08 + * syntax: echo alpha[0]+=~ がチルダ展開として認識されていない [#D2007] + これは単純なミスだった。修正した。 + + * sabbrev: 変数代入右辺での展開の対応 [#D2006] + + 変数代入の右辺では右辺に対して sabbrev 展開を行う。: で区切ったフィールドも + 認識する。 + + * ok: 然しこれに対応するには複数の sabbrev 展開位置について考慮に入れる必要 + がある気がする。例えば locale-key の context に rhs も対応すれば良い気が + するが、そうすると今度は通常の sabbrev で = も含めて展開しようとしている + 物が動かなくなる。と思ったが、現在の設定だと = を含む sabbrev はそもそも + 定義できないのでは?なので rhs は含めてしまって良い気がする。 + + * done: 変数代入右辺の特定 + + 実際に変数代入の右辺での sabbrev に対応するとしてどの様にして変数代入の右 + 辺を特定するのか。一旦その様な関数を書いたかもしれないと思ったがどのよう + に探せば良いか分からない。使っていそうな所を探すのが良い気がする。 + + arr=([0]=xxx) 及び var=xxx の場合には rhs でちゃんと抽出できている。問題 + は argument の時にどの様にしているのかという事。 + + a var=xxx の時にどの様に抽出しているのかを確認すれば良いのではないか? + + b 或いは complete 側で source:argument の fallback をどの様に処理している + か。うーん。これは単に正規表現で一致させているだけの気がする。 + + c と思ったら ble/syntax:bash/find-rhs という名前のそのままな関数があった。 + この関数を使って見る事にする。 + + 取り敢えず対応した。更に : による区切りにも対応したい気がするがそれは後回 + しにする。と思ったがやはり後になると面倒なのでここで対応する事にする。 + + * done: rhs や argument (変数代入) の時に : 区切りで一番近いフィールドに対 + して sabbrev 展開を実行する? + + ":" を含む sabbrev があっても良いが、特に a=...:... の形式をしている時に + は効かない様にしてしまっても良い気がする。 + + a 取り敢えず simple-word で区切る事にした。 + + b もっとちゃんとやろうと思ったら文法情報を参照する事もできるかもしれない。 + + 特に、rhs の文脈では必ず : で stat を設置しているのだから rhs 内部を舐 + めて stat に記録された ctx をチェックすれば良いのでは? + + local i + for ((i=asrc[1];i&2 flags=E$flags elif [[ $flags == *A* ]]; then @@ -3037,7 +3037,7 @@ function ble/util/for-global-variables { builtin unset -v "${!_ble_processed_@}" for __ble_name; do - [[ ${__ble_name//[0-9a-zA-Z_]} || $__ble_name == __ble_* ]] && continue + [[ ${__ble_name//[_a-zA-Z0-9]} || $__ble_name == __ble_* ]] && continue ((__ble_processed_$__ble_name)) && continue ((__ble_processed_$__ble_name=1))