実現したいこと
Vim のスクリプトに関する質問です。
現在、下記の様に、特定のキーを押すと、カーソルより一つ前の文字が切り替わるプラグインを作成しています。
(下記例では、「A」を押下することで、A->B->C->D->E->A->B->...と、切り替わります。)
現状、シングルバイト->シングルバイト、マルチバイト->マルチバイトの切り替えはうまく動いているのですが、
カーソルが行末(or 行末より一つ前) にある時においてのみ、マルチバイト->シングルバイトの切り替えが
うまくいきません。(下記の様にカーソルの位置がずれてしまいます。)
これをどんな場合でも、連続した切り替えを成功させる方法をご教示いただけないでしょうか。
試したこと
問題の切り分けを行った結果、行末のマルチバイト文字の後ろにカーソルがある場合、
col('.')の値が以下の例の様になることがわかりました。
例)
| = インサートモードにおけるカーソル位置
Aあ|AA の場合 col('.')=> 4
Aあ|A の場合 col('.')=> 3
Aあ| の場合 col('.')=> 2
※文字コードを utf-8 なので、日本語一文字が 3byte になっています。
該当のソースコード
Vim
1"マッピングするためのメイン関数" 2function! SwitchChar(switch_list,key) 3 "引数が辞書型以外の場合に却下" 4 if type(a:switch_list) != type([]) 5 finish "Argument requires List type!" 6 endif 7 8 let cnt_chr= GetCurrentChar() 9 if SearchList(a:switch_list, cnt_chr) < 0 10 return a:key 11 endif 12 13 call SingleSwitch(cnt_chr, a:switch_list) 14 return '' 15endfunction 16 17 18"現在の文字が切り替え対象の文字かをチェック" 19function! SearchList(switch_list, chr) 20 for item in a:switch_list 21 if item ==# a:chr 22 return match(a:switch_list, a:chr) 23 endif 24 endfor 25 return -1 26endfunction 27 28 29function! GetCurrentChar() 30 if col('.') == 1 31 return '\0' 32 endif 33 34 return matchstr(strpart(getline('.'), 0, col('.')-1), ".$") 35endfunction 36 37 38function! SingleSwitch(cnt_chr, switch_list) 39 let next_chr = a:switch_list[(match(a:switch_list, a:cnt_chr)+1) % len(a:switch_list)] 40 let cnt_chr = a:cnt_chr 41 42 call setline(line("."), 43 \ strpart(getline('.'), 0, col('.')-1 -len(cnt_chr)).next_chr.strpart(getline('.'), col('.')-1)) 44 "↓ここのカーソル位置の調整でおかしくなる" 45 call cursor(".", col('.') +(len(next_chr) - len(cnt_chr))) 46 47 return "\<BS>\<BS>" 48endfunction 49 50 51"下記の様にキーと切り替え文字のリストをマッピングして使用する" 52inoremap <buffer>A <C-R>=SwitchChar(["A","B","C","D","E"], "A")<CR> 53inoremap <buffer>. <C-R>=SwitchChar([".", "…"], ".")<CR>
あなたの回答
tips
プレビュー