diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index ab2230641d..5292847240 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1802,13 +1802,23 @@ A jump table for the options with a short description can be found at |Q_op|. *'cursorline'* *'cul'* *'nocursorline'* *'nocul'* 'cursorline' 'cul' boolean (default off) local to window - 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 + 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 diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index c19b05f6c7..77e69a3eea 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -659,6 +659,7 @@ Short explanation of each option: *option-list* '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 diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index bc7a1e34c3..0cd3aed7a2 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -5065,7 +5065,8 @@ Substitute |:substitute| replacement text highlighting 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 diff --git a/runtime/optwin.vim b/runtime/optwin.vim index 633cb9e509..d4c10f7afa 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -440,6 +440,9 @@ if has("syntax") call append("$", "cursorline\thighlight the screen line of the cursor") call append("$", "\t(local to window)") call BinOptionL("cul") + call append("$", "cursorlineopt\tspecifies which area 'cursorline' highlights") + call append("$", "\t(local to window)") + call OptionL("culopt") call append("$", "colorcolumn\tcolumns to highlight") call append("$", "\t(local to window)") call OptionL("cc") diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 2fe85e0543..1099573f83 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -226,6 +226,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' char_u *wo_stl; diff --git a/src/nvim/option.c b/src/nvim/option.c index f67cfd109b..95970a77f8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -322,6 +322,7 @@ static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2", static char *(p_fdc_values[]) = { "auto", "auto:1", "auto:2", "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; +static char *(p_culopt_values[]) = { "line", "number", "both", NULL }; /// All possible flags for 'shm'. static char_u SHM_ALL[] = { @@ -2411,6 +2412,12 @@ did_set_string_option( os_setenv("VIMRUNTIME", "", 1); didset_vimruntime = false; } + } else if (varp == &curwin->w_p_culopt + || gvarp == &curwin->w_allbuf_opt.wo_culopt) { // 'cursorlineopt' + if (**varp == NUL + || check_opt_strings(*varp, p_culopt_values, false) != OK) { + errmsg = e_invarg; + } } else if (varp == &curwin->w_p_cc) { // 'colorcolumn' errmsg = check_colorcolumn(curwin); } else if (varp == &p_hlg) { // 'helplang' @@ -5652,6 +5659,7 @@ static char_u *get_varp(vimoption_T *p) case PV_SPELL: return (char_u *)&(curwin->w_p_spell); 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); case PV_DIFF: return (char_u *)&(curwin->w_p_diff); case PV_FDC: return (char_u *)&(curwin->w_p_fdc); @@ -5799,6 +5807,7 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_spell = from->wo_spell; 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); to->wo_diff = from->wo_diff; to->wo_diff_saved = from->wo_diff_saved; @@ -5849,6 +5858,7 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_scl); check_string_option(&wop->wo_rlc); check_string_option(&wop->wo_stl); + check_string_option(&wop->wo_culopt); check_string_option(&wop->wo_cc); check_string_option(&wop->wo_cocu); check_string_option(&wop->wo_briopt); @@ -5871,6 +5881,7 @@ void clear_winopt(winopt_T *wop) clear_string_option(&wop->wo_scl); clear_string_option(&wop->wo_rlc); clear_string_option(&wop->wo_stl); + clear_string_option(&wop->wo_culopt); clear_string_option(&wop->wo_cc); clear_string_option(&wop->wo_cocu); clear_string_option(&wop->wo_briopt); diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 5e40bdd6ef..37e75a6cc7 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -870,6 +870,7 @@ enum { , WV_SPELL , WV_CUC , WV_CUL + , WV_CULOPT , WV_CC , WV_STL , WV_WFH diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 0830fb4638..7b8170094e 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -555,6 +555,13 @@ return { redraw={'current_window_only'}, defaults={if_true={vi=false}} }, + { + full_name='cursorlineopt', abbreviation='culopt', + short_desc=N_("settings for 'cursorline'"), + type='string', scope={'window'}, + redraw={'current_window_only'}, + defaults={if_true={vi="both"}} + }, { full_name='debug', short_desc=N_("to \"msg\" to see all error messages"), diff --git a/src/nvim/screen.c b/src/nvim/screen.c index aee10c06ad..b048facfb7 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2362,7 +2362,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (lnum == wp->w_cursor.lnum) { // Do not show the cursor line when Visual mode is active, because it's // not clear what is selected then. - if (wp->w_p_cul && !(wp == curwin && VIsual_active)) { + if (wp->w_p_cul && !(wp == curwin && VIsual_active) + && *wp->w_p_culopt != 'n') { int cul_attr = win_hl_attr(wp, HLF_CUL); HlAttrs ae = syn_attr2entry(cul_attr); @@ -2786,6 +2787,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, // :sign defined with "numhl" highlight. char_attr = num_sattr->sat_numhl; } else if ((wp->w_p_cul || wp->w_p_rnu) + && *wp->w_p_culopt != 'l' && lnum == wp->w_cursor.lnum && filler_todo == 0) { // When 'cursorline' is set highlight the line number of @@ -2821,7 +2823,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (diff_hlf != (hlf_T)0) { char_attr = win_hl_attr(wp, 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, win_hl_attr(wp, HLF_CUL)); } } @@ -2881,7 +2884,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (tocol == vcol) tocol += n_extra; // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. - 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(win_hl_attr(wp, HLF_CUL), char_attr); } } @@ -3116,7 +3120,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } line_attr = win_hl_attr(wp, diff_hlf); // Overlay CursorLine onto diff-mode highlight. - 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 = 0 != line_attr_lowprio // Low-priority CursorLine ? hl_combine_attr(hl_combine_attr(win_hl_attr(wp, HLF_CUL), line_attr), @@ -3924,7 +3929,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } int eol_attr = char_attr; - 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') { eol_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), eol_attr); } linebuf_attr[off] = eol_attr; diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index b5c50b5894..cc767a9bcf 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -7,6 +7,7 @@ source test_cd.vim source test_changedtick.vim source test_compiler.vim source test_cursor_func.vim +source test_cursorline.vim source test_ex_equal.vim source test_ex_undo.vim source test_ex_z.vim diff --git a/src/nvim/testdir/test_cursorline.vim b/src/nvim/testdir/test_cursorline.vim new file mode 100644 index 0000000000..46fbd0cd64 --- /dev/null +++ b/src/nvim/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