I found some unexpected behavior of text formatting.

1) :set ai tw=2 fo=m

            [input]           [result]        [expected]
            1|  Xa|    ->    infinite loop   1|  X|
                       gqgq                   2|  a|

("X" is U+FF38, double-width character)


2) :set noai tw=2 fo=m

            [input]           [result]        [expected]
            1|  Xa|    ->    1|  |           1|  X|
                       gqgq   2|X|           2|a|
                              3|a|


3) :set tw=1 fo=m

            [input]           [result]        [expected]
            1|Xa|      ->    1|Xa|          1|X|
                       gqgq                   2|a|


4) :set tw=2 fo=m

            [input]           [result]        [expected]
            1|aX|      ->    1|aX|          1|a|
                       gqgq                   2|X|


5) :set tw=2 fo=m

            [input]           [result]        [expected]
            1|abX|     ->    1|abX|         1|ab|
                       gqgq                   2|X|


6) :set tw=3 fo=

            [input]           [result]        [expected]
            1|a ^A|     ->    1|a ^A|         1|a|
                       gqgq                   2|^A|


7) :set tw=2 fo=mq comments=:X

            [input]           [result]        [expected]
            1|Xa|      ->    infinite loop   1|Xa|
                       gqgq


8) :set tw=2 fo=mt        (insert with replace mode)

            [input]           [result]        [expected]
            1||         ->    crash           1|X|
            (empty)   "RXa"                  2|a|


9) :set noai tw=2 fo=t    (insert with virtual replace mode)

            [input]           [result]        [expected]
            1|    |     ->    1|a|            1|a|
              ^      "gRa b"  2|bXXXX|        2|b|
              cursor              ^
                             random text


10) :set ai tw=2 fo=wt

            [input]           [result]        [expected]
            1|a    |    ->    1|a    |        1|a  |
                 ^     "ib"   2|b|            2|b|
               cursor


Attached patch fixes this problem.

1-8.diff is for (1) to (8), fix for multi-byte/double-width
(including ctrl-char like ^A) character.

9.diff is for (9).

10.diff is for (10).

Each patch can be applied separately.

test.vim is a test script to reproduce.


-- 
Yukihiro Nakadaira - [email protected]


















--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---

=== modified file 'src/edit.c'
*** src/edit.c	2009-07-10 03:04:52 +0000
--- src/edit.c	2009-09-26 13:36:08 +0000
***************
*** 181,187 ****
  static void ins_ctrl_v __ARGS((void));
  static void undisplay_dollar __ARGS((void));
  static void insert_special __ARGS((int, int, int));
! static void internal_format __ARGS((int textwidth, int second_indent, int flags, int format_only));
  static void check_auto_format __ARGS((int));
  static void redo_literal __ARGS((int c));
  static void start_arrow __ARGS((pos_T *end_insert_pos));
--- 181,187 ----
  static void ins_ctrl_v __ARGS((void));
  static void undisplay_dollar __ARGS((void));
  static void insert_special __ARGS((int, int, int));
! static void internal_format __ARGS((int textwidth, int second_indent, int flags, int format_only, int c));
  static void check_auto_format __ARGS((int));
  static void redo_literal __ARGS((int c));
  static void start_arrow __ARGS((pos_T *end_insert_pos));
***************
*** 5558,5564 ****
  	}
  	if (do_internal)
  #endif
! 	    internal_format(textwidth, second_indent, flags, c == NUL);
      }
  
      if (c == NUL)	    /* only formatting was wanted */
--- 5558,5564 ----
  	}
  	if (do_internal)
  #endif
! 	    internal_format(textwidth, second_indent, flags, c == NUL, c);
      }
  
      if (c == NUL)	    /* only formatting was wanted */
***************
*** 5738,5748 ****
   * Format text at the current insert position.
   */
      static void
! internal_format(textwidth, second_indent, flags, format_only)
      int		textwidth;
      int		second_indent;
      int		flags;
      int		format_only;
  {
      int		cc;
      int		save_char = NUL;
--- 5738,5749 ----
   * Format text at the current insert position.
   */
      static void
! internal_format(textwidth, second_indent, flags, format_only, c)
      int		textwidth;
      int		second_indent;
      int		flags;
      int		format_only;
+     int		c; /* character to be inserted (can be NUL) */
  {
      int		cc;
      int		save_char = NUL;
***************
*** 5789,5797 ****
  	char_u	*saved_text = NULL;
  #endif
  	colnr_T	col;
  
! 	virtcol = get_nolist_virtcol();
! 	if (virtcol < (colnr_T)textwidth)
  	    break;
  
  #ifdef FEAT_COMMENTS
--- 5790,5800 ----
  	char_u	*saved_text = NULL;
  #endif
  	colnr_T	col;
+ 	colnr_T	end_col;
  
! 	virtcol = get_nolist_virtcol()
! 		+ char2cells(c != NUL ? c : gchar_cursor());
! 	if (virtcol <= (colnr_T)textwidth)
  	    break;
  
  #ifdef FEAT_COMMENTS
***************
*** 5831,5842 ****
  	coladvance((colnr_T)textwidth);
  	wantcol = curwin->w_cursor.col;
  
! 	curwin->w_cursor.col = startcol - 1;
! #ifdef FEAT_MBYTE
! 	/* Correct cursor for multi-byte character. */
! 	if (has_mbyte)
! 	    mb_adjust_cursor();
! #endif
  	foundcol = 0;
  
  	/*
--- 5834,5840 ----
  	coladvance((colnr_T)textwidth);
  	wantcol = curwin->w_cursor.col;
  
! 	curwin->w_cursor.col = startcol;
  	foundcol = 0;
  
  	/*
***************
*** 5847,5857 ****
  		    || curwin->w_cursor.lnum != Insstart.lnum
  		    || curwin->w_cursor.col >= Insstart.col)
  	{
! 	    cc = gchar_cursor();
  	    if (WHITECHAR(cc))
  	    {
  		/* remember position of blank just before text */
! 		end_foundcol = curwin->w_cursor.col;
  
  		/* find start of sequence of blanks */
  		while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
--- 5845,5858 ----
  		    || curwin->w_cursor.lnum != Insstart.lnum
  		    || curwin->w_cursor.col >= Insstart.col)
  	{
! 	    if (curwin->w_cursor.col == startcol && c != NUL)
! 		cc = c;
! 	    else
! 		cc = gchar_cursor();
  	    if (WHITECHAR(cc))
  	    {
  		/* remember position of blank just before text */
! 		end_col = curwin->w_cursor.col;
  
  		/* find start of sequence of blanks */
  		while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
***************
*** 5880,5905 ****
  			continue;	/* one-letter, continue */
  		    curwin->w_cursor.col = col;
  		}
! #ifdef FEAT_MBYTE
! 		if (has_mbyte)
! 		    foundcol = curwin->w_cursor.col
! 					 + (*mb_ptr2len)(ml_get_cursor());
! 		else
! #endif
! 		    foundcol = curwin->w_cursor.col + 1;
! 		if (curwin->w_cursor.col < (colnr_T)wantcol)
  		    break;
  	    }
  #ifdef FEAT_MBYTE
! 	    else if (cc >= 0x100 && fo_multibyte
! 			      && curwin->w_cursor.col <= (colnr_T)wantcol)
  	    {
  		/* Break after or before a multi-byte character. */
  		foundcol = curwin->w_cursor.col;
- 		if (curwin->w_cursor.col < (colnr_T)wantcol)
- 		    foundcol += (*mb_char2len)(cc);
  		end_foundcol = foundcol;
! 		break;
  	    }
  #endif
  	    if (curwin->w_cursor.col == 0)
--- 5881,5940 ----
  			continue;	/* one-letter, continue */
  		    curwin->w_cursor.col = col;
  		}
! 
! 		inc_cursor();
! 
! 		end_foundcol = end_col + 1;
! 		foundcol = curwin->w_cursor.col;
! 		if (curwin->w_cursor.col <= (colnr_T)wantcol)
  		    break;
  	    }
  #ifdef FEAT_MBYTE
