diff --git a/blerc.template b/blerc.template index ad9e66ff..0c682ce9 100644 --- a/blerc.template +++ b/blerc.template @@ -313,13 +313,25 @@ #bleopt allow_exit_with_jobs= -## The following setting controls the cursor position after the move to other -## history entries. When non-empty values are specified, the offset of the -## cursor from the beginning of the command line is preserved. When an empty -## value is specified the cursor position is the beginning or the end of the -## command lines when the move is to a newer or older entry, respectively. - -#bleopt history_preserve_point= +## The following setting controls the default cursor position after moving to +## another history entry. When "preserve" is specified, ble.sh tries to +## preserve the cursor position before moving the history entry. When "begin" +## and "end" are specified, the cursor is placed at the beginning and end, +## respectively, of the entry. When "near" is specified, when we move to an +## older (newer) history entry, the cursor is placed at the end (beginning) of +## the text. When "far" is specified, when we move to an older (newer) history +## entry, the cursor is palced at the beginning (end) of the text. When +## "beginning-of-{,graphical-,logical-}line" is specified, the cursor is placed +## at the beginning of the last (first) line when we move to an older (newer) +## history entry. When "end-of-{,graphical-,logical-}line" is specified, the +## cursor is placed at the end of the last (first) line when we move to an +## older (newer) history entry. When "preserve-{,graphical-,logical-}-column" +## is specified, te cursor is placed at the same column as before moving the +## history entry. When the versions without "graphical" or "logical" is used, +## a logical or graphical line is used based on "bleopt edit_line_type". The +## default is "end-of-line". + +#bleopt history_default_point= ## The following setting controls the history sharing. If it has non-empty diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index e253d5f9..49d7b45a 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -68,6 +68,7 @@ - nsearch: support `action={load-{line,command},insert{,-line}}` (motivated by vaab) `#D2286` 32f290df - complete: support completion for `execute-named-command` `#D2288` 4fee44e6 - complete: support `ble-face menu_complete_{match,selected}` (requested by simonLeary42) `#D2291` 31f264ad +- edit: support `bleopt history_default_point={preserve,begin,end,near,far,{beginning,end}-of-line,preserve-column,...}` (requested by miltieIV2) `#D2297` xxxxxxxx ## Changes diff --git a/lib/keymap.vi.sh b/lib/keymap.vi.sh index e302db2c..5b818bf3 100644 --- a/lib/keymap.vi.sh +++ b/lib/keymap.vi.sh @@ -2702,7 +2702,7 @@ function ble/widget/vi-command/goto-global-mark.impl { ble/widget/vi-command/bell return 1 fi - ble-edit/history/goto "${data[0]}" + ble-edit/history/goto "${data[0]}" point=near fi # find position by data[1]:data[2] @@ -4068,18 +4068,17 @@ function ble/widget/vi-command/.history-goto { return 1 fi - ble-edit/history/goto "$new_index" - - # adjust the cursor position - local ret - if ((new_indexold_index)); then + point_opts=forward else - ble-edit/content/find-logical-bol 0 "$count" + point_opts=backward fi - _ble_edit_ind=$ret + ble-edit/history/goto "$new_index" + + # adjust the cursor position + ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) ble/keymap:vi/adjust-command-mode } @@ -5568,7 +5567,7 @@ function ble/widget/vi-command/search.core { if ((r==0)); then local new_index; ble/history/get-index -v new_index [[ $index != "$new_index" ]] && - ble-edit/history/goto "$index" + ble-edit/history/goto "$index" point=none if ((opt_backward)); then local i=${#_ble_edit_str} ble/keymap:vi/needs-eol-fix "$i" && ((i--)) diff --git a/note.txt b/note.txt index 7cd90d2d..027926db 100644 --- a/note.txt +++ b/note.txt @@ -1926,6 +1926,20 @@ bash_tips - make_command.sh の整理 (scan 分離, char_width 分離) - note.txt -> memo.txt +2024-12-18 + + * edit: C-c 後の履歴位置が変だ (reported by dezza) + https://github.com/akinomyoga/ble.sh/discussions/540 + + C-c を実行した後は C-m を実行した時と同様に全ての編集をクリアして、履歴位置 + は履歴の末端に移動するべきである。 + + * global: 実は [:space:] は \v\f\r\n にも一致する + + 一方で [:blank:] は全く使われていない。実は [:space:] になっている箇所は全 + て [:blank:] なのでは? ただし改行 \n も意図していた可能性があるのでそれにつ + いては $_ble_term_IFS に置き換える。 + 2024-12-09 * highlight: cd を bind -x 経由で実行するとコマンドキャッシュがクリアされないので @@ -7700,6 +7714,72 @@ bash_tips Done (実装ログ) ------------------------------------------------------------------------------- +2024-12-18 + + * edit: 履歴移動を行った時のカーソル位置の設定 (requested by miltieIV2) [#D2297] + https://github.com/akinomyoga/ble.sh/issues/537 + + * fixed: 何と今まで "bleopt edit_line_type" が動いていなかった様だ。 + + * fixed: 何と今まで bleopt/check:input_encoding のエラーメッセージの一部が + 表示されていなかった様だ。 + + * ok: ble-0.3 では ble/util/print ではなく echo を使っているので問題なかっ + た。 + + * ok: 類似のものは他にはないようだ。 + + * done: wiki, blerc + + x fixed: preserve にしても位置が preserve されていない + + これは何処かの時点で壊れたという事だろうか。上に遡る時には必ずカーソルは + 先頭に移動してしまう。また、下に移動する時には前のコマンドラインの末端位 + 置に移動しようとする。現在のカーソル位置は全く保持していない。keymap.vi + 特有の問題ではないようだ。emacs モードでも同様の現象が起こっている。 + + うーん。呼び出しの順序的に履歴移動が発生しなかった時に正しい位置にカーソ + ルを移動してエラーメッセージも必要に応じて出力しなければならない。しかし + 現在の枠組みだと履歴移動が発生したかどうかを forward-history-line.impl の + 呼び出し元で知ることができない。 + + 振る舞いについて確認する forward-history-line.impl は先ず行を追跡して適切 + な履歴項目の位置を探し出している。その後で対応する行が見つかれば其処に移 + 動するし、見つからなければ先頭項目か末端項目に移動して終了する。 + + * 先ず ble/widget/forward-history-line.impl を呼び出したら、履歴移動が発 + 生しなかったとしても、必ずカーソル位置は適切な位置に設置することにする。 + + x resolved: forward-history-line etc 等との consistency はどうなっているの + か? 複数行の時に forward-history-line も位置を調整しようとしている。履歴 + 移動後にどの位置にいるのかは実は ble-edit/history/goto で管理するのではな + くて forward-history-line 等の実装ごとに適切に処理する必要があるのではな + いか? + + * done: ble-edit/history/goto でもカーソル位置を調整するしその呼び出し元 + でもカーソル位置を調整しているというのは無駄の処理の気がする。→これは + ble-edit/history/goto で opts を受け取って clear-point が指定されている + 場合には、単に _ble_edit_ind=0 にする事にした。 + + forward-history-line 等の行指向の履歴移動の場合には振る舞いを行指向に変更 + した物を別に実装することにした。 + + * done: preserve-{,graphical,logical-}column 等も用意するべきではないか? + + * done: clear-point ではなく point=none にする。point=near 等に対応する + + * done: graphical, logical も外から指定できるようにする? graphical-linewise + もしくは logical-linewise の形で。と思ったが、そもそも + forward-history-line.impl の時点でどちらか分からないので、これも更に外側 + から種類を受け取る様に修正する必要がある→面倒だと思ったが結局対応した。 + + [動作確認] + + x fixed: 全く動かなくなっている。と思ったら graphica/logical の決定による + point の書き換えに失敗していた。修正した。 + + その他は大体動いている様だ。 + 2024-12-12 * style: prefix:$name の形をしている定義関数の呼び出しのクォートを調整 [#D2296] diff --git a/src/edit.sh b/src/edit.sh index b5e7692a..4e4b83ee 100644 --- a/src/edit.sh +++ b/src/edit.sh @@ -174,7 +174,7 @@ function bleopt/check:edit_line_type { } function ble/edit/performs-on-graphical-line { - [[ $edit_line_type == graphical ]] || return 1 + [[ $bleopt_edit_line_type == graphical ]] || return 1 ble/textmap#is-up-to-date && return 0 ((bleopt_edit_forced_textmap)) || return 1 ble/widget/.update-textmap @@ -5814,19 +5814,32 @@ function ble/widget/kill-logical-line { ((bol0?arg:-arg)) if ((arg>0)); then if [[ ! $_ble_history_prefix && ! $_ble_history_load_done ]]; then # 履歴を未だロードしていないので次の項目は存在しない + _ble_edit_ind=${#_ble_edit_str} ble/widget/.bell 'end of history' return 1 fi fi + # Handle "history_default_point" in this function instead of using the + # handling by "ble-edit/history/goto" + local point_opts point point_x + if ((arg>0)); then + opts=$opts:linewise:forward + else + opts=$opts:linewise:backward + fi + ble-edit/history/goto/.prepare-point "$opts" + + local rest=$((arg>0?arg:-arg)) + ble/history/initialize local index=$_ble_history_INDEX @@ -5838,21 +5851,17 @@ function ble/widget/forward-history-line.impl { while ((expr_next)); do if ((--rest<=0)); then - ble-edit/history/goto "$index" # 位置は goto に任せる - return "$?" + ble-edit/history/goto "$index" point=none + ble-edit/history/goto/.set-point 0 + return 0 fi local entry; ble/history/get-edited-entry "$index" if [[ $entry == *$'\n'* ]]; then local ret; ble/string#count-char "$entry" $'\n' if ((rest<=ret)); then - ble-edit/history/goto "$index" - if ((arg>0)); then - ble-edit/content/find-logical-eol 0 "$rest" - else - ble-edit/content/find-logical-eol "${#entry}" "$((-rest))" - fi - _ble_edit_ind=$ret + ble-edit/history/goto "$index" point=none + ble-edit/history/goto/.set-point "$rest" return 0 fi ((rest-=ret)) @@ -5860,11 +5869,11 @@ function ble/widget/forward-history-line.impl { done if ((arg>0)); then - ble-edit/history/goto "$count" + ble-edit/history/goto "$count" point=none _ble_edit_ind=${#_ble_edit_str} ble/widget/.bell 'end of history' else - ble-edit/history/goto 0 + ble-edit/history/goto 0 point=none _ble_edit_ind=0 ble/widget/.bell 'beginning of history' fi @@ -5913,6 +5922,12 @@ function ble/widget/forward-logical-line.impl { return 0 fi + # 履歴項目の移動を行う場合 + if [[ :$opts: == *:history:* && ! $_ble_edit_mark_active ]]; then + ble/widget/forward-history-line.impl "$arg" logical + return "$?" + fi + # 取り敢えず移動できる所まで移動する if ((arg>0)); then ble-edit/content/find-logical-eol "$bol2" @@ -5921,18 +5936,13 @@ function ble/widget/forward-logical-line.impl { fi _ble_edit_ind=$ret - # 履歴項目の移動を行う場合 - if [[ :$opts: == *:history:* && ! $_ble_edit_mark_active ]]; then - ble/widget/forward-history-line.impl "$arg" - return "$?" - fi - # 移動先行がない場合は bell if ((arg>0)); then ble/widget/.bell 'end of string' else ble/widget/.bell 'beginning of string' fi + return 0 } function ble/widget/forward-logical-line { @@ -5946,9 +5956,9 @@ function ble/widget/backward-logical-line { ble/widget/forward-logical-line.impl "$((-arg))" "$opts" } -## @fn ble/keymap:emacs/find-graphical-eol [index [offset]] +## @fn ble-edit/content/find-graphical-eol [index [offset]] ## @var[out] ret -function ble/keymap:emacs/find-graphical-eol { +function ble-edit/content/find-graphical-eol { local axis=${1:-$_ble_edit_ind} arg=${2:-0} local x y index ble/textmap#getxy.cur "$axis" @@ -5972,7 +5982,7 @@ function ble/widget/beginning-of-graphical-line { function ble/widget/end-of-graphical-line { ble/textmap#is-up-to-date || ble/widget/.update-textmap local arg; ble-edit/content/get-arg 1 - local ret; ble/keymap:emacs/find-graphical-eol "$_ble_edit_ind" "$((arg-1))" + local ret; ble-edit/content/find-graphical-eol "$_ble_edit_ind" "$((arg-1))" _ble_edit_ind=$ret } @@ -5990,7 +6000,7 @@ function ble/widget/kill-backward-graphical-line { ((index==_ble_edit_ind&&index>0&&index--)) ble/widget/.kill-range "$index" "$_ble_edit_ind" else - local ret; ble/keymap:emacs/find-graphical-eol "$_ble_edit_ind" "$((-arg))" + local ret; ble-edit/content/find-graphical-eol "$_ble_edit_ind" "$((-arg))" ble/widget/.kill-range "$ret" "$_ble_edit_ind" fi } @@ -6031,25 +6041,30 @@ function ble/widget/forward-graphical-line.impl { local arg=$1 opts=$2 ((arg==0)) && return 0 + local old_edit_ind=$_ble_edit_ind local x y index ax ay ble/textmap#getxy.cur "$_ble_edit_ind" ble/textmap#get-index-at "$x" "$((y+arg))" ble/textmap#getxy.cur --prefix=a "$index" ((arg-=ay-y)) - _ble_edit_ind=$index # 何れにしても移動は行う # 現在の履歴項目内で移動が完結する場合 - ((arg==0)) && return 0 + if ((arg==0)); then + _ble_edit_ind=$index + return 0 + fi # 履歴項目の移動を行う場合 if [[ :$opts: == *:history:* && ! $_ble_edit_mark_active ]]; then - ble/widget/forward-history-line.impl "$arg" + ble/widget/forward-history-line.impl "$arg" graphical return "$?" fi if ((arg>0)); then + _ble_edit_ind=${#_ble_edit_str} ble/widget/.bell 'end of string' else + _ble_edit_ind=0 ble/widget/.bell 'beginning of string' fi return 0 @@ -8607,8 +8622,44 @@ function ble/widget/print-keyboard-macro { #------------------------------------------------------------------------------ # **** history **** @history -bleopt/declare -v history_preserve_point '' +bleopt/declare -v history_default_point 'end' +function bleopt/check:history_default_point { + case $value in + (begin|end|near|far|preserve) return 0 ;; + (beginning-of-line|end-of-line|preserve-column) return 0 ;; + (beginning-of-logical-line|end-of-logical-line|preserve-logical-column) return 0 ;; + (beginning-of-graphical-line|end-of-graphical-line|preserve-graphical-column) return 0;; + (*) + ble/util/print "bleopt: Unrecognized value history_default_point='$value'." >&2 + return 1 + esac +} + +bleopt/declare -o history_preserve_point history_default_point +function bleopt/check:history_preserve_point { + case $value in + (begin|end|near|far|preserve) ;; + (beginning-of-line|end-of-line|preserve-column) ;; + (beginning-of-logical-line|end-of-logical-line|preserve-logical-column) ;; + (beginning-of-graphical-line|end-of-graphical-line|preserve-graphical-column) ;; + ('') value=end ;; + (*) value=preserve ;; + esac + bleopt/declare/.check-renamed-option history_preserve_point history_default_point +} +## @fn ble-edit/history/goto index [opts] +## @param[in] index +## @param[in,opt] opts +## @opt point=POINT ... When this is specified, the cursor position after +## the history movement is placed based on POINT instead of "bleopt +## history_default_point". +## @opt point=none ... When this is specified, the cursor position is set +## to 0 instead of placing at the position specified by "bleopt +## history_default_point". +## @opt linewise ... When this is specified, the cursor position +## arrangement specified by "point" is converted to a linewise version. +## In particular, "begin", "end", "near", and "far" are affected. function ble-edit/history/goto { ble/history/initialize @@ -8638,7 +8689,7 @@ function ble-edit/history/goto { local histlen2=$_ble_history_COUNT if ((histlen!=histlen2)); then ble/textarea#invalidate - ble-edit/history/goto "$((index1==histlen?histlen:index1))" + ble-edit/history/goto "$((index1==histlen?histlen:index1))" "$2" return "$?" fi fi @@ -8648,28 +8699,164 @@ function ble-edit/history/goto { ble/history/set-edited-entry "$index0" "$_ble_edit_str" ble/history/onleave.fire + local opts=$2 + if ((index1>=index0)); then + opts=$opts:forward + else + opts=$opts:backward + fi + local point point_x point_opts + ble-edit/history/goto/.prepare-point "$opts" + # restore ble/history/set-index "$index1" local entry; ble/history/get-edited-entry -v entry "$index1" ble-edit/content/reset "$entry" history - # point - if [[ $bleopt_history_preserve_point ]]; then - if ((_ble_edit_ind>${#_ble_edit_str})); then - _ble_edit_ind=${#_ble_edit_str} + _ble_edit_ind=0 + _ble_edit_mark=0 + _ble_edit_mark_active= + ble-edit/history/goto/.set-point +} + +## @fn ble-edit/history/goto/.prepare-point opts +## @param[in] opts +## @bleopt history_default_point +## @bleopt edit_line_type +## @var[out] point point_x point_opts +function ble-edit/history/goto/.prepare-point { + point_opts=$1 + point_x= + + local ret + ble/opts#extract-last-optarg "$point_opts" point + [[ $ret ]] || ret=$bleopt_history_default_point + point=$ret + + case $point in + (near) + if [[ :$point_opts: == *:backward:* ]]; then + # 遡ったときは最後 + point=end + else + # 進んだときは最初 + point=begin + fi ;; + (far) + # near の逆。連続した履歴移動がしやすくなる。 + if [[ :$point_opts: == *:backward:* ]]; then + point=begin + else + point=end + fi ;; + esac + + if [[ :$point_opts: == *:linewise:* ]]; then + case $point in + (begin) point=beginning-of-line ;; + (end) point=end-of-line ;; + (preserve) point=preserve-column ;; + esac + fi + case $point in + (end-of-line|beginning-of-line|preserve-column) + local prefix + if [[ :$point_opts: == *:graphical:* ]]; then + prefix=graphical + elif [[ :$point_opts: == *:logical:* ]]; then + prefix=logical + elif [[ $bleopt_edit_line_type == graphical ]]; then + prefix=graphical + else + prefix=logical fi - else - if ((index1${#_ble_edit_str})); then + _ble_edit_ind=${#_ble_edit_str} + fi ;; + (preserve-logical-column) + if [[ :$point_opts: == *:backward:* ]]; then + ble-edit/content/find-logical-bol 0 "$delta"; local beg=$ret + else + ble-edit/content/find-logical-bol "${#_ble_edit_str}" "$((-delta))"; local beg=$ret + fi + _ble_edit_ind=$beg + if ((point_x)); then + ((_ble_edit_ind+=point_x)) + ble-edit/content/find-logical-eol "$beg" + ((_ble_edit_ind>ret)) && _ble_edit_ind=$ret + fi ;; + (preserve-graphical-column) + ble/textmap#is-up-to-date || ble/widget/.update-textmap + if [[ :$point_opts: == *:backward:* ]]; then + local x y + ble/textmap#getxy.cur "${#_ble_edit_str}" + ((y-=delta)) + else + local y=$delta + fi + local index + ble/textmap#get-index-at "$point_x" "$y" + _ble_edit_ind=$index ;; + esac } function ble-edit/history/history-message.hook { @@ -9493,7 +9680,7 @@ function ble/widget/isearch/cancel { if ((${#_ble_edit_isearch_arr[@]})); then local step ble/string#split step : "${_ble_edit_isearch_arr[0]}" - ble-edit/history/goto "${step[0]}" + ble-edit/history/goto "${step[0]}" point=none fi ble/widget/isearch/exit.impl @@ -9686,7 +9873,7 @@ function ble-edit/nsearch/.goto-match { ble-edit/content/reset-and-check-dirty "$left$line$right" fi else - ble-edit/history/goto "$index" + ble-edit/history/goto "$index" point=none line=$_ble_edit_str fi @@ -9756,7 +9943,7 @@ function ble-edit/nsearch/.search.fib { if [[ $_ble_edit_nsearch_loadctx ]]; then ble-edit/content/reset-and-check-dirty "$line" else - ble-edit/history/goto "${record[1]}" + ble-edit/history/goto "${record[1]}" point=none fi _ble_edit_nsearch_match=${record[1]} _ble_edit_nsearch_index=${record[1]} @@ -10121,7 +10308,7 @@ function ble/widget/nsearch/cancel { if [[ $_ble_edit_nsearch_loadctx ]]; then ble-edit/content/reset-and-check-dirty "$line" else - ble-edit/history/goto "$_ble_edit_nsearch_index0" + ble-edit/history/goto "$_ble_edit_nsearch_index0" point=none fi _ble_edit_ind=${record[2]} _ble_edit_mark=${record[3]} diff --git a/src/util.sh b/src/util.sh index 290f7177..d281ec38 100644 --- a/src/util.sh +++ b/src/util.sh @@ -312,24 +312,19 @@ function bleopt/reinitialize { bleopt/declare -n input_encoding UTF-8 function bleopt/check:input_encoding { if ! ble/is-function ble/encoding:"$value"/decode; then - ble/util/print "bleopt: Invalid value input_encoding='$value'." \ - "A function 'ble/encoding:$value/decode' is not defined." >&2 + ble/util/print "bleopt: Invalid value input_encoding='$value'. A function 'ble/encoding:$value/decode' is not defined." >&2 return 1 elif ! ble/is-function ble/encoding:"$value"/b2c; then - ble/util/print "bleopt: Invalid value input_encoding='$value'." \ - "A function 'ble/encoding:$value/b2c' is not defined." >&2 + ble/util/print "bleopt: Invalid value input_encoding='$value'. A function 'ble/encoding:$value/b2c' is not defined." >&2 return 1 elif ! ble/is-function ble/encoding:"$value"/c2bc; then - ble/util/print "bleopt: Invalid value input_encoding='$value'." \ - "A function 'ble/encoding:$value/c2bc' is not defined." >&2 + ble/util/print "bleopt: Invalid value input_encoding='$value'. A function 'ble/encoding:$value/c2bc' is not defined." >&2 return 1 elif ! ble/is-function ble/encoding:"$value"/generate-binder; then - ble/util/print "bleopt: Invalid value input_encoding='$value'." \ - "A function 'ble/encoding:$value/generate-binder' is not defined." >&2 + ble/util/print "bleopt: Invalid value input_encoding='$value'. A function 'ble/encoding:$value/generate-binder' is not defined." >&2 return 1 elif ! ble/is-function ble/encoding:"$value"/is-intermediate; then - ble/util/print "bleopt: Invalid value input_encoding='$value'." \ - "A function 'ble/encoding:$value/is-intermediate' is not defined." >&2 + ble/util/print "bleopt: Invalid value input_encoding='$value'. A function 'ble/encoding:$value/is-intermediate' is not defined." >&2 return 1 fi