keymap.vi.sh (274965B)
1 #!/bin/bash 2 3 # Note: bind (INITIALIZE_DEFMAP) の中から再帰的に呼び出されうるので、 4 # 先に ble-edit/bind/load-editing-mode:vi を上書きする必要がある。 5 ble/is-function ble-edit/bind/load-editing-mode:vi && return 0 6 function ble-edit/bind/load-editing-mode:vi { :; } 7 8 # 2020-04-29 force update (rename ble-decode/keymap/.register) 9 # 2021-01-25 force update (change mapping of C-w and M-w) 10 # 2021-04-26 force update (rename ble/decode/keymap#.register) 11 # 2021-09-23 force update (change to nsearch and bind-history) 12 13 source "$_ble_base/lib/keymap.vi_digraph.sh" 14 15 ## @bleopt keymap_vi_macro_depth 16 bleopt/declare -n keymap_vi_macro_depth 64 17 18 ## @fn ble/keymap:vi/k2c key 19 ## @var[out] ret 20 function ble/keymap:vi/k2c { 21 local key=$1 22 local flag=$((key&_ble_decode_MaskFlag)) char=$((key&_ble_decode_MaskChar)) 23 if ((flag==0&&(32<=char&&char<_ble_decode_FunctionKeyBase))); then 24 ret=$char 25 return 0 26 elif ((flag==_ble_decode_Ctrl&&63<=char&&char<128&&(char&0x1F)!=0)); then 27 ((char=char==63?127:char&0x1F)) 28 ret=$char 29 return 0 30 else 31 return 1 32 fi 33 } 34 35 #------------------------------------------------------------------------------ 36 # utils 37 38 ## @fn ble/string#index-of-chars text chars [index] 39 ## 文字集合に含まれる文字を、文字列中で順方向に探索します。 40 ## @fn ble/string#last-index-of-chars text chars [index] 41 ## 文字集合に含まれる文字を、文字列中で逆方向に探索します。 42 ## 43 ## @param[in] text 44 ## 検索する対象の文字列を指定します。 45 ## @param[in] chars 46 ## 検索する文字の集合を指定します 47 ## @param[in] index 48 ## text の内の検索開始位置を指定します。 49 ## @var[out] ret 50 ## 51 function ble/string#index-of-chars { 52 local chars=$2 index=${3:-0} 53 local text=${1:index} 54 local cut=${text%%["$chars"]*} 55 if ((${#cut}<${#text})); then 56 ((ret=index+${#cut})) 57 return 0 58 else 59 ret=-1 60 return 1 61 fi 62 } 63 function ble/string#last-index-of-chars { 64 local text=$1 chars=$2 index=$3 65 [[ $index ]] && text=${text::index} 66 local cut=${text%["$chars"]*} 67 if ((${#cut}<${#text})); then 68 ((ret=${#cut})) 69 return 0 70 else 71 ret=-1 72 return 1 73 fi 74 } 75 76 ## @fn ble-edit/content/nonbol-eolp text 77 ## @var[out] ret 78 function ble-edit/content/nonbol-eolp { 79 local pos=${1:-$_ble_edit_ind} 80 ! ble-edit/content/bolp "$pos" && ble-edit/content/eolp "$pos" 81 } 82 83 ## @fn ble/keymap:vi/string#encode-rot13 text 84 ## @var[out] ret 85 function ble/keymap:vi/string#encode-rot13 { 86 local text=$1 87 local -a buff=() ch 88 for ((i=0;i<${#text};i++)); do 89 ch=${text:i:1} 90 if [[ $ch == [A-Z] ]]; then 91 ch=${_ble_util_string_upper_list%%"$ch"*} 92 ch=${_ble_util_string_upper_list:(${#ch}+13)%26:1} 93 elif [[ $ch == [a-z] ]]; then 94 ch=${_ble_util_string_lower_list%%"$ch"*} 95 ch=${_ble_util_string_lower_list:(${#ch}+13)%26:1} 96 fi 97 ble/array#push buff "$ch" 98 done 99 IFS= builtin eval 'ret="${buff[*]-}"' 100 } 101 102 #------------------------------------------------------------------------------ 103 # constants 104 105 _ble_keymap_vi_REX_WORD=$'[_a-zA-Z0-9]+|[!-/:-@[-`{-~]+|[^ \t\na-zA-Z0-9!-/:-@[-`{-~]+' 106 107 #------------------------------------------------------------------------------ 108 # vi_imap/__default__, vi-command/decompose-meta 109 110 function ble/widget/vi_imap/__default__ { 111 local flag=$((KEYS[0]&_ble_decode_MaskFlag)) code=$((KEYS[0]&_ble_decode_MaskChar)) 112 113 # メタ修飾付きの入力 M-key は ESC + key に分解する 114 if ((flag&_ble_decode_Meta)); then 115 ble/keymap:vi/imap-repeat/pop 116 117 local esc=27 # ESC 118 # local esc=$((_ble_decode_Ctrl|0x5b)) # もしくは C-[ 119 ble/decode/widget/skip-lastwidget 120 ((flag&=~_ble_decode_Meta)) 121 ((flag==_ble_decode_Shft&&0x61<=code&&code<=0x7A&&(flag=0,code-=0x20))) 122 ble/decode/widget/redispatch-by-keys "$esc" "$((flag|code))" "${KEYS[@]:1}" 123 return 0 124 fi 125 126 # Control 修飾された文字 C-@ - C-\, C-? は制御文字 \000 - \037, \177 に戻して挿入 127 if local ret; ble/keymap:vi/k2c "${KEYS[0]}"; then 128 local -a KEYS; KEYS=("$ret") 129 ble/widget/self-insert 130 return 0 131 fi 132 133 return 125 134 } 135 136 function ble/widget/vi-command/decompose-meta { 137 local flag=$((KEYS[0]&_ble_decode_MaskFlag)) code=$((KEYS[0]&_ble_decode_MaskChar)) 138 139 # メタ修飾付きの入力 M-key は ESC + key に分解する 140 if ((flag&_ble_decode_Meta)); then 141 local esc=$((_ble_decode_Ctrl|0x5b)) # C-[ (もしくは esc=27 ESC?) 142 ble/decode/widget/skip-lastwidget 143 ((flag&=~_ble_decode_Meta)) 144 ((flag==_ble_decode_Shft&&0x61<=code&&code<=0x7A&&(flag=0,code-=0x20))) 145 ble/decode/widget/redispatch-by-keys "$esc" "$((flag|code))" "${KEYS[@]:1}" 146 return 0 147 fi 148 149 return 125 150 } 151 152 function ble/widget/vi_omap/__default__ { 153 ble/widget/vi-command/decompose-meta || ble/widget/vi-command/bell 154 return 0 155 } 156 function ble/widget/vi_omap/cancel { 157 ble/keymap:vi/adjust-command-mode 158 return 0 159 } 160 161 #------------------------------------------------------------------------------ 162 # repeat 163 164 ## @var _ble_keymap_vi_irepeat_count 165 ## 挿入モードに入る時に指定された引数を記録する。 166 _ble_keymap_vi_irepeat_count= 167 168 ## @arr _ble_keymap_vi_irepeat 169 ## 挿入モードに入るときに指定された引数が 1 より大きい時、 170 ## 後で操作を繰り返すために操作内容を記録する配列。 171 ## 172 ## 各要素は keys:widget の形式を持つ。 173 ## keys は空白区切りの key (整数値) の列、つまり ${KEYS[*]} である。 174 ## widget は実際に呼び出す WIDGET の内容である。 175 ## 176 _ble_keymap_vi_irepeat=() 177 178 ble/array#push _ble_textarea_local_VARNAMES \ 179 _ble_keymap_vi_irepeat_count \ 180 _ble_keymap_vi_irepeat 181 182 function ble/keymap:vi/imap-repeat/pop { 183 local top_index=$((${#_ble_keymap_vi_irepeat[*]}-1)) 184 ((top_index>=0)) && builtin unset -v '_ble_keymap_vi_irepeat[top_index]' 185 } 186 function ble/keymap:vi/imap-repeat/push { 187 local IFS=$_ble_term_IFS 188 ble/array#push _ble_keymap_vi_irepeat "${KEYS[*]-}:$WIDGET" 189 } 190 191 function ble/keymap:vi/imap-repeat/reset { 192 local count=${1-} 193 _ble_keymap_vi_irepeat_count= 194 _ble_keymap_vi_irepeat=() 195 ((count>1)) && _ble_keymap_vi_irepeat_count=$count 196 } 197 function ble/keymap:vi/imap-repeat/process { 198 if ((_ble_keymap_vi_irepeat_count>1)); then 199 local repeat=$_ble_keymap_vi_irepeat_count 200 local -a widgets; widgets=("${_ble_keymap_vi_irepeat[@]}") 201 202 local i widget 203 for ((i=1;i<repeat;i++)); do 204 for widget in "${widgets[@]}"; do 205 ble/decode/widget/call "${widget#*:}" ${widget%%:*} 206 done 207 done 208 fi 209 } 210 211 function ble/keymap:vi/imap/invoke-widget { 212 local WIDGET=$1 213 local -a KEYS; KEYS=("${@:2}") 214 ble/keymap:vi/imap-repeat/push 215 builtin eval -- "$WIDGET" 216 } 217 218 ## @arr _ble_keymap_vi_imap_white_list 219 ## 引数を指定して入った挿入モードを抜けるときの繰り返しで許されるコマンドのリスト 220 _ble_keymap_vi_imap_white_list=( 221 self-insert 222 batch-insert 223 nop 224 magic-space magic-slash 225 delete-backward-{c,f,s,u}word 226 copy{,-forward,-backward}-{c,f,s,u}word 227 copy-region{,-or} 228 clear-screen 229 command-help 230 display-shell-version 231 redraw-line 232 ) 233 function ble/keymap:vi/imap/is-command-white { 234 if [[ $1 == ble/widget/self-insert ]]; then 235 # frequently used command is checked first 236 return 0 237 elif [[ $1 == ble/widget/* ]]; then 238 local IFS=$_ble_term_IFS 239 local cmd=${1#ble/widget/}; cmd=${cmd%%["$_ble_term_IFS"]*} 240 [[ $cmd == vi_imap/* || " ${_ble_keymap_vi_imap_white_list[*]} " == *" $cmd "* ]] && return 0 241 fi 242 return 1 243 } 244 245 function ble/widget/vi_imap/__before_widget__ { 246 if ble/keymap:vi/imap/is-command-white "$WIDGET"; then 247 ble/keymap:vi/imap-repeat/push 248 else 249 if ((_ble_keymap_vi_mark_edit_dbeg>=0)); then 250 ble/keymap:vi/mark/end-edit-area 251 ble/keymap:vi/repeat/record-insert 252 ble/keymap:vi/mark/start-edit-area 253 fi 254 ble/keymap:vi/imap-repeat/reset 255 fi 256 } 257 258 #------------------------------------------------------------------------------ 259 # vi_imap/complete 260 261 function ble/widget/vi_imap/complete { 262 ble/keymap:vi/imap-repeat/pop 263 ble/keymap:vi/undo/add more 264 ble/widget/complete "$@" 265 } 266 function ble/keymap:vi/complete/insert.hook { 267 [[ $_ble_decode_keymap == vi_imap || 268 $_ble_decode_keymap == auto_complete ]] || return 1 269 270 local original=${comp_text:insert_beg:insert_end-insert_beg} 271 local q="'" Q="'\''" 272 local WIDGET="ble/widget/complete-insert '${original//$q/$Q}' '${insert//$q/$Q}' '${suffix//$q/$Q}'" 273 ble/keymap:vi/imap-repeat/push 274 [[ $_ble_decode_keymap == vi_imap ]] && 275 ble/keymap:vi/undo/add more 276 } 277 blehook complete_insert!=ble/keymap:vi/complete/insert.hook 278 279 function ble-decode/keymap:vi_imap/bind-complete { 280 ble-bind -f 'C-i' 'vi_imap/complete' 281 ble-bind -f 'TAB' 'vi_imap/complete' 282 ble-bind -f 'C-TAB' 'menu-complete' 283 ble-bind -f 'S-C-i' 'menu-complete backward' 284 ble-bind -f 'S-TAB' 'menu-complete backward' 285 ble-bind -f 'auto_complete_enter' 'auto-complete-enter' 286 287 ble-bind -f 'C-x /' 'menu-complete context=filename' 288 ble-bind -f 'C-x ~' 'menu-complete context=username' 289 ble-bind -f 'C-x $' 'menu-complete context=variable' 290 ble-bind -f 'C-x @' 'menu-complete context=hostname' 291 ble-bind -f 'C-x !' 'menu-complete context=command' 292 293 ble-bind -f 'C-]' 'sabbrev-expand' 294 ble-bind -f 'C-x C-r' 'dabbrev-expand' 295 296 ble-bind -f 'C-x *' 'complete insert_all:context=glob' 297 ble-bind -f 'C-x g' 'complete show_menu:context=glob' 298 } 299 300 #------------------------------------------------------------------------------ 301 # modes 302 303 ## @var _ble_keymap_vi_insert_overwrite 304 ## 挿入モードに入った時の上書き文字 305 _ble_keymap_vi_insert_overwrite= 306 307 ## @var _ble_keymap_vi_insert_leave 308 ## 挿入モードから抜ける時に実行する関数を設定します 309 _ble_keymap_vi_insert_leave= 310 311 ## @var _ble_keymap_vi_single_command 312 ## ノーマルモードにおいて 1 つコマンドを実行したら 313 ## 元の挿入モードに戻るモード (C-o) にいるかどうかを表します。 314 _ble_keymap_vi_single_command= 315 _ble_keymap_vi_single_command_overwrite= 316 317 ble/array#push _ble_textarea_local_VARNAMES \ 318 _ble_keymap_vi_insert_overwrite \ 319 _ble_keymap_vi_insert_leave \ 320 _ble_keymap_vi_single_command \ 321 _ble_keymap_vi_single_command_overwrite 322 323 ## @bleopt keymap_vi_mode_string_nmap 324 ## ノーマルモードの時に表示する文字列を指定します。 325 ## 空文字列を指定したときは何も表示しません。 326 bleopt/declare -n keymap_vi_mode_string_nmap $'\e[1m~\e[m' 327 bleopt/declare -o keymap_vi_nmap_name keymap_vi_mode_string_nmap 328 329 bleopt/declare -v term_vi_imap '' 330 bleopt/declare -v term_vi_nmap '' 331 bleopt/declare -v term_vi_omap '' 332 bleopt/declare -v term_vi_xmap '' 333 bleopt/declare -v term_vi_smap '' 334 bleopt/declare -v term_vi_cmap '' 335 336 bleopt/declare -v keymap_vi_imap_cursor '' 337 bleopt/declare -v keymap_vi_nmap_cursor '' 338 bleopt/declare -v keymap_vi_omap_cursor '' 339 bleopt/declare -v keymap_vi_xmap_cursor '' 340 bleopt/declare -v keymap_vi_smap_cursor '' 341 bleopt/declare -v keymap_vi_cmap_cursor '' 342 function ble/keymap:vi/.process-cursor-options { 343 local keymap=${FUNCNAME[1]#bleopt/check:keymap_}; keymap=${keymap%_cursor} 344 ble-bind -m "$keymap" --cursor "$value" 345 local locate=$'\e[32m'$bleopt_source:$bleopt_lineno$'\e[m' 346 ble/util/print-lines \ 347 "bleopt ($locate): The option 'keymap_${keymap}_cursor' has been removed." \ 348 " Please use 'ble-bind -m $keymap --cursor $value' instead." >&2 349 } 350 function bleopt/check:keymap_vi_imap_cursor { ble/keymap:vi/.process-cursor-options; } 351 function bleopt/check:keymap_vi_nmap_cursor { ble/keymap:vi/.process-cursor-options; } 352 function bleopt/check:keymap_vi_omap_cursor { ble/keymap:vi/.process-cursor-options; } 353 function bleopt/check:keymap_vi_xmap_cursor { ble/keymap:vi/.process-cursor-options; } 354 function bleopt/check:keymap_vi_smap_cursor { ble/keymap:vi/.process-cursor-options; } 355 function bleopt/check:keymap_vi_cmap_cursor { ble/keymap:vi/.process-cursor-options; } 356 function bleopt/obsolete:keymap_vi_imap_cursor { :; } 357 function bleopt/obsolete:keymap_vi_nmap_cursor { :; } 358 function bleopt/obsolete:keymap_vi_omap_cursor { :; } 359 function bleopt/obsolete:keymap_vi_xmap_cursor { :; } 360 function bleopt/obsolete:keymap_vi_smap_cursor { :; } 361 function bleopt/obsolete:keymap_vi_cmap_cursor { :; } 362 363 bleopt/declare -v keymap_vi_mode_show 1 364 function bleopt/check:keymap_vi_mode_show { 365 local bleopt_keymap_vi_mode_show=$value 366 [[ $_ble_attached ]] && 367 ble/keymap:vi/update-mode-indicator 368 return 0 369 } 370 371 bleopt/declare -v keymap_vi_mode_update_prompt '' 372 bleopt/declare -v keymap_vi_mode_name_insert 'INSERT' 373 bleopt/declare -v keymap_vi_mode_name_replace 'REPLACE' 374 bleopt/declare -v keymap_vi_mode_name_vreplace 'VREPLACE' 375 bleopt/declare -v keymap_vi_mode_name_visual 'VISUAL' 376 bleopt/declare -v keymap_vi_mode_name_select 'SELECT' 377 bleopt/declare -v keymap_vi_mode_name_linewise 'LINE' 378 bleopt/declare -v keymap_vi_mode_name_blockwise 'BLOCK' 379 function bleopt/check:keymap_vi_mode_name_insert { ble/keymap:vi/update-mode-indicator; } 380 function bleopt/check:keymap_vi_mode_name_replace { ble/keymap:vi/update-mode-indicator; } 381 function bleopt/check:keymap_vi_mode_name_vreplace { ble/keymap:vi/update-mode-indicator; } 382 function bleopt/check:keymap_vi_mode_name_visual { ble/keymap:vi/update-mode-indicator; } 383 function bleopt/check:keymap_vi_mode_name_select { ble/keymap:vi/update-mode-indicator; } 384 function bleopt/check:keymap_vi_mode_name_linewise { ble/keymap:vi/update-mode-indicator; } 385 function bleopt/check:keymap_vi_mode_name_blockwise { ble/keymap:vi/update-mode-indicator; } 386 387 388 ## @fn ble/keymap:vi/script/get-vi-keymap 389 ## 現在の vi キーマップ名 (vi_?map) を取得します。 390 ## もし現在 vi キーマップにない場合には失敗します。 391 function ble/keymap:vi/script/get-vi-keymap { 392 ble/prompt/unit/add-hash '$_ble_decode_keymap,${_ble_decode_keymap_stack[*]}' 393 local i=${#_ble_decode_keymap_stack[@]} 394 395 keymap=$_ble_decode_keymap 396 while [[ $keymap != vi_?map && $keymap != emacs ]]; do 397 ((i--)) || return 1 398 keymap=${_ble_decode_keymap_stack[i]} 399 done 400 [[ $keymap == vi_?map ]] 401 } 402 403 ## @fn ble/keymap:vi/script/get-mode 404 ## @var[out] mode 405 function ble/keymap:vi/script/get-mode { 406 ble/prompt/unit/add-hash '$_ble_decode_keymap,${_ble_decode_keymap_stack[*]}' 407 ble/prompt/unit/add-hash '$_ble_keymap_vi_single_command,$_ble_edit_mark_active' 408 409 mode= 410 411 local keymap; ble/keymap:vi/script/get-vi-keymap 412 413 # /[iR^R]?/ 414 if [[ $_ble_keymap_vi_single_command || $keymap == vi_imap ]]; then 415 local overwrite= 416 if [[ $keymap == vi_imap ]]; then 417 overwrite=$_ble_edit_overwrite_mode 418 elif [[ $keymap == vi_[noxs]map ]]; then 419 overwrite=$_ble_keymap_vi_single_command_overwrite 420 fi 421 case $overwrite in 422 ('') mode=i ;; 423 (R) mode=R ;; 424 (*) mode=$'\x12' ;; # C-r 425 esac 426 fi 427 428 # /[nvV^VsS^S]?/ 429 case $keymap:${_ble_edit_mark_active%+} in 430 (vi_xmap:vi_line) mode=$mode'V' ;; 431 (vi_xmap:vi_block)mode=$mode$'\x16' ;; # C-v 432 (vi_xmap:*) mode=$mode'v' ;; 433 (vi_smap:vi_line) mode=$mode'S' ;; 434 (vi_smap:vi_block)mode=$mode$'\x13' ;; # C-s 435 (vi_smap:*) mode=$mode's' ;; 436 (vi_[no]map:*) mode=$mode'n' ;; 437 (vi_cmap:*) mode=$mode'c' ;; 438 (vi_imap:*) ;; 439 (*:*) mode=$mode'?' ;; 440 esac 441 } 442 443 _ble_keymap_vi_mode_name_dirty= 444 function ble/keymap:vi/info_reveal.hook { 445 [[ $_ble_keymap_vi_mode_name_dirty ]] || return 0 446 _ble_keymap_vi_mode_name_dirty= 447 ble/keymap:vi/update-mode-indicator 448 } 449 blehook info_reveal!=ble/keymap:vi/info_reveal.hook 450 451 bleopt/declare -v prompt_vi_mode_indicator '\q{keymap:vi/mode-indicator}' 452 function bleopt/check:prompt_vi_mode_indicator { 453 local bleopt_prompt_vi_mode_indicator=$value 454 [[ $_ble_attached ]] && ble/keymap:vi/update-mode-indicator 455 return 0 456 } 457 458 _ble_keymap_vi_mode_indicator_data=() 459 function ble/prompt/unit:_ble_keymap_vi_mode_indicator/update { 460 local trace_opts=truncate:relative:noscrc:ansi 461 local prompt_rows=1 462 local prompt_cols=${COLUMNS:-80} 463 ((prompt_cols&&prompt_cols--)) 464 local "${_ble_prompt_cache_vars[@]/%/=}" # WA #D1570 checked 465 ble/prompt/unit:{section}/update _ble_keymap_vi_mode_indicator "$bleopt_prompt_vi_mode_indicator" "$trace_opts" 466 } 467 468 function ble/keymap:vi/update-mode-indicator { 469 if [[ ! $_ble_attached ]] || ble/edit/is-command-layout; then 470 _ble_keymap_vi_mode_name_dirty=1 471 return 0 472 fi 473 474 local keymap 475 ble/keymap:vi/script/get-vi-keymap || return 0 476 477 if [[ $keymap == vi_imap ]]; then 478 ble/util/buffer "$bleopt_term_vi_imap" 479 elif [[ $keymap == vi_nmap ]]; then 480 ble/util/buffer "$bleopt_term_vi_nmap" 481 elif [[ $keymap == vi_xmap ]]; then 482 ble/util/buffer "$bleopt_term_vi_xmap" 483 elif [[ $keymap == vi_smap ]]; then 484 ble/util/buffer "$bleopt_term_vi_smap" 485 elif [[ $keymap == vi_omap ]]; then 486 ble/util/buffer "$bleopt_term_vi_omap" 487 elif [[ $keymap == vi_cmap ]]; then 488 ble/edit/info/default text '' 489 ble/util/buffer "$bleopt_term_vi_cmap" 490 return 0 491 fi 492 493 [[ $bleopt_keymap_vi_mode_update_prompt ]] && ble/prompt/clear 494 495 # prompt_vi_mode_indicator 496 local prompt_vi_keymap=$keymap 497 local version=$COLUMNS,$_ble_edit_lineno,$_ble_history_count,$_ble_edit_CMD 498 local prompt_hashref_base='$version' 499 ble/prompt/unit#update _ble_keymap_vi_mode_indicator 500 local ret; ble/prompt/unit:{section}/get _ble_keymap_vi_mode_indicator; local mode=$ret 501 502 local str=$mode 503 if [[ $_ble_keymap_vi_reg_record ]]; then 504 str=$str${str:+' '}$'\e[1;31mREC @'$_ble_keymap_vi_reg_record_char$'\e[m' 505 elif [[ $_ble_edit_kbdmacro_record ]]; then 506 str=$str${str:+' '}$'\e[1;31mREC\e[m' 507 fi 508 509 # Note #D2062: mc-4.8.29 以降ではコマンド終了直後に "-- INSERT --" 等の mode 510 # indicator を出力すると、それをプロンプトと勘違いして抽出してしまう。仕方が 511 # ないので mc の中では imap に対しては mode indicator は表示しない様にする。 512 if [[ $_ble_edit_integration_mc_precmd_stop && $keymap == vi_imap ]]; then 513 ble/edit/info/clear 514 return 0 515 fi 516 517 ble/edit/info/default ansi "$str" # 6ms 518 } 519 blehook internal_PRECMD!=ble/keymap:vi/update-mode-indicator 520 521 ## @fn ble/prompt/backslash:keymap:vi/mode-indicator 522 ## @var[in,opt] prompt_vi_keymap 523 ## ble/keymap:vi/script/get-vi-keymap のキャッシュ 524 function ble/prompt/backslash:keymap:vi/mode-indicator { 525 [[ $bleopt_keymap_vi_mode_show ]] || return 0 526 527 local keymap=${prompt_vi_keymap-} 528 if [[ $keymap ]]; then 529 ble/prompt/unit/add-hash '$_ble_decode_keymap,${_ble_decode_keymap_stack[*]}' 530 else 531 ble/keymap:vi/script/get-vi-keymap || return 0 532 fi 533 534 local name= show= overwrite= 535 ble/prompt/unit/add-hash '$_ble_edit_overwrite_mode,$_ble_keymap_vi_single_command,$_ble_keymap_vi_single_command_overwrite' 536 if [[ $keymap == vi_imap ]]; then 537 show=1 overwrite=$_ble_edit_overwrite_mode 538 elif [[ $_ble_keymap_vi_single_command && ( $keymap == vi_nmap || $keymap == vi_omap ) ]]; then 539 show=1 overwrite=$_ble_keymap_vi_single_command_overwrite 540 elif [[ $keymap == vi_[xs]map ]]; then 541 show=x overwrite=$_ble_keymap_vi_single_command_overwrite 542 else 543 name=$bleopt_keymap_vi_mode_string_nmap 544 fi 545 546 if [[ $show ]]; then 547 if [[ $overwrite == R ]]; then 548 name=$bleopt_keymap_vi_mode_name_replace 549 elif [[ $overwrite ]]; then 550 name=$bleopt_keymap_vi_mode_name_vreplace 551 else 552 name=$bleopt_keymap_vi_mode_name_insert 553 fi 554 555 if [[ $_ble_keymap_vi_single_command ]]; then 556 local ret; ble/string#tolower "$name"; name="($ret)" 557 fi 558 559 if [[ $show == x ]]; then 560 ble/prompt/unit/add-hash '${_ble_edit_mark_active%+}' 561 local mark_type=${_ble_edit_mark_active%+} 562 local visual_name=$bleopt_keymap_vi_mode_name_visual 563 [[ $keymap == vi_smap ]] && visual_name=$bleopt_keymap_vi_mode_name_select 564 if [[ $mark_type == vi_line ]]; then 565 visual_name=$visual_name' '$bleopt_keymap_vi_mode_name_linewise 566 elif [[ $mark_type == vi_block ]]; then 567 visual_name=$visual_name' '$bleopt_keymap_vi_mode_name_blockwise 568 fi 569 570 if [[ $_ble_keymap_vi_single_command ]]; then 571 name="$name $visual_name" 572 else 573 name=$visual_name 574 fi 575 fi 576 577 name=$'\e[1m-- '$name$' --\e[m' 578 fi 579 580 [[ ! $name ]] || ble/prompt/print "$name" 581 } 582 583 function ble/widget/vi_imap/normal-mode.impl { 584 local opts=$1 585 586 # finalize insert mode 587 ble/keymap:vi/mark/set-local-mark 94 "$_ble_edit_ind" # `^ 588 ble/keymap:vi/mark/end-edit-area 589 [[ :$opts: == *:InsertLeave:* ]] && builtin eval -- "$_ble_keymap_vi_insert_leave" 590 591 # set up normal mode 592 _ble_edit_mark_active= 593 _ble_edit_overwrite_mode= 594 _ble_keymap_vi_insert_leave= 595 _ble_keymap_vi_single_command= 596 _ble_keymap_vi_single_command_overwrite= 597 ble-edit/content/bolp || ((_ble_edit_ind--)) 598 ble/decode/keymap/push vi_nmap 599 } 600 function ble/widget/vi_imap/normal-mode { 601 ble-edit/content/clear-arg 602 ble/keymap:vi/imap-repeat/pop 603 ble/keymap:vi/imap-repeat/process 604 ble/keymap:vi/repeat/record-insert 605 ble/widget/vi_imap/normal-mode.impl InsertLeave 606 ble/keymap:vi/update-mode-indicator 607 return 0 608 } 609 function ble/widget/vi_imap/normal-mode-without-insert-leave { 610 ble-edit/content/clear-arg 611 ble/keymap:vi/imap-repeat/pop 612 ble/keymap:vi/repeat/record-insert 613 ble/widget/vi_imap/normal-mode.impl 614 ble/keymap:vi/update-mode-indicator 615 return 0 616 } 617 function ble/widget/vi_imap/single-command-mode { 618 ble-edit/content/clear-arg 619 local single_command=1 620 local single_command_overwrite=$_ble_edit_overwrite_mode 621 ble-edit/content/eolp && _ble_keymap_vi_single_command=2 622 623 ble/keymap:vi/imap-repeat/pop 624 ble/widget/vi_imap/normal-mode.impl 625 _ble_keymap_vi_single_command=$single_command 626 _ble_keymap_vi_single_command_overwrite=$single_command_overwrite 627 ble/keymap:vi/update-mode-indicator 628 return 0 629 } 630 631 ## @fn ble/keymap:vi/needs-eol-fix 632 ## 633 ## Note: この関数を使った後は ble/keymap:vi/adjust-command-mode を呼び出す必要がある。 634 ## そうしないとノーマルモードにおいてありえない位置にカーソルが来ることになる。 635 ## 636 function ble/keymap:vi/needs-eol-fix { 637 [[ $_ble_decode_keymap == vi_nmap || $_ble_decode_keymap == vi_omap ]] || return 1 638 [[ $_ble_keymap_vi_single_command ]] && return 1 639 local index=${1:-$_ble_edit_ind} 640 ble-edit/content/nonbol-eolp "$index" 641 } 642 function ble/keymap:vi/adjust-command-mode { 643 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 644 # 移動コマンドが来たら末尾拡張を無効にする。 645 # 移動コマンドはここを通るはず… 646 ble/keymap:vi/xmap/remove-eol-extension 647 fi 648 649 local kmap_popped= 650 if [[ $_ble_decode_keymap == vi_omap ]]; then 651 ble/decode/keymap/pop 652 kmap_popped=1 653 fi 654 655 # search による mark の設定・解除 656 if [[ $_ble_keymap_vi_search_activate ]]; then 657 if [[ $_ble_decode_keymap != vi_[xs]map ]]; then 658 _ble_edit_mark_active=$_ble_keymap_vi_search_activate 659 fi 660 _ble_keymap_vi_search_matched=1 661 _ble_keymap_vi_search_activate= 662 else 663 [[ $_ble_edit_mark_active == vi_search ]] && _ble_edit_mark_active= 664 ((_ble_keymap_vi_search_matched)) && _ble_keymap_vi_search_matched= 665 fi 666 667 if [[ $_ble_decode_keymap == vi_nmap && $_ble_keymap_vi_single_command ]]; then 668 if ((_ble_keymap_vi_single_command==2)); then 669 local index=$((_ble_edit_ind+1)) 670 ble-edit/content/nonbol-eolp "$index" && _ble_edit_ind=$index 671 fi 672 ble/widget/vi_nmap/.insert-mode 1 "$_ble_keymap_vi_single_command_overwrite" resume 673 ble/keymap:vi/repeat/clear-insert 674 elif [[ $kmap_popped ]]; then 675 ble/keymap:vi/update-mode-indicator 676 fi 677 678 return 0 679 } 680 function ble/widget/vi-command/bell { 681 ble/widget/.bell "$1" 682 ble/keymap:vi/adjust-command-mode 683 return 0 684 } 685 686 ## @fn ble/widget/vi_nmap/.insert-mode [arg [overwrite [opts]]] 687 ## @param[in] arg 688 ## @param[in] overwrite 689 ## @param[in] opts 690 function ble/widget/vi_nmap/.insert-mode { 691 [[ $_ble_decode_keymap == vi_[xs]map ]] && ble/decode/keymap/pop 692 [[ $_ble_decode_keymap == vi_omap ]] && ble/decode/keymap/pop 693 local arg=$1 overwrite=$2 694 ble/keymap:vi/imap-repeat/reset "$arg" 695 _ble_edit_mark_active= 696 _ble_edit_overwrite_mode=$overwrite 697 _ble_keymap_vi_insert_leave= 698 _ble_keymap_vi_insert_overwrite=$overwrite 699 _ble_keymap_vi_single_command= 700 _ble_keymap_vi_single_command_overwrite= 701 ble/keymap:vi/search/clear-matched 702 ble/decode/keymap/pop 703 ble/keymap:vi/update-mode-indicator 704 705 ble/keymap:vi/mark/start-edit-area 706 if [[ :$opts: != *:resume:* ]]; then 707 ble/keymap:vi/mark/commit-edit-area "$_ble_edit_ind" "$_ble_edit_ind" 708 fi 709 } 710 function ble/widget/vi_nmap/insert-mode { 711 local ARG FLAG REG; ble/keymap:vi/get-arg 1 712 ble/widget/vi_nmap/.insert-mode "$ARG" 713 ble/keymap:vi/repeat/record 714 return 0 715 } 716 function ble/widget/vi_nmap/append-mode { 717 local ARG FLAG REG; ble/keymap:vi/get-arg 1 718 if ! ble-edit/content/eolp; then 719 ((_ble_edit_ind++)) 720 fi 721 ble/widget/vi_nmap/.insert-mode "$ARG" 722 ble/keymap:vi/repeat/record 723 return 0 724 } 725 function ble/widget/vi_nmap/append-mode-at-end-of-line { 726 local ARG FLAG REG; ble/keymap:vi/get-arg 1 727 local ret; ble-edit/content/find-logical-eol 728 _ble_edit_ind=$ret 729 ble/widget/vi_nmap/.insert-mode "$ARG" 730 ble/keymap:vi/repeat/record 731 return 0 732 } 733 function ble/widget/vi_nmap/insert-mode-at-beginning-of-line { 734 local ARG FLAG REG; ble/keymap:vi/get-arg 1 735 local ret; ble-edit/content/find-logical-bol 736 _ble_edit_ind=$ret 737 ble/widget/vi_nmap/.insert-mode "$ARG" 738 ble/keymap:vi/repeat/record 739 return 0 740 } 741 function ble/widget/vi_nmap/insert-mode-at-first-non-space { 742 local ARG FLAG REG; ble/keymap:vi/get-arg 1 743 ble/widget/vi-command/first-non-space 744 [[ ${_ble_edit_str:_ble_edit_ind:1} == [$' \t'] ]] && 745 ((_ble_edit_ind++)) # 逆eol補正 746 ble/widget/vi_nmap/.insert-mode "$ARG" 747 ble/keymap:vi/repeat/record 748 return 0 749 } 750 # nmap: gi 751 function ble/widget/vi_nmap/insert-mode-at-previous-point { 752 local ARG FLAG REG; ble/keymap:vi/get-arg 1 753 local ret 754 ble/keymap:vi/mark/get-local-mark 94 && _ble_edit_ind=$ret 755 ble/widget/vi_nmap/.insert-mode "$ARG" 756 ble/keymap:vi/repeat/record 757 return 0 758 } 759 function ble/widget/vi_nmap/replace-mode { 760 local ARG FLAG REG; ble/keymap:vi/get-arg 1 761 ble/widget/vi_nmap/.insert-mode "$ARG" R 762 ble/keymap:vi/repeat/record 763 return 0 764 } 765 function ble/widget/vi_nmap/virtual-replace-mode { 766 local ARG FLAG REG; ble/keymap:vi/get-arg 1 767 ble/widget/vi_nmap/.insert-mode "$ARG" 1 768 ble/keymap:vi/repeat/record 769 return 0 770 } 771 function ble/widget/vi_nmap/accept-line { 772 ble/keymap:vi/clear-arg 773 ble/widget/vi_nmap/.insert-mode 774 ble/keymap:vi/repeat/clear-insert 775 [[ $_ble_keymap_vi_reg_record ]] && 776 ble/widget/vi_nmap/record-register 777 ble/widget/default/accept-line 778 } 779 function ble/widget/vi-command/edit-and-execute-command { 780 ble/keymap:vi/clear-arg 781 ble/widget/vi_nmap/.insert-mode 782 ble/keymap:vi/repeat/clear-insert 783 [[ $_ble_keymap_vi_reg_record ]] && 784 ble/widget/vi_nmap/record-register 785 ble/widget/edit-and-execute-command 786 } 787 788 #------------------------------------------------------------------------------ 789 # args 790 # 791 # arg : 0-9 d y c 792 # command : dd yy cc [dyc]0 Y S 793 794 _ble_keymap_vi_oparg= 795 _ble_keymap_vi_opfunc= 796 _ble_keymap_vi_reg= 797 798 ble/array#push _ble_textarea_local_VARNAMES \ 799 _ble_keymap_vi_oparg \ 800 _ble_keymap_vi_opfunc \ 801 _ble_keymap_vi_reg 802 803 # ble/keymap:vi における _ble_edit_kill_ring の扱いついて 804 # 805 # _ble_edit_kill_type=L のとき 806 # 行指向の切り取り文字列であることを表し、 807 # _ble_edit_kill_ring の末端には必ず改行文字が来ると仮定して良い。 808 # 809 # _ble_edit_kill_type=B:* の形式をしているとき、 810 # 矩形の切り取り文字列であることを表し、 811 # _ble_edit_kill_ring は改行区切りで各行を連結したものである。 812 # 末端には改行文字は付加しない。末端に改行文字があるときは、 813 # それは付加された改行ではなく、最後に空行があることを意味する。 814 # 815 # _ble_edit_kill_type の 2 文字目以降は数字を空白区切りで並べたもので、 816 # 各数字は _ble_edit_kill_ring 内の各行に対応する。 817 # 意味は、行の途中に挿入する際に矩形を保つために右に補填するべき空白の数である。 818 # 行末に挿入する際にはこの空白の補填は起こらないことに注意する。 819 # 820 # _ble_edit_kill_type= (空文字列) もしくは それ意外の場合は 821 # 通常の切り取り文字列であることを表す。 822 # _ble_edit_kill_ring は任意の文字列である。 823 # 824 _ble_keymap_vi_register=() 825 _ble_keymap_vi_register_onplay= 826 827 ## @fn ble/keymap:vi/clear-arg 828 function ble/keymap:vi/clear-arg { 829 _ble_edit_arg= 830 _ble_keymap_vi_oparg= 831 _ble_keymap_vi_opfunc= 832 _ble_keymap_vi_reg= 833 } 834 ## @fn ble/keymap:vi/get-arg [default_value]; ARG FLAG REG 835 ## 836 ## 引数の内容について 837 ## vi_nmap, vi_xmap, vi_smap においては FLAG は空であると仮定して良い。 838 ## vi_omap においては FLAG は非空である。 839 ## get-arg{,-reg} を呼び出すことによって空になる。 840 ## つまり vi_omap においてこの関数を呼び出したとき、vi_omap から vi_nmap に戻る必要がある。 841 ## これは通例 ble/keymap:vi/adjust-command-mode によって実施される。 842 ## 843 function ble/keymap:vi/get-arg { 844 local default_value=$1 845 REG=$_ble_keymap_vi_reg 846 FLAG=$_ble_keymap_vi_opfunc 847 if [[ ! $_ble_edit_arg && ! $_ble_keymap_vi_oparg ]]; then 848 ARG=$default_value 849 else 850 ARG=$((10#0${_ble_edit_arg:-1}*10#0${_ble_keymap_vi_oparg:-1})) 851 fi 852 ble/keymap:vi/clear-arg 853 } 854 ## @fn ble/keymap:vi/register#load reg 855 function ble/keymap:vi/register#load { 856 local reg=$1 857 if [[ $reg ]] && ((reg!=34)); then 858 if [[ $reg == 37 ]]; then # "% 859 ble-edit/content/push-kill-ring "$HISTFILE" '' 860 return 0 861 fi 862 863 local value=${_ble_keymap_vi_register[reg]} 864 if [[ $value == */* ]]; then 865 ble-edit/content/push-kill-ring "${value#*/}" "${value%%/*}" 866 return 0 867 else 868 ble-edit/content/push-kill-ring 869 return 1 870 fi 871 fi 872 } 873 ## @fn ble/keymap:vi/register#set reg type content 874 function ble/keymap:vi/register#set { 875 local reg=$1 type=$2 content=$3 876 877 # type = L は行指向の値 878 # type = B は矩形指向の値 879 # type = '' は文字指向の値 880 # type = q はキーボードマクロ 881 # 882 # Note: 実際に記録される type は以下の何れかである。 883 # type = L 884 # type = B:* 885 # type = '' 886 887 # 追記の場合 888 if [[ $reg == +* ]]; then 889 local value=${_ble_keymap_vi_register[reg]} 890 if [[ $value == */* ]]; then 891 local otype=${value%%/*} 892 local oring=${value#*/} 893 894 if [[ $otype == L ]]; then 895 if [[ $type == q ]]; then 896 type=L content=${oring%$'\n'}$content # V + * → V 897 else 898 type=L content=$oring$content # V + * → V 899 fi 900 elif [[ $type == L ]]; then 901 type=L content=$oring$'\n'$content # C-v + V, v + V → V 902 elif [[ $otype == B:* ]]; then 903 if [[ $type == B:* ]]; then 904 type=$otype' '${type#B:} 905 content=$oring$'\n'$content # C-v + C-v → C-v 906 elif [[ $type == q ]]; then 907 local ret; ble/string#count-char "$content" $'\n' 908 ble/string#repeat ' 0' "$ret" 909 type=$otype$ret 910 content=$oring$$content # C-v + q → C-v 911 else 912 local ret; ble/string#count-char "$content" $'\n' 913 ble/string#repeat ' 0' "$((ret+1))" 914 type=$otype$ret 915 content=$oring$'\n'$content # C-v + v → C-v 916 fi 917 else 918 type= content=$oring$content # v + C-v, v + v, v + q → v 919 fi 920 fi 921 fi 922 923 [[ $type == L && $content != *$'\n' ]] && content=$content$'\n' 924 925 local suppress_default= 926 [[ $type == q ]] && type= suppress_default=1 927 928 if [[ ! $reg ]] || ((reg==34)); then # "" 929 # unnamed register 930 ble-edit/content/push-kill-ring "$content" "$type" 931 return 0 932 elif ((reg==58||reg==46||reg==37||reg==126)); then # ": ". "% "~ 933 # read only register 934 ble/widget/.bell "attempted to write on a read-only register #$reg" 935 return 1 936 elif ((reg==95)); then # "_ 937 # black hole register 938 return 0 939 else 940 if [[ ! $suppress_default ]]; then 941 ble-edit/content/push-kill-ring "$content" "$type" 942 fi 943 _ble_keymap_vi_register[reg]=$type/$content 944 return 0 945 fi 946 } 947 948 ## @fn ble/keymap:vi/register#set-yank reg type content 949 ## レジスタ "0 に文字列を登録します。 950 ## 951 function ble/keymap:vi/register#set-yank { 952 ble/keymap:vi/register#set "$@" || return 1 953 local reg=$1 type=$2 content=$3 954 if [[ $reg == '' || $reg == 34 ]]; then 955 ble/keymap:vi/register#set 48 "$type" "$content" # "0 956 fi 957 } 958 ## @fn ble/keymap:vi/register#set-edit reg type content 959 ## レジスタ "1 に文字列を登録します。 960 ## 961 ## content に改行が含まれる場合、または、特定の WIDGET の時、 962 ## 元々レジスタ "1 - "8 にあった内容をレジスタ "2 - "9 に移動し、 963 ## 新しい文字列をレジスタ "1 に登録します。 964 ## それ以外の時、新しい文字列はレジスタ "- に登録します。 965 ## 966 _ble_keymap_vi_register_49_widget_list=( 967 # % 968 ble/widget/vi-command/search-matchpair-or 969 ble/widget/vi-command/percentage-line 970 971 # ` 972 ble/widget/vi-command/goto-mark 973 974 # / ? n N 975 ble/widget/vi-command/search-forward 976 ble/widget/vi-command/search-backward 977 ble/widget/vi-command/search-repeat 978 ble/widget/vi-command/search-reverse-repeat 979 980 # ( ) { } 981 # ToDo 982 ) 983 function ble/keymap:vi/register#set-edit { 984 ble/keymap:vi/register#set "$@" || return 1 985 local reg=$1 type=$2 content=$3 986 if [[ $reg == '' || $reg == 34 ]]; then 987 local IFS=$_ble_term_IFS 988 local widget=${WIDGET%%["$_ble_term_IFS"]*} 989 if [[ $content == *$'\n'* || " $widget " == " ${_ble_keymap_vi_register_49_widget_list[*]} " ]]; then 990 local n 991 for ((n=9;n>=2;n--)); do 992 _ble_keymap_vi_register[48+n]=${_ble_keymap_vi_register[48+n-1]} 993 done 994 ble/keymap:vi/register#set 49 "$type" "$content" # "1 995 else 996 ble/keymap:vi/register#set 45 "$type" "$content" # "- 997 fi 998 fi 999 } 1000 1001 function ble/keymap:vi/register#play { 1002 local reg=$1 value 1003 if [[ $reg ]] && ((reg!=34)); then 1004 value=${_ble_keymap_vi_register[reg]} 1005 if [[ $value == */* ]]; then 1006 value=${value#*/} 1007 else 1008 value= 1009 return 1 1010 fi 1011 else 1012 value=$_ble_edit_kill_ring 1013 fi 1014 1015 local _ble_keymap_vi_register_onplay=1 1016 local ret; ble/decode/charlog#decode "$value" 1017 ble/widget/.MACRO "${ret[@]}" 1018 return 0 1019 } 1020 ## @fn ble/keymap:vi/register#dump/escape text 1021 ## @var[out] ret 1022 function ble/keymap:vi/register#dump/escape { 1023 local text=$1 1024 local out= i=0 iN=${#text} 1025 while ((i<iN)); do 1026 local tail=${text:i} 1027 if ble/util/isprint+ "$tail"; then 1028 out=$out$BASH_REMATCH 1029 ((i+=${#BASH_REMATCH})) 1030 else 1031 ble/util/s2c "$tail" 1032 local code=$ret 1033 if ((code<32)); then 1034 ble/util/c2s "$((code+64))" 1035 out=$out$_ble_term_rev^$ret$_ble_term_sgr0 1036 elif ((code==127)); then 1037 out=$out$_ble_term_rev^?$_ble_term_sgr0 1038 elif ((128<=code&&code<160)); then 1039 ble/util/c2s "$((code-64))" 1040 out=$out${_ble_term_rev}M-^$ret$_ble_term_sgr0 1041 else 1042 out=$out${tail::1} 1043 fi 1044 ((i++)) 1045 fi 1046 done 1047 ret=$out 1048 } 1049 function ble/keymap:vi/register#dump { 1050 local k ret out= 1051 local value type content 1052 for k in 34 "${!_ble_keymap_vi_register[@]}"; do 1053 if ((k==34)); then 1054 type=$_ble_edit_kill_type 1055 content=$_ble_edit_kill_ring 1056 else 1057 value=${_ble_keymap_vi_register[k]} 1058 type=${value%%/*} content=${value#*/} 1059 fi 1060 1061 ble/util/c2s "$k"; k=$ret 1062 case $type in 1063 (L) type=line ;; 1064 (B:*) type=block ;; 1065 (*) type=char ;; 1066 esac 1067 ble/keymap:vi/register#dump/escape "$content"; content=$ret 1068 1069 out=$out'"'$k' ('$type') '$content$'\n' 1070 done 1071 ble/edit/info/show ansi "$out" 1072 return 0 1073 } 1074 function ble/widget/vi-command:reg { ble/keymap:vi/register#dump; } 1075 function ble/widget/vi-command:regi { ble/keymap:vi/register#dump; } 1076 function ble/widget/vi-command:regis { ble/keymap:vi/register#dump; } 1077 function ble/widget/vi-command:regist { ble/keymap:vi/register#dump; } 1078 function ble/widget/vi-command:registe { ble/keymap:vi/register#dump; } 1079 function ble/widget/vi-command:register { ble/keymap:vi/register#dump; } 1080 function ble/widget/vi-command:registers { ble/keymap:vi/register#dump; } 1081 1082 function ble/widget/vi-command/append-arg { 1083 local ret ch=$1 1084 if [[ ! $ch ]]; then 1085 local n=${#KEYS[@]} 1086 local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar)) 1087 ((code==0)) && return 1 1088 ble/util/c2s "$code"; ch=$ret 1089 fi 1090 ble/util/assert '[[ ! ${ch//[0-9]} ]]' 1091 1092 # 0 1093 if [[ $ch == 0 && ! $_ble_edit_arg ]]; then 1094 ble/widget/vi-command/beginning-of-line 1095 return "$?" 1096 fi 1097 1098 _ble_edit_arg="$_ble_edit_arg$ch" 1099 return 0 1100 } 1101 function ble/widget/vi-command/register { 1102 _ble_decode_key__hook="ble/widget/vi-command/register.hook" 1103 } 1104 function ble/widget/vi-command/register.hook { 1105 local key=$1 1106 ble/keymap:vi/clear-arg 1107 local ret 1108 if ble/keymap:vi/k2c "$key" && local c=$ret; then 1109 if ((65<=c&&c<91)); then # A-Z 1110 _ble_keymap_vi_reg=+$((c+32)) 1111 return 0 1112 elif ((97<=c&&c<123||48<=c&&c<58||c==45||c==58||c==46||c==37||c==35||c==61||c==42||c==43||c==126||c==95||c==47)); then # a-z 0-9 - : . % # = * + ~ _ / 1113 _ble_keymap_vi_reg=$c 1114 return 0 1115 elif ((c==34)); then # "" 1116 # Note: vim の内部的には "" を指定するのと何も指定しないのは区別される。 1117 # 例えば diw"y. は "y に記録されるが ""diw"y. は "" に記録される。 1118 _ble_keymap_vi_reg=$c 1119 return 0 1120 fi 1121 fi 1122 ble/widget/vi-command/bell 1123 return 1 1124 } 1125 1126 _ble_keymap_vi_reg_record= 1127 _ble_keymap_vi_reg_record_char= 1128 _ble_keymap_vi_reg_record_play=0 1129 ble/array#push _ble_textarea_local_VARNAMES \ 1130 _ble_keymap_vi_reg_record \ 1131 _ble_keymap_vi_reg_record_char \ 1132 _ble_keymap_vi_reg_record_play 1133 1134 # nmap q 1135 function ble/widget/vi_nmap/record-register { 1136 # レジスタに含まれる q は再生中には何も起こさない 1137 if [[ $_ble_keymap_vi_register_onplay ]]; then 1138 ble/keymap:vi/clear-arg 1139 ble/keymap:vi/adjust-command-mode 1140 return 0 1141 fi 1142 1143 if [[ $_ble_keymap_vi_reg_record ]]; then 1144 ble/keymap:vi/clear-arg 1145 local -a ret 1146 ble/decode/charlog#end-exclusive-depth1 1147 ble/decode/charlog#encode "${ret[@]}" 1148 ble/keymap:vi/register#set "$_ble_keymap_vi_reg_record" q "$ret" 1149 1150 _ble_keymap_vi_reg_record= 1151 ble/keymap:vi/update-mode-indicator 1152 else 1153 _ble_decode_key__hook="ble/widget/vi_nmap/record-register.hook" 1154 fi 1155 } 1156 function ble/widget/vi_nmap/record-register.hook { 1157 local key=$1 ret 1158 ble/keymap:vi/clear-arg 1159 1160 # check register 1161 local reg= c= 1162 if ble/keymap:vi/k2c "$key" && c=$ret; then 1163 if ((65<=c&&c<91)); then # q{A-Z} 1164 reg=+$((c+32)) 1165 elif ((48<=c&&c<58||97<=c&&c<123)); then # q{0-9a-z} 1166 reg=$c 1167 elif ((c==34)); then # q" 1168 reg=$c 1169 fi 1170 fi 1171 if [[ ! $reg ]]; then 1172 ble/widget/vi-command/bell "invalid register key=$key" 1173 return 1 1174 fi 1175 1176 # start logging 1177 if ! ble/decode/charlog#start vi-macro; then 1178 ble/widget/.bell 'vi-macro: the logging system is currently busy' 1179 return 1 1180 fi 1181 1182 # update status 1183 ble/util/c2s "$c" 1184 _ble_keymap_vi_reg_record=$reg 1185 _ble_keymap_vi_reg_record_char=$ret 1186 ble/keymap:vi/update-mode-indicator 1187 return 0 1188 } 1189 # nmap @ 1190 function ble/widget/vi_nmap/play-register { 1191 _ble_decode_key__hook="ble/widget/vi_nmap/play-register.hook" 1192 } 1193 function ble/widget/vi_nmap/play-register.hook { 1194 ble/keymap:vi/clear-arg 1195 1196 local depth=$_ble_keymap_vi_reg_record_play 1197 if ((depth>=bleopt_keymap_vi_macro_depth)) || ble/util/is-stdin-ready; then 1198 return 1 # 無限ループを防ぐため 1199 fi 1200 1201 local _ble_keymap_vi_reg_record_play=$((depth+1)) 1202 local key=$1 1203 local ret 1204 if ble/keymap:vi/k2c "$key" && local c=$ret; then 1205 ((65<=c&&c<91)) && ((c+=32)) # A-Z -> a-z 1206 if ((48<=c&&c<58||97<=c&&c<123)); then # 0-9a-z 1207 ble/keymap:vi/register#play "$c" && return 0 1208 fi 1209 fi 1210 ble/widget/vi-command/bell 1211 return 1 1212 } 1213 1214 function ble/widget/vi-command/operator { 1215 local ret opname=$1 1216 1217 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 1218 local ARG FLAG REG; ble/keymap:vi/get-arg '' 1219 # ※FLAG はユーザにより設定されているかもしれないが無視 1220 1221 local a=$_ble_edit_ind b=$_ble_edit_mark 1222 ((a<=b||(a=_ble_edit_mark,b=_ble_edit_ind))) 1223 1224 ble/widget/vi_xmap/.save-visual-state 1225 local ble_keymap_vi_mark_active=$_ble_edit_mark_active # used in call-operator-blockwise 1226 local mark_type=${_ble_edit_mark_active%+} 1227 ble/widget/vi_xmap/exit 1228 1229 local ble_keymap_vi_opmode=$mark_type 1230 if [[ $mark_type == vi_line ]]; then 1231 ble/keymap:vi/call-operator-linewise "$opname" "$a" "$b" "$ARG" "$REG" 1232 elif [[ $mark_type == vi_block ]]; then 1233 ble/keymap:vi/call-operator-blockwise "$opname" "$a" "$b" "$ARG" "$REG" 1234 else 1235 local end=$b 1236 ((end<${#_ble_edit_str}&&end++)) 1237 ble/keymap:vi/call-operator-charwise "$opname" "$a" "$end" "$ARG" "$REG" 1238 fi; local ext=$? 1239 ((ext==147)) && return 147 1240 ((ext)) && ble/widget/.bell 1241 ble/keymap:vi/adjust-command-mode 1242 return "$ext" 1243 elif [[ $_ble_decode_keymap == vi_nmap ]]; then 1244 ble/decode/keymap/push vi_omap 1245 _ble_keymap_vi_oparg=$_ble_edit_arg 1246 _ble_keymap_vi_opfunc=$opname 1247 _ble_edit_arg= 1248 ble/keymap:vi/update-mode-indicator 1249 1250 elif [[ $_ble_decode_keymap == vi_omap ]]; then 1251 local opname1=${_ble_keymap_vi_opfunc%%:*} 1252 if [[ $opname == "$opname1" ]]; then 1253 # 2つの同じオペレータ (yy, dd, cc, etc.) = 行指向の処理 1254 ble/widget/vi_nmap/linewise-operator "$_ble_keymap_vi_opfunc" 1255 else 1256 ble/keymap:vi/clear-arg 1257 ble/widget/vi-command/bell 1258 return 1 1259 fi 1260 fi 1261 return 0 1262 } 1263 1264 function ble/widget/vi_nmap/linewise-operator { 1265 local opname=${1%%:*} opflags=${1#*:} 1266 local ARG FLAG REG; ble/keymap:vi/get-arg 1 # _ble_edit_arg is consumed here 1267 if ((ARG==1)) || [[ ${_ble_edit_str:_ble_edit_ind} == *$'\n'* ]]; then 1268 if [[ :$opflags: == *:vi_char:* || :$opflags: == *:vi_block:* ]]; then 1269 local beg=$_ble_edit_ind 1270 local ret; ble-edit/content/find-logical-bol "$beg" "$((ARG-1))"; local end=$ret 1271 ((beg<=end)) || local beg=$end end=$beg 1272 if [[ :$opflags: == *:vi_block:* ]]; then 1273 ble/keymap:vi/call-operator-blockwise "$opname" "$beg" "$end" '' "$REG" 1274 else 1275 ble/keymap:vi/call-operator-charwise "$opname" "$beg" "$end" '' "$REG" 1276 fi 1277 else 1278 ble/keymap:vi/call-operator-linewise "$opname" "$_ble_edit_ind" "$_ble_edit_ind:$((ARG-1))" '' "$REG"; local ext=$? 1279 fi 1280 if ((ext==0)); then 1281 ble/keymap:vi/adjust-command-mode 1282 return 0 1283 elif ((ext==147)); then 1284 return 147 1285 fi 1286 fi 1287 ble/widget/vi-command/bell 1288 return 1 1289 } 1290 # nmap Y 1291 function ble/widget/vi_nmap/copy-current-line { 1292 ble/widget/vi_nmap/linewise-operator y 1293 } 1294 function ble/widget/vi_nmap/kill-current-line { 1295 ble/widget/vi_nmap/linewise-operator d 1296 } 1297 # nmap S 1298 function ble/widget/vi_nmap/kill-current-line-and-insert { 1299 ble/widget/vi_nmap/linewise-operator c 1300 } 1301 1302 # nmap: 0, <home> 1303 function ble/widget/vi-command/beginning-of-line { 1304 local ARG FLAG REG; ble/keymap:vi/get-arg 1 1305 local ret; ble-edit/content/find-logical-bol; local beg=$ret 1306 ble/widget/vi-command/exclusive-goto.impl "$beg" "$FLAG" "$REG" nobell 1307 } 1308 1309 #------------------------------------------------------------------------------ 1310 # Operators 1311 1312 ## オペレータは以下の形式の関数として定義される。 1313 ## 1314 ## @fn ble/keymap:vi/operator:名称 a b context [count [reg]] 1315 ## 1316 ## @param[in] a b 1317 ## 範囲の開始点と終了点。終了点は開始点以降にあることが保証される。 1318 ## context が 'line' のとき、それぞれ行頭・行末にあることが保証される。 1319 ## ただし、行末に改行があるときは b は次の行頭を指す。 1320 ## 1321 ## @param[in] context 1322 ## 範囲の種類を表す文字列。char, line, block の何れか。 1323 ## 1324 ## @param[in] count 1325 ## オペレータの操作に対する引数。 1326 ## これはビジュアルモードで指定される。 1327 ## 1328 ## @var[in,out] beg end 1329 ## 範囲の開始点と終了点。a b と同一の値。 1330 ## 行指向オペレータのとき範囲が拡大されることがある。 1331 ## その時 beg に拡大後の開始点を返す。 1332 ## 1333 ## @var[out] ble_keymap_vi_operator_index 1334 ## オペレータ作用後のカーソル位置を明示するとき、 1335 ## オペレータ内部でこの変数に値を設定する。 1336 ## 1337 ## @exit 1338 ## operator 関数が終了ステータス 147 を返したとき、 1339 ## operator が非同期に入力を読み取ることを表す。 1340 ## 147 を返した operator は、実際に操作が完了した時に: 1341 ## 1342 ## 1 ble/keymap:vi/mark/end-edit-area を呼び出す必要がある。 1343 ## 2 適切な位置にカーソルを移動する必要がある。 1344 ## 1345 ## 1346 ## オペレータは現在以下の4箇所で呼び出されている。 1347 ## 1348 ## - ble/widget/vi-command/linewise-range.impl 1349 ## - ble/keymap:vi/call-operator 1350 ## - ble/keymap:vi/call-operator-charwise 1351 ## - ble/keymap:vi/call-operator-linewise 1352 ## - ble/keymap:vi/call-operator-blockwise 1353 1354 1355 ## @fn ble/keymap:vi/call-operator op beg end type arg reg 1356 ## @fn ble/keymap:vi/call-operator-charwise op beg end arg reg 1357 ## @fn ble/keymap:vi/call-operator-linewise op beg end arg reg 1358 ## @fn ble/keymap:vi/call-operator-blockwise op beg end arg reg 1359 ## 1360 ## @var[in] ble_keymap_vi_mark_active 1361 ## オペレータ作用前の $_ble_edit_mark_active を指定する。 1362 ## call-operator-blockwise での矩形領域を決定するのに用いる。 1363 ## 演算子の呼び出し時には既に $_ble_edit_mark_active は 1364 ## 作用後の値に変わっていることに注意する。 1365 ## 1366 function ble/keymap:vi/call-operator { 1367 ble/keymap:vi/mark/start-edit-area 1368 local _ble_keymap_vi_mark_suppress_edit=1 1369 ble/keymap:vi/operator:"$@"; local ext=$? 1370 ble/util/unlocal _ble_keymap_vi_mark_suppress_edit 1371 ble/keymap:vi/mark/end-edit-area 1372 if ((ext==0)); then 1373 if ble/is-function ble/keymap:vi/operator:"$1".record; then 1374 ble/keymap:vi/operator:"$1".record 1375 else 1376 ble/keymap:vi/repeat/record 1377 fi 1378 fi 1379 return "$ext" 1380 } 1381 function ble/keymap:vi/call-operator-charwise { 1382 local ch=$1 beg=$2 end=$3 arg=$4 reg=$5 1383 ((beg<=end||(beg=$3,end=$2))) 1384 if ble/is-function ble/keymap:vi/operator:"$ch"; then 1385 local ble_keymap_vi_operator_index= 1386 ble/keymap:vi/call-operator "$ch" "$beg" "$end" char "$arg" "$reg"; local ext=$? 1387 ((ext==147)) && return 147 1388 1389 local index=${ble_keymap_vi_operator_index:-$beg} 1390 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 1391 _ble_edit_ind=$index 1392 return 0 1393 else 1394 return 1 1395 fi 1396 } 1397 function ble/keymap:vi/call-operator-linewise { 1398 local ch=$1 a=$2 b=$3 arg=$4 reg=$5 ia=0 ib=0 1399 [[ $a == *:* ]] && local a=${a%%:*} ia=${a#*:} 1400 [[ $b == *:* ]] && local b=${b%%:*} ib=${b#*:} 1401 local ret 1402 ble-edit/content/find-logical-bol "$a" "$ia"; local beg=$ret 1403 ble-edit/content/find-logical-eol "$b" "$ib"; local end=$ret 1404 1405 if ble/is-function ble/keymap:vi/operator:"$ch"; then 1406 local ble_keymap_vi_operator_index= 1407 ((end<${#_ble_edit_str}&&end++)) 1408 ble/keymap:vi/call-operator "$ch" "$beg" "$end" line "$arg" "$reg"; local ext=$? 1409 ((ext==147)) && return 147 1410 1411 # index 1412 if [[ $ble_keymap_vi_operator_index ]]; then 1413 local index=$ble_keymap_vi_operator_index 1414 else 1415 ble-edit/content/find-logical-bol "$beg"; beg=$ret # operator 中で beg が変更されているかも 1416 ble-edit/content/find-non-space "$beg"; local index=$ret 1417 fi 1418 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 1419 _ble_edit_ind=$index 1420 return 0 1421 else 1422 return 1 1423 fi 1424 } 1425 function ble/keymap:vi/call-operator-blockwise { 1426 local ch=$1 beg=$2 end=$3 arg=$4 reg=$5 1427 if ble/is-function ble/keymap:vi/operator:"$ch"; then 1428 local mark_active=${ble_keymap_vi_mark_active:-vi_block} 1429 local sub_ranges sub_x1 sub_x2 1430 _ble_edit_mark_active=$mark_active ble/keymap:vi/extract-block "$beg" "$end" 1431 local nrange=${#sub_ranges[@]} 1432 ((nrange)) || return 1 1433 1434 local ble_keymap_vi_operator_index= 1435 local beg=${sub_ranges[0]}; beg=${beg%%:*} 1436 local end=${sub_ranges[nrange-1]}; end=${end#*:}; end=${end%%:*} 1437 ble/keymap:vi/call-operator "$ch" "$beg" "$end" block "$arg" "$reg" 1438 ((ext==147)) && return 147 1439 1440 local index=${ble_keymap_vi_operator_index:-$beg} 1441 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 1442 _ble_edit_ind=$index 1443 return 0 1444 else 1445 return 1 1446 fi 1447 } 1448 1449 1450 function ble/keymap:vi/operator:d { 1451 local context=$3 arg=$4 reg=$5 # beg end は上書きする 1452 if [[ $context == line ]]; then 1453 ble/keymap:vi/register#set-edit "$reg" L "${_ble_edit_str:beg:end-beg}" || return 1 1454 1455 # 最後の行が削除される時は前の行の非空白行頭まで後退 1456 if ((end==${#_ble_edit_str}&&beg>0)); then 1457 # fix start position 1458 local ret 1459 ((beg--)) 1460 ble-edit/content/find-logical-bol "$beg" 1461 ble-edit/content/find-non-space "$ret" 1462 ble_keymap_vi_operator_index=$ret 1463 fi 1464 1465 ble/widget/.delete-range "$beg" "$end" 1466 elif [[ $context == block ]]; then 1467 local -a afill=() atext=() arep=() 1468 local sub shift=0 slpad0= 1469 local smin smax slpad srpad sfill stext 1470 for sub in "${sub_ranges[@]}"; do 1471 stext=${sub#*:*:*:*:*:} 1472 ble/string#split sub : "$sub" 1473 smin=${sub[0]} smax=${sub[1]} 1474 slpad=${sub[2]} srpad=${sub[3]} 1475 sfill=${sub[4]} 1476 1477 [[ $slpad0 ]] || slpad0=$slpad # 最初の slpad 1478 1479 ble/array#push afill "$sfill" 1480 ble/array#push atext "$stext" 1481 local ret; ble/string#repeat ' ' "$((slpad+srpad))" 1482 ble/array#push arep "$((smin+shift)):$((smax+shift)):$ret" 1483 ((shift+=(slpad+srpad)-(smax-smin))) 1484 done 1485 1486 # yank 1487 IFS=$'\n' builtin eval 'local yank_content="${atext[*]-}"' 1488 local IFS=$_ble_term_IFS 1489 local yank_type=B:"${afill[*]-}" 1490 ble/keymap:vi/register#set-edit "$reg" "$yank_type" "$yank_content" || return 1 1491 1492 # delete 1493 local rep 1494 for rep in "${arep[@]}"; do 1495 smin=${rep%%:*}; rep=${rep:${#smin}+1} 1496 smax=${rep%%:*}; rep=${rep:${#smax}+1} 1497 ble/widget/.replace-range "$smin" "$smax" "$rep" 1498 done 1499 ((beg+=slpad)) # fix start position 1500 else 1501 if ((beg<end)); then 1502 1503 if [[ $ble_keymap_vi_opmode != vi_char && ${_ble_edit_str:beg:end-beg} == *$'\n'* ]]; then 1504 # d の例外動作: 文字単位で開始点と終了点が異なる行で、 1505 # 開始点より前・終了点より後に空白しかない時、行指向で処理する。 1506 if local rex=$'(^|\n)([ \t]*)$'; [[ ${_ble_edit_str::beg} =~ $rex ]]; then 1507 local prefix=${BASH_REMATCH[2]} 1508 if rex=$'^[ \t]*(\n|$)'; [[ ${_ble_edit_str:end} =~ $rex ]]; then 1509 local suffix=$BASH_REMATCH 1510 ((beg-=${#prefix},end+=${#suffix})) 1511 ble/keymap:vi/operator:d "$beg" "$end" line "$arg" "$reg" 1512 return "$?" 1513 fi 1514 fi 1515 fi 1516 1517 ble/keymap:vi/register#set-edit "$reg" '' "${_ble_edit_str:beg:end-beg}" || return 1 1518 ble/widget/.delete-range "$beg" "$end" 1519 fi 1520 fi 1521 return 0 1522 } 1523 function ble/keymap:vi/operator:c { 1524 local context=$3 arg=$4 reg=$5 # beg は上書き対象 1525 if [[ $context == line ]]; then 1526 ble/keymap:vi/register#set-edit "$reg" L "${_ble_edit_str:beg:end-beg}" || return 1 1527 1528 local end2=$end 1529 ((end2)) && [[ ${_ble_edit_str:end2-1:1} == $'\n' ]] && ((end2--)) 1530 1531 local indent= ret 1532 ble-edit/content/find-non-space "$beg"; local nol=$ret 1533 ((beg<nol)) && indent=${_ble_edit_str:beg:nol-beg} 1534 1535 ble/widget/.replace-range "$beg" "$end2" "$indent" 1536 ble/widget/vi_nmap/.insert-mode 1537 elif [[ $context == block ]]; then 1538 ble/keymap:vi/operator:d "$@" || return 1 # @var beg will be overwritten here 1539 1540 # operator:d によってずれた矩形領域を修正する。 1541 # 一から計算し直すのは面倒なので sub_ranges を直接弄る。 1542 # 実のところ block-insert-mode insert は sub_ranges[0] の smin と sub_x1 1543 # しか参照しないので、sub_ranges[0] だけ修正すれば良い。 1544 local sub=${sub_ranges[0]} 1545 local smin=${sub%%:*} sub=${sub#*:} 1546 local smax=${sub%%:*} sub=${sub#*:} 1547 local slpad=${sub%%:*} sub=${sub#*:} 1548 ((smin+=slpad,smax=smin,slpad=0)) 1549 sub_ranges[0]=$smin:$smax:$slpad:$sub 1550 1551 ble/widget/vi_xmap/block-insert-mode.impl insert 1552 else 1553 local ble_keymap_vi_opmode=vi_char 1554 ble/keymap:vi/operator:d "$@" || return 1 1555 ble/widget/vi_nmap/.insert-mode 1556 fi 1557 return 0 1558 } 1559 function ble/keymap:vi/operator:y.record { :; } 1560 function ble/keymap:vi/operator:y { 1561 local beg=$1 end=$2 context=$3 arg=$4 reg=$5 1562 local yank_type= yank_content= 1563 if [[ $context == line ]]; then 1564 ble_keymap_vi_operator_index=$_ble_edit_ind # operator:y では現在位置を動かさない 1565 yank_type=L 1566 yank_content=${_ble_edit_str:beg:end-beg} 1567 elif [[ $context == block ]]; then 1568 local sub 1569 local -a afill=() atext=() 1570 for sub in "${sub_ranges[@]}"; do 1571 local sub4=${sub#*:*:*:*:} 1572 local sfill=${sub4%%:*} stext=${sub4#*:} 1573 ble/array#push afill "$sfill" 1574 ble/array#push atext "$stext" 1575 done 1576 1577 IFS=$'\n' builtin eval 'local yank_content="${atext[*]-}"' 1578 local IFS=$_ble_term_IFS 1579 yank_type=B:"${afill[*]-}" 1580 else 1581 yank_type= 1582 yank_content=${_ble_edit_str:beg:end-beg} 1583 fi 1584 1585 ble/keymap:vi/register#set-yank "$reg" "$yank_type" "$yank_content" || return 1 1586 ble/keymap:vi/mark/commit-edit-area "$beg" "$end" 1587 return 0 1588 } 1589 function ble/keymap:vi/operator:tr.impl { 1590 local beg=$1 end=$2 context=$3 filter=$4 1591 if [[ $context == block ]]; then 1592 local isub=${#sub_ranges[@]} 1593 while ((isub--)); do 1594 ble/string#split sub : "${sub_ranges[isub]}" 1595 local smin=${sub[0]} smax=${sub[1]} 1596 local ret; "$filter" "${_ble_edit_str:smin:smax-smin}" 1597 ble/widget/.replace-range "$smin" "$smax" "$ret" 1598 done 1599 else 1600 local ret; "$filter" "${_ble_edit_str:beg:end-beg}" 1601 ble/widget/.replace-range "$beg" "$end" "$ret" 1602 fi 1603 return 0 1604 } 1605 function ble/keymap:vi/operator:u { 1606 ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/string#tolower 1607 } 1608 function ble/keymap:vi/operator:U { 1609 ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/string#toupper 1610 } 1611 function ble/keymap:vi/operator:toggle_case { 1612 ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/string#toggle-case 1613 } 1614 function ble/keymap:vi/operator:rot13 { 1615 ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/keymap:vi/string#encode-rot13 1616 } 1617 1618 ## @fn ble/keymap:vi/expand-range-for-linewise-operator 1619 ## @var[in,out] beg, end 1620 function ble/keymap:vi/expand-range-for-linewise-operator { 1621 local ret 1622 1623 # 行頭補正: 1624 ble-edit/content/find-logical-bol "$beg"; beg=$ret 1625 1626 # 行末補正: 1627 # 行前進時は非空白行頭以前に end がある場合はその行は無視 1628 # 行後退時は行頭に end (_ble_edit_ind) がある場合はその行は無視 1629 # 同一行内の移動の場合は無条件にその行は含まれる。 1630 ble-edit/content/find-logical-bol "$end"; local bol2=$ret 1631 ble-edit/content/find-non-space "$bol2"; local nol2=$ret 1632 if ((beg<bol2&&_ble_edit_ind<=bol2&&end<=nol2)); then 1633 end=$bol2 1634 else 1635 ble-edit/content/find-logical-eol "$end"; end=$ret 1636 [[ ${_ble_edit_str:end:1} == $'\n' ]] && ((end++)) 1637 fi 1638 } 1639 1640 #-------------------------------------- 1641 # Indent operators < > 1642 1643 ## @fn ble/keymap:vi/string#increase-indent 1644 ## @var[out] ret 1645 function ble/keymap:vi/string#increase-indent { 1646 local text=$1 delta=$2 1647 local space=$' \t' it=${bleopt_tab_width:-$_ble_term_it} 1648 local arr; ble/string#split-lines arr "$text" 1649 local -a arr2=() 1650 local line indent i len x r 1651 for line in "${arr[@]}"; do 1652 indent=${line%%[!$space]*} 1653 line=${line:${#indent}} 1654 1655 ((x=0)) 1656 if [[ $indent ]]; then 1657 ((len=${#indent})) 1658 for ((i=0;i<len;i++)); do 1659 if [[ ${indent:i:1} == ' ' ]]; then 1660 ((x++)) 1661 else 1662 ((x=(x+it)/it*it)) 1663 fi 1664 done 1665 fi 1666 1667 ((x+=delta,x<0&&(x=0))) 1668 1669 indent= 1670 if ((x)); then 1671 if ((bleopt_indent_tabs&&(r=x/it))); then 1672 ble/string#repeat $'\t' "$r" 1673 indent=$ret 1674 ((x%=it)) 1675 fi 1676 if ((x)); then 1677 ble/string#repeat ' ' "$x" 1678 indent=$indent$ret 1679 fi 1680 fi 1681 1682 ble/array#push arr2 "$indent$line" 1683 done 1684 1685 IFS=$'\n' builtin eval 'ret="${arr2[*]-}"' 1686 } 1687 ## @fn ble/keymap:vi/operator:indent.impl/increase-block-indent width 1688 ## @param[in] width 1689 ## @var[in] sub_ranges 1690 function ble/keymap:vi/operator:indent.impl/increase-block-indent { 1691 local width=$1 1692 local isub=${#sub_ranges[@]} 1693 local sub smin slpad ret 1694 while ((isub--)); do 1695 ble/string#split sub : "${sub_ranges[isub]}" 1696 smin=${sub[0]} slpad=${sub[2]} 1697 ble/string#repeat ' ' "$((slpad+width))" 1698 ble/widget/.replace-range "$smin" "$smin" "$ret" 1699 done 1700 } 1701 ## @fn ble/keymap:vi/operator:indent.impl/decrease-graphical-block-indent width 1702 ## @param[in] width 1703 ## @var[in] sub_ranges 1704 function ble/keymap:vi/operator:indent.impl/decrease-graphical-block-indent { 1705 local width=$1 1706 local it=${bleopt_tab_width:-$_ble_term_it} cols=$_ble_textmap_cols 1707 local sub smin slpad ret 1708 local -a replaces=() 1709 local isub=${#sub_ranges[@]} 1710 while ((isub--)); do 1711 ble/string#split sub : "${sub_ranges[isub]}" 1712 smin=${sub[0]} slpad=${sub[2]} 1713 ble-edit/content/find-non-space "$smin"; local nsp=$ret 1714 ((smin<nsp)) || continue 1715 1716 local ax ay bx by 1717 ble/textmap#getxy.out --prefix=a "$smin" 1718 ble/textmap#getxy.out --prefix=b "$nsp" 1719 local w=$(((bx-ax)-(by-ay)*cols-width)) 1720 ((w<slpad)) && w=$slpad 1721 1722 local ins= 1723 if ((w)); then 1724 local r 1725 if ((bleopt_indent_tabs&&(r=(ax+w)/it-ax/it))); then 1726 ble/string#repeat $'\t' "$r"; ins=$ret 1727 ((w=(ax+w)%it)) 1728 fi 1729 if ((w)); then 1730 ble/string#repeat ' ' "$w" 1731 ins=$ins$ret 1732 fi 1733 fi 1734 1735 ble/array#push replaces "$smin:$nsp:$ins" 1736 done 1737 1738 local rep 1739 for rep in "${replaces[@]}"; do 1740 ble/string#split rep : "$rep" 1741 ble/widget/.replace-range "${rep[@]::3}" 1742 done 1743 } 1744 ## @fn ble/keymap:vi/operator:indent.impl/decrease-logical-block-indent width 1745 ## @param[in] width 1746 ## @var[in] sub_ranges 1747 function ble/keymap:vi/operator:indent.impl/decrease-logical-block-indent { 1748 # タブは幅 it で固定と見做して削除する 1749 local width=$1 1750 local it=${bleopt_tab_width:-$_ble_term_it} 1751 local sub smin ret nsp 1752 local isub=${#sub_ranges[@]} 1753 while ((isub--)); do 1754 ble/string#split sub : "${sub_ranges[isub]}" 1755 smin=${sub[0]} 1756 ble-edit/content/find-non-space "$smin"; nsp=$ret 1757 ((smin<nsp)) || continue 1758 1759 local stext=${_ble_edit_str:smin:nsp-smin} 1760 local i=0 n=${#stext} c=0 pad=0 1761 for ((i=0;i<n;i++)); do 1762 if [[ ${stext:i:1} == $'\t' ]]; then 1763 ((c+=it)) 1764 else 1765 ((c++)) 1766 fi 1767 if ((c>=width)); then 1768 pad=$((c-width)) 1769 nsp=$((smin+i+1)) 1770 break 1771 fi 1772 done 1773 1774 local padding= 1775 ((pad)) && { ble/string#repeat ' ' "$pad"; padding=$ret; } 1776 ble/widget/.replace-range "$smin" "$nsp" "$padding" 1777 done 1778 } 1779 function ble/keymap:vi/operator:indent.impl { 1780 local delta=$1 context=$2 1781 ((delta)) || return 0 1782 if [[ $context == block ]]; then 1783 if ((delta>=0)); then 1784 ble/keymap:vi/operator:indent.impl/increase-block-indent "$delta" 1785 elif ble/edit/use-textmap; then 1786 ble/keymap:vi/operator:indent.impl/decrease-graphical-block-indent "$((-delta))" 1787 else 1788 ble/keymap:vi/operator:indent.impl/decrease-logical-block-indent "$((-delta))" 1789 fi 1790 else 1791 [[ $context == char ]] && ble/keymap:vi/expand-range-for-linewise-operator 1792 ((beg<end)) && [[ ${_ble_edit_str:end-1:1} == $'\n' ]] && ((end--)) 1793 1794 local ret 1795 ble/keymap:vi/string#increase-indent "${_ble_edit_str:beg:end-beg}" "$delta"; local content=$ret 1796 ble/widget/.replace-range "$beg" "$end" "$content" 1797 1798 if [[ $context == char ]]; then 1799 ble-edit/content/find-non-space "$beg" 1800 ble_keymap_vi_operator_index=$ret 1801 fi 1802 fi 1803 return 0 1804 } 1805 function ble/keymap:vi/operator:indent-left { 1806 local context=$3 arg=${4:-1} 1807 ble/keymap:vi/operator:indent.impl "$((-bleopt_indent_offset*arg))" "$context" 1808 } 1809 function ble/keymap:vi/operator:indent-right { 1810 local context=$3 arg=${4:-1} 1811 ble/keymap:vi/operator:indent.impl "$((bleopt_indent_offset*arg))" "$context" 1812 } 1813 1814 #-------------------------------------- 1815 # Fold operators gq gw 1816 1817 ## @fn ble/keymap:vi/string#measure-width text 1818 ## 指定した文字列の表示上の幅を計測します。 1819 ## 1820 ## @param[in] text 1821 ## @var[out] ret 1822 ## 1823 ## 折り返し処理は行いません。 1824 ## タブや改行などの特別処理は行いません。 1825 ## C0 文字は 2 文字として取り扱います。 1826 ## C1 文字は 4 文字として取り扱います。 1827 function ble/keymap:vi/string#measure-width { 1828 local text=$1 iN=${#1} i=0 s=0 1829 while ((i<iN)); do 1830 if ble/util/isprint+ "${text:i}"; then 1831 ((s+=${#BASH_REMATCH}, 1832 i+=${#BASH_REMATCH})) 1833 else 1834 ble/util/s2c "${text:i:1}" 1835 ble/util/c2w-edit "$ret" 1836 ((s+=ret,i++)) 1837 fi 1838 done 1839 ret=$s 1840 } 1841 ## @fn ble/keymap:vi/string#fold/.get-interval text x 1842 ## 単語間のスペースの表示上の幅を計算します。 1843 ## 1844 ## @param[in] text 1845 ## スペース・タブで構成される文字列を指定します。 1846 ## @param[in] x 1847 ## 画面上の初期位置を指定します。 1848 ## @var[out] ret 1849 ## 1850 function ble/keymap:vi/string#fold/.get-interval { 1851 local text=$1 x=$2 1852 local it=${bleopt_tab_width:-${_ble_term_it:-8}} 1853 1854 local i=0 iN=${#text} 1855 for ((i=0;i<iN;i++)); do 1856 if [[ ${text:i:1} == $'\t' ]]; then 1857 ((x=(x/it+1)*it)) 1858 else 1859 ((x++)) 1860 fi 1861 done 1862 ret=$((x-$2)) 1863 } 1864 ## @fn ble/keymap:vi/string#fold text [cols] 1865 ## @param[in] text 1866 ## @param[in,opt] cols [既定値 ${COLUMNS:-80}] 1867 ## 折り返す幅を指定します。 1868 ## cols-1 列以内に表示文字が収まる様に折り返し処理されます。 1869 ## 但し長い単語の途中で折り返しは起こりません。 1870 ## @var[out] ret 1871 function ble/keymap:vi/string#fold { 1872 local text=$1 1873 local cols=${2:-${COLUMNS-80}} 1874 local sp=$' \t' nl=$'\n' 1875 1876 # 途中状態について 1877 # @var i text 内の現在処理している位置 1878 # @var out 今までに確定した結果文字列 1879 # @var otmp 保留中の単語間スペース。次の単語が来て初めて確定する。 1880 # @var x $out を処理した後の表示横位置 1881 # @var xtmp $out$otmp を処理した後の表示横位置 1882 # @var isfirst 初回の正規表現一致かどうか 1883 # @var indent インデント (改行直後に挿入する空白類) 1884 # @var xindent インデント挿入直後の表示横位置 1885 local i=0 out= otmp= x=0 xtmp=0 1886 local isfirst=1 indent= xindent=0 1887 1888 local rex='^([^'$nl$sp']+)|^(['$sp']+)|^.' 1889 while [[ ${text:i} =~ $rex ]]; do 1890 ((i+=${#BASH_REMATCH})) 1891 if [[ ${BASH_REMATCH[1]} ]]; then 1892 # 単語 1893 local word=${BASH_REMATCH[1]} 1894 ble/keymap:vi/string#measure-width "$word" 1895 if ((xtmp+ret<cols||xtmp<=xindent)); then 1896 out=$out$otmp$word 1897 ((x=xtmp+=ret)) 1898 else 1899 out=$out$'\n'$indent$word 1900 ((x=xtmp=xindent+ret)) 1901 fi 1902 otmp= 1903 else 1904 local w=1 1905 if [[ ${BASH_REMATCH[2]} ]]; then 1906 [[ $otmp ]] && continue # 改行直後の空白は無視 1907 # 単語間のスペース 1908 otmp=${BASH_REMATCH[2]} 1909 ble/keymap:vi/string#fold/.get-interval "$otmp" "$x"; w=$ret 1910 [[ $isfirst ]] && indent=$otmp xindent=$ret # インデント記録 1911 else 1912 # 改行は空白に置換。既存の空白 otmp は消去。 1913 otmp=' ' w=1 1914 fi 1915 1916 if ((x+w<cols)); then 1917 ((xtmp=x+w)) 1918 else 1919 ((xtmp=xindent)) 1920 otmp=$'\n'$indent 1921 fi 1922 fi 1923 isfirst= 1924 done 1925 ret=$out 1926 } 1927 ## @fn ble/keymap:vi/operator:fold/.fold-paragraphwise text [cols] 1928 ## @var[out] ret 1929 function ble/keymap:vi/operator:fold/.fold-paragraphwise { 1930 local text=$1 1931 local cols=${2:-${COLUMNS:-80}} 1932 1933 local nl=$'\n' sp=$' \t' 1934 local rex_paragraph='^((['$sp']*'$nl')*)(['$sp']*[^'$sp$nl'][^'$nl']*('$nl'|$))+' 1935 1936 local i=0 out= 1937 while [[ ${text:i} =~ $rex_paragraph ]]; do 1938 ((i+=${#BASH_REMATCH})) 1939 local rematch1=${BASH_REMATCH[1]} 1940 local len1=${#rematch1} 1941 local paragraph=${BASH_REMATCH:len1} 1942 1943 # fold (実はここだけ変えれば paragraphwise の様々な処理を実装できる) 1944 ble/keymap:vi/string#fold "$paragraph" "$cols" 1945 paragraph=${ret%$'\n'}$'\n' 1946 1947 out=$out$rematch1$paragraph 1948 done 1949 ret=$out${text:i} 1950 } 1951 1952 function ble/keymap:vi/operator:fold.impl { 1953 local context=$1 opts=$2 1954 local ret 1955 1956 [[ $context != line ]] && ble/keymap:vi/expand-range-for-linewise-operator 1957 local old=${_ble_edit_str:beg:end-beg} oind=$_ble_edit_ind 1958 1959 local cols=${COLUMNS:-80}; ((cols>80&&(cols=80))) 1960 ble/keymap:vi/operator:fold/.fold-paragraphwise "$old" "$cols"; local new=$ret 1961 ble/widget/.replace-range "$beg" "$end" "$new" 1962 1963 # 変換後のカーソル位置を修正。 1964 if [[ :$opts: == *:preserve_point:* ]]; then 1965 # gw: もともとカーソルが合った文字に移動。 1966 if ((end<=oind)); then 1967 ble_keymap_vi_operator_index=$((beg+${#new})) 1968 elif ((beg<oind)); then 1969 ble/keymap:vi/operator:fold/.fold-paragraphwise "${old::oind-beg}" "$cols" 1970 ble_keymap_vi_operator_index=$((beg+${#ret})) 1971 fi 1972 else 1973 # gq: 最終行の非空白行頭 (gq) に移動。 1974 if [[ $new ]]; then 1975 ble-edit/content/find-logical-bol "$((beg+${#new}-1))" 1976 ble-edit/content/find-non-space "$ret" 1977 ble_keymap_vi_operator_index=$ret 1978 fi 1979 fi 1980 return 0 1981 } 1982 function ble/keymap:vi/operator:fold { 1983 local context=$3 1984 ble/keymap:vi/operator:fold.impl "$context" 1985 } 1986 function ble/keymap:vi/operator:fold-preserve-point { 1987 local context=$3 1988 ble/keymap:vi/operator:fold.impl "$context" preserve_point 1989 } 1990 1991 #-------------------------------------- 1992 # Filter operator: ! 1993 1994 _ble_keymap_vi_filter_args=() 1995 _ble_keymap_vi_filter_repeat=() 1996 1997 _ble_keymap_vi_filter_history=() 1998 _ble_keymap_vi_filter_history_edit=() 1999 _ble_keymap_vi_filter_history_dirt=() 2000 _ble_keymap_vi_filter_history_index=0 2001 2002 function ble/highlight/layer:region/mark:vi_filter/get-face { 2003 face=region_target 2004 } 2005 function ble/keymap:vi/operator:filter/.cache-repeat { 2006 local -a _ble_keymap_vi_repeat _ble_keymap_vi_repeat_irepeat 2007 ble/keymap:vi/repeat/record-normal 2008 _ble_keymap_vi_filter_repeat=("${_ble_keymap_vi_repeat[@]}") 2009 } 2010 function ble/keymap:vi/operator:filter/.record-repeat { 2011 ble/keymap:vi/repeat/record-special && return 0 2012 local command=$1 2013 _ble_keymap_vi_repeat=("${_ble_keymap_vi_filter_repeat[@]}") 2014 _ble_keymap_vi_repeat_irepeat=() 2015 _ble_keymap_vi_repeat[10]=$command 2016 } 2017 function ble/keymap:vi/operator:filter { 2018 local context=$3 2019 [[ $context != line ]] && ble/keymap:vi/expand-range-for-linewise-operator 2020 _ble_keymap_vi_filter_args=("$beg" "$end" "${@:3}") 2021 2022 if [[ $_ble_keymap_vi_repeat_invoke ]]; then 2023 # nmap . によって繰り返しが要求された時 2024 local command=${_ble_keymap_vi_repeat[10]} 2025 ble/keymap:vi/operator:filter/.hook "$command" 2026 return "$?" 2027 else 2028 # 通常の呼び出し時 2029 ble/keymap:vi/operator:filter/.cache-repeat 2030 _ble_edit_ind=$beg 2031 _ble_edit_mark=$end 2032 _ble_edit_mark_active=vi_filter 2033 ble/keymap:vi/async-commandline-mode 'ble/keymap:vi/operator:filter/.hook' 2034 _ble_edit_PS1='!' 2035 ble/history/set-prefix _ble_keymap_vi_filter 2036 _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook 2037 _ble_keymap_vi_cmap_cancel_hook=ble/keymap:vi/operator:filter/cancel.hook 2038 _ble_syntax_lang=bash 2039 _ble_highlight_layer_list=(plain syntax region overwrite_mode) 2040 return 147 2041 fi 2042 } 2043 function ble/keymap:vi/operator:filter/cancel.hook { 2044 _ble_edit_mark_active= # clear mark:vi_filter 2045 } 2046 function ble/keymap:vi/operator:filter/.hook { 2047 local command=$1 # 入力されたコマンド 2048 if [[ ! $command ]]; then 2049 ble/widget/vi-command/bell 2050 return 1 2051 fi 2052 local beg=${_ble_keymap_vi_filter_args[0]} 2053 local end=${_ble_keymap_vi_filter_args[1]} 2054 local context=${_ble_keymap_vi_filter_args[2]} 2055 2056 _ble_edit_mark_active= # clear mark:vi_filter 2057 2058 local old=${_ble_edit_str:beg:end-beg} new 2059 old=${old%$'\n'} 2060 if ! ble/util/assign new 'builtin eval -- "$command" <<< "$old" 2>/dev/null'; then 2061 ble/widget/vi-command/bell 2062 return 1 2063 fi 2064 new=${new%$'\n'} 2065 ((end<${#_ble_edit_str})) && new=$new$'\n' 2066 ble/widget/.replace-range "$beg" "$end" "$new" 2067 2068 _ble_edit_ind=$beg 2069 if [[ $context == line ]]; then 2070 ble/widget/vi-command/first-non-space 2071 else 2072 ble/keymap:vi/adjust-command-mode 2073 fi 2074 2075 ble/keymap:vi/mark/set-previous-edit-area "$beg" "$((beg+${#new}))" 2076 ble/keymap:vi/operator:filter/.record-repeat "$command" 2077 return 0 2078 } 2079 2080 #-------------------------------------- 2081 # User operator: g@ 2082 2083 bleopt/declare -v keymap_vi_operatorfunc '' 2084 2085 function ble/keymap:vi/operator:map { 2086 local context=$3 2087 if [[ $bleopt_keymap_vi_operatorfunc ]]; then 2088 local opfunc=ble/keymap:vi/operator:$bleopt_keymap_vi_operatorfunc 2089 if ble/is-function "$opfunc"; then 2090 "$opfunc" "$@" 2091 return "$?" 2092 fi 2093 fi 2094 return 1 2095 } 2096 2097 #------------------------------------------------------------------------------ 2098 # Motions 2099 2100 #-------------------------------------- 2101 # Primitive motion 2102 2103 ## @fn ble/widget/vi-command/exclusive-range.impl src dst flag reg nobell 2104 ## @fn ble/widget/vi-command/exclusive-goto.impl index flag reg nobell 2105 ## @fn ble/widget/vi-command/inclusive-goto.impl index flag reg nobell 2106 ## 2107 ## @param[in] src, dst 2108 ## 移動前の位置と移動先の位置を指定します。 2109 ## 2110 ## @param[in] flag 2111 ## オペレータ名を指定します。 2112 ## 2113 ## @param[in] reg 2114 ## レジスタ番号を指定します。 2115 ## 2116 ## @param[in] opts 2117 ## コロン区切りのオプションです。 2118 ## nobell 移動前と移動後の位置が同じときにベルを鳴らしません。 2119 ## inclusive 移動の既定の動作が inclusive である事を示します。 2120 ## 2121 function ble/widget/vi-command/exclusive-range.impl { 2122 local src=$1 dst=$2 flag=$3 reg=$4 opts=$5 2123 if [[ $flag ]]; then 2124 local opname=${flag%%:*} opflags=${flag#*:} 2125 if [[ :$opflags: == *:vi_line:* ]]; then 2126 local ble_keymap_vi_opmode=vi_line 2127 ble/keymap:vi/call-operator-linewise "$opname" "$src" "$dst" '' "$reg"; local ext=$? 2128 elif [[ :$opflags: == *:vi_block:* ]]; then 2129 local ble_keymap_vi_opmode=vi_line 2130 ble/keymap:vi/call-operator-blockwise "$opname" "$src" "$dst" '' "$reg"; local ext=$? 2131 elif [[ :$opflags: == *:vi_char:* ]]; then 2132 local ble_keymap_vi_opmode=vi_char 2133 2134 # 規則 o_v (omap v) の toggle inclusive/exclusive 2135 if [[ :$opts: == *:inclusive:* ]]; then 2136 ((src<dst?dst--:(dst<src&&src--))) 2137 else 2138 if ((src<=dst)); then 2139 ((dst<${#_ble_edit_str})) && 2140 [[ ${_ble_edit_str:dst:1} != $'\n' ]] && 2141 ((dst++)) 2142 else 2143 ((src<${#_ble_edit_str})) && 2144 [[ ${_ble_edit_str:src:1} != $'\n' ]] && 2145 ((src++)) 2146 fi 2147 fi 2148 2149 ble/keymap:vi/call-operator-charwise "$opname" "$src" "$dst" '' "$reg"; local ext=$? 2150 else 2151 local ble_keymap_vi_opmode= 2152 ble/keymap:vi/call-operator-charwise "$opname" "$src" "$dst" '' "$reg"; local ext=$? 2153 fi 2154 ((ext==147)) && return 147 2155 ((ext)) && ble/widget/.bell 2156 ble/keymap:vi/adjust-command-mode 2157 return "$ext" 2158 else 2159 ble/keymap:vi/needs-eol-fix "$dst" && ((dst--)) 2160 if ((dst!=_ble_edit_ind)); then 2161 _ble_edit_ind=$dst 2162 elif [[ :$opts: != *:nobell:* ]]; then 2163 ble/widget/vi-command/bell 2164 return 1 2165 fi 2166 ble/keymap:vi/adjust-command-mode 2167 return 0 2168 fi 2169 } 2170 function ble/widget/vi-command/exclusive-goto.impl { 2171 local index=$1 flag=$2 reg=$3 opts=$4 2172 if [[ $flag ]]; then 2173 if ble-edit/content/bolp "$index"; then 2174 local is_linewise= 2175 if ((_ble_edit_ind<index)); then 2176 # :help exclusive-linewise の規則1 (src<ind の時のみ) 2177 ((index--)) 2178 # :help exclusive-linewise の規則2 2179 rex=$'(^|\n)[ \t]*$' 2180 [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]] && 2181 is_linewise=1 2182 elif ((index<_ble_edit_ind)); then 2183 # :help exclusive-linewise の規則2 (条件が異なる) 2184 ble-edit/content/bolp && 2185 is_linewise=1 2186 fi 2187 2188 if [[ $is_linewise ]]; then 2189 ble/widget/vi-command/linewise-goto.impl "$index" "$flag" "$reg" 2190 return "$?" 2191 fi 2192 fi 2193 fi 2194 ble/widget/vi-command/exclusive-range.impl "$_ble_edit_ind" "$index" "$flag" "$reg" "$opts" 2195 } 2196 function ble/widget/vi-command/inclusive-goto.impl { 2197 local index=$1 flag=$2 reg=$3 opts=$4 2198 if [[ $flag ]]; then 2199 if ((_ble_edit_ind<=index)); then 2200 ble-edit/content/eolp "$index" || ((index++)) 2201 else 2202 ble-edit/content/eolp || ((_ble_edit_ind++)) 2203 fi 2204 fi 2205 ble/widget/vi-command/exclusive-range.impl "$_ble_edit_ind" "$index" "$flag" "$reg" "$opts:inclusive" 2206 } 2207 2208 ## @fn ble/widget/vi-command/linewise-range.impl p q flag reg opts 2209 ## @fn ble/widget/vi-command/linewise-goto.impl index flag reg opts 2210 ## 2211 ## @param[in] p, q 2212 ## 開始位置と終了位置を指定します。 2213 ## flag が設定されていない場合は q に移動します。 2214 ## 2215 ## @param[in] index 2216 ## 開始位置を _ble_edit_ind とし、 2217 ## 移動先または終了位置を指定します。 2218 ## 2219 ## index=indx:linex の形をしているとき、 2220 ## 基準の位置 indx から linex 行目を移動先とします。 2221 ## index=整数 の場合 index を含む行を移動先とします。 2222 ## 2223 ## @param[in] flag 2224 ## @param[in] reg 2225 ## 2226 ## @param[in] opts 2227 ## 以下のフィールドを似にに含むコロン区切りのリスト 2228 ## 2229 ## preserve_column 2230 ## require_multiline 2231 ## goto_bol 2232 ## 2233 ## bolx=NUMBER 2234 ## 既に計算済みの移動先 (index, q) の行の行頭がある場合はここに指定します。 2235 ## 2236 ## nolx=NUMBER 2237 ## 既に計算済みの移動先 (index, q) の行の非空白行頭位置がある場合はここに指定します。 2238 ## 2239 function ble/widget/vi-command/linewise-range.impl { 2240 local p=$1 q=$2 flag=$3 reg=$4 opts=$5 2241 local ret 2242 if [[ $q == *:* ]]; then 2243 local qbase=${q%%:*} qline=${q#*:} 2244 else 2245 local qbase=$q qline=0 2246 fi 2247 2248 local bolx=; local rex=':bolx=([0-9]+):'; [[ :$opts: =~ $rex ]] && bolx=${BASH_REMATCH[1]} 2249 local nolx=; local rex=':nolx=([0-9]+):'; [[ :$opts: =~ $rex ]] && nolx=${BASH_REMATCH[1]} 2250 2251 # 移動時 (オペレータが設定されていない時) 2252 if [[ ! $flag ]]; then 2253 if [[ ! $nolx ]]; then 2254 if [[ ! $bolx ]]; then 2255 ble-edit/content/find-logical-bol "$qbase" "$qline"; bolx=$ret 2256 fi 2257 ble-edit/content/find-non-space "$bolx"; nolx=$ret 2258 fi 2259 ble-edit/content/nonbol-eolp "$nolx" && ((nolx--)) 2260 _ble_edit_ind=$nolx 2261 ble/keymap:vi/adjust-command-mode 2262 return 0 2263 fi 2264 2265 local opname=${flag%%:*} opflags=${flag#*:} 2266 if ! ble/is-function ble/keymap:vi/operator:"$opname"; then 2267 ble/widget/vi-command/bell 2268 return 1 2269 fi 2270 2271 local bolp bolq=$bolx nolq=$nolx 2272 ble-edit/content/find-logical-bol "$p"; bolp=$ret 2273 [[ $bolq ]] || { ble-edit/content/find-logical-bol "$qbase" "$qline"; bolq=$ret; } 2274 2275 # jk+- で1行も移動できない場合は操作をキャンセルする。 2276 # Note: qline を用いる場合は必ずしも望みどおり 2277 # qline 行目が存在するとは限らないことに注意する。 2278 if [[ :$opts: == *:require_multiline:* ]]; then 2279 if ((bolq==bolp)); then 2280 ble/widget/vi-command/bell 2281 return 1 2282 fi 2283 fi 2284 2285 # オペレータ呼び出し 2286 if [[ :$opflags: == *:vi_char:* || :$opflags: == *:vi_block:* ]]; then 2287 # 行き先の決定 2288 local beg=$p end 2289 if [[ :$opts: == *:preserve_column:* ]]; then 2290 local index 2291 ble/keymap:vi/get-index-of-relative-line "$qbase" "$qline"; end=$index 2292 elif [[ :$opts: == *:goto_bol:* ]]; then 2293 end=$bolq 2294 else 2295 [[ $nolq ]] || { ble-edit/content/find-non-space "$bolq"; nolq=$ret; } 2296 end=$nolq 2297 fi 2298 ((beg<=end)) || local beg=$end end=$beg 2299 2300 if [[ :$opflags: == *:vi_block:* ]]; then 2301 local ble_keymap_vi_opmode=vi_block 2302 ble/keymap:vi/call-operator "$opname" "$beg" "$end" block '' "$reg"; local ext=$? 2303 else 2304 local ble_keymap_vi_opmode=vi_char 2305 ble/keymap:vi/call-operator "$opname" "$beg" "$end" char '' "$reg"; local ext=$? 2306 fi 2307 if ((ext)); then 2308 ((ext==147)) && return 147 2309 ble/widget/vi-command/bell 2310 return "$ext" 2311 fi 2312 else 2313 # 行指向の処理 (既定) 2314 2315 # 最初の行の行頭 beg と最後の行の行末 end 2316 local beg end 2317 if ((bolp<=bolq)); then 2318 ble-edit/content/find-logical-eol "$bolq"; beg=$bolp end=$ret 2319 else 2320 ble-edit/content/find-logical-eol "$bolp"; beg=$bolq end=$ret 2321 fi 2322 ((end<${#_ble_edit_str}&&end++)) 2323 2324 local ble_keymap_vi_opmode= 2325 [[ :$opflags: == *:vi_line:* ]] && ble_keymap_vi_opmode=vi_line 2326 ble/keymap:vi/call-operator "$opname" "$beg" "$end" line '' "$reg"; local ext=$? 2327 if ((ext)); then 2328 ((ext==147)) && return 147 2329 ble/widget/vi-command/bell 2330 return "$ext" 2331 fi 2332 2333 # 範囲の先頭に移動 2334 local ind=$_ble_edit_ind 2335 if [[ $opname == [cd] ]]; then 2336 # これらは常に first-non-space になる。 2337 _ble_edit_ind=$beg 2338 ble/widget/vi-command/first-non-space 2339 elif [[ :$opts: == *:preserve_column:* ]]; then # j k 2340 if ((beg<ind)); then 2341 ble/string#count-char "${_ble_edit_str:beg:ind-beg}" $'\n' 2342 ((ret=-ret)) 2343 elif ((ind<beg)); then 2344 ble/string#count-char "${_ble_edit_str:ind:beg-ind}" $'\n' 2345 else 2346 ret=0 2347 fi 2348 2349 if ((ret)); then 2350 local index; ble/keymap:vi/get-index-of-relative-line "$_ble_edit_ind" "$ret" 2351 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 2352 _ble_edit_ind=$index 2353 fi 2354 elif [[ :$opts: == *:goto_bol:* ]]; then # 行指向 yis 2355 _ble_edit_ind=$beg 2356 else # + - gg G L H 2357 if ((beg==bolq||ind<beg)) || [[ ${_ble_edit_str:beg:ind-beg} == *$'\n'* ]] ; then 2358 # 先頭行の非空白行頭に移動する 2359 if ((bolq<=bolp)) && [[ $nolq ]]; then 2360 local nolb=$nolq 2361 else 2362 ble-edit/content/find-non-space "$beg"; local nolb=$ret 2363 fi 2364 ble-edit/content/nonbol-eolp "$nolb" && ((nolb--)) 2365 ((ind<beg||nolb<ind)) && _ble_edit_ind=$nolb 2366 fi 2367 fi 2368 fi 2369 ble/keymap:vi/adjust-command-mode 2370 return 0 2371 } 2372 function ble/widget/vi-command/linewise-goto.impl { 2373 ble/widget/vi-command/linewise-range.impl "$_ble_edit_ind" "$@" 2374 } 2375 2376 #------------------------------------------------------------------------------ 2377 # single char arguments 2378 2379 function ble/keymap:vi/async-read-char.hook { 2380 local IFS=$_ble_term_IFS 2381 local command="${*:1:$#-1}" key="${*:$#}" 2382 if ((key==(_ble_decode_Ctrl|0x6B))); then # C-k 2383 ble/decode/keymap/push vi_digraph 2384 _ble_keymap_vi_digraph__hook="$command" 2385 else 2386 builtin eval -- "$command $key" 2387 fi 2388 } 2389 2390 function ble/keymap:vi/async-read-char { 2391 local IFS=$_ble_term_IFS 2392 _ble_decode_key__hook="ble/keymap:vi/async-read-char.hook $*" 2393 return 147 2394 } 2395 2396 #------------------------------------------------------------------------------ 2397 # marks 2398 2399 ## @arr _ble_keymap_vi_mark_local 2400 ## 添字は mark の文字コードで指定する。 2401 ## 各要素は point:bytes の形をしている。 2402 ## @arr _ble_keymap_vi_mark_global 2403 ## 添字は mark の文字コードで指定する。 2404 ## 各要素は hindex:point:bytes の形をしている。 2405 _ble_keymap_vi_mark_Offset=32 2406 _ble_keymap_vi_mark_hindex= 2407 _ble_keymap_vi_mark_local=() 2408 _ble_keymap_vi_mark_global=() 2409 _ble_keymap_vi_mark_history=() 2410 _ble_keymap_vi_mark_edit_dbeg=-1 2411 _ble_keymap_vi_mark_edit_dend=-1 2412 _ble_keymap_vi_mark_edit_dend0=-1 2413 ble/array#push _ble_textarea_local_VARNAMES \ 2414 _ble_keymap_vi_mark_hindex \ 2415 _ble_keymap_vi_mark_local \ 2416 _ble_keymap_vi_mark_global \ 2417 _ble_keymap_vi_mark_history \ 2418 _ble_keymap_vi_mark_edit_dbeg \ 2419 _ble_keymap_vi_mark_edit_dend \ 2420 _ble_keymap_vi_mark_edit_dend0 2421 2422 # mark 番号と用途の対応 2423 # 2424 # 2425 # 1 内部使用。矩形挿入モードの開始点を記録するためのもの 2426 # 91 93 `[ と `]。編集・ヤンク範囲を保持する。 2427 # 96 39 `` と `'。最後のジャンプ位置を保持する。39 は実際には使用されない。 2428 # 60 62 `< と `>。最後のビジュアル範囲。 2429 # 2430 2431 ble/array#push _ble_edit_dirty_observer ble/keymap:vi/mark/shift-by-dirty-range 2432 blehook history_leave!=ble/keymap:vi/mark/history-onleave.hook 2433 2434 ## @fn ble/keymap:vi/mark/history-onleave.hook 2435 function ble/keymap:vi/mark/history-onleave.hook { 2436 if [[ $_ble_decode_keymap == vi_[inoxs]map ]]; then 2437 ble/keymap:vi/mark/set-local-mark 34 "$_ble_edit_ind" # `" 2438 fi 2439 } 2440 2441 # 履歴がロードされていない時は取り敢えず _ble_history_index=0 で登録をしておく。 2442 # 履歴がロードされた後の初めての利用のときに正しい履歴番号に修正する。 2443 function ble/keymap:vi/mark/update-mark-history { 2444 local h; ble/history/get-index -v h 2445 if [[ ! $_ble_keymap_vi_mark_hindex ]]; then 2446 _ble_keymap_vi_mark_hindex=$h 2447 elif ((_ble_keymap_vi_mark_hindex!=h)); then 2448 local imark value 2449 2450 # save 2451 local -a save=() 2452 for imark in "${!_ble_keymap_vi_mark_local[@]}"; do 2453 local value=${_ble_keymap_vi_mark_local[imark]} 2454 ble/array#push save "$imark:$value" 2455 done 2456 local IFS=$_ble_term_IFS 2457 _ble_keymap_vi_mark_history[_ble_keymap_vi_mark_hindex]="${save[*]-}" 2458 2459 # load 2460 _ble_keymap_vi_mark_local=() 2461 local entry 2462 for entry in ${_ble_keymap_vi_mark_history[h]-}; do 2463 imark=${entry%%:*} value=${entry#*:} 2464 _ble_keymap_vi_mark_local[imark]=$value 2465 done 2466 2467 _ble_keymap_vi_mark_hindex=$h 2468 fi 2469 } 2470 blehook history_change!=ble/keymap:vi/mark/history-change.hook 2471 ## @fn ble/keymap:vi/mark/history-change.hook 'delete' index... 2472 ## @fn ble/keymap:vi/mark/history-change.hook 'clear' 2473 ## @fn ble/keymap:vi/mark/history-change.hook 'insert' beg len 2474 ## @param[in] index... 2475 ## 削除する項目の番号を指定します。昇順に並んでいる事と重複がない事を仮定します。 2476 ## @param[in] beg len 2477 ## 挿入位置と挿入項目の個数を指定します。 2478 function ble/keymap:vi/mark/history-change.hook { 2479 local kind=$1; shift 2480 case $kind in 2481 (delete) 2482 # update _ble_keymap_vi_mark_global 2483 local imark 2484 for imark in "${!_ble_keymap_vi_mark_global[@]}"; do 2485 local value=${_ble_keymap_vi_mark_global[imark]} 2486 local h=${value%%:*} v=${value#*:} 2487 local idel shift=0 2488 for idel; do 2489 if [[ $idel == *-* ]]; then 2490 local b=${idel%-*} e=${idel#*-} 2491 ((b<=h&&h<e)) && shift= # delete 2492 ((h<e)) && break 2493 ((shift+=e-b)) 2494 else 2495 ((idel==h)) && shift= # delete 2496 ((idel>=h)) && break 2497 ((shift++)) 2498 fi 2499 done 2500 [[ $shift ]] && 2501 _ble_keymap_vi_mark_global[imark]=$((h-shift)):$v 2502 done 2503 2504 # update _ble_keymap_vi_mark_history 2505 ble/builtin/history/array#delete-hindex _ble_keymap_vi_mark_history "$@" 2506 2507 # reset _ble_keymap_vi_mark_hindex 2508 _ble_keymap_vi_mark_hindex= ;; 2509 2510 (clear) 2511 _ble_keymap_vi_mark_global=() 2512 _ble_keymap_vi_mark_history=() 2513 _ble_keymap_vi_mark_hindex= ;; 2514 2515 (insert) 2516 local beg=$1 len=$2 2517 2518 # update _ble_keymap_vi_mark_global 2519 local imark 2520 for imark in "${!_ble_keymap_vi_mark_global[@]}"; do 2521 local value=${_ble_keymap_vi_mark_global[imark]} 2522 2523 local h=${value%%:*} v=${value#*:} 2524 ((h>=beg)) && _ble_keymap_vi_mark_global[imark]=$((h+len)):$v 2525 done 2526 2527 # update _ble_keymap_vi_mark_history 2528 ble/builtin/history/array#insert-range _ble_keymap_vi_mark_history "$@" 2529 2530 # reset _ble_keymap_vi_mark_hindex 2531 _ble_keymap_vi_mark_hindex= ;; 2532 esac 2533 } 2534 2535 function ble/keymap:vi/mark/shift-by-dirty-range { 2536 local beg=$1 end=$2 end0=$3 reason=$4 2537 if [[ $4 == edit ]]; then 2538 ble/dirty-range#update --prefix=_ble_keymap_vi_mark_edit_d "${@:1:3}" 2539 ble/keymap:vi/xmap/update-dirty-range "$@" 2540 2541 ble/keymap:vi/mark/update-mark-history 2542 local shift=$((end-end0)) 2543 local imark 2544 for imark in "${!_ble_keymap_vi_mark_local[@]}"; do 2545 local value=${_ble_keymap_vi_mark_local[imark]} 2546 local index=${value%%:*} rest=${value#*:} 2547 ((index<beg)) || _ble_keymap_vi_mark_local[imark]=$((index<end0?beg:index+shift)):$rest 2548 done 2549 local h; ble/history/get-index -v h 2550 for imark in "${!_ble_keymap_vi_mark_global[@]}"; do 2551 local value=${_ble_keymap_vi_mark_global[imark]} 2552 [[ $value == "$h":* ]] || continue 2553 local h=${value%%:*}; value=${value:${#h}+1} 2554 local index=${value%%:*}; value=${value:${#index}+1} 2555 ((index<beg)) || _ble_keymap_vi_mark_global[imark]=$h:$((index<end0?beg:index+shift)):$value 2556 done 2557 ble/keymap:vi/mark/set-local-mark 46 "$beg" # `. 2558 else 2559 ble/dirty-range#clear --prefix=_ble_keymap_vi_mark_edit_d 2560 if [[ $4 == newline && $_ble_decode_keymap != vi_cmap ]]; then 2561 ble/keymap:vi/mark/set-local-mark 96 0 # `` 2562 fi 2563 fi 2564 } 2565 function ble/keymap:vi/mark/set-global-mark { 2566 local c=$1 index=$2 ret 2567 ble/keymap:vi/mark/update-mark-history 2568 ble-edit/content/find-logical-bol "$index"; local bol=$ret 2569 local h; ble/history/get-index -v h 2570 _ble_keymap_vi_mark_global[c]=$h:$bol:$((index-bol)) 2571 } 2572 function ble/keymap:vi/mark/set-local-mark { 2573 local c=$1 index=$2 ret 2574 ble/keymap:vi/mark/update-mark-history 2575 ble-edit/content/find-logical-bol "$index"; local bol=$ret 2576 _ble_keymap_vi_mark_local[c]=$bol:$((index-bol)) 2577 } 2578 ## @fn ble/keymap:vi/mark/get-mark.impl index bytes 2579 ## @param[in] index bytes 2580 ## 記録された行頭の位置と列を指定します。 2581 ## @var[out] ret 2582 ## マークが見つかったとき対応する位置を返します。 2583 function ble/keymap:vi/mark/get-mark.impl { 2584 local index=$1 bytes=$2 2585 local len=${#_ble_edit_str} 2586 ((index>len&&(index=len))) 2587 ble-edit/content/find-logical-bol "$index"; index=$ret 2588 ble-edit/content/find-logical-eol "$index"; local eol=$ret 2589 ((index+=bytes,index>eol&&(index=eol))) # ToDo: calculate by byte offset 2590 ret=$index 2591 return 0 2592 } 2593 ## @fn ble/keymap:vi/mark/get-mark.impl c 2594 ## @param[in] c 2595 ## mark の番号 (文字コード) を指定します。 2596 ## @var[out] ret 2597 ## マークが見つかったとき対応する位置を返します。 2598 function ble/keymap:vi/mark/get-local-mark { 2599 local c=$1 2600 ble/keymap:vi/mark/update-mark-history 2601 local value=${_ble_keymap_vi_mark_local[c]} 2602 [[ $value ]] || return 1 2603 2604 local data 2605 ble/string#split data : "$value" 2606 ble/keymap:vi/mark/get-mark.impl "${data[0]}" "${data[1]}" # -> ret 2607 } 2608 2609 # `[ `] 2610 _ble_keymap_vi_mark_suppress_edit= 2611 ## @fn ble/keymap:vi/mark/set-previous-edit-area beg end 2612 ## @param[in] beg 2613 ## @param[in] end 2614 function ble/keymap:vi/mark/set-previous-edit-area { 2615 [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0 2616 local beg=$1 end=$2 2617 ((beg<end)) && ! ble-edit/content/bolp "$end" && ((end--)) 2618 ble/keymap:vi/mark/set-local-mark 91 "$beg" # `[ 2619 ble/keymap:vi/mark/set-local-mark 93 "$end" # `] 2620 ble/keymap:vi/undo/add 2621 } 2622 function ble/keymap:vi/mark/start-edit-area { 2623 [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0 2624 ble/dirty-range#clear --prefix=_ble_keymap_vi_mark_edit_d 2625 } 2626 function ble/keymap:vi/mark/commit-edit-area { 2627 local beg=$1 end=$2 2628 ble/dirty-range#update --prefix=_ble_keymap_vi_mark_edit_d "$beg" "$end" "$end" 2629 } 2630 function ble/keymap:vi/mark/end-edit-area { 2631 [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0 2632 local beg=$_ble_keymap_vi_mark_edit_dbeg 2633 local end=$_ble_keymap_vi_mark_edit_dend 2634 ((beg>=0)) && ble/keymap:vi/mark/set-previous-edit-area "$beg" "$end" 2635 } 2636 2637 # `` 2638 function ble/keymap:vi/mark/set-jump { 2639 # ToDo: jumplist? 2640 ble/keymap:vi/mark/set-local-mark 96 "$_ble_edit_ind" 2641 } 2642 2643 function ble/widget/vi-command/set-mark { 2644 _ble_decode_key__hook="ble/widget/vi-command/set-mark.hook" 2645 return 147 2646 } 2647 function ble/widget/vi-command/set-mark.hook { 2648 local key=$1 2649 ble/keymap:vi/clear-arg 2650 local ret 2651 if ble/keymap:vi/k2c "$key" && local c=$ret; then 2652 if ((65<=c&&c<91)); then # A-Z 2653 ble/keymap:vi/mark/set-global-mark "$c" "$_ble_edit_ind" 2654 ble/keymap:vi/adjust-command-mode 2655 return 0 2656 elif ((97<=c&&c<123||c==91||c==93||c==60||c==62||c==96||c==39)); then # a-z [ ] < > ` ' 2657 ((c==39)) && c=96 # m' は m` に読み替える 2658 ble/keymap:vi/mark/set-local-mark "$c" "$_ble_edit_ind" 2659 ble/keymap:vi/adjust-command-mode 2660 return 0 2661 fi 2662 fi 2663 ble/widget/vi-command/bell 2664 return 1 2665 } 2666 2667 function ble/widget/vi-command/goto-mark.impl { 2668 local index=$1 flag=$2 reg=$3 opts=$4 2669 [[ $flag ]] || ble/keymap:vi/mark/set-jump # `` 2670 if [[ :$opts: == *:line:* ]]; then 2671 ble/widget/vi-command/linewise-goto.impl "$index" "$flag" "$reg" 2672 else 2673 ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg" nobell 2674 fi 2675 } 2676 function ble/widget/vi-command/goto-local-mark.impl { 2677 local c=$1 opts=$2 ret 2678 local ARG FLAG REG; ble/keymap:vi/get-arg 1 2679 if ble/keymap:vi/mark/get-local-mark "$c" && local index=$ret; then 2680 ble/widget/vi-command/goto-mark.impl "$index" "$FLAG" "$REG" "$opts" 2681 else 2682 ble/widget/vi-command/bell 2683 return 1 2684 fi 2685 } 2686 function ble/widget/vi-command/goto-global-mark.impl { 2687 local c=$1 opts=$2 2688 local ARG FLAG REG; ble/keymap:vi/get-arg 1 2689 2690 ble/keymap:vi/mark/update-mark-history 2691 local value=${_ble_keymap_vi_mark_global[c]} 2692 if [[ ! $value ]]; then 2693 ble/widget/vi-command/bell 2694 return 1 2695 fi 2696 2697 local data 2698 ble/string#split data : "$value" 2699 2700 # find a history entry by data[0] 2701 local index; ble/history/get-index 2702 if ((index!=data[0])); then 2703 if [[ $FLAG ]]; then 2704 ble/widget/vi-command/bell 2705 return 1 2706 fi 2707 ble-edit/history/goto "${data[0]}" 2708 fi 2709 2710 # find position by data[1]:data[2] 2711 local ret 2712 ble/keymap:vi/mark/get-mark.impl "${data[1]}" "${data[2]}" 2713 ble/widget/vi-command/goto-mark.impl "$ret" "$FLAG" "$REG" "$opts" 2714 } 2715 2716 function ble/widget/vi-command/goto-mark { 2717 _ble_decode_key__hook="ble/widget/vi-command/goto-mark.hook ${1:-char}" 2718 return 147 2719 } 2720 function ble/widget/vi-command/goto-mark.hook { 2721 local opts=$1 key=$2 2722 local ret 2723 if ble/keymap:vi/k2c "$key" && local c=$ret; then 2724 if ((65<=c&&c<91)); then # A-Z 2725 ble/widget/vi-command/goto-global-mark.impl "$c" "$opts" 2726 return "$?" 2727 elif ((_ble_keymap_vi_mark_Offset<=c)); then 2728 ((c==39)) && c=96 # `' は `` に読み替える 2729 ble/widget/vi-command/goto-local-mark.impl "$c" "$opts" 2730 return "$?" 2731 fi 2732 fi 2733 ble/keymap:vi/clear-arg 2734 ble/widget/vi-command/bell 2735 return 1 2736 } 2737 2738 #------------------------------------------------------------------------------ 2739 # repeat (nmap .) 2740 2741 ## @arr _ble_keymap_vi_repeat 2742 ## @arr _ble_keymap_vi_repeat_insert 2743 ## 2744 ## _ble_keymap_vi_repeat が前回の操作を記録する 2745 ## _ble_keymap_vi_repeat_insert は挿入モードにいる時に、 2746 ## その挿入モードに突入するきっかけとなった操作を保持する。 2747 ## これは <C-[> または <C-c> で挿入モードを完了する際に、 2748 ## _ble_keymap_vi_repeat に書き込まれるものである。 2749 ## 2750 ## ${_ble_keymap_vi_repeat[0]} = KEYMAP 2751 ## 呼び出し時の kmap を保持します。 2752 ## ${_ble_keymap_vi_repeat[1]} = KEYS 2753 ## 呼び出しに用いられたキーの列を保持します。 2754 ## ${_ble_keymap_vi_repeat[2]} = WIDGET 2755 ## 呼び出された編集コマンドを保持します。 2756 ## ${_ble_keymap_vi_repeat[@]:3:3} = ARG FLAG REG 2757 ## 呼び出し時の修飾状態を保持します。 2758 ## ${_ble_keymap_vi_repeat[6]} = _ble_keymap_vi_xmap_prev_edit 2759 ## vi_xmap のとき範囲の大きさと種類を記録します。 2760 ## ${_ble_keymap_vi_repeat[@]:10} 2761 ## 各 WIDGET が自由に使える領域 2762 ## 2763 ## @arr _ble_keymap_vi_repeat_irepeat 2764 ## 2765 ## _ble_keymap_vi_repeat の操作によって挿入モードに入るとき、 2766 ## そこで行われる挿入操作の列を記録する配列である。 2767 ## 形式は _ble_keymap_vi_irepeat と同じ。 2768 ## 2769 ## @var _ble_keymap_vi_repeat_invoke 2770 ## ble/keymap:vi/repeat/invoke を通して呼び出された widget かどうかを保持するローカル変数です。 2771 ## この変数が非空白のとき ble/keymap:vi/repeat/invoke 内部での呼び出しであることを表します。 2772 ## 2773 _ble_keymap_vi_repeat=() 2774 _ble_keymap_vi_repeat_insert=() 2775 _ble_keymap_vi_repeat_irepeat=() 2776 _ble_keymap_vi_repeat_invoke= 2777 function ble/keymap:vi/repeat/record-special { 2778 [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0 2779 2780 if [[ $_ble_keymap_vi_repeat_invoke ]]; then 2781 # repeat に引数が指定されたときは以降それを使う 2782 [[ $repeat_arg ]] && _ble_keymap_vi_repeat[3]=$repeat_arg 2783 # レジスタが記録されていないときは、以降新しく指定されたレジスタを使う 2784 [[ ! ${_ble_keymap_vi_repeat[5]} ]] && _ble_keymap_vi_repeat[5]=$repeat_reg 2785 return 0 2786 fi 2787 2788 return 1 2789 } 2790 function ble/keymap:vi/repeat/record-normal { 2791 local IFS=$_ble_term_IFS 2792 local -a repeat; repeat=("$KEYMAP" "${KEYS[*]-}" "$WIDGET" "$ARG" "$FLAG" "$REG" '') 2793 if [[ $KEYMAP == vi_[xs]map ]]; then 2794 repeat[6]=$_ble_keymap_vi_xmap_prev_edit 2795 fi 2796 if [[ $_ble_decode_keymap == vi_imap ]]; then 2797 _ble_keymap_vi_repeat_insert=("${repeat[@]}") 2798 else 2799 _ble_keymap_vi_repeat=("${repeat[@]}") 2800 _ble_keymap_vi_repeat_irepeat=() 2801 fi 2802 } 2803 function ble/keymap:vi/repeat/record { 2804 ble/keymap:vi/repeat/record-special && return 0 2805 ble/keymap:vi/repeat/record-normal 2806 } 2807 ## @fn ble/keymap:vi/repeat/record-insert 2808 ## 挿入モードを抜ける時に、挿入モードに入るきっかけになった操作と、 2809 ## 挿入モードで行われた挿入操作の列を記録します。 2810 function ble/keymap:vi/repeat/record-insert { 2811 ble/keymap:vi/repeat/record-special && return 0 2812 if [[ ${_ble_keymap_vi_repeat_insert-} ]]; then 2813 # 挿入モード突入操作が未だ有効ならば、挿入操作の有無に拘らず記録 2814 _ble_keymap_vi_repeat=("${_ble_keymap_vi_repeat_insert[@]}") 2815 _ble_keymap_vi_repeat_irepeat=("${_ble_keymap_vi_irepeat[@]}") 2816 elif ((${#_ble_keymap_vi_irepeat[@]})); then 2817 # 挿入モード突入操作が初期化されていたら、挿入操作がある時のみに記録 2818 local IFS=$_ble_term_IFS 2819 _ble_keymap_vi_repeat=(vi_nmap "${KEYS[*]-}" ble/widget/vi_nmap/insert-mode 1 '' '') 2820 _ble_keymap_vi_repeat_irepeat=("${_ble_keymap_vi_irepeat[@]}") 2821 fi 2822 ble/keymap:vi/repeat/clear-insert 2823 } 2824 ## @fn ble/keymap:vi/repeat/clear-insert 2825 ## 挿入モードにおいて white list にないコマンドが実行された時に、 2826 ## 挿入モードに入るきっかけになった操作を初期化します。 2827 function ble/keymap:vi/repeat/clear-insert { 2828 _ble_keymap_vi_repeat_insert=() 2829 } 2830 2831 function ble/keymap:vi/repeat/invoke { 2832 local repeat_arg=$_ble_edit_arg 2833 local repeat_reg=$_ble_keymap_vi_reg 2834 local KEYMAP=${_ble_keymap_vi_repeat[0]} 2835 local -a KEYS; ble/string#split-words KEYS "${_ble_keymap_vi_repeat[1]}" 2836 local WIDGET=${_ble_keymap_vi_repeat[2]} 2837 2838 # keymap の状態復元 2839 if [[ $KEYMAP != vi_[onxs]map ]]; then 2840 ble/widget/vi-command/bell 2841 return 1 2842 elif [[ $KEYMAP == vi_omap ]]; then 2843 ble/decode/keymap/push vi_omap 2844 elif [[ $KEYMAP == vi_[xs]map ]]; then 2845 local _ble_keymap_vi_xmap_prev_edit=${_ble_keymap_vi_repeat[6]} 2846 ble/widget/vi_xmap/.restore-visual-state 2847 ble/decode/keymap/push "$KEYMAP" 2848 # Note: vim では . によって領域の大きさは更新されない。 2849 # 従ってここでは敢えて _ble_keymap_vi_xmap_prev_edit を unset しない 2850 fi 2851 2852 # ※本体の _ble_keymap_vi_repeat は成功した時にのみ repeat/record で書き換える 2853 _ble_edit_arg= 2854 _ble_keymap_vi_oparg=${_ble_keymap_vi_repeat[3]} 2855 _ble_keymap_vi_opfunc=${_ble_keymap_vi_repeat[4]} 2856 [[ $repeat_arg ]] && _ble_keymap_vi_oparg=$repeat_arg 2857 2858 # vim ではレジスタは記録されたものが優先されるようだ 2859 local REG=${_ble_keymap_vi_repeat[5]} 2860 [[ $REG ]] && _ble_keymap_vi_reg=$REG 2861 2862 local _ble_keymap_vi_single_command{,_overwrite}= # single-command-mode は持続させる。 2863 local _ble_keymap_vi_repeat_invoke=1 2864 local LASTWIDGET=$_ble_decode_widget_last 2865 _ble_decode_widget_last=$WIDGET 2866 builtin eval -- "$WIDGET" 2867 2868 if [[ $_ble_decode_keymap == vi_imap ]]; then 2869 ((_ble_keymap_vi_irepeat_count<=1?(_ble_keymap_vi_irepeat_count=2):_ble_keymap_vi_irepeat_count++)) 2870 local -a _ble_keymap_vi_irepeat 2871 _ble_keymap_vi_irepeat=("${_ble_keymap_vi_repeat_irepeat[@]}") 2872 2873 ble/array#push _ble_keymap_vi_irepeat '0:ble/widget/dummy' # Note: normal-mode が自分自身を pop しようとするので。 2874 ble/widget/vi_imap/normal-mode 2875 fi 2876 ble/util/unlocal _ble_keymap_vi_single_command{,_overwrite} 2877 } 2878 2879 # nmap . 2880 function ble/widget/vi_nmap/repeat { 2881 ble/keymap:vi/repeat/invoke 2882 ble/keymap:vi/adjust-command-mode 2883 } 2884 2885 #------------------------------------------------------------------------------ 2886 # command: [cdy]?[hl] 2887 2888 ## @widget vi-command/forward-char [type] 2889 ## @widget vi-command/backward-char [type] 2890 ## 2891 ## @param[in] type 2892 ## type=wrap のとき複数行に亘る移動を許します。 2893 ## 2894 function ble/widget/vi-command/forward-char { 2895 local ARG FLAG REG; ble/keymap:vi/get-arg 1 2896 2897 local index 2898 if [[ $1 == wrap ]]; then 2899 # SP 2900 if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then 2901 ((index=_ble_edit_ind+ARG, 2902 index>${#_ble_edit_str}&&(index=${#_ble_edit_str}))) 2903 else 2904 local nl=$'\n' 2905 local rex="^([^$nl]$nl?|$nl){0,$ARG}" 2906 [[ ${_ble_edit_str:_ble_edit_ind} =~ $rex ]] 2907 ((index=_ble_edit_ind+${#BASH_REMATCH})) 2908 fi 2909 else 2910 local line=${_ble_edit_str:_ble_edit_ind:ARG} 2911 line=${line%%$'\n'*} 2912 ((index=_ble_edit_ind+${#line})) 2913 fi 2914 2915 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" 2916 } 2917 2918 function ble/widget/vi-command/backward-char { 2919 local ARG FLAG REG; ble/keymap:vi/get-arg 1 2920 2921 local index 2922 ((ARG>_ble_edit_ind&&(ARG=_ble_edit_ind))) 2923 if [[ $1 == wrap ]]; then 2924 # DEL 2925 if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then 2926 ((index=_ble_edit_ind-ARG,index<0&&(index=0))) 2927 else 2928 local width=$ARG line 2929 while ((width<=_ble_edit_ind)); do 2930 line=${_ble_edit_str:_ble_edit_ind-width:width} 2931 line=${line//[!$'\n']$'\n'/x} 2932 ((${#line}>=ARG)) && break 2933 ((width+=ARG-${#line})) 2934 done 2935 ((index=_ble_edit_ind-width,index<0&&(index=0))) 2936 fi 2937 else 2938 local line=${_ble_edit_str:_ble_edit_ind-ARG:ARG} 2939 line=${line##*$'\n'} 2940 ((index=_ble_edit_ind-${#line})) 2941 fi 2942 2943 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" 2944 } 2945 2946 # nmap ~ 2947 function ble/widget/vi_nmap/forward-char-toggle-case { 2948 local ARG FLAG REG; ble/keymap:vi/get-arg 1 2949 local line=${_ble_edit_str:_ble_edit_ind:ARG} 2950 line=${line%%$'\n'*} 2951 local len=${#line} 2952 if ((len==0)); then 2953 ble/widget/vi-command/bell 2954 return 1 2955 fi 2956 2957 local index=$((_ble_edit_ind+len)) 2958 local ret; ble/string#toggle-case "${_ble_edit_str:_ble_edit_ind:len}" 2959 ble/widget/.replace-range "$_ble_edit_ind" "$index" "$ret" 2960 ble/keymap:vi/mark/set-previous-edit-area "$_ble_edit_ind" "$index" 2961 ble/keymap:vi/repeat/record 2962 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 2963 _ble_edit_ind=$index 2964 ble/keymap:vi/adjust-command-mode 2965 return 0 2966 } 2967 2968 #------------------------------------------------------------------------------ 2969 # command: [cdy]?[jk] 2970 2971 ## @fn ble/widget/vi-command/.history-relative-line offset 2972 ## 2973 ## @param[in] offset 2974 ## 移動する相対行数を指定する。負の値は前に移動することを表し、 2975 ## 正の値は後に移動することを表す。 2976 ## 2977 ## @exit 2978 ## 全く移動しなかった場合は 1 を返します。 2979 ## それ以外の場合は 0 を返します。 2980 ## 2981 function ble/widget/vi-command/.history-relative-line { 2982 local offset=$1 2983 ((offset)) || return 0 2984 2985 # 履歴が初期化されていないとき最終行にいる。 2986 if [[ ! $_ble_history_prefix && ! $_ble_history_load_done ]]; then 2987 ((offset<0)) || return 1 2988 ble/history/initialize # to use ble/history/get-index 2989 fi 2990 2991 local index histsize 2992 ble/history/get-index 2993 ble/history/get-count -v histsize 2994 2995 local ret count=$((offset<0?-offset:offset)) exit=1 2996 ((count--)) 2997 while ((count>=0)); do 2998 if ((offset<0)); then 2999 ((index>0)) || return "$exit" 3000 ble/widget/history-prev 3001 ret=${#_ble_edit_str} 3002 ble/keymap:vi/needs-eol-fix "$ret" && ((ret--)) 3003 _ble_edit_ind=$ret 3004 else 3005 ((index<histsize)) || return "$exit" 3006 ble/widget/history-next 3007 _ble_edit_ind=0 3008 fi 3009 exit=0 3010 ble/string#count-char "$_ble_edit_str" $'\n'; local nline=$((ret+1)) 3011 ((count<nline)) && break 3012 ((count-=nline)) 3013 done 3014 3015 if ((count)); then 3016 if ((offset<0)); then 3017 ble-edit/content/find-logical-eol 0 "$((nline-count-1))" 3018 ble/keymap:vi/needs-eol-fix "$ret" && ((ret--)) 3019 else 3020 ble-edit/content/find-logical-bol 0 "$count" 3021 fi 3022 _ble_edit_ind=$ret 3023 fi 3024 3025 return 0 3026 } 3027 3028 ## @fn ble/keymap:vi/get-index-of-relative-line p offset 3029 ## 列を保持した行移動の先の位置を計算します。 3030 ## @param[in,opt] p 3031 ## 基準となる位置を指定します。空文字列を指定した時は現在位置が使われます。 3032 ## @param[in] offset 3033 ## 移動する行数を指定します。 3034 ## @param[out] index 3035 function ble/keymap:vi/get-index-of-relative-line { 3036 local ind=${1:-$_ble_edit_ind} offset=$2 3037 if ((offset==0)); then 3038 index=$ind 3039 return 0 3040 fi 3041 3042 local count=$((offset<0?-offset:offset)) 3043 local ret 3044 ble-edit/content/find-logical-bol "$ind" 0; local bol1=$ret 3045 ble-edit/content/find-logical-bol "$ind" "$offset"; local bol2=$ret 3046 if ble/edit/use-textmap; then 3047 # 列の表示相対位置 (x,y) を保持 3048 local b1x b1y; ble/textmap#getxy.cur --prefix=b1 "$bol1" 3049 local b2x b2y; ble/textmap#getxy.cur --prefix=b2 "$bol2" 3050 3051 ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret 3052 local c1x c1y; ble/textmap#getxy.cur --prefix=c1 "$ind" 3053 local e2x e2y; ble/textmap#getxy.cur --prefix=e2 "$eol2" 3054 3055 local x=$c1x y=$((b2y+c1y-b1y)) 3056 ((y>e2y&&(x=e2x,y=e2y))) 3057 3058 ble/textmap#get-index-at "$x" "$y" # local variable "index" is set here 3059 else 3060 # 論理列を保持 3061 ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret 3062 ((index=bol2+ind-bol1,index>eol2&&(index=eol2))) 3063 fi 3064 } 3065 3066 ## @fn ble/widget/vi-command/relative-line.impl offset flag reg opts 3067 ## @widget vi-command/forward-line # nmap j 3068 ## @widget vi-command/backward-line # nmap k 3069 ## 3070 ## j, k による移動の動作について。論理行を移動するとする。 3071 ## 配置情報があるとき、列は行頭からの相対表示位置 (dx,dy) を保持する。 3072 ## 配置情報がないとき、論理列を保持する。 3073 ## 3074 ## より前の履歴項目に移った時は列は行末に移る。 3075 ## より後の履歴項目に移った時は列は先頭に移る。 3076 ## 3077 ## ToDo: 移動開始時の相対表示位置の記録は現在行っていない。 3078 ## 3079 ## @param[in] offset flag 3080 ## 3081 ## @param[in] opts 3082 ## 以下の値をコロンで区切って繋げた物を指定する。 3083 ## 3084 ## history 3085 ## 現在の履歴項目内で要求された行数だけ移動できないとき、 3086 ## 履歴項目内の論理行を移動する。 3087 ## 但し flag がある場合は履歴項目の移動は行わない。 3088 ## 3089 function ble/widget/vi-command/relative-line.impl { 3090 local offset=$1 flag=$2 reg=$3 opts=$4 3091 ((offset==0)) && return 0 3092 if [[ $flag ]]; then 3093 ble/widget/vi-command/linewise-goto.impl "$_ble_edit_ind:$offset" "$flag" "$reg" preserve_column:require_multiline 3094 return "$?" 3095 fi 3096 3097 # 現在履歴項目内で移動できる行数の判定 3098 local count=$((offset<0?-offset:offset)) ret 3099 if ((offset<0)); then 3100 ble/string#count-char "${_ble_edit_str::_ble_edit_ind}" $'\n' 3101 else 3102 ble/string#count-char "${_ble_edit_str:_ble_edit_ind}" $'\n' 3103 fi 3104 ((count-=count<ret?count:ret)) 3105 3106 # 現在の履歴項目内での探索 3107 if ((count==0)); then 3108 local index; ble/keymap:vi/get-index-of-relative-line "$_ble_edit_ind" "$offset" 3109 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 3110 _ble_edit_ind=$index 3111 ble/keymap:vi/adjust-command-mode 3112 return 0 3113 fi 3114 3115 # 履歴項目を行数を数えつつ移動 3116 if [[ $_ble_decode_keymap == vi_nmap && :$opts: == *:history:* ]]; then 3117 if ble/widget/vi-command/.history-relative-line "$((offset>=0?count:-count))" || ((nmove)); then 3118 ble/keymap:vi/adjust-command-mode 3119 return 0 3120 fi 3121 fi 3122 3123 ble/widget/vi-command/bell 3124 return 1 3125 } 3126 function ble/widget/vi-command/forward-line { 3127 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3128 ble/widget/vi-command/relative-line.impl "$ARG" "$FLAG" "$REG" history 3129 } 3130 function ble/widget/vi-command/backward-line { 3131 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3132 ble/widget/vi-command/relative-line.impl "$((-ARG))" "$FLAG" "$REG" history 3133 } 3134 3135 ## @fn ble/widget/vi-command/graphical-relative-line.impl offset flag reg opts 3136 ## @widget vi-command/graphical-forward-line # nmap gj 3137 ## @widget vi-command/graphical-backward-line # nmap gk 3138 ## 3139 ## @param[in] offset 3140 ## 移動する相対行数。負の値は上の行へ行くことを表す。正の値は下の行へ行くことを表す。 3141 ## @param[in] flag 3142 ## オペレータを指定する。 3143 ## @param[in] opts 3144 ## 以下のオプションをコロンで繋げたものを指定する。 3145 ## 3146 ## history 3147 ## 3148 function ble/widget/vi-command/graphical-relative-line.impl { 3149 local offset=$1 flag=$2 reg=$3 opts=$4 3150 local index move 3151 if ble/edit/use-textmap; then 3152 local x y ax ay 3153 ble/textmap#getxy.cur "$_ble_edit_ind" 3154 ((ax=x,ay=y+offset, 3155 ay<_ble_textmap_begy?(ay=_ble_textmap_begy): 3156 (ay>_ble_textmap_endy?(ay=_ble_textmap_endy):0))) 3157 ble/textmap#get-index-at "$ax" "$ay" 3158 ble/textmap#getxy.cur --prefix=a "$index" 3159 ((offset-=move=ay-y)) 3160 else 3161 local ret ind=$_ble_edit_ind 3162 ble-edit/content/find-logical-bol "$ind" 0; local bol1=$ret 3163 ble-edit/content/find-logical-bol "$ind" "$offset"; local bol2=$ret 3164 ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret 3165 ((index=bol2+ind-bol1,index>eol2&&(index=eol2))) 3166 3167 if ((index>ind)); then 3168 ble/string#count-char "${_ble_edit_str:ind:index-ind}" $'\n' 3169 ((offset+=move=-ret)) 3170 elif ((index<ind)); then 3171 ble/string#count-char "${_ble_edit_str:index:ind-index}" $'\n' 3172 ((offset+=move=ret)) 3173 fi 3174 fi 3175 3176 if ((offset==0)); then 3177 ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg" 3178 return "$?" 3179 fi 3180 3181 if [[ ! $flag && $_ble_decode_keymap == vi_nmap && :$opts: == *:history:* ]]; then 3182 if ble/widget/vi-command/.history-relative-line "$offset"; then 3183 ble/keymap:vi/adjust-command-mode 3184 return 0 3185 fi 3186 fi 3187 3188 # 失敗: オペレータは実行されないが移動はする。 3189 ((move)) && ble/widget/vi-command/exclusive-goto.impl "$index" 3190 ble/widget/vi-command/bell 3191 return 1 3192 } 3193 function ble/widget/vi-command/graphical-forward-line { 3194 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3195 ble/widget/vi-command/graphical-relative-line.impl "$ARG" "$FLAG" "$REG" 3196 } 3197 function ble/widget/vi-command/graphical-backward-line { 3198 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3199 ble/widget/vi-command/graphical-relative-line.impl "$((-ARG))" "$FLAG" "$REG" 3200 } 3201 3202 #------------------------------------------------------------------------------ 3203 # command: ^ + - _ $ 3204 3205 function ble/widget/vi-command/relative-first-non-space.impl { 3206 local arg=$1 flag=$2 reg=$3 opts=$4 3207 local ret ind=$_ble_edit_ind 3208 ble-edit/content/find-logical-bol "$ind" "$arg"; local bolx=$ret 3209 ble-edit/content/find-non-space "$bolx"; local nolx=$ret 3210 3211 # 2017-09-12 何故か分からないが vim はこういう振る舞いに見える。 3212 ((_ble_keymap_vi_single_command==2&&_ble_keymap_vi_single_command--)) 3213 3214 if [[ $flag ]]; then 3215 if [[ :$opts: == *:charwise:* ]]; then 3216 # command: ^ 3217 ble-edit/content/nonbol-eolp "$nolx" && ((nolx--)) 3218 ble/widget/vi-command/exclusive-goto.impl "$nolx" "$flag" "$reg" nobell 3219 elif [[ :$opts: == *:multiline:* ]]; then 3220 # command: + - 3221 ble/widget/vi-command/linewise-goto.impl "$nolx" "$flag" "$reg" require_multiline:bolx="$bolx":nolx="$nolx" 3222 else 3223 # command: _ 3224 ble/widget/vi-command/linewise-goto.impl "$nolx" "$flag" "$reg" bolx="$bolx":nolx="$nolx" 3225 fi 3226 return "$?" 3227 fi 3228 3229 local count=$((arg<0?-arg:arg)) nmove=0 3230 if ((count)); then 3231 local beg end; ((nolx<ind?(beg=nolx,end=ind):(beg=ind,end=nolx))) 3232 ble/string#count-char "${_ble_edit_str:beg:end-beg}" $'\n'; nmove=$ret 3233 ((count-=nmove)) 3234 fi 3235 3236 if ((count==0)); then 3237 ble/keymap:vi/needs-eol-fix "$nolx" && ((nolx--)) 3238 _ble_edit_ind=$nolx 3239 ble/keymap:vi/adjust-command-mode 3240 return 0 3241 fi 3242 3243 # 履歴項目の移動 3244 if [[ $_ble_decode_keymap == vi_nmap && :$opts: == *:history:* ]] && ble/widget/vi-command/.history-relative-line "$((arg>=0?count:-count))"; then 3245 ble/widget/vi-command/first-non-space 3246 elif ((nmove)); then 3247 ble/keymap:vi/needs-eol-fix "$nolx" && ((nolx--)) 3248 _ble_edit_ind=$nolx 3249 ble/keymap:vi/adjust-command-mode 3250 else 3251 ble/widget/vi-command/bell 3252 return 1 3253 fi 3254 } 3255 # nmap ^ 3256 function ble/widget/vi-command/first-non-space { 3257 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3258 ble/widget/vi-command/relative-first-non-space.impl 0 "$FLAG" "$REG" charwise:history 3259 } 3260 # nmap + 3261 function ble/widget/vi-command/forward-first-non-space { 3262 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3263 ble/widget/vi-command/relative-first-non-space.impl "$ARG" "$FLAG" "$REG" multiline:history 3264 } 3265 # nmap - 3266 function ble/widget/vi-command/backward-first-non-space { 3267 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3268 ble/widget/vi-command/relative-first-non-space.impl "$((-ARG))" "$FLAG" "$REG" multiline:history 3269 } 3270 # nmap _ 3271 function ble/widget/vi-command/first-non-space-forward { 3272 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3273 ble/widget/vi-command/relative-first-non-space.impl "$((ARG-1))" "$FLAG" "$REG" history 3274 } 3275 # nmap $ 3276 function ble/widget/vi-command/forward-eol { 3277 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3278 if ((ARG>1)) && [[ ${_ble_edit_str:_ble_edit_ind} != *$'\n'* ]]; then 3279 ble/widget/vi-command/bell 3280 return 1 3281 fi 3282 3283 local ret index 3284 ble-edit/content/find-logical-eol "$_ble_edit_ind" "$((ARG-1))"; index=$ret 3285 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 3286 ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell 3287 [[ $_ble_decode_keymap == vi_[xs]map ]] && 3288 ble/keymap:vi/xmap/add-eol-extension # 末尾拡張 3289 } 3290 # nmap g0 g<home> 3291 function ble/widget/vi-command/beginning-of-graphical-line { 3292 if ble/edit/use-textmap; then 3293 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3294 local x y index 3295 ble/textmap#getxy.cur "$_ble_edit_ind" 3296 ble/textmap#get-index-at 0 "$y" 3297 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 3298 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell 3299 else 3300 ble/widget/vi-command/beginning-of-line 3301 fi 3302 } 3303 # nmap g^ 3304 function ble/widget/vi-command/graphical-first-non-space { 3305 if ble/edit/use-textmap; then 3306 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3307 local x y index ret 3308 ble/textmap#getxy.cur "$_ble_edit_ind" 3309 ble/textmap#get-index-at 0 "$y" 3310 ble-edit/content/find-non-space "$index" 3311 ble/keymap:vi/needs-eol-fix "$ret" && ((ret--)) 3312 ble/widget/vi-command/exclusive-goto.impl "$ret" "$FLAG" "$REG" nobell 3313 else 3314 ble/widget/vi-command/first-non-space 3315 fi 3316 } 3317 # nmap g$ g<end> 3318 function ble/widget/vi-command/graphical-forward-eol { 3319 if ble/edit/use-textmap; then 3320 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3321 local x y index 3322 ble/textmap#getxy.cur "$_ble_edit_ind" 3323 ble/textmap#get-index-at "$((_ble_textmap_cols-1))" "$((y+ARG-1))" 3324 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 3325 ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell 3326 else 3327 ble/widget/vi-command/forward-eol 3328 fi 3329 } 3330 # nmap gm 3331 function ble/widget/vi-command/middle-of-graphical-line { 3332 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3333 local index 3334 if ble/edit/use-textmap; then 3335 local x y 3336 ble/textmap#getxy.cur "$_ble_edit_ind" 3337 ble/textmap#get-index-at "$((_ble_textmap_cols/2))" "$y" 3338 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 3339 else 3340 local ret 3341 ble-edit/content/find-logical-bol; local bol=$ret 3342 ble-edit/content/find-logical-eol; local eol=$ret 3343 ((index=(bol+${COLUMNS:-eol})/2, 3344 index>eol&&(index=eol), 3345 bol<eol&&index==eol&&(index--))) 3346 fi 3347 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell 3348 } 3349 # nmap g_ 3350 function ble/widget/vi-command/last-non-space { 3351 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3352 local ret 3353 ble-edit/content/find-logical-eol "$_ble_edit_ind" "$((ARG-1))"; local index=$ret 3354 if ((ARG>1)) && [[ ${_ble_edit_str:_ble_edit_ind:index-_ble_edit_ind} != *$'\n'* ]]; then 3355 # 行移動を起こすはずだったのに一行も進めなかった場合は失敗 3356 ble/widget/vi-command/bell 3357 return 1 3358 fi 3359 3360 local rex=$'([^ \t\n]?[ \t]+|[^ \t\n])$' 3361 [[ ${_ble_edit_str::index} =~ $rex ]] && ((index-=${#BASH_REMATCH})) 3362 ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell 3363 3364 } 3365 3366 #------------------------------------------------------------------------------ 3367 # vi_nmap: scroll 3368 # C-d, C-u, C-e, C-y 3369 # C-b, prior, C-f, next 3370 3371 _ble_keymap_vi_previous_scroll= 3372 ## @fn ble/widget/vi_nmap/scroll.impl opts 3373 ## @arg[in] opts 3374 ## forward 3375 ## backward 3376 function ble/widget/vi_nmap/scroll.impl { 3377 local opts=$1 3378 local height=${_ble_canvas_panel_height[_ble_textarea_panel]} 3379 3380 # adjust arguments 3381 local ARG FLAG REG; ble/keymap:vi/get-arg "$_ble_keymap_vi_previous_scroll" 3382 _ble_keymap_vi_previous_scroll=$ARG 3383 [[ $ARG ]] || ((ARG=height/2)) 3384 [[ :$opts: == *:backward:* ]] && ((ARG=-ARG)) 3385 3386 ble/widget/.update-textmap 3387 if [[ :$opts: == *:cursor:* ]]; then 3388 # move 3389 local x y index ret 3390 ble/textmap#getxy.cur "$_ble_edit_ind" 3391 ble/textmap#get-index-at 0 "$((y+ARG))" 3392 ble-edit/content/find-non-space "$index" 3393 ble/keymap:vi/needs-eol-fix "$ret" && ((ret--)) 3394 _ble_edit_ind=$ret 3395 ble/keymap:vi/adjust-command-mode 3396 3397 ((_ble_textmap_endy<height)) && return 0 3398 local ax ay 3399 ble/textmap#getxy.cur --prefix=a "$_ble_edit_ind" 3400 local max_scroll=$((_ble_textmap_endy+1-height)) 3401 ((_ble_textarea_scroll_new+=ay-y)) 3402 if ((_ble_textarea_scroll_new<0)); then 3403 _ble_textarea_scroll_new=0 3404 elif ((_ble_textarea_scroll_new>max_scroll)); then 3405 _ble_textarea_scroll_new=$max_scroll 3406 fi 3407 else 3408 ((_ble_textmap_endy<height)) && return 0 3409 3410 local max_scroll=$((_ble_textmap_endy+1-height)) 3411 ((_ble_textarea_scroll_new+=ARG)) 3412 if ((_ble_textarea_scroll_new<0)); then 3413 _ble_textarea_scroll_new=0 3414 elif ((_ble_textarea_scroll_new>max_scroll)); then 3415 _ble_textarea_scroll_new=$max_scroll 3416 fi 3417 3418 # ax ay 表示範囲 3419 local ay=$((_ble_textarea_scroll_new+_ble_textmap_begy)) 3420 local by=$((_ble_textarea_scroll_new+height-1)) 3421 ((_ble_textarea_scroll_new&&ay++)) 3422 3423 # カーソル範囲 3424 ((_ble_textarea_scroll_new!=0&&ay<by&&ay++, 3425 _ble_textarea_scroll_new!=max_scroll&&ay<by&&by--)) 3426 local x y 3427 ble/textmap#getxy.cur "$_ble_edit_ind" 3428 if ((y<ay?(y=ay,1):(y>by?(y=by,1):0))); then 3429 local index 3430 ble/textmap#get-index-at "$x" "$y" 3431 _ble_edit_ind=$index 3432 fi 3433 3434 ble/keymap:vi/adjust-command-mode 3435 fi 3436 } 3437 3438 # nmap C-d 3439 function ble/widget/vi_nmap/forward-line-scroll { 3440 ble/widget/vi_nmap/scroll.impl forward:cursor 3441 } 3442 # nmap C-u 3443 function ble/widget/vi_nmap/backward-line-scroll { 3444 ble/widget/vi_nmap/scroll.impl backward:cursor 3445 } 3446 # nmap C-e 3447 function ble/widget/vi_nmap/forward-scroll { 3448 ble/widget/vi_nmap/scroll.impl forward 3449 } 3450 # nmap C-y 3451 function ble/widget/vi_nmap/backward-scroll { 3452 ble/widget/vi_nmap/scroll.impl backward 3453 } 3454 3455 # nmap C-f, next 3456 function ble/widget/vi_nmap/pagedown { 3457 local height=${_ble_canvas_panel_height[_ble_textarea_panel]} 3458 3459 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3460 3461 ble/widget/.update-textmap 3462 3463 # 最終行以外にいる事を確認 3464 local x y 3465 ble/textmap#getxy.cur "$_ble_edit_ind" 3466 if ((y==_ble_textmap_endy)); then 3467 ble/widget/vi-command/bell 3468 return 1 3469 fi 3470 3471 # 行き先を決定 3472 local vheight=$((height-_ble_textmap_begy-1)) 3473 local ybase=$((_ble_textarea_scroll_new+height-1)) 3474 local y1=$((ybase+(ARG-1)*(vheight-2))) 3475 local index ret 3476 ble/textmap#get-index-at 0 "$y1" 3477 ble-edit/content/bolp "$index" && 3478 ble-edit/content/find-non-space "$index"; index=$ret 3479 _ble_edit_ind=$index 3480 3481 # スクロール (現在位置が上から2行目になる様に) 3482 local max_scroll=$((_ble_textmap_endy+1-height)) 3483 ble/textmap#getxy.cur "$_ble_edit_ind" 3484 local scroll=$((y<=_ble_textmap_begy+1?0:(y-_ble_textmap_begy-1))) 3485 ((scroll>max_scroll&&(scroll=max_scroll))) 3486 _ble_textarea_scroll_new=$scroll 3487 ble/keymap:vi/adjust-command-mode 3488 } 3489 # nmap C-b, prior 3490 function ble/widget/vi_nmap/pageup { 3491 local height=${_ble_canvas_panel_height[_ble_textarea_panel]} 3492 3493 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3494 3495 ble/widget/.update-textmap 3496 3497 # 少なくとも1行目が表示されていない事を確認 3498 if ((!_ble_textarea_scroll_new)); then 3499 ble/widget/vi-command/bell 3500 return 1 3501 fi 3502 3503 # 行き先を決定 3504 local vheight=$((height-_ble_textmap_begy-1)) 3505 local ybase=$((_ble_textarea_scroll_new+_ble_textmap_begy+1)) 3506 local y1=$((ybase-(ARG-1)*(vheight-2))) 3507 ((y1<_ble_textmap_begy&&(y1=_ble_textmap_begy))) 3508 local index ret 3509 ble/textmap#get-index-at 0 "$y1" 3510 ble-edit/content/bolp "$index" && 3511 ble-edit/content/find-non-space "$index"; index=$ret 3512 _ble_edit_ind=$index 3513 3514 # スクロール (現在位置が下から2行目になる様に) 3515 local x y 3516 ble/textmap#getxy.cur "$_ble_edit_ind" 3517 local scroll=$((y-height+2)) 3518 ((scroll<0&&(scroll=0))) 3519 _ble_textarea_scroll_new=$scroll 3520 ble/keymap:vi/adjust-command-mode 3521 } 3522 3523 function ble/widget/vi_nmap/scroll-to-center.impl { 3524 local opts=$1 3525 ble/widget/.update-textmap 3526 local height=${_ble_canvas_panel_height[_ble_textarea_panel]} 3527 3528 local ARG FLAG REG; ble/keymap:vi/get-arg '' 3529 if [[ ! $ARG && :$opts: == *:pagedown:* ]]; then 3530 local y1=$((_ble_textarea_scroll_new+height)) 3531 local index 3532 ble/textmap#get-index-at 0 "$y1" 3533 ((_ble_edit_ind=index)) 3534 fi 3535 3536 local ret 3537 ble-edit/content/find-logical-bol "$_ble_edit_ind"; local bol1=$ret 3538 if [[ $ARG || :$opts: == *:nol:* ]]; then 3539 if [[ $ARG ]]; then 3540 ble-edit/content/find-logical-bol 0 "$((ARG-1))"; local bol2=$ret 3541 else 3542 local bol2=$bol1 3543 fi 3544 3545 if [[ :$opts: == *:nol:* ]]; then 3546 # 非空白行頭に移動する 3547 ble-edit/content/find-non-space "$bol2" 3548 _ble_edit_ind=$ret 3549 elif ((bol1!=bol2)); then 3550 # 行内の同じ相対位置に移動する 3551 3552 # dx dy = 行頭からの相対位置 3553 local b1x b1y p1x p1y dx dy 3554 ble/textmap#getxy.cur --prefix=b1 "$bol1" 3555 ble/textmap#getxy.cur --prefix=p1 "$_ble_edit_ind" 3556 ((dx=p1x,dy=p1y-b1y)) 3557 3558 # index = 行き先の行 bol2 の同じ相対位置のインデックス 3559 local b2x b2y p2x p2y index 3560 ble/textmap#getxy.cur --prefix=b2 "$bol2" 3561 ((p2x=b2x,p2y=b2y+dy)) 3562 ble/textmap#get-index-at "$p2x" "$p2y" 3563 3564 if ble-edit/content/find-logical-bol "$index"; ((ret==bol2)); then 3565 _ble_edit_ind=$index 3566 else 3567 # 別の行になっている時は行末に移動 3568 ble-edit/content/find-logical-eol "$bol2" 3569 _ble_edit_ind=$ret 3570 fi 3571 fi 3572 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 3573 fi 3574 3575 # スクロール量の計算 3576 if ((_ble_textmap_endy+1>height)); then 3577 local max_scroll=$((_ble_textmap_endy+1-height)) 3578 3579 local b1x b1y 3580 ble/textmap#getxy.cur --prefix=b1 "$bol1" 3581 3582 local scroll= 3583 if [[ :$opts: == *:top:* ]]; then 3584 ((scroll=b1y-(_ble_textmap_begy+2))) 3585 elif [[ :$opts: == *:bottom:* ]]; then 3586 ((scroll=b1y-(height-2))) 3587 else 3588 local vheight=$((height-_ble_textmap_begy-1)) 3589 ((scroll=b1y-(_ble_textmap_begy+1+vheight/2))) 3590 fi 3591 3592 if ((scroll<0)); then 3593 scroll=0 3594 elif ((scroll>max_scroll)); then 3595 scroll=$max_scroll 3596 fi 3597 _ble_textarea_scroll_new=$scroll 3598 fi 3599 3600 ble/keymap:vi/adjust-command-mode 3601 } 3602 3603 # nmap zz 3604 function ble/widget/vi_nmap/scroll-to-center-and-redraw { 3605 ble/widget/vi_nmap/scroll-to-center.impl 3606 ble/widget/redraw-line 3607 } 3608 # nmap zt 3609 function ble/widget/vi_nmap/scroll-to-top-and-redraw { 3610 ble/widget/vi_nmap/scroll-to-center.impl top 3611 ble/widget/redraw-line 3612 } 3613 # nmap zb 3614 function ble/widget/vi_nmap/scroll-to-bottom-and-redraw { 3615 ble/widget/vi_nmap/scroll-to-center.impl bottom 3616 ble/widget/redraw-line 3617 } 3618 # nmap z. 3619 function ble/widget/vi_nmap/scroll-to-center-non-space-and-redraw { 3620 ble/widget/vi_nmap/scroll-to-center.impl nol 3621 ble/widget/redraw-line 3622 } 3623 # nmap z<C-m> 3624 function ble/widget/vi_nmap/scroll-to-top-non-space-and-redraw { 3625 ble/widget/vi_nmap/scroll-to-center.impl top:nol 3626 ble/widget/redraw-line 3627 } 3628 # nmap z- 3629 function ble/widget/vi_nmap/scroll-to-bottom-non-space-and-redraw { 3630 ble/widget/vi_nmap/scroll-to-center.impl bottom:nol 3631 ble/widget/redraw-line 3632 } 3633 # nmap z+ 3634 function ble/widget/vi_nmap/scroll-or-pagedown-and-redraw { 3635 ble/widget/vi_nmap/scroll-to-center.impl top:nol:pagedown 3636 ble/widget/redraw-line 3637 } 3638 3639 #------------------------------------------------------------------------------ 3640 # command: p P 3641 3642 ## @fn ble/widget/vi_nmap/paste.impl/block arg [type] 3643 ## 3644 ## @param[in] arg 3645 ## 挿入する各行の繰り返し回数を指定します。 3646 ## 3647 ## @param[in] type 3648 ## graphical を指定すると配置情報を用いて挿入します。 3649 ## 省略したときは、配置情報があるときにそれを使用します。 3650 ## それ以外を指定すると論理列に基いて挿入を行います。 3651 ## 3652 ## @var[in] _ble_edit_kill_ring 3653 ## 改行区切りの文字列リストです。 3654 ## 3655 ## @var[in] _ble_edit_kill_type == B:* 3656 ## B: に続き空白区切りの数字のリストを保持します。 3657 ## 数字は _ble_edit_kill_ring に含まれる行の数と同じだけ指定します。 3658 ## 数字は行の途中に挿入する際に後ろに追加する空白の数を表します。 3659 ## 3660 function ble/widget/vi_nmap/paste.impl/block { 3661 local arg=${1:-1} type=$2 3662 local graphical= 3663 if [[ $type ]]; then 3664 [[ $type == graphical ]] && graphical=1 3665 else 3666 ble/edit/use-textmap && graphical=1 3667 fi 3668 3669 local ret cols=$_ble_textmap_cols 3670 3671 local -a afill; ble/string#split-words afill "${_ble_edit_kill_type:2}" 3672 local atext; ble/string#split-lines atext "$_ble_edit_kill_ring" 3673 local ntext=${#atext[@]} 3674 3675 if [[ $graphical ]]; then 3676 ble-edit/content/find-logical-bol; local bol=$ret 3677 local bx by x y c 3678 ble/textmap#getxy.cur --prefix=b "$bol" 3679 ble/textmap#getxy.cur "$_ble_edit_ind" 3680 ((y-=by,c=y*cols+x)) 3681 else 3682 ble-edit/content/find-logical-bol; local bol=$ret 3683 local c=$((_ble_edit_ind-bol)) 3684 fi 3685 3686 local -a ins_beg=() ins_end=() ins_text=() 3687 local i is_newline= 3688 for ((i=0;i<ntext;i++)); do 3689 if ((i>0)); then 3690 ble-edit/content/find-logical-bol "$bol" 1 3691 if ((bol==ret)); then 3692 is_newline=1 3693 else 3694 bol=$ret 3695 [[ $graphical ]] && ble/textmap#getxy.cur --prefix=b "$bol" 3696 fi 3697 fi 3698 3699 # 挿入文字列 3700 local text=${atext[i]} 3701 local fill=$((afill[i])) 3702 if ((arg>1)); then 3703 ret= 3704 ((fill)) && ble/string#repeat ' ' "$fill" 3705 ble/string#repeat "$text$ret" "$arg" 3706 text=${ret::${#ret}-fill} 3707 fi 3708 3709 # 挿入位置と padding 3710 local index iend= 3711 if [[ $is_newline ]]; then 3712 index=${#_ble_edit_str} 3713 ble/string#repeat ' ' "$c" 3714 text=$'\n'$ret$text 3715 3716 elif [[ $graphical ]]; then 3717 ble-edit/content/find-logical-eol "$bol"; local eol=$ret 3718 ble/textmap#get-index-at "$x" "$((by+y))"; ((index>eol&&(index=eol))) 3719 3720 # left padding (行末がより左にある、または、全角文字があるとき) 3721 local ax ay ac; ble/textmap#getxy.out --prefix=a "$index" 3722 ((ay-=by,ac=ay*cols+ax)) 3723 if ((ac<c)); then 3724 ble/string#repeat ' ' "$((c-ac))" 3725 text=$ret$text 3726 3727 # タブを空白に変換 3728 if ((index<eol)) && [[ ${_ble_edit_str:index:1} == $'\t' ]]; then 3729 local rx ry rc; ble/textmap#getxy.out --prefix=r "$((index+1))" 3730 ((rc=(ry-by)*cols+rx)) 3731 ble/string#repeat ' ' "$((rc-c))" 3732 text=$text$ret 3733 iend=$((index+1)) 3734 fi 3735 fi 3736 3737 # right padding (行末がより右にあるとき) 3738 if ((index<eol&&fill)); then 3739 ble/string#repeat ' ' "$fill" 3740 text=$text$ret 3741 fi 3742 3743 else 3744 ble-edit/content/find-logical-eol "$bol"; local eol=$ret 3745 local index=$((bol+c)) 3746 3747 if ((index<eol)); then 3748 if ((fill)); then 3749 ble/string#repeat ' ' "$fill" 3750 text=$text$ret 3751 fi 3752 elif ((index>eol)); then 3753 ble/string#repeat ' ' "$((index-eol))" 3754 text=$ret$text 3755 index=$eol 3756 fi 3757 fi 3758 3759 ble/array#push ins_beg "$index" 3760 ble/array#push ins_end "${iend:-$index}" 3761 ble/array#push ins_text "$text" 3762 done 3763 3764 # 逆順に挿入 3765 ble/keymap:vi/mark/start-edit-area 3766 local i=${#ins_beg[@]} 3767 while ((i--)); do 3768 local ibeg=${ins_beg[i]} iend=${ins_end[i]} text=${ins_text[i]} 3769 ble/widget/.replace-range "$ibeg" "$iend" "$text" 3770 done 3771 ble/keymap:vi/mark/end-edit-area 3772 ble/keymap:vi/repeat/record 3773 3774 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 3775 ble/keymap:vi/adjust-command-mode 3776 } 3777 3778 function ble/widget/vi_nmap/paste.impl { 3779 local arg=$1 reg=$2 is_after=$3 3780 if [[ $reg ]]; then 3781 local _ble_edit_kill_ring _ble_edit_kill_type 3782 ble/keymap:vi/register#load "$reg" 3783 fi 3784 3785 [[ $_ble_edit_kill_ring ]] || return 0 3786 local ret 3787 if [[ $_ble_edit_kill_type == L ]]; then 3788 ble/string#repeat "$_ble_edit_kill_ring" "$arg" 3789 local content=$ret 3790 3791 local index dbeg dend 3792 if ((is_after)); then 3793 ble-edit/content/find-logical-eol; index=$ret 3794 if ((index==${#_ble_edit_str})); then 3795 content=$'\n'${content%$'\n'} 3796 ((dbeg=index+1,dend=index+${#content})) 3797 else 3798 ((index++,dbeg=index,dend=index+${#content}-1)) 3799 fi 3800 else 3801 ble-edit/content/find-logical-bol 3802 ((index=ret,dbeg=index,dend=index+${#content}-1)) 3803 fi 3804 3805 ble/widget/.replace-range "$index" "$index" "$content" 3806 _ble_edit_ind=$dbeg 3807 ble/keymap:vi/mark/set-previous-edit-area "$dbeg" "$dend" 3808 ble/keymap:vi/repeat/record 3809 ble/widget/vi-command/first-non-space 3810 elif [[ $_ble_edit_kill_type == B:* ]]; then 3811 if ((is_after)) && ! ble-edit/content/eolp; then 3812 ((_ble_edit_ind++)) 3813 fi 3814 ble/widget/vi_nmap/paste.impl/block "$arg" 3815 else 3816 if ((is_after)) && ! ble-edit/content/eolp; then 3817 ((_ble_edit_ind++)) 3818 fi 3819 ble/string#repeat "$_ble_edit_kill_ring" "$arg" 3820 local beg=$_ble_edit_ind 3821 ble/widget/.insert-string "$ret" 3822 local end=$_ble_edit_ind 3823 ble/keymap:vi/mark/set-previous-edit-area "$beg" "$end" 3824 ble/keymap:vi/repeat/record 3825 [[ $_ble_keymap_vi_single_command ]] || ((_ble_edit_ind--)) 3826 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 3827 ble/keymap:vi/adjust-command-mode 3828 fi 3829 return 0 3830 } 3831 3832 function ble/widget/vi_nmap/paste-after { 3833 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3834 ble/widget/vi_nmap/paste.impl "$ARG" "$REG" 1 3835 } 3836 function ble/widget/vi_nmap/paste-before { 3837 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3838 ble/widget/vi_nmap/paste.impl "$ARG" "$REG" 0 3839 } 3840 3841 #------------------------------------------------------------------------------ 3842 # command: x s X C D 3843 3844 # nmap x, <delete> 3845 function ble/widget/vi_nmap/kill-forward-char { 3846 _ble_keymap_vi_opfunc=d 3847 ble/widget/vi-command/forward-char 3848 } 3849 # nmap s 3850 function ble/widget/vi_nmap/kill-forward-char-and-insert { 3851 _ble_keymap_vi_opfunc=c 3852 ble/widget/vi-command/forward-char 3853 } 3854 # nmap X 3855 function ble/widget/vi_nmap/kill-backward-char { 3856 _ble_keymap_vi_opfunc=d 3857 ble/widget/vi-command/backward-char 3858 } 3859 # nmap D 3860 function ble/widget/vi_nmap/kill-forward-line { 3861 _ble_keymap_vi_opfunc=d 3862 ble/widget/vi-command/forward-eol 3863 } 3864 # nmap C 3865 function ble/widget/vi_nmap/kill-forward-line-and-insert { 3866 _ble_keymap_vi_opfunc=c 3867 ble/widget/vi-command/forward-eol 3868 } 3869 3870 #------------------------------------------------------------------------------ 3871 # command: w W b B e E 3872 3873 function ble/widget/vi-command/forward-word.impl { 3874 local arg=$1 flag=$2 reg=$3 rex_word=$4 3875 local ifs=$_ble_term_IFS 3876 if [[ $flag == c && ${_ble_edit_str:_ble_edit_ind:1} != [$ifs] ]]; then 3877 # Note: cw cW は特別な動作 3878 # http://vim-jp.org/vimdoc-ja/change.html#cw 3879 ble/widget/vi-command/forward-word-end.impl "$arg" "$flag" "$reg" "$rex_word" allow_here 3880 return "$?" 3881 fi 3882 local b=$'[ \t]' n=$'\n' 3883 local rex="^((($rex_word)$n?|$b+$n?|$n)($b+$n)*$b*){0,$arg}" # 単語先頭または空行に止まる 3884 [[ ${_ble_edit_str:_ble_edit_ind} =~ $rex ]] 3885 local index=$((_ble_edit_ind+${#BASH_REMATCH})) 3886 if [[ $flag ]]; then 3887 # :help word-motions の特別規則 (通過した最後の単語が行末にあるとき) 3888 local rematch1=${BASH_REMATCH[1]} 3889 if local rex="$n$b*\$"; [[ $rematch1 =~ $rex ]]; then 3890 local suffix_len=${#BASH_REMATCH} 3891 ((suffix_len<${#rematch1})) && 3892 ((index-=suffix_len)) 3893 fi 3894 fi 3895 ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg" 3896 } 3897 function ble/widget/vi-command/forward-word-end.impl { 3898 local arg=$1 flag=$2 reg=$3 rex_word=$4 opts=$5 3899 local IFS=$_ble_term_IFS 3900 local rex="^([$IFS]*($rex_word)?){0,$arg}" # 単語末端に止まる。空行には止まらない 3901 local offset=1; [[ :$opts: == *:allow_here:* ]] && offset=0 3902 [[ ${_ble_edit_str:_ble_edit_ind+offset} =~ $rex ]] 3903 local index=$((_ble_edit_ind+offset+${#BASH_REMATCH}-1)) 3904 ((index<_ble_edit_ind&&(index=_ble_edit_ind))) 3905 [[ ! $flag && $BASH_REMATCH && ${_ble_edit_str:index:1} == [$IFS] ]] && ble/widget/.bell 3906 ble/widget/vi-command/inclusive-goto.impl "$index" "$flag" "$reg" 3907 } 3908 function ble/widget/vi-command/backward-word.impl { 3909 local arg=$1 flag=$2 reg=$3 rex_word=$4 3910 local b=$'[ \t]' n=$'\n' 3911 local rex="((($rex_word)$n?|$b+$n?|$n)($b+$n)*$b*){0,$arg}\$" # 単語先頭または空行に止まる 3912 [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]] 3913 local index=$((_ble_edit_ind-${#BASH_REMATCH})) 3914 ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg" 3915 } 3916 function ble/widget/vi-command/backward-word-end.impl { 3917 local arg=$1 flag=$2 reg=$3 rex_word=$4 3918 local i=$'[ \t\n]' b=$'[ \t]' n=$'\n' w="($rex_word)" 3919 local rex1="(^|$w$n?|$n)($b+$n)*$b*" 3920 local rex="($rex1)($rex1){$((arg-1))}($rex_word|$i)\$" # 単語末端または空行に止まる 3921 [[ ${_ble_edit_str::_ble_edit_ind+1} =~ $rex ]] 3922 local index=$((_ble_edit_ind+1-${#BASH_REMATCH})) 3923 local rematch3=${BASH_REMATCH[3]} # 最初の ($rex_word) 3924 [[ $rematch3 ]] && ((index+=${#rematch3}-1)) 3925 ble/widget/vi-command/inclusive-goto.impl "$index" "$flag" "$reg" 3926 } 3927 3928 # motion w 3929 function ble/widget/vi-command/forward-vword { 3930 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3931 ble/widget/vi-command/forward-word.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD" 3932 } 3933 # motion e 3934 function ble/widget/vi-command/forward-vword-end { 3935 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3936 ble/widget/vi-command/forward-word-end.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD" 3937 } 3938 # motion b 3939 function ble/widget/vi-command/backward-vword { 3940 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3941 ble/widget/vi-command/backward-word.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD" 3942 } 3943 # motion ge 3944 function ble/widget/vi-command/backward-vword-end { 3945 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3946 ble/widget/vi-command/backward-word-end.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD" 3947 } 3948 # motion W 3949 function ble/widget/vi-command/forward-uword { 3950 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3951 ble/widget/vi-command/forward-word.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+' 3952 } 3953 # motion E 3954 function ble/widget/vi-command/forward-uword-end { 3955 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3956 ble/widget/vi-command/forward-word-end.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+' 3957 } 3958 # motion B 3959 function ble/widget/vi-command/backward-uword { 3960 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3961 ble/widget/vi-command/backward-word.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+' 3962 } 3963 # motion gE 3964 function ble/widget/vi-command/backward-uword-end { 3965 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3966 ble/widget/vi-command/backward-word-end.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+' 3967 } 3968 3969 #------------------------------------------------------------------------------ 3970 # command: [cdy]?[|HL] G gg 3971 3972 # nmap | 3973 function ble/widget/vi-command/nth-column { 3974 local ARG FLAG REG; ble/keymap:vi/get-arg 1 3975 3976 local ret index 3977 ble-edit/content/find-logical-bol; local bol=$ret 3978 ble-edit/content/find-logical-eol; local eol=$ret 3979 if ble/edit/use-textmap; then 3980 local bx by; ble/textmap#getxy.cur --prefix=b "$bol" # Note: 先頭行はプロンプトにより bx!=0 3981 local ex ey; ble/textmap#getxy.cur --prefix=e "$eol" 3982 local dstx=$((bx+ARG-1)) dsty=$by cols=${COLUMNS:-80} 3983 ((dsty+=dstx/cols,dstx%=cols)) 3984 ((dsty>ey&&(dsty=ey,dstx=ex))) 3985 ble/textmap#get-index-at "$dstx" "$dsty" # local variable "index" is set here 3986 3987 # Note: 何故かノーマルモードで d や c を実行するときには行末に行かないのに、 3988 # ビジュアルモードでは行末に行くことができるようだ。 3989 [[ $_ble_decode_keymap != vi_[xs]map ]] && 3990 ble-edit/content/nonbol-eolp "$index" && ((index--)) 3991 else 3992 [[ $_ble_decode_keymap != vi_[xs]map ]] && 3993 ble-edit/content/nonbol-eolp "$eol" && ((eol--)) 3994 ((index=bol+ARG-1,index>eol&&(index=eol))) 3995 fi 3996 3997 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell 3998 } 3999 4000 # nmap H 4001 function ble/widget/vi-command/nth-line { 4002 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4003 [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # `` 4004 ble/widget/vi-command/linewise-goto.impl "0:$((ARG-1))" "$FLAG" "$REG" 4005 } 4006 # nmap L 4007 function ble/widget/vi-command/nth-last-line { 4008 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4009 [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # `` 4010 ble/widget/vi-command/linewise-goto.impl "${#_ble_edit_str}:$((-(ARG-1)))" "$FLAG" "$REG" 4011 } 4012 4013 # nmap gg in history 4014 function ble/widget/vi-command/history-beginning { 4015 local ARG FLAG REG; ble/keymap:vi/get-arg 0 4016 if [[ $FLAG ]]; then 4017 if ((ARG)); then 4018 _ble_keymap_vi_oparg=$ARG 4019 else 4020 _ble_keymap_vi_oparg= 4021 fi 4022 _ble_keymap_vi_opfunc=$FLAG 4023 _ble_keymap_vi_reg=$REG 4024 ble/widget/vi-command/nth-line 4025 return "$?" 4026 fi 4027 4028 if ((ARG)); then 4029 ble-edit/history/goto "$((ARG-1))" 4030 else 4031 ble/widget/history-beginning 4032 fi 4033 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 4034 ble/keymap:vi/adjust-command-mode 4035 return 0 4036 } 4037 4038 # nmap G in history 4039 function ble/widget/vi-command/history-end { 4040 local ARG FLAG REG; ble/keymap:vi/get-arg 0 4041 if [[ $FLAG ]]; then 4042 _ble_keymap_vi_opfunc=$FLAG 4043 _ble_keymap_vi_reg=$REG 4044 if ((ARG)); then 4045 _ble_keymap_vi_oparg=$ARG 4046 ble/widget/vi-command/nth-line 4047 else 4048 _ble_keymap_vi_oparg= 4049 ble/widget/vi-command/nth-last-line 4050 fi 4051 return "$?" 4052 fi 4053 4054 if ((ARG)); then 4055 ble-edit/history/goto "$((ARG-1))" 4056 else 4057 ble/widget/history-end 4058 fi 4059 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 4060 ble/keymap:vi/adjust-command-mode 4061 return 0 4062 } 4063 4064 # nmap G 4065 # Note: vim では G はこの振る舞いだが、blesh では実際には 4066 # vi-command/history-end が束縛されるのでこれは既定では使われない。 4067 function ble/widget/vi-command/last-line { 4068 local ARG FLAG REG; ble/keymap:vi/get-arg 0 4069 [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # `` 4070 if ((ARG)); then 4071 ble/widget/vi-command/linewise-goto.impl "0:$((ARG-1))" "$FLAG" "$REG" 4072 else 4073 ble/widget/vi-command/linewise-goto.impl "${#_ble_edit_str}:0" "$FLAG" "$REG" 4074 fi 4075 } 4076 4077 # nmap C-home / gg 4078 # Note: nth-line (H) との違いは jump でない事のみである。 4079 # Note: vim では gg もこの振る舞いだが、blesh では gg は 4080 # 既定では vi-command/history-beginning に束縛される。 4081 function ble/widget/vi-command/first-nol { 4082 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4083 ble/widget/vi-command/linewise-goto.impl "0:$((ARG-1))" "$FLAG" "$REG" 4084 } 4085 4086 # nmap C-end 4087 function ble/widget/vi-command/last-eol { 4088 local ARG FLAG REG; ble/keymap:vi/get-arg '' 4089 local ret index 4090 if [[ $ARG ]]; then 4091 ble-edit/content/find-logical-eol 0 "$((ARG-1))"; index=$ret 4092 else 4093 ble-edit/content/find-logical-eol "${#_ble_edit_str}"; index=$ret 4094 fi 4095 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 4096 ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell 4097 } 4098 4099 #------------------------------------------------------------------------------ 4100 # command: r gr 4101 4102 ## @fn ble/widget/vi_nmap/replace-char.impl code [overwrite_mode] 4103 ## @param[in] overwrite_mode 4104 ## 置換する文字の挿入方法を指定します。 4105 function ble/widget/vi_nmap/replace-char.impl { 4106 local key=$1 overwrite_mode=${2:-R} 4107 _ble_edit_overwrite_mode= 4108 4109 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4110 local ret 4111 if ((key==(_ble_decode_Ctrl|91))); then # C-[ 4112 ble/keymap:vi/adjust-command-mode 4113 return 27 4114 elif ! ble/keymap:vi/k2c "$key"; then 4115 ble/widget/vi-command/bell 4116 return 1 4117 fi 4118 4119 local pos=$_ble_edit_ind 4120 4121 ble/keymap:vi/mark/start-edit-area 4122 { 4123 local -a KEYS; KEYS=("$ret") 4124 local _ble_edit_arg=$ARG 4125 local _ble_edit_overwrite_mode=$overwrite_mode 4126 local ble_widget_self_insert_opts=nolineext 4127 ble/widget/self-insert 4128 ble/util/unlocal KEYS 4129 } 4130 ble/keymap:vi/mark/end-edit-area 4131 ble/keymap:vi/repeat/record 4132 4133 ((pos<_ble_edit_ind&&_ble_edit_ind--)) 4134 ble/keymap:vi/adjust-command-mode 4135 return 0 4136 } 4137 4138 function ble/widget/vi_nmap/replace-char.hook { 4139 ble/widget/vi_nmap/replace-char.impl "$1" R 4140 } 4141 function ble/widget/vi_nmap/replace-char { 4142 _ble_edit_overwrite_mode=R 4143 ble/keymap:vi/async-read-char ble/widget/vi_nmap/replace-char.hook 4144 } 4145 function ble/widget/vi_nmap/virtual-replace-char.hook { 4146 ble/widget/vi_nmap/replace-char.impl "$1" 1 4147 } 4148 function ble/widget/vi_nmap/virtual-replace-char { 4149 _ble_edit_overwrite_mode=1 4150 ble/keymap:vi/async-read-char ble/widget/vi_nmap/virtual-replace-char.hook 4151 } 4152 4153 #------------------------------------------------------------------------------ 4154 # command: J gJ o O 4155 4156 # nmap J 4157 function ble/widget/vi_nmap/connect-line-with-space { 4158 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4159 local ret 4160 ble-edit/content/find-logical-eol; local eol1=$ret 4161 ble-edit/content/find-logical-eol "$_ble_edit_ind" "$((ARG<=1?1:ARG-1))"; local eol2=$ret 4162 ble-edit/content/find-logical-bol "$eol2"; local bol2=$ret 4163 if ((eol1<eol2)); then 4164 local text=${_ble_edit_str:eol1:eol2-eol1} 4165 text=${text//$'\n'/' '} 4166 ble/widget/.replace-range "$eol1" "$eol2" "$text" 4167 ble/keymap:vi/mark/set-previous-edit-area "$eol1" "$eol2" 4168 ble/keymap:vi/repeat/record 4169 _ble_edit_ind=$((bol2-1)) 4170 ble/keymap:vi/adjust-command-mode 4171 return 0 4172 else 4173 ble/widget/vi-command/bell 4174 return 1 4175 fi 4176 } 4177 # nmap gJ 4178 function ble/widget/vi_nmap/connect-line { 4179 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4180 local ret 4181 ble-edit/content/find-logical-eol; local eol1=$ret 4182 ble-edit/content/find-logical-eol "$_ble_edit_ind" "$((ARG<=1?1:ARG-1))"; local eol2=$ret 4183 ble-edit/content/find-logical-bol "$eol2"; local bol2=$ret 4184 if ((eol1<eol2)); then 4185 local text=${_ble_edit_str:eol1:bol2-eol1} 4186 text=${text//$'\n'} 4187 ble/widget/.replace-range "$eol1" "$bol2" "$text" 4188 local delta=$((${#text}-(bol2-eol1))) 4189 ble/keymap:vi/mark/set-previous-edit-area "$eol1" "$((eol2+delta))" 4190 ble/keymap:vi/repeat/record 4191 _ble_edit_ind=$((bol2+delta)) 4192 ble/keymap:vi/adjust-command-mode 4193 return 0 4194 else 4195 ble/widget/vi-command/bell 4196 return 1 4197 fi 4198 } 4199 4200 function ble/widget/vi_nmap/insert-mode-at-forward-line { 4201 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4202 local ret 4203 ble-edit/content/find-logical-bol; local bol=$ret 4204 ble-edit/content/find-logical-eol; local eol=$ret 4205 ble-edit/content/find-non-space "$bol"; local indent=${_ble_edit_str:bol:ret-bol} 4206 _ble_edit_ind=$eol 4207 ble/widget/.insert-string $'\n'"$indent" 4208 ble/widget/vi_nmap/.insert-mode "$ARG" 4209 ble/keymap:vi/repeat/record 4210 return 0 4211 } 4212 function ble/widget/vi_nmap/insert-mode-at-backward-line { 4213 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4214 local ret 4215 ble-edit/content/find-logical-bol; local bol=$ret 4216 ble-edit/content/find-non-space "$bol"; local indent=${_ble_edit_str:bol:ret-bol} 4217 _ble_edit_ind=$bol 4218 ble/widget/.insert-string "$indent"$'\n' 4219 _ble_edit_ind=$((bol+${#indent})) 4220 ble/widget/vi_nmap/.insert-mode "$ARG" 4221 ble/keymap:vi/repeat/record 4222 return 0 4223 } 4224 4225 #------------------------------------------------------------------------------ 4226 # command: f F t F 4227 4228 4229 ## @var _ble_keymap_vi_char_search 4230 ## 前回の ble/widget/vi-command/search-char.impl/core の検索を記録します。 4231 _ble_keymap_vi_char_search= 4232 4233 ## @fn ble/widget/vi-command/search-char.impl/core opts key|char 4234 ## 4235 ## @param[in] opts 4236 ## 以下のフラグ文字から構成される文字列です。 4237 ## 4238 ## b 後方検索であることを表します。 4239 ## 4240 ## p 見つかった文字の1つ手前に移動することを表します。 4241 ## 4242 ## r 繰り返し検索であることを表します。 4243 ## このとき第1引数は文字 char と解釈されます。 4244 ## これ以外のとき第1引数はキーコード key と解釈されます。 4245 ## 4246 ## @param[in] key 4247 ## @param[in] char 4248 ## key は検索対象のキーコードを指定します。 4249 ## char は検索対象の文字を指定します。 4250 ## どちらで解釈されるかは後述する opts のフラグ r に依存します。 4251 ## 4252 ## 4253 function ble/widget/vi-command/search-char.impl/core { 4254 local opts=$1 key=$2 4255 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4256 4257 local ret c 4258 [[ $opts != *p* ]]; local isprev=$? 4259 [[ $opts != *r* ]]; local isrepeat=$? 4260 if ((isrepeat)); then 4261 c=$key 4262 elif ((key==(_ble_decode_Ctrl|91))); then # C-[ -> cancel 4263 return 27 4264 else 4265 ble/keymap:vi/k2c "$key" || return 1 4266 ble/util/c2s "$ret"; local c=$ret 4267 fi 4268 [[ $c ]] || return 1 4269 4270 ((isrepeat)) || _ble_keymap_vi_char_search=$c$opts 4271 4272 local index 4273 if [[ $opts == *b* ]]; then 4274 # backward search 4275 ble-edit/content/find-logical-bol; local bol=$ret 4276 local base=$_ble_edit_ind 4277 ((isrepeat&&isprev&&base--,base>bol)) || return 1 4278 local line=${_ble_edit_str:bol:base-bol} 4279 ble/string#last-index-of "$line" "$c" "$ARG" 4280 ((ret>=0)) || return 1 4281 4282 ((index=bol+ret,isprev&&index++)) 4283 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell 4284 return "$?" 4285 else 4286 # forward search 4287 ble-edit/content/find-logical-eol; local eol=$ret 4288 local base=$((_ble_edit_ind+1)) 4289 ((isrepeat&&isprev&&base++,base<eol)) || return 1 4290 4291 local line=${_ble_edit_str:base:eol-base} 4292 ble/string#index-of "$line" "$c" "$ARG" 4293 ((ret>=0)) || return 1 4294 4295 ((index=base+ret,isprev&&index--)) 4296 ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell 4297 return "$?" 4298 fi 4299 } 4300 function ble/widget/vi-command/search-char.impl { 4301 if ble/widget/vi-command/search-char.impl/core "$1" "$2"; then 4302 ble/keymap:vi/adjust-command-mode 4303 return 0 4304 else 4305 ble/widget/vi-command/bell 4306 return 1 4307 fi 4308 } 4309 4310 function ble/widget/vi-command/search-forward-char { 4311 ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl f 4312 } 4313 function ble/widget/vi-command/search-forward-char-prev { 4314 ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl fp 4315 } 4316 function ble/widget/vi-command/search-backward-char { 4317 ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl b 4318 } 4319 function ble/widget/vi-command/search-backward-char-prev { 4320 ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl bp 4321 } 4322 function ble/widget/vi-command/search-char-repeat { 4323 [[ $_ble_keymap_vi_char_search ]] || ble/widget/.bell 4324 local c=${_ble_keymap_vi_char_search::1} opts=${_ble_keymap_vi_char_search:1} 4325 ble/widget/vi-command/search-char.impl "r$opts" "$c" 4326 } 4327 function ble/widget/vi-command/search-char-reverse-repeat { 4328 [[ $_ble_keymap_vi_char_search ]] || ble/widget/.bell 4329 local c=${_ble_keymap_vi_char_search::1} opts=${_ble_keymap_vi_char_search:1} 4330 if [[ $opts == *b* ]]; then 4331 opts=f${opts//b} 4332 else 4333 opts=b${opts//f} 4334 fi 4335 ble/widget/vi-command/search-char.impl "r$opts" "$c" 4336 } 4337 4338 #------------------------------------------------------------------------------ 4339 # command: % 4340 4341 ## @fn ble/widget/vi-command/search-matchpair/.search-forward 4342 ## @var[in] _ble_edit_str, ch1, ch2, index 4343 ## @var[out] ret 4344 function ble/widget/vi-command/search-matchpair/.search-forward { 4345 ble/string#index-of-chars "$_ble_edit_str" "$ch1$ch2" "$((index+1))" 4346 } 4347 function ble/widget/vi-command/search-matchpair/.search-backward { 4348 ble/string#last-index-of-chars "$_ble_edit_str" "$ch1$ch2" "$index" 4349 } 4350 4351 function ble/widget/vi-command/search-matchpair-or { 4352 local ARG FLAG REG; ble/keymap:vi/get-arg -1 4353 if ((ARG>=0)); then 4354 _ble_keymap_vi_oparg=$ARG 4355 _ble_keymap_vi_opfunc=$FLAG 4356 _ble_keymap_vi_reg=$REG 4357 ble/widget/"$@" 4358 return "$?" 4359 fi 4360 4361 local open='({[' close=')}]' 4362 4363 local ret 4364 ble-edit/content/find-logical-eol; local eol=$ret 4365 if ! ble/string#index-of-chars "${_ble_edit_str::eol}" '(){}[]' "$_ble_edit_ind"; then 4366 ble/keymap:vi/adjust-command-mode 4367 return 1 4368 fi 4369 local index1=$ret ch1=${_ble_edit_str:ret:1} 4370 4371 if [[ $ch1 == ["$open"] ]]; then 4372 local i=${open%%"$ch"*}; i=${#i} 4373 local ch2=${close:i:1} 4374 local searcher=ble/widget/vi-command/search-matchpair/.search-forward 4375 else 4376 local i=${close%%"$ch"*}; i=${#i} 4377 local ch2=${open:i:1} 4378 local searcher=ble/widget/vi-command/search-matchpair/.search-backward 4379 fi 4380 4381 local index=$index1 count=1 4382 while "$searcher"; do 4383 index=$ret 4384 if [[ ${_ble_edit_str:ret:1} == "$ch1" ]]; then 4385 ((++count)) 4386 else 4387 ((--count==0)) && break 4388 fi 4389 done 4390 4391 if ((count)); then 4392 ble/keymap:vi/adjust-command-mode 4393 return 1 4394 fi 4395 4396 [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # `` 4397 ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell 4398 } 4399 4400 function ble/widget/vi-command/percentage-line { 4401 local ARG FLAG REG; ble/keymap:vi/get-arg 0 4402 local ret; ble/string#count-char "$_ble_edit_str" $'\n'; local nline=$((ret+1)) 4403 local iline=$(((ARG*nline+99)/100)) 4404 ble/widget/vi-command/linewise-goto.impl "0:$((iline-1))" "$FLAG" "$REG" 4405 } 4406 4407 #------------------------------------------------------------------------------ 4408 # command: go 4409 4410 function ble/widget/vi-command/nth-byte { 4411 local ARG FLAG REG; ble/keymap:vi/get-arg 1 4412 ((ARG--)) 4413 local offset=0 text=$_ble_edit_str len=${#_ble_edit_str} 4414 local left nleft ret 4415 while ((ARG>0&&len>1)); do 4416 left=${text::len/2} 4417 ble/util/strlen "$left"; nleft=$ret 4418 if ((ARG<nleft)); then 4419 text=$left 4420 ((len/=2)) 4421 else 4422 text=${text:len/2} 4423 ((offset+=len/2, 4424 ARG-=nleft, 4425 len-=len/2)) 4426 fi 4427 done 4428 ble/keymap:vi/needs-eol-fix "$offset" && ((offset--)) 4429 ble/widget/vi-command/exclusive-goto.impl "$offset" "$FLAG" "$REG" nobell 4430 } 4431 4432 #------------------------------------------------------------------------------ 4433 # text objects 4434 4435 _ble_keymap_vi_text_object= 4436 4437 ## @fn ble/keymap:vi/text-object/word.impl arg flag reg type 4438 ## @fn ble/keymap:vi/text-object/quote.impl arg flag reg type 4439 ## @fn ble/keymap:vi/text-object/block.impl arg flag reg type 4440 ## @fn ble/keymap:vi/text-object/tag.impl arg flag reg type 4441 ## @fn ble/keymap:vi/text-object/sentence.impl arg flag reg type 4442 ## @fn ble/keymap:vi/text-object/paragraph.impl arg flag reg type 4443 ## 4444 ## @exit テキストオブジェクトの処理が完了したときに 0 を返します。 4445 ## 4446 4447 4448 ## @fn ble/keymap:vi/text-object/word.extend-forward 4449 ## Note #D0855 4450 ## @var[in] type arg 4451 ## @var[in] rex_word nl space ifs 4452 ## @var[in,out] beg end 4453 ## @var[out] flags 4454 ## A 先頭に空白が含まれる事を表す。 4455 ## Z 末尾に空白が含まれる事を表す。 4456 ## I 単語前半の取り込みが試みられた事を表す。 4457 function ble/keymap:vi/text-object/word.extend-forward { 4458 local rex 4459 4460 flags= 4461 [[ ${_ble_edit_str:beg:1} == ["$ifs"] ]] && flags=${flags}A 4462 if [[ $_ble_decode_keymap != vi_[xs]map ]]; then 4463 flags=${flags}I 4464 elif ((_ble_edit_mark==_ble_edit_ind)); then 4465 flags=${flags}I 4466 fi 4467 4468 local rex_unit 4469 local W='('$rex_word')' b='['$space']' n=$nl 4470 if [[ $type == i* ]]; then 4471 rex_unit='^'$W'|^'$b'+|^'$n 4472 elif [[ $type == a* ]]; then 4473 rex_unit='^'$W$b'*|^'$b'+'$W'|^'$b'*'$n'('$b'+'$n')*('$n'|'$b'*'$W')' 4474 else 4475 return 1 4476 fi 4477 4478 local i rematch= 4479 for ((i=0;i<arg;i++)); do 4480 if ((i==0)) && [[ $flags == *I* ]]; then 4481 # 単語前方を取り込む 4482 rex='('$rex_word')$|['$space']*['$ifs']$' 4483 [[ ${_ble_edit_str::beg+1} =~ $rex ]] && 4484 ((beg-=${#BASH_REMATCH}-1,end=beg)) 4485 else 4486 [[ ${_ble_edit_str:end:1} == $'\n' ]] && ((end++)) 4487 fi 4488 4489 [[ ${_ble_edit_str:end} =~ $rex_unit ]] || return 1 4490 rematch=$BASH_REMATCH 4491 ((end+=${#rematch})) 4492 4493 # Note: aw に対する正規表現では二重改行を読むが後退する。 4494 [[ $type == a* && $rematch == *$'\n\n' ]] && ((end--)) 4495 4496 # Note: Vim では何故か最初の一致だけ改行を除去。 4497 # 最後の一致の改行は exclusive にする事で、 4498 # 呼び出し元に除去させている様な気がする。 4499 # Note: aw の時は "非空白から改行" に一致する事はない。 4500 if ((i==0)) && [[ $flags == *I* ]] || ((i==arg-1)); then 4501 [[ $type == i* && $rematch == *"$nl" ]] && ((end--)) 4502 fi 4503 done 4504 4505 [[ ${_ble_edit_str:end-1:1} == *["$ifs"] ]] && flags=${flags}Z 4506 4507 if [[ $type == a* && $flags != *[AZ]* ]]; then 4508 # aw で前後に空白が含まれない時、前方の空白を取り込む 4509 # Note: vim の実装 (search.c (current_word)) では 4510 # 行頭 exclusive でも前方空白を取り込むが、 4511 # aw において行頭 exclusive になる事は普通はないので謎。 4512 # virtual_active() の時行の途中で oneleft() が失敗する事はあるが、 4513 # この様な状況を意図してこの条件が加えられたとは思えない。 4514 if rex='['$space']+$'; [[ ${_ble_edit_str::beg} =~ $rex ]]; then 4515 local p=$((beg-${#BASH_REMATCH})) 4516 ble-edit/content/bolp "$p" || beg=$p 4517 fi 4518 fi 4519 4520 return 0 4521 } 4522 ## @fn ble/keymap:vi/text-object/word.extend-backward 4523 ## Note #D0855 4524 ## @var[in,out] beg 4525 ## @var[in] type arg 4526 ## @var[in] rex_word nl space ifs 4527 function ble/keymap:vi/text-object/word.extend-backward { 4528 local rex_unit= 4529 local W='('$rex_word')' b='['$space']' n=$nl 4530 if [[ $type == i* ]]; then 4531 rex_unit='('$W'|'$b'+)'$n'?$|'$n'$' 4532 elif [[ $type == a* ]]; then 4533 rex_unit=$b'*'$W$n'?$|'$W'?'$b'*('$n'('$b'+'$n')*'$b'*)?('$b$n'?|'$n')$' 4534 else 4535 return 1 4536 fi 4537 4538 local count=$arg 4539 while ((count--)); do 4540 [[ ${_ble_edit_str::beg} =~ $rex_unit ]] || return 1 4541 ((beg-=${#BASH_REMATCH})) 4542 4543 # Note: vim の振る舞いに倣って 4544 local match=${BASH_REMATCH%"$nl"} 4545 if ((beg==0&&${#match}>=2)); then 4546 if [[ $type == i* ]]; then 4547 [[ $match == ["$space"]* ]] && beg=1 4548 elif [[ $type == a* ]]; then 4549 [[ $match == *[!"$ifs"] ]] && beg=1 4550 fi 4551 fi 4552 done 4553 4554 return 0 4555 } 4556 4557 function ble/keymap:vi/text-object/word.impl { 4558 local arg=$1 flag=$2 reg=$3 type=$4 4559 local space=$' \t' nl=$'\n' ifs=$_ble_term_IFS 4560 ((arg==0)) && return 0 4561 4562 local rex_word 4563 if [[ $type == ?W ]]; then 4564 rex_word="[^$ifs]+" 4565 else 4566 rex_word=$_ble_keymap_vi_REX_WORD 4567 fi 4568 4569 local index=$_ble_edit_ind 4570 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 4571 if ((index<_ble_edit_mark)); then 4572 local beg=$index 4573 if ble/keymap:vi/text-object/word.extend-backward; then 4574 _ble_edit_ind=$beg 4575 else 4576 _ble_edit_ind=0 4577 ble/widget/.bell 4578 fi 4579 ble/keymap:vi/adjust-command-mode 4580 return 0 4581 fi 4582 fi 4583 4584 local beg=$index end=$index flags= 4585 if ! ble/keymap:vi/text-object/word.extend-forward; then 4586 # 一致失敗 4587 index=${#_ble_edit_str} 4588 ble-edit/content/nonbol-eolp "$index" && ((index--)) 4589 _ble_edit_ind=$index 4590 ble/widget/vi-command/bell 4591 return 1 4592 fi 4593 4594 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 4595 ((end--)) 4596 ble-edit/content/nonbol-eolp "$end" && ((end--)) 4597 ((beg<_ble_edit_mark)) && _ble_edit_mark=$beg 4598 [[ $_ble_edit_mark_active == vi_line ]] && 4599 _ble_edit_mark_active=vi_char 4600 _ble_edit_ind=$end 4601 ble/keymap:vi/adjust-command-mode 4602 return 0 4603 else 4604 ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg" 4605 fi 4606 } 4607 4608 ## @fn ble/keymap:vi/text-object:quote/.next [index] 4609 ## @var[out] ret 4610 function ble/keymap:vi/text-object:quote/.next { 4611 local index=${1:-$((_ble_edit_ind+1))} nl=$'\n' 4612 local rex="^[^$nl$quote]*$quote" 4613 [[ ${_ble_edit_str:index} =~ $rex ]] || return 1 4614 ((ret=index+${#BASH_REMATCH}-1)) 4615 return 0 4616 } 4617 ## @fn ble/keymap:vi/text-object:quote/.prev [index] 4618 ## @var[out] ret 4619 function ble/keymap:vi/text-object:quote/.prev { 4620 local index=${1:-_ble_edit_ind} nl=$'\n' 4621 local rex="$quote[^$nl$quote]*\$" 4622 [[ ${_ble_edit_str::index} =~ $rex ]] || return 1 4623 ((ret=index-${#BASH_REMATCH})) 4624 return 0 4625 } 4626 function ble/keymap:vi/text-object/quote.impl { 4627 local arg=$1 flag=$2 reg=$3 type=$4 4628 local ret quote=${type:1} 4629 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 4630 if ble/keymap:vi/text-object:quote/.xmap; then 4631 ble/keymap:vi/adjust-command-mode 4632 return 0 4633 else 4634 ble/widget/vi-command/bell 4635 return 1 4636 fi 4637 fi 4638 4639 local beg= end= 4640 if [[ ${_ble_edit_str:_ble_edit_ind:1} == "$quote" ]]; then 4641 ble-edit/content/find-logical-bol; local bol=$ret 4642 ble/string#count-char "${_ble_edit_str:bol:_ble_edit_ind-bol}" "$quote" 4643 if ((ret%2==1)); then 4644 # 現在終了引用符 4645 ((end=_ble_edit_ind+1)) 4646 ble/keymap:vi/text-object:quote/.prev && beg=$ret 4647 else 4648 ((beg=_ble_edit_ind)) 4649 ble/keymap:vi/text-object:quote/.next && end=$((ret+1)) 4650 fi 4651 elif ble/keymap:vi/text-object:quote/.prev && beg=$ret; then 4652 ble/keymap:vi/text-object:quote/.next && end=$((ret+1)) 4653 elif ble/keymap:vi/text-object:quote/.next && beg=$ret; then 4654 ble/keymap:vi/text-object:quote/.next "$((beg+1))" && end=$((ret+1)) 4655 fi 4656 4657 if [[ $beg && $end ]]; then 4658 [[ $type == i* || arg -gt 1 ]] && ((beg++,end--)) 4659 ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg" 4660 else 4661 ble/widget/vi-command/bell 4662 return 1 4663 fi 4664 } 4665 ## @fn ble/keymap:vi/text-object:quote/.expand-xmap-range mode 4666 ## @param[in] mode 4667 ## @var[in,out] beg 4668 ## @var[in,out] end 4669 function ble/keymap:vi/text-object:quote/.expand-xmap-range { 4670 local inclusive=$1 4671 ((end++)) 4672 if ((inclusive==2)); then 4673 local rex 4674 rex=$'^[ \t]+'; [[ ${_ble_edit_str:end} =~ $rex ]] && ((end+=${#BASH_REMATCH})) 4675 elif ((inclusive==0&&end-beg>2)); then 4676 ((beg++,end--)) 4677 fi 4678 } 4679 function ble/keymap:vi/text-object:quote/.xmap { 4680 # 複数行に亘る場合は失敗 4681 local min=$_ble_edit_ind max=$_ble_edit_mark 4682 ((min>max)) && local min=$max max=$min 4683 [[ ${_ble_edit_str:min:max+1-min} == *$'\n'* ]] && return 1 4684 4685 local inclusive=0 4686 if [[ $type == a* ]]; then 4687 inclusive=2 4688 elif ((arg>1)); then 4689 inclusive=1 4690 fi 4691 4692 local ret 4693 if ((_ble_edit_ind==_ble_edit_mark)); then 4694 ble/keymap:vi/text-object:quote/.prev "$((_ble_edit_ind+1))" || 4695 ble/keymap:vi/text-object:quote/.next "$((_ble_edit_ind+1))" || return 1 4696 local beg=$ret 4697 ble/keymap:vi/text-object:quote/.next "$((beg+1))" || return 1 4698 local end=$ret 4699 4700 ble/keymap:vi/text-object:quote/.expand-xmap-range "$inclusive" 4701 _ble_edit_mark=$beg 4702 _ble_edit_ind=$((end-1)) 4703 return 0 4704 elif ((_ble_edit_ind>_ble_edit_mark)); then 4705 local updates_mark= 4706 if [[ ${_ble_edit_str:_ble_edit_ind:1} == "$quote" ]]; then 4707 # 現在位置に " があるとき。 4708 ble/keymap:vi/text-object:quote/.next "$((_ble_edit_ind+1))" || return 1; local beg=$ret 4709 if ble/keymap:vi/text-object:quote/.next "$((beg+1))"; then 4710 local end=$ret 4711 else 4712 local end=$beg beg=$_ble_edit_ind 4713 fi 4714 else 4715 # 現在位置以降の最初の 右" (その行の偶数番目の ") と対応する 左" 4716 ble-edit/content/find-logical-bol; local bol=$ret 4717 ble/string#count-char "${_ble_edit_str:bol:_ble_edit_ind-bol}" "$quote" 4718 if ((ret%2==0)); then 4719 ble/keymap:vi/text-object:quote/.next "$((_ble_edit_ind+1))" || return 1; local beg=$ret 4720 ble/keymap:vi/text-object:quote/.next "$((beg+1))" || return 1; local end=$ret 4721 else 4722 ble/keymap:vi/text-object:quote/.prev "$_ble_edit_ind" || return 1; local beg=$ret 4723 ble/keymap:vi/text-object:quote/.next "$((_ble_edit_ind+1))" || return 1; local end=$ret 4724 fi 4725 local i1=$((_ble_edit_mark?_ble_edit_mark-1:0)) 4726 [[ ${_ble_edit_str:i1:_ble_edit_ind-i1} != *"$quote"* ]] && updates_mark=1 4727 fi 4728 4729 ble/keymap:vi/text-object:quote/.expand-xmap-range "$inclusive" 4730 [[ $updates_mark ]] && _ble_edit_mark=$beg 4731 _ble_edit_ind=$((end-1)) 4732 return 0 4733 else 4734 ble-edit/content/find-logical-bol; local bol=$ret nl=$'\n' 4735 local rex="^([^$nl$quote]*$quote[^$nl$quote]*$quote)*[^$nl$quote]*$quote" 4736 [[ ${_ble_edit_str:bol:_ble_edit_ind-bol} =~ $rex ]] || return 1 4737 local beg=$((bol+${#BASH_REMATCH}-1)) 4738 ble/keymap:vi/text-object:quote/.next "$((beg+1))" || return 1 4739 local end=$ret 4740 4741 ble/keymap:vi/text-object:quote/.expand-xmap-range "$inclusive" 4742 [[ ${_ble_edit_str:_ble_edit_ind:_ble_edit_mark+2-_ble_edit_ind} != *"$quote"* ]] && _ble_edit_mark=$((end-1)) 4743 _ble_edit_ind=$beg 4744 return 0 4745 fi 4746 } 4747 4748 function ble/keymap:vi/text-object/block.impl { 4749 local arg=$1 flag=$2 reg=$3 type=$4 4750 local ret paren=${type:1} lparen=${type:1:1} rparen=${type:2:1} 4751 local axis=$_ble_edit_ind 4752 [[ ${_ble_edit_str:axis:1} == "$lparen" ]] && ((axis++)) 4753 4754 local count=$arg beg=$axis 4755 while ble/string#last-index-of-chars "$_ble_edit_str" "$paren" "$beg"; do 4756 beg=$ret 4757 if [[ ${_ble_edit_str:beg:1} == "$lparen" ]]; then 4758 ((--count==0)) && break 4759 else 4760 ((++count)) 4761 fi 4762 done 4763 if ((count)); then 4764 ble/widget/vi-command/bell 4765 return 1 4766 fi 4767 4768 local count=$arg end=$axis 4769 while ble/string#index-of-chars "$_ble_edit_str" "$paren" "$end"; do 4770 end=$((ret+1)) 4771 if [[ ${_ble_edit_str:end-1:1} == "$rparen" ]]; then 4772 ((--count==0)) && break 4773 else 4774 ((++count)) 4775 fi 4776 done 4777 if ((count)); then 4778 ble/widget/vi-command/bell 4779 return 1 4780 fi 4781 4782 local linewise= 4783 if [[ $type == *i* ]]; then 4784 ((beg++,end--)) 4785 [[ ${_ble_edit_str:beg:1} == $'\n' ]] && ((beg++)) 4786 ((beg<end)) && ble-edit/content/bolp "$end" && ((end--)) 4787 ((beg<end)) && ble-edit/content/bolp "$beg" && ble-edit/content/eolp "$end" && linewise=1 4788 fi 4789 4790 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 4791 _ble_edit_mark=$beg 4792 ble/widget/vi-command/exclusive-goto.impl "$end" 4793 elif [[ $linewise ]]; then 4794 ble/widget/vi-command/linewise-range.impl "$beg" "$end" "$flag" "$reg" goto_bol 4795 else 4796 ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg" 4797 fi 4798 } 4799 4800 ## @fn ble/keymap:vi/text-object:tag/.find-end-tag 4801 ## @var[in] beg 4802 ## @var[out] end 4803 function ble/keymap:vi/text-object:tag/.find-end-tag { 4804 local ifs=$_ble_term_IFS ret rex 4805 4806 rex="^<([^$ifs/>!]+)"; [[ ${_ble_edit_str:beg} =~ $rex ]] || return 1 4807 ble/string#escape-for-extended-regex "${BASH_REMATCH[1]}"; local tagname=$ret 4808 rex="^</?$tagname([$ifs]+([^>]*[^/])?)?>" 4809 4810 end=$beg 4811 local count=0 4812 while ble/string#index-of-chars "$_ble_edit_str" '<' "$end" && end=$((ret+1)); do 4813 [[ ${_ble_edit_str:end-1} =~ $rex ]] || continue 4814 ((end+=${#BASH_REMATCH}-1)) 4815 4816 if [[ ${BASH_REMATCH::2} == '</' ]]; then 4817 ((--count==0)) && return 0 4818 else 4819 ((++count)) 4820 fi 4821 done 4822 return 1 4823 } 4824 function ble/keymap:vi/text-object/tag.impl { 4825 local arg=$1 flag=$2 reg=$3 type=$4 4826 local ret rex 4827 4828 local pivot=$_ble_edit_ind ret=$_ble_edit_ind 4829 if [[ ${_ble_edit_str:ret:1} == '<' ]] || ble/string#last-index-of-chars "${_ble_edit_str::_ble_edit_ind}" '<>'; then 4830 if rex='^<[^/][^>]*>' && [[ ${_ble_edit_str:ret} =~ $rex ]]; then 4831 ((pivot=ret+${#BASH_REMATCH})) 4832 else 4833 ((pivot=ret+1)) 4834 fi 4835 fi 4836 4837 local ifs=$_ble_term_IFS 4838 4839 local beg=$pivot count=$arg 4840 rex="<([^$ifs/>!]+([$ifs]+([^>]*[^/])?)?|/[^>]*)>\$" 4841 while ble/string#last-index-of-chars "${_ble_edit_str::beg}" '>' && beg=$ret; do 4842 [[ ${_ble_edit_str::beg+1} =~ $rex ]] || continue 4843 ((beg-=${#BASH_REMATCH}-1)) 4844 4845 if [[ ${BASH_REMATCH::2} == '</' ]]; then 4846 ((++count)) 4847 else 4848 if ((--count==0)); then 4849 if ble/keymap:vi/text-object:tag/.find-end-tag "$beg" && ((_ble_edit_ind<end)); then 4850 break 4851 else 4852 ((count++)) 4853 fi 4854 fi 4855 fi 4856 done 4857 if ((count)); then 4858 ble/widget/vi-command/bell 4859 return 1 4860 fi 4861 4862 if [[ $type == i* ]]; then 4863 rex='^<[^>]*>'; [[ ${_ble_edit_str:beg:end-beg} =~ $rex ]] && ((beg+=${#BASH_REMATCH})) 4864 rex='<[^>]*>$'; [[ ${_ble_edit_str:beg:end-beg} =~ $rex ]] && ((end-=${#BASH_REMATCH})) 4865 fi 4866 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 4867 _ble_edit_mark=$beg 4868 ble/widget/vi-command/exclusive-goto.impl "$end" 4869 else 4870 ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg" 4871 fi 4872 } 4873 4874 ## @fn ble/keymap:vi/text-object:sentence/.beg 4875 ## @var[out] beg 4876 ## @var[out] is_interval 4877 ## @var[in] lf, ht 4878 function ble/keymap:vi/text-object:sentence/.beg { 4879 beg= is_interval= 4880 local pivot=$_ble_edit_ind rex= 4881 if ble-edit/content/bolp && ble-edit/content/eolp; then 4882 if rex=$'^\n+[^\n]'; [[ ${_ble_edit_str:pivot} =~ $rex ]]; then 4883 # 前方に非空白が見つかればその手前の行を開始点とする 4884 beg=$((pivot+${#BASH_REMATCH}-2)) 4885 else 4886 # 前の非空行末を基点に取り直す 4887 if rex=$'\n+$'; [[ ${_ble_edit_str::pivot} =~ $rex ]]; then 4888 ((pivot-=${#BASH_REMATCH})) 4889 fi 4890 fi 4891 fi 4892 if [[ ! $beg ]]; then 4893 rex="^.*((^$lf?|$lf$lf)([ $ht]*)|[.!?][])'\"]*([ $ht$lf]+))" 4894 if [[ ${_ble_edit_str::pivot+1} =~ $rex ]]; then 4895 beg=${#BASH_REMATCH} 4896 if ((pivot<beg)); then 4897 # pivot < beg は beg == pivot + 1 (終端まで一致) を意味する。 4898 # この時点で pivot は必ず非空行または先頭行にいるので /\n\n/ に一致することはない。 4899 local rematch34=${BASH_REMATCH[3]}${BASH_REMATCH[4]} 4900 if [[ $rematch34 ]]; then 4901 # /(^\n\s+|\n\n\s+|[.!?]\s+)$/ 4902 beg=$((pivot+1-${#rematch34})) is_interval=1 4903 else 4904 # /^\n$/ 4905 beg=$pivot 4906 fi 4907 fi 4908 else 4909 beg=0 4910 fi 4911 fi 4912 } 4913 ## @fn ble/keymap:vi/text-object:sentence/.next { 4914 ## @var[in,out] end 4915 ## @var[in,out] is_interval 4916 ## @var[in] lf, ht 4917 function ble/keymap:vi/text-object:sentence/.next { 4918 if [[ $is_interval ]]; then 4919 is_interval= 4920 local rex=$'[ \t]*((\n[ \t]+)*\n[ \t]*)?' 4921 [[ ${_ble_edit_str:end} =~ $rex ]] 4922 local index=$((end+${#BASH_REMATCH})) 4923 ((end<index)) && [[ ${_ble_edit_str:index-1:1} == $'\n' ]] && ((index--)) 4924 ((end=index)) 4925 else 4926 is_interval=1 4927 if local rex=$'^\n+'; [[ ${_ble_edit_str:end} =~ $rex ]]; then 4928 # 連続する LF を読み切る 4929 ((end+=${#BASH_REMATCH})) 4930 elif rex="(([.!?][])\"']*)[ $ht$lf]|$lf$lf).*\$"; [[ ${_ble_edit_str:end} =~ $rex ]]; then 4931 # 文を次の文末記号まで 4932 local rematch2=${BASH_REMATCH[2]} 4933 end=$((${#_ble_edit_str}-${#BASH_REMATCH}+${#rematch2})) 4934 else 4935 # 最後の文 4936 local index=${#_ble_edit_str} 4937 ((end<index)) && [[ ${_ble_edit_str:index-1:1} == $'\n' ]] && ((index--)) 4938 ((end=index)) 4939 fi 4940 fi 4941 } 4942 function ble/keymap:vi/text-object/sentence.impl { 4943 local arg=$1 flag=$2 reg=$3 type=$4 4944 local lf=$'\n' ht=$'\t' 4945 local rex 4946 4947 local beg is_interval 4948 ble/keymap:vi/text-object:sentence/.beg 4949 4950 local end=$beg i n=$arg 4951 [[ $type != i* ]] && ((n*=2)) 4952 for ((i=0;i<n;i++)); do 4953 ble/keymap:vi/text-object:sentence/.next 4954 done 4955 ((beg<end)) && [[ ${_ble_edit_str:end-1:1} == $'\n' ]] && ((end--)) 4956 4957 # at は後方 (forward) に空白を確保できなければ前方 (backward) に空白を確保する。 4958 if [[ $type != i* && ! $is_interval ]]; then 4959 local ifs=$_ble_term_IFS 4960 if ((end)) && [[ ${_ble_edit_str:end-1:1} != ["$ifs"] ]]; then 4961 rex="^.*(^$lf$lf|[.!?][])'\"]*([ $ht$lf]))([ $ht$lf]*)\$" 4962 if [[ ${_ble_edit_str::beg} =~ $rex ]]; then 4963 local rematch2=${BASH_REMATCH[2]} 4964 local rematch3=${BASH_REMATCH[3]} 4965 ((beg-=${#rematch2}+${#rematch3})) 4966 [[ ${_ble_edit_str:beg:1} == $'\n' ]] && ((beg++)) 4967 fi 4968 fi 4969 fi 4970 4971 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 4972 _ble_edit_mark=$beg 4973 ble/widget/vi-command/exclusive-goto.impl "$end" 4974 elif ble-edit/content/bolp "$beg" && [[ ${_ble_edit_str:end:1} == $'\n' ]]; then 4975 # 行頭から LF の手前までのときに linewise になる。 4976 # _ble_edit_str の末端までのときは linewise ではないことに注意する。 4977 ble/widget/vi-command/linewise-range.impl "$beg" "$end" "$flag" "$reg" goto_bol 4978 else 4979 ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg" 4980 fi 4981 } 4982 4983 function ble/keymap:vi/text-object/paragraph.impl { 4984 local arg=$1 flag=$2 reg=$3 type=$4 4985 local rex ret 4986 4987 local beg= empty_start= 4988 ble-edit/content/find-logical-bol; local bol=$ret 4989 ble-edit/content/find-non-space "$bol"; local nol=$ret 4990 if rex=$'[ \t]*(\n|$)' ble-edit/content/eolp "$nol"; then 4991 # 空行のときは連続する一番初めの空行に移動する 4992 empty_start=1 4993 rex=$'(^|\n)([ \t]*\n)*$' 4994 [[ ${_ble_edit_str::bol} =~ $rex ]] 4995 local rematch1=${BASH_REMATCH[1]} # Note: for bash-3.1 ${#arr[n]} bug 4996 ((beg=bol-(${#BASH_REMATCH}-${#rematch1}))) 4997 else 4998 # 非空行のときは最初の非空行の先頭まで移動する。 4999 if rex=$'^(.*\n)?[ \t]*\n'; [[ ${_ble_edit_str::bol} =~ $rex ]]; then 5000 ((beg=${#BASH_REMATCH})) 5001 else 5002 ((beg=0)) 5003 fi 5004 fi 5005 5006 local end=$beg 5007 local rex_empty_line=$'([ \t]*\n|[ \t]+$)' rex_paragraph_line=$'([ \t]*[^ \t\n][^\n]*(\n|$))' 5008 if [[ $type == i* ]]; then 5009 rex="$rex_empty_line+|$rex_paragraph_line+" 5010 elif [[ $empty_start ]]; then 5011 rex="$rex_empty_line*$rex_paragraph_line+" 5012 else 5013 rex="$rex_paragraph_line+$rex_empty_line*" 5014 fi 5015 local i 5016 for ((i=0;i<arg;i++)); do 5017 if [[ ${_ble_edit_str:end} =~ $rex ]]; then 5018 ((end+=${#BASH_REMATCH})) 5019 else 5020 # paragraph の場合は次が見つからない場合はエラー 5021 ble/widget/vi-command/bell 5022 return 1 5023 fi 5024 done 5025 5026 # at で後続の空行がなければ backward の空行を取り入れる 5027 if [[ $type != i* && ! $empty_start ]]; then 5028 if rex=$'(^|\n)[ \t]*\n$'; ! [[ ${_ble_edit_str::end} =~ $rex ]]; then 5029 if rex=$'(^|\n)([ \t]*\n)*$'; [[ ${_ble_edit_str::beg} =~ $rex ]]; then 5030 local rematch1=${BASH_REMATCH[1]} 5031 ((beg-=${#BASH_REMATCH}-${#rematch1})) 5032 fi 5033 fi 5034 fi 5035 ((beg<end)) && [[ ${_ble_edit_str:end-1:1} == $'\n' ]] && ((end--)) 5036 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 5037 _ble_edit_mark=$beg 5038 ble/widget/vi-command/exclusive-goto.impl "$end" 5039 else 5040 ble/widget/vi-command/linewise-range.impl "$beg" "$end" "$flag" "$reg" 5041 fi 5042 } 5043 5044 ## @fn ble/keymap:vi/text-object.impl 5045 ## 5046 ## @exit テキストオブジェクトの処理が完了したときに 0 を返します。 5047 ## 5048 function ble/keymap:vi/text-object.impl { 5049 local arg=$1 flag=$2 reg=$3 type=$4 5050 case $type in 5051 ([ia][wW]) ble/keymap:vi/text-object/word.impl "$arg" "$flag" "$reg" "$type" ;; 5052 ([ia][\"\'\`]) ble/keymap:vi/text-object/quote.impl "$arg" "$flag" "$reg" "$type" ;; 5053 ([ia]['b()']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}()" ;; 5054 ([ia]['B{}']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}{}" ;; 5055 ([ia]['<>']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}<>" ;; 5056 ([ia]['][']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}[]" ;; 5057 ([ia]t) ble/keymap:vi/text-object/tag.impl "$arg" "$flag" "$reg" "$type" ;; 5058 ([ia]s) ble/keymap:vi/text-object/sentence.impl "$arg" "$flag" "$reg" "$type" ;; 5059 ([ia]p) ble/keymap:vi/text-object/paragraph.impl "$arg" "$flag" "$reg" "$type" ;; 5060 (*) 5061 ble/widget/vi-command/bell 5062 return 1;; 5063 esac 5064 } 5065 5066 function ble/keymap:vi/text-object.hook { 5067 local key=$1 5068 local ARG FLAG REG; ble/keymap:vi/get-arg 1 5069 if ! ble-decode-key/ischar "$key"; then 5070 ble/widget/vi-command/bell 5071 return 1 5072 fi 5073 5074 local ret; ble/util/c2s "$key" 5075 local type=$_ble_keymap_vi_text_object$ret 5076 ble/keymap:vi/text-object.impl "$ARG" "$FLAG" "$REG" "$type" 5077 return 0 5078 } 5079 5080 function ble/keymap:vi/.check-text-object { 5081 local n=${#KEYS[@]}; ((n&&n--)) 5082 ble-decode-key/ischar "${KEYS[n]}" || return 1 5083 5084 local ret; ble/util/c2s "${KEYS[n]}"; local c=$ret 5085 [[ $c == [ia] ]] || return 1 5086 5087 [[ $_ble_keymap_vi_opfunc || $_ble_decode_keymap == vi_[xs]map ]] || return 1 5088 5089 _ble_keymap_vi_text_object=$c 5090 _ble_decode_key__hook=ble/keymap:vi/text-object.hook 5091 return 0 5092 } 5093 5094 function ble/widget/vi-command/text-object { 5095 ble/keymap:vi/.check-text-object && return 0 5096 ble/widget/vi-command/bell 5097 return 1 5098 } 5099 5100 #------------------------------------------------------------------------------ 5101 # Command 5102 # 5103 # map: :cmd 5104 5105 # 既定の cmap 履歴 5106 _ble_keymap_vi_commandline_history=() 5107 _ble_keymap_vi_commandline_history_edit=() 5108 _ble_keymap_vi_commandline_history_dirt=() 5109 _ble_keymap_vi_commandline_history_index=0 5110 5111 ## @arr _ble_keymap_vi_cmap_is_cancel_key 5112 ## コマンドラインが空の時にキャンセルに使うキーの辞書です。 5113 _ble_keymap_vi_cmap_is_cancel_key[63|_ble_decode_Ctrl]=1 # C-? 5114 _ble_keymap_vi_cmap_is_cancel_key[127]=1 # DEL 5115 _ble_keymap_vi_cmap_is_cancel_key[104|_ble_decode_Ctrl]=1 # C-h 5116 _ble_keymap_vi_cmap_is_cancel_key[8]=1 # BS 5117 function ble/keymap:vi/commandline/before-command.hook { 5118 if [[ ! $_ble_edit_str ]] && ((_ble_keymap_vi_cmap_is_cancel_key[KEYS[0]])); then 5119 ble/widget/vi_cmap/cancel 5120 ble/decode/widget/suppress-widget 5121 fi 5122 } 5123 5124 function ble/widget/vi-command/commandline { 5125 ble/keymap:vi/clear-arg 5126 ble/keymap:vi/async-commandline-mode ble/widget/vi-command/commandline.hook 5127 _ble_edit_PS1=: 5128 ble/history/set-prefix _ble_keymap_vi_commandline 5129 _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook 5130 return 147 5131 } 5132 function ble/widget/vi-command/commandline.hook { 5133 local command 5134 ble/string#split-words command "$1" 5135 local cmd="ble/widget/vi-command:${command[0]}" 5136 if ble/is-function "$cmd"; then 5137 "$cmd" "${command[@]:1}"; local ext=$? 5138 else 5139 ble/widget/vi-command/bell "unknown command $1"; local ext=1 5140 fi 5141 [[ $1 ]] && _ble_keymap_vi_register[58]=/$result # ": 5142 return "$ext" 5143 } 5144 5145 function ble/widget/vi-command:w { 5146 local file= 5147 if [[ $1 ]]; then 5148 ble/builtin/history -a "$1" 5149 file=$1 5150 elif [[ ${HISTFILE-} ]]; then 5151 ble/builtin/history -a 5152 file=$HISTFILE 5153 else 5154 ble/widget/vi-command/bell 'w: the history filename is empty or not specified' 5155 return 1 5156 fi 5157 local wc 5158 ble/util/assign-words wc 'ble/bin/wc "$file"' 5159 ble/edit/info/show text "\"$file\" ${wc[0]}L, ${wc[2]}C written" 5160 ble/keymap:vi/adjust-command-mode 5161 return 0 5162 } 5163 function ble/widget/vi-command:q! { 5164 ble/widget/exit force 5165 return 1 5166 } 5167 function ble/widget/vi-command:q { 5168 ble/widget/exit 5169 ble/keymap:vi/adjust-command-mode # ジョブがあるときは終了しないので。 5170 return 1 5171 } 5172 function ble/widget/vi-command:wq { 5173 ble/widget/vi-command:w "$@" 5174 ble/widget/exit 5175 ble/keymap:vi/adjust-command-mode 5176 return 1 5177 } 5178 5179 #------------------------------------------------------------------------------ 5180 # Search 5181 # 5182 # map: / ? n N 5183 5184 _ble_keymap_vi_search_obackward= 5185 _ble_keymap_vi_search_ohistory= 5186 _ble_keymap_vi_search_needle= 5187 _ble_keymap_vi_search_activate= 5188 _ble_keymap_vi_search_matched= 5189 5190 _ble_keymap_vi_search_history=() 5191 _ble_keymap_vi_search_history_edit=() 5192 _ble_keymap_vi_search_history_dirt=() 5193 _ble_keymap_vi_search_history_index=0 5194 5195 ## @bleopt keymap_vi_search_match_current 5196 ## 非空の文字列が設定されている時 /, ?, n, N で 5197 ## 現在のカーソルの下にある単語に一致します。 5198 ## 既定値は空文字列で vim の振る舞いに倣います。 5199 bleopt/declare -v keymap_vi_search_match_current '' 5200 5201 function ble/highlight/layer:region/mark:vi_search/get-selection { 5202 ble/highlight/layer:region/mark:vi_char/get-selection 5203 } 5204 function ble/keymap:vi/search/matched { 5205 [[ $_ble_keymap_vi_search_matched || $_ble_edit_mark_active == vi_search || $_ble_keymap_vi_search_activate ]] 5206 } 5207 function ble/keymap:vi/search/clear-matched { 5208 _ble_keymap_vi_search_activate= 5209 _ble_keymap_vi_search_matched= 5210 [[ $_ble_edit_mark_active == vi_search ]] && _ble_edit_mark_active= 5211 } 5212 ## @fn ble/keymap:vi/search/invoke-search needle 5213 ## 5214 ## @param[in] needle 5215 ## 検索パターンを表す正規表現を指定する。 5216 ## 5217 ## @var[out] beg end 5218 ## 一致範囲を返す。 5219 ## 5220 ## @exit 5221 ## 一致が見つかった場合に正常終了 0。それ以外の時は 0 以外の値を返す。 5222 ## 5223 ## @var[in] opt_optional_next 5224 ## 現在位置より後または前の一致を検索する。 5225 ## vi_omap で呼び出した時、現在位置で一致した時に設定される。 5226 ## keymap_vi_search_match_current が非空の時はここには来ない。 5227 ## 5228 ## @var[in] opt_locate 5229 ## 現在位置に一致可能な検索を行う。 5230 ## 履歴を遡って検索して一致する履歴項目が見つかった時、 5231 ## その履歴項目内で最初に見つかったものを特定する為に使われる。 5232 ## 5233 ## @var[in] opt_backward 5234 ## 検索方向を指定する。 5235 ## 5236 function ble/keymap:vi/search/invoke-search { 5237 local needle=$1 5238 local dir=+; ((opt_backward)) && dir=B 5239 local ind=$_ble_edit_ind 5240 5241 # 検索開始位置 5242 if ((opt_optional_next)); then 5243 if ((!opt_backward)); then 5244 ((_ble_edit_ind<${#_ble_edit_str}&&_ble_edit_ind++)) 5245 fi 5246 elif ((opt_locate)) || ! ble/keymap:vi/search/matched; then 5247 # 何にも一致していない状態から 5248 if ((opt_locate)) || [[ $bleopt_keymap_vi_search_match_current ]]; then 5249 # 現在位置に一致可能 5250 # 前方検索: @hello → @hello (そのまま) 5251 # 後方検索: hell@o → hello@ (ずらす) 5252 if ((opt_backward)); then 5253 ble-edit/content/eolp || ((_ble_edit_ind++)) 5254 fi 5255 else 5256 # 現在位置には一致させない 5257 # 前方検索: @hello → h@ello (ずらす) 5258 # 後方検索: hell@o → hell@o (そのまま) 5259 if ((!opt_backward)); then 5260 ble-edit/content/eolp || ((_ble_edit_ind++)) 5261 fi 5262 fi 5263 else 5264 # _ble_edit_ind .. _ble_edit_mark[+1] に一致しているとき 5265 if ((!opt_backward)); then 5266 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 5267 # vi_xmap, vi_smap では _ble_edit_mark は別の用途に使われていて 5268 # 終端点の情報が失われているので再度一致を試みる。 5269 if ble-edit/isearch/search "$@" && ((beg==_ble_edit_ind)); then 5270 _ble_edit_ind=$end 5271 else 5272 ((_ble_edit_ind<${#_ble_edit_str}&&_ble_edit_ind++)) 5273 fi 5274 else 5275 ((_ble_edit_ind=_ble_edit_mark)) 5276 ble-edit/content/eolp || ((_ble_edit_ind++)) 5277 fi 5278 else 5279 # 2回目以降の一致では opts=- で検索する。 5280 dir=- 5281 fi 5282 fi 5283 5284 ble-edit/isearch/search "$needle" "$dir":regex; local ret=$? 5285 _ble_edit_ind=$ind 5286 return "$ret" 5287 } 5288 5289 ## @fn ble/widget/vi-command/search.core 5290 ## 5291 ## @var[in] needle 5292 ## @var[in] opt_backward 5293 ## @var[in] opt_history 5294 ## @var[in] opt_locate 5295 ## @var[in] start 5296 ## @var[in] ntask 5297 ## 5298 function ble/widget/vi-command/search.core { 5299 local beg= end= is_empty_match= 5300 if ble/keymap:vi/search/invoke-search "$needle"; then 5301 if ((beg<end)); then 5302 ble-edit/content/bolp "$end" || ((end--)) 5303 _ble_edit_ind=$beg # eol 補正は search.impl 側で最後に行う 5304 [[ $_ble_decode_keymap != vi_[xs]map ]] && _ble_edit_mark=$end 5305 _ble_keymap_vi_search_activate=vi_search 5306 return 0 5307 else 5308 # vim では空一致は即座に失敗のようだ。 5309 # 続きを検索するということはしない。 5310 opt_history= 5311 is_empty_match=1 5312 fi 5313 fi 5314 5315 if ((opt_history)) && [[ $_ble_history_load_done || opt_backward -ne 0 ]]; then 5316 ble/history/initialize 5317 local index; ble/history/get-index 5318 [[ $start ]] || start=$index 5319 if ((opt_backward)); then 5320 ((index--)) 5321 else 5322 ((index++)) 5323 fi 5324 5325 local _ble_edit_isearch_dir=+; ((opt_backward)) && _ble_edit_isearch_dir=- 5326 local _ble_edit_isearch_str=$needle 5327 local isearch_ntask=$ntask 5328 local isearch_time=0 5329 local isearch_progress_callback=ble-edit/isearch/.show-status-with-progress.fib 5330 if ((opt_backward)); then 5331 ble/history/isearch-backward-blockwise regex:progress 5332 else 5333 ble/history/isearch-forward regex:progress 5334 fi; local r=$? 5335 ble/edit/info/default 5336 5337 if ((r==0)); then 5338 local new_index; ble/history/get-index -v new_index 5339 [[ $index != "$new_index" ]] && 5340 ble-edit/history/goto "$index" 5341 if ((opt_backward)); then 5342 local i=${#_ble_edit_str} 5343 ble/keymap:vi/needs-eol-fix "$i" && ((i--)) 5344 _ble_edit_ind=$i 5345 else 5346 _ble_edit_ind=0 5347 fi 5348 5349 opt_locate=1 opt_history=0 ble/widget/vi-command/search.core 5350 return "$?" 5351 fi 5352 fi 5353 5354 if ((!opt_optional_next)); then 5355 if [[ $is_empty_match ]]; then 5356 ble/widget/.bell "search: empty match" 5357 else 5358 ble/widget/.bell "search: not found" 5359 fi 5360 if [[ $_ble_edit_mark_active == vi_search ]]; then 5361 _ble_keymap_vi_search_activate=vi_search 5362 fi 5363 fi 5364 return 1 5365 } 5366 function ble/widget/vi-command/search.impl { 5367 local ARG FLAG REG; ble/keymap:vi/get-arg 1 5368 5369 local opts=$1 needle=$2 5370 [[ :$opts: != *:repeat:* ]]; local opt_repeat=$? # 再検索 n N 5371 [[ :$opts: != *:history:* ]]; local opt_history=$? # 履歴検索が有効か 5372 [[ :$opts: != *:-:* ]]; local opt_backward=$? # 逆方向 5373 local opt_locate=0 5374 local opt_optional_next=0 5375 if ((opt_repeat)); then 5376 # n N 5377 if [[ $_ble_keymap_vi_search_needle ]]; then 5378 needle=$_ble_keymap_vi_search_needle 5379 ((opt_backward^=_ble_keymap_vi_search_obackward, 5380 opt_history=_ble_keymap_vi_search_ohistory)) 5381 else 5382 ble/widget/vi-command/bell 'no previous search' 5383 return 1 5384 fi 5385 else 5386 # / ? * # 5387 ble/keymap:vi/search/clear-matched 5388 if [[ $needle ]]; then 5389 _ble_keymap_vi_search_needle=$needle 5390 _ble_keymap_vi_search_obackward=$opt_backward 5391 _ble_keymap_vi_search_ohistory=$opt_history 5392 elif [[ $_ble_keymap_vi_search_needle ]]; then 5393 needle=$_ble_keymap_vi_search_needle 5394 _ble_keymap_vi_search_obackward=$opt_backward 5395 _ble_keymap_vi_search_ohistory=$opt_history 5396 else 5397 ble/widget/vi-command/bell 'no previous search' 5398 return 1 5399 fi 5400 fi 5401 5402 local original_ind=$_ble_edit_ind 5403 if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then 5404 opt_history=0 5405 else 5406 local old_hindex; ble/history/get-index -v old_hindex 5407 fi 5408 5409 local start= # 初めの履歴番号。search.core 内で最初に履歴を読み込んだあとで設定される。 5410 local ntask=$ARG 5411 while ((ntask)); do 5412 ble/widget/vi-command/search.core || break 5413 ((ntask--)) 5414 done 5415 5416 if [[ $FLAG ]]; then 5417 if ((ntask)); then 5418 # 検索対象が見つからなかったとき 5419 _ble_keymap_vi_search_activate= 5420 _ble_edit_ind=$original_ind 5421 ble/keymap:vi/adjust-command-mode 5422 return 1 5423 else 5424 # 見つかったとき 5425 if ((_ble_edit_ind==original_index)); then 5426 # 範囲が空のときは次の一致場所まで。 5427 # 次の一致場所がないとき (自分自身のとき) は空領域になる。 5428 opt_optional_next=1 ble/widget/vi-command/search.core 5429 fi 5430 local index=$_ble_edit_ind 5431 5432 _ble_keymap_vi_search_activate= 5433 _ble_edit_ind=$original_ind 5434 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell 5435 fi 5436 else 5437 if ((ntask<ARG)); then 5438 # 同じ履歴項目内でのジャンプ 5439 if ((opt_history)); then 5440 local new_hindex; ble/history/get-index -v new_hindex 5441 ((new_hindex==old_hindex)) 5442 fi && ble/keymap:vi/mark/set-local-mark 96 "$original_index" # `` 5443 5444 # 行末補正 5445 if ble/keymap:vi/needs-eol-fix; then 5446 if ((!opt_backward&&_ble_edit_ind<_ble_edit_mark)); then 5447 ((_ble_edit_ind++)) 5448 else 5449 ((_ble_edit_ind--)) 5450 fi 5451 fi 5452 fi 5453 ble/keymap:vi/adjust-command-mode 5454 return 0 5455 fi 5456 } 5457 function ble/widget/vi-command/search-forward { 5458 ble/keymap:vi/async-commandline-mode 'ble/widget/vi-command/search.impl +:history' 5459 _ble_edit_PS1='/' 5460 ble/history/set-prefix _ble_keymap_vi_search 5461 _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook 5462 return 147 5463 } 5464 function ble/widget/vi-command/search-backward { 5465 ble/keymap:vi/async-commandline-mode 'ble/widget/vi-command/search.impl -:history' 5466 _ble_edit_PS1='?' 5467 ble/history/set-prefix _ble_keymap_vi_search 5468 _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook 5469 return 147 5470 } 5471 function ble/widget/vi-command/search-repeat { 5472 ble/widget/vi-command/search.impl repeat:+ 5473 } 5474 function ble/widget/vi-command/search-reverse-repeat { 5475 ble/widget/vi-command/search.impl repeat:- 5476 } 5477 5478 function ble/widget/vi-command/search-word.impl { 5479 local opts=$1 5480 local rex=$'^([^[:alnum:]_\n]*)([[:alnum:]_]*)' 5481 if ! [[ ${_ble_edit_str:_ble_edit_ind} =~ $rex ]]; then 5482 ble/keymap:vi/clear-arg 5483 ble/widget/vi-command/bell 'word is not found' 5484 return 1 5485 fi 5486 5487 local end=$((_ble_edit_ind+${#BASH_REMATCH})) 5488 local word=${BASH_REMATCH[2]} 5489 if [[ ! ${BASH_REMATCH[1]} ]]; then 5490 rex=$'[[:alnum:]_]+$' 5491 [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]] && 5492 word=$BASH_REMATCH$word 5493 fi 5494 5495 # Note: Bash 正規表現は <regex.h> を用いるので、 5496 # 必ずしも非 POSIX ERE \<\> に対応しているとは限らない。 5497 # また [[:alnum:]_] と符合しているかも分からない。 5498 # 従って適用できるか確認してから境界に一致することを要求する。 5499 local needle=$word 5500 rex='\<'$needle; [[ $word =~ $rex ]] && needle=$rex 5501 rex=$needle'\>'; [[ $word =~ $rex ]] && needle=$rex 5502 5503 if [[ $opts == backward ]]; then 5504 ble/widget/vi-command/search.impl -:history "$needle" 5505 else 5506 local original_ind=$_ble_edit_ind 5507 _ble_edit_ind=$((end-1)) 5508 ble/widget/vi-command/search.impl +:history "$needle" && return 0 5509 _ble_edit_ind=$original_ind 5510 return 1 5511 fi 5512 } 5513 # nmap * 5514 function ble/widget/vi-command/search-word-forward { 5515 ble/widget/vi-command/search-word.impl forward 5516 } 5517 # nmap # 5518 function ble/widget/vi-command/search-word-backward { 5519 ble/widget/vi-command/search-word.impl backward 5520 } 5521 5522 #------------------------------------------------------------------------------ 5523 # command-help 5524 5525 # nmap K 5526 function ble/widget/vi_nmap/command-help { 5527 ble/keymap:vi/clear-arg 5528 ble/widget/command-help; local ext=$? 5529 ble/keymap:vi/adjust-command-mode 5530 return "$ext" 5531 } 5532 function ble/widget/vi_xmap/command-help.core { 5533 ble/keymap:vi/clear-arg 5534 local get_selection=ble/highlight/layer:region/mark:$_ble_edit_mark_active/get-selection 5535 ble/is-function "$get_selection" || return 1 5536 5537 local selection 5538 "$get_selection" || return 1 5539 ((${#selection[*]}==2)) || return 1 5540 5541 local comp_cword=0 comp_line=$_ble_edit_str comp_point=$_ble_edit_ind 5542 local -a comp_words; comp_words=("$cmd") 5543 local cmd=${_ble_edit_str:selection[0]:selection[1]-selection[0]} 5544 ble/widget/command-help.impl "$cmd"; local ext=$? 5545 ble/keymap:vi/adjust-command-mode 5546 return "$ext" 5547 } 5548 function ble/widget/vi_xmap/command-help { 5549 if ! ble/widget/vi_xmap/command-help.core; then 5550 ble/widget/vi-command/bell 5551 return 1 5552 fi 5553 } 5554 5555 #------------------------------------------------------------------------------ 5556 5557 ## @fn ble/keymap:vi/set-up-command-map 5558 ## @var[in] ble_bind_keymap 5559 function ble/keymap:vi/set-up-command-map { 5560 ble-bind -f 0 vi-command/append-arg 5561 ble-bind -f 1 vi-command/append-arg 5562 ble-bind -f 2 vi-command/append-arg 5563 ble-bind -f 3 vi-command/append-arg 5564 ble-bind -f 4 vi-command/append-arg 5565 ble-bind -f 5 vi-command/append-arg 5566 ble-bind -f 6 vi-command/append-arg 5567 ble-bind -f 7 vi-command/append-arg 5568 ble-bind -f 8 vi-command/append-arg 5569 ble-bind -f 9 vi-command/append-arg 5570 ble-bind -f y 'vi-command/operator y' 5571 ble-bind -f d 'vi-command/operator d' 5572 ble-bind -f c 'vi-command/operator c' 5573 ble-bind -f '<' 'vi-command/operator indent-left' 5574 ble-bind -f '>' 'vi-command/operator indent-right' 5575 ble-bind -f '!' 'vi-command/operator filter' 5576 ble-bind -f 'g ~' 'vi-command/operator toggle_case' 5577 ble-bind -f 'g u' 'vi-command/operator u' 5578 ble-bind -f 'g U' 'vi-command/operator U' 5579 ble-bind -f 'g ?' 'vi-command/operator rot13' 5580 ble-bind -f 'g q' 'vi-command/operator fold' 5581 ble-bind -f 'g w' 'vi-command/operator fold-preserve-point' 5582 ble-bind -f 'g @' 'vi-command/operator map' 5583 # ble-bind -f '=' 'vi-command/operator =' # インデント (equalprg, ep) 5584 # ble-bind -f 'z f' 'vi-command/operator f' 5585 5586 ble-bind -f paste_begin vi-command/bracketed-paste 5587 5588 ble-bind -f 'home' vi-command/beginning-of-line 5589 ble-bind -f '$' vi-command/forward-eol 5590 ble-bind -f 'end' vi-command/forward-eol 5591 ble-bind -f '^' vi-command/first-non-space 5592 ble-bind -f '_' vi-command/first-non-space-forward 5593 ble-bind -f '+' vi-command/forward-first-non-space 5594 ble-bind -f 'C-m' vi-command/forward-first-non-space 5595 ble-bind -f 'RET' vi-command/forward-first-non-space 5596 ble-bind -f '-' vi-command/backward-first-non-space 5597 ble-bind -f 'g 0' vi-command/beginning-of-graphical-line 5598 ble-bind -f 'g home' vi-command/beginning-of-graphical-line 5599 ble-bind -f 'g ^' vi-command/graphical-first-non-space 5600 ble-bind -f 'g $' vi-command/graphical-forward-eol 5601 ble-bind -f 'g end' vi-command/graphical-forward-eol 5602 ble-bind -f 'g m' vi-command/middle-of-graphical-line 5603 ble-bind -f 'g _' vi-command/last-non-space 5604 5605 ble-bind -f h vi-command/backward-char 5606 ble-bind -f l vi-command/forward-char 5607 ble-bind -f left vi-command/backward-char 5608 ble-bind -f right vi-command/forward-char 5609 ble-bind -f 'C-?' 'vi-command/backward-char wrap' 5610 ble-bind -f 'DEL' 'vi-command/backward-char wrap' 5611 ble-bind -f 'C-h' 'vi-command/backward-char wrap' 5612 ble-bind -f 'BS' 'vi-command/backward-char wrap' 5613 ble-bind -f SP 'vi-command/forward-char wrap' 5614 5615 ble-bind -f j vi-command/forward-line 5616 ble-bind -f down vi-command/forward-line 5617 ble-bind -f C-n vi-command/forward-line 5618 ble-bind -f C-j vi-command/forward-line 5619 ble-bind -f k vi-command/backward-line 5620 ble-bind -f up vi-command/backward-line 5621 ble-bind -f C-p vi-command/backward-line 5622 ble-bind -f 'g j' vi-command/graphical-forward-line 5623 ble-bind -f 'g down' vi-command/graphical-forward-line 5624 ble-bind -f 'g k' vi-command/graphical-backward-line 5625 ble-bind -f 'g up' vi-command/graphical-backward-line 5626 5627 ble-bind -f w vi-command/forward-vword 5628 ble-bind -f W vi-command/forward-uword 5629 ble-bind -f b vi-command/backward-vword 5630 ble-bind -f B vi-command/backward-uword 5631 ble-bind -f e vi-command/forward-vword-end 5632 ble-bind -f E vi-command/forward-uword-end 5633 ble-bind -f 'g e' vi-command/backward-vword-end 5634 ble-bind -f 'g E' vi-command/backward-uword-end 5635 ble-bind -f C-right vi-command/forward-vword 5636 ble-bind -f S-right vi-command/forward-vword 5637 ble-bind -f C-left vi-command/backward-vword 5638 ble-bind -f S-left vi-command/backward-vword 5639 5640 ble-bind -f 'g o' vi-command/nth-byte 5641 ble-bind -f '|' vi-command/nth-column 5642 ble-bind -f H vi-command/nth-line 5643 ble-bind -f L vi-command/nth-last-line 5644 ble-bind -f 'g g' vi-command/history-beginning 5645 ble-bind -f G vi-command/history-end 5646 ble-bind -f C-home vi-command/first-nol 5647 ble-bind -f C-end vi-command/last-eol 5648 5649 ble-bind -f 'f' vi-command/search-forward-char 5650 ble-bind -f 'F' vi-command/search-backward-char 5651 ble-bind -f 't' vi-command/search-forward-char-prev 5652 ble-bind -f 'T' vi-command/search-backward-char-prev 5653 ble-bind -f ';' vi-command/search-char-repeat 5654 ble-bind -f ',' vi-command/search-char-reverse-repeat 5655 5656 ble-bind -f '%' 'vi-command/search-matchpair-or vi-command/percentage-line' 5657 5658 ble-bind -f 'C-\ C-n' nop 5659 5660 ble-bind -f ':' vi-command/commandline 5661 ble-bind -f '/' vi-command/search-forward 5662 ble-bind -f '?' vi-command/search-backward 5663 ble-bind -f 'n' vi-command/search-repeat 5664 ble-bind -f 'N' vi-command/search-reverse-repeat 5665 ble-bind -f '*' vi-command/search-word-forward 5666 ble-bind -f '#' vi-command/search-word-backward 5667 5668 ble-bind -f '`' 'vi-command/goto-mark' 5669 ble-bind -f \' 'vi-command/goto-mark line' 5670 5671 # bash 5672 ble-bind -c 'C-z' fg 5673 } 5674 5675 #------------------------------------------------------------------------------ 5676 # Operator pending mode 5677 5678 function ble/widget/vi_omap/operator-rot13-or-search-backward { 5679 if [[ $_ble_keymap_vi_opfunc == rot13 ]]; then 5680 # g?? の時だけは rot13-encode lines 5681 ble/widget/vi-command/operator rot13 5682 else 5683 ble/widget/vi-command/search-backward 5684 fi 5685 } 5686 5687 # o_v o_V 5688 function ble/widget/vi_omap/switch-visual-mode.impl { 5689 local new_mode=$1 5690 5691 local old=$_ble_keymap_vi_opfunc 5692 [[ $old ]] || return 1 5693 5694 # clear existing visual-mode 5695 local new=$old: 5696 new=${new/:vi_char:/:} 5697 new=${new/:vi_line:/:} 5698 new=${new/:vi_block:/:} 5699 5700 # add new visual-mode 5701 [[ $new_mode ]] && new=$new:$new_mode 5702 5703 _ble_keymap_vi_opfunc=$new 5704 } 5705 # omap v 5706 function ble/widget/vi_omap/switch-to-charwise { 5707 ble/widget/vi_omap/switch-visual-mode.impl vi_char 5708 } 5709 # omap V 5710 function ble/widget/vi_omap/switch-to-linewise { 5711 ble/widget/vi_omap/switch-visual-mode.impl vi_line 5712 } 5713 # omap <C-v> 5714 function ble/widget/vi_omap/switch-to-blockwise { 5715 ble/widget/vi_omap/switch-visual-mode.impl vi_block 5716 } 5717 5718 function ble-decode/keymap:vi_omap/define { 5719 ble/keymap:vi/set-up-command-map 5720 5721 ble-bind -f __default__ vi_omap/__default__ 5722 ble-bind -f __line_limit__ nop 5723 ble-bind -f 'ESC' vi_omap/cancel 5724 ble-bind -f 'C-[' vi_omap/cancel 5725 ble-bind -f 'C-c' vi_omap/cancel 5726 5727 ble-bind -f a vi-command/text-object 5728 ble-bind -f i vi-command/text-object 5729 5730 # 範囲の種類の変更 (vim o_v o_V) 5731 ble-bind -f v vi_omap/switch-to-charwise 5732 ble-bind -f V vi_omap/switch-to-linewise 5733 ble-bind -f C-v vi_omap/switch-to-blockwise 5734 ble-bind -f C-q vi_omap/switch-to-blockwise 5735 5736 # 2文字オペレータの短縮形 5737 ble-bind -f '~' 'vi-command/operator toggle_case' 5738 ble-bind -f 'u' 'vi-command/operator u' 5739 ble-bind -f 'U' 'vi-command/operator U' 5740 ble-bind -f '?' 'vi_omap/operator-rot13-or-search-backward' 5741 ble-bind -f 'q' 'vi-command/operator fold' 5742 # Note: w は前方単語。例: {N}gww は format {N} words 5743 # Note: @ は omap では定義されない。例: {N}g@@ は bell 5744 } 5745 5746 #------------------------------------------------------------------------------ 5747 # Normal mode 5748 5749 # nmap C-d 5750 function ble/widget/vi-command/exit-on-empty-line { 5751 if [[ $_ble_edit_str ]]; then 5752 ble/widget/vi_nmap/forward-scroll 5753 return "$?" 5754 else 5755 ble/widget/exit 5756 ble/keymap:vi/adjust-command-mode # ジョブがあるときは終了しないので。 5757 return 1 5758 fi 5759 } 5760 5761 # nmap C-g (show line and column) 5762 function ble/widget/vi-command/show-line-info { 5763 local index count 5764 ble/history/get-index -v index 5765 ble/history/get-count -v count 5766 local hist_ratio=$(((100*index+count-1)/count))% 5767 local hist_stat=$'!\e[32m'$index$'\e[m / \e[32m'$count$'\e[m (\e[32m'$hist_ratio$'\e[m)' 5768 5769 local ret 5770 ble/string#count-char "$_ble_edit_str" $'\n'; local nline=$((ret+1)) 5771 ble/string#count-char "${_ble_edit_str::_ble_edit_ind}" $'\n'; local iline=$((ret+1)) 5772 local line_ratio=$(((100*iline+nline-1)/nline))% 5773 local line_stat=$'line \e[34m'$iline$'\e[m / \e[34m'$nline$'\e[m --\e[34m'$line_ratio$'\e[m--' 5774 5775 ble/edit/info/show ansi "\"$hist_stat\" $line_stat" 5776 ble/keymap:vi/adjust-command-mode 5777 return 0 5778 } 5779 5780 # nmap C-c (jobs) 5781 function ble/widget/vi-command/cancel { 5782 if [[ $_ble_keymap_vi_single_command ]]; then 5783 _ble_keymap_vi_single_command= 5784 _ble_keymap_vi_single_command_overwrite= 5785 ble/keymap:vi/update-mode-indicator 5786 else 5787 local joblist; ble/util/joblist 5788 if ((${#joblist[*]})); then 5789 ble/array#push joblist $'Type \e[35m:q!\e[m and press \e[35m<Enter>\e[m to abandon all \e[31mjobs\e[m and exit Bash' 5790 IFS=$'\n' builtin eval 'ble/edit/info/show ansi "${joblist[*]}"' 5791 else 5792 ble/edit/info/show ansi $'Type \e[35m:q\e[m and press \e[35m<Enter>\e[m to exit Bash' 5793 fi 5794 fi 5795 ble/widget/vi-command/bell 5796 return 0 5797 } 5798 5799 # nmap u, U, C-r 5800 # 5801 # `[`] は設定する。vim と違って実際に変更のあった範囲を抽出する。 5802 # . は設定しない。 5803 # 5804 bleopt/declare -v keymap_vi_imap_undo '' 5805 _ble_keymap_vi_undo_suppress= 5806 function ble/keymap:vi/undo/add { 5807 [[ $_ble_keymap_vi_undo_suppress ]] && return 0 5808 [[ $1 == more && $bleopt_keymap_vi_imap_undo != more ]] && return 0 5809 ble-edit/undo/add 5810 } 5811 function ble/widget/vi_nmap/undo { 5812 local ARG FLAG REG; ble/keymap:vi/get-arg 1 5813 local _ble_keymap_vi_undo_suppress=1 5814 ble/keymap:vi/mark/start-edit-area 5815 if ble-edit/undo/undo "$ARG"; then 5816 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 5817 ble/keymap:vi/mark/end-edit-area 5818 ble/keymap:vi/adjust-command-mode 5819 else 5820 ble/widget/vi-command/bell 5821 return 1 5822 fi 5823 } 5824 function ble/widget/vi_nmap/redo { 5825 local ARG FLAG REG; ble/keymap:vi/get-arg 1 5826 local _ble_keymap_vi_undo_suppress=1 5827 ble/keymap:vi/mark/start-edit-area 5828 if ble-edit/undo/redo "$ARG"; then 5829 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 5830 ble/keymap:vi/mark/end-edit-area 5831 ble/keymap:vi/adjust-command-mode 5832 else 5833 ble/widget/vi-command/bell 5834 return 1 5835 fi 5836 } 5837 function ble/widget/vi_nmap/revert { 5838 local ARG FLAG REG; ble/keymap:vi/get-arg 1 5839 local _ble_keymap_vi_undo_suppress=1 5840 ble/keymap:vi/mark/start-edit-area 5841 if ble-edit/undo/revert-toggle "$ARG"; then 5842 ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--)) 5843 ble/keymap:vi/mark/end-edit-area 5844 ble/keymap:vi/adjust-command-mode 5845 else 5846 ble/widget/vi-command/bell 5847 return 1 5848 fi 5849 } 5850 5851 # nmap C-a, C-x 5852 function ble/widget/vi_nmap/increment.impl { 5853 local delta=$1 5854 ((delta==0)) && return 0 5855 5856 # 数字の範囲の確定 5857 local line=${_ble_edit_str:_ble_edit_ind} 5858 line=${line%%$'\n'*} 5859 local rex='^([^0-9]*)[0-9]+' 5860 if ! [[ $line =~ $rex ]]; then 5861 # 行末にいる時(空行を意味する)にはベルは鳴らさない。 5862 [[ $line ]] && ble/widget/.bell 'number not found' 5863 ble/keymap:vi/adjust-command-mode 5864 return 0 5865 fi 5866 local rematch1=${BASH_REMATCH[1]} 5867 local beg=$((_ble_edit_ind+${#rematch1})) 5868 local end=$((_ble_edit_ind+${#BASH_REMATCH})) 5869 rex='-?[0-9]*$'; [[ ${_ble_edit_str::beg} =~ $rex ]] 5870 ((beg-=${#BASH_REMATCH})) 5871 5872 # 数の抽出 5873 local number=${_ble_edit_str:beg:end-beg} 5874 local abs=${number#-} 5875 if [[ $abs == 0?* ]]; then 5876 if [[ $number == -* ]]; then 5877 number=-$((10#0$abs)) 5878 else 5879 number=$((10#0$abs)) 5880 fi 5881 fi 5882 5883 # 数の増加・減少 5884 ((number+=delta)) 5885 if [[ $abs == 0?* ]]; then 5886 # Zero padding 5887 local wsign=$((number<0?1:0)) 5888 local zpad=$((wsign+${#abs}-${#number})) 5889 if ((zpad>0)); then 5890 local ret; ble/string#repeat 0 "$zpad" 5891 number=${number::wsign}$ret${number:wsign} 5892 fi 5893 fi 5894 5895 ble/widget/.replace-range "$beg" "$end" "$number" 5896 ble/keymap:vi/mark/set-previous-edit-area "$beg" "$((beg+${#number}))" 5897 ble/keymap:vi/repeat/record 5898 _ble_edit_ind=$((beg+${#number}-1)) 5899 ble/keymap:vi/adjust-command-mode 5900 return 0 5901 } 5902 function ble/widget/vi_nmap/increment { 5903 local ARG FLAG REG; ble/keymap:vi/get-arg 1 5904 ble/widget/vi_nmap/increment.impl "$ARG" 5905 } 5906 function ble/widget/vi_nmap/decrement { 5907 local ARG FLAG REG; ble/keymap:vi/get-arg 1 5908 ble/widget/vi_nmap/increment.impl "$((-ARG))" 5909 } 5910 function ble/widget/vi_nmap/__line_limit__.edit { 5911 ble/keymap:vi/clear-arg 5912 ble/widget/vi_nmap/.insert-mode 5913 ble/keymap:vi/repeat/clear-insert 5914 ble/widget/edit-and-execute-command.impl "$1" 5915 } 5916 function ble/widget/vi_nmap/__line_limit__ { 5917 ble/widget/__line_limit__ vi_nmap/__line_limit__.edit 5918 } 5919 5920 function ble-decode/keymap:vi_nmap/define { 5921 ble/keymap:vi/set-up-command-map 5922 5923 ble-bind -f __default__ vi-command/decompose-meta 5924 ble-bind -f __line_limit__ vi_nmap/__line_limit__ 5925 ble-bind -f 'ESC' vi-command/bell 5926 ble-bind -f 'C-[' vi-command/bell 5927 ble-bind -f 'C-c' vi-command/cancel 5928 5929 ble-bind -f a vi_nmap/append-mode 5930 ble-bind -f A vi_nmap/append-mode-at-end-of-line 5931 ble-bind -f i vi_nmap/insert-mode 5932 ble-bind -f insert vi_nmap/insert-mode 5933 ble-bind -f I vi_nmap/insert-mode-at-first-non-space 5934 ble-bind -f 'g I' vi_nmap/insert-mode-at-beginning-of-line 5935 ble-bind -f o vi_nmap/insert-mode-at-forward-line 5936 ble-bind -f O vi_nmap/insert-mode-at-backward-line 5937 ble-bind -f R vi_nmap/replace-mode 5938 ble-bind -f 'g R' vi_nmap/virtual-replace-mode 5939 ble-bind -f 'g i' vi_nmap/insert-mode-at-previous-point 5940 5941 ble-bind -f '~' vi_nmap/forward-char-toggle-case 5942 5943 ble-bind -f Y vi_nmap/copy-current-line 5944 ble-bind -f S vi_nmap/kill-current-line-and-insert 5945 ble-bind -f D vi_nmap/kill-forward-line 5946 ble-bind -f C vi_nmap/kill-forward-line-and-insert 5947 5948 ble-bind -f p vi_nmap/paste-after 5949 ble-bind -f P vi_nmap/paste-before 5950 5951 ble-bind -f x vi_nmap/kill-forward-char 5952 ble-bind -f s vi_nmap/kill-forward-char-and-insert 5953 ble-bind -f X vi_nmap/kill-backward-char 5954 ble-bind -f delete vi_nmap/kill-forward-char 5955 5956 ble-bind -f 'r' vi_nmap/replace-char 5957 ble-bind -f 'g r' vi_nmap/virtual-replace-char # vim で実際に試すとこの機能はない 5958 5959 ble-bind -f J vi_nmap/connect-line-with-space 5960 ble-bind -f 'g J' vi_nmap/connect-line 5961 5962 ble-bind -f v vi_nmap/charwise-visual-mode 5963 ble-bind -f V vi_nmap/linewise-visual-mode 5964 ble-bind -f C-v vi_nmap/blockwise-visual-mode 5965 ble-bind -f C-q vi_nmap/blockwise-visual-mode 5966 ble-bind -f 'g v' vi-command/previous-visual-area 5967 ble-bind -f 'g h' vi_nmap/charwise-select-mode 5968 ble-bind -f 'g H' vi_nmap/linewise-select-mode 5969 ble-bind -f 'g C-h' vi_nmap/blockwise-select-mode 5970 5971 ble-bind -f . vi_nmap/repeat 5972 5973 ble-bind -f K vi_nmap/command-help 5974 ble-bind -f f1 vi_nmap/command-help 5975 5976 ble-bind -f 'C-d' vi_nmap/forward-line-scroll 5977 ble-bind -f 'C-u' vi_nmap/backward-line-scroll 5978 ble-bind -f 'C-e' vi_nmap/forward-scroll 5979 ble-bind -f 'C-y' vi_nmap/backward-scroll 5980 ble-bind -f 'C-f' vi_nmap/pagedown 5981 ble-bind -f 'next' vi_nmap/pagedown 5982 ble-bind -f 'C-b' vi_nmap/pageup 5983 ble-bind -f 'prior' vi_nmap/pageup 5984 ble-bind -f 'z t' vi_nmap/scroll-to-top-and-redraw 5985 ble-bind -f 'z z' vi_nmap/scroll-to-center-and-redraw 5986 ble-bind -f 'z b' vi_nmap/scroll-to-bottom-and-redraw 5987 ble-bind -f 'z RET' vi_nmap/scroll-to-top-non-space-and-redraw 5988 ble-bind -f 'z C-m' vi_nmap/scroll-to-top-non-space-and-redraw 5989 ble-bind -f 'z +' vi_nmap/scroll-or-pagedown-and-redraw 5990 ble-bind -f 'z -' vi_nmap/scroll-to-bottom-non-space-and-redraw 5991 ble-bind -f 'z .' vi_nmap/scroll-to-center-non-space-and-redraw 5992 5993 ble-bind -f m vi-command/set-mark 5994 ble-bind -f '"' vi-command/register 5995 5996 ble-bind -f 'C-g' vi-command/show-line-info 5997 5998 ble-bind -f 'q' vi_nmap/record-register 5999 ble-bind -f '@' vi_nmap/play-register 6000 6001 ble-bind -f u vi_nmap/undo 6002 ble-bind -f C-r vi_nmap/redo 6003 ble-bind -f U vi_nmap/revert 6004 6005 ble-bind -f C-a vi_nmap/increment 6006 ble-bind -f C-x vi_nmap/decrement 6007 6008 ble-bind -f 'Z Z' 'vi-command:q' 6009 ble-bind -f 'Z Q' 'vi-command:q' 6010 6011 #---------------------------------------------------------------------------- 6012 # bash 6013 6014 ble-bind -f 'C-j' 'accept-line' 6015 ble-bind -f 'C-RET' 'accept-line' 6016 ble-bind -f 'C-m' 'accept-single-line-or vi-command/forward-first-non-space' 6017 ble-bind -f 'RET' 'accept-single-line-or vi-command/forward-first-non-space' 6018 #ble-bind -f 'C-x C-e' 'vi-command/edit-and-execute-command' 6019 ble-bind -f 'C-l' 'clear-screen' 6020 ble-bind -f 'C-d' 'vi-command/exit-on-empty-line' # overwrites vi_nmap/forward-scroll 6021 ble-bind -f 'auto_complete_enter' auto-complete-enter 6022 6023 # Note #D1256: Bash vi-command 互換性の為 6024 ble-bind -f M-left 'vi-command/backward-vword' 6025 ble-bind -f M-right 'vi-command/forward-vword' 6026 ble-bind -f C-delete 'vi-rlfunc/kill-word' 6027 ble-bind -f '#' 'vi-rlfunc/insert-comment' 6028 ble-bind -f '&' 'vi_nmap/@edit tilde-expand' 6029 6030 # ble-bind -f 'C-u' 'vi-rlfunc/unix-line-discard' 6031 # ble-bind -f 'C-q' 'vi-rlfunc/quoted-insert' 6032 # ble-bind -f 'C-v' 'vi-rlfunc/quoted-insert' 6033 # ble-bind -f 'C-d' 'vi-rlfunc/eof-maybe' 6034 # ble-bind -f '_' 'vi-rlfunc/yank-arg' 6035 } 6036 6037 # lib/core-decode.vi_nmap-rlfunc.txt 用 6038 6039 function ble/widget/vi-rlfunc/.is-uppercase { 6040 local n=${#KEYS[@]} 6041 local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar)) 6042 ((0x41<=code&&code<=0x5a)) 6043 } 6044 6045 # d or D 6046 function ble/widget/vi-rlfunc/delete-to { 6047 if ble/widget/vi-rlfunc/.is-uppercase; then 6048 ble/widget/vi_nmap/kill-forward-line 6049 else 6050 ble/widget/vi-command/operator d 6051 fi 6052 } 6053 # c or C 6054 function ble/widget/vi-rlfunc/change-to { 6055 if ble/widget/vi-rlfunc/.is-uppercase; then 6056 ble/widget/vi_nmap/kill-forward-line-and-insert 6057 else 6058 ble/widget/vi-command/operator c 6059 fi 6060 } 6061 # y or Y 6062 function ble/widget/vi-rlfunc/yank-to { 6063 if ble/widget/vi-rlfunc/.is-uppercase; then 6064 ble/widget/vi_nmap/copy-current-line 6065 else 6066 ble/widget/vi-command/operator y 6067 fi 6068 } 6069 function ble/widget/vi-rlfunc/char-search { 6070 local n=${#KEYS[@]} 6071 local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar)) 6072 ((code==0)) && return 1 6073 ble/util/c2s "$code" 6074 case $ret in 6075 ('f') ble/widget/vi-command/search-forward-char ;; 6076 ('F') ble/widget/vi-command/search-backward-char ;; 6077 ('t') ble/widget/vi-command/search-forward-char-prev ;; 6078 ('T') ble/widget/vi-command/search-backward-char-prev ;; 6079 (';') ble/widget/vi-command/search-char-repeat ;; 6080 (',') ble/widget/vi-command/search-char-reverse-repeat ;; 6081 (*) return 1 ;; 6082 esac 6083 } 6084 # w or W 6085 function ble/widget/vi-rlfunc/next-word { 6086 if ble/widget/vi-rlfunc/.is-uppercase; then 6087 ble/widget/vi-command/forward-uword 6088 else 6089 ble/widget/vi-command/forward-vword 6090 fi 6091 } 6092 # b or B 6093 function ble/widget/vi-rlfunc/prev-word { 6094 if ble/widget/vi-rlfunc/.is-uppercase; then 6095 ble/widget/vi-command/backward-uword 6096 else 6097 ble/widget/vi-command/backward-vword 6098 fi 6099 } 6100 # e or E 6101 function ble/widget/vi-rlfunc/end-word { 6102 if ble/widget/vi-rlfunc/.is-uppercase; then 6103 ble/widget/vi-command/forward-uword-end 6104 else 6105 ble/widget/vi-command/forward-vword-end 6106 fi 6107 } 6108 # p or P 6109 function ble/widget/vi-rlfunc/put { 6110 if ble/widget/vi-rlfunc/.is-uppercase; then 6111 ble/widget/vi_nmap/paste-before 6112 else 6113 ble/widget/vi_nmap/paste-after 6114 fi 6115 } 6116 # / or ? 6117 function ble/widget/vi-rlfunc/search { 6118 local n=${#KEYS[@]} 6119 local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar)) 6120 if ((code==63)); then 6121 ble/widget/vi-command/search-backward 6122 else 6123 ble/widget/vi-command/search-forward 6124 fi 6125 } 6126 # n or N 6127 function ble/widget/vi-rlfunc/search-again { 6128 if ble/widget/vi-rlfunc/.is-uppercase; then 6129 ble/widget/vi-command/search-reverse-repeat 6130 else 6131 ble/widget/vi-command/search-repeat 6132 fi 6133 } 6134 # s or S 6135 function ble/widget/vi-rlfunc/subst { 6136 if ble/widget/vi-rlfunc/.is-uppercase; then 6137 ble/widget/vi_nmap/kill-current-line-and-insert 6138 else 6139 ble/widget/vi_nmap/kill-forward-char-and-insert 6140 fi 6141 } 6142 # rl_nmap C-delete 6143 function ble/widget/vi-rlfunc/kill-word { 6144 _ble_keymap_vi_opfunc=d 6145 ble/widget/vi-command/forward-vword-end 6146 } 6147 # rl_nmap C-u 6148 function ble/widget/vi-rlfunc/unix-line-discard { 6149 _ble_keymap_vi_opfunc=d 6150 ble/widget/vi-command/beginning-of-line 6151 } 6152 # rl_nmap # 6153 function ble/widget/vi-rlfunc/insert-comment { 6154 local ARG FLAG REG; ble/keymap:vi/get-arg '' 6155 ble/keymap:vi/mark/start-edit-area 6156 ble/widget/insert-comment/.insert "$ARG" 6157 ble/keymap:vi/mark/end-edit-area 6158 ble/widget/vi_nmap/accept-line 6159 } 6160 # rl_nmap C-v, C-q 6161 function ble/widget/vi-rlfunc/quoted-insert-char.hook { 6162 local ARG FLAG REG; ble/keymap:vi/get-arg 1 6163 ble/keymap:vi/mark/start-edit-area 6164 _ble_edit_arg=$ARG ble/widget/quoted-insert-char.hook 6165 ble/keymap:vi/mark/end-edit-area 6166 ble/keymap:vi/repeat/record 6167 ble/keymap:vi/adjust-command-mode 6168 return 0 6169 } 6170 function ble/widget/vi-rlfunc/quoted-insert-char { 6171 _ble_edit_mark_active= 6172 _ble_decode_char__hook=ble/widget/vi-rlfunc/quoted-insert-char.hook 6173 return 147 6174 } 6175 function ble/widget/vi-rlfunc/quoted-insert.hook { 6176 local ARG FLAG REG; ble/keymap:vi/get-arg 1 6177 ble/keymap:vi/mark/start-edit-area 6178 _ble_edit_arg=$ARG ble/widget/quoted-insert.hook 6179 ble/keymap:vi/mark/end-edit-area 6180 ble/keymap:vi/repeat/record 6181 ble/keymap:vi/adjust-command-mode 6182 return 0 6183 } 6184 function ble/widget/vi-rlfunc/quoted-insert { 6185 _ble_edit_mark_active= 6186 _ble_decode_key__hook=ble/widget/vi-rlfunc/quoted-insert.hook 6187 return 147 6188 } 6189 # rl_nmap C-d 6190 function ble/widget/vi-rlfunc/eof-maybe { 6191 if [[ ! $_ble_edit_str ]]; then 6192 ble/widget/exit 6193 ble/keymap:vi/adjust-command-mode # ジョブがあるときは終了しないので。 6194 return 1 6195 elif ble-edit/is-single-complete-line; then 6196 ble/widget/vi_nmap/accept-line 6197 else 6198 local ARG FLAG REG; ble/keymap:vi/get-arg 1 6199 ble/keymap:vi/mark/start-edit-area 6200 _ble_edit_ind=${#_ble_edit_str} 6201 _ble_edit_arg=$ARG 6202 ble/widget/self-insert 6203 ble/keymap:vi/mark/end-edit-area 6204 ble/keymap:vi/adjust-command-mode 6205 fi 6206 } 6207 # rl_nmap _ 6208 function ble/widget/vi-rlfunc/yank-arg { 6209 ble/widget/vi_nmap/append-mode 6210 ble/keymap:vi/imap-repeat/reset 6211 local -a KEYS; KEYS=(32) 6212 ble/widget/self-insert 6213 ble/util/unlocal KEYS 6214 ble/widget/insert-last-argument 6215 return "$?" 6216 } 6217 6218 # rlfunc: forward-byte, backward-byte 6219 function ble/widget/vi-command/forward-byte { 6220 local ARG FLAG REG; ble/keymap:vi/get-arg 1 6221 local index=$_ble_edit_ind 6222 ble/widget/.locate-forward-byte "$ARG" || [[ $FLAG ]] || ble/widget/.bell 6223 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" 6224 } 6225 function ble/widget/vi-command/backward-byte { 6226 local ARG FLAG REG; ble/keymap:vi/get-arg 1 6227 local index=$_ble_edit_ind 6228 ble/widget/.locate-forward-byte "$((-ARG))" || [[ $FLAG ]] || ble/widget/.bell 6229 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" 6230 } 6231 6232 # rlfunc: capitalize-word, downcase-word, upcase-word 6233 #%define 2 6234 function ble/widget/vi_nmap/capitalize-XWORD { ble/widget/filter-word.impl XWORD ble/string#capitalize; } 6235 function ble/widget/vi_nmap/downcase-XWORD { ble/widget/filter-word.impl XWORD ble/string#tolower; } 6236 function ble/widget/vi_nmap/upcase-XWORD { ble/widget/filter-word.impl XWORD ble/string#toupper; } 6237 #%end 6238 #%expand 2.r/XWORD/eword/ 6239 #%expand 2.r/XWORD/cword/ 6240 #%expand 2.r/XWORD/uword/ 6241 #%expand 2.r/XWORD/sword/ 6242 #%expand 2.r/XWORD/fword/ 6243 6244 function ble/widget/vi_nmap/@edit { 6245 ble/keymap:vi/clear-arg 6246 ble/keymap:vi/repeat/record 6247 ble/keymap:vi/mark/start-edit-area 6248 ble/widget/"$@" 6249 ble/keymap:vi/mark/end-edit-area 6250 ble/keymap:vi/adjust-command-mode 6251 } 6252 function ble/widget/vi_nmap/@adjust { 6253 ble/keymap:vi/clear-arg 6254 ble/widget/"$@" 6255 ble/keymap:vi/adjust-command-mode 6256 } 6257 function ble/widget/vi_nmap/@motion { 6258 local ARG FLAG REG; ble/keymap:vi/get-arg 1 6259 local _ble_edit_ind=$_ble_edit_ind _ble_edit_arg=$ARG 6260 if ble/widget/"$@"; then 6261 local index=$_ble_edit_ind 6262 ble/util/unlocal _ble_edit_ind 6263 ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell 6264 else 6265 ble/keymap:vi/adjust-command-mode 6266 fi 6267 } 6268 6269 #------------------------------------------------------------------------------ 6270 # Visual mode 6271 6272 # 選択の種類は _ble_edit_mark_active に設定される文字列で区別する。 6273 # 6274 # _ble_edit_mark_active は vi_char, vi_line, vi_block のどれかである 6275 # 更に末尾拡張 (行末までの選択範囲の拡張) が設定されているときには 6276 # vi_char+, vi_line+, vi_block+ などの様に + が末尾に付く。 6277 6278 function ble/keymap:vi/xmap/has-eol-extension { 6279 [[ $_ble_edit_mark_active == *+ ]] 6280 } 6281 function ble/keymap:vi/xmap/add-eol-extension { 6282 [[ $_ble_edit_mark_active ]] && 6283 _ble_edit_mark_active=${_ble_edit_mark_active%+}+ 6284 } 6285 function ble/keymap:vi/xmap/remove-eol-extension { 6286 [[ $_ble_edit_mark_active ]] && 6287 _ble_edit_mark_active=${_ble_edit_mark_active%+} 6288 } 6289 function ble/keymap:vi/xmap/switch-type { 6290 local suffix; [[ $_ble_edit_mark_active == *+ ]] && suffix=+ 6291 _ble_edit_mark_active=$1$suffix 6292 } 6293 6294 #-------------------------------------- 6295 # xmap/矩形範囲の抽出 6296 6297 ## @fn local p0 q0 lx ly rx ry; ble/keymap:vi/get-graphical-rectangle [index1 [index2]] 6298 ## @fn local p0 q0 lx ly rx ry; ble/keymap:vi/get-logical-rectangle [index1 [index2]] 6299 ## @fn local p0 q0 lx ly rx ry; ble/keymap:vi/get-rectangle [index1 [index2]] 6300 ## @fn local ret ; ble/keymap:vi/get-rectangle-height [index1 [index2]] 6301 ## 6302 ## @param[in,opt] index1 [=_ble_edit_mark] 6303 ## @param[in,opt] index2 [=_ble_edit_ind] 6304 ## 6305 ## @var[out] p0 q0 6306 ## @var[out] lx ly rx ry 6307 ## 6308 function ble/keymap:vi/get-graphical-rectangle { 6309 local p=${1:-$_ble_edit_mark} q=${2:-$_ble_edit_ind} 6310 local ret 6311 ble-edit/content/find-logical-bol "$p"; p0=$ret 6312 ble-edit/content/find-logical-bol "$q"; q0=$ret 6313 6314 local p0x p0y q0x q0y 6315 ble/textmap#getxy.out --prefix=p0 "$p0" 6316 ble/textmap#getxy.out --prefix=q0 "$q0" 6317 6318 local plx ply qlx qly 6319 ble/textmap#getxy.cur --prefix=pl "$p" 6320 ble/textmap#getxy.cur --prefix=ql "$q" 6321 6322 local prx=$plx pry=$ply qrx=$qlx qry=$qly 6323 ble-edit/content/eolp "$p" && ((prx++)) || ble/textmap#getxy.out --prefix=pr "$((p+1))" 6324 ble-edit/content/eolp "$q" && ((qrx++)) || ble/textmap#getxy.out --prefix=qr "$((q+1))" 6325 6326 ((ply-=p0y,qly-=q0y,pry-=p0y,qry-=q0y, 6327 (ply<qly||ply==qly&&plx<qlx)?(lx=plx,ly=ply):(lx=qlx,ly=qly), 6328 (pry>qry||pry==qry&&prx>qrx)?(rx=prx,ry=pry):(rx=qrx,ry=qry))) 6329 } 6330 function ble/keymap:vi/get-logical-rectangle { 6331 local p=${1:-$_ble_edit_mark} q=${2:-$_ble_edit_ind} 6332 local ret 6333 ble-edit/content/find-logical-bol "$p"; p0=$ret 6334 ble-edit/content/find-logical-bol "$q"; q0=$ret 6335 ((p-=p0,q-=q0,p<=q)) || local p=$q q=$p 6336 lx=$p rx=$((q+1)) ly=0 ry=0 6337 } 6338 function ble/keymap:vi/get-rectangle { 6339 if ble/edit/use-textmap; then 6340 ble/keymap:vi/get-graphical-rectangle "$@" 6341 else 6342 ble/keymap:vi/get-logical-rectangle "$@" 6343 fi 6344 } 6345 ## @fn ble/keymap:vi/get-rectangle-height [index1 [index2]] 6346 ## @var[out] ret 6347 function ble/keymap:vi/get-rectangle-height { 6348 local p0 q0 lx ly rx ry 6349 ble/keymap:vi/get-rectangle "$@" 6350 ble/string#count-char "${_ble_edit_str:p0:q0-p0}" $'\n' 6351 ((ret++)) 6352 return 0 6353 } 6354 6355 6356 ## @fn ble/keymap:vi/extract-graphical-block-by-geometry bol1 bol2 x1:y1 x2:y2 opts 6357 ## @fn ble/keymap:vi/extract-logical-block-by-geometry bol1 bol2 c1 c2 opts 6358 ## 指定した引数の範囲を元に矩形範囲を抽出します。 6359 ## @fn ble/keymap:vi/extract-graphical-block [index1 [index2 [opts]]] 6360 ## @fn ble/keymap:vi/extract-logical-block [index1 [index2 [opts]]] 6361 ## @fn ble/keymap:vi/extract-block [index1 [index2 [opts]]] 6362 ## 現在位置 (_ble_edit_ind) とマーク (_ble_edit_mark) を元に矩形範囲を抽出します。 6363 ## 6364 ## @param[in] bol1 bol2 6365 ## 2つの行の行頭を指定します。 6366 ## @param[in] x1:y1 x2:y2 6367 ## 2つの列を行頭からの相対位置で指定します。 6368 ## @param[in] c1 c2 6369 ## 2つの列を論理列で指定します。 6370 ## 6371 ## @param[in,opt] index1 [$_ble_edit_mark] 6372 ## @param[in,opt] index2 [$_ble_edit_ind] 6373 ## 矩形の端点の文字インデックスを指定します。 6374 ## 6375 ## @param[in,opt] opts 6376 ## コロン区切りのフラグ指定です。 6377 ## 6378 ## first_line 6379 ## 矩形を構成する最初の行についてだけ情報を取得します。 6380 ## その他の行については空の情報 (':::::') を sub_ranges に格納します。 6381 ## 6382 ## skip_middle 6383 ## 矩形を構成する最初と最後の行についてだけ情報を取得します。 6384 ## その他の行については空の情報 (':::::') を sub_ranges に格納します。 6385 ## 6386 ## @var[in] _ble_edit_mark_active 6387 ## 末尾拡張を行うばあいにこの引数の末端に + を指定します。 6388 ## 6389 ## @arr[out] sub_ranges 6390 ## 矩形を構成する各行の情報を格納します。 6391 ## 各要素は以下の形式を持ちます。 6392 ## 6393 ## smin:smax:slpad:srpad:sfill:stext 6394 ## 6395 ## smin smax 6396 ## 選択範囲を強調するとき・切り取るときの範囲を指定します。 6397 ## slpad srpad 6398 ## 選択範囲を切り取ったときに左右に補填する空白の数を指定します。 6399 ## sfill 6400 ## 矩形の挿入時に右端に補填するべき空白の数を指定します。 6401 ## stext 6402 ## 選択範囲から読み取られる文字列を指定します。 6403 ## 全角文字などが範囲の境界を跨ぐとき、 6404 ## その文字は (範囲に被る幅と同数の) 空白に置き換えられます。 6405 ## @var[out] sub_x1 sub_x2 6406 ## 6407 function ble/keymap:vi/extract-graphical-block-by-geometry { 6408 local bol1=$1 bol2=$2 x1=$3 x2=$4 y1=0 y2=0 opts=$5 6409 ((bol1<=bol2||(bol1=$2,bol2=$1))) 6410 [[ $x1 == *:* ]] && local x1=${x1%%:*} y1=${x1#*:} 6411 [[ $x2 == *:* ]] && local x2=${x2%%:*} y2=${x2#*:} 6412 6413 local cols=$_ble_textmap_cols 6414 local c1=$((cols*y1+x1)) c2=$((cols*y2+x2)) 6415 sub_x1=$c1 sub_x2=$c2 6416 6417 local ret index lx ly rx ly 6418 6419 ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret 6420 local lines; ble/string#split-lines lines "${_ble_edit_str:bol1:eol2-bol1}" 6421 6422 sub_ranges=() 6423 local min_sfill=0 6424 local line bol=$bol1 eol bolx boly 6425 local c1l c1r c2l c2r 6426 for line in "${lines[@]}"; do 6427 ((eol=bol+${#line})) 6428 6429 if [[ :$opts: == *:first_line:* ]] && ((${#sub_ranges[@]})); then 6430 ble/array#push sub_ranges ::::: 6431 elif [[ :$opts: == *:skip_middle:* ]] && ((0<${#sub_ranges[@]}&&${#sub_ranges[@]}<${#lines[@]}-1)); then 6432 ble/array#push sub_ranges ::::: 6433 else 6434 ble/textmap#getxy.out --prefix=bol "$bol" 6435 ble/textmap#hit out "$x1" "$((boly+y1))" "$bol" "$eol" 6436 local smin=$index x1l=$lx y1l=$ly x1r=$rx y1r=$ry 6437 if ble/keymap:vi/xmap/has-eol-extension; then 6438 local eolx eoly; ble/textmap#getxy.out --prefix=eol "$eol" 6439 local smax=$eol x2l=$eolx y2l=$eoly x2r=$eolx y2r=$eoly 6440 else 6441 ble/textmap#hit out "$x2" "$((boly+y2))" "$bol" "$eol" 6442 local smax=$index x2l=$lx y2l=$ly x2r=$rx y2r=$ry 6443 fi 6444 6445 local sfill=0 slpad=0 srpad=0 6446 local stext=${_ble_edit_str:smin:smax-smin} 6447 if ((smin<smax)); then 6448 # 1. 左の境界 c1 を大きな文字が跨いでいるときは空白に変換する。 6449 ((c1l=(y1l-boly)*cols+x1l)) 6450 if ((c1l<c1)); then 6451 ((slpad=c1-c1l)) 6452 6453 # assert: smin < smax <= eol なので行末ではない 6454 ble/util/assert '! ble-edit/content/eolp "$smin"' 6455 6456 ((c1r=(y1r-boly)*cols+x1r)) 6457 ble/util/assert '((c1r>c1))' || ((c1r=c1)) 6458 ble/string#repeat ' ' "$((c1r-c1))" 6459 stext=$ret${stext:1} 6460 fi 6461 6462 # 2. 右の境界 c2 を大きな文字が跨いでいるときは空白に変換する 6463 ((c2l=(y2l-boly)*cols+x2l)) 6464 if ((c2l<c2)); then 6465 if ((smax==eol)); then 6466 ((sfill=c2-c2l)) 6467 else 6468 ble/string#repeat ' ' "$((c2-c2l))" 6469 stext=$stext$ret 6470 ((smax++)) 6471 6472 ((c2r=(y2r-boly)*cols+x2r)) 6473 ble/util/assert '((c2r>c2))' || ((c2r=c2)) 6474 ((srpad=c2r-c2)) 6475 fi 6476 elif ((c2l>c2)); then 6477 # ここに来るのは ble/keymap:vi/xmap/has-eol-extension のときのみの筈 6478 ((sfill=c2-c2l, 6479 sfill<min_sfill&&(min_sfill=sfill))) 6480 fi 6481 else 6482 if ((smin==eol)); then 6483 # 行末 6484 ((sfill=c2-c1)) 6485 elif ((c2>c1)); then 6486 # 範囲の両端が単一の文字の左端または内部にある 6487 ble/string#repeat ' ' "$((c2-c1))" 6488 stext=$ret${stext:1} 6489 ((smax++)) 6490 6491 ((c1l=(y1l-boly)*cols+x1l,slpad=c1-c1l)) 6492 ((c1r=(y1r-boly)*cols+x1r,srpad=c1r-c1)) 6493 fi 6494 fi 6495 6496 ble/array#push sub_ranges "$smin:$smax:$slpad:$srpad:$sfill:$stext" 6497 fi 6498 6499 ((bol=eol+1)) 6500 done 6501 6502 if ((min_sfill<0)); then 6503 local isub=${#sub_ranges[@]} 6504 while ((isub--)); do 6505 local sub=${sub_ranges[isub]} 6506 local sub45=${sub#*:*:*:*:} 6507 local sfill=${sub45%%:*} 6508 sub_ranges[isub]=${sub::${#sub}-${#sub45}}$((sfill-min_sfill))${sub45:${#sfill}} 6509 done 6510 fi 6511 } 6512 function ble/keymap:vi/extract-graphical-block { 6513 local opts=$3 6514 local p0 q0 lx ly rx ry 6515 ble/keymap:vi/get-graphical-rectangle "$@" 6516 ble/keymap:vi/extract-graphical-block-by-geometry "$p0" "$q0" "$lx:$ly" "$rx:$ry" "$opts" 6517 } 6518 function ble/keymap:vi/extract-logical-block-by-geometry { 6519 local bol1=$1 bol2=$2 x1=$3 x2=$4 opts=$5 6520 ((bol1<=bol2||(bol1=$2,bol2=$1))) 6521 sub_x1=$c1 sub_x2=$c2 6522 6523 local ret min_sfill=0 6524 local bol=$bol1 eol smin smax slpad srpad sfill 6525 sub_ranges=() 6526 while :; do 6527 ble-edit/content/find-logical-eol "$bol"; eol=$ret 6528 slpad=0 srpad=0 sfill=0 6529 ((smin=bol+x1,smin>eol&&(smin=eol))) 6530 if ble/keymap:vi/xmap/has-eol-extension; then 6531 ((smax=eol, 6532 sfill=bol+x2-eol, 6533 sfill<min_sfill&&(min_sfill=sfill))) 6534 else 6535 ((smax=bol+x2,smax>eol&&(sfill=smax-eol,smax=eol))) 6536 fi 6537 6538 local stext=${_ble_edit_str:smin:smax-smin} 6539 6540 ble/array#push sub_ranges "$smin:$smax:$slpad:$srpad:$sfill:$stext" 6541 6542 ((bol>=bol2)) && break 6543 ble-edit/content/find-logical-bol "$bol" 1; bol=$ret 6544 done 6545 6546 if ((min_sfill<0)); then 6547 local isub=${#sub_ranges[@]} 6548 while ((isub--)); do 6549 local sub=${sub_ranges[isub]} 6550 local sub45=${sub#*:*:*:*:} 6551 local sfill=${sub45%%:*} 6552 sub_ranges[isub]=${sub::${#sub}-${#sub45}}$((sfill-min_sfill))${sub45:${#sfill}} 6553 done 6554 fi 6555 } 6556 function ble/keymap:vi/extract-logical-block { 6557 local opts=$3 6558 local p0 q0 lx ly rx ry 6559 ble/keymap:vi/get-logical-rectangle "$@" 6560 ble/keymap:vi/extract-logical-block-by-geometry "$p0" "$q0" "$lx" "$rx" "$opts" 6561 } 6562 function ble/keymap:vi/extract-block { 6563 if ble/edit/use-textmap; then 6564 ble/keymap:vi/extract-graphical-block "$@" 6565 else 6566 ble/keymap:vi/extract-logical-block "$@" 6567 fi 6568 } 6569 6570 #-------------------------------------- 6571 # xmap/選択範囲の着色の設定 6572 6573 ## @fn ble/highlight/layer:region/mark:vi_char/get-selection 6574 ## @fn ble/highlight/layer:region/mark:vi_line/get-selection 6575 ## @fn ble/highlight/layer:region/mark:vi_block/get-selection 6576 ## @arr[out] selection 6577 function ble/highlight/layer:region/mark:vi_char/get-selection { 6578 local rmin rmax 6579 if ((_ble_edit_mark<_ble_edit_ind)); then 6580 rmin=$_ble_edit_mark rmax=$_ble_edit_ind 6581 else 6582 rmin=$_ble_edit_ind rmax=$_ble_edit_mark 6583 fi 6584 ble-edit/content/eolp "$rmax" || ((rmax++)) 6585 selection=("$rmin" "$rmax") 6586 } 6587 function ble/highlight/layer:region/mark:vi_line/get-selection { 6588 local rmin rmax 6589 if ((_ble_edit_mark<_ble_edit_ind)); then 6590 rmin=$_ble_edit_mark rmax=$_ble_edit_ind 6591 else 6592 rmin=$_ble_edit_ind rmax=$_ble_edit_mark 6593 fi 6594 local ret 6595 ble-edit/content/find-logical-bol "$rmin"; rmin=$ret 6596 ble-edit/content/find-logical-eol "$rmax"; rmax=$ret 6597 selection=("$rmin" "$rmax") 6598 } 6599 function ble/highlight/layer:region/mark:vi_block/get-selection { 6600 local sub_ranges sub_x1 sub_x2 6601 ble/keymap:vi/extract-block 6602 6603 selection=() 6604 local sub 6605 for sub in "${sub_ranges[@]}"; do 6606 ble/string#split sub : "$sub" 6607 ((sub[0]<sub[1])) || continue 6608 ble/array#push selection "${sub[0]}" "${sub[1]}" 6609 done 6610 } 6611 function ble/highlight/layer:region/mark:vi_char+/get-selection { 6612 ble/highlight/layer:region/mark:vi_char/get-selection 6613 } 6614 function ble/highlight/layer:region/mark:vi_line+/get-selection { 6615 ble/highlight/layer:region/mark:vi_line/get-selection 6616 } 6617 function ble/highlight/layer:region/mark:vi_block+/get-selection { 6618 ble/highlight/layer:region/mark:vi_block/get-selection 6619 } 6620 6621 function ble/highlight/layer:region/mark:vi_char/get-face { [[ $_ble_edit_overwrite_mode ]] && face=region_target; } 6622 function ble/highlight/layer:region/mark:vi_char+/get-face { ble/highlight/layer:region/mark:vi_char/get-face; } 6623 function ble/highlight/layer:region/mark:vi_line/get-face { ble/highlight/layer:region/mark:vi_char/get-face; } 6624 function ble/highlight/layer:region/mark:vi_line+/get-face { ble/highlight/layer:region/mark:vi_char/get-face; } 6625 function ble/highlight/layer:region/mark:vi_block/get-face { ble/highlight/layer:region/mark:vi_char/get-face; } 6626 function ble/highlight/layer:region/mark:vi_block+/get-face { ble/highlight/layer:region/mark:vi_char/get-face; } 6627 6628 6629 #-------------------------------------- 6630 # xmap/前回の選択サイズ 6631 6632 _ble_keymap_vi_xmap_prev_edit=vi_char:1:1 6633 ble/array#push _ble_textarea_local_VARNAMES \ 6634 _ble_keymap_vi_xmap_prev_edit 6635 function ble/widget/vi_xmap/.save-visual-state { 6636 local nline nchar mark_type=${_ble_edit_mark_active%+} 6637 if [[ $mark_type == vi_block ]]; then 6638 local p0 q0 lx rx ly ry 6639 if ble/edit/use-textmap; then 6640 local cols=$_ble_textmap_cols 6641 ble/keymap:vi/get-graphical-rectangle 6642 ((lx+=ly*cols,rx+=ry*cols)) 6643 else 6644 ble/keymap:vi/get-logical-rectangle 6645 fi 6646 6647 nchar=$((rx-lx)) 6648 6649 local ret 6650 ((p0<=q0)) || local p0=$q0 q0=$p0 6651 ble/string#count-char "${_ble_edit_str:p0:q0-p0}" $'\n' 6652 nline=$((ret+1)) 6653 6654 else 6655 local ret 6656 local p=$_ble_edit_mark q=$_ble_edit_ind 6657 ((p<=q)) || local p=$q q=$p 6658 ble/string#count-char "${_ble_edit_str:p:q-p}" $'\n' 6659 nline=$((ret+1)) 6660 6661 local base 6662 if ((nline==1)) && [[ $mark_type != vi_line ]]; then 6663 base=$p 6664 else 6665 ble-edit/content/find-logical-bol "$q"; base=$ret 6666 fi 6667 6668 if ble/edit/use-textmap; then 6669 local cols=$_ble_textmap_cols 6670 local bx by x y 6671 ble/textmap#getxy.cur --prefix=b "$base" 6672 ble/textmap#getxy.cur "$q" 6673 nchar=$((x-bx+(y-by)*cols+1)) 6674 else 6675 nchar=$((q-base+1)) 6676 fi 6677 fi 6678 6679 _ble_keymap_vi_xmap_prev_edit=$_ble_edit_mark_active:$nchar:$nline 6680 } 6681 function ble/widget/vi_xmap/.restore-visual-state { 6682 local arg=$1; ((arg>0)) || arg=1 6683 local prev; ble/string#split prev : "$_ble_keymap_vi_xmap_prev_edit" 6684 _ble_edit_mark_active=${prev[0]:-vi_char} 6685 local nchar=${prev[1]:-1} 6686 local nline=${prev[2]:-1} 6687 ((nchar<1&&(nchar=1),nline<1&&(nline=1))) 6688 6689 local is_x_relative=0 6690 if [[ ${_ble_edit_mark_active%+} == vi_block ]]; then 6691 ((is_x_relative=1,nchar*=arg,nline*=arg)) 6692 elif [[ ${_ble_edit_mark_active%+} == vi_line ]]; then 6693 ((nline*=arg,is_x_relative=1,nchar=1)) 6694 else 6695 ((nline==1?(is_x_relative=1,nchar*=arg):(nline*=arg))) 6696 fi 6697 ((nchar--,nline--)) 6698 6699 local index ret 6700 ble-edit/content/find-logical-bol "$_ble_edit_ind" 0; local b1=$ret 6701 ble-edit/content/find-logical-bol "$_ble_edit_ind" "$nline"; local b2=$ret 6702 ble-edit/content/find-logical-eol "$b2"; local e2=$ret 6703 if ble/keymap:vi/xmap/has-eol-extension; then 6704 index=$e2 6705 elif ble/edit/use-textmap; then 6706 local cols=$_ble_textmap_cols 6707 local b1x b1y b2x b2y x y 6708 ble/textmap#getxy.out --prefix=b1 "$b1" 6709 ble/textmap#getxy.out --prefix=b2 "$b2" 6710 if ((is_x_relative)); then 6711 ble/textmap#getxy.out "$_ble_edit_ind" 6712 local c=$((x+(y-b1y)*cols+nchar)) 6713 else 6714 local c=$nchar 6715 fi 6716 ((y=c/cols,x=c%cols)) 6717 6718 local lx ly rx ry 6719 ble/textmap#hit out "$x" "$((b2y+y))" "$b2" "$e2" 6720 else 6721 local c=$((is_x_relative?_ble_edit_ind-b1+nchar:nchar)) 6722 ((index=b2+c,index>e2&&(index=e2))) 6723 fi 6724 6725 _ble_edit_mark=$_ble_edit_ind 6726 _ble_edit_ind=$index 6727 } 6728 6729 #-------------------------------------- 6730 # xmap/前回の選択範囲 6731 6732 # mark `< `> 6733 _ble_keymap_vi_xmap_prev_visual= 6734 ble/array#push _ble_textarea_local_VARNAMES \ 6735 _ble_keymap_vi_xmap_prev_visual 6736 function ble/keymap:vi/xmap/set-previous-visual-area { 6737 local beg end 6738 local mark_type=${_ble_edit_mark_active%+} 6739 if [[ $mark_type == vi_block ]]; then 6740 local sub_ranges sub_x1 sub_x2 6741 ble/keymap:vi/extract-block 6742 local nrange=${#sub_ranges[*]} 6743 ((nrange)) || return 1 6744 local beg=${sub_ranges[0]%%:*} 6745 local sub2_slice1=${sub_ranges[nrange-1]#*:} 6746 local end=${sub2_slice1%%:*} 6747 ((beg<end)) && ! ble-edit/content/bolp "$end" && ((end--)) 6748 else 6749 local beg=$_ble_edit_mark end=$_ble_edit_ind 6750 ((beg<=end)) || local beg=$end end=$beg 6751 if [[ $mark_type == vi_line ]]; then 6752 local ret 6753 ble-edit/content/find-logical-bol "$beg"; beg=$ret 6754 ble-edit/content/find-logical-eol "$end"; end=$ret 6755 ble-edit/content/bolp "$end" || ((end--)) 6756 fi 6757 fi 6758 _ble_keymap_vi_xmap_prev_visual=$_ble_edit_mark_active 6759 ble/keymap:vi/mark/set-local-mark 60 "$beg" # `< 6760 ble/keymap:vi/mark/set-local-mark 62 "$end" # `> 6761 } 6762 # nmap/xmap gv 6763 function ble/widget/vi-command/previous-visual-area { 6764 local mark=$_ble_keymap_vi_xmap_prev_visual 6765 local ret beg= end= 6766 ble/keymap:vi/mark/get-local-mark 60 && beg=$ret # `< 6767 ble/keymap:vi/mark/get-local-mark 62 && end=$ret # `> 6768 [[ $beg && $end ]] || return 1 6769 6770 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 6771 ble/keymap:vi/clear-arg 6772 ble/keymap:vi/xmap/set-previous-visual-area 6773 _ble_edit_ind=$end 6774 _ble_edit_mark=$beg 6775 _ble_edit_mark_active=$mark 6776 ble/keymap:vi/update-mode-indicator 6777 else 6778 ble/keymap:vi/clear-arg 6779 ble/widget/vi-command/visual-mode.impl vi_xmap "$mark" 6780 _ble_edit_ind=$end 6781 _ble_edit_mark=$beg 6782 fi 6783 return 0 6784 } 6785 6786 #-------------------------------------- 6787 # xmap/モード遷移 6788 6789 function ble/widget/vi-command/visual-mode.impl { 6790 local keymap=$1 visual_type=$2 6791 local ARG FLAG REG; ble/keymap:vi/get-arg 0 6792 if [[ $FLAG ]]; then 6793 ble/widget/vi-command/bell 6794 return 1 6795 fi 6796 6797 _ble_edit_overwrite_mode= 6798 _ble_edit_mark=$_ble_edit_ind 6799 _ble_edit_mark_active=$visual_type 6800 _ble_keymap_vi_xmap_insert_data= # ※矩形挿入の途中で更に xmap に入ったときはキャンセル 6801 6802 ((ARG)) && ble/widget/vi_xmap/.restore-visual-state "$ARG" 6803 6804 ble/decode/keymap/push "$keymap" 6805 ble/keymap:vi/update-mode-indicator 6806 return 0 6807 } 6808 function ble/widget/vi_nmap/charwise-visual-mode { 6809 ble/widget/vi-command/visual-mode.impl vi_xmap vi_char 6810 } 6811 function ble/widget/vi_nmap/linewise-visual-mode { 6812 ble/widget/vi-command/visual-mode.impl vi_xmap vi_line 6813 } 6814 function ble/widget/vi_nmap/blockwise-visual-mode { 6815 ble/widget/vi-command/visual-mode.impl vi_xmap vi_block 6816 } 6817 function ble/widget/vi_nmap/charwise-select-mode { 6818 ble/widget/vi-command/visual-mode.impl vi_smap vi_char 6819 } 6820 function ble/widget/vi_nmap/linewise-select-mode { 6821 ble/widget/vi-command/visual-mode.impl vi_smap vi_line 6822 } 6823 function ble/widget/vi_nmap/blockwise-select-mode { 6824 ble/widget/vi-command/visual-mode.impl vi_smap vi_block 6825 } 6826 6827 function ble/widget/vi_xmap/exit { 6828 # Note: xmap operator:c 6829 # -> vi_xmap/block-insert-mode.impl 6830 # → vi_xmap/cancel 経由で呼び出されるとき、 6831 # 既に vi_nmap に戻っていることがあるので、vi_xmap, vi_smap のときだけ処理する。 6832 if [[ $_ble_decode_keymap == vi_[xs]map ]]; then 6833 ble/keymap:vi/xmap/set-previous-visual-area 6834 _ble_edit_mark_active= 6835 ble/decode/keymap/pop 6836 ble/keymap:vi/update-mode-indicator 6837 ble/keymap:vi/adjust-command-mode 6838 fi 6839 return 0 6840 } 6841 function ble/widget/vi_xmap/cancel { 6842 # もし single-command-mode にいたとしても消去して normal へ移動する 6843 6844 _ble_keymap_vi_single_command= 6845 _ble_keymap_vi_single_command_overwrite= 6846 ble-edit/content/nonbol-eolp && ((_ble_edit_ind--)) 6847 ble/widget/vi_xmap/exit 6848 } 6849 function ble/widget/vi_xmap/switch-visual-mode.impl { 6850 local visual_type=$1 6851 local ARG FLAG REG; ble/keymap:vi/get-arg 0 6852 if [[ $FLAG ]]; then 6853 ble/widget/.bell 6854 return 1 6855 fi 6856 6857 if [[ ${_ble_edit_mark_active%+} == "$visual_type" ]]; then 6858 ble/widget/vi_xmap/cancel 6859 else 6860 ble/keymap:vi/xmap/switch-type "$visual_type" 6861 ble/keymap:vi/update-mode-indicator 6862 return 0 6863 fi 6864 6865 } 6866 # xmap v 6867 function ble/widget/vi_xmap/switch-to-charwise { 6868 ble/widget/vi_xmap/switch-visual-mode.impl vi_char 6869 } 6870 # xmap V 6871 function ble/widget/vi_xmap/switch-to-linewise { 6872 ble/widget/vi_xmap/switch-visual-mode.impl vi_line 6873 } 6874 # xmap <C-v> 6875 function ble/widget/vi_xmap/switch-to-blockwise { 6876 ble/widget/vi_xmap/switch-visual-mode.impl vi_block 6877 } 6878 # xmap <C-g> 6879 function ble/widget/vi_xmap/switch-to-select { 6880 if [[ $_ble_decode_keymap == vi_xmap ]]; then 6881 ble/decode/keymap/pop 6882 ble/decode/keymap/push vi_smap 6883 ble/keymap:vi/update-mode-indicator 6884 fi 6885 } 6886 # smap <C-g> 6887 function ble/widget/vi_xmap/switch-to-visual { 6888 if [[ $_ble_decode_keymap == vi_smap ]]; then 6889 ble/decode/keymap/pop 6890 ble/decode/keymap/push vi_xmap 6891 ble/keymap:vi/update-mode-indicator 6892 fi 6893 } 6894 # smap <C-v> 6895 function ble/widget/vi_xmap/switch-to-visual-blockwise { 6896 if [[ $_ble_decode_keymap == vi_smap ]]; then 6897 ble/decode/keymap/pop 6898 ble/decode/keymap/push vi_xmap 6899 fi 6900 if [[ ${_ble_edit_mark_active%+} != vi_block ]]; then 6901 ble/widget/vi_xmap/switch-to-blockwise 6902 else 6903 xble/keymap:vi/update-mode-indicator 6904 fi 6905 } 6906 6907 ## @bleopt keymap_vi_keymodel 6908 ## 選択モードにおける移動コマンドの振る舞いを制御します。 6909 bleopt/declare -v keymap_vi_keymodel '' 6910 function ble/widget/vi_smap/@nomarked { 6911 [[ ,$bleopt_keymap_vi_keymodel, == *,stopsel,* ]] && 6912 ble/widget/vi_xmap/exit 6913 ble/widget/"$@" 6914 } 6915 6916 #-------------------------------------- 6917 # xmap/各種コマンド 6918 6919 function ble/widget/vi_smap/self-insert { 6920 # Note: repeat (nmap .) についてはこの実装で良い。 6921 # KEYS=(...) vi_smap/self-insert として記録されるので。 6922 ble/widget/vi-command/operator c 6923 ble/widget/self-insert 6924 } 6925 6926 # xmap o 6927 function ble/widget/vi_xmap/exchange-points { 6928 ble/keymap:vi/xmap/remove-eol-extension 6929 ble/widget/exchange-point-and-mark 6930 return 0 6931 } 6932 # xmap O 6933 function ble/widget/vi_xmap/exchange-boundaries { 6934 if [[ ${_ble_edit_mark_active%+} == vi_block ]]; then 6935 ble/keymap:vi/xmap/remove-eol-extension 6936 6937 local sub_ranges sub_x1 sub_x2 6938 ble/keymap:vi/extract-block '' '' skip_middle 6939 local nline=${#sub_ranges[@]} 6940 ble/util/assert '((nline))' 6941 6942 local data1; ble/string#split data1 : "${sub_ranges[0]}" 6943 local lpos1=${data1[0]} rpos1=$((data1[4]?data1[1]:data1[1]-1)) 6944 if ((nline==1)); then 6945 local lpos2=$lpos1 rpos2=$rpos1 6946 else 6947 local data2; ble/string#split data2 : "${sub_ranges[nline-1]}" 6948 local lpos2=${data2[0]} rpos2=$((data2[4]?data2[1]:data2[1]-1)) 6949 fi 6950 6951 # lpos2:rpos2 が _ble_edit_ind に対応していないとき swap する 6952 if ! ((lpos2<=_ble_edit_ind&&_ble_edit_ind<=rpos2)); then 6953 local lpos1=$lpos2 lpos2=$lpos1 6954 local rpos1=$rpos2 rpos2=$rpos1 6955 fi 6956 6957 _ble_edit_mark=$((_ble_edit_mark==lpos1?rpos1:lpos1)) 6958 _ble_edit_ind=$((_ble_edit_ind==lpos2?rpos2:lpos2)) 6959 return 0 6960 else 6961 ble/widget/vi_xmap/exchange-points 6962 fi 6963 } 6964 6965 # xmap r{char} 6966 function ble/widget/vi_xmap/visual-replace-char.hook { 6967 local key=$1 6968 _ble_edit_overwrite_mode= 6969 local ARG FLAG REG; ble/keymap:vi/get-arg 1 6970 6971 local ret 6972 if [[ $FLAG ]]; then 6973 ble/widget/.bell 6974 return 1 6975 elif ((key==(_ble_decode_Ctrl|91))); then # C-[ -> cancel 6976 return 27 6977 elif ! ble/keymap:vi/k2c "$key"; then 6978 ble/widget/.bell 6979 return 1 6980 fi 6981 local c=$ret 6982 ble/util/c2s "$c"; local s=$ret 6983 6984 local old_mark_active=$_ble_edit_mark_active # save 6985 local mark_type=${_ble_edit_mark_active%+} 6986 ble/widget/vi_xmap/.save-visual-state 6987 ble/widget/vi_xmap/exit # Note: _ble_edit_mark_active will be cleared here 6988 if [[ $mark_type == vi_block ]]; then 6989 ble/util/c2w "$c"; local w=$ret 6990 ((w<=0)) && w=1 6991 6992 local sub_ranges sub_x1 sub_x2 6993 _ble_edit_mark_active=$old_mark_active ble/keymap:vi/extract-block 6994 local n=${#sub_ranges[@]} 6995 if ((n==0)); then 6996 ble/widget/.bell 6997 return 1 6998 fi 6999 7000 # create ins 7001 local width=$((sub_x2-sub_x1)) 7002 local count=$((width/w)) 7003 ble/string#repeat "$s" "$count"; local ins=$ret 7004 local pad=$((width-count*w)) 7005 if ((pad)); then 7006 ble/string#repeat ' ' "$pad"; ins=$ins$ret 7007 fi 7008 7009 local i=$n sub smin=0 7010 ble/keymap:vi/mark/start-edit-area 7011 while ((i--)); do 7012 ble/string#split sub : "${sub_ranges[i]}" 7013 local smin=${sub[0]} smax=${sub[1]} 7014 local slpad=${sub[2]} srpad=${sub[3]} sfill=${sub[4]} 7015 7016 local ins1=$ins 7017 ((sfill)) && ins1=${ins1::(width-sfill)/w} 7018 ((slpad)) && { ble/string#repeat ' ' "$slpad"; ins1=$ret$ins1; } 7019 ((srpad)) && { ble/string#repeat ' ' "$srpad"; ins1=$ins1$ret; } 7020 ble/widget/.replace-range "$smin" "$smax" "$ins1" 7021 done 7022 local beg=$smin 7023 ble/keymap:vi/needs-eol-fix "$beg" && ((beg--)) 7024 _ble_edit_ind=$beg 7025 ble/keymap:vi/mark/end-edit-area 7026 ble/keymap:vi/repeat/record 7027 else 7028 local beg=$_ble_edit_mark end=$_ble_edit_ind 7029 ((beg<=end)) || local beg=$end end=$beg 7030 if [[ $mark_type == vi_line ]]; then 7031 ble-edit/content/find-logical-bol "$beg"; local beg=$ret 7032 ble-edit/content/find-logical-eol "$end"; local end=$ret 7033 else 7034 ble-edit/content/eolp "$end" || ((end++)) 7035 fi 7036 7037 local ins=${_ble_edit_str:beg:end-beg} 7038 ins=${ins//[!$'\n']/"$s"} 7039 ble/widget/.replace-range "$beg" "$end" "$ins" 7040 ble/keymap:vi/needs-eol-fix "$beg" && ((beg--)) 7041 _ble_edit_ind=$beg 7042 ble/keymap:vi/mark/set-previous-edit-area "$beg" "$end" 7043 ble/keymap:vi/repeat/record 7044 fi 7045 return 0 7046 } 7047 function ble/widget/vi_xmap/visual-replace-char { 7048 _ble_edit_overwrite_mode=R 7049 ble/keymap:vi/async-read-char ble/widget/vi_xmap/visual-replace-char.hook 7050 } 7051 7052 function ble/widget/vi_xmap/linewise-operator.impl { 7053 local op=$1 opts=$2 7054 local ARG FLAG REG; ble/keymap:vi/get-arg 1 7055 if [[ $FLAG ]]; then 7056 ble/widget/.bell 'wrong keymap: xmap ではオペレータは設定されないはず' 7057 return 1 7058 fi 7059 7060 local mark_type=${_ble_edit_mark_active%+} 7061 local beg=$_ble_edit_mark end=$_ble_edit_ind 7062 ((beg<=end)) || local beg=$end end=$beg 7063 7064 local call_operator= 7065 if [[ :$opts: != *:force_line:* && $mark_type == vi_block ]]; then 7066 call_operator=ble/keymap:vi/call-operator-blockwise 7067 _ble_edit_mark_active=vi_block 7068 [[ :$opts: == *:extend:* ]] && _ble_edit_mark_active=vi_block+ 7069 else 7070 call_operator=ble/keymap:vi/call-operator-linewise 7071 _ble_edit_mark_active=vi_line 7072 fi 7073 7074 local ble_keymap_vi_mark_active=$_ble_edit_mark_active 7075 ble/widget/vi_xmap/.save-visual-state 7076 ble/widget/vi_xmap/exit 7077 "$call_operator" "$op" "$beg" "$end" "$ARG" "$REG"; local ext=$? 7078 ((ext==147)) && return 147 7079 ((ext)) && ble/widget/.bell 7080 ble/keymap:vi/adjust-command-mode 7081 return "$ext" 7082 } 7083 7084 # xmap C 7085 function ble/widget/vi_xmap/replace-block-lines { ble/widget/vi_xmap/linewise-operator.impl c extend; } 7086 # xmap D X 7087 function ble/widget/vi_xmap/delete-block-lines { ble/widget/vi_xmap/linewise-operator.impl d extend; } 7088 # xmap R S 7089 function ble/widget/vi_xmap/delete-lines { ble/widget/vi_xmap/linewise-operator.impl d force_line; } 7090 # xmap Y 7091 function ble/widget/vi_xmap/copy-block-or-lines { ble/widget/vi_xmap/linewise-operator.impl y; } 7092 7093 function ble/widget/vi_xmap/connect-line.impl { 7094 local name=$1 7095 local ARG FLAG REG; ble/keymap:vi/get-arg 1 # ignored 7096 7097 local beg=$_ble_edit_mark end=$_ble_edit_ind 7098 ((beg<=end)) || local beg=$end end=$beg 7099 local ret; ble/string#count-char "${_ble_edit_str:beg:end-beg}" $'\n'; local nline=$((ret+1)) 7100 7101 ble/widget/vi_xmap/.save-visual-state 7102 ble/widget/vi_xmap/exit # Note: _ble_edit_mark_active will be cleared here 7103 7104 _ble_edit_ind=$beg 7105 _ble_edit_arg=$nline 7106 _ble_keymap_vi_oparg= 7107 _ble_keymap_vi_opfunc= 7108 _ble_keymap_vi_reg= 7109 "ble/widget/$name" 7110 } 7111 # xmap J 7112 function ble/widget/vi_xmap/connect-line-with-space { 7113 ble/widget/vi_xmap/connect-line.impl vi_nmap/connect-line-with-space 7114 } 7115 # xmap gJ 7116 function ble/widget/vi_xmap/connect-line { 7117 ble/widget/vi_xmap/connect-line.impl vi_nmap/connect-line 7118 } 7119 7120 #-------------------------------------- 7121 # xmap/矩形挿入モード 7122 7123 ## @var _ble_keymap_vi_xmap_insert_data 7124 ## 矩形挿入モードの情報を保持します。 7125 ## iline:x1:width:content の形式です。 7126 ## 7127 ## iline 7128 ## 編集を行う行の番号を保持します。 7129 ## x1 7130 ## 挿入開始位置を表示列で保持します。 7131 ## width 7132 ## 編集行の元々の幅を保持します。 7133 ## nline 7134 ## 行数を保持します。 7135 ## 7136 _ble_keymap_vi_xmap_insert_data= 7137 _ble_keymap_vi_xmap_insert_dbeg=-1 7138 ble/array#push _ble_textarea_local_VARNAMES \ 7139 _ble_keymap_vi_xmap_insert_data \ 7140 _ble_keymap_vi_xmap_insert_dbeg 7141 function ble/keymap:vi/xmap/update-dirty-range { 7142 [[ $_ble_keymap_vi_insert_leave == ble/widget/vi_xmap/block-insert-mode.onleave ]] && 7143 ((_ble_keymap_vi_xmap_insert_dbeg<0||beg<_ble_keymap_vi_xmap_insert_dbeg)) && 7144 _ble_keymap_vi_xmap_insert_dbeg=$beg 7145 } 7146 7147 ## @fn ble/widget/vi_xmap/block-insert-mode.impl 7148 ## @var[in] sub_ranges sub_x1 sub_x2 7149 function ble/widget/vi_xmap/block-insert-mode.impl { 7150 local type=$1 7151 local ARG FLAG REG; ble/keymap:vi/get-arg 1 7152 7153 local nline=${#sub_ranges[@]} 7154 ble/util/assert '((nline))' 7155 7156 local index ins_x 7157 if [[ $type == append ]]; then 7158 local sub=${sub_ranges[0]#*:} 7159 local smax=${sub%%:*} 7160 index=$smax 7161 if ble/keymap:vi/xmap/has-eol-extension; then 7162 ins_x='$' 7163 else 7164 ins_x=$sub_x2 7165 fi 7166 else 7167 local sub=${sub_ranges[0]} 7168 local smin=${sub%%:*} 7169 index=$smin 7170 ins_x=$sub_x1 7171 fi 7172 7173 ble/widget/vi_xmap/cancel 7174 _ble_edit_ind=$index 7175 ble/widget/vi_nmap/.insert-mode "$ARG" 7176 ble/keymap:vi/repeat/record 7177 ble/keymap:vi/mark/set-local-mark 1 "$_ble_edit_ind" 7178 _ble_keymap_vi_xmap_insert_dbeg=-1 7179 7180 local ret display_width 7181 ble/string#count-char "${_ble_edit_str::_ble_edit_ind}" $'\n'; local iline=$ret 7182 ble-edit/content/find-logical-bol; local bol=$ret 7183 ble-edit/content/find-logical-eol; local eol=$ret 7184 if ble/edit/use-textmap; then 7185 local bx by ex ey 7186 ble/textmap#getxy.out --prefix=b "$bol" 7187 ble/textmap#getxy.out --prefix=e "$eol" 7188 ((display_width=ex+_ble_textmap_cols*(ey-by))) 7189 else 7190 ((display_width=eol-bol)) 7191 fi 7192 _ble_keymap_vi_xmap_insert_data=$iline:$ins_x:$display_width:$nline 7193 _ble_keymap_vi_insert_leave=ble/widget/vi_xmap/block-insert-mode.onleave 7194 return 0 7195 } 7196 function ble/widget/vi_xmap/block-insert-mode.onleave { 7197 local data=$_ble_keymap_vi_xmap_insert_data 7198 [[ $data ]] || continue 7199 _ble_keymap_vi_xmap_insert_data= 7200 7201 ble/string#split data : "$data" 7202 7203 # カーソル行が記録行と同じか 7204 local ret 7205 ble-edit/content/find-logical-bol; local bol=$ret 7206 ble/string#count-char "${_ble_edit_str::bol}" $'\n'; ((ret==data[0])) || return 1 # 行番号 7207 ble/keymap:vi/mark/get-local-mark 1 || return 1; local mark=$ret # `[ 7208 ble-edit/content/find-logical-bol "$mark"; ((bol==ret)) || return 1 # 記録行 `[ と同じか 7209 7210 local has_textmap= 7211 if ble/edit/use-textmap; then 7212 local cols=$_ble_textmap_cols 7213 has_textmap=1 7214 fi 7215 7216 # 表示幅の変量 7217 local new_width delta 7218 ble-edit/content/find-logical-eol; local eol=$ret 7219 if [[ $has_textmap ]]; then 7220 local bx by ex ey 7221 ble/textmap#getxy.out --prefix=b "$bol" 7222 ble/textmap#getxy.out --prefix=e "$eol" 7223 ((new_width=ex+cols*(ey-by))) 7224 else 7225 ((new_width=eol-bol)) 7226 fi 7227 ((delta=new_width-data[2])) 7228 ((delta>0)) || return 1 # 縮んだ場合は処理しない 7229 7230 # 切り出し列の決定 7231 local x1=${data[1]} 7232 [[ $x1 == '$' ]] && ((x1=data[2])) 7233 ((x1>new_width&&(x1=new_width))) 7234 if ((bol<=_ble_keymap_vi_xmap_insert_dbeg&&_ble_keymap_vi_xmap_insert_dbeg<=eol)); then 7235 local px py 7236 if [[ $has_textmap ]]; then 7237 ble/textmap#getxy.out --prefix=p "$_ble_keymap_vi_xmap_insert_dbeg" 7238 ((px+=cols*(py-by))) 7239 else 7240 ((px=_ble_keymap_vi_xmap_insert_dbeg-bol)) 7241 fi 7242 ((px>x1&&(x1=px))) 7243 fi 7244 local x2=$((x1+delta)) 7245 7246 # 切り出し 7247 local ins= p1 p2 7248 if [[ $has_textmap ]]; then 7249 local index lx ly rx ry 7250 ble/textmap#hit out "$((x1%cols))" "$((by+x1/cols))" "$bol" "$eol"; p1=$index 7251 ble/textmap#hit out "$((x2%cols))" "$((by+x2/cols))" "$bol" "$eol"; p2=$index 7252 ((lx+=(ly-by)*cols,rx+=(ry-by)*cols,lx!=rx&&p2++)) 7253 else 7254 ((p1=bol+x1,p2=bol+x2)) 7255 fi 7256 ins=${_ble_edit_str:p1:p2-p1} 7257 7258 # 挿入の決定 7259 local -a ins_beg=() ins_text=() 7260 local iline=1 nline=${data[3]} strlen=${#_ble_edit_str} 7261 for ((iline=1;iline<nline;iline++)); do 7262 local index= lpad= 7263 if ((eol<strlen)); then 7264 bol=$((eol+1)) 7265 ble-edit/content/find-logical-eol "$bol"; eol=$ret 7266 else 7267 bol=$eol lpad=$'\n' 7268 fi 7269 7270 if [[ ${data[1]} == '$' ]]; then 7271 index=$eol 7272 elif [[ $has_textmap ]]; then 7273 ble/textmap#getxy.out --prefix=b "$bol" 7274 ble/textmap#hit out "$((x1%cols))" "$((by+x1/cols))" "$bol" "$eol" # -> index 7275 7276 local nfill 7277 if ((index==eol&&(nfill=x1-lx+(ly-by)*cols)>0)); then 7278 ble/string#repeat ' ' "$nfill"; lpad=$lpad$ret 7279 fi 7280 else 7281 index=$((bol+x1)) 7282 if ((index>eol)); then 7283 ble/string#repeat ' ' "$((index-eol))"; lpad=$lpad$ret 7284 ((index=eol)) 7285 fi 7286 fi 7287 7288 ble/array#push ins_beg "$index" 7289 ble/array#push ins_text "$lpad$ins" 7290 done 7291 7292 # 挿入実行 7293 local i=${#ins_beg[@]} 7294 ble/keymap:vi/mark/start-edit-area 7295 ble/keymap:vi/mark/commit-edit-area "$p1" "$p2" 7296 while ((i--)); do 7297 local index=${ins_beg[i]} text=${ins_text[i]} 7298 ble/widget/.replace-range "$index" "$index" "$text" 7299 done 7300 ble/keymap:vi/mark/end-edit-area 7301 # Note: この編集は record-insert 経由で記録されるので 7302 # ここで明示的に ble/keymap:vi/repeat/record を呼び出す必要はない。 7303 7304 # 領域の最初に 7305 local index 7306 if ble/keymap:vi/mark/get-local-mark 60 && index=$ret; then 7307 ble/widget/vi-command/goto-mark.impl "$index" 7308 else 7309 ble-edit/content/find-logical-bol; index=$ret 7310 fi 7311 7312 # ノーマルモードに戻る時に一文字カーソルが戻るので一文字進めておく。 7313 ble-edit/content/eolp || ((index++)) 7314 _ble_edit_ind=$index 7315 return 0 7316 } 7317 # xmap I 7318 function ble/widget/vi_xmap/insert-mode { 7319 local mark_type=${_ble_edit_mark_active%+} 7320 if [[ $mark_type == vi_block ]]; then 7321 local sub_ranges sub_x1 sub_x2 7322 ble/keymap:vi/extract-block '' '' first_line 7323 ble/widget/vi_xmap/block-insert-mode.impl insert 7324 else 7325 local ARG FLAG REG; ble/keymap:vi/get-arg 1 7326 7327 local beg=$_ble_edit_mark end=$_ble_edit_ind 7328 ((beg<=end)) || local beg=$end end=$beg 7329 if [[ $mark_type == vi_line ]]; then 7330 local ret 7331 ble-edit/content/find-logical-bol "$beg"; beg=$ret 7332 fi 7333 7334 ble/widget/vi_xmap/cancel 7335 _ble_edit_ind=$beg 7336 ble/widget/vi_nmap/.insert-mode "$ARG" 7337 ble/keymap:vi/repeat/record 7338 return 0 7339 fi 7340 } 7341 # xmap A 7342 function ble/widget/vi_xmap/append-mode { 7343 local mark_type=${_ble_edit_mark_active%+} 7344 if [[ $mark_type == vi_block ]]; then 7345 local sub_ranges sub_x1 sub_x2 7346 ble/keymap:vi/extract-block '' '' first_line 7347 ble/widget/vi_xmap/block-insert-mode.impl append 7348 else 7349 local ARG FLAG REG; ble/keymap:vi/get-arg 1 7350 7351 local beg=$_ble_edit_mark end=$_ble_edit_ind 7352 ((beg<=end)) || local beg=$end end=$beg 7353 if [[ $mark_type == vi_line ]]; then 7354 # 行指向のときは最終行の先頭か _ble_edit_ind の内、 7355 # 後にある文字の後に移動する。 7356 if ((_ble_edit_mark>_ble_edit_ind)); then 7357 local ret 7358 ble-edit/content/find-logical-bol "$end"; end=$ret 7359 fi 7360 fi 7361 ble-edit/content/eolp "$end" || ((end++)) 7362 7363 ble/widget/vi_xmap/cancel 7364 _ble_edit_ind=$end 7365 ble/widget/vi_nmap/.insert-mode "$ARG" 7366 ble/keymap:vi/repeat/record 7367 return 0 7368 fi 7369 } 7370 7371 #-------------------------------------- 7372 # xmap/貼り付け 7373 7374 # xmap: p, P 7375 function ble/widget/vi_xmap/paste.impl { 7376 local opts=$1 7377 [[ :$opts: != *:after:* ]]; local is_after=$? 7378 7379 local ARG FLAG REG; ble/keymap:vi/get-arg 1 7380 [[ $REG ]] && ble/keymap:vi/register#load "$REG" 7381 7382 local mark_type=${_ble_edit_mark_active%+} 7383 local kill_ring=$_ble_edit_kill_ring 7384 local kill_type=$_ble_edit_kill_type 7385 7386 local adjustment= 7387 if [[ $mark_type == vi_block ]]; then 7388 if [[ $kill_type == L ]]; then 7389 # P: V → C-v のときは C-v の最終行直後に挿入 7390 if ((is_after)); then 7391 local ret; ble/keymap:vi/get-rectangle-height; local nline=$ret 7392 adjustment=lastline:$nline 7393 fi 7394 elif [[ $kill_type == B:* ]]; then 7395 # C-v → C-v 7396 is_after=0 7397 else 7398 # 単純 v → C-v はブロック挿入に切り替え 7399 is_after=0 7400 if [[ $kill_ring != *$'\n'* ]]; then 7401 ((${#kill_ring}>=2)) && adjustment=index:$((${#kill_ring}*ARG-1)) 7402 local ret; ble/keymap:vi/get-rectangle-height; local nline=$ret 7403 ble/string#repeat "$kill_ring"$'\n' "$nline"; kill_ring=${ret%$'\n'} 7404 ble/string#repeat '0 ' "$nline"; kill_type=B:${ret% } 7405 fi 7406 fi 7407 elif [[ $mark_type == vi_line ]]; then 7408 if [[ $kill_type == L ]]; then 7409 # V → V のとき 7410 is_after=0 7411 elif [[ $kill_type == B:* ]]; then 7412 # C-v → V のとき、行貼り付け。 7413 # kill_type=B:* のとき kill_ring の末端の改行は空行を意味するので、 7414 # 空行が消えないように $'\n' を付加する必要がある。 7415 is_after=0 kill_type=L kill_ring=$kill_ring$'\n' 7416 else 7417 # v → V のとき、行貼り付けになる。 7418 is_after=0 kill_type=L 7419 [[ $kill_ring == *$'\n' ]] && kill_ring=$kill_ring$'\n' 7420 fi 7421 else 7422 # v, V, C-v → v のとき 7423 is_after=0 7424 [[ $kill_type == L ]] && adjustment=newline 7425 fi 7426 7427 ble/keymap:vi/mark/start-edit-area 7428 local _ble_keymap_vi_mark_suppress_edit=1 7429 { 7430 ble/widget/vi-command/operator d; local ext=$? # _ble_edit_kill_{ring,type} is set here 7431 if [[ $adjustment == newline ]]; then 7432 local -a KEYS=(10) 7433 ble/widget/self-insert 7434 elif [[ $adjustment == lastline:* ]]; then 7435 local ret 7436 ble-edit/content/find-logical-bol "$_ble_edit_ind" "$((${adjustment#*:}-1))" 7437 _ble_edit_ind=$ret 7438 fi 7439 local _ble_edit_kill_ring=$kill_ring 7440 local _ble_edit_kill_type=$kill_type 7441 ble/widget/vi_nmap/paste.impl "$ARG" '' "$is_after" 7442 if [[ $adjustment == index:* ]]; then 7443 local index=$((_ble_edit_ind+${adjustment#*:})) 7444 ((index>${#_ble_edit_str}&&(index=${#_ble_edit_str}))) 7445 ble/keymap:vi/needs-eol-fix "$index" && ((index--)) 7446 _ble_edit_ind=$index 7447 fi 7448 } 7449 ble/util/unlocal _ble_keymap_vi_mark_suppress_edit 7450 ble/keymap:vi/mark/end-edit-area 7451 ble/keymap:vi/repeat/record 7452 return "$ext" 7453 } 7454 function ble/widget/vi_xmap/paste-after { 7455 ble/widget/vi_xmap/paste.impl after 7456 } 7457 function ble/widget/vi_xmap/paste-before { 7458 ble/widget/vi_xmap/paste.impl before 7459 } 7460 7461 #-------------------------------------- 7462 # xmap <C-a>, <C-x>, g<C-a>, g<C-x> 7463 7464 ## @fn ble/widget/vi_xmap/increment.impl opts 7465 ## 7466 ## @param[in] opts 7467 ## 以下の項目をコロンで区切って指定したものです。 7468 ## 7469 ## - increase [既定] 7470 ## 数字を増加させます。 7471 ## - decrease 7472 ## 数字を減少させるます。 7473 ## - progressive 7474 ## k 個目の数字について増加・減少量を k 倍します。 7475 ## 7476 function ble/widget/vi_xmap/increment.impl { 7477 local opts=$1 7478 local ARG FLAG REG; ble/keymap:vi/get-arg 1 7479 if [[ $FLAG ]]; then 7480 ble/widget/.bell 7481 return 1 7482 fi 7483 7484 local delta=$ARG 7485 [[ :$opts: == *:decrease:* ]] && ((delta=-delta)) 7486 local progress=0 7487 [[ :$opts: == *:progressive:* ]] && progress=$delta 7488 7489 local old_mark_active=$_ble_edit_mark_active # save 7490 local mark_type=${_ble_edit_mark_active%+} 7491 ble/widget/vi_xmap/.save-visual-state 7492 ble/widget/vi_xmap/exit # Note: _ble_edit_mark_active will be cleared here 7493 if [[ $mark_type == vi_block ]]; then 7494 local sub_ranges sub_x1 sub_x2 7495 _ble_edit_mark_active=$old_mark_active ble/keymap:vi/extract-block 7496 if ((${#sub_ranges[@]}==0)); then 7497 ble/widget/.bell 7498 return 1 7499 fi 7500 else 7501 local beg=$_ble_edit_mark end=$_ble_edit_ind 7502 ((beg<=end)) || local beg=$end end=$beg 7503 if [[ $mark_type == vi_line ]]; then 7504 local ret 7505 ble-edit/content/find-logical-bol "$beg"; local beg=$ret 7506 ble-edit/content/find-logical-eol "$end"; local end=$ret 7507 else 7508 ble-edit/content/eolp "$end" || ((end++)) 7509 fi 7510 7511 local -a lines 7512 ble/string#split-lines lines "${_ble_edit_str:beg:end-beg}" 7513 7514 # sub_ranges 生成 7515 local line index=$beg 7516 local -a sub_ranges 7517 for line in "${lines[@]}"; do 7518 [[ $line ]] && ble/array#push sub_ranges "$index:::::$line" 7519 ((index+=${#line}+1)) 7520 done 7521 7522 ((${#sub_ranges[@]})) || return 0 7523 fi 7524 7525 local sub rex_number='^([^0-9]*)([0-9]+)' shift=0 dmin=-1 dmax=-1 7526 for sub in "${sub_ranges[@]}"; do 7527 local stext=${sub#*:*:*:*:*:} 7528 [[ $stext =~ $rex_number ]] || continue 7529 7530 # 元々の数 7531 local rematch1=${BASH_REMATCH[1]} 7532 local rematch2=${BASH_REMATCH[2]} 7533 local offset=${#rematch1} length=${#rematch2} 7534 local number=$((10#0$rematch2)) 7535 [[ $rematch1 == *- ]] && ((number=-number,offset--,length++)) 7536 7537 # 新しい数 7538 ((number+=delta,delta+=progress)) 7539 if [[ $rematch2 == 0?* ]]; then 7540 # Zero padding 7541 local wsign=$((number<0?1:0)) 7542 local zpad=$((wsign+${#rematch2}-${#number})) 7543 if ((zpad>0)); then 7544 local ret; ble/string#repeat 0 "$zpad" 7545 number=${number::wsign}$ret${number:wsign} 7546 fi 7547 fi 7548 7549 local smin=${sub%%:*} 7550 local beg=$((shift+smin+offset)) 7551 local end=$((beg+length)) 7552 ble/widget/.replace-range "$beg" "$end" "$number" 7553 ((shift+=${#number}-length, 7554 dmin<0&&(dmin=beg), 7555 dmax=beg+${#number})) 7556 done 7557 local beg=${sub_ranges[0]%%:*} 7558 ble/keymap:vi/needs-eol-fix "$beg" && ((beg--)) 7559 _ble_edit_ind=$beg 7560 7561 ((dmin>=0)) && ble/keymap:vi/mark/set-previous-edit-area "$dmin" "$dmax" 7562 ble/keymap:vi/repeat/record 7563 return 0 7564 } 7565 # xmap <C-a> 7566 function ble/widget/vi_xmap/increment { ble/widget/vi_xmap/increment.impl increase; } 7567 # xmap <C-x> 7568 function ble/widget/vi_xmap/decrement { ble/widget/vi_xmap/increment.impl decrease; } 7569 # xmap g<C-a> 7570 function ble/widget/vi_xmap/progressive-increment { ble/widget/vi_xmap/increment.impl progressive:increase; } 7571 # xmap g<C-x> 7572 function ble/widget/vi_xmap/progressive-decrement { ble/widget/vi_xmap/increment.impl progressive:decrease; } 7573 7574 #-------------------------------------- 7575 7576 function ble-decode/keymap:vi_xmap/define { 7577 ble/keymap:vi/set-up-command-map 7578 7579 ble-bind -f __default__ vi-command/decompose-meta 7580 7581 ble-bind -f 'ESC' vi_xmap/exit 7582 ble-bind -f 'C-[' vi_xmap/exit 7583 ble-bind -f 'C-c' vi_xmap/cancel 7584 7585 ble-bind -f '"' vi-command/register 7586 7587 ble-bind -f a vi-command/text-object 7588 ble-bind -f i vi-command/text-object 7589 7590 ble-bind -f 'C-\ C-n' vi_xmap/cancel 7591 ble-bind -f 'C-\ C-g' vi_xmap/cancel 7592 ble-bind -f v vi_xmap/switch-to-charwise 7593 ble-bind -f V vi_xmap/switch-to-linewise 7594 ble-bind -f C-v vi_xmap/switch-to-blockwise 7595 ble-bind -f C-q vi_xmap/switch-to-blockwise 7596 ble-bind -f 'g v' vi-command/previous-visual-area 7597 ble-bind -f C-g vi_xmap/switch-to-select 7598 7599 ble-bind -f o vi_xmap/exchange-points 7600 ble-bind -f O vi_xmap/exchange-boundaries 7601 7602 ble-bind -f '~' 'vi-command/operator toggle_case' 7603 ble-bind -f 'u' 'vi-command/operator u' 7604 ble-bind -f 'U' 'vi-command/operator U' 7605 7606 ble-bind -f 's' 'vi-command/operator c' 7607 ble-bind -f 'x' 'vi-command/operator d' 7608 ble-bind -f delete 'vi-command/operator d' 7609 7610 ble-bind -f r vi_xmap/visual-replace-char 7611 7612 ble-bind -f C vi_xmap/replace-block-lines 7613 ble-bind -f D vi_xmap/delete-block-lines 7614 ble-bind -f X vi_xmap/delete-block-lines 7615 ble-bind -f S vi_xmap/delete-lines 7616 ble-bind -f R vi_xmap/delete-lines 7617 ble-bind -f Y vi_xmap/copy-block-or-lines 7618 ble-bind -f J vi_xmap/connect-line-with-space 7619 ble-bind -f 'g J' vi_xmap/connect-line 7620 7621 ble-bind -f I vi_xmap/insert-mode 7622 ble-bind -f A vi_xmap/append-mode 7623 ble-bind -f p vi_xmap/paste-after 7624 ble-bind -f P vi_xmap/paste-before 7625 7626 ble-bind -f 'C-a' vi_xmap/increment 7627 ble-bind -f 'C-x' vi_xmap/decrement 7628 ble-bind -f 'g C-a' vi_xmap/progressive-increment 7629 ble-bind -f 'g C-x' vi_xmap/progressive-decrement 7630 7631 ble-bind -f f1 vi_xmap/command-help 7632 ble-bind -f K vi_xmap/command-help 7633 } 7634 7635 function ble-decode/keymap:vi_smap/define { 7636 ble-bind -f __default__ vi-command/decompose-meta 7637 7638 ble-bind -f 'ESC' vi_xmap/exit 7639 ble-bind -f 'C-[' vi_xmap/exit 7640 ble-bind -f 'C-c' vi_xmap/cancel 7641 7642 ble-bind -f 'C-\ C-n' nop 7643 ble-bind -f 'C-\ C-n' vi_xmap/cancel 7644 ble-bind -f 'C-\ C-g' vi_xmap/cancel 7645 ble-bind -f C-v vi_xmap/switch-to-visual-blockwise 7646 ble-bind -f C-q vi_xmap/switch-to-visual-blockwise 7647 ble-bind -f C-g vi_xmap/switch-to-visual 7648 7649 ble-bind -f delete 'vi-command/operator d' 7650 ble-bind -f 'C-?' 'vi-command/operator d' 7651 ble-bind -f 'DEL' 'vi-command/operator d' 7652 ble-bind -f 'C-h' 'vi-command/operator d' 7653 ble-bind -f 'BS' 'vi-command/operator d' 7654 7655 #---------------------------------------------------------------------------- 7656 7657 ble-bind -f __defchar__ vi_smap/self-insert 7658 ble-bind -f paste_begin vi-command/bracketed-paste 7659 7660 ble-bind -f 'C-a' vi_xmap/increment 7661 ble-bind -f 'C-x' vi_xmap/decrement 7662 ble-bind -f f1 vi_xmap/command-help 7663 ble-bind -c 'C-z' fg 7664 7665 #---------------------------------------------------------------------------- 7666 # motion, etc. 7667 7668 ble-bind -f home 'vi_smap/@nomarked vi-command/beginning-of-line' 7669 ble-bind -f end 'vi_smap/@nomarked vi-command/forward-eol' 7670 ble-bind -f C-m 'vi_smap/@nomarked vi-command/forward-first-non-space' 7671 ble-bind -f RET 'vi_smap/@nomarked vi-command/forward-first-non-space' 7672 ble-bind -f S-home 'vi-command/beginning-of-line' 7673 ble-bind -f S-end 'vi-command/forward-eol' 7674 ble-bind -f S-C-m 'vi-command/forward-first-non-space' 7675 ble-bind -f S-RET 'vi-command/forward-first-non-space' 7676 7677 ble-bind -f C-right 'vi_smap/@nomarked vi-command/forward-vword' 7678 ble-bind -f C-left 'vi_smap/@nomarked vi-command/backward-vword' 7679 ble-bind -f S-C-right 'vi-command/forward-vword' 7680 ble-bind -f S-C-left 'vi-command/backward-vword' 7681 7682 ble-bind -f left 'vi_smap/@nomarked vi-command/backward-char' 7683 ble-bind -f right 'vi_smap/@nomarked vi-command/forward-char' 7684 ble-bind -f 'C-?' 'vi_smap/@nomarked vi-command/backward-char wrap' 7685 ble-bind -f 'DEL' 'vi_smap/@nomarked vi-command/backward-char wrap' 7686 ble-bind -f 'C-h' 'vi_smap/@nomarked vi-command/backward-char wrap' 7687 ble-bind -f 'BS' 'vi_smap/@nomarked vi-command/backward-char wrap' 7688 ble-bind -f SP 'vi_smap/@nomarked vi-command/forward-char wrap' 7689 ble-bind -f S-left 'vi-command/backward-char' 7690 ble-bind -f S-right 'vi-command/forward-char' 7691 ble-bind -f 'S-C-?' 'vi-command/backward-char wrap' 7692 ble-bind -f 'S-DEL' 'vi-command/backward-char wrap' 7693 ble-bind -f 'S-C-h' 'vi-command/backward-char wrap' 7694 ble-bind -f 'S-BS' 'vi-command/backward-char wrap' 7695 ble-bind -f S-SP 'vi-command/forward-char wrap' 7696 7697 ble-bind -f down 'vi_smap/@nomarked vi-command/forward-line' 7698 ble-bind -f C-n 'vi_smap/@nomarked vi-command/forward-line' 7699 ble-bind -f C-j 'vi_smap/@nomarked vi-command/forward-line' 7700 ble-bind -f up 'vi_smap/@nomarked vi-command/backward-line' 7701 ble-bind -f C-p 'vi_smap/@nomarked vi-command/backward-line' 7702 ble-bind -f C-home 'vi_smap/@nomarked vi-command/first-nol' 7703 ble-bind -f C-end 'vi_smap/@nomarked vi-command/last-eol' 7704 ble-bind -f S-down 'vi-command/forward-line' 7705 ble-bind -f S-C-n 'vi-command/forward-line' 7706 ble-bind -f S-C-j 'vi-command/forward-line' 7707 ble-bind -f S-up 'vi-command/backward-line' 7708 ble-bind -f S-C-p 'vi-command/backward-line' 7709 ble-bind -f S-C-home 'vi-command/first-nol' 7710 ble-bind -f S-C-end 'vi-command/last-eol' 7711 } 7712 7713 #------------------------------------------------------------------------------ 7714 # vi_imap 7715 7716 function ble/widget/vi_imap/__attach__ { 7717 ble/keymap:vi/update-mode-indicator 7718 return 0 7719 } 7720 function ble/widget/vi_imap/__detach__ { 7721 ble/edit/info/default clear 7722 ble/keymap:vi/clear-arg 7723 ble/keymap:vi/search/clear-matched 7724 return 0 7725 } 7726 function ble/widget/vi_imap/accept-single-line-or { 7727 if ble-edit/is-single-complete-line; then 7728 ble/keymap:vi/imap-repeat/reset 7729 ble/widget/accept-line 7730 else 7731 ble/widget/"$@" 7732 fi 7733 } 7734 function ble/widget/vi_imap/delete-region-or { 7735 if [[ $_ble_edit_mark_active ]]; then 7736 ble/keymap:vi/imap-repeat/reset 7737 if ((_ble_edit_ind!=_ble_edit_mark)); then 7738 ble/keymap:vi/undo/add more 7739 ble/widget/delete-region 7740 ble/keymap:vi/undo/add more 7741 fi 7742 else 7743 ble/widget/"$@" 7744 fi 7745 } 7746 function ble/widget/vi_imap/overwrite-mode { 7747 ble-edit/content/clear-arg 7748 if [[ $_ble_edit_overwrite_mode ]]; then 7749 _ble_edit_overwrite_mode= 7750 else 7751 _ble_edit_overwrite_mode=${_ble_keymap_vi_insert_overwrite:-R} 7752 fi 7753 ble/keymap:vi/update-mode-indicator 7754 return 0 7755 } 7756 7757 # imap C-w 7758 function ble/widget/vi_imap/delete-backward-word { 7759 local space=$' \t' nl=$'\n' 7760 local rex="($_ble_keymap_vi_REX_WORD)[$space]*\$|[$space]+\$|$nl\$" 7761 if [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]]; then 7762 local index=$((_ble_edit_ind-${#BASH_REMATCH})) 7763 if ((index!=_ble_edit_ind)); then 7764 ble/keymap:vi/undo/add more 7765 ble/widget/.delete-range "$index" "$_ble_edit_ind" 7766 ble/keymap:vi/undo/add more 7767 fi 7768 return 0 7769 else 7770 ble/widget/.bell 7771 return 1 7772 fi 7773 } 7774 7775 # imap C-q, C-v 7776 function ble/widget/vi_imap/quoted-insert-char { 7777 ble/keymap:vi/imap-repeat/pop 7778 _ble_edit_mark_active= 7779 _ble_decode_char__hook=ble/widget/vi_imap/quoted-insert-char.hook 7780 return 147 7781 } 7782 function ble/widget/vi_imap/quoted-insert-char.hook { 7783 ble/keymap:vi/imap/invoke-widget ble/widget/self-insert "$1" 7784 } 7785 function ble/widget/vi_imap/quoted-insert { 7786 ble/keymap:vi/imap-repeat/pop 7787 _ble_edit_mark_active= 7788 _ble_decode_key__hook=ble/widget/vi_imap/quoted-insert.hook 7789 return 147 7790 } 7791 function ble/widget/vi_imap/quoted-insert.hook { 7792 ble/keymap:vi/imap/invoke-widget ble/widget/quoted-insert.hook "$1" 7793 } 7794 7795 # bracketed paste mode 7796 7797 function ble/widget/vi_imap/bracketed-paste { 7798 ble/keymap:vi/imap-repeat/pop 7799 ble/widget/bracketed-paste 7800 _ble_edit_bracketed_paste_proc=ble/widget/vi_imap/bracketed-paste.proc 7801 return 147 7802 } 7803 function ble/widget/vi_imap/bracketed-paste.proc { 7804 local WIDGET=ble/widget/batch-insert 7805 local -a KEYS; KEYS=("$@") 7806 ble/keymap:vi/imap-repeat/push 7807 builtin eval -- "$WIDGET" 7808 } 7809 7810 _ble_keymap_vi_brackated_paste_mark_active= 7811 function ble/widget/vi-command/bracketed-paste { 7812 local ARG FLAG REG; ble/keymap:vi/get-arg 1 # discard args 7813 _ble_keymap_vi_brackated_paste_mark_active=$_ble_edit_mark_active 7814 _ble_edit_mark_active= 7815 ble/widget/bracketed-paste 7816 _ble_edit_bracketed_paste_proc=ble/widget/vi-command/bracketed-paste.proc 7817 return 147 7818 } 7819 function ble/widget/vi-command/bracketed-paste.proc { 7820 if [[ $_ble_decode_keymap == vi_nmap ]]; then 7821 local isbol index=$_ble_edit_ind 7822 ble-edit/content/bolp && isbol=1 7823 ble/decode/widget/call-interactively 'ble/widget/vi_nmap/append-mode' 97 7824 [[ $isbol ]] && ((_ble_edit_ind=index)) # 行頭にいたときは戻る 7825 7826 ble/widget/vi_imap/bracketed-paste.proc "$@" 7827 ble/keymap:vi/imap/invoke-widget \ 7828 ble/widget/vi_imap/normal-mode "$((_ble_decode_Ctrl|0x5b))" 7829 elif [[ $_ble_decode_keymap == vi_[xs]map ]]; then 7830 local _ble_edit_mark_active=$_ble_keymap_vi_brackated_paste_mark_active 7831 ble/decode/widget/call-interactively 'ble/widget/vi-command/operator c' 99 || return 1 7832 ble/widget/vi_imap/bracketed-paste.proc "$@" 7833 ble/keymap:vi/imap/invoke-widget \ 7834 ble/widget/vi_imap/normal-mode "$((_ble_decode_Ctrl|0x5b))" 7835 elif [[ $_ble_decode_keymap == vi_omap ]]; then 7836 ble/widget/vi_omap/cancel 7837 ble/widget/.bell 7838 return 1 7839 else # vi_omap 7840 ble/widget/.bell 7841 return 1 7842 fi 7843 } 7844 7845 #------------------------------------------------------------------------------ 7846 # imap: C-k (digraph) 7847 7848 function ble/widget/vi_imap/insert-digraph.hook { 7849 local -a KEYS; KEYS=("$1") 7850 ble/widget/self-insert 7851 } 7852 7853 function ble/widget/vi_imap/insert-digraph { 7854 ble/decode/keymap/push vi_digraph 7855 _ble_keymap_vi_digraph__hook=ble/widget/vi_imap/insert-digraph.hook 7856 return 0 7857 } 7858 7859 # imap: CR, LF (newline) 7860 function ble/widget/vi_imap/newline { 7861 local ret 7862 ble-edit/content/find-logical-bol; local bol=$ret 7863 ble-edit/content/find-non-space "$bol"; local nol=$ret 7864 ble/widget/default/newline 7865 ((bol<nol)) && ble/widget/.insert-string "${_ble_edit_str:bol:nol-bol}" 7866 return 0 7867 } 7868 7869 # imap: C-h, DEL 7870 function ble/widget/vi_imap/delete-backward-indent-or { 7871 local rex=$'(^|\n)([ \t]+)$' 7872 if [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]]; then 7873 local rematch2=${BASH_REMATCH[2]} # Note: for bash-3.1 ${#arr[n]} bug 7874 if [[ $rematch2 ]]; then 7875 ble/keymap:vi/undo/add more 7876 ble/widget/.delete-range "$((_ble_edit_ind-${#rematch2}))" "$_ble_edit_ind" 7877 ble/keymap:vi/undo/add more 7878 fi 7879 return 0 7880 else 7881 ble/widget/"$@" 7882 fi 7883 } 7884 7885 #------------------------------------------------------------------------------ 7886 7887 function ble-decode/keymap:vi_imap/define { 7888 #---------------------------------------------------------------------------- 7889 # common bindings 7890 7891 local ble_bind_nometa=1 7892 ble-decode/keymap:safe/bind-common 7893 ble-decode/keymap:safe/bind-history 7894 7895 #---------------------------------------------------------------------------- 7896 # from ble-decode/keymap:safe/define 7897 7898 ble-bind -f 'C-d' 'delete-region-or delete-forward-char-or-exit' 7899 7900 ble-bind -f 'SP' 'magic-space' 7901 ble-bind -f '/' 'magic-slash' 7902 7903 # ble-bind -f 'C-c' 'discard-line' 7904 ble-bind -f 'C-j' 'accept-line' 7905 ble-bind -f 'C-RET' 'accept-line' 7906 ble-bind -f 'C-m' 'accept-single-line-or-newline' 7907 ble-bind -f 'RET' 'accept-single-line-or-newline' 7908 # ble-bind -f 'C-o' 'accept-and-next' 7909 ble-bind -f 'C-x C-e' 'edit-and-execute-command' 7910 ble-bind -f 'C-g' 'bell' 7911 ble-bind -f 'C-x C-g' 'bell' 7912 7913 ble-bind -f 'C-l' 'clear-screen' 7914 7915 ble-bind -f 'f1' 'command-help' 7916 ble-bind -f 'C-x C-v' 'display-shell-version' 7917 ble-bind -c 'C-z' 'fg' 7918 7919 # args 7920 local key 7921 for key in {,C-}{0..9}; do 7922 ble-bind -f "$key" 'append-arg' 7923 done 7924 7925 #---------------------------------------------------------------------------- 7926 # vi_imap modifications 7927 7928 ble-bind -f insert 'vi_imap/overwrite-mode' 7929 7930 # insert 7931 ble-bind -f 'C-q' 'vi_imap/quoted-insert' 7932 ble-bind -f 'C-v' 'vi_imap/quoted-insert' 7933 ble-bind -f 'C-RET' 'newline' 7934 ble-bind -f paste_begin 'vi_imap/bracketed-paste' 7935 7936 # charwise operations 7937 ble-bind -f 'C-?' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char' 7938 ble-bind -f 'DEL' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char' 7939 ble-bind -f 'C-h' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char' 7940 ble-bind -f 'BS' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char' 7941 7942 # wordwise operations 7943 ble-bind -f 'C-w' 'vi_imap/delete-backward-word' 7944 7945 # complete 7946 ble-decode/keymap:vi_imap/bind-complete 7947 7948 #---------------------------------------------------------------------------- 7949 # shell functions (from keymap emacs-standard) 7950 7951 ble-bind -f 'C-\' bell 7952 ble-bind -f 'C-^' bell 7953 7954 #---------------------------------------------------------------------------- 7955 # vi bindings 7956 7957 ble-bind -f __attach__ vi_imap/__attach__ 7958 ble-bind -f __detach__ vi_imap/__detach__ 7959 ble-bind -f __default__ vi_imap/__default__ 7960 ble-bind -f __before_widget__ vi_imap/__before_widget__ 7961 ble-bind -f __line_limit__ __line_limit__ 7962 7963 ble-bind -f 'ESC' 'vi_imap/normal-mode' 7964 ble-bind -f 'C-[' 'vi_imap/normal-mode' 7965 ble-bind -f 'C-c' 'vi_imap/normal-mode-without-insert-leave' 7966 7967 ble-bind -f 'C-o' 'vi_imap/single-command-mode' 7968 7969 # ble-bind -f 'C-l' vi_imap/normal-mode 7970 # ble-bind -f 'C-k' vi_imap/insert-digraph 7971 } 7972 7973 ## @fn ble-decode/keymap:vi_imap/define-meta-bindings 7974 ## M- で始まるキーバインディングを定義します。 7975 ## ユーザから呼び出すための関数です。 7976 function ble-decode/keymap:vi_imap/define-meta-bindings { 7977 local ble_bind_keymap=vi_imap 7978 7979 #---------------------------------------------------------------------------- 7980 # from ble-decode/keymap:safe/define 7981 7982 ble-bind -f 'M-^' 'history-expand-line' 7983 ble-bind -f 'C-M-l' 'redraw-line' 7984 ble-bind -f 'M-#' 'insert-comment' 7985 ble-bind -f 'M-C-e' 'shell-expand-line' 7986 ble-bind -f 'M-&' 'tilde-expand' 7987 ble-bind -f 'C-M-g' 'bell' 7988 ble-bind -c 'M-z' 'fg' 7989 7990 #---------------------------------------------------------------------------- 7991 # from ble-decode/keymap:safe/bind-common 7992 7993 ble-bind -f 'M-C-m' 'newline' 7994 ble-bind -f 'M-RET' 'newline' 7995 ble-bind -f 'M-SP' 'set-mark' 7996 ble-bind -f 'M-w' 'copy-region-or copy-uword' 7997 ble-bind -f 'M-y' 'yank-pop' 7998 ble-bind -f 'M-S-y' 'yank-pop backward' 7999 ble-bind -f 'M-Y' 'yank-pop backward' 8000 ble-bind -f 'M-\' 'delete-horizontal-space' 8001 8002 ble-bind -f 'M-right' '@nomarked forward-sword' 8003 ble-bind -f 'M-left' '@nomarked backward-sword' 8004 ble-bind -f 'S-M-right' '@marked forward-sword' 8005 ble-bind -f 'S-M-left' '@marked backward-sword' 8006 ble-bind -f 'M-d' 'kill-forward-cword' 8007 ble-bind -f 'M-h' 'kill-backward-cword' 8008 ble-bind -f 'M-delete' 'copy-forward-sword' 8009 ble-bind -f 'M-C-?' 'copy-backward-sword' 8010 ble-bind -f 'M-DEL' 'copy-backward-sword' 8011 ble-bind -f 'M-C-h' 'copy-backward-sword' 8012 ble-bind -f 'M-BS' 'copy-backward-sword' 8013 8014 ble-bind -f 'M-f' '@nomarked forward-cword' 8015 ble-bind -f 'M-b' '@nomarked backward-cword' 8016 ble-bind -f 'M-F' '@marked forward-cword' 8017 ble-bind -f 'M-B' '@marked backward-cword' 8018 ble-bind -f 'M-S-f' '@marked forward-cword' 8019 ble-bind -f 'M-S-b' '@marked backward-cword' 8020 ble-bind -f 'M-c' 'capitalize-eword' 8021 ble-bind -f 'M-l' 'downcase-eword' 8022 ble-bind -f 'M-u' 'upcase-eword' 8023 ble-bind -f 'M-t' 'transpose-ewords' 8024 8025 ble-bind -f 'M-m' '@nomarked non-space-beginning-of-line' 8026 ble-bind -f 'M-S-m' '@marked non-space-beginning-of-line' 8027 ble-bind -f 'M-M' '@marked non-space-beginning-of-line' 8028 8029 #---------------------------------------------------------------------------- 8030 # from ble-decode/keymap:safe/bind-history 8031 8032 ble-bind -f 'M-<' 'history-beginning' 8033 ble-bind -f 'M->' 'history-end' 8034 ble-bind -f 'M-.' 'insert-last-argument' 8035 ble-bind -f 'M-_' 'insert-last-argument' 8036 ble-bind -f 'M-C-y' 'insert-nth-argument' 8037 8038 #---------------------------------------------------------------------------- 8039 # from ble-decode/keymap:safe/bind-complete 8040 8041 ble-bind -f 'M-?' 'complete show_menu' 8042 ble-bind -f 'M-*' 'complete insert_all' 8043 ble-bind -f 'M-{' 'complete insert_braces' 8044 ble-bind -f 'M-/' 'complete context=filename' 8045 ble-bind -f 'M-~' 'complete context=username' 8046 ble-bind -f 'M-$' 'complete context=variable' 8047 ble-bind -f 'M-@' 'complete context=hostname' 8048 ble-bind -f 'M-!' 'complete context=command' 8049 ble-bind -f "M-'" 'sabbrev-expand' 8050 ble-bind -f 'M-g' 'complete context=glob' 8051 ble-bind -f 'M-C-i' 'complete context=dynamic-history' 8052 ble-bind -f 'M-TAB' 'complete context=dynamic-history' 8053 8054 #---------------------------------------------------------------------------- 8055 # from ble-decode/keymap:safe/bind-arg 8056 8057 ble-bind -f 'M-0' 'append-arg' 8058 ble-bind -f 'M-1' 'append-arg' 8059 ble-bind -f 'M-2' 'append-arg' 8060 ble-bind -f 'M-3' 'append-arg' 8061 ble-bind -f 'M-4' 'append-arg' 8062 ble-bind -f 'M-5' 'append-arg' 8063 ble-bind -f 'M-6' 'append-arg' 8064 ble-bind -f 'M-7' 'append-arg' 8065 ble-bind -f 'M-8' 'append-arg' 8066 ble-bind -f 'M-9' 'append-arg' 8067 } 8068 8069 #------------------------------------------------------------------------------ 8070 # vi_cmap 8071 8072 _ble_keymap_vi_cmap_hook= 8073 _ble_keymap_vi_cmap_cancel_hook= 8074 _ble_keymap_vi_cmap_before_command= 8075 8076 # 既定の cmap 履歴 8077 _ble_keymap_vi_cmap_history=() 8078 _ble_keymap_vi_cmap_history_edit=() 8079 _ble_keymap_vi_cmap_history_dirt=() 8080 _ble_keymap_vi_cmap_history_index=0 8081 8082 function ble/keymap:vi/async-commandline-mode { 8083 local hook=$1 8084 _ble_keymap_vi_cmap_hook=$hook 8085 _ble_keymap_vi_cmap_cancel_hook= 8086 _ble_keymap_vi_cmap_before_command= 8087 8088 # 記録 8089 ble/textarea#render 8090 ble/textarea#save-state _ble_keymap_vi_cmap 8091 ble/util/save-vars _ble_keymap_vi_cmap _ble_canvas_panel_focus 8092 _ble_keymap_vi_cmap_history_prefix=$_ble_history_prefix 8093 8094 # 初期化 8095 ble/decode/keymap/push vi_cmap 8096 ble/keymap:vi/update-mode-indicator 8097 8098 # textarea 8099 _ble_textarea_panel=1 8100 _ble_canvas_panel_focus=1 8101 ble/textarea#invalidate 8102 8103 # edit/prompt 8104 _ble_edit_PS1=$PS2 8105 _ble_prompt_ps1_data=(0 '' '' 0 0 0 32 0 '' '') 8106 8107 # edit 8108 # Note: ble/widget/.newline/clear-content の中で 8109 # ble-edit/content/reset が呼び出され、更に _ble_edit_dirty_observer が呼び出さる。 8110 # ble/keymap:vi/mark/shift-by-dirty-range が呼び出されないように、 8111 # _ble_edit_dirty_observer=() より後である必要がある。 8112 _ble_edit_dirty_observer=() 8113 ble/widget/.newline/clear-content 8114 _ble_edit_arg= 8115 8116 # edit/undo 8117 ble-edit/undo/clear-all 8118 8119 # edit/history 8120 ble/history/set-prefix _ble_keymap_vi_cmap 8121 8122 # syntax, highlight 8123 _ble_syntax_lang=text 8124 _ble_highlight_layer_list=(plain region overwrite_mode) 8125 } 8126 8127 function ble/widget/vi_cmap/accept { 8128 local hook=${_ble_keymap_vi_cmap_hook} 8129 _ble_keymap_vi_cmap_hook= 8130 8131 local result=$_ble_edit_str 8132 [[ $result ]] && ble/history/add "$result" # Note: cancel でも登録する 8133 8134 # 消去 8135 local -a DRAW_BUFF=() 8136 ble/canvas/panel#set-height.draw "$_ble_textarea_panel" 0 8137 ble/canvas/bflush.draw 8138 8139 # 復元 8140 ble/textarea#restore-state _ble_keymap_vi_cmap 8141 ble/textarea#clear-state _ble_keymap_vi_cmap 8142 ble/util/restore-vars _ble_keymap_vi_cmap _ble_canvas_panel_focus 8143 [[ $_ble_edit_overwrite_mode ]] && ble/util/buffer "$_ble_term_civis" 8144 ble/history/set-prefix "$_ble_keymap_vi_cmap_history_prefix" 8145 8146 ble/decode/keymap/pop 8147 ble/keymap:vi/update-mode-indicator 8148 if [[ $hook ]]; then 8149 builtin eval -- "$hook \"\$result\"" 8150 else 8151 ble/keymap:vi/adjust-command-mode 8152 return 0 8153 fi 8154 } 8155 8156 function ble/widget/vi_cmap/cancel { 8157 _ble_keymap_vi_cmap_hook=$_ble_keymap_vi_cmap_cancel_hook 8158 ble/widget/vi_cmap/accept 8159 } 8160 8161 function ble/widget/vi_cmap/__before_widget__ { 8162 if [[ $_ble_keymap_vi_cmap_before_command ]]; then 8163 builtin eval -- "$_ble_keymap_vi_cmap_before_command" 8164 fi 8165 } 8166 8167 function ble/widget/vi_cmap/__line_limit__.edit { 8168 local content=$1 8169 ble/widget/edit-and-execute-command.edit "$content" no-newline; local ext=$? 8170 ((ext==127)) && return "$ext" 8171 ble-edit/content/reset "$ret" 8172 ble/widget/vi_cmap/accept 8173 } 8174 function ble/widget/vi_cmap/__line_limit__ { 8175 ble/widget/__line_limit__ vi_cmap/__line_limit__.edit 8176 } 8177 8178 function ble-decode/keymap:vi_cmap/define { 8179 #---------------------------------------------------------------------------- 8180 # common bindings + modifications 8181 8182 local ble_bind_nometa= 8183 ble-decode/keymap:safe/bind-common 8184 ble-decode/keymap:safe/bind-history 8185 ble-decode/keymap:safe/bind-complete 8186 8187 #---------------------------------------------------------------------------- 8188 8189 ble-bind -f __before_widget__ vi_cmap/__before_widget__ 8190 ble-bind -f __line_limit__ vi_cmap/__line_limit__ 8191 8192 # accept/cancel 8193 ble-bind -f 'ESC' vi_cmap/cancel 8194 ble-bind -f 'C-[' vi_cmap/cancel 8195 ble-bind -f 'C-c' vi_cmap/cancel 8196 ble-bind -f 'C-m' vi_cmap/accept 8197 ble-bind -f 'RET' vi_cmap/accept 8198 ble-bind -f 'C-j' vi_cmap/accept 8199 ble-bind -f 'C-g' bell 8200 ble-bind -f 'C-x C-g' bell 8201 ble-bind -f 'C-M-g' bell 8202 8203 # shell function 8204 # ble-bind -f 'C-l' clear-screen 8205 ble-bind -f 'C-l' redraw-line 8206 ble-bind -f 'C-M-l' redraw-line 8207 ble-bind -f 'C-x C-v' display-shell-version 8208 8209 # command-history 8210 # ble-bind -f 'M-^' history-expand-line 8211 # ble-bind -f 'SP' magic-space 8212 # ble-bind -f '/' magic-slash 8213 8214 ble-bind -f 'C-\' bell 8215 ble-bind -f 'C-^' bell 8216 } 8217 8218 #------------------------------------------------------------------------------ 8219 8220 function ble-decode/keymap:vi/initialize { 8221 local fname_keymap_cache=$_ble_base_cache/keymap.vi 8222 if [[ -s $fname_keymap_cache && 8223 $fname_keymap_cache -nt $_ble_base/lib/keymap.vi.sh && 8224 $fname_keymap_cache -nt $_ble_base/lib/init-cmap.sh ]]; then 8225 source "$fname_keymap_cache" && return 0 8226 fi 8227 8228 ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi..." 8229 8230 { 8231 ble/decode/keymap#load isearch dump 8232 ble/decode/keymap#load nsearch dump 8233 ble/decode/keymap#load vi_imap dump 8234 ble/decode/keymap#load vi_nmap dump 8235 ble/decode/keymap#load vi_omap dump 8236 ble/decode/keymap#load vi_xmap dump 8237 ble/decode/keymap#load vi_cmap dump 8238 } 3>| "$fname_keymap_cache" 8239 8240 ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi... done" 8241 } 8242 8243 ble-decode/keymap:vi/initialize 8244 blehook/invoke keymap_load 8245 blehook/invoke keymap_vi_load 8246 return 0