! 	    else if (cc >= 0x100 && fo_multibyte)
  	    {
  		/* Break after or before a multi-byte character. */
+ 		if (curwin->w_cursor.col != startcol)
+ 		{
+ #ifdef FEAT_COMMENTS
+ 		    /* Don't break until after the comment leader */
+ 		    if (curwin->w_cursor.col < leader_len)
+ 			break;
+ #endif
+ 		    col = curwin->w_cursor.col;
+ 		    inc_cursor();
+ 		    /* Don't change end_foundcol if already set. */
+ 		    if (foundcol != curwin->w_cursor.col)
+ 		    {
+ 			foundcol = curwin->w_cursor.col;
+ 			end_foundcol = foundcol;
+ 			if (curwin->w_cursor.col <= (colnr_T)wantcol)
+ 			    break;
+ 		    }
+ 		    curwin->w_cursor.col = col;
+ 		}
+ 
+ 		if (curwin->w_cursor.col == 0)
+ 		    break;
+ 
+ 		col = curwin->w_cursor.col;
+ 
+ 		dec_cursor();
+ 		cc = gchar_cursor();
+ 
+ 		if (WHITECHAR(cc))
+ 		    continue;		/* break with space */
+ #ifdef FEAT_COMMENTS
+ 		/* Don't break until after the comment leader */
+ 		if (curwin->w_cursor.col < leader_len)
+ 		    break;
+ #endif
+ 
+ 		curwin->w_cursor.col = col;
+ 
  		foundcol = curwin->w_cursor.col;
  		end_foundcol = foundcol;
! 		if (curwin->w_cursor.col <= (colnr_T)wantcol)
! 		    break;
  	    }
  #endif
  	    if (curwin->w_cursor.col == 0)
***************
*** 5926,5932 ****
  	    orig_col = startcol;	/* Will start backspacing from here */
  	else
  #endif
! 	    replace_offset = startcol - end_foundcol - 1;
  
  	/*
  	 * adjust startcol for spaces that will be deleted and
--- 5961,5967 ----
  	    orig_col = startcol;	/* Will start backspacing from here */
  	else
  #endif
! 	    replace_offset = startcol - end_foundcol;
  
  	/*
  	 * adjust startcol for spaces that will be deleted and




=== modified file 'src/edit.c'
*** src/edit.c	2009-07-10 03:04:52 +0000
--- src/edit.c	2009-09-26 13:36:32 +0000
***************
*** 5763,5769 ****
       * When 'ai' is off we don't want a space under the cursor to be
       * deleted.  Replace it with an 'x' temporarily.
       */
!     if (!curbuf->b_p_ai)
      {
  	cc = gchar_cursor();
  	if (vim_iswhite(cc))
--- 5763,5773 ----
       * When 'ai' is off we don't want a space under the cursor to be
       * deleted.  Replace it with an 'x' temporarily.
       */
!     if (!curbuf->b_p_ai
! #ifdef FEAT_VREPLACE
! 	    && !(State & VREPLACE_FLAG)
! #endif
! 	    )
      {
  	cc = gchar_cursor();
  	if (vim_iswhite(cc))




=== modified file 'src/edit.c'
*** src/edit.c	2009-07-10 03:04:52 +0000
--- src/edit.c	2009-09-26 13:36:40 +0000
***************
*** 5933,5939 ****
  	 * characters that will remain on top line
  	 */
  	curwin->w_cursor.col = foundcol;
! 	while (cc = gchar_cursor(), WHITECHAR(cc))
  	    inc_cursor();
  	startcol -= curwin->w_cursor.col;
  	if (startcol < 0)
--- 5933,5940 ----
  	 * characters that will remain on top line
  	 */
  	curwin->w_cursor.col = foundcol;
! 	while ((cc = gchar_cursor(), WHITECHAR(cc))
! 		    && (!fo_white_par || curwin->w_cursor.col < startcol))
  	    inc_cursor();
  	startcol -= curwin->w_cursor.col;
  	if (startcol < 0)




" coding: utf-8
" Test for text formatting.

" :setl ai tw=2 fo=m
" |  Xa| -> |  X|
"            |  a|
function! Test1()
  let expected = ["  X", "  a"]

  botright vnew __test1__expected__
  call setline(1, expected)

  belowright new __test1__result__normal__
  setl ai tw=2 fo=m
  execute "normal! i  Xa\<Esc>gqgqgg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif

  belowright new __test1__result__insert__
  setl ai tw=2 fo=mt
  execute "normal! i  Xa\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl noai tw=2 fo=m
" |  Xa| -> |  X|
"            |a|
function! Test2()
  let expected = ["  X", "a"]

  botright vnew __test2__expected__
  call setline(1, expected)

  belowright new __test2__result__normal__
  setl noai tw=2 fo=m
  execute "normal! i  Xa\<Esc>gqgqgg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif

  belowright new __test2__result__insert__
  setl noai tw=2 fo=mt
  execute "normal! i  Xa\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl tw=1 fo=m
" |Xa| -> |X|
"          |a|
function! Test3()
  let expected = ["X", "a"]

  botright vnew __test3__expected__
  call setline(1, expected)

  belowright new __test3__result__normal__
  setl tw=1 fo=m
  execute "normal! iXa\<Esc>gqgqgg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif

  belowright new __test3_result_insert__
  setl tw=1 fo=mt
  execute "normal! iXa\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl tw=2 fo=m
" |aX| -> |a|
"          |X|
function! Test4()
  let expected = ["a", "X"]

  botright vnew __test4__expected__
  call setline(1, expected)

  belowright new __test4__result__normal__
  setl tw=2 fo=m
  execute "normal! iaX\<Esc>gqgqgg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif

  belowright new __test4_result_insert__
  setl tw=2 fo=mt
  execute "normal! iaX\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl tw=2 fo=m
" |abX| -> |ab|
"           |X|
function! Test5()
  let expected = ["ab", "X"]

  botright vnew __test5__expected__
  call setline(1, expected)

  belowright new __test5__result__normal__
  setl tw=2 fo=m
  execute "normal! iabX\<Esc>gqgqgg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif

  belowright new __test5_result_insert__
  setl tw=2 fo=mt
  execute "normal! iabX\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl tw=3 fo=
" |a ^A| -> |a|
"           |^A|
function! Test6()
  let expected = ["a", "\<C-A>"]

  botright vnew __test6__expected__
  call setline(1, expected)

  belowright new __test6__result__normal__
  setl tw=3 fo=
  execute "normal! ia \<C-V>\<C-A>\<Esc>gqgqgg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif

  belowright new __test6_result_insert__
  setl tw=3 fo=t
  execute "normal! ia \<C-V>\<C-A>\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl tw=2 fo=mq comments=:X
" 1|Xa| -> 1|Xa|
function! Test7()
  let expected = ["Xa"]

  botright vnew __test7__expected__
  call setline(1, expected)

  belowright new __test7__result__normal__
  setl tw=2 fo=mq comments=:X
  execute "normal! iXa\<Esc>gqgqgg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif

  belowright new __test7_result_insert__
  setl tw=2 fo=mc comments=:X
  execute "normal! iXa\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl tw=2 fo=mt    (insert with replace mode)
" RXa -> 1|X|
"         2|a|
function! Test8()
  let expected = ["X", "a"]

  botright vnew __test8__expected__
  call setline(1, expected)

  belowright new __test8__result__replace__
  setl tw=2 fo=mt
  execute "normal! RXa\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl noai tw=2 fo=t    (insert with virtual replace mode)
" 1|    |   ->    1|a|
"        "gRa b"  2|b|
function! Test9()
  let expected = ["a", "b"]

  botright vnew __test9__expected__
  call setline(1, expected)

  belowright new __test9__result__replace__
  setl noai tw=2 fo=t
  execute "normal! i    \<Esc>0gRa b\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction

" :setl ai tw=2 fo=wt
" 1|a    | -> 1|a  |
"      ^ "ib" 2|b|
function! Test10()
  let expected = ["a  ", "b"]

  botright vnew __test10__expected__
  setl list   " to show trailing spaces
  call setline(1, expected)

  belowright new __test10_result_insert__
  setl ai tw=2 fo=wt
  setl list   " to show trailing spaces
  execute "normal! ia    \<Esc>\<Left>ib\<Esc>gg"
  if expected != getline(1, "$")
    echoerr bufname("%")
  endif
endfunction


call Test1()
call Test2()
call Test3()
call Test4()
call Test5()
call Test6()
call Test7()
call Test8()
call Test9()
call Test10()

Raspunde prin e-mail lui