Problem: 'cursorline' always highlights the whole line.
Solution: Add 'cursorlineopt' to specify what is highlighted.
(closes #4693)
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
'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
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
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")
#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
(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},
#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);
}
#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);
#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
#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
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
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
#ifdef FEAT_SYN_HL
, WV_CUC
, WV_CUL
+ , WV_CULOPT
, WV_CC
#endif
#ifdef FEAT_STL_OPT
{
// 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;
* 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
{
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
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
&& 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
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));
}
# 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
test_crypt \
test_cscope \
test_cursor_func \
+ test_cursorline \
test_curswant \
test_debugger \
test_delete \
\ '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']],
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
--- /dev/null
+" 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
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2019,
/**/
2018,
/**/