diff --git a/blerc.template b/blerc.template index 1af36caa..be2d9d92 100644 --- a/blerc.template +++ b/blerc.template @@ -927,6 +927,13 @@ #bleopt syntax_eval_polling_interval=50 +## The following setting limits the number of expanded words to process in +## highlighting a single grammatical word. When this setting is set to an +## empty string, the number of expanded words to process is unlimited. + +#bleopt highlight_eval_word_limit=200 + + ## If set to a non-empty value, the setting "color_scheme" specifies a preset ## graphic styles for basic faces. The supported schemes are found in the ## subdirectory "contrib/scheme". The default value is "default". diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index 65a7b3cc..cb564d24 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -53,6 +53,7 @@ - util(vbell): support `bleopt vbell_align=panel` (requested by bb010g) `#D2228` fe85e0dd - highlight: reflect the top-level positional parameters `#D2246` f08e8f08 - color: adjust default fg values in faces and add `bleopt color_scheme` (requested by mattmc3) `#D2248` +- highlight: add `bleopt highlight_eval_word_limit` (motivated by orionalves) `#D2256` xxxxxxxx ## Changes diff --git a/lib/core-complete.sh b/lib/core-complete.sh index 808941f4..7e4711f7 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -1769,7 +1769,7 @@ function ble/complete/action/requote-final-insert { if [[ $insert == "$comps_prefix"* && $comps_prefix != *[!':/={,'] ]]; then local ret ins=${insert:${#comps_prefix}} if ! ble/syntax:bash/simple-word/is-literal "$ins" && - ble/syntax:bash/simple-word/safe-eval "$ins" && + ble/syntax:bash/simple-word/safe-eval "$ins" limit=2 && ((${#ret[@]}==1)) then ble/string#quote-word "$ret" quote-empty diff --git a/lib/core-debug.sh b/lib/core-debug.sh index 95369f98..979260de 100644 --- a/lib/core-debug.sh +++ b/lib/core-debug.sh @@ -177,7 +177,16 @@ function ble/debug/profiler/stop { ble/util/assign-words nline 'ble/bin/wc -l "$f1" 2>/dev/null' ble/util/print $'\e[A\rble/debug/profiler: counting lines... '"$nline" >&2 - ble/bin/awk -v magic="$_ble_debug_profiler_magic" -v nline="$nline" ' + # nawk becomes unacceptably slow when there is a long line. It seems to scale + # as O(N^2). If mawk/gawk is available, we prefer mawk/gawk to nawk. + local awk=ble/bin/awk + if ble/is-function ble/bin/mawk; then + awk=ble/bin/mawk + elif ble/is-function ble/bin/gawk; then + awk=ble/bin/gawk + fi + + "$awk" -v magic="$_ble_debug_profiler_magic" -v nline="$nline" ' BEGIN { xtrace_debug_enabled = 1; print "ble/debug/profiler: collecting information..." >"/dev/stderr"; diff --git a/lib/core-syntax-def.sh b/lib/core-syntax-def.sh index babb6941..c9f9db5f 100644 --- a/lib/core-syntax-def.sh +++ b/lib/core-syntax-def.sh @@ -90,6 +90,7 @@ bleopt/declare -v highlight_filename 1 bleopt/declare -v highlight_variable 1 bleopt/declare -v highlight_timeout_sync 50 bleopt/declare -v highlight_timeout_async 5000 +bleopt/declare -v highlight_eval_word_limit 200 bleopt/declare -v syntax_eval_polling_interval 50 builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_syntax_highlight_filetype}" diff --git a/lib/core-syntax.sh b/lib/core-syntax.sh index 59b44471..d49a94a2 100644 --- a/lib/core-syntax.sh +++ b/lib/core-syntax.sh @@ -1337,8 +1337,16 @@ function ble/syntax:bash/simple-word/extract-parameter-names/.process-dquot { done } -function ble/syntax:bash/simple-word/eval/.set-result { __ble_ret=("$@"); } +function ble/syntax:bash/simple-word/eval/.set-result { + if [[ $__ble_word_limit ]] && (($#>__ble_word_limit)); then + set -- "${@::__ble_word_limit}" + fi + __ble_ret=("$@") +} function ble/syntax:bash/simple-word/eval/.print-result { + if [[ $__ble_word_limit ]] && (($#>__ble_word_limit)); then + set -- "${@::__ble_word_limit}" + fi if (($#>=1000)) && [[ $OSTYPE != cygwin ]]; then # ファイル数が少ない場合は fork コストを避ける為に多少遅くても quote&eval # でデータを親シェルに転送する。Cygwin では mapfile/read が unbuffered で遅 @@ -1406,6 +1414,10 @@ function ble/syntax:bash/simple-word/eval/.impl { builtin eval -- "$__ble_defs" &>/dev/null # 読み取り専用の変数のこともある fi + local __ble_word_limit= + ble/string#match ":$__ble_opts:" ':limit=([^:]*):' && + ((__ble_word_limit=BASH_REMATCH[1])) + # glob パターンを含む可能性がある時の処理 (Note: is-simple-noglob の # 判定で変数を参照するので、グローバル変数の復元よりも後で処理する必 # 要がある) @@ -1523,6 +1535,9 @@ function ble/syntax:bash/simple-word/eval/.cache-load { ## ## single ## 最初の展開結果のみを ret に設定します。 +## limit=COUNT +## 評価後の単語数を COUNT 以下に制限します。これは count によって設定さ +## れる展開結果の単語数にも影響を与えます。 ## count ## 変数 count に展開結果の単語数を返します。 ## cached @@ -1543,8 +1558,8 @@ function ble/syntax:bash/simple-word/eval/.cache-load { ## パス名展開のタイムアウトの既定値を指定します。空文字列が指定さ ## れている時、既定でタイムアウトは起こりません。 ## @var[in,out] _ble_syntax_bash_simple_eval_timeout_carry -## この値が設定されている時、パス名展開に対して強制的にタイムアウ -## トが起こります。opts に timeout-carry が指定されている時に値が設定されます。 +## この値が設定されている時、パス名展開に対して強制的にタイムアウトが起こり +## ます。opts に timeout-carry が指定されている時に値が設定されます。 ## ## @arr[out] ret ## 展開結果を返します。複数の単語に評価される場合にはそれを全て返します。 @@ -1586,9 +1601,12 @@ function ble/syntax:bash/simple-word/eval { } ## @fn ble/syntax:bash/simple-word/eval word [opts] +## Evaluate the specified word only when the word is safe and take the first +## word when the word is expanded to multiple words. +## ## @param[in,opt] opts ## A colon-separated list of options. In addition to the values supported -## by ble/syntax:bash/simple-word/eval, the following value is available: +## by ble/syntax:bash/simple-word/eval, the following values are available: ## ## @opt reconstruct ## Try to reconstruct the full word using @@ -1600,18 +1618,26 @@ function ble/syntax:bash/simple-word/eval { ## expansion an empty array "${arr[@]}" or unmatching glob pattern with ## nullglob. ## +## The other options are processed by "ble/syntax:bash/simple-word/eval", +## but if "limit=COUNT" is not specified, the option "limit=1" is added to +## suppress the number of generated words. +## ## @arr[out] ret ## function ble/syntax:bash/simple-word/safe-eval { - if [[ :$2: == *:reconstruct:* ]]; then + local __ble_opts=$2 + if [[ :$__ble_opts: == *:reconstruct:* ]]; then local simple_flags simple_ibrace ble/syntax:bash/simple-word/reconstruct-incomplete-word "$1" || return 1 ble/util/unlocal simple_flags simple_ibrace else ble/syntax:bash/simple-word/is-simple "$1" || return 1 fi - ble/syntax:bash/simple-word/eval "$1" && - { [[ :$2: != *:nonull:* ]] || ((${#ret[@]})); } + [[ :$__ble_opts: == *:limit=*:* ]] || + __ble_opts=$__ble_opts:limit=1 + + ble/syntax:bash/simple-word/eval "$1" "$__ble_opts" && + { [[ :$__ble_opts: != *:nonull:* ]] || ((${#ret[@]})); } } ## @fn ble/syntax:bash/simple-word/get-rex_element sep @@ -7558,14 +7584,16 @@ function ble/highlight/layer:syntax/word/.update-attributes/.proc { function ble/highlight/layer:syntax/word/.update-attributes { ((_ble_syntax_word_umin>=0)) || return 1 + local _ble_syntax_bash_simple_eval_timeout=$bleopt_highlight_timeout_sync + local highlight_eval_opts=cached:single:stopcheck + + [[ $bleopt_highlight_eval_word_limit ]] && + highlight_eval_opts=$highlight_eval_opts:limit=$((bleopt_highlight_eval_word_limit)) + # Timeout setting for simple-word/eval if [[ ! $ble_textarea_render_defer_running ]]; then - local _ble_syntax_bash_simple_eval_timeout=$bleopt_highlight_timeout_sync local _ble_syntax_bash_simple_eval_timeout_carry= - local highlight_eval_opts=cached:single:stopcheck:timeout-carry - else - local _ble_syntax_bash_simple_eval_timeout=$bleopt_highlight_timeout_async - local highlight_eval_opts=cached:single:stopcheck + highlight_eval_opts=$highlight_eval_opts:timeout-carry fi ble/syntax/tree-enumerate-in-range "$_ble_syntax_word_umin" "$_ble_syntax_word_umax" \ diff --git a/note.txt b/note.txt index 321e4fc3..d4fb1575 100644 --- a/note.txt +++ b/note.txt @@ -7394,6 +7394,29 @@ bash_tips 2024-08-22 + * simple-word: limit the number of expanded words (motivated by orionalves) [#D2256] + https://github.com/akinomyoga/ble.sh/issues/482 + + ブレース展開で巨大な数を入力するとシステムがクラッシュするという報告。正直 + そんな非現実的な物を入力するのが悪いとしか言いようがない。 + + ble/syntax:bash/simple-word/eval について limit=COUNT opts を追加して、構文 + 着色の際に実施される単語の展開および補完の為の展開について上限を設ける事に + した。 + + 但し、単語数の制限は展開の後に行われるので、必ず一回は大量の単語を生成する + ことになる。単にその後の処理をできるだけ軽くするだけの事であるが、単語着色 + に関しては response はかなり改善したように思う。取り敢えず単語数の上限は既 + 定では 200 という事にする。 + + テストに使ったコード: + + | if ((${#__ble_ret[@]}>200)); then + | echo "count=${#__ble_ret[@]} opts=($__ble_opts)" >/dev/tty + | printf -- '- %s\n' "${FUNCNAME[@]}" >/dev/tty + | __ble_ret=("${__ble_ret[@]::200}") + | fi + * mandb: sudo などから呼び出されたコマンドオプションに説明がつかない [#D2255] https://github.com/akinomyoga/ble.sh/issues/480#issuecomment-2298976015