2009年11月12日木曜日

MacVim-KaoriYaのformat.vimを正しく動かす

※正確には、encoding=utf-8を指定したvimの話。

format.vimは、vimにおける禁則処理等の文章整形用のスクリプト。
MacVim-Kaoriyaの環境においては動作不備が確認される。
具体的には、インラインモードにて行末禁止文字を打ち込んだ場合、本来改行すべき桁数よりかなり前の桁にて改行される。(正確にはtextwidthに指定した数値の2/3の桁数)

これは、format.vimの内部処理にて、マルチバイト文字の表示幅として、文字のバイト数をそのまま用いているためである。
マルチバイト文字のバイト数は、encoding=cp932(windowsでのデフォルト)の場合は「2バイト」となり特に問題は起きないが、encoding=utf-8の場合、「3バイト」となるため、これをそのまま表示幅として用いることが出来ない。

これを回避するため、以下の様な修正を行った。

--- format.vim.org 2009-10-27 09:00:56.000000000 +0900
+++ format.vim 2009-11-12 17:13:28.000000000 +0900
@@ -686,17 +686,17 @@
   let back_count = 0
   let no_begin = s:GetOption('format_no_begin')
   let no_end = s:GetOption('format_no_end')
-  let curr_char = matchstr(a:curr_line, '\%'.a:curr_col.'c.')
+  let curr_char = matchstr(a:curr_line, '\%'.a:curr_col.'v.')
   let back_col = 0
   while 1
-    let prev_char = matchstr(a:curr_line, '.\%'.(a:curr_col - back_col).'c')
+    let prev_char = matchstr(a:curr_line, '.\%'.(a:curr_col - back_col).'v')
     if curr_char == ''
       let back_count = 0
       break
     elseif s:IsTaboo(curr_char, no_begin) || s:IsTaboo(prev_char, no_end)
       let back_count += 1
       let curr_char = prev_char
-      let back_col += strlen(curr_char)
+      let back_col += (strlen(curr_char) > 1 ? 2 : strlen(curr_char))
     else
       break
     endif
@@ -712,10 +712,10 @@
     " Too difficult to implement.
     return 1
   else
-    let curcol = col('.')
+    let curcol = virtcol('.')
     " v:charを入力した後で&textwidthを超える場合に改行位置の補正を行う
     let new_line = getline('.') . v:char
-    if curcol + strlen(v:char) > &textwidth
+    if curcol + (strlen(v:char) > 1 ? 2 : strlen(v:char)) > &textwidth
       let back_count = s:GetLinebreakOffset(new_line, curcol)
       " カーソル移動と改行の挿入を行う
       if back_count > 0

以上により、encoding=utf-8の環境においても、encoding=cp932の環境と同等の動作を期待出来る。

※ref : MacVim-KaoriYa (http://code.google.com/p/macvim-kaoriya/)
※ref : format.vim (http://www.kaoriya.net/doc/vim_script.html)
※source var : format.vim 1.7rc2 03-Mar-2007. in MacVim-KaoriYa 20091027


ここからはオリジナルの動作に対するコメント。
  1. 現状、textwidth値ジャストに行末禁止文字を入力すると、改行が実施されてしまう。
    本来であれば、textwidth値に収まっているのであるから、改行は不要の様に思う。
    ちなみに、gqコマンドであれば改行されない。
  2. 現状のアルゴリズムだと、textwidthを1バイトだけ超える、行末禁止文字「以外」の文字が行末に入力された場合に、正しく改行が挿入されないことになる。
    例えば、textwidth=10の場合に、"aあああああ"という文字を入力すると、最後の「あ」が改行されない。
    実質的にはtextwidthを超えているため、改行されるべきの様に思う。
    ちなみに、gqコマンドであれば改行される。

なお、(1)については、L:718の部分を、以下の様にすることで正しい動作が期待出来る。

-    if curcol + strlen(v:char) > &textwidth
+    if curcol + (strlen(v:char) > 1 ? 2 : strlen(v:char)) - 1 > &textwidth

(2)については、ASCIIの入力が若干絡むため、少しめんどくさい気がする。
こちらについては、追って検討したい。

0 件のコメント: