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()