Bram,
the breakindent feature has a bug, if an overlong line is written on the 
screen and the first chars are skipped. In that case, if the line is 
indented, the first visual line also needs to display an indent. If you 
move to the last character using $ the cursor will be moved after the 
last displayed character. Attached is a patch which fixes the issue.

Also included is a rewrite of the current test_breakindent oldstyle test 
to a new style test. That part was harder than I initially thought, 
because after having created several tests I saw some failures of 
previously successful tests when adding new tests. I think this was 
because the caching of the indent kicked in and lead to strange non 
reproducible errors.

Another thing to notice is that I added a test for the currently fixed 
bug, however it does not fail for older vims, although it does when run 
interactively. But after having already spent too much time in 
converting the test, I'll just leave it as is, because I don't think it 
makes much sense to spend even more time on it.

Best,
Christian
-- 
Je reiner die Schuld der Opfer, desto schmutziger die Hände der
Henker.
                -- Stanislaw Jerzy Lec (eig. S. J. de Tusch-Letz)

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
From 3a0f690dc3fd8b1f288aba46359da96172f276fb Mon Sep 17 00:00:00 2001
From: Christian Brabandt <c...@256bit.org>
Date: Thu, 10 Nov 2016 21:48:21 +0100
Subject: [PATCH] Fix a problem with overlong lines and breakindent

When a line does start halfway on a screen and is indented,
breakindent must also be applied.

Add new style test for breakindent

Remove old style breakindent test
---
 src/screen.c                     |   7 +-
 src/testdir/Make_all.mak         |   2 +-
 src/testdir/test_breakindent.in  | 122 --------------------
 src/testdir/test_breakindent.ok  |  74 ------------
 src/testdir/test_breakindent.vim | 242 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 247 insertions(+), 200 deletions(-)
 delete mode 100644 src/testdir/test_breakindent.in
 delete mode 100644 src/testdir/test_breakindent.ok
 create mode 100644 src/testdir/test_breakindent.vim

