vim-surround.sh (28091B)
1 #!/bin/bash 2 3 ble-import keymap.vi 4 5 # surround.vim (https://github.com/tpope/vim-surround) の模倣実装 6 # 7 # 現在以下のみに対応している。 8 # 9 # nmap: ys{move}{ins} 10 # nmap: yss{ins} 11 # nmap: yS{move}{ins} 12 # nmap: ySS{ins} または ySs{ins} 13 # xmap: S{ins} 14 # xmap: gS{ins} 15 # 16 # {ins} ~ / ?./ 17 # 18 # 空白を前置した場合は、囲まれる文字列の両端に半角空白を1つずつ付加する。 19 # 最後の文字によって囲み文字を指定する。 20 # 21 # <, t (未対応) タグで囲む 22 # 右括弧類 括弧で囲む 23 # 左括弧類 括弧で囲む 24 # [a-zA-Z] エラー 25 # 他の文字 その文字で囲む 26 # 27 # 注意: surround.vim と違って、 28 # テキストオブジェクト等に対する引数は有効である。 29 # または、aw は iw と異なる位置に挿入する。 30 # 31 # 注意: surround.vim と違って、 32 # 2ys3s のような引数の指定を行うことができる。 33 # これは 2y3y と同様に現在行から 6 行に亘って作用する。 34 # 35 # 注意: . によってこのオペレータを繰り返すとき、 36 # 再度入力を求める surround.vim と違って、 37 # 前回使用した区切り文字を使用する。 38 # 39 # 注意: surround.vim では矩形選択の末尾拡張を判定できないため、 40 # S は非末尾拡張で gS は末尾拡張として働くが、 41 # この実装では S は現在末尾拡張状態を使い gS は末尾拡張を常に行う。 42 # 43 # nmap: ds{del} 44 # nmap: cs{del}{ins} 45 # nmap: cS{del}{ins} 46 # 47 # {del} ~ /([0-9]+| )?./ 48 # 49 # 削除される囲み文字を指定する。 50 # [0-9]+ を指定した場合は引数に対する倍率となる。 51 # 空白を前置した場合は囲まれた文字列の両端の空白を trim する。 52 # 53 # 最後の文字によって囲み文字を指定する。 54 # 55 # b()B{}r[]a<> 括弧を削除する。左括弧を指定したとき囲まれた文字列は trim される。 56 # wW 範囲を指定するのみで、何も削除しない。 57 # ps (未対応) 範囲を指定するのみで、何も削除しない。 58 # tT タグ。T を用いたとき囲まれた文字列は trim される。 59 # / /* ... */ で囲まれた領域を削除する。 60 # 他の文字 その文字を、行内で左右に探して対で削除する。 61 # 62 # {ins} ~ / ?./ 63 # 64 # 代わりに挿入される囲み文字を指定する。ys, yss と同じ。 65 # 66 # 注意: . によってこの操作を繰り返すとき、 67 # surround.vim では {del} を空文字列とし {ins} について入力を求めるが、 68 # この実装では前回使用した {del} と {ins} を使用して動作する。 69 # 70 # 以下には対応していない。 71 # 72 # imap: <C-S> 73 # imap: <C-G>s 74 # imap: <C-G>S 75 # 76 77 bleopt/declare -n vim_surround_45 $'$(\r)' # ysiw- 78 bleopt/declare -n vim_surround_61 $'$((\r))' # ysiw= 79 bleopt/declare -n vim_surround_q \" # ysiwQ 80 bleopt/declare -n vim_surround_Q \' # ysiwq 81 bleopt/declare -v vim_surround_omap_bind 1 82 83 #------------------------------------------------------------------------------ 84 # util 85 86 ## @fn ble/lib/vim-surround.sh/get-char-from-key key 87 ## @param[in] key 88 ## @var[out] ret 89 function ble/lib/vim-surround.sh/get-char-from-key { 90 local key=$1 91 if ! ble-decode-key/ischar "$key"; then 92 local flag=$((key&_ble_decode_MaskFlag)) code=$((key&_ble_decode_MaskChar)) 93 if ((flag==_ble_decode_Ctrl&&63<=code&&code<128&&(code&0x1F)!=0)); then 94 ((key=code==63?127:code&0x1F)) 95 else 96 return 1 97 fi 98 fi 99 100 ble/util/c2s "$key" 101 return 0 102 } 103 104 function ble/lib/vim-surround.sh/async-inputtarget.hook { 105 local mode=$1 hook=${@:2:$#-2} key=${@:$#} ret 106 if ! ble/lib/vim-surround.sh/get-char-from-key "$key"; then 107 ble/widget/vi-command/bell 108 return 1 109 fi 110 111 local c=$ret 112 if [[ :$mode: == *:digit:* && $c == [0-9] ]]; then 113 _ble_edit_arg=$_ble_edit_arg$c 114 _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook digit $hook" 115 return 147 116 elif [[ :$mode: == *:init:* && $c == ' ' ]]; then 117 _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook space $hook" 118 return 147 119 fi 120 121 if [[ $c == [$'\e\003'] ]]; then # C-[, C-c 122 ble/widget/vi-command/bell 123 return 1 124 else 125 [[ $c == \' ]] && c="'\''" 126 [[ $mode == space ]] && c=' '$c 127 builtin eval -- "$hook '$c'" 128 fi 129 } 130 function ble/lib/vim-surround.sh/async-inputtarget { 131 local IFS=$_ble_term_IFS 132 _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook init:digit $*" 133 return 147 134 } 135 function ble/lib/vim-surround.sh/async-inputtarget-noarg { 136 local IFS=$_ble_term_IFS 137 _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook init $*" 138 return 147 139 } 140 141 _ble_lib_vim_surround_previous_tag=html 142 143 ## @fn ble/lib/vim-surround.sh/load-template ins 144 ## @param[in] ins 145 ## @var[out] template 146 function ble/lib/vim-surround.sh/load-template { 147 local ins=$1 148 149 # read user settings 150 151 if [[ ${ins//[0-9]} && ! ${ins//[_a-zA-Z0-9]} ]]; then 152 local optname=bleopt_vim_surround_$ins 153 template=${!optname} 154 [[ $template ]] && return 0 155 fi 156 157 local ret; ble/util/s2c "$ins" 158 local optname=bleopt_vim_surround_$ret 159 template=${!optname} 160 [[ $template ]] && return 0 161 162 # default 163 164 case $ins in 165 (['<tT']*) 166 local tag=${ins:1}; tag=${tag//$'\r'/' '} 167 if [[ ! $tag ]]; then 168 tag=$_ble_lib_vim_surround_previous_tag 169 else 170 tag=${tag%'>'} 171 _ble_lib_vim_surround_previous_tag=$tag 172 fi 173 local end_tag=${tag%%["$_ble_term_IFS"]*} 174 template="<$tag>"$'\r'"</$end_tag>" ;; 175 ('(') template=$'( \r )' ;; 176 ('[') template=$'[ \r ]' ;; 177 ('{') template=$'{ \r }' ;; 178 (['b)']) template=$'(\r)' ;; 179 (['r]']) template=$'[\r]' ;; 180 (['B}']) template=$'{\r}' ;; 181 (['a>']) template=$'<\r>' ;; 182 ([a-zA-Z]) return 1 ;; 183 (*) template=$ins ;; 184 esac 185 } &>/dev/null 186 187 ## @fn ble/lib/vim-surround.sh/surround text ins opts 188 ## @param[in] text 189 ## @param[in] ins 190 ## @param[in] opts 191 ## linewise 192 ## 囲まれた文字列を新しい独立した業にします。 193 ## cS yS VS VgS などで使用します。 194 ## indent 195 ## linewise のとき、新しい行のインデントを追加します。 196 ## 197 ## @var[in] beg 198 ## @var[out] ret 199 function ble/lib/vim-surround.sh/surround { 200 local text=$1 ins=$2 opts=$3 201 202 local instype= 203 [[ $ins == $'\x1D' ]] && ins='}' instype=indent # C-], C-} 204 205 local has_space= 206 [[ $ins == ' '?* ]] && ins=${ins:1} has_space=1 207 208 local template= 209 ble/lib/vim-surround.sh/load-template "$ins" || return 1 210 211 local prefix= suffix= 212 if [[ $template == *$'\r'* ]]; then 213 prefix=${template%%$'\r'*} 214 suffix=${template#*$'\r'} 215 else 216 prefix=$template 217 suffix=$template 218 fi 219 220 if [[ $prefix == *' ' && $suffix == ' '* ]]; then 221 prefix=${prefix::${#prefix}-1} 222 suffix=${suffix:1} 223 has_space=1 224 fi 225 226 if [[ $instype == indent || :$opts: == *:linewise:* ]]; then 227 ble-edit/content/find-logical-bol "$beg"; local bol=$ret 228 ble-edit/content/find-non-space "$bol"; local nol=$ret 229 local indent= 230 if [[ $instype == indent ]] || ((bol<nol)); then 231 indent=${_ble_edit_str:bol:nol-bol} 232 elif [[ $has_space ]]; then 233 indent=' ' 234 fi 235 text=$indent$text 236 if [[ $instype == indent || :$opts: == *:indent:* ]]; then 237 ble/keymap:vi/string#increase-indent "$text" "$bleopt_indent_offset"; text=$ret 238 fi 239 text=$'\n'$text$'\n'$indent 240 # ToDo: 初めから text に改行が含まれていた場合は、 241 # 更にここで = による自動インデントを実行する? 242 elif [[ $has_space ]]; then 243 text=' '$text' ' 244 fi 245 246 ret=$prefix$text$suffix 247 } 248 249 #------------------------------------------------------------------------------ 250 # async-read-tagname 251 252 function ble/lib/vim-surround.sh/async-read-tagname { 253 ble/keymap:vi/async-commandline-mode "$1" 254 _ble_edit_PS1='<' 255 _ble_keymap_vi_cmap_before_command=ble/lib/vim-surround.sh/async-read-tagname/.before-command.hook 256 return 147 257 } 258 function ble/lib/vim-surround.sh/async-read-tagname/.before-command.hook { 259 if [[ ${KEYS[0]} == 62 ]]; then # '>' 260 ble/widget/self-insert 261 ble/widget/vi_cmap/accept 262 ble/decode/widget/suppress-widget 263 fi 264 } 265 266 #------------------------------------------------------------------------------ 267 # ys yss yS ySS ySs vS vgS 268 269 _ble_lib_vim_surround_ys_type= # ys | yS | vS | vgS 270 _ble_lib_vim_surround_ys_args=() 271 _ble_lib_vim_surround_ys_ranges=() 272 273 ## @fn ble/highlight/layer:region/mark:vi_surround/get-selection 274 ## 入力待ち状態の時の領域着色を定義します。 275 ## @arr[out] selection 276 function ble/highlight/layer:region/mark:vi_surround/get-selection { 277 local type=$_ble_lib_vim_surround_ys_type 278 local context=${_ble_lib_vim_surround_ys_args[2]} 279 if [[ $context == block ]]; then 280 local -a sub_ranges 281 sub_ranges=("${_ble_lib_vim_surround_ys_ranges[@]}") 282 283 selection=() 284 local sub 285 for sub in "${sub_ranges[@]}"; do 286 ble/string#split sub : "$sub" 287 ((sub[0]<sub[1])) || continue 288 ble/array#push selection "${sub[0]}" "${sub[1]}" 289 done 290 else 291 selection=("${_ble_lib_vim_surround_ys_args[@]::2}") 292 293 # convert to linewise 294 if [[ $context == char && ( $type == yS || $type == ySS || $type == vgS ) ]]; then 295 local ret 296 ble-edit/content/find-logical-bol "${selection[0]}"; selection[0]=$ret 297 ble-edit/content/find-logical-eol "${selection[1]}"; selection[1]=$ret 298 fi 299 fi 300 } 301 function ble/highlight/layer:region/mark:vi_surround/get-face { 302 face=region_target 303 } 304 305 function ble/lib/vim-surround.sh/operator.impl { 306 _ble_lib_vim_surround_ys_type=$1; shift 307 _ble_lib_vim_surround_ys_args=("$@") 308 [[ $3 == block ]] && _ble_lib_vim_surround_ys_ranges=("${sub_ranges[@]}") 309 _ble_edit_mark_active=vi_surround 310 ble/lib/vim-surround.sh/async-inputtarget-noarg ble/widget/vim-surround.sh/ysurround.hook1 311 ble/lib/vim-surround.sh/ysurround.repeat/entry 312 return 147 313 } 314 function ble/keymap:vi/operator:yS { ble/lib/vim-surround.sh/operator.impl yS "$@"; } 315 function ble/keymap:vi/operator:ys { ble/lib/vim-surround.sh/operator.impl ys "$@"; } 316 function ble/keymap:vi/operator:ySS { ble/lib/vim-surround.sh/operator.impl ySS "$@"; } 317 function ble/keymap:vi/operator:yss { ble/lib/vim-surround.sh/operator.impl yss "$@"; } 318 function ble/keymap:vi/operator:vS { ble/lib/vim-surround.sh/operator.impl vS "$@"; } 319 function ble/keymap:vi/operator:vgS { ble/lib/vim-surround.sh/operator.impl vgS "$@"; } 320 function ble/widget/vim-surround.sh/ysurround.hook1 { 321 local ins=$1 322 if local rex='^ ?[<tT]$'; [[ $ins =~ $rex ]]; then 323 ble/lib/vim-surround.sh/async-read-tagname "ble/widget/vim-surround.sh/ysurround.hook2 '$ins'" 324 else 325 ble/widget/vim-surround.sh/ysurround.core "$ins" 326 fi 327 } 328 function ble/widget/vim-surround.sh/ysurround.hook2 { 329 local ins=$1 tagName=$2 330 ble/widget/vim-surround.sh/ysurround.core "$ins$tagName" 331 } 332 function ble/widget/vim-surround.sh/ysurround.core { 333 local ins=$1 334 _ble_edit_mark_active= # mark:vi_surround を解除 335 336 local ret 337 338 # saved arguments 339 local type=$_ble_lib_vim_surround_ys_type 340 local beg=${_ble_lib_vim_surround_ys_args[0]} 341 local end=${_ble_lib_vim_surround_ys_args[1]} 342 local context=${_ble_lib_vim_surround_ys_args[2]} 343 local sub_ranges; sub_ranges=("${_ble_lib_vim_surround_ys_ranges[@]}") 344 _ble_lib_vim_surround_ys_type= 345 _ble_lib_vim_surround_ys_args=() 346 _ble_lib_vim_surround_ys_ranges=() 347 348 if [[ $context == block ]]; then 349 local isub=${#sub_ranges[@]} sub 350 local smin= smax= slpad= srpad= 351 while ((isub--)); do 352 local sub=${sub_ranges[isub]} 353 local stext=${sub#*:*:*:*:*:} 354 ble/string#split sub : "${sub::${#sub}-${#stext}}" 355 smin=${sub[0]} smax=${sub[1]} 356 slpad=${sub[2]} srpad=${sub[3]} 357 358 if ! ble/lib/vim-surround.sh/surround "$stext" "$ins"; then 359 ble/widget/vi-command/bell 360 return 1 361 fi 362 stext=$ret 363 364 ((slpad)) && { ble/string#repeat ' ' "$slpad"; stext=$ret$stext; } 365 ((srpad)) && { ble/string#repeat ' ' "$srpad"; stext=$stext$ret; } 366 ble/widget/.replace-range "$smin" "$smax" "$stext" 367 done 368 369 else 370 # text 371 local text=${_ble_edit_str:beg:end-beg} 372 if [[ $type == ys ]]; then 373 if local rex=$'[ \t\n]+$'; [[ $text =~ $rex ]]; then 374 # 範囲末端の空白は囲む対象としない 375 ((end-=${#BASH_REMATCH})) 376 text=${_ble_edit_str:beg:end-beg} 377 fi 378 fi 379 380 # Note: char から linewise への昇格条件の変更は以下の関数にも反映させる必要がある: 381 # ble/highlight/layer:region/mark:vi_surround/get-selection 382 local opts= 383 if [[ $type == yS || $type == ySS || $context == char && $type == vgS ]]; then 384 opts=linewise:indent 385 elif [[ $context == line ]]; then 386 opts=linewise 387 fi 388 389 # surround 390 if ! ble/lib/vim-surround.sh/surround "$text" "$ins" "$opts"; then 391 ble/widget/vi-command/bell 392 return 1 393 fi 394 local text=$ret 395 396 ble/widget/.replace-range "$beg" "$end" "$text" 397 fi 398 399 _ble_edit_ind=$beg 400 if [[ $context == line ]]; then 401 ble/widget/vi-command/first-non-space 402 else 403 ble/keymap:vi/adjust-command-mode 404 fi 405 ble/keymap:vi/mark/end-edit-area 406 ble/lib/vim-surround.sh/ysurround.repeat/record "$type" "$ins" 407 return 0 408 } 409 410 function ble/widget/vim-surround.sh/ysurround-current-line { 411 ble/widget/vi_nmap/linewise-operator yss 412 } 413 function ble/widget/vim-surround.sh/ySurround-current-line { 414 ble/widget/vi_nmap/linewise-operator ySS 415 } 416 function ble/widget/vim-surround.sh/vsurround { # vS 417 ble/widget/vi-command/operator vS 418 } 419 function ble/widget/vim-surround.sh/vgsurround { # vgS 420 [[ $_ble_decode_keymap == vi_xmap ]] && 421 ble/keymap:vi/xmap/add-eol-extension # 末尾拡張 422 ble/widget/vi-command/operator vgS 423 } 424 425 # repeat (nmap .) 用の変数・関数 426 _ble_lib_vim_surround_ys_repeat=() 427 function ble/lib/vim-surround.sh/ysurround.repeat/entry { 428 local -a _ble_keymap_vi_repeat _ble_keymap_vi_repeat_irepeat 429 ble/keymap:vi/repeat/record-normal 430 _ble_lib_vim_surround_ys_repeat=("${_ble_keymap_vi_repeat[@]}") 431 } 432 function ble/lib/vim-surround.sh/ysurround.repeat/record { 433 ble/keymap:vi/repeat/record-special && return 0 434 local type=$1 ins=$2 435 _ble_keymap_vi_repeat=("${_ble_lib_vim_surround_ys_repeat[@]}") 436 _ble_keymap_vi_repeat_irepeat=() 437 _ble_keymap_vi_repeat[10]=$type 438 _ble_keymap_vi_repeat[11]=$ins 439 case $type in 440 (vS|vgS) 441 _ble_keymap_vi_repeat[2]='ble/widget/vi-command/operator ysurround.repeat' 442 _ble_keymap_vi_repeat[4]= ;; 443 (yss|ySS) 444 _ble_keymap_vi_repeat[2]='ble/widget/vi_nmap/linewise-operator ysurround.repeat' 445 _ble_keymap_vi_repeat[4]= ;; 446 (*) 447 _ble_keymap_vi_repeat[4]=ysurround.repeat 448 esac 449 } 450 function ble/keymap:vi/operator:ysurround.repeat { 451 _ble_lib_vim_surround_ys_type=${_ble_keymap_vi_repeat[10]} 452 _ble_lib_vim_surround_ys_args=("$@") 453 [[ $3 == block ]] && _ble_lib_vim_surround_ys_ranges=("${sub_ranges[@]}") 454 local ins=${_ble_keymap_vi_repeat[11]} 455 ble/widget/vim-surround.sh/ysurround.core "$ins" 456 } 457 458 #------------------------------------------------------------------------------ 459 # ds cs 460 461 # 仕様: surround.vim の実装は杜撰なのでここで vim-surround.sh の独自仕様を定める。 462 # 463 # ds, cs は続いて /([0-9]+| )?./ の形式の引数を受け取る。 464 # 465 # /[0-9]+/ が指定された時は引数に対する倍率を表す。 466 # 467 # / / が指定された時は囲みの内側にある空白も削除することを表す。 468 # 469 # /./ として wW を指定したときは何も削除しない。 470 # c = b)B}r]a> を指定した時は text-object {arg}ic を残して {arg}ac を削除する。 471 # c = ({[< を指定した時は更に内側の空白も削除する。 472 # c = '"` を指定した場合には引数は無視する。ic を残して ac を削除する。 473 # それ以外の c = a-zA-Z は既定として text-object {arg}ic を残し {arg}ac を削除する。 474 # それ以外の文字に関しては行内で一致を検索する。 475 # 476 # 更に cs は続いて / ?./ の形式の引数を受け取る。 477 # 478 # / / が指定されたtときは左右内側に空白を 1 つずつ付加する。 479 # 480 # オリジナルの surround.vim とはところどころで振る舞いが異なる。 481 # 振る舞いの違いに関しては ble.sh/memo.txt #D0457 を参照のこと。 482 # 483 # ToDo: ds, cs において囲まれている対象に改行が含まれる場合、 484 # 置換を行った後に関係する行を == でインデントする。 485 # 現在、本体で = に対応していないのでこれも未対応である。 486 # 487 488 ## @fn ble/keymap:vi/operator:surround 489 ## @var[in] surround_content 490 ## @var[in] surround_ins 491 ## @var[in] surround_trim 492 ## @var[in] surround_type 493 ## ds cs cS の何れかの値 494 function ble/keymap:vi/operator:surround.record { :; } 495 function ble/keymap:vi/operator:surround { 496 local beg=$1 end=$2 context=$3 497 local content=$surround_content ins=$surround_ins trims=$surround_trim 498 499 local ret 500 if [[ $trims ]]; then 501 ble/string#trim "$content"; content=$ret 502 fi 503 504 local opts=; [[ $surround_type == cS ]] && opts=linewise 505 if ! ble/lib/vim-surround.sh/surround "$content" "$ins" "$opts"; then 506 ble/widget/vi-command/bell 507 return 0 508 fi 509 content=$ret 510 511 ble/widget/.replace-range "$beg" "$end" "$content" 512 513 # if [[ $has_nl ]]; then 514 # # ToDo: indent 515 # fi 516 517 return 0 518 } 519 ## @fn ble/keymap:vi/operator:surround-extract-region 520 ## 着色の為に範囲を抽出するオペレータ 521 ## @var[out] surround_beg 522 ## @var[out] surround_end 523 function ble/keymap:vi/operator:surround-extract-region { 524 surround_beg=$beg surround_end=$end 525 return 147 # 強制中断する為 526 } 527 528 ## @arr _ble_lib_vim_surround_cs 529 ## 処理途中の情報はここに記録する。 530 ## 以下の要素は指定された引数を記録する。 531 ## 532 ## [0]=type 533 ## ds | cs | cS 534 ## [1]=arg 535 ## [2]=reg 536 ## [3]=del 537 ## 538 ## 以下の要素は引数から計算される途中の変数を保持する。 539 ## 540 ## [11]=del2 541 ## [12]=obj1 [13]=obj2 542 ## [14]=beg [15]=end 543 ## [16]=arg2 544 ## [17]=trim 545 ## 546 _ble_lib_vim_surround_cs=() 547 548 function ble/widget/vim-surround.sh/nmap/csurround.initialize { 549 _ble_lib_vim_surround_cs=("${@:1:3}") 550 return 0 551 } 552 function ble/widget/vim-surround.sh/nmap/csurround.set-delimiter { 553 local type=${_ble_lib_vim_surround_cs[0]} 554 local arg=${_ble_lib_vim_surround_cs[1]} 555 local reg=${_ble_lib_vim_surround_cs[2]} 556 _ble_lib_vim_surround_cs[3]=$1 557 558 local trim= 559 [[ $del == ' '?* ]] && trim=1 del=${del:1} 560 if [[ $del == a ]]; then 561 del='>' 562 elif [[ $del == r ]]; then 563 del=']' 564 elif [[ $del == T ]]; then 565 del='t' trim=1 566 fi 567 568 local obj1= obj2= 569 case $del in 570 ([wWps]) obj1=i$del obj2=i$del ;; 571 ([\'\"\`]) obj1=i$del obj2=a$del arg=1 ;; 572 (['bB)}>]t']) obj1=i$del obj2=a$del ;; 573 (['({<[']) obj1=i$del obj2=a$del trim=1 ;; 574 ([a-zA-Z]) obj1=i$del obj2=a$del ;; 575 esac 576 577 local beg end 578 if [[ $obj1 && $obj2 ]]; then 579 # テキストオブジェクトによって指定される範囲 580 581 local surround_beg=$_ble_edit_ind surround_end=$_ble_edit_ind 582 ble/keymap:vi/text-object.impl "$arg" surround-extract-region '' "$obj2" 583 beg=$surround_beg end=$surround_end 584 elif [[ $del == / ]]; then 585 # /* .. */ で囲まれた部分 586 587 local rex='(/\*([^/]|/[^*])*/?){1,'$arg'}$' 588 [[ ${_ble_edit_str::_ble_edit_ind+2} =~ $rex ]] || return 1 589 beg=$((_ble_edit_ind+2-${#BASH_REMATCH})) 590 591 ble/string#index-of "${_ble_edit_str:beg+2}" '*/' || return 1 592 end=$((beg+ret+4)) 593 elif [[ $del ]]; then 594 # 指定した文字で囲まれた部分 595 596 local ret 597 ble-edit/content/find-logical-bol; local bol=$ret 598 ble-edit/content/find-logical-eol; local eol=$ret 599 local line=${_ble_edit_str:bol:eol-bol} 600 local ind=$((_ble_edit_ind-bol)) 601 602 # beg 603 if ble/string#last-index-of "${line::ind}" "$del"; then 604 beg=$ret 605 elif local base=$((ind-(2*${#del}-1))); ((base>=0||(base=0))) 606 ble/string#index-of "${line:base:ind+${#del}-base}" "$del"; then 607 beg=$((base+ret)) 608 else 609 return 1 610 fi 611 612 # end 613 ble/string#index-of "${line:beg+${#del}}" "$del" || return 1 614 end=$((beg+2*${#del}+ret)) 615 616 ((beg+=bol,end+=bol)) 617 fi 618 619 _ble_lib_vim_surround_cs[11]=$del 620 _ble_lib_vim_surround_cs[12]=$obj1 621 _ble_lib_vim_surround_cs[13]=$obj2 622 _ble_lib_vim_surround_cs[14]=$beg 623 _ble_lib_vim_surround_cs[15]=$end 624 _ble_lib_vim_surround_cs[16]=$arg 625 _ble_lib_vim_surround_cs[17]=$trim 626 } 627 function ble/widget/vim-surround.sh/nmap/csurround.replace { 628 local ins=$1 629 630 local type=${_ble_lib_vim_surround_cs[0]} 631 local arg=${_ble_lib_vim_surround_cs[1]} 632 local reg=${_ble_lib_vim_surround_cs[2]} 633 local del=${_ble_lib_vim_surround_cs[3]} 634 635 local del2=${_ble_lib_vim_surround_cs[11]} 636 local obj1=${_ble_lib_vim_surround_cs[12]} 637 local obj2=${_ble_lib_vim_surround_cs[13]} 638 local beg=${_ble_lib_vim_surround_cs[14]} 639 local end=${_ble_lib_vim_surround_cs[15]} 640 local arg2=${_ble_lib_vim_surround_cs[16]} 641 642 local surround_ins=$ins 643 local surround_type=$type 644 local surround_trim=${_ble_lib_vim_surround_cs[17]} 645 646 if [[ $obj1 && $obj2 ]]; then 647 # テキストオブジェクトによって指定される範囲 648 local ind=$_ble_edit_ind 649 650 local _ble_edit_kill_ring _ble_edit_kill_type 651 ble/keymap:vi/text-object.impl "$arg2" y '' "$obj1"; local ext=$? 652 _ble_edit_ind=$ind 653 ((ext!=0)) && return 1 654 655 local surround_content=$_ble_edit_kill_ring 656 ble/keymap:vi/text-object.impl "$arg2" surround '' "$obj2" || return 1 657 elif [[ $del2 == / ]]; then 658 # /* .. */ で囲まれた部分 659 local surround_content=${_ble_edit_str:beg+2:end-beg-4} 660 ble/keymap:vi/call-operator surround "$beg" "$end" char '' '' 661 _ble_edit_ind=$beg 662 elif [[ $del2 ]]; then 663 # 指定した文字で囲まれた部分 664 local surround_content=${_ble_edit_str:beg+${#del2}:end-beg-2*${#del2}} 665 ble/keymap:vi/call-operator surround "$beg" "$end" char '' '' 666 _ble_edit_ind=$beg 667 else 668 ble/widget/vi-command/bell 669 return 1 670 fi 671 ble/widget/vim-surround.sh/nmap/csurround.record "$type" "$arg" "$reg" "$del" "$ins" 672 ble/keymap:vi/adjust-command-mode 673 return 0 674 } 675 676 #---- repeat ---- 677 678 ## @fn ble/widget/vim-surround.sh/nmap/csurround.record 679 function ble/widget/vim-surround.sh/nmap/csurround.record { 680 # Note: ble/keymap:vi/repeat/record の実装に合わせた条件判定。 681 [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0 682 683 local type=$1 arg=$2 reg=$3 del=$4 ins=$5 684 local WIDGET=ble/widget/vim-surround.sh/nmap/csurround.repeat ARG=$arg FLAG= REG=$reg 685 ble/keymap:vi/repeat/record 686 if [[ $_ble_decode_keymap == vi_imap ]]; then 687 # Note: ble/keymap:vi/repeat/record の実装に合わせた条件判定。 688 # この実装では vi_imap で呼び出される事はない筈だが念の為。 689 # ble/keymap:vi/repeat/record は keymap が vi_imap の時は異なる場所に記録する。 690 _ble_keymap_vi_repeat_insert[10]=$type 691 _ble_keymap_vi_repeat_insert[11]=$del 692 _ble_keymap_vi_repeat_insert[12]=$ins 693 else 694 _ble_keymap_vi_repeat[10]=$type 695 _ble_keymap_vi_repeat[11]=$del 696 _ble_keymap_vi_repeat[12]=$ins 697 fi 698 } 699 function ble/widget/vim-surround.sh/nmap/csurround.repeat { 700 local ARG FLAG REG; ble/keymap:vi/get-arg 1 701 local type=${_ble_keymap_vi_repeat[10]} 702 local del=${_ble_keymap_vi_repeat[11]} 703 local ins=${_ble_keymap_vi_repeat[12]} 704 ble/widget/vim-surround.sh/nmap/csurround.initialize "$type" "$ARG" "$REG" && 705 ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del" && 706 ble/widget/vim-surround.sh/nmap/csurround.replace "$ins" && return 0 707 ble/widget/vi-command/bell 708 return 1 709 } 710 711 #---- ds ---- 712 713 function ble/widget/vim-surround.sh/nmap/dsurround { 714 local ARG FLAG REG; ble/keymap:vi/get-arg 1 715 ble/widget/vim-surround.sh/nmap/csurround.initialize ds "$ARG" "$REG" 716 ble/lib/vim-surround.sh/async-inputtarget ble/widget/vim-surround.sh/nmap/dsurround.hook 717 } 718 function ble/widget/vim-surround.sh/nmap/dsurround.hook { 719 local del=$1 720 ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del" && 721 ble/widget/vim-surround.sh/nmap/csurround.replace '' && return 0 722 ble/widget/vi-command/bell 723 return 1 724 } 725 726 #---- cs ---- 727 728 ## @fn ble/highlight/layer:region/mark:vi_surround/get-selection 729 ## 入力待ち状態の時の領域着色を定義します。 730 ## @arr[out] selection 731 function ble/highlight/layer:region/mark:vi_csurround/get-selection { 732 local beg=${_ble_lib_vim_surround_cs[14]} 733 local end=${_ble_lib_vim_surround_cs[15]} 734 selection=("$beg" "$end") 735 } 736 function ble/highlight/layer:region/mark:vi_csurround/get-face { 737 face=region_target 738 } 739 740 function ble/widget/vim-surround.sh/nmap/csurround { 741 ble/widget/vim-surround.sh/nmap/csurround.impl cs 742 } 743 function ble/widget/vim-surround.sh/nmap/cSurround { 744 ble/widget/vim-surround.sh/nmap/csurround.impl cS 745 } 746 function ble/widget/vim-surround.sh/nmap/csurround.impl { 747 local ARG FLAG REG; ble/keymap:vi/get-arg 1 748 local type=$1 749 ble/widget/vim-surround.sh/nmap/csurround.initialize "$type" "$ARG" "$REG" 750 ble/lib/vim-surround.sh/async-inputtarget ble/widget/vim-surround.sh/nmap/csurround.hook1 751 } 752 function ble/widget/vim-surround.sh/nmap/csurround.hook1 { 753 local del=$1 754 if [[ $del ]] && ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del"; then 755 _ble_edit_mark_active=vi_csurround 756 ble/lib/vim-surround.sh/async-inputtarget-noarg ble/widget/vim-surround.sh/nmap/csurround.hook2 757 return "$?" 758 fi 759 760 _ble_lib_vim_surround_cs=() 761 ble/widget/vi-command/bell 762 return 1 763 } 764 function ble/widget/vim-surround.sh/nmap/csurround.hook2 { 765 local ins=$1 766 if local rex='^ ?[<tT]$'; [[ $ins =~ $rex ]]; then 767 ble/lib/vim-surround.sh/async-read-tagname "ble/widget/vim-surround.sh/nmap/csurround.hook3 '$ins'" 768 else 769 ble/widget/vim-surround.sh/nmap/csurround.hook3 "$ins" 770 fi 771 } 772 ## @fn ble/widget/vim-surround.sh/nmap/csurround.hook3 ins [tagName] 773 function ble/widget/vim-surround.sh/nmap/csurround.hook3 { 774 local ins=$1 tagName=$2 775 _ble_edit_mark_active= # clear mark:vi_csurround 776 ble/widget/vim-surround.sh/nmap/csurround.replace "$ins$tagName" && return 0 777 ble/widget/vi-command/bell 778 return 1 779 } 780 781 #------------------------------------------------------------------------------ 782 783 function ble/widget/vim-surround.sh/omap { 784 local ret n=${#KEYS[@]} 785 if ! ble/keymap:vi/k2c "${KEYS[n?n-1:0]}"; then 786 ble/widget/.bell 787 return 1 788 fi 789 ble/util/c2s "$ret"; local s=$ret 790 791 local opfunc=${_ble_keymap_vi_opfunc%%:*}$s 792 local opflags=${_ble_keymap_vi_opfunc#*:} 793 case $opfunc in 794 (y[sS]) 795 local ARG FLAG REG; ble/keymap:vi/get-arg 1 796 _ble_edit_arg=$ARG 797 _ble_keymap_vi_reg=$REG 798 ble/decode/keymap/pop 799 ble/widget/vi-command/operator "$opfunc:$opflags" ;; 800 (yss) 801 ble/widget/vi_nmap/linewise-operator "yss:$opflags" ;; 802 (yS[sS]) 803 ble/widget/vi_nmap/linewise-operator "ySS:$opflags" ;; 804 (ds) ble/widget/vim-surround.sh/nmap/dsurround ;; 805 (cs) ble/widget/vim-surround.sh/nmap/csurround ;; 806 (cS) ble/widget/vim-surround.sh/nmap/cSurround ;; 807 (*) ble/widget/.bell ;; 808 esac 809 } 810 811 ble-bind -m vi_xmap -f 'S' vim-surround.sh/vsurround 812 ble-bind -m vi_xmap -f 'g S' vim-surround.sh/vgsurround 813 814 if [[ $bleopt_vim_surround_omap_bind ]]; then 815 ble-bind -m vi_omap -f s 'vim-surround.sh/omap' 816 ble-bind -m vi_omap -f S 'vim-surround.sh/omap' 817 else 818 ble-bind -m vi_nmap -f 'y s' 'vi-command/operator ys' 819 ble-bind -m vi_nmap -f 'y s s' 'vim-surround.sh/ysurround-current-line' 820 ble-bind -m vi_nmap -f 'y S' 'vi-command/operator yS' 821 ble-bind -m vi_nmap -f 'y S s' 'vim-surround.sh/ySurround-current-line' 822 ble-bind -m vi_nmap -f 'y S S' 'vim-surround.sh/ySurround-current-line' 823 ble-bind -m vi_nmap -f 'd s' 'vim-surround.sh/nmap/dsurround' 824 ble-bind -m vi_nmap -f 'c s' 'vim-surround.sh/nmap/csurround' 825 ble-bind -m vi_nmap -f 'c S' 'vim-surround.sh/nmap/cSurround' 826 fi