changeset 18047:6650e3dff8d4 v8.1.2019

patch 8.1.2019: 'cursorline' always highlights the whole line Commit: https://github.com/vim/vim/commit/410e98a70bc00ea4bed51e55a8fe20e56a72c087 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Sep 9 22:05:49 2019 +0200 patch 8.1.2019: 'cursorline' always highlights the whole line Problem: 'cursorline' always highlights the whole line. Solution: Add 'cursorlineopt' to specify what is highlighted. (closes #4693)
author Bram Moolenaar <Bram@vim.org>
date Mon, 09 Sep 2019 22:15:04 +0200
parents 4b4c49dee5e6
children ceafe0986ad7
files runtime/doc/options.txt runtime/doc/quickref.txt runtime/doc/syntax.txt runtime/optwin.vim src/option.c src/option.h src/screen.c src/structs.h src/testdir/Make_all.mak src/testdir/gen_opt_test.vim src/testdir/test_alot.vim src/testdir/test_cursorline.vim src/version.c
diffstat 13 files changed, 172 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2461,13 +2461,26 @@ A jump table for the options with a shor
 			local to window
 			{not available when compiled without the |+syntax|
 			feature}
-	Highlight the screen line of the cursor with CursorLine
-	|hl-CursorLine|.  Useful to easily spot the cursor.  Will make screen
-	redrawing slower.
+	Highlight the text line of the cursor with CursorLine |hl-CursorLine|.
+	Useful to easily spot the cursor.  Will make screen redrawing slower.
 	When Visual mode is active the highlighting isn't used to make it
 	easier to see the selected text.
 
 
+						*'cursorlineopt'* *'culopt'*
+'cursorlineopt' 'culopt' string (default: "both")
+			local to window
+			{not in Vi}
+			{not available when compiled without the |+syntax|
+			feature}
+	Settings for how 'cursorline' is displayed.  Valid values:
+	    "line"	Highlight the text line of the cursor with
+			CursorLine |hl-CursorLine|.
+	    "number"	Highlight the line number of the cursor with
+			CursorLineNr |hl-CursorLineNr|.
+	    "both"	Highlight as both "line" and "number" are set.
+
+
 						*'debug'*
 'debug'			string	(default "")
 			global
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -670,6 +670,7 @@ Short explanation of each option:		*opti
 'cursorbind'	  'crb'     move cursor in window as it moves in other windows
 'cursorcolumn'	  'cuc'	    highlight the screen column of the cursor
 'cursorline'	  'cul'	    highlight the screen line of the cursor
+'cursorlineopt'	  'culopt'  settings for 'cursorline'
 'debug'			    set to "msg" to see all error messages
 'define'	  'def'     pattern to be used to find a macro definition
 'delcombine'	  'deco'    delete combining characters on their own
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -5042,7 +5042,8 @@ IncSearch	'incsearch' highlighting; also
 LineNr		Line number for ":number" and ":#" commands, and when 'number'
 		or 'relativenumber' option is set.
 							*hl-CursorLineNr*
-CursorLineNr	Like LineNr when 'cursorline' or 'relativenumber' is set for
+CursorLineNr	Like LineNr when 'cursorline' is set and 'cursorlineopt' is
+		set to "number" or "both", or 'relativenumber' is set, for
 		the cursor line.
 							*hl-MatchParen*
 MatchParen	The character under the cursor or just before it, if it
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -429,6 +429,9 @@ if has("syntax")
   call append("$", "cursorline\thighlight the screen line of the cursor")
   call append("$", "\t(local to window)")
   call <SID>BinOptionL("cul")
+  call append("$", "cursorlineopt\tspecifies which area 'cursorline' highlights")
+  call append("$", "\t(local to window)")
+  call <SID>OptionL("culopt")
   call append("$", "colorcolumn\tcolumns to highlight")
   call append("$", "\t(local to window)")
   call <SID>OptionL("cc")
--- a/src/option.c
+++ b/src/option.c
@@ -238,6 +238,7 @@
 #ifdef FEAT_SYN_HL
 # define PV_CUC		OPT_WIN(WV_CUC)
 # define PV_CUL		OPT_WIN(WV_CUL)