diff --git a/src/screen.c b/src/screen.c
index 621f25c..c5824b0 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -3010,7 +3010,7 @@ win_line(
 #endif
     colnr_T	trailcol = MAXCOL;	/* start of trailing spaces */
 #ifdef FEAT_LINEBREAK
-    int		need_showbreak = FALSE;
+    int		need_showbreak = FALSE; /* overlong line, skipping first x chars */
 #endif
 #if defined(FEAT_SIGNS) || (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
 	|| defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
@@ -3793,13 +3793,14 @@ win_line(
 	    if (draw_state == WL_BRI - 1 && n_extra == 0)
 	    {
 		draw_state = WL_BRI;
-		if (wp->w_p_bri && n_extra == 0 && row != startrow
+		/* if need_showbreak is set, breakindent also applies */
+		if (wp->w_p_bri && n_extra == 0 && (row != startrow || need_showbreak)
 # ifdef FEAT_DIFF
 			&& filler_lines == 0
 # endif
 		   )
 		{
-		    char_attr = 0; /* was: hl_attr(HLF_AT); */
+		    char_attr = 0;
 # ifdef FEAT_DIFF
 		    if (diff_hlf != (hlf_T)0)
 		    {
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index a8ea543..82bd9b1 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -75,7 +75,6 @@ SCRIPTS_ALL = \
 	test108.out \
 	test_autocmd_option.out \
 	test_autoformat_join.out \
-	test_breakindent.out \
 	test_changelist.out \
 	test_close_count.out \
 	test_comparators.out \
@@ -141,6 +140,7 @@ NEW_TESTS = test_arglist.res \
 	    test_assert.res \
 	    test_autochdir.res \
 	    test_backspace_opt.res \
+	    test_breakindent.res \
 	    test_bufwintabinfo.res \
 	    test_cdo.res \
 	    test_channel.res \
diff --git a/src/testdir/test_breakindent.in b/src/testdir/test_breakindent.in
deleted file mode 100644
index d286931..0000000
--- a/src/testdir/test_breakindent.in
+++ /dev/null
@@ -1,122 +0,0 @@
-Test for breakindent
-
-STARTTEST
-:so small.vim
-:if !exists("+breakindent") | e! test.ok | w! test.out | qa! | endif
-:10new|:vsp|:vert resize 20
-:put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\"
-:set ts=4 sw=4 sts=4 breakindent
-:fu! ScreenChar(line, width)
-:	let c=''
-:	for i in range(1,a:width)
-:		let c.=nr2char(screenchar(a:line, i))
-:	endfor
-:       let c.="\n"
-:	for i in range(1,a:width)
-:		let c.=nr2char(screenchar(a:line+1, i))
-:	endfor
-:       let c.="\n"
-:	for i in range(1,a:width)
-:		let c.=nr2char(screenchar(a:line+2, i))
-:	endfor
-:	return c
-:endfu
-:fu DoRecordScreen()
-:	wincmd l
-:	$put =printf(\"\n%s\", g:test)
-:	$put =g:line1
-:	wincmd p
-:endfu
-:set briopt=min:0
-:let g:test="Test 1: Simple breakindent"
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test="Test 2: Simple breakindent + sbr=>>"
-:set sbr=>>
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test ="Test 3: Simple breakindent + briopt:sbr"
-:set briopt=sbr,min:0 sbr=++
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test ="Test 4: Simple breakindent + min width: 18"
-:set sbr= briopt=min:18
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test =" Test 5: Simple breakindent + shift by 2"
-:set briopt=shift:2,min:0
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test=" Test 6: Simple breakindent + shift by -1"
-:set briopt=shift:-1,min:0
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr"
-:set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr"
-:set briopt=shift:1,sbr,min:0 nu sbr=# list
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list"
-:set briopt-=sbr
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n"
-:set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:wincmd p
-:let g:test="\n Test 11: strdisplaywidth when breakindent is on"
-:set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4
-:let text=getline(2) "skip leading tab when calculating text width
-:let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3 " text wraps 3 times
-:$put =g:test
-:$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width)
-:let g:str="\t\t\t\t\t{"
-:let g:test=" Test 12: breakindent + long indent"
-:wincmd p
-:set all& breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4
-:$put =g:str
-zt:let line1=ScreenChar(1,10)
-:wincmd p
-:call DoRecordScreen()
-:"
-:" Test, that the string "    a\tb\tc\td\te" is correctly
-:" displayed in a 20 column wide window (see bug report
-:" https://groups.google.com/d/msg/vim_dev/ZOdg2mc9c9Y/TT8EhFjEy0IJ
-:only
-:vert 20new
-:set all& nocp breakindent briopt=min:10
-:call setline(1, ["    a\tb\tc\td\te", "    z   y       x       w       v"])
-:/^\s*a
-fbgjyl:let line1 = @0
-:?^\s*z
-fygjyl:let line2 = @0
-:quit!
-:$put ='Test 13: breakindent with wrapping Tab'
-:$put =line1
-:$put =line2
-:"
-:let g:test="Test 14: breakindent + visual blockwise delete #1"
-:set all& breakindent viminfo+=nviminfo
-:30vnew
-:normal! 3a1234567890
-:normal! a    abcde
-:exec "normal! 0\<C-V>tex"
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:"
-:let g:test="Test 15: breakindent + visual blockwise delete #2"
-:%d
-:normal! 4a1234567890
-:exec "normal! >>\<C-V>3f0x"
-:let line1=ScreenChar(line('.'),20)
-:call DoRecordScreen()
-:quit!
-:"
-:%w! test.out
-:qa!
-ENDTEST
-dummy text
diff --git a/src/testdir/test_breakindent.ok b/src/testdir/test_breakindent.ok
deleted file mode 100644
index 3eb9c24..0000000
--- a/src/testdir/test_breakindent.ok
+++ /dev/null
@@ -1,74 +0,0 @@
-
-	abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
-
-Test 1: Simple breakindent
-    abcd
-    qrst
-    GHIJ
-
-Test 2: Simple breakindent + sbr=>>
-    abcd
-    >>qr
-    >>EF
-
-Test 3: Simple breakindent + briopt:sbr
-    abcd
-++  qrst
-++  GHIJ
-
-Test 4: Simple breakindent + min width: 18
-    abcd
-  qrstuv
-  IJKLMN
-
- Test 5: Simple breakindent + shift by 2
-    abcd
-      qr
-      EF
-
- Test 6: Simple breakindent + shift by -1
-    abcd
-   qrstu
-   HIJKL
-
- Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr
-  2     ab
-?        m
-?        x
-
- Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr
-  2 ^Iabcd
-#      opq
-#      BCD
-
- Test 9: breakindent + shift by +1 + 'nu' + sbr=# list
-  2 ^Iabcd
-       #op
-       #AB
-
- Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n
-  2     ab
-~       mn
-~       yz
-
- Test 11: strdisplaywidth when breakindent is on
-strdisplaywidth: 46 == calculated: 64
-					{
-
- Test 12: breakindent + long indent
-56        
-          
-~         
-Test 13: breakindent with wrapping Tab
-d
-w
-
-Test 14: breakindent + visual blockwise delete #1
-e       
-~       
-~       
-
-Test 15: breakindent + visual blockwise delete #2
-        1234567890  
-~                   
-~                   
diff --git a/src/testdir/test_breakindent.vim b/src/testdir/test_breakindent.vim
new file mode 100644
index 0000000..43e1265
--- /dev/null
+++ b/src/testdir/test_breakindent.vim
@@ -0,0 +1,242 @@
+" Test for breakindent
+"
+" Note: if you get strange failures when adding new tests, it might be that
+" while the test is run, the breakindent cacheing gets in its way.
+" It helps to change the tabastop setting and force a redraw (e.g. see
+" Test_breakindent08())
+if !exists('+breakindent')
+  finish
+endif
+
+let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
+
+function s:screenline(lnum, width) abort
+  " always get 4 screen lines
+  redraw!
+  let line = []
+  for j in range(3)
+    for c in range(1, a:width)
+  call add(line, nr2char(screenchar(a:lnum+j, c)))
+    endfor
+    call add(line, "\n")
+  endfor
+  return join(line, '')
+endfunction
+
+function s:testwindows(...)
+  10new
+  vsp
+  vert resize 20
+  setl ts=4 sw=4 sts=4 breakindent 
+  put =s:input
+  if a:0
+    exe a:1
+  endif
+endfunction
+
+function s:close_windows(...)
+  bw!
+  if a:0
+    exe a:1
+  endif
+  unlet! g:line g:expect
+endfunction
+
+function Test_breakindent01()
+  " simple breakindent test
+  call s:testwindows('setl briopt=min:0')
+  let g:line=s:screenline(line('.'),8)
+  let g:expect="    abcd\n    qrst\n    GHIJ\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows()
+endfunction
+
+function Test_breakindent02()
+  " simple breakindent test with showbreak set
+  call s:testwindows('setl briopt=min:0 sbr=>>')
+  let g:line=s:screenline(line('.'),8)
+  let g:expect="    abcd\n    >>qr\n    >>EF\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows('set sbr=')
+endfunction
+
+function Test_breakindent03()
+  " simple breakindent test with showbreak set and briopt including sbr
+  call s:testwindows('setl briopt=sbr,min:0 sbr=++')
+  let g:line=s:screenline(line('.'),8)
+  let g:expect="    abcd\n++  qrst\n++  GHIJ\n"
+  call assert_equal(g:expect, g:line)
+  " clean up
+  call s:close_windows('set sbr=')
+endfunction
+
+function Test_breakindent04()
+  " breakindent set with min width 18
+  call s:testwindows('setl sbr= briopt=min:18')
+  let g:line=s:screenline(line('.'),8)
+  let g:expect="    abcd\n  qrstuv\n  IJKLMN\n"
+  call assert_equal(g:expect, g:line)
+  " clean up
+  call s:close_windows('set sbr=')
+endfunction
+
+function Test_breakindent05()
+  " breakindent set and shift by 2
+  call s:testwindows('setl briopt=shift:2,min:0')
+  let g:line=s:screenline(line('.'),8)
+  let g:expect="    abcd\n      qr\n      EF\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows()
+endfunction
+
+function Test_breakindent06()
+  " breakindent set and shift by -1
+  call s:testwindows('setl briopt=shift:-1,min:0')
+  let g:line=s:screenline(line('.'),8)
+  let g:expect="    abcd\n   qrstu\n   HIJKL\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows()
+endfunction
+
+function Test_breakindent07()
+  " breakindent set and shift by 1, Number  set sbr=? and briopt:sbr
+  call s:testwindows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n')
+  let g:line=s:screenline(line('.'),10)
+  let g:expect="  2     ab\n?        m\n?        x\n"
+  call assert_equal(g:expect, g:line)
+  " clean up
+  call s:close_windows('set sbr= cpo-=n')
+endfunction
+
+function Test_breakindent07a()
+  " breakindent set and shift by 1, Number  set sbr=? and briopt:sbr
+  call s:testwindows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4')
+  let g:line=s:screenline(line('.'),10)
+  let g:expect="  2     ab\n    ?    m\n    ?    x\n"
+  call assert_equal(g:expect, g:line)
+  " clean up
+  call s:close_windows('set sbr=')
+endfunction
+
+function Test_breakindent08()
+  " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+  call s:testwindows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4')
+  " make sure, cache is invalidated!
+  set ts=8
+  redraw!
+  set ts=4
+  redraw!
+  let g:line=s:screenline(line('.'),10)
+  let g:expect="  2 ^Iabcd\n#      opq\n#      BCD\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows('set sbr= cpo-=n')
+endfunction
+
+function Test_breakindent08a()
+  " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+  call s:testwindows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list')
+  let g:line=s:screenline(line('.'),10)
+  let g:expect="  2 ^Iabcd\n    #  opq\n    #  BCD\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows('set sbr=')
+endfunction
+
+function Test_breakindent09()
+  " breakindent set and shift by 1, Number and list set sbr=#
+  call s:testwindows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list')
+  let g:line=s:screenline(line('.'),10)
+  let g:expect="  2 ^Iabcd\n       #op\n       #AB\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows('set sbr=')
+endfunction
+
+function Test_breakindent10()
+  " breakindent set, Number set sbr=~
+  call s:testwindows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0')
+  " make sure, cache is invalidated!
+  set ts=8
+  redraw!
+  set ts=4
+  redraw!
+  let g:line=s:screenline(line('.'),10)
+  let g:expect="  2     ab\n~       mn\n~       yz\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows('set sbr= cpo-=n')
+endfunction
+
+function Test_breakindent11()
+  " test strdisplaywidth()
+  call s:testwindows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4')
+  let text=getline(2)
+  let width = strlen(text[1:])+indent(2)+strlen(&sbr)*3 " text wraps 3 times
+  call assert_equal(width, strdisplaywidth(text))
+  call s:close_windows('set sbr=')
+endfunction
+
+function Test_breakindent12()
+  " test breakindent with long indent
+  let s:input="\t\t\t\t\t{"
+  call s:testwindows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>-')
+  let g:line=s:screenline(2,16)
+  let g:expect=" 2 >--->--->--->\n          ---{  \n~               \n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows('set nuw=4 listchars=')
+endfunction
+
+function Test_breakindent13()
+  let s:input=""
+  call s:testwindows('setl breakindent briopt=min:10 ts=8')
+  vert resize 20
+  call setline(1, ["    a\tb\tc\td\te", "    z   y       x       w       v"])
+  1
+  norm! fbgj"ayl
+  2
+  norm! fygj"byl
+  call assert_equal('d', @a)
+  call assert_equal('w', @b)
+  call s:close_windows()
+endfunction
+
+function Test_breakindent14()
+  let s:input=""
+  call s:testwindows('setl breakindent briopt= ts=8')
+  vert resize 30
+  norm! 3a1234567890
+  norm! a    abcde
+  exec "norm! 0\<C-V>tex"
+  let g:line=s:screenline(line('.'),8)
+  let g:expect="e       \n~       \n~       \n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows()
+endfunction
+
+function Test_breakindent15()
+  let s:input=""
+  call s:testwindows('setl breakindent briopt= ts=8 sw=8')
+  vert resize 30
+  norm! 4a1234567890
+  exe "normal! >>\<C-V>3f0x"
+  let g:line=s:screenline(line('.'),20)
+  let g:expect="        1234567890  \n~                   \n~                   \n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows()
+endfunction
+
+function Test_breakindent16()
+  " check that overlong lines are indented
+  " correctly (however currently it does not
+  " fail for older Vims)
+  let s:input=""
+  call s:testwindows('setl breakindent briopt=min:0 ts=4')
+  call setline(1, "\t".repeat("1234567890", 10))
+  resize 6
+  norm! 1gg$
+  redraw!
+  let g:line=s:screenline(1,10)
+  let g:expect="    123456\n    789012\n    345678\n"
+  call assert_equal(g:expect, g:line)
+  let g:line=s:screenline(4,10)
+  let g:expect="    901234\n    567890\n    123456\n"
+  call assert_equal(g:expect, g:line)
+  call s:close_windows()
+endfunction
-- 
2.9.3

Raspunde prin e-mail lui