diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index d2d010882e5664..8fb6290e50a536 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -1018,7 +1018,7 @@ nvim_get_mode() *nvim_get_mode()* {fast} nvim_get_option({name}) *nvim_get_option()* - Gets an option value string. + Gets the global value of an option. Parameters: ~ {name} Option name @@ -1049,6 +1049,24 @@ nvim_get_option_info({name}) *nvim_get_option_info()* Return: ~ Option Information +nvim_get_option_value({name}, {*opts}) *nvim_get_option_value()* + Gets the value of an option. The behavior of this function + matches that of |:set|: the local value of an option is + returned if it exists; otherwise, the global value is + returned. Local values always correspond to the current buffer + or window. To get a buffer-local or window-local option for a + specific buffer or window, use |nvim_buf_get_option()| or + |nvim_win_get_option()|. + + Parameters: ~ + {name} Option name + {opts} Optional parameters + • scope: One of 'global' or 'local'. Analagous to + |:setglobal| and |:setlocal|, respectively. + + Return: ~ + Option value + nvim_get_proc({pid}) *nvim_get_proc()* Gets info describing process `pid` . @@ -1510,11 +1528,25 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()* key is an error. nvim_set_option({name}, {value}) *nvim_set_option()* - Sets an option value. + Sets the global value of an option. + + Parameters: ~ + {name} Option name + {value} New option value + + *nvim_set_option_value()* +nvim_set_option_value({name}, {value}, {*opts}) + Sets the value of an option. The behavior of this function + matches that of |:set|: for global-local options, both the + global and local value are set unless otherwise specified with + {scope}. Parameters: ~ {name} Option name {value} New option value + {opts} Optional parameters + • scope: One of 'global' or 'local'. Analagous to + |:setglobal| and |:setlocal|, respectively. nvim_set_var({name}, {value}) *nvim_set_var()* Sets a global (g:) variable. diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 11f9d62e693891..6ae45c72aa9383 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -630,6 +630,12 @@ client() *vim.lsp.client* server. • {handlers} (table): The handlers used by the client as described in |lsp-handler|. + • {requests} (table): The current pending requests in flight + to the server. Entries are key-value pairs with the key + being the request ID while the value is a table with + `type` , `bufnr` , and `method` key-value pairs. `type` is + either "pending" for an active request, or "cancel" for a + cancel request. • {config} (table): copy of the table that was passed by the user to |vim.lsp.start_client()|. • {server_capabilities} (table): Response from the server diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt index 895ee5ebef9a0f..68165f3d3d5b8c 100644 --- a/runtime/doc/sign.txt +++ b/runtime/doc/sign.txt @@ -47,6 +47,8 @@ The color of the column is set with the SignColumn highlight group :highlight SignColumn guibg=darkgrey < +If 'cursorline' is enabled, then the CursorLineSign highlight group is used +|hl-CursorLineSign|. *sign-identifier* Each placed sign is identified by a number called the sign identifier. This identifier is used to jump to the sign or to remove the sign. The identifier @@ -131,6 +133,10 @@ See |sign_define()| for the equivalent Vim script function. texthl={group} Highlighting group used for the text item. + culhl={group} + Highlighting group used for the text item when the cursor is + on the same line as the sign and 'cursorline' is enabled. + Example: > :sign define MySign text=>> texthl=Search linehl=DiffText < @@ -377,6 +383,9 @@ sign_define({list}) text text that is displayed when there is no icon or the GUI is not being used. texthl highlight group used for the text item + culhl highlight group used for the text item when + the cursor is on the same line as the sign and + 'cursorline' is enabled. numhl highlight group used for 'number' column at the associated line. Overrides |hl-LineNr|, |hl-CursorLineNr|. @@ -425,9 +434,13 @@ sign_getdefined([{name}]) *sign_getdefined()* or the GUI is not being used. texthl highlight group used for the text item; not present if not set. + culhl highlight group used for the text item when + the cursor is on the same line as the sign and + 'cursorline' is enabled; not present if not + set. numhl highlight group used for 'number' column at the associated line. Overrides |hl-LineNr|, - |hl-CursorLineNr|. + |hl-CursorLineNr|; not present if not set. Returns an empty List if there are no signs and when {name} is not found. diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index b57b8bfd5cf8a8..d49809599d872e 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -5127,6 +5127,10 @@ LineNrBelow Line number for when the 'relativenumber' *hl-CursorLineNr* CursorLineNr Like LineNr when 'cursorline' is set and 'cursorlineopt' contains "number" or is "both", for the cursor line. + *hl-CursorLineSign* +CursorLineSign Like SignColumn when 'cursorline' is set for the cursor line. + *hl-CursorLineFold* +CursorLineFold Like FoldColumn when 'cursorline' is set for the cursor line. *hl-MatchParen* MatchParen The character under the cursor or just before it, if it is a paired bracket, and its match. |pi_paren.txt| diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 08dc0583ac1afb..df9ed0f328eb62 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -530,11 +530,9 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop}) for id, node in pairs(match) do local name = query.captures[id] -- `node` was captured by the `name` capture in the match -< -> - local node_data = metadata[id] -- Node level metadata -< -> + + local node_data = metadata[id] -- Node level metadata + ... use the info here ... end end diff --git a/src/nvim/globals.h b/src/nvim/globals.h index b2422fd5319fd6..938e9c7db77c1d 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -997,6 +997,8 @@ EXTERN char e_non_empty_string_required[] INIT(= N_("E1142: Non-empty string req EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); +EXTERN char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); + EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index d4d53c4126ca37..50a03e0c02d6f4 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -65,6 +65,8 @@ typedef enum { HLF_LNA, // LineNrAbove HLF_LNB, // LineNrBelow HLF_CLN, // current line number when 'cursorline' is set + HLF_CLS, // current line sign column + HLF_CLF, // current line fold HLF_R, // return to continue message and yes/no questions HLF_S, // status lines HLF_SNC, // status lines of not-current windows @@ -122,6 +124,8 @@ EXTERN const char *hlf_names[] INIT(= { [HLF_LNA] = "LineNrAbove", [HLF_LNB] = "LineNrBelow", [HLF_CLN] = "CursorLineNr", + [HLF_CLS] = "CursorLineSign", + [HLF_CLF] = "CursorLineFold", [HLF_R] = "Question", [HLF_S] = "StatusLine", [HLF_SNC] = "StatusLineNC", diff --git a/src/nvim/option.c b/src/nvim/option.c index 1fe2e1d04cdfbf..92c27378eee062 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -262,6 +262,7 @@ typedef struct vimoption { #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \ "i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr," \ + "G:CursorLineSign,O:CursorLineFold" \ "r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \ "W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \ "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar," \ diff --git a/src/nvim/screen.c b/src/nvim/screen.c index a666b9c8b09fee..6d3142451f9e01 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2746,7 +2746,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc p_extra = p_extra_free; c_extra = NUL; c_final = NUL; - char_attr = win_hl_attr(wp, HLF_FC); + if (use_cursor_line_sign(wp, lnum)) { + char_attr = win_hl_attr(wp, HLF_CLF); + } else { + char_attr = win_hl_attr(wp, HLF_FC); + } } } @@ -2757,7 +2761,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc * buffer or when using Netbeans. */ int count = win_signcol_count(wp); if (count > 0) { - get_sign_display_info(false, wp, sattrs, row, + get_sign_display_info(false, wp, lnum, sattrs, row, startrow, filler_lines, filler_todo, count, &c_extra, &c_final, extra, sizeof(extra), &p_extra, &n_extra, @@ -2778,7 +2782,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && num_signs > 0) { int count = win_signcol_count(wp); - get_sign_display_info(true, wp, sattrs, row, + get_sign_display_info(true, wp, lnum, sattrs, row, startrow, filler_lines, filler_todo, count, &c_extra, &c_final, extra, sizeof(extra), &p_extra, &n_extra, @@ -4617,6 +4621,14 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off) } } +// Return true if CursorLineSign highlight is to be used. +static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) +{ + return wp->w_p_cul + && lnum == wp->w_cursor.lnum + && (wp->w_p_culopt_flags & CULOPT_NBR); +} + // Get information needed to display the sign in line 'lnum' in window 'wp'. // If 'nrcol' is TRUE, the sign is going to be displayed in the number column. // Otherwise the sign is going to be displayed in the sign column. @@ -4624,11 +4636,11 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off) // @param count max number of signs // @param[out] n_extrap number of characters from pp_extra to display // @param[in, out] sign_idxp Index of the displayed sign -static void get_sign_display_info(bool nrcol, win_T *wp, sign_attrs_T sattrs[], int row, - int startrow, int filler_lines, int filler_todo, int count, - int *c_extrap, int *c_finalp, char_u *extra, size_t extra_size, - char_u **pp_extra, int *n_extrap, int *char_attrp, - int *draw_statep, int *sign_idxp) +static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_attrs_T sattrs[], + int row, int startrow, int filler_lines, int filler_todo, + int count, int *c_extrap, int *c_finalp, char_u *extra, + size_t extra_size, char_u **pp_extra, int *n_extrap, + int *char_attrp, int *draw_statep, int *sign_idxp) { // Draw cells with the sign value or blank. *c_extrap = ' '; @@ -4636,7 +4648,11 @@ static void get_sign_display_info(bool nrcol, win_T *wp, sign_attrs_T sattrs[], if (nrcol) { *n_extrap = number_width(wp) + 1; } else { - *char_attrp = win_hl_attr(wp, HLF_SC); + if (use_cursor_line_sign(wp, lnum)) { + *char_attrp = win_hl_attr(wp, HLF_CLS); + } else { + *char_attrp = win_hl_attr(wp, HLF_SC); + } *n_extrap = win_signcol_width(wp); } @@ -4676,7 +4692,12 @@ static void get_sign_display_info(bool nrcol, win_T *wp, sign_attrs_T sattrs[], (*pp_extra)[*n_extrap] = NUL; } } - *char_attrp = sattr->sat_texthl; + + if (use_cursor_line_sign(wp, lnum) && sattr->sat_culhl > 0) { + *char_attrp = sattr->sat_culhl; + } else { + *char_attrp = sattr->sat_texthl; + } } } diff --git a/src/nvim/sign.c b/src/nvim/sign.c index fca73dc9f23692..32be7141845e9e 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -31,6 +31,7 @@ struct sign { char_u *sn_text; // text used instead of pixmap int sn_line_hl; // highlight ID for line int sn_text_hl; // highlight ID for text + int sn_cul_hl; // highlight ID for text on current line when 'cursorline' is set int sn_num_hl; // highlight ID for line number }; @@ -499,6 +500,9 @@ int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[]) if (sp->sn_line_hl != 0) { sattr.sat_linehl = syn_id2attr(sp->sn_line_hl); } + if (sp->sn_cul_hl != 0) { + sattr.sat_culhl = syn_id2attr(sp->sn_cul_hl); + } if (sp->sn_num_hl != 0) { sattr.sat_numhl = syn_id2attr(sp->sn_num_hl); } @@ -901,7 +905,7 @@ static int sign_define_init_text(sign_T *sp, char_u *text) /// Define a new sign or update an existing sign int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl, - char *numhl) + char_u *culhl, char *numhl) { sign_T *sp_prev; sign_T *sp; @@ -939,15 +943,35 @@ int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text } if (linehl != NULL) { - sp->sn_line_hl = syn_check_group((char *)linehl, (int)STRLEN(linehl)); + if (*linehl == NUL) { + sp->sn_line_hl = 0; + } else { + sp->sn_line_hl = syn_check_group((char *)linehl, (int)STRLEN(linehl)); + } } if (texthl != NULL) { - sp->sn_text_hl = syn_check_group((char *)texthl, (int)STRLEN(texthl)); + if (*texthl == NUL) { + sp->sn_text_hl = 0; + } else { + sp->sn_text_hl = syn_check_group((char *)texthl, (int)STRLEN(texthl)); + } + } + + if (culhl != NULL) { + if (*culhl == NUL) { + sp->sn_cul_hl = 0; + } else { + sp->sn_cul_hl = syn_check_group((char *)culhl, (int)STRLEN(culhl)); + } } if (numhl != NULL) { - sp->sn_num_hl = syn_check_group(numhl, (int)STRLEN(numhl)); + if (*numhl == NUL) { + sp->sn_num_hl = 0; + } else { + sp->sn_num_hl = syn_check_group(numhl, (int)STRLEN(numhl)); + } } return OK; @@ -1133,6 +1157,7 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline) char_u *text = NULL; char_u *linehl = NULL; char_u *texthl = NULL; + char_u *culhl = NULL; char_u *numhl = NULL; int failed = false; @@ -1155,6 +1180,9 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline) } else if (STRNCMP(arg, "texthl=", 7) == 0) { arg += 7; texthl = vim_strnsave(arg, (size_t)(p - arg)); + } else if (STRNCMP(arg, "culhl=", 6) == 0) { + arg += 6; + culhl = vim_strnsave(arg, (size_t)(p - arg)); } else if (STRNCMP(arg, "numhl=", 6) == 0) { arg += 6; numhl = vim_strnsave(arg, (size_t)(p - arg)); @@ -1166,13 +1194,14 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline) } if (!failed) { - sign_define_by_name(sign_name, icon, linehl, text, texthl, (char *)numhl); + sign_define_by_name(sign_name, icon, linehl, text, texthl, culhl, (char *)numhl); } xfree(icon); xfree(text); xfree(linehl); xfree(texthl); + xfree(culhl); xfree(numhl); } @@ -1481,6 +1510,13 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict) } tv_dict_add_str(retdict, S_LEN("texthl"), (char *)p); } + if (sp->sn_cul_hl > 0) { + p = get_highlight_name_ext(NULL, sp->sn_cul_hl - 1, false); + if (p == NULL) { + p = "NONE"; + } + tv_dict_add_str(retdict, S_LEN("culhl"), (char *)p); + } if (sp->sn_num_hl > 0) { p = get_highlight_name_ext(NULL, sp->sn_num_hl - 1, false); if (p == NULL) { @@ -1609,6 +1645,16 @@ static void sign_list_defined(sign_T *sp) msg_puts(p); } } + if (sp->sn_cul_hl > 0) { + msg_puts(" culhl="); + const char *const p = get_highlight_name_ext(NULL, + sp->sn_cul_hl - 1, false); + if (p == NULL) { + msg_puts("NONE"); + } else { + msg_puts(p); + } + } if (sp->sn_num_hl > 0) { msg_puts(" numhl="); const char *const p = get_highlight_name_ext(NULL, @@ -1847,6 +1893,7 @@ int sign_define_from_dict(const char *name_arg, dict_T *dict) char *linehl = NULL; char *text = NULL; char *texthl = NULL; + char *culhl = NULL; char *numhl = NULL; int retval = -1; @@ -1866,11 +1913,12 @@ int sign_define_from_dict(const char *name_arg, dict_T *dict) linehl = tv_dict_get_string(dict, "linehl", true); text = tv_dict_get_string(dict, "text", true); texthl = tv_dict_get_string(dict, "texthl", true); + culhl = tv_dict_get_string(dict, "culhl", true); numhl = tv_dict_get_string(dict, "numhl", true); } if (sign_define_by_name((char_u *)name, (char_u *)icon, (char_u *)linehl, - (char_u *)text, (char_u *)texthl, numhl) + (char_u *)text, (char_u *)texthl, (char_u *)culhl, numhl) == OK) { retval = 0; } @@ -1881,6 +1929,7 @@ int sign_define_from_dict(const char *name_arg, dict_T *dict) xfree(linehl); xfree(text); xfree(texthl); + xfree(culhl); xfree(numhl); return retval; diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h index 46436b2c8e6ff0..c7345028785f1e 100644 --- a/src/nvim/sign_defs.h +++ b/src/nvim/sign_defs.h @@ -38,6 +38,7 @@ typedef struct sign_attrs_S { char_u *sat_text; int sat_texthl; int sat_linehl; + int sat_culhl; int sat_numhl; } sign_attrs_T; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index cb243668ce70de..9a133eeadfba9c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -115,6 +115,8 @@ static int include_none = 0; // when 1 include "nvim/None" static int include_default = 0; // when 1 include "nvim/default" static int include_link = 0; // when 2 include "nvim/link" and "clear" +#define MAX_SYN_NAME 200 + /// The "term", "cterm" and "gui" arguments can be any combination of the /// following names, separated by commas (but no spaces!). static char *(hl_name_table[]) = @@ -6175,6 +6177,8 @@ static const char *highlight_init_both[] = { "default link LineNrAbove LineNr", "default link LineNrBelow LineNr", "default link QuickFixLine Search", + "default link CursorLineSign SignColumn", + "default link CursorLineFold FoldColumn", "default link Substitute Search", "default link Whitespace NonText", "default link MsgSeparator StatusLine", @@ -7623,10 +7627,9 @@ int syn_name2id(const char *name) int syn_name2id_len(const char_u *name, size_t len) FUNC_ATTR_NONNULL_ALL { - char name_u[201]; + char name_u[MAX_SYN_NAME + 1]; - if (len == 0 || len > 200) { - // ID names over 200 chars don't deserve to be found! + if (len == 0 || len > MAX_SYN_NAME) { return 0; } @@ -7684,6 +7687,10 @@ char_u *syn_id2name(int id) /// @return 0 for failure else the id of the group int syn_check_group(const char *name, int len) { + if (len > MAX_SYN_NAME) { + emsg(_(e_highlight_group_name_too_long)); + return 0; + } int id = syn_name2id_len((char_u *)name, len); if (id == 0) { // doesn't exist yet return syn_add_group(vim_strnsave((char_u *)name, len)); diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim index c38bfa56772322..899eb530ecdf42 100644 --- a/src/nvim/testdir/test_highlight.vim +++ b/src/nvim/testdir/test_highlight.vim @@ -661,6 +661,13 @@ function Test_no_space_before_xxx() let &columns = l:org_columns endfunction +" Test for :highlight command errors +func Test_highlight_cmd_errors() + if has('gui_running') || has('nvim') + call assert_fails('hi ' .. repeat('a', 201) .. ' ctermfg=black', 'E1249:') + endif +endfunc + " Test for using RGB color values in a highlight group func Test_xxlast_highlight_RGB_color() CheckCanRunGui diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index f2872563964d53..799e6cb57b4667 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -15,13 +15,13 @@ func Test_sign() " the icon name when listing signs. sign define Sign1 text=x - call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error icon=../../pixmaps/stock_vim_find_help.png') + call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error culhl=Search icon=../../pixmaps/stock_vim_find_help.png') " Test listing signs. let a=execute('sign list') call assert_match('^\nsign Sign1 text=x \nsign Sign2 ' . \ 'icon=../../pixmaps/stock_vim_find_help.png .*text=xy ' . - \ 'linehl=Error texthl=Title$', a) + \ 'linehl=Error texthl=Title culhl=Search$', a) let a=execute('sign list Sign1') call assert_equal("\nsign Sign1 text=x ", a) @@ -126,6 +126,30 @@ func Test_sign() " call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:') call assert_fails("sign define Sign4 text=\\ ab linehl=Comment", 'E239:') + " an empty highlight argument for an existing sign clears it + sign define SignY texthl=TextHl culhl=CulHl linehl=LineHl + let sl = sign_getdefined('SignY')[0] + call assert_equal('TextHl', sl.texthl) + call assert_equal('CulHl', sl.culhl) + call assert_equal('LineHl', sl.linehl) + + sign define SignY texthl= culhl=CulHl linehl=LineHl + let sl = sign_getdefined('SignY')[0] + call assert_false(has_key(sl, 'texthl')) + call assert_equal('CulHl', sl.culhl) + call assert_equal('LineHl', sl.linehl) + + sign define SignY linehl= + let sl = sign_getdefined('SignY')[0] + call assert_false(has_key(sl, 'linehl')) + call assert_equal('CulHl', sl.culhl) + + sign define SignY culhl= + let sl = sign_getdefined('SignY')[0] + call assert_false(has_key(sl, 'culhl')) + + sign undefine SignY + " define sign with whitespace sign define Sign4 text=\ X linehl=Comment sign undefine Sign4 @@ -392,19 +416,21 @@ func Test_sign_funcs() call sign_undefine() " Tests for sign_define() - let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'} + let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error', + \ 'culhl': 'Visual'} call assert_equal(0, "sign1"->sign_define(attr)) call assert_equal([{'name' : 'sign1', 'texthl' : 'Error', - \ 'linehl' : 'Search', 'text' : '=>'}], sign_getdefined()) + \ 'linehl' : 'Search', 'culhl': 'Visual', 'text' : '=>'}], + \ sign_getdefined()) " Define a new sign without attributes and then update it call sign_define("sign2") let attr = {'text' : '!!', 'linehl' : 'DiffAdd', 'texthl' : 'DiffChange', - \ 'icon' : 'sign2.ico'} + \ 'culhl': 'DiffDelete', 'icon' : 'sign2.ico'} call Sign_define_ignore_error("sign2", attr) call assert_equal([{'name' : 'sign2', 'texthl' : 'DiffChange', - \ 'linehl' : 'DiffAdd', 'text' : '!!', 'icon' : 'sign2.ico'}], - \ "sign2"->sign_getdefined()) + \ 'linehl' : 'DiffAdd', 'culhl' : 'DiffDelete', 'text' : '!!', + \ 'icon' : 'sign2.ico'}], "sign2"->sign_getdefined()) " Test for a sign name with digits call assert_equal(0, sign_define(0002, {'linehl' : 'StatusLine'})) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 6b9586b4de311b..bed2bad36d6279 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -734,6 +734,15 @@ describe('TUI', function() end) it('paste: split "start paste" code', function() + child_session:request('nvim_exec_lua', [[ + _G.paste_phases = {} + vim.paste = (function(overridden) + return function(lines, phase) + table.insert(_G.paste_phases, phase) + overridden(lines, phase) + end + end)(vim.paste) + ]], {}) feed_data('i') -- Send split "start paste" sequence. feed_data('\027[2') @@ -747,13 +756,24 @@ describe('TUI', function() {3:-- INSERT --} | {3:-- TERMINAL --} | ]]) + screen:expect_unchanged() + local _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) + eq({-1}, rv) end) it('paste: split "stop paste" code', function() + child_session:request('nvim_exec_lua', [[ + _G.paste_phases = {} + vim.paste = (function(overridden) + return function(lines, phase) + table.insert(_G.paste_phases, phase) + overridden(lines, phase) + end + end)(vim.paste) + ]], {}) feed_data('i') -- Send split "stop paste" sequence. - feed_data('\027[200~pasted from terminal\027[20') - feed_data('1~') + feed_data('\027[200~pasted from terminal\027[20') -- phase 1 screen:expect([[ pasted from terminal{1: } | {4:~ }| @@ -763,6 +783,55 @@ describe('TUI', function() {3:-- INSERT --} | {3:-- TERMINAL --} | ]]) + local _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) + eq({1}, rv) + -- Remaining part of "stop paste" sequence + feed_data('1~') -- phase 3 + screen:expect_unchanged() + _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) + eq({1, 3}, rv) + end) + + it('paste: streamed paste with isolated "stop paste" code', function() + child_session:request('nvim_exec_lua', [[ + _G.paste_phases = {} + vim.paste = (function(overridden) + return function(lines, phase) + table.insert(_G.paste_phases, phase) + overridden(lines, phase) + end + end)(vim.paste) + ]], {}) + feed_data('i') + feed_data('\027[200~pasted') -- phase 1 + screen:expect([[ + pasted{1: } | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] [+] }| + {3:-- INSERT --} | + {3:-- TERMINAL --} | + ]]) + local _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) + eq({1}, rv) + feed_data(' from terminal') -- phase 2 + screen:expect([[ + pasted from terminal{1: } | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] [+] }| + {3:-- INSERT --} | + {3:-- TERMINAL --} | + ]]) + _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) + eq({1, 2}, rv) + -- Send isolated "stop paste" sequence. + feed_data('\027[201~') -- phase 3 + screen:expect_unchanged() + _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) + eq({1, 2, 3}, rv) end) it('allows termguicolors to be set at runtime', function() diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 9c035c728bea4f..03cd4bfd06750a 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -212,10 +212,10 @@ describe('ui/cursor', function() if m.blinkwait then m.blinkwait = 700 end end if m.hl_id then - m.hl_id = 58 + m.hl_id = 60 m.attr = {background = Screen.colors.DarkGray} end - if m.id_lm then m.id_lm = 59 end + if m.id_lm then m.id_lm = 61 end end -- Assert the new expectation. diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 249686234c28df..3e0e15c2b72751 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -41,6 +41,7 @@ describe("folded lines", function() [9] = {bold = true, foreground = Screen.colors.Brown}, [10] = {background = Screen.colors.LightGrey, underline = true}, [11] = {bold=true}, + [12] = {background = Screen.colors.Grey90}, }) end) @@ -84,6 +85,117 @@ describe("folded lines", function() end end) + it("highlights with CursorLineFold when 'cursorline' is set", function() + command("set cursorline foldcolumn=2 foldmethod=marker") + command("hi link CursorLineFold Search") + insert(content1) + feed("zf3j") + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {7: }This is a | + {7: }valid English | + {7: }sentence composed by | + {7: }an exhausted developer | + {7: }in his cave. | + {6: }{12:^ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {7: }This is a | + {7: }valid English | + {7: }sentence composed by | + {7: }an exhausted developer | + {7: }in his cave. | + {6: }{12:^ }| + {1:~ }| + | + ]]) + end + feed("k") + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {7: }This is a | + {7: }valid English | + {7: }sentence composed by | + {7: }an exhausted developer | + {6: }{12:^in his cave. }| + {7: } | + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {7: }This is a | + {7: }valid English | + {7: }sentence composed by | + {7: }an exhausted developer | + {6: }{12:^in his cave. }| + {7: } | + {1:~ }| + | + ]]) + end + command("set cursorlineopt=line") + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {7: }This is a | + {7: }valid English | + {7: }sentence composed by | + {7: }an exhausted developer | + {7: }{12:^in his cave. }| + {7: } | + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {7: }This is a | + {7: }valid English | + {7: }sentence composed by | + {7: }an exhausted developer | + {7: }{12:^in his cave. }| + {7: } | + {1:~ }| + | + ]]) + end + end) + it("highlighting with relative line numbers", function() command("set relativenumber cursorline cursorlineopt=number foldmethod=marker") feed_command("set foldcolumn=2") diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 741b93043d88ac..dcd31cfdb71e55 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -157,6 +157,99 @@ describe('Signs', function() ]]) end) + it('higlights the cursorline sign with culhl', function() + feed('iabc') + command('sign define piet text=>> texthl=Search culhl=ErrorMsg') + command('sign place 1 line=1 name=piet buffer=1') + command('sign place 2 line=2 name=piet buffer=1') + command('sign place 3 line=3 name=piet buffer=1') + command('set cursorline') + screen:expect([[ + {1:>>}a | + {1:>>}b | + {8:>>}{3:^c }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed('k') + screen:expect([[ + {1:>>}a | + {8:>>}{3:^b }| + {1:>>}c | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + command('set nocursorline') + screen:expect([[ + {1:>>}a | + {1:>>}^b | + {1:>>}c | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + command('set cursorline cursorlineopt=line') + screen:expect([[ + {1:>>}a | + {1:>>}{3:^b }| + {1:>>}c | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + command('set cursorlineopt=number') + screen:expect([[ + {1:>>}a | + {8:>>}^b | + {1:>>}c | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) + it('multiple signs #9295', function() feed('iabc') command('set number')