changeset 34327:cb3d20e3dcd9 v9.1.0097

patch 9.1.0097: 'breakindent' behaves inconsistently with 'list' and splits Commit: https://github.com/vim/vim/commit/efabd7c8d4f733350364356b8950a11f013aec49 Author: zeertzjq <zeertzjq@outlook.com> Date: Sun Feb 11 17:16:19 2024 +0100 patch 9.1.0097: 'breakindent' behaves inconsistently with 'list' and splits Problem: 'breakindent' behaves inconsistently with 'list' and splits. Solution: Use 'listchars' from the correct window and handle caching properly. Move cheaper comparisons to the top. (zeertzjq) closes: #14008 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Sun, 11 Feb 2024 17:30:02 +0100
parents 8aeb5e1daea6
children d94ca764273d
files src/indent.c src/proto/indent.pro src/testdir/test_breakindent.vim src/version.c
diffstat 4 files changed, 87 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/src/indent.c
+++ b/src/indent.c
@@ -434,20 +434,17 @@ get_indent_buf(buf_T *buf, linenr_T lnum
 get_indent_str(
     char_u	*ptr,
     int		ts,
-    int		list) // if TRUE, count only screen size for tabs
+    int		no_ts) // if TRUE, count a tab as ^I
 {
     int		count = 0;
 
     for ( ; *ptr; ++ptr)
     {
-	if (*ptr == TAB)
+	if (*ptr == TAB)    // count a tab for what it is worth
 	{
-	    if (!list || curwin->w_lcs_chars.tab1)
-		// count a tab for what it is worth
+	    if (!no_ts)
 		count += ts - (count % ts);
 	    else
-		// In list mode, when tab is not set, count screen char width
-		// for Tab, displays: ^I
 		count += ptr2cells(ptr);
 	}
 	else if (*ptr == ' ')
@@ -462,10 +459,10 @@ get_indent_str(
 /*
  * Count the size (in window cells) of the indent in line "ptr", using
  * variable tabstops.
- * if "list" is TRUE, count only screen size for tabs.
+ * If "no_ts" is TRUE, count a tab as ^I.
  */
     int
-get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list)
+get_indent_str_vtab(char_u *ptr, int ts, int *vts, int no_ts)
 {
     int		count = 0;
 
@@ -473,11 +470,9 @@ get_indent_str_vtab(char_u *ptr, int ts,
     {
 	if (*ptr == TAB)    // count a tab for what it is worth
 	{
-	    if (!list || curwin->w_lcs_chars.tab1)
+	    if (!no_ts)
 		count += tabstop_padding(count, ts, vts);
 	    else
-		// In list mode, when tab is not set, count screen char width
-		// for Tab, displays: ^I
 		count += ptr2cells(ptr);
 	}
 	else if (*ptr == ' ')
@@ -925,14 +920,16 @@ get_breakindent_win(
 {
     static int	    prev_indent = 0;	// cached indent value
     static long	    prev_ts     = 0L;	// cached tabstop value
+# ifdef FEAT_VARTABS
+    static int      *prev_vts = NULL;   // cached vartabs values
+# endif
     static int	    prev_fnum   = 0;	// cached buffer number
     static char_u   *prev_line  = NULL;	// cached copy of "line"
     static varnumber_T prev_tick = 0;   // changedtick of cached value
-# ifdef FEAT_VARTABS
-    static int      *prev_vts = NULL;   // cached vartabs values
-# endif
-    static int      prev_list = 0;	// cached list value
+    static int      prev_list = 0;	// cached list indent
     static int      prev_listopt = 0;	// cached w_p_briopt_list value
+    static int      prev_no_ts = FALSE;	// cached no_ts value
+    static unsigned prev_dy_uhex = 0;	// cached 'display' "uhex" value
     // cached formatlistpat value
     static char_u   *prev_flp = NULL;
     int		    bri = 0;
@@ -942,44 +939,53 @@ get_breakindent_win(
 				&& (vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
 						? number_width(wp) + 1 : 0);
 
-    // used cached indent, unless
-    // - buffer changed
-    // - 'tabstop' changed
-    // - buffer was changed
-    // - 'briopt_list changed' changed or
-    // - 'formatlistpattern' changed
-    // - line changed
-    // - 'vartabs' changed
+    // In list mode, if 'listchars' "tab" isn't set, a TAB is displayed as ^I.
+    int no_ts = wp->w_p_list && wp->w_lcs_chars.tab1 == NUL;
+
+    // Used cached indent, unless
+    // - buffer changed, or
+    // - 'tabstop' changed, or
+    // - 'vartabstop' changed, or
+    // - buffer was changed, or
+    // - 'breakindentopt' "list" changed, or
+    // - 'list' or 'listchars' "tab" changed, or
+    // - 'display' "uhex" flag changed, or
+    // - 'formatlistpat' changed, or
+    // - line changed.
     if (prev_fnum != wp->w_buffer->b_fnum
 	    || prev_ts != wp->w_buffer->b_p_ts
+# ifdef FEAT_VARTABS
+	    || prev_vts != wp->w_buffer->b_p_vts_array
+# endif
 	    || prev_tick != CHANGEDTICK(wp->w_buffer)
 	    || prev_listopt != wp->w_briopt_list
+	    || prev_no_ts != no_ts
+	    || prev_dy_uhex != (dy_flags & DY_UHEX)
 	    || prev_flp == NULL
 	    || STRCMP(prev_flp, get_flp_value(wp->w_buffer)) != 0
 	    || prev_line == NULL || STRCMP(prev_line, line) != 0
-# ifdef FEAT_VARTABS
-	    || prev_vts != wp->w_buffer->b_p_vts_array
-# endif
 	)
     {
 	prev_fnum = wp->w_buffer->b_fnum;
 	vim_free(prev_line);
 	prev_line = vim_strsave(line);
 	prev_ts = wp->w_buffer->b_p_ts;
-	prev_tick = CHANGEDTICK(wp->w_buffer);
 # ifdef FEAT_VARTABS
 	prev_vts = wp->w_buffer->b_p_vts_array;
 	if (wp->w_briopt_vcol == 0)
 	    prev_indent = get_indent_str_vtab(line,
 				     (int)wp->w_buffer->b_p_ts,
-				    wp->w_buffer->b_p_vts_array, wp->w_p_list);
+				      wp->w_buffer->b_p_vts_array, no_ts);
 # else
 	if (wp->w_briopt_vcol == 0)
 	    prev_indent = get_indent_str(line,
-				     (int)wp->w_buffer->b_p_ts, wp->w_p_list);
+				        (int)wp->w_buffer->b_p_ts, no_ts);
 # endif
+	prev_tick = CHANGEDTICK(wp->w_buffer);
 	prev_listopt = wp->w_briopt_list;
 	prev_list = 0;
+	prev_no_ts = no_ts;
+	prev_dy_uhex = (dy_flags & DY_UHEX);
 	vim_free(prev_flp);
 	prev_flp = vim_strsave(get_flp_value(wp->w_buffer));
 	// add additional indent for numbered lists
--- a/src/proto/indent.pro
+++ b/src/proto/indent.pro
@@ -14,8 +14,8 @@ long get_sts_value(void);
 int get_indent(void);
 int get_indent_lnum(linenr_T lnum);
 int get_indent_buf(buf_T *buf, linenr_T lnum);
-int get_indent_str(char_u *ptr, int ts, int list);
-int get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list);
+int get_indent_str(char_u *ptr, int ts, int no_ts);
+int get_indent_str_vtab(char_u *ptr, int ts, int *vts, int no_ts);
 int set_indent(int size, int flags);
 int get_number_indent(linenr_T lnum);
 int briopt_check(win_T *wp);
--- a/src/testdir/test_breakindent.vim
+++ b/src/testdir/test_breakindent.vim
@@ -424,7 +424,7 @@ func Test_breakindent12()
 	\ "~               ",
 	\ ]
   call s:compare_lines(expect, lines)
-  call s:close_windows('set nuw=4 listchars=')
+  call s:close_windows('set nuw=4 listchars&')
 endfunc
 
 func Test_breakindent12_vartabs()
@@ -439,7 +439,7 @@ func Test_breakindent12_vartabs()
 	\ "~               ",
 	\ ]
   call s:compare_lines(expect, lines)
-  call s:close_windows('set nuw=4 listchars= vts&')
+  call s:close_windows('set nuw=4 listchars& vts&')
 endfunc
 
 func Test_breakindent13()
@@ -1086,5 +1086,51 @@ func Test_linebreak_list()
   bwipe!
 endfunc
 
+func Test_breakindent_change_display_uhex()
+  call s:test_windows('setl briopt=min:0 list listchars=eol:$')
+  redraw!
+  let lines = s:screen_lines(line('.'), 20)
+  let expect = [
+        \ "^Iabcdefghijklmnopqr",
+        \ "  stuvwxyzABCDEFGHIJ",
+        \ "  KLMNOP$           "
+        \ ]
+  call s:compare_lines(expect, lines)
+  set display+=uhex
+  redraw!
+  let lines = s:screen_lines(line('.'), 20)
+  let expect = [
+        \ "<09>abcdefghijklmnop",
+        \ "    qrstuvwxyzABCDEF",
+        \ "    GHIJKLMNOP$     "
+        \ ]
+  call s:compare_lines(expect, lines)
+  set display&
+
+  call s:close_windows()
+endfunc
+
+func Test_breakindent_list_split()
+  10new
+  61vsplit
+  setlocal tabstop=8 breakindent list listchars=tab:<->,eol:$
+  put =s:input
+  30vsplit
+  setlocal listchars=eol:$
+  let expect = [
+      \ "^IabcdefghijklmnopqrstuvwxyzAB|<------>abcdefghijklmnopqrstuv",
+      \ "  CDEFGHIJKLMNOP$             |        wxyzABCDEFGHIJKLMNOP$ ",
+      \ "~                             |~                             "
+      \ ]
+  redraw!
+  let lines = s:screen_lines(line('.'), 61)
+  call s:compare_lines(expect, lines)
+  wincmd p
+  redraw!
+  let lines = s:screen_lines(line('.'), 61)
+  call s:compare_lines(expect, lines)
+
+  bwipe!
+endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    97,
+/**/
     96,
 /**/
     95,