+# define PV_CULOPT	OPT_WIN(WV_CULOPT)
 # define PV_CC		OPT_WIN(WV_CC)
 #endif
 #ifdef FEAT_STL_OPT
@@ -993,6 +994,13 @@ static struct vimoption options[] =
 			    (char_u *)NULL, PV_NONE,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+    {"cursorlineopt", "culopt", P_STRING|P_VI_DEF|P_RWIN,
+#ifdef FEAT_SYN_HL
+			    (char_u *)VAR_WIN, PV_CULOPT,
+#else
+			    (char_u *)NULL, PV_NONE,
+#endif
+			    {(char_u *)"both", (char_u *)0L} SCTX_INIT},
     {"debug",	    NULL,   P_STRING|P_VI_DEF,
 			    (char_u *)&p_debug, PV_NONE,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
@@ -3228,6 +3236,9 @@ static char *(p_scl_values[]) = {"yes", 
 #if defined(MSWIN) && defined(FEAT_TERMINAL)
 static char *(p_twt_values[]) = {"winpty", "conpty", "", NULL};
 #endif
+#ifdef FEAT_SYN_HL
+static char *(p_culopt_values[]) = {"line", "number", "both", NULL};
+#endif
 
 static void set_options_default(int opt_flags);
 static void set_string_default_esc(char *name, char_u *val, int escape);
@@ -6326,6 +6337,15 @@ did_set_string_option(
     }
 
 #ifdef FEAT_SYN_HL
+    /* 'cursorlineopt' */
+    else if (varp == &curwin->w_p_culopt
+				  || gvarp == &curwin->w_allbuf_opt.wo_culopt)
+    {
+	if (**varp == NUL
+		    || check_opt_strings(*varp, p_culopt_values, FALSE) != OK)
+	    errmsg = e_invarg;
+    }
+
     /* 'colorcolumn' */
     else if (varp == &curwin->w_p_cc)
 	errmsg = check_colorcolumn(curwin);
@@ -10775,6 +10795,7 @@ get_varp(struct vimoption *p)
 #ifdef FEAT_SYN_HL
 	case PV_CUC:	return (char_u *)&(curwin->w_p_cuc);
 	case PV_CUL:	return (char_u *)&(curwin->w_p_cul);
+	case PV_CULOPT:	return (char_u *)&(curwin->w_p_culopt);
 	case PV_CC:	return (char_u *)&(curwin->w_p_cc);
 #endif
 #ifdef FEAT_DIFF
@@ -11012,6 +11033,7 @@ copy_winopt(winopt_T *from, winopt_T *to
 #ifdef FEAT_SYN_HL
     to->wo_cuc = from->wo_cuc;
     to->wo_cul = from->wo_cul;
+    to->wo_culopt = vim_strsave(from->wo_culopt);
     to->wo_cc = vim_strsave(from->wo_cc);
 #endif
 #ifdef FEAT_DIFF
@@ -11087,6 +11109,7 @@ check_winopt(winopt_T *wop UNUSED)
     check_string_option(&wop->wo_stl);
 #endif
 #ifdef FEAT_SYN_HL
+    check_string_option(&wop->wo_culopt);
     check_string_option(&wop->wo_cc);
 #endif
 #ifdef FEAT_CONCEAL
@@ -11132,6 +11155,7 @@ clear_winopt(winopt_T *wop UNUSED)
     clear_string_option(&wop->wo_stl);
 #endif
 #ifdef FEAT_SYN_HL
+    clear_string_option(&wop->wo_culopt);
     clear_string_option(&wop->wo_cc);
 #endif
 #ifdef FEAT_CONCEAL
--- a/src/option.h
+++ b/src/option.h
@@ -1161,6 +1161,7 @@ enum
 #ifdef FEAT_SYN_HL
     , WV_CUC
     , WV_CUL
+    , WV_CULOPT
     , WV_CC
 #endif
 #ifdef FEAT_STL_OPT
--- a/src/screen.c
+++ b/src/screen.c
@@ -3817,7 +3817,7 @@ win_line(
     {
 	// Do not show the cursor line when Visual mode is active, because it's
 	// not clear what is selected then.  Do update w_last_cursorline.
-	if (!(wp == curwin && VIsual_active))
+	if (!(wp == curwin && VIsual_active) && *wp->w_p_culopt != 'n')
 	{
 	    line_attr = HL_ATTR(HLF_CUL);
 	    area_highlighting = TRUE;
@@ -4021,6 +4021,7 @@ win_line(
 		       * TODO: Can we use CursorLine instead of CursorLineNr
 		       * when CursorLineNr isn't set? */
 		      if ((wp->w_p_cul || wp->w_p_rnu)
+						 && *wp->w_p_culopt != 'l'
 						 && lnum == wp->w_cursor.lnum)
 			char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_CLN));
 #endif
@@ -4055,7 +4056,8 @@ win_line(
 		    {
 			char_attr = HL_ATTR(diff_hlf);
 #  ifdef FEAT_SYN_HL
-			if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+			if (wp->w_p_cul && lnum == wp->w_cursor.lnum
+						    && *wp->w_p_culopt != 'n')
 			    char_attr = hl_combine_attr(char_attr,
 							    HL_ATTR(HLF_CUL));
 #  endif
@@ -4117,7 +4119,8 @@ win_line(
 			tocol += n_extra;
 #ifdef FEAT_SYN_HL
 		    /* combine 'showbreak' with 'cursorline' */
-		    if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+		    if (wp->w_p_cul && lnum == wp->w_cursor.lnum
+						    && *wp->w_p_culopt != 'n')
 			char_attr = hl_combine_attr(char_attr,
 							    HL_ATTR(HLF_CUL));
 #endif
@@ -4212,7 +4215,8 @@ win_line(
 							      && n_extra == 0)
 		    diff_hlf = HLF_CHD;		/* changed line */
 		line_attr = HL_ATTR(diff_hlf);
-		if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+		if (wp->w_p_cul && lnum == wp->w_cursor.lnum
+						    && *wp->w_p_culopt != 'n')
 		    line_attr = hl_combine_attr(line_attr, HL_ATTR(HLF_CUL));
 	    }
 #endif
@@ -5180,7 +5184,8 @@ win_line(
 			if (vi_attr == 0 || char_attr != vi_attr)
 			{
 			    char_attr = HL_ATTR(diff_hlf);
-			    if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+			    if (wp->w_p_cul && lnum == wp->w_cursor.lnum
+						    && *wp->w_p_culopt != 'n')
 				char_attr = hl_combine_attr(char_attr,
 							    HL_ATTR(HLF_CUL));
 			}
--- a/src/structs.h
+++ b/src/structs.h
@@ -249,6 +249,8 @@ typedef struct
 # define w_p_cuc w_onebuf_opt.wo_cuc	// 'cursorcolumn'
     int		wo_cul;
 # define w_p_cul w_onebuf_opt.wo_cul	// 'cursorline'
+    char_u	*wo_culopt;
+# define w_p_culopt w_onebuf_opt.wo_culopt	// 'cursorlineopt'
     char_u	*wo_cc;
 # define w_p_cc w_onebuf_opt.wo_cc	// 'colorcolumn'
 #endif
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -92,6 +92,7 @@ NEW_TESTS = \
 	test_crypt \
 	test_cscope \
 	test_cursor_func \
+	test_cursorline \
 	test_curswant \
 	test_debugger \
 	test_delete \
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -82,6 +82,7 @@ let test_values = {
       \ 'completeslash': [['', 'slash', 'backslash'], ['xxx']],
       \ 'cryptmethod': [['', 'zip'], ['xxx']],
       \ 'cscopequickfix': [['', 's-', 's-,c+,e0'], ['xxx', 's,g,d']],
+      \ 'cursorlineopt': [['both', 'line', 'number'], ['', 'xxx', 'line,number']],
       \ 'debug': [['', 'msg', 'msg', 'beep'], ['xxx']],
       \ 'diffopt': [['', 'filler', 'icase,iwhite'], ['xxx', 'algorithm:xxx', 'algorithm:']],
       \ 'display': [['', 'lastline', 'lastline,uhex'], ['xxx']],
--- a/src/testdir/test_alot.vim
+++ b/src/testdir/test_alot.vim
@@ -9,6 +9,7 @@ source test_cd.vim
 source test_changedtick.vim
 source test_compiler.vim
 source test_cursor_func.vim
+source test_cursorline.vim
 source test_delete.vim
 source test_ex_equal.vim
 source test_ex_undo.vim
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_cursorline.vim
@@ -0,0 +1,108 @@
+" Test for cursorline and cursorlineopt
+"
+source view_util.vim
+source check.vim
+
+function! s:screen_attr(lnum) abort
+  return map(range(1, 8), 'screenattr(a:lnum, v:val)')
+endfunction
+
+function! s:test_windows(h, w) abort
+  call NewWindow(a:h, a:w)
+endfunction
+
+function! s:close_windows() abort
+  call CloseWindow()
+endfunction
+
+function! s:new_hi() abort
+  redir => save_hi
+  silent! hi CursorLineNr
+  redir END
+  let save_hi = join(split(substitute(save_hi, '\s*xxx\s*', ' ', ''), "\n"), '')
+  exe 'hi' save_hi 'ctermbg=0 guibg=Black'
+  return save_hi
+endfunction
+
+func Test_cursorline_highlight1()
+  let save_hi = s:new_hi()
+  try
+    call s:test_windows(10, 20)
+    call setline(1, repeat(['aaaa'], 10))
+    redraw
+    let attr01 = s:screen_attr(1)
+    call assert_equal(repeat([attr01[0]], 8), attr01)
+
+    setl number numberwidth=4
+    redraw
+    let attr11 = s:screen_attr(1)
+    call assert_equal(repeat([attr11[0]], 4), attr11[0:3])
+    call assert_equal(repeat([attr11[4]], 4), attr11[4:7])
+    call assert_notequal(attr11[0], attr11[4])
+
+    setl cursorline
+    redraw
+    let attr21 = s:screen_attr(1)
+    let attr22 = s:screen_attr(2)
+    call assert_equal(repeat([attr21[0]], 4), attr21[0:3])
+    call assert_equal(repeat([attr21[4]], 4), attr21[4:7])
+    call assert_equal(attr11, attr22)
+    call assert_notequal(attr22, attr21)
+
+    setl nocursorline relativenumber
+    redraw
+    let attr31 = s:screen_attr(1)
+    call assert_equal(attr21[0:3], attr31[0:3])
+    call assert_equal(attr11[4:7], attr31[4:7])
+
+    call s:close_windows()
+  finally
+    exe 'hi' save_hi
+  endtry
+endfunc
+
+func Test_cursorline_highlight2()
+  CheckOption cursorlineopt
+
+  let save_hi = s:new_hi()
+  try
+    call s:test_windows(10, 20)
+    call setline(1, repeat(['aaaa'], 10))
+    redraw
+    let attr0 = s:screen_attr(1)
+    call assert_equal(repeat([attr0[0]], 8), attr0)
+
+    setl number
+    redraw
+    let attr1 = s:screen_attr(1)
+    call assert_notequal(attr0[0:3], attr1[0:3])
+    call assert_equal(attr0[0:3], attr1[4:7])
+
+    setl cursorline cursorlineopt=both
+    redraw
+    let attr2 = s:screen_attr(1)
+    call assert_notequal(attr1[0:3], attr2[0:3])
+    call assert_notequal(attr1[4:7], attr2[4:7])
+
+    setl cursorlineopt=line
+    redraw
+    let attr3 = s:screen_attr(1)
+    call assert_equal(attr1[0:3], attr3[0:3])
+    call assert_equal(attr2[4:7], attr3[4:7])
+
+    setl cursorlineopt=number
+    redraw
+    let attr4 = s:screen_attr(1)
+    call assert_equal(attr2[0:3], attr4[0:3])
+    call assert_equal(attr1[4:7], attr4[4:7])
+
+    setl nonumber
+    redraw
+    let attr5 = s:screen_attr(1)
+    call assert_equal(attr0, attr5)
+
+    call s:close_windows()
+  finally
+    exe 'hi' save_hi
+  endtry
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2019,
+/**/
     2018,
 /**/
     2017,