From 376de1483ee5380aaf5d2b6bb93d6ba245bfc329 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 8 Oct 2024 06:24:36 +0800 Subject: fix(drawline): correct highlight priority with Visual selection (#30706) --- src/nvim/drawline.c | 50 +++++++++++++------------------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 3b88dd2e90..79f3298eb4 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -927,7 +927,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s bool noinvcur = false; // don't invert the cursor bool lnum_in_visual_area = false; - bool attr_pri = false; // char_attr has priority + int char_attr_pri = 0; // attributes with high priority + int char_attr_base = 0; // attributes with low priority bool area_highlighting = false; // Visual or incsearch highlighting in this line int vi_attr = 0; // attributes for Visual and incsearch highlighting int area_attr = 0; // attributes desired by highlighting @@ -1741,16 +1742,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } // Decide which of the highlight attributes to use. - attr_pri = true; - if (area_attr != 0) { - wlv.char_attr = hl_combine_attr(wlv.line_attr, area_attr); + char_attr_pri = hl_combine_attr(wlv.line_attr, area_attr); if (!highlight_match) { // let search highlight show in Visual area if possible - wlv.char_attr = hl_combine_attr(search_attr, wlv.char_attr); + char_attr_pri = hl_combine_attr(search_attr, char_attr_pri); } } else if (search_attr != 0) { - wlv.char_attr = hl_combine_attr(wlv.line_attr, search_attr); + char_attr_pri = hl_combine_attr(wlv.line_attr, search_attr); } else if (wlv.line_attr != 0 && ((wlv.fromcol == -10 && wlv.tocol == MAXCOL) || wlv.vcol < wlv.fromcol @@ -1758,15 +1757,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s || wlv.vcol >= wlv.tocol)) { // Use wlv.line_attr when not in the Visual or 'incsearch' area // (area_attr may be 0 when "noinvcur" is set). - wlv.char_attr = wlv.line_attr; + char_attr_pri = wlv.line_attr; } else { - attr_pri = false; - wlv.char_attr = decor_attr; - } - - if (folded_attr != 0) { - wlv.char_attr = hl_combine_attr(folded_attr, wlv.char_attr); + char_attr_pri = 0; } + char_attr_base = hl_combine_attr(folded_attr, decor_attr); + wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri); } if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) { @@ -1997,25 +1993,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s can_spell = TRISTATE_TO_BOOL(decor_state.spell, can_spell); } - if (folded_attr) { - decor_attr = hl_combine_attr(folded_attr, decor_attr); - } - - if (decor_attr) { - if (!attr_pri) { - if (wlv.cul_attr) { - wlv.char_attr = 0 != wlv.line_attr_lowprio - ? hl_combine_attr(wlv.cul_attr, decor_attr) - : hl_combine_attr(decor_attr, wlv.cul_attr); - } else { - wlv.char_attr = decor_attr; - } - } else { - wlv.char_attr = hl_combine_attr(decor_attr, wlv.char_attr); - } - } else if (!attr_pri) { - wlv.char_attr = 0; - } + char_attr_base = hl_combine_attr(folded_attr, decor_attr); + wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri); // Check spelling (unless at the end of the line). // Only do this when there is no syntax highlighting, the @@ -2083,11 +2062,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } if (spell_attr != 0) { - if (!attr_pri) { - wlv.char_attr = hl_combine_attr(wlv.char_attr, spell_attr); - } else { - wlv.char_attr = hl_combine_attr(spell_attr, wlv.char_attr); - } + char_attr_base = hl_combine_attr(char_attr_base, spell_attr); + wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri); } if (wp->w_buffer->terminal) { -- cgit From 60e1862ccba744c4252d30f043bb077c2c657427 Mon Sep 17 00:00:00 2001 From: Devon Gardner Date: Mon, 7 Oct 2024 23:22:09 +0000 Subject: fix(coverity/510275): linematch out of bounds access (#30687) Problem: Int pointer cast to unsigned long pointer causes potential memory corruption. Solution: Cast and store value first, then pass the new pointer. --- src/nvim/linematch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c index 8943e6e8a6..39dfb8eeb9 100644 --- a/src/nvim/linematch.c +++ b/src/nvim/linematch.c @@ -150,7 +150,9 @@ static int count_n_matched_chars(mmfile_t **sp, const size_t n, bool iwhite) mmfile_t fastforward_buf_to_lnum(mmfile_t s, linenr_T lnum) { for (int i = 0; i < lnum - 1; i++) { - s.ptr = strnchr(s.ptr, (size_t *)&s.size, '\n'); + size_t n = (size_t)s.size; + s.ptr = strnchr(s.ptr, &n, '\n'); + s.size = (int)n; if (!s.ptr) { break; } -- cgit From f659699a26999cba4947f3c335c6e48d05c95310 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 8 Oct 2024 08:43:44 +0800 Subject: vim-patch:9.1.0766: too many strlen() calls in ex_getln.c (#30715) Problem: too many strlen() calls in ex_getln.c Solution: refactor the code to reduce the number of strlen() calls (John Marriott) closes: vim/vim#15809 https://github.com/vim/vim/commit/ccf8907570e14396e265b742e51f5089fdf97bf5 Co-authored-by: John Marriott --- src/nvim/ex_getln.c | 86 +++++++++++++++++++++++++++++++---------------------- src/nvim/search.c | 5 ++++ 2 files changed, 56 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 7d87e609ca..ca01a158a3 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -125,6 +125,7 @@ typedef struct { bool gotesc; // true when just typed int do_abbr; // when true check for abbr. char *lookfor; // string to match + int lookforlen; int hiscnt; // current history line in use int save_hiscnt; // history line before attempting // to jump to next match @@ -385,7 +386,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s if (!use_last_pat) { char c = *end; *end = NUL; - bool empty = empty_pattern_magic(p, strlen(p), magic); + bool empty = empty_pattern_magic(p, (size_t)(end - p), magic); *end = c; if (empty) { goto theend; @@ -538,7 +539,8 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state if (!use_last_pat) { next_char = ccline.cmdbuff[skiplen + patlen]; ccline.cmdbuff[skiplen + patlen] = NUL; - if (empty_pattern(ccline.cmdbuff + skiplen, search_delim) && !no_hlsearch) { + if (empty_pattern(ccline.cmdbuff + skiplen, (size_t)patlen, search_delim) + && !no_hlsearch) { redraw_all_later(UPD_SOME_VALID); set_no_hlsearch(true); } @@ -900,12 +902,11 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear && ccline.cmdlen && s->firstc != NUL && (s->some_key_typed || s->histype == HIST_SEARCH)) { - size_t cmdbufflen = strlen(ccline.cmdbuff); - add_to_history(s->histype, ccline.cmdbuff, cmdbufflen, true, + add_to_history(s->histype, ccline.cmdbuff, (size_t)ccline.cmdlen, true, s->histype == HIST_SEARCH ? s->firstc : NUL); if (s->firstc == ':') { xfree(new_last_cmdline); - new_last_cmdline = xstrnsave(ccline.cmdbuff, cmdbufflen); + new_last_cmdline = xstrnsave(ccline.cmdbuff, (size_t)ccline.cmdlen); } } @@ -1262,6 +1263,7 @@ static int command_line_execute(VimState *state, int key) && s->c != K_LEFT && s->c != K_RIGHT && (s->xpc.xp_numfiles > 0 || (s->c != Ctrl_P && s->c != Ctrl_N))) { XFREE_CLEAR(s->lookfor); + s->lookforlen = 0; } // When there are matching completions to select works like @@ -1440,7 +1442,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s return FAIL; } skiplen = 0; - patlen = (int)strlen(pat); + patlen = (int)last_search_pattern_len(); } else { pat = ccline.cmdbuff + skiplen; } @@ -1574,7 +1576,8 @@ static int command_line_erase_chars(CommandLineState *s) return CMDLINE_NOT_CHANGED; } - XFREE_CLEAR(ccline.cmdbuff); // no commandline to return + dealloc_cmdbuff(); // no commandline to return + if (!cmd_silent && !ui_has(kUICmdline)) { msg_col = 0; msg_putchar(' '); // delete ':' @@ -1702,7 +1705,6 @@ static void command_line_left_right_mouse(CommandLineState *s) static void command_line_next_histidx(CommandLineState *s, bool next_match) { - int j = (int)strlen(s->lookfor); while (true) { // one step backwards if (!next_match) { @@ -1746,7 +1748,7 @@ static void command_line_next_histidx(CommandLineState *s, bool next_match) if ((s->c != K_UP && s->c != K_DOWN) || s->hiscnt == s->save_hiscnt || strncmp(get_histentry(s->histype)[s->hiscnt].hisstr, - s->lookfor, (size_t)j) == 0) { + s->lookfor, (size_t)s->lookforlen) == 0) { break; } } @@ -1765,30 +1767,34 @@ static int command_line_browse_history(CommandLineState *s) // save current command string so it can be restored later if (s->lookfor == NULL) { - s->lookfor = xstrdup(ccline.cmdbuff); + s->lookfor = xstrnsave(ccline.cmdbuff, (size_t)ccline.cmdlen); s->lookfor[ccline.cmdpos] = NUL; + s->lookforlen = ccline.cmdpos; } bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N || s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN); command_line_next_histidx(s, next_match); - if (s->hiscnt != s->save_hiscnt) { - // jumped to other entry + if (s->hiscnt != s->save_hiscnt) { // jumped to other entry char *p; + int plen; int old_firstc; - XFREE_CLEAR(ccline.cmdbuff); + dealloc_cmdbuff(); + s->xpc.xp_context = EXPAND_NOTHING; if (s->hiscnt == get_hislen()) { p = s->lookfor; // back to the old one + plen = s->lookforlen; } else { p = get_histentry(s->histype)[s->hiscnt].hisstr; + plen = (int)strlen(p); } if (s->histype == HIST_SEARCH && p != s->lookfor - && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) { + && (old_firstc = (uint8_t)p[plen + 1]) != s->firstc) { int len = 0; // Correct for the separator character used when // adding the history entry vs the one used now. @@ -1827,12 +1833,13 @@ static int command_line_browse_history(CommandLineState *s) } } ccline.cmdbuff[len] = NUL; + ccline.cmdpos = ccline.cmdlen = len; } else { - alloc_cmdbuff((int)strlen(p)); + alloc_cmdbuff(plen); STRCPY(ccline.cmdbuff, p); + ccline.cmdpos = ccline.cmdlen = plen; } - ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff); redrawcmd(); return CMDLINE_CHANGED; } @@ -2201,18 +2208,17 @@ static int command_line_not_changed(CommandLineState *s) /// Guess that the pattern matches everything. Only finds specific cases, such /// as a trailing \|, which can happen while typing a pattern. -static bool empty_pattern(char *p, int delim) +static bool empty_pattern(char *p, size_t len, int delim) { - size_t n = strlen(p); magic_T magic_val = MAGIC_ON; - if (n > 0) { + if (len > 0) { skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic_val); } else { return true; } - return empty_pattern_magic(p, n, magic_val); + return empty_pattern_magic(p, len, magic_val); } static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val) @@ -2225,11 +2231,9 @@ static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val) // true, if the pattern is empty, or the pattern ends with \| and magic is // set (or it ends with '|' and very magic is set) - return len == 0 || (len > 1 - && ((p[len - 2] == '\\' - && p[len - 1] == '|' && magic_val == MAGIC_ON) - || (p[len - 2] != '\\' - && p[len - 1] == '|' && magic_val == MAGIC_ALL))); + return len == 0 || (len > 1 && p[len - 1] == '|' + && ((p[len - 2] == '\\' && magic_val == MAGIC_ON) + || (p[len - 2] != '\\' && magic_val == MAGIC_ALL))); } handle_T cmdpreview_get_bufnr(void) @@ -2710,7 +2714,7 @@ static int command_line_changed(CommandLineState *s) /// Abandon the command line. static void abandon_cmdline(void) { - XFREE_CLEAR(ccline.cmdbuff); + dealloc_cmdbuff(); ccline.redraw_state = kCmdRedrawNone; if (msg_scrolled == 0) { compute_cmdrow(); @@ -3000,8 +3004,15 @@ bool cmdline_at_end(void) return (ccline.cmdpos >= ccline.cmdlen); } -// Allocate a new command line buffer. -// Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. +/// Deallocate a command line buffer, updating the buffer size and length. +static void dealloc_cmdbuff(void) +{ + XFREE_CLEAR(ccline.cmdbuff); + ccline.cmdlen = ccline.cmdbufflen = 0; +} + +/// Allocate a new command line buffer. +/// Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. static void alloc_cmdbuff(int len) { // give some extra space to avoid having to allocate all the time @@ -3023,6 +3034,7 @@ void realloc_cmdbuff(int len) } char *p = ccline.cmdbuff; + alloc_cmdbuff(len); // will get some more // There isn't always a NUL after the command, but it may need to be // there, thus copy up to the NUL and add a NUL. @@ -4509,17 +4521,20 @@ static int open_cmdwin(void) cmdwin_result = Ctrl_C; } // Set the new command line from the cmdline buffer. - xfree(ccline.cmdbuff); + dealloc_cmdbuff(); + if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { // :qa[!] typed const char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!"; + size_t plen = (cmdwin_result == K_XF2) ? 2 : 3; if (histtype == HIST_CMD) { // Execute the command directly. - ccline.cmdbuff = xstrdup(p); + ccline.cmdbuff = xmemdupz(p, plen); + ccline.cmdlen = (int)plen; + ccline.cmdbufflen = (int)plen + 1; cmdwin_result = CAR; } else { // First need to cancel what we were doing. - ccline.cmdbuff = NULL; stuffcharReadbuff(':'); stuffReadbuff(p); stuffcharReadbuff(CAR); @@ -4529,17 +4544,18 @@ static int open_cmdwin(void) // and don't modify the cmd window. ccline.cmdbuff = NULL; } else { - ccline.cmdbuff = xstrdup(get_cursor_line_ptr()); + ccline.cmdlen = get_cursor_line_len(); + ccline.cmdbufflen = ccline.cmdlen + 1; + ccline.cmdbuff = xstrnsave(get_cursor_line_ptr(), (size_t)ccline.cmdlen); } + if (ccline.cmdbuff == NULL) { - ccline.cmdbuff = xstrdup(""); + ccline.cmdbuff = xmemdupz("", 0); ccline.cmdlen = 0; ccline.cmdbufflen = 1; ccline.cmdpos = 0; cmdwin_result = Ctrl_C; } else { - ccline.cmdlen = (int)strlen(ccline.cmdbuff); - ccline.cmdbufflen = ccline.cmdlen + 1; ccline.cmdpos = curwin->w_cursor.col; // If the cursor is on the last character, it probably should be after it. if (ccline.cmdpos == ccline.cmdlen - 1 || ccline.cmdpos > ccline.cmdlen) { diff --git a/src/nvim/search.c b/src/nvim/search.c index ff6e135df1..2a935f6878 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -380,6 +380,11 @@ char *last_search_pattern(void) return spats[RE_SEARCH].pat; } +size_t last_search_pattern_len(void) +{ + return spats[RE_SEARCH].patlen; +} + /// Return true when case should be ignored for search pattern "pat". /// Uses the 'ignorecase' and 'smartcase' options. int ignorecase(char *pat) -- cgit From f449a38f6a47bee30f0d4e291d8234d1ac8288a7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Oct 2024 08:14:18 +0800 Subject: vim-patch:9.1.0770: current command line completion is a bit limited (#30728) Problem: current command completion is a bit limited Solution: Add the shellcmdline completion type and getmdcomplpat() function (Ruslan Russkikh). closes: vim/vim#15823 https://github.com/vim/vim/commit/0407d621bbad020b840ffbbbd25ba023bbc05edd Co-authored-by: Ruslan Russkikh --- src/nvim/cmdexpand.c | 4 +++- src/nvim/cmdexpand_defs.h | 1 + src/nvim/eval.lua | 16 +++++++++++++++- src/nvim/ex_getln.c | 39 ++++++++++++++++++++++++++++++++++++++- src/nvim/usercmd.c | 7 ++++--- 5 files changed, 61 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 402a891099..b37a1d690f 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -119,6 +119,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp) && xp->xp_context != EXPAND_PACKADD && xp->xp_context != EXPAND_RUNTIME && xp->xp_context != EXPAND_SHELLCMD + && xp->xp_context != EXPAND_SHELLCMDLINE && xp->xp_context != EXPAND_TAGS && xp->xp_context != EXPAND_TAGS_LISTFILES && xp->xp_context != EXPAND_USER_LIST @@ -1527,7 +1528,8 @@ static void set_context_for_wildcard_arg(exarg_T *eap, const char *arg, bool use xp->xp_context = EXPAND_FILES; // For a shell command more chars need to be escaped. - if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal) { + if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal + || *complp == EXPAND_SHELLCMDLINE) { #ifndef BACKSLASH_IN_FILENAME xp->xp_shell = true; #endif diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h index 3369790151..86725eafd6 100644 --- a/src/nvim/cmdexpand_defs.h +++ b/src/nvim/cmdexpand_defs.h @@ -106,6 +106,7 @@ enum { EXPAND_ARGOPT, EXPAND_KEYMAP, EXPAND_DIRS_IN_CDPATH, + EXPAND_SHELLCMDLINE, EXPAND_CHECKHEALTH, EXPAND_LUA, }; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 50aaf9e03b..24f986ef4e 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3611,6 +3611,20 @@ M.funcs = { returns = 'string', signature = 'getcharstr([{expr}])', }, + getcmdcomplpat = { + desc = [=[ + Return completion pattern of the current command-line. + Only works when the command line is being edited, thus + requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, + |getcmdprompt()|, |getcmdcompltype()| and |setcmdline()|. + Returns an empty string when completion is not defined. + ]=], + name = 'getcmdcomplpat', + params = {}, + returns = 'string', + signature = 'getcmdcomplpat()', + }, getcmdcompltype = { desc = [=[ Return the type of the current command-line completion. @@ -3618,7 +3632,7 @@ M.funcs = { requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, - |getcmdprompt()| and |setcmdline()|. + |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. Returns an empty string when completion is not defined. ]=], name = 'getcmdcompltype', diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index ca01a158a3..b58a6b16f1 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4086,14 +4086,44 @@ static char *get_cmdline_str(void) return xstrnsave(p->cmdbuff, (size_t)p->cmdlen); } +/// Get the current command-line completion pattern. +static char *get_cmdline_completion_pattern(void) +{ + if (cmdline_star > 0) { + return NULL; + } + + CmdlineInfo *p = get_ccline_ptr(); + if (p == NULL || p->xpc == NULL) { + return NULL; + } + + int xp_context = p->xpc->xp_context; + if (xp_context == EXPAND_NOTHING) { + set_expand_context(p->xpc); + xp_context = p->xpc->xp_context; + p->xpc->xp_context = EXPAND_NOTHING; + } + if (xp_context == EXPAND_UNSUCCESSFUL) { + return NULL; + } + + char *compl_pat = p->xpc->xp_pattern; + if (compl_pat == NULL) { + return NULL; + } + + return xstrdup(compl_pat); +} + /// Get the current command-line completion type. static char *get_cmdline_completion(void) { if (cmdline_star > 0) { return NULL; } - CmdlineInfo *p = get_ccline_ptr(); + CmdlineInfo *p = get_ccline_ptr(); if (p == NULL || p->xpc == NULL) { return NULL; } @@ -4123,6 +4153,13 @@ static char *get_cmdline_completion(void) return xstrdup(cmd_compl); } +/// "getcmdcomplpat()" function +void f_getcmdcomplpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = get_cmdline_completion_pattern(); +} + /// "getcmdcompltype()" function void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index d32e0ee319..8404b2bc14 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -91,6 +91,7 @@ static const char *command_complete[] = { [EXPAND_PACKADD] = "packadd", [EXPAND_RUNTIME] = "runtime", [EXPAND_SHELLCMD] = "shellcmd", + [EXPAND_SHELLCMDLINE] = "shellcmdline", [EXPAND_SIGN] = "sign", [EXPAND_TAGS] = "tag", [EXPAND_TAGS_LISTFILES] = "tag_listfiles", @@ -285,8 +286,7 @@ const char *set_context_in_user_cmdarg(const char *cmd FUNC_ATTR_UNUSED, const c } if (argt & EX_XFILE) { - // EX_XFILE: file names are handled above. - xp->xp_context = context; + // EX_XFILE: file names are handled before this call. return NULL; } @@ -675,7 +675,8 @@ int parse_compl_arg(const char *value, int vallen, int *complp, uint32_t *argt, *complp = i; if (i == EXPAND_BUFFERS) { *argt |= EX_BUFNAME; - } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES) { + } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES + || i == EXPAND_SHELLCMDLINE) { *argt |= EX_XFILE; } break; -- cgit From cd8e15e3373dc9544d582640f043d3dee83a953d Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 9 Oct 2024 19:16:36 +0200 Subject: build(deps): bump wasmtime to v25.0.2 --- src/nvim/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index c2a358327a..8819da1ae5 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -49,7 +49,7 @@ if(ENABLE_LIBINTL) endif() if(ENABLE_WASMTIME) - find_package(Wasmtime 25.0.1 EXACT REQUIRED) + find_package(Wasmtime 25.0.2 EXACT REQUIRED) target_link_libraries(main_lib INTERFACE wasmtime) target_compile_definitions(nvim_bin PRIVATE HAVE_WASMTIME) endif() -- cgit From 8450752f46e1482bf34b7f05e484cca740f61075 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Oct 2024 08:15:14 +0800 Subject: vim-patch:9.1.0771: completion attribute hl_group is confusing Problem: Currently completion attribute hl_group is combined with all items, which is redundant and confusing with kind_hlgroup Solution: Renamed to abbr_hlgroup and combine it only with the abbr item (glepnir). closes: vim/vim#15818 https://github.com/vim/vim/commit/0fe17f8ffbd2588ecd2bf42dced556897bc64f89 Co-authored-by: glepnir --- src/nvim/cmdexpand.c | 3 ++- src/nvim/insexpand.c | 19 ++++++++++--------- src/nvim/popupmenu.c | 28 ++++++++++++++++++---------- src/nvim/popupmenu.h | 2 +- 4 files changed, 31 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index b37a1d690f..45648fc15f 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -357,7 +357,8 @@ static int cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches, .pum_info = NULL, .pum_extra = NULL, .pum_kind = NULL, - .pum_user_hlattr = -1, + .pum_user_abbr_hlattr = -1, + .pum_user_kind_hlattr = -1, }; } diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 84dd55fa78..4a73826233 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -164,7 +164,7 @@ struct compl_S { int cp_flags; ///< CP_ values int cp_number; ///< sequence number int cp_score; ///< fuzzy match score - int cp_user_hlattr; ///< highlight attribute to combine with + int cp_user_abbr_hlattr; ///< highlight attribute to combine with for abbr int cp_user_kind_hlattr; ///< highlight attribute for kind }; @@ -798,7 +798,7 @@ static inline void free_cptext(char *const *const cptext) /// returned in case of error. static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext, const bool cptext_allocated, typval_T *user_data, const Direction cdir, - int flags_arg, const bool adup, int user_hlattr, int user_kind_hlattr) + int flags_arg, const bool adup, int user_abbr_hlattr, int user_kind_hlattr) FUNC_ATTR_NONNULL_ARG(1) { compl_T *match; @@ -864,7 +864,7 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons match->cp_fname = NULL; } match->cp_flags = flags; - match->cp_user_hlattr = user_hlattr; + match->cp_user_abbr_hlattr = user_abbr_hlattr; match->cp_user_kind_hlattr = user_kind_hlattr; if (cptext != NULL) { @@ -1268,7 +1268,7 @@ static int ins_compl_build_pum(void) compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND]; compl_match_array[i].pum_info = comp->cp_text[CPT_INFO]; compl_match_array[i].pum_score = comp->cp_score; - compl_match_array[i].pum_user_hlattr = comp->cp_user_hlattr; + compl_match_array[i].pum_user_abbr_hlattr = comp->cp_user_abbr_hlattr; compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr; if (comp->cp_text[CPT_MENU] != NULL) { compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU]; @@ -2567,9 +2567,9 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) bool empty = false; int flags = fast ? CP_FAST : 0; char *(cptext[CPT_COUNT]); - char *user_hlname = NULL; + char *user_abbr_hlname = NULL; + int user_abbr_hlattr = -1; char *user_kind_hlname = NULL; - int user_hlattr = -1; int user_kind_hlattr = -1; typval_T user_data; @@ -2581,8 +2581,8 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true); cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true); - user_hlname = tv_dict_get_string(tv->vval.v_dict, "hl_group", false); - user_hlattr = get_user_highlight_attr(user_hlname); + user_abbr_hlname = tv_dict_get_string(tv->vval.v_dict, "abbr_hlgroup", false); + user_abbr_hlattr = get_user_highlight_attr(user_abbr_hlname); user_kind_hlname = tv_dict_get_string(tv->vval.v_dict, "kind_hlgroup", false); user_kind_hlattr = get_user_highlight_attr(user_kind_hlname); @@ -2608,7 +2608,8 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) return FAIL; } int status = ins_compl_add((char *)word, -1, NULL, cptext, true, - &user_data, dir, flags, dup, user_hlattr, user_kind_hlattr); + &user_data, dir, flags, dup, + user_abbr_hlattr, user_kind_hlattr); if (status != OK) { tv_clear(&user_data); } diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index ddcb819054..3f64e841e2 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -654,11 +654,14 @@ void pum_redraw(void) int item_type = order[j]; hlf = hlfs[item_type]; attr = win_hl_attr(curwin, (int)hlf); - if (pum_array[idx].pum_user_hlattr > 0) { - attr = hl_combine_attr(attr, pum_array[idx].pum_user_hlattr); + int orig_attr = attr; + int user_abbr_hlattr = pum_array[idx].pum_user_abbr_hlattr; + int user_kind_hlattr = pum_array[idx].pum_user_kind_hlattr; + if (item_type == CPT_ABBR && user_abbr_hlattr > 0) { + attr = hl_combine_attr(attr, user_abbr_hlattr); } - if (item_type == CPT_KIND && pum_array[idx].pum_user_kind_hlattr > 0) { - attr = hl_combine_attr(attr, pum_array[idx].pum_user_kind_hlattr); + if (item_type == CPT_KIND && user_kind_hlattr > 0) { + attr = hl_combine_attr(attr, user_kind_hlattr); } int width = 0; char *s = NULL; @@ -684,8 +687,10 @@ void pum_redraw(void) *p = saved; } - int user_hlattr = pum_array[idx].pum_user_hlattr; - int *attrs = pum_compute_text_attrs(st, hlf, user_hlattr); + int *attrs = NULL; + if (item_type == CPT_ABBR) { + attrs = pum_compute_text_attrs(st, hlf, user_abbr_hlattr); + } if (pum_rl) { char *rt = reverse_text(st); @@ -727,7 +732,10 @@ void pum_redraw(void) grid_col += width; } - xfree(attrs); + if (attrs != NULL) { + xfree(attrs); + attrs = NULL; + } if (*p != TAB) { break; @@ -735,10 +743,10 @@ void pum_redraw(void) // Display two spaces for a Tab. if (pum_rl) { - grid_line_puts(grid_col - 1, " ", 2, attr); + grid_line_puts(grid_col - 1, " ", 2, orig_attr); grid_col -= 2; } else { - grid_line_puts(grid_col, " ", 2, attr); + grid_line_puts(grid_col, " ", 2, orig_attr); grid_col += 2; } totwidth += 2; @@ -772,7 +780,7 @@ void pum_redraw(void) grid_line_fill(col_off - basic_width - n + 1, grid_col + 1, schar_from_ascii(' '), attr); grid_col = col_off - basic_width - n; } else { - grid_line_fill(grid_col, col_off + basic_width + n, schar_from_ascii(' '), attr); + grid_line_fill(grid_col, col_off + basic_width + n, schar_from_ascii(' '), orig_attr); grid_col = col_off + basic_width + n; } totwidth = basic_width + n; diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h index f7eb0240ae..5f02b3b9e0 100644 --- a/src/nvim/popupmenu.h +++ b/src/nvim/popupmenu.h @@ -16,7 +16,7 @@ typedef struct { char *pum_info; ///< extra info int pum_score; ///< fuzzy match score int pum_idx; ///< index of item before sorting by score - int pum_user_hlattr; ///< highlight attribute to combine with + int pum_user_abbr_hlattr; ///< highlight attribute to combine with int pum_user_kind_hlattr; ///< highlight attribute for kind } pumitem_T; -- cgit From 9612b3a9053ae2dfe5a4321a5dd0af249c281543 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 10 Oct 2024 06:49:37 +0800 Subject: vim-patch:9.1.0772: some missing changes from v9.1.0771 Problem: some missing changes from v9.1.0771 Solution: use correct highlighting attribute and adjust comments (glepnir) closes: vim/vim#15836 https://github.com/vim/vim/commit/7baa014d0f73c3b2c6831471d047220633651238 Co-authored-by: glepnir --- src/nvim/insexpand.c | 2 +- src/nvim/popupmenu.c | 13 +++++++------ src/nvim/popupmenu.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 4a73826233..2482cef7a1 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -164,7 +164,7 @@ struct compl_S { int cp_flags; ///< CP_ values int cp_number; ///< sequence number int cp_score; ///< fuzzy match score - int cp_user_abbr_hlattr; ///< highlight attribute to combine with for abbr + int cp_user_abbr_hlattr; ///< highlight attribute for abbr int cp_user_kind_hlattr; ///< highlight attribute for kind }; diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 3f64e841e2..ed4c9f3056 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -733,8 +733,7 @@ void pum_redraw(void) } if (attrs != NULL) { - xfree(attrs); - attrs = NULL; + XFREE_CLEAR(attrs); } if (*p != TAB) { @@ -743,10 +742,10 @@ void pum_redraw(void) // Display two spaces for a Tab. if (pum_rl) { - grid_line_puts(grid_col - 1, " ", 2, orig_attr); + grid_line_puts(grid_col - 1, " ", 2, attr); grid_col -= 2; } else { - grid_line_puts(grid_col, " ", 2, orig_attr); + grid_line_puts(grid_col, " ", 2, attr); grid_col += 2; } totwidth += 2; @@ -777,10 +776,12 @@ void pum_redraw(void) } if (pum_rl) { - grid_line_fill(col_off - basic_width - n + 1, grid_col + 1, schar_from_ascii(' '), attr); + grid_line_fill(col_off - basic_width - n + 1, grid_col + 1, + schar_from_ascii(' '), orig_attr); grid_col = col_off - basic_width - n; } else { - grid_line_fill(grid_col, col_off + basic_width + n, schar_from_ascii(' '), orig_attr); + grid_line_fill(grid_col, col_off + basic_width + n, + schar_from_ascii(' '), orig_attr); grid_col = col_off + basic_width + n; } totwidth = basic_width + n; diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h index 5f02b3b9e0..40bd42ee17 100644 --- a/src/nvim/popupmenu.h +++ b/src/nvim/popupmenu.h @@ -16,7 +16,7 @@ typedef struct { char *pum_info; ///< extra info int pum_score; ///< fuzzy match score int pum_idx; ///< index of item before sorting by score - int pum_user_abbr_hlattr; ///< highlight attribute to combine with + int pum_user_abbr_hlattr; ///< highlight attribute for abbr int pum_user_kind_hlattr; ///< highlight attribute for kind } pumitem_T; -- cgit From 6f1601a1b94e6ea724d8436600c64760525d1d2b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 11 Oct 2024 06:48:45 +0800 Subject: vim-patch:9.1.0774: "shellcmdline" doesn't work with getcompletion() (#30750) Problem: "shellcmdline" doesn't work with getcompletion(). Solution: Use set_context_for_wildcard_arg() (zeertzjq). closes: vim/vim#15834 https://github.com/vim/vim/commit/85f36d61e09b12d6f1c60201129823371daa4a84 --- src/nvim/cmdexpand.c | 8 +++++++- src/nvim/eval.lua | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 45648fc15f..250d705ee6 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -1529,7 +1529,8 @@ static void set_context_for_wildcard_arg(exarg_T *eap, const char *arg, bool use xp->xp_context = EXPAND_FILES; // For a shell command more chars need to be escaped. - if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal + if (usefilter + || (eap != NULL && (eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal)) || *complp == EXPAND_SHELLCMDLINE) { #ifndef BACKSLASH_IN_FILENAME xp->xp_shell = true; @@ -3604,6 +3605,11 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) set_context_in_runtime_cmd(&xpc, xpc.xp_pattern); xpc.xp_pattern_len = strlen(xpc.xp_pattern); } + if (xpc.xp_context == EXPAND_SHELLCMDLINE) { + int context = EXPAND_SHELLCMDLINE; + set_context_for_wildcard_arg(NULL, xpc.xp_pattern, false, &xpc, &context); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); + } theend: if (xpc.xp_context == EXPAND_LUA) { diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 24f986ef4e..a440450b9d 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3775,6 +3775,7 @@ M.funcs = { runtime |:runtime| completion scriptnames sourced script names |:scriptnames| shellcmd Shell command + shellcmdline Shell command line with filename arguments sign |:sign| suboptions syntax syntax file names |'syntax'| syntime |:syntime| suboptions -- cgit From a0e3fe57417f0b7c8de60dcebe44d0cf034c4b9a Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Thu, 10 Oct 2024 23:26:25 -0700 Subject: feat(ui): cascading style inheritance for Pmenu* highlights #29980 - `PmenuSel` and `PmenuMatch` inherit from `Pmenu` - `PmenuMatchSel` inherits from both `PmenuSel` and `PmenuMatch` --- src/nvim/popupmenu.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index ed4c9f3056..87ef6a27ad 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -480,13 +480,19 @@ static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr) for (int i = 0; i < ga->ga_len; i++) { if (char_pos == ((uint32_t *)ga->ga_data)[i]) { new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI); + new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PMNI), new_attr); + new_attr = hl_combine_attr(win_hl_attr(curwin, (int)hlf), new_attr); break; } } } else if (matched_start && ptr < text + leader_len) { new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI); + new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PMNI), new_attr); + new_attr = hl_combine_attr(win_hl_attr(curwin, (int)hlf), new_attr); } + new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), new_attr); + if (user_hlattr > 0) { new_attr = hl_combine_attr(new_attr, user_hlattr); } @@ -629,6 +635,7 @@ void pum_redraw(void) const hlf_T *const hlfs = (idx == pum_selected) ? hlfsSel : hlfsNorm; hlf_T hlf = hlfs[0]; // start with "word" highlight int attr = win_hl_attr(curwin, (int)hlf); + attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), attr); grid_line_start(&pum_grid, row); @@ -663,6 +670,7 @@ void pum_redraw(void) if (item_type == CPT_KIND && user_kind_hlattr > 0) { attr = hl_combine_attr(attr, user_kind_hlattr); } + attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), attr); int width = 0; char *s = NULL; p = pum_get_item(idx, item_type); -- cgit From 267c7525f738cdd6024c39da758e885c026ffaaa Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Wed, 2 Oct 2024 10:34:14 -0700 Subject: feat(treesitter): introduce child_with_descendant() This commit also marks `child_containing_descendant()` as deprecated (per upstream's documentation), and uses `child_with_descendant()` in its place. Minimum required tree-sitter version will now be `0.24`. --- src/nvim/CMakeLists.txt | 2 +- src/nvim/lua/treesitter.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 8819da1ae5..0ba2eeb376 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -31,7 +31,7 @@ target_link_libraries(main_lib INTERFACE ${LUV_LIBRARY}) find_package(Iconv REQUIRED) find_package(Libuv 1.28.0 REQUIRED) find_package(Lpeg REQUIRED) -find_package(Treesitter 0.23.0 REQUIRED) +find_package(Treesitter 0.24.0 REQUIRED) find_package(Unibilium 2.0 REQUIRED) find_package(UTF8proc REQUIRED) diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index ab97704dfe..819ec41390 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -828,6 +828,7 @@ static struct luaL_Reg node_meta[] = { { "parent", node_parent }, { "__has_ancestor", __has_ancestor }, { "child_containing_descendant", node_child_containing_descendant }, + { "child_with_descendant", node_child_with_descendant }, { "iter_children", node_iter_children }, { "next_sibling", node_next_sibling }, { "prev_sibling", node_prev_sibling }, @@ -1146,7 +1147,7 @@ static int __has_ancestor(lua_State *L) int const pred_len = (int)lua_objlen(L, 2); TSNode node = ts_tree_root_node(descendant.tree); - while (!ts_node_is_null(node)) { + while (node.id != descendant.id) { char const *node_type = ts_node_type(node); size_t node_type_len = strlen(node_type); @@ -1163,7 +1164,7 @@ static int __has_ancestor(lua_State *L) lua_pop(L, 1); } - node = ts_node_child_containing_descendant(node, descendant); + node = ts_node_child_with_descendant(node, descendant); } lua_pushboolean(L, false); @@ -1179,6 +1180,15 @@ static int node_child_containing_descendant(lua_State *L) return 1; } +static int node_child_with_descendant(lua_State *L) +{ + TSNode node = node_check(L, 1); + TSNode descendant = node_check(L, 2); + TSNode child = ts_node_child_with_descendant(node, descendant); + push_node(L, child, 1); + return 1; +} + static int node_next_sibling(lua_State *L) { TSNode node = node_check(L, 1); -- cgit From d3193afc2559e7d84ed2d76664a650dc03b4c6ef Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Thu, 19 Sep 2024 13:08:22 -0700 Subject: fix(treesitter): remove duplicate symbol names in language.inspect() **Problems:** - `vim.treesitter.language.inspect()` returns duplicate symbol names, sometimes up to 6 of one kind in the case of `markdown` - The list-like `symbols` table can have holes and is thus not even a valid msgpack table anyway, mentioned in a test **Solution:** Return symbols as a map, rather than a list, where field names are the names of the symbol. The boolean value associated with the field encodes whether or not the symbol is named. Note that anonymous nodes are surrounded with double quotes (`"`) to prevent potential collisions with named counterparts that have the same identifier. --- src/nvim/lua/treesitter.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 819ec41390..3ceb21b61a 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -271,12 +271,16 @@ int tslua_inspect_lang(lua_State *L) // not used by the API continue; } - lua_createtable(L, 2, 0); // [retval, symbols, elem] - lua_pushstring(L, ts_language_symbol_name(lang, (TSSymbol)i)); - lua_rawseti(L, -2, 1); - lua_pushboolean(L, t == TSSymbolTypeRegular); - lua_rawseti(L, -2, 2); // [retval, symbols, elem] - lua_rawseti(L, -2, (int)i); // [retval, symbols] + const char *name = ts_language_symbol_name(lang, (TSSymbol)i); + bool named = t == TSSymbolTypeRegular; + lua_pushboolean(L, named); // [retval, symbols, is_named] + if (!named) { + char buf[256]; + snprintf(buf, sizeof(buf), "\"%s\"", name); + lua_setfield(L, -2, buf); // [retval, symbols] + } else { + lua_setfield(L, -2, name); // [retval, symbols] + } } lua_setfield(L, -2, "symbols"); // [retval] -- cgit From 486076a0e1ee3c7bb230e0f95a21607fadea96d4 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 11 Oct 2024 20:25:35 +0200 Subject: fix(build): remove USE_FNAME_CASE, redundant with CASE_INSENSITIVE_FILENAME It stands to reason, you need to "fix" case-insensitive filenames if-and-only-if you have case-insensitive filenames. --- src/nvim/buffer.c | 2 +- src/nvim/ex_cmds.c | 2 +- src/nvim/main.c | 2 +- src/nvim/path.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 4a87cebfa7..ce47705aa6 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2985,7 +2985,7 @@ int setfname(buf_T *buf, char *ffname_arg, char *sfname_arg, bool message) close_buffer(NULL, obuf, DOBUF_WIPE, false, false); } sfname = xstrdup(sfname); -#ifdef USE_FNAME_CASE +#ifdef CASE_INSENSITIVE_FILENAME path_fix_case(sfname); // set correct case for short file name #endif if (buf->b_sfname != buf->b_ffname) { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a98de05815..d48d25fc22 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2134,7 +2134,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum if (sfname == NULL) { sfname = ffname; } -#ifdef USE_FNAME_CASE +#ifdef CASE_INSENSITIVE_FILENAME if (sfname != NULL) { path_fix_case(sfname); // set correct case for sfname } diff --git a/src/nvim/main.c b/src/nvim/main.c index dc102f6f6d..b54b2a531a 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1448,7 +1448,7 @@ scripterror: p = r; } -#ifdef USE_FNAME_CASE +#ifdef CASE_INSENSITIVE_FILENAME // Make the case of the file name match the actual file. path_fix_case(p); #endif diff --git a/src/nvim/path.c b/src/nvim/path.c index 9cce504831..4c16adde4c 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1827,7 +1827,7 @@ char *fix_fname(const char *fname) fname = xstrdup(fname); -# ifdef USE_FNAME_CASE +# ifdef CASE_INSENSITIVE_FILENAME path_fix_case((char *)fname); // set correct case for file name # endif -- cgit From c49030b75ad8b8a9f8e7f023b0ee5f9c8c40afdd Mon Sep 17 00:00:00 2001 From: Devon Gardner Date: Fri, 11 Oct 2024 23:43:07 +0000 Subject: fix(coverity/497375): f_strpart cast overflow (#30773) Problem: Casting long to int introduces risk of overflow. Solution: Work with all int64_t (long) rather than casting back and forth. --- src/nvim/strings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 118abbae6d..2de65391cc 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -2838,10 +2838,10 @@ void f_strpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) { - int off; + int64_t off; // length in characters - for (off = (int)n; off < (int)slen && len > 0; len--) { + for (off = n; off < (int64_t)slen && len > 0; len--) { off += utfc_ptr2len(p + off); } len = off - n; -- cgit From 0e42c81c7fd429529d89458349c7cdde254d5406 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 12 Oct 2024 08:07:05 +0800 Subject: fix(lua): avoid recursive vim.on_key() callback (#30753) --- src/nvim/lua/executor.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d4940f3add..9392765f40 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2065,6 +2065,13 @@ char *nlua_register_table_as_callable(const typval_T *const arg) void nlua_execute_on_key(int c, char *typed_buf) { + static bool recursive = false; + + if (recursive) { + return; + } + recursive = true; + char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); vim_unescape_ks(typed_buf); @@ -2103,6 +2110,8 @@ void nlua_execute_on_key(int c, char *typed_buf) // [ ] assert(top == lua_gettop(lstate)); #endif + + recursive = false; } // Sets the editor "script context" during Lua execution. Used by :verbose. -- cgit From 4b909528516032b002a4a32f3e06f0eb6185ea6b Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Fri, 11 Oct 2024 15:07:36 -0700 Subject: fix(treesitter): mark supertype nodes as named **Problem:** Tree-sitter 0.24.0 introduced a new symbol type to denote supertype nodes (`TSSymbolTypeSupertype`). Now, `language.inspect()` (and the query `omnifunc`) return supertype symbols, but with double quotes around them. **Solution:** Mark a symbol as "named" based on it *not* being an anonymous node, rather than checking that it is a regular node (which a supertype also is not). --- src/nvim/lua/treesitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 3ceb21b61a..1ebf835eb5 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -272,7 +272,7 @@ int tslua_inspect_lang(lua_State *L) continue; } const char *name = ts_language_symbol_name(lang, (TSSymbol)i); - bool named = t == TSSymbolTypeRegular; + bool named = t != TSSymbolTypeAnonymous; lua_pushboolean(L, named); // [retval, symbols, is_named] if (!named) { char buf[256]; -- cgit From e049c6e4c08a141c94218672e770f86f91c27a11 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sat, 12 Oct 2024 10:57:31 -0700 Subject: feat(ui): statusline text inherits highlights #29976 Changes apply to the winbar, statusline, and tabline text. --- src/nvim/statusline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 07bb7dd69a..6b8f5e27a3 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -430,7 +430,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) if (hltab[n].userhl == 0) { curattr = attr; } else if (hltab[n].userhl < 0) { - curattr = syn_id2attr(-hltab[n].userhl); + curattr = hl_combine_attr(attr, syn_id2attr(-hltab[n].userhl)); } else if (wp != NULL && wp != curwin && wp->w_status_height != 0) { curattr = highlight_stlnc[hltab[n].userhl - 1]; } else { -- cgit From b56aa80a264f64776bccd8757909cf7f220e6cb8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 13 Oct 2024 08:09:53 +0800 Subject: vim-patch:9.1.0775: tests: not enough tests for setting options (#30785) Problem: tests: not enough tests for setting options Solution: Add more comprehensive tests to test_options (Milly). closes: vim/vim#15856 https://github.com/vim/vim/commit/484facebe4a0fb775ad011a99ba007f55fc4f11a Restore behavior of &l:option for unset local boolean options that was accidentally changed in #26429. Co-authored-by: Milly --- src/nvim/eval/vars.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index a33636667e..d002bff321 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -1965,14 +1965,12 @@ typval_T optval_as_tv(OptVal value, bool numbool) case kOptValTypeNil: break; case kOptValTypeBoolean: - if (value.data.boolean != kNone) { - if (numbool) { - rettv.v_type = VAR_NUMBER; - rettv.vval.v_number = value.data.boolean == kTrue; - } else { - rettv.v_type = VAR_BOOL; - rettv.vval.v_bool = value.data.boolean == kTrue; - } + if (numbool) { + rettv.v_type = VAR_NUMBER; + rettv.vval.v_number = value.data.boolean; + } else if (value.data.boolean != kNone) { + rettv.v_type = VAR_BOOL; + rettv.vval.v_bool = value.data.boolean == kTrue; } break; // return v:null for None boolean value. case kOptValTypeNumber: -- cgit From 8c8c6fb05a993574abfa58784c62a1b983565785 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 13 Oct 2024 18:31:36 +0800 Subject: vim-patch:8.2.0985: simplify() does not remove slashes from "///path" Problem: Simplify() does not remove slashes from "///path". Solution: Reduce > 2 slashes to one. (closes vim/vim#6263) https://github.com/vim/vim/commit/fdcbe3c3fedf48a43b22938c9331addb2f1182f1 Omit Test_readdirex() change: changed again in patch 9.0.0323. Co-authored-by: Bram Moolenaar --- src/nvim/path.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/nvim/path.c b/src/nvim/path.c index 4c16adde4c..80890acb7d 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1538,6 +1538,13 @@ void simplify_filename(char *filename) } while (vim_ispathsep(*p)); } char *start = p; // remember start after "c:/" or "/" or "///" +#ifdef UNIX + // Posix says that "//path" is unchanged but "///path" is "/path". + if (start > filename + 2) { + STRMOVE(filename + 1, p); + start = p = filename + 1; + } +#endif do { // At this point "p" is pointing to the char following a single "/" -- cgit From 4846bf05dc639592c73135fb6f1a69f410c1c40f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 15 Oct 2024 07:34:13 +0800 Subject: fix(tui): avoid flushing buffer halfway an OSC 2 sequence (#30793) Problem: Setting title while TUI buffer is almost full may cause the end of a flush to be treated as a part of an OSC 2 or OSC 0 sequence, leading to problems like invisible cursor. Solution: Make the whole sequence to set title a unibi_ext string. --- src/nvim/tui/tui.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index fa50a8252d..2839a665da 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -134,11 +134,12 @@ struct TUIData { int resize_screen; int reset_scroll_region; int set_cursor_style, reset_cursor_style; - int save_title, restore_title; + int save_title, restore_title, set_title; int set_underline_style; int set_underline_color; int sync; } unibi_ext; + char *set_title; char *space_buf; size_t space_buf_len; bool stopped; @@ -536,6 +537,7 @@ static void terminfo_stop(TUIData *tui) abort(); } unibi_destroy(tui->ut); + XFREE_CLEAR(tui->set_title); } static void tui_terminal_start(TUIData *tui) @@ -1567,8 +1569,7 @@ void tui_suspend(TUIData *tui) void tui_set_title(TUIData *tui, String title) { - if (!(unibi_get_str(tui->ut, unibi_to_status_line) - && unibi_get_str(tui->ut, unibi_from_status_line))) { + if (!unibi_get_ext_str(tui->ut, (unsigned)tui->unibi_ext.set_title)) { return; } if (title.size > 0) { @@ -1577,9 +1578,9 @@ void tui_set_title(TUIData *tui, String title) unibi_out_ext(tui, tui->unibi_ext.save_title); tui->title_enabled = true; } - unibi_out(tui, unibi_to_status_line); - out(tui, title.data, title.size); - unibi_out(tui, unibi_from_status_line); + UNIBI_SET_NUM_VAR(tui->params[0], 0); + UNIBI_SET_STR_VAR(tui->params[1], title.data); + unibi_out_ext(tui, tui->unibi_ext.set_title); } else if (tui->title_enabled) { // Restore title/icon from the "stack". #4063 unibi_out_ext(tui, tui->unibi_ext.restore_title); @@ -1803,12 +1804,17 @@ static void unibi_goto(TUIData *tui, int row, int col) memset(&vars, 0, sizeof(vars)); \ tui->cork = true; \ retry: \ + /* Copy parameters on every retry, as unibi_format() may modify them. */ \ memcpy(params, tui->params, sizeof(params)); \ unibi_format(vars, vars + 26, str, params, out, tui, pad, tui); \ if (tui->overflow) { \ tui->bufpos = orig_pos; \ - flush_buf(tui); \ - goto retry; \ + /* If orig_pos is 0, there's nothing to flush and retrying won't work. */ \ + /* TODO(zeertzjq): should this situation still be handled? */ \ + if (orig_pos > 0) { \ + flush_buf(tui); \ + goto retry; \ + } \ } \ tui->cork = false; \ } \ @@ -1840,6 +1846,7 @@ static void out(void *ctx, const char *str, size_t len) } flush_buf(tui); } + // TODO(zeertzjq): handle string longer than buffer size? #30794 memcpy(tui->buf + tui->bufpos, str, len); tui->bufpos += len; @@ -2378,6 +2385,19 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in tui->unibi_ext.save_title = (int)unibi_add_ext_str(ut, "ext.save_title", "\x1b[22;0t"); tui->unibi_ext.restore_title = (int)unibi_add_ext_str(ut, "ext.restore_title", "\x1b[23;0t"); + const char *tsl = unibi_get_str(ut, unibi_to_status_line); + const char *fsl = unibi_get_str(ut, unibi_from_status_line); + if (tsl != NULL && fsl != NULL) { + // Add a single extended capability for the whole sequence to set title, + // as it is usually an OSC sequence that cannot be cut in half. + // Use %p2 for the title string, as to_status_line may take an argument. + size_t set_title_len = strlen(tsl) + strlen("%p2%s") + strlen(fsl); + char *set_title = xmallocz(set_title_len); + snprintf(set_title, set_title_len + 1, "%s%s%s", tsl, "%p2%s", fsl); + tui->unibi_ext.set_title = (int)unibi_add_ext_str(ut, "ext.set_title", set_title); + tui->set_title = set_title; + } + /// Terminals usually ignore unrecognized private modes, and there is no /// known ambiguity with these. So we just set them unconditionally. tui->unibi_ext.enable_lr_margin = -- cgit From 9701cbf036aecf18e7d88681040c07d61c314ca6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 15 Oct 2024 08:16:56 +0800 Subject: vim-patch:7b5e52d: runtime(doc): add preview flag to statusline example Problem: The standard statusline example is missing the preview flag "%w" Solution: Add the preview flag "%w" closes: vim/vim#15874 https://github.com/vim/vim/commit/7b5e52d16fb457c90cc44340a6190712aab7e03b Co-authored-by: saher --- src/nvim/options.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index f20933d172..8c6d7bd9cf 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -8356,7 +8356,7 @@ return { Examples: Emulate standard status line with 'ruler' set >vim - set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P + set statusline=%<%f\ %h%w%m%r%=%-14.(%l,%c%V%)\ %P < Similar, but add ASCII value of char under the cursor (like "ga") >vim set statusline=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P < Display byte count and byte value, modified flag in red. >vim -- cgit From dbd172e7e953bdab7132bd635532295a4dc64af9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 15 Oct 2024 08:20:09 +0800 Subject: vim-patch:5bcfb5a: runtime(doc): add some docs for file-watcher programs fixes: vim/vim#15733 https://github.com/vim/vim/commit/5bcfb5a30cfd8e8574061bdd82a192f47aae09b5 Co-authored-by: Christian Brabandt --- src/nvim/options.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 8c6d7bd9cf..3c3eaaf5a1 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -435,12 +435,13 @@ return { useful for example in source trees where all the files are symbolic or hard links and any changes should stay in the local source tree, not be propagated back to the original source. - *crontab* + *crontab* One situation where "no" and "auto" will cause problems: A program that opens a file, invokes Vim to edit that file, and then tests if the open file was changed (through the file descriptor) will check the backup file instead of the newly created file. "crontab -e" is an - example. + example, as are several |file-watcher| daemons like inotify. In that + case you probably want to switch this option. When a copy is made, the original file is truncated and then filled with the new text. This means that protection bits, owner and -- cgit From f25ebc229042d605cde1ba365883657fd0c0e693 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 15 Oct 2024 09:40:54 +0800 Subject: vim-patch:9.1.0783: 'spell' option setting has problems (#30818) Problem: 'spell' option setting has problems Solution: correctly check for comma for 'spellfile' option, remove unnecessary checks, refactor slightly (Milly) closes: vim/vim#15873 https://github.com/vim/vim/commit/322ad0c953b7a3023cd2a65db61d05e180a5d682 Co-authored-by: Milly --- src/nvim/option.c | 2 +- src/nvim/optionstr.c | 4 ++-- src/nvim/spell.c | 28 ++++++++++++---------------- 3 files changed, 15 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index f54da54a4b..0aa9cf4d93 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1705,7 +1705,7 @@ static void didset_options(void) spell_check_msm(); spell_check_sps(); compile_cap_prog(curwin->w_s); - did_set_spell_option(true); + did_set_spell_option(); // set cedit_key did_set_cedit(NULL); // initialize the table for 'breakat'. diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index c8f19d7ccf..1850b82209 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -2118,7 +2118,7 @@ const char *did_set_spellfile(optset_T *args) if ((!valid_spellfile(*varp))) { return e_invarg; } - return did_set_spell_option(true); + return did_set_spell_option(); } /// The 'spelllang' option is changed. @@ -2131,7 +2131,7 @@ const char *did_set_spelllang(optset_T *args) if (!valid_spelllang(*varp)) { return e_invarg; } - return did_set_spell_option(false); + return did_set_spell_option(); } /// The 'spelloptions' option is changed. diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 8ec28c7f61..a0fdd46b04 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -2091,7 +2091,7 @@ char *parse_spelllang(win_T *wp) int_wordlist_spl(spf_name); } else { // One entry in 'spellfile'. - copy_option_part(&spf, spf_name, MAXPATHL - 5, ","); + copy_option_part(&spf, spf_name, MAXPATHL - 4, ","); strcat(spf_name, ".spl"); int c; @@ -3664,30 +3664,26 @@ bool valid_spelllang(const char *val) bool valid_spellfile(const char *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - for (const char *s = val; *s != NUL; s++) { - if (!vim_is_fname_char((uint8_t)(*s))) { + char spf_name[MAXPATHL]; + char *spf = (char *)val; + while (*spf != NUL) { + size_t l = copy_option_part(&spf, spf_name, MAXPATHL, ","); + if (l >= MAXPATHL - 4 || l < 4 || strcmp(spf_name + l - 4, ".add") != 0) { return false; } + for (char *s = spf_name; *s != NUL; s++) { + if (!vim_is_fname_char((uint8_t)(*s))) { + return false; + } + } } return true; } -const char *did_set_spell_option(bool is_spellfile) +const char *did_set_spell_option(void) { const char *errmsg = NULL; - if (is_spellfile) { - int l = (int)strlen(curwin->w_s->b_p_spf); - if (l > 0 - && (l < 4 || strcmp(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) { - errmsg = e_invarg; - } - } - - if (errmsg != NULL) { - return errmsg; - } - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer == curbuf && wp->w_p_spell) { errmsg = parse_spelllang(wp); -- cgit From 84623dbe93777c0a8e7ddf57470ddeb2ea738069 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 15 Oct 2024 18:53:59 +0800 Subject: vim-patch:9.1.0785: cannot preserve error position when setting quickfix list (#30820) Problem: cannot preserve error position when setting quickfix lists Solution: Add the 'u' action for setqflist()/setloclist() and try to keep the closes target position (Jeremy Fleischman) fixes: vim/vim#15839 closes: vim/vim#15841 https://github.com/vim/vim/commit/27fbf6e5e8bee5c6b61819a5e82a0b50b265f0b0 Co-authored-by: Jeremy Fleischman --- src/nvim/eval.lua | 2 + src/nvim/quickfix.c | 130 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 113 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index a440450b9d..f0746e6159 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -9896,6 +9896,8 @@ M.funcs = { clear the list: >vim call setqflist([], 'r') < + 'u' Like 'r', but tries to preserve the current selection + in the quickfix list. 'f' All the quickfix lists in the quickfix stack are freed. diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index ddf2a7247f..5bd81ce469 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -6462,6 +6462,64 @@ static int qf_add_entry_from_dict(qf_list_T *qfl, dict_T *d, bool first_entry, b return status; } +/// Check if `entry` is closer to the target than `other_entry`. +/// +/// Only returns true if `entry` is definitively closer. If it's further +/// away, or there's not enough information to tell, return false. +static bool entry_is_closer_to_target(qfline_T *entry, qfline_T *other_entry, int target_fnum, + int target_lnum, int target_col) +{ + // First, compare entries to target file. + if (!target_fnum) { + // Without a target file, we can't know which is closer. + return false; + } + + bool is_target_file = entry->qf_fnum && entry->qf_fnum == target_fnum; + bool other_is_target_file = other_entry->qf_fnum && other_entry->qf_fnum == target_fnum; + if (!is_target_file && other_is_target_file) { + return false; + } else if (is_target_file && !other_is_target_file) { + return true; + } + + // Both entries are pointing at the exact same file. Now compare line numbers. + if (!target_lnum) { + // Without a target line number, we can't know which is closer. + return false; + } + + int line_distance = entry->qf_lnum + ? abs(entry->qf_lnum - target_lnum) : INT_MAX; + int other_line_distance = other_entry->qf_lnum + ? abs(other_entry->qf_lnum - target_lnum) : INT_MAX; + if (line_distance > other_line_distance) { + return false; + } else if (line_distance < other_line_distance) { + return true; + } + + // Both entries are pointing at the exact same line number (or no line + // number at all). Now compare columns. + if (!target_col) { + // Without a target column, we can't know which is closer. + return false; + } + + int column_distance = entry->qf_col + ? abs(entry->qf_col - target_col) : INT_MAX; + int other_column_distance = other_entry->qf_col + ? abs(other_entry->qf_col - target_col) : INT_MAX; + if (column_distance > other_column_distance) { + return false; + } else if (column_distance < other_column_distance) { + return true; + } + + // It's a complete tie! The exact same file, line, and column. + return false; +} + /// Add list of entries to quickfix/location list. Each list entry is /// a dictionary with item information. static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title, int action) @@ -6471,19 +6529,48 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title, int retval = OK; bool valid_entry = false; + // If there's an entry selected in the quickfix list, remember its location + // (file, line, column), so we can select the nearest entry in the updated + // quickfix list. + int prev_fnum = 0; + int prev_lnum = 0; + int prev_col = 0; + if (qfl->qf_ptr) { + prev_fnum = qfl->qf_ptr->qf_fnum; + prev_lnum = qfl->qf_ptr->qf_lnum; + prev_col = qfl->qf_ptr->qf_col; + } + + bool select_first_entry = false; + bool select_nearest_entry = false; + if (action == ' ' || qf_idx == qi->qf_listcount) { + select_first_entry = true; // make place for a new list qf_new_list(qi, title); qf_idx = qi->qf_curlist; qfl = qf_get_list(qi, qf_idx); - } else if (action == 'a' && !qf_list_empty(qfl)) { - // Adding to existing list, use last entry. - old_last = qfl->qf_last; + } else if (action == 'a') { + if (qf_list_empty(qfl)) { + // Appending to empty list, select first entry. + select_first_entry = true; + } else { + // Adding to existing list, use last entry. + old_last = qfl->qf_last; + } } else if (action == 'r') { + select_first_entry = true; + qf_free_items(qfl); + qf_store_title(qfl, title); + } else if (action == 'u') { + select_nearest_entry = true; qf_free_items(qfl); qf_store_title(qfl, title); } + qfline_T *entry_to_select = NULL; + int entry_to_select_index = 0; + TV_LIST_ITER_CONST(list, li, { if (TV_LIST_ITEM_TV(li)->v_type != VAR_DICT) { continue; // Skip non-dict items. @@ -6498,6 +6585,16 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title, if (retval == QF_FAIL) { break; } + + qfline_T *entry = qfl->qf_last; + if ((select_first_entry && entry_to_select == NULL) + || (select_nearest_entry + && (entry_to_select == NULL + || entry_is_closer_to_target(entry, entry_to_select, prev_fnum, + prev_lnum, prev_col)))) { + entry_to_select = entry; + entry_to_select_index = qfl->qf_count; + } }); // Check if any valid error entries are added to the list. @@ -6507,16 +6604,10 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title, qfl->qf_nonevalid = true; } - // If not appending to the list, set the current error to the first entry - if (action != 'a') { - qfl->qf_ptr = qfl->qf_start; - } - - // Update the current error index if not appending to the list or if the - // list was empty before and it is not empty now. - if ((action != 'a' || qfl->qf_index == 0) - && !qf_list_empty(qfl)) { - qfl->qf_index = 1; + // Set the current error. + if (entry_to_select) { + qfl->qf_ptr = entry_to_select; + qfl->qf_index = entry_to_select_index; } // Don't update the cursor in quickfix window when appending entries @@ -6632,7 +6723,7 @@ static int qf_setprop_items_from_lines(qf_info_T *qi, int qf_idx, const dict_T * return FAIL; } - if (action == 'r') { + if (action == 'r' || action == 'u') { qf_free_items(&qi->qf_lists[qf_idx]); } if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat, @@ -6789,10 +6880,11 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi) } } -// Populate the quickfix list with the items supplied in the list -// of dictionaries. "title" will be copied to w:quickfix_title -// "action" is 'a' for add, 'r' for replace. Otherwise create a new list. -// When "what" is not NULL then only set some properties. +/// Populate the quickfix list with the items supplied in the list +/// of dictionaries. "title" will be copied to w:quickfix_title +/// "action" is 'a' for add, 'r' for replace, 'u' for update. Otherwise +/// create a new list. +/// When "what" is not NULL then only set some properties. int set_errorlist(win_T *wp, list_T *list, int action, char *title, dict_T *what) { qf_info_T *qi = &ql_info; @@ -7433,7 +7525,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) return; } const char *const act = tv_get_string_chk(action_arg); - if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') + if ((*act == 'a' || *act == 'r' || *act == 'u' || *act == ' ' || *act == 'f') && act[1] == NUL) { action = *act; } else { -- cgit From 82b02ae2f2af439a8c678ed6b55a43121055f279 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 12 Oct 2024 11:23:31 +0200 Subject: fix(runtime): clean up one-off scripts Problem: Some runtime files no longer spark joy. Solution: Kondo the place up. Still sparks _some_ joy (moved to new `runtime/scripts` folder): * `macros/less.*` * `mswin.vim` * `tools/emoji_list.lua` No longer sparks joy (removed): * `macmap.vim` (gvimrc file; not useful in Nvim) * `tools/check_colors.vim` (no longer useful with new default colorscheme and treesitter) * `macros/editexisting.vim` (throws error on current Nvim) * `macros/justify.vim` (obsolete shim for `packadd! justify`) * `macros/matchit.vim` (same) * `macros/shellmenu.vim` (same) * `macros/swapmous.vim` (same) --- src/nvim/eval.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index f0746e6159..351b9f0510 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -9540,7 +9540,7 @@ M.funcs = { To clear the overrides pass an empty {list}: >vim call setcellwidths([]) - Date: Thu, 17 Oct 2024 07:48:42 +0800 Subject: vim-patch:6c2fc37: runtime(help): Update help syntax This commit makaes the following changes to the vim help syntax: - fix excessive URL detection in help, because `file:{filename}` in doc/options.txt is determined to be a URL. - update highlighting N for :resize in help - split Italian-specific syntax into separate help script - highlight `Note` in parentheses in help - update 'titlestring' behaviour in documentation for invalid '%' format closes: vim/vim#15883 https://github.com/vim/vim/commit/6c2fc377bfbfb6f1a46b1061413cd21116b596ed Co-authored-by: Milly --- src/nvim/eval.lua | 2 +- src/nvim/options.lua | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 351b9f0510..9572de471e 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -12768,7 +12768,7 @@ M.funcs = { For example to make work like in wildmode, use: >vim cnoremap wildmenumode() ? "\\" : "\" < - (Note, this needs the 'wildcharm' option set appropriately). + (Note: this needs the 'wildcharm' option set appropriately). ]=], name = 'wildmenumode', params = {}, diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 3c3eaaf5a1..fba5eab0bc 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -9130,7 +9130,9 @@ return { window. This happens only when the 'title' option is on. When this option contains printf-style '%' items, they will be - expanded according to the rules used for 'statusline'. + expanded according to the rules used for 'statusline'. If it contains + an invalid '%' format, the value is used as-is and no error or warning + will be given when the value is set. This option cannot be set in a modeline when 'modelineexpr' is off. Example: >vim -- cgit From 21151144c6ee0d38841aea78b2e0ecb8a0046429 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 16 Oct 2024 09:33:13 +0100 Subject: feat(meta): add type for quickfix entries --- src/nvim/eval.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 351b9f0510..34072cbb88 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -9955,7 +9955,11 @@ M.funcs = { ]=], name = 'setqflist', - params = { { 'list', 'any[]' }, { 'action', 'string' }, { 'what', 'table' } }, + params = { + { 'list', 'vim.quickfix.entry[]' }, + { 'action', 'string' }, + { 'what', 'vim.fn.setqflist.what' }, + }, signature = 'setqflist({list} [, {action} [, {what}]])', }, setreg = { -- cgit From 395f420fc65cb99f1c5cf17e230b962cb1e74bcd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 18 Oct 2024 22:39:27 +0800 Subject: fix(options): fix some 'belloff' flags not working properly (#30856) Problem: Some 'belloff' flags don't work properly. Solution: Keep BO_ flags and p_bo_values[] in sync. --- src/nvim/optionstr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 1850b82209..082073148e 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -72,8 +72,8 @@ static char *(p_ambw_values[]) = { "single", "double", NULL }; static char *(p_bg_values[]) = { "light", "dark", NULL }; static char *(p_bkc_values[]) = { "yes", "auto", "no", "breaksymlink", "breakhardlink", NULL }; static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete", "copy", "ctrlg", "error", - "esc", "ex", "hangul", "lang", "mess", "showmatch", "operator", - "register", "shell", "spell", "wildmode", NULL }; + "esc", "ex", "hangul", "insertmode", "lang", "mess", "showmatch", + "operator", "register", "shell", "spell", "wildmode", NULL }; // Note: Keep this in sync with briopt_check() static char *(p_briopt_values[]) = { "shift:", "min:", "sbr", "list:", "column:", NULL }; // Note: Keep this in sync with diffopt_changed() -- cgit From 3cf602486ce5cfaa50f33edbe179928f84527dc9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 20 Oct 2024 07:59:43 +0800 Subject: feat(terminal)!: make 'belloff' and 'visualbell' apply to terminal bell (#30859) vim-patch:8.2.4744: a terminal window can't use the bell vim-patch:8.2.4745: using wrong flag for using bell in the terminal BREAKING CHANGE: Bells from :terminal are now silent by default, unless 'belloff' option doesn't contain "term" or "all". --- src/nvim/option_vars.h | 3 ++- src/nvim/options.lua | 2 ++ src/nvim/optionstr.c | 3 ++- src/nvim/terminal.c | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index 8be437e477..bfdaa11ed9 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -403,7 +403,8 @@ EXTERN unsigned bo_flags; #define BO_REG 0x8000 #define BO_SH 0x10000 #define BO_SPELL 0x20000 -#define BO_WILD 0x40000 +#define BO_TERM 0x40000 +#define BO_WILD 0x80000 EXTERN char *p_bsk; ///< 'backupskip' EXTERN char *p_breakat; ///< 'breakat' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index fba5eab0bc..4e4de1ba31 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -598,6 +598,7 @@ return { separated list of items. For each item that is present, the bell will be silenced. This is most useful to specify specific events in insert mode to be silenced. + You can also make it flash by using 'visualbell'. item meaning when present ~ all All events. @@ -621,6 +622,7 @@ return { register Unknown register after in |Insert-mode|. shell Bell from shell output |:!|. spell Error happened on spell suggest. + term Bell from |:terminal| output. wildmode More matches in |cmdline-completion| available (depends on the 'wildmode' setting). diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 082073148e..8e488d2539 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -73,7 +73,8 @@ static char *(p_bg_values[]) = { "light", "dark", NULL }; static char *(p_bkc_values[]) = { "yes", "auto", "no", "breaksymlink", "breakhardlink", NULL }; static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete", "copy", "ctrlg", "error", "esc", "ex", "hangul", "insertmode", "lang", "mess", "showmatch", - "operator", "register", "shell", "spell", "wildmode", NULL }; + "operator", "register", "shell", "spell", "term", "wildmode", + NULL }; // Note: Keep this in sync with briopt_check() static char *(p_briopt_values[]) = { "shift:", "min:", "sbr", "list:", "column:", NULL }; // Note: Keep this in sync with diffopt_changed() diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index b916660024..f444021b90 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -1178,9 +1178,10 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data) return 1; } +/// Called when the terminal wants to ring the system bell. static int term_bell(void *data) { - ui_call_bell(); + vim_beep(BO_TERM); return 1; } -- cgit From 9b8907d90508d7b66f025bbd1f5a48a78c5ce035 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 20 Oct 2024 22:18:26 +0800 Subject: feat(float): allow enabling mouse for non-focusable window (#30844) Problem: Cannot allow mouse interaction for non-focusable float window. Solution: Add a "mouse" field to float window config. --- src/nvim/api/keysets_defs.h | 1 + src/nvim/api/ui_events.in.h | 2 +- src/nvim/api/win_config.c | 13 ++++++++++++- src/nvim/buffer_defs.h | 2 ++ src/nvim/grid_defs.h | 4 ++-- src/nvim/message.c | 2 +- src/nvim/mouse.c | 2 +- src/nvim/ui_compositor.c | 2 +- src/nvim/window.c | 5 +++-- src/nvim/winfloat.c | 1 + 10 files changed, 25 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index 552612dd13..96aabb851f 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -119,6 +119,7 @@ typedef struct { Array bufpos; Boolean external; Boolean focusable; + Boolean mouse; Boolean vertical; Integer zindex; Object border; diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 2bd8792d71..865e84ab91 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -102,7 +102,7 @@ void win_pos(Integer grid, Window win, Integer startrow, Integer startcol, Integ Integer height) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; void win_float_pos(Integer grid, Window win, String anchor, Integer anchor_grid, Float anchor_row, - Float anchor_col, Boolean focusable, Integer zindex) + Float anchor_col, Boolean mouse_enabled, Integer zindex) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; void win_external_pos(Integer grid, Window win) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index f63fdc5381..16811e0cd9 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -129,7 +129,12 @@ /// fractional. /// - focusable: Enable focus by user actions (wincmds, mouse events). /// Defaults to true. Non-focusable windows can be entered by -/// |nvim_set_current_win()|. +/// |nvim_set_current_win()|, or, when the `mouse` field is set to true, +/// by mouse events. +/// - mouse: Specify how this window interacts with mouse events. +/// Defaults to `focusable` value. +/// - If false, mouse events pass through this window. +/// - If true, mouse events interact with this window normally. /// - external: GUI should display the window as an external /// top-level window. Currently accepts no other positioning /// configuration together with this. @@ -714,6 +719,7 @@ Dict(win_config) nvim_win_get_config(Window window, Arena *arena, Error *err) PUT_KEY_X(rv, focusable, config->focusable); PUT_KEY_X(rv, external, config->external); PUT_KEY_X(rv, hide, config->hide); + PUT_KEY_X(rv, mouse, config->mouse); if (wp->w_floating) { PUT_KEY_X(rv, width, config->width); @@ -1202,6 +1208,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco if (HAS_KEY_X(config, focusable)) { fconfig->focusable = config->focusable; + fconfig->mouse = config->focusable; + } + + if (HAS_KEY_X(config, mouse)) { + fconfig->mouse = config->mouse; } if (HAS_KEY_X(config, zindex)) { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 6f059fc376..1fe5512708 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -938,6 +938,7 @@ typedef struct { FloatRelative relative; bool external; bool focusable; + bool mouse; WinSplit split; int zindex; WinStyle style; @@ -964,6 +965,7 @@ typedef struct { .row = 0, .col = 0, .anchor = 0, \ .relative = 0, .external = false, \ .focusable = true, \ + .mouse = true, \ .split = 0, \ .zindex = kZIndexFloatDefault, \ .style = kWinStyleUnused, \ diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h index ac67f42fe0..19a79ff810 100644 --- a/src/nvim/grid_defs.h +++ b/src/nvim/grid_defs.h @@ -80,8 +80,8 @@ struct ScreenGrid { // whether the compositor should blend the grid with the background grid bool blending; - // whether the grid can be focused with mouse clicks. - bool focusable; + // whether the grid interacts with mouse events. + bool mouse_enabled; // z-index: the order in the stack of grids. int zindex; diff --git a/src/nvim/message.c b/src/nvim/message.c index 79e6bc8be7..151fb3d903 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -199,7 +199,7 @@ void msg_grid_validate(void) ui_call_grid_resize(msg_grid.handle, msg_grid.cols, msg_grid.rows); msg_scrolled_at_flush = msg_scrolled; - msg_grid.focusable = false; + msg_grid.mouse_enabled = false; msg_grid_adj.target = &msg_grid; } else if (!should_alloc && msg_grid.chars) { ui_comp_remove_grid(&msg_grid); diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 884bc88d73..1289adfabb 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -1740,7 +1740,7 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp) } else if (*gridp > 1) { win_T *wp = get_win_by_grid_handle(*gridp); if (wp && wp->w_grid_alloc.chars - && !(wp->w_floating && !wp->w_config.focusable)) { + && !(wp->w_floating && !wp->w_config.mouse)) { *rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.rows - 1); *colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.cols - 1); return wp; diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index 6e89894e0b..e28e8d4da7 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -275,7 +275,7 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col) { for (ssize_t i = (ssize_t)kv_size(layers) - 1; i > 0; i--) { ScreenGrid *grid = kv_A(layers, i); - if (grid->focusable + if (grid->mouse_enabled && row >= grid->comp_row && row < grid->comp_row + grid->rows && col >= grid->comp_col && col < grid->comp_col + grid->cols) { return grid; diff --git a/src/nvim/window.c b/src/nvim/window.c index d3280a3478..91a69c3ec4 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -857,7 +857,7 @@ void ui_ext_win_position(win_T *wp, bool validate) String anchor = cstr_as_string(float_anchor_str[c.anchor]); if (!c.hide) { ui_call_win_float_pos(wp->w_grid_alloc.handle, wp->handle, anchor, - grid->handle, row, col, c.focusable, + grid->handle, row, col, c.mouse, wp->w_grid_alloc.zindex); } else { ui_call_win_hide(wp->w_grid_alloc.handle); @@ -889,7 +889,7 @@ void ui_ext_win_position(win_T *wp, bool validate) ui_comp_put_grid(&wp->w_grid_alloc, comp_row, comp_col, wp->w_height_outer, wp->w_width_outer, valid, false); ui_check_cursor_grid(wp->w_grid_alloc.handle); - wp->w_grid_alloc.focusable = wp->w_config.focusable; + wp->w_grid_alloc.mouse_enabled = wp->w_config.mouse; if (!valid) { wp->w_grid_alloc.valid = false; redraw_later(wp, UPD_NOT_VALID); @@ -4044,6 +4044,7 @@ void win_alloc_aucmd_win(int idx) fconfig.width = Columns; fconfig.height = 5; fconfig.focusable = false; + fconfig.mouse = false; aucmd_win[idx].auc_win = win_new_float(NULL, true, fconfig, &err); aucmd_win[idx].auc_win->w_buffer->b_nwindows--; RESET_BINDING(aucmd_win[idx].auc_win); diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index fdb65ad614..054ef07fc5 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -389,6 +389,7 @@ win_T *win_float_create(bool enter, bool new_buf) config.row = curwin->w_wrow; config.relative = kFloatRelativeEditor; config.focusable = false; + config.mouse = false; config.anchor = 0; // NW config.noautocmd = true; config.hide = true; -- cgit From 8c2d45be77299d6eb70165697bc5c29898cdb25e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 21 Oct 2024 07:22:42 +0800 Subject: fix(exit): close memfiles after processing events (#30872) Problem: When exiting, processed events may still use memfiles after they are closed. Solution: Close memfiles after processing events. --- src/nvim/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index b54b2a531a..436c3ccc7a 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -678,12 +678,14 @@ void os_exit(int r) } else { ui_flush(); ui_call_stop(); - ml_close_all(true); // remove all memfiles } if (!event_teardown() && r == 0) { r = 1; // Exit with error if main_loop did not teardown gracefully. } + if (!ui_client_channel_id) { + ml_close_all(true); // remove all memfiles + } if (used_stdin) { stream_set_blocking(STDIN_FILENO, true); // normalize stream (#2598) } -- cgit From c8e47f648052f8001d8a493cf7ca6c4867a36bc3 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 21 Oct 2024 11:36:02 +0100 Subject: fix(meta): do not use hyphens in param names Fixes #30882 --- src/nvim/eval.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index d60e9bd290..69f36796b9 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -326,17 +326,17 @@ M.funcs = { args = { 2, 3 }, base = 1, desc = [=[ - When the files {fname-one} and {fname-two} do not contain + When the files {fname_one} and {fname_two} do not contain exactly the same text an error message is added to |v:errors|. Also see |assert-return|. - When {fname-one} or {fname-two} does not exist the error will + When {fname_one} or {fname_two} does not exist the error will mention that. ]=], name = 'assert_equalfile', - params = { { 'fname-one', 'string' }, { 'fname-two', 'string' } }, + params = { { 'fname_one', 'string' }, { 'fname_two', 'string' } }, returns = '0|1', - signature = 'assert_equalfile({fname-one}, {fname-two})', + signature = 'assert_equalfile({fname_one}, {fname_two})', }, assert_exception = { args = { 1, 2 }, -- cgit From f663243e95f488b8f4224bdae2697ddac21d0ffb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 22 Oct 2024 09:05:14 +0800 Subject: vim-patch:9.1.0797: testing of options can be further improved (#30893) Problem: testing of options can be further improved Solution: split the generated option test into test_options_all.vim, add more test cases, save and restore values, fix use-after-free closes: vim/vim#15894 https://github.com/vim/vim/commit/6eca04e9f1d446dc509ba51e32da56fa413fe2f0 Co-authored-by: Milly --- src/nvim/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index 436c3ccc7a..695bd4c95a 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -777,7 +777,11 @@ void getout(int exitval) } } - if (p_shada && *p_shada != NUL) { + if ( +#ifdef EXITFREE + !entered_free_all_mem && +#endif + p_shada && *p_shada != NUL) { // Write out the registers, history, marks etc, to the ShaDa file shada_write_file(NULL, false); } -- cgit From 1b9dafa67ba98e360444832e1fddce1e96acc1d6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 22 Oct 2024 11:34:09 +0800 Subject: fix(options): fix :setglobal not working for 'spelloptions' (#30894) --- src/nvim/option.c | 1 + src/nvim/optionstr.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 0aa9cf4d93..2e6d317778 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5325,6 +5325,7 @@ void buf_copy_options(buf_T *buf, int flags) COPY_OPT_SCTX(buf, BV_SPL); buf->b_s.b_p_spo = xstrdup(p_spo); COPY_OPT_SCTX(buf, BV_SPO); + buf->b_s.b_p_spo_flags = spo_flags; buf->b_p_inde = xstrdup(p_inde); COPY_OPT_SCTX(buf, BV_INDE); buf->b_p_indk = xstrdup(p_indk); diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 8e488d2539..b560275de7 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -2116,7 +2116,7 @@ const char *did_set_spellfile(optset_T *args) // When there is a window for this buffer in which 'spell' // is set load the wordlists. - if ((!valid_spellfile(*varp))) { + if (!valid_spellfile(*varp)) { return e_invarg; } return did_set_spell_option(); @@ -2139,8 +2139,15 @@ const char *did_set_spelllang(optset_T *args) const char *did_set_spelloptions(optset_T *args) { win_T *win = (win_T *)args->os_win; - if (opt_strings_flags(win->w_s->b_p_spo, p_spo_values, &(win->w_s->b_p_spo_flags), - true) != OK) { + int opt_flags = args->os_flags; + const char *val = args->os_newval.string.data; + + if (!(opt_flags & OPT_LOCAL) + && opt_strings_flags(val, p_spo_values, &spo_flags, true) != OK) { + return e_invarg; + } + if (!(opt_flags & OPT_GLOBAL) + && opt_strings_flags(val, p_spo_values, &win->w_s->b_p_spo_flags, true) != OK) { return e_invarg; } return NULL; -- cgit From ca7855c5ba7025e512ffbbc060fcf928cc480c91 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 22 Oct 2024 13:03:02 +0800 Subject: vim-patch:9.1.0798: too many strlen() calls in cmdhist.c (#30895) Problem: too many strlen() calls in cmdhist.c Solution: refactor code and remove strlen() calls (John Marriott) closes: vim/vim#15888 https://github.com/vim/vim/commit/8df07d0ca310a55e1540f7d234b536abee49abd4 Co-authored-by: John Marriott --- src/nvim/cmdhist.c | 47 ++++++++++++++++++++--------------------------- src/nvim/cmdhist.h | 1 + src/nvim/ex_cmds.c | 2 +- src/nvim/ex_getln.c | 2 +- src/nvim/shada.c | 3 ++- 5 files changed, 25 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index 47a4ffba9e..fc3382f486 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -221,7 +221,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep) // well. char *p = history[type][i].hisstr; if (strcmp(str, p) == 0 - && (type != HIST_SEARCH || sep == p[strlen(p) + 1])) { + && (type != HIST_SEARCH || sep == p[history[type][i].hisstrlen + 1])) { if (!move_to_front) { return true; } @@ -239,6 +239,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep) AdditionalData *ad = history[type][i].additional_data; char *const save_hisstr = history[type][i].hisstr; + const size_t save_hisstrlen = history[type][i].hisstrlen; while (i != hisidx[type]) { if (++i >= hislen) { i = 0; @@ -249,6 +250,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep) xfree(ad); history[type][i].hisnum = ++hisnum[type]; history[type][i].hisstr = save_hisstr; + history[type][i].hisstrlen = save_hisstrlen; history[type][i].timestamp = os_time(); history[type][i].additional_data = NULL; return true; @@ -339,6 +341,7 @@ void add_to_history(int histype, const char *new_entry, size_t new_entrylen, boo hisptr->timestamp = os_time(); hisptr->additional_data = NULL; hisptr->hisstr[new_entrylen + 1] = (char)sep; + hisptr->hisstrlen = new_entrylen; hisptr->hisnum = ++hisnum[histype]; if (histype == HIST_SEARCH && in_map) { @@ -400,19 +403,6 @@ static int calc_hist_idx(int histype, int num) return -1; } -/// Get a history entry by its index. -/// -/// @param histype may be one of the HIST_ values. -static char *get_history_entry(int histype, int idx) -{ - idx = calc_hist_idx(histype, idx); - if (idx >= 0) { - return history[histype][idx].hisstr; - } else { - return ""; - } -} - /// Clear all entries in a history /// /// @param[in] histype One of the HIST_ values. @@ -575,10 +565,15 @@ void f_histget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (argvars[1].v_type == VAR_UNKNOWN) { idx = get_history_idx(type); } else { - idx = (int)tv_get_number_chk(&argvars[1], NULL); + idx = (int)tv_get_number_chk(&argvars[1], NULL); // -1 on type error + } + idx = calc_hist_idx(type, idx); + if (idx < 0) { + rettv->vval.v_string = xstrnsave("", 0); + } else { + rettv->vval.v_string = xstrnsave(history[type][idx].hisstr, + history[type][idx].hisstrlen); } - // -1 on type error - rettv->vval.v_string = xstrdup(get_history_entry(type, idx)); } rettv->v_type = VAR_STRING; } @@ -591,9 +586,10 @@ void f_histnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) ? HIST_INVALID : get_histtype(histname, strlen(histname), false); if (i != HIST_INVALID) { - i = get_history_idx(i); + rettv->vval.v_number = get_history_idx(i); + } else { + rettv->vval.v_number = HIST_INVALID; } - rettv->vval.v_number = i; } /// :history command - print a history @@ -642,10 +638,8 @@ void ex_history(exarg_T *eap) } for (; !got_int && histype1 <= histype2; histype1++) { - xstrlcpy(IObuff, "\n # ", IOSIZE); assert(history_names[histype1] != NULL); - xstrlcat(IObuff, history_names[histype1], IOSIZE); - xstrlcat(IObuff, " history", IOSIZE); + vim_snprintf(IObuff, IOSIZE, "\n # %s history", history_names[histype1]); msg_puts_title(IObuff); int idx = hisidx[histype1]; histentry_T *hist = history[histype1]; @@ -666,13 +660,12 @@ void ex_history(exarg_T *eap) && hist[i].hisnum >= j && hist[i].hisnum <= k && !message_filtered(hist[i].hisstr)) { msg_putchar('\n'); - snprintf(IObuff, IOSIZE, "%c%6d ", i == idx ? '>' : ' ', - hist[i].hisnum); + int len = snprintf(IObuff, IOSIZE, + "%c%6d ", i == idx ? '>' : ' ', hist[i].hisnum); if (vim_strsize(hist[i].hisstr) > Columns - 10) { - trunc_string(hist[i].hisstr, IObuff + strlen(IObuff), - Columns - 10, IOSIZE - (int)strlen(IObuff)); + trunc_string(hist[i].hisstr, IObuff + len, Columns - 10, IOSIZE - len); } else { - xstrlcat(IObuff, hist[i].hisstr, IOSIZE); + xstrlcpy(IObuff + len, hist[i].hisstr, (size_t)(IOSIZE - len)); } msg_outtrans(IObuff, 0); } diff --git a/src/nvim/cmdhist.h b/src/nvim/cmdhist.h index 4df4b09e68..c933982593 100644 --- a/src/nvim/cmdhist.h +++ b/src/nvim/cmdhist.h @@ -23,6 +23,7 @@ enum { HIST_COUNT = HIST_DEBUG + 1, }; ///< Number of history tables typedef struct { int hisnum; ///< Entry identifier number. char *hisstr; ///< Actual entry, separator char after the NUL. + size_t hisstrlen; ///< Length of hisstr (excluding the NUL). Timestamp timestamp; ///< Time when entry was added. AdditionalData *additional_data; ///< Additional entries from ShaDa file. } histentry_T; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index d48d25fc22..702dbeac27 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -4434,11 +4434,11 @@ void ex_global(exarg_T *eap) delim = *cmd; // get the delimiter cmd++; // skip delimiter if there is one pat = cmd; // remember start of pattern - patlen = strlen(pat); cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delim) { // end delimiter found *cmd++ = NUL; // replace it with a NUL } + patlen = strlen(pat); } char *used_pat; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index b58a6b16f1..389e935557 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1789,7 +1789,7 @@ static int command_line_browse_history(CommandLineState *s) plen = s->lookforlen; } else { p = get_histentry(s->histype)[s->hiscnt].hisstr; - plen = (int)strlen(p); + plen = (int)get_histentry(s->histype)[s->hiscnt].hisstrlen; } if (s->histype == HIST_SEARCH diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 27671771ec..11fe291559 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -658,7 +658,7 @@ static const void *shada_hist_iter(const void *const iter, const uint8_t history .histtype = history_type, .string = hist_he.hisstr, .sep = (char)(history_type == HIST_SEARCH - ? hist_he.hisstr[strlen(hist_he.hisstr) + 1] + ? hist_he.hisstr[hist_he.hisstrlen + 1] : 0), } }, @@ -784,6 +784,7 @@ static inline void hms_to_he_array(const HistoryMergerState *const hms_p, hist->timestamp = cur_entry->data.timestamp; hist->hisnum = (int)(hist - hist_array) + 1; hist->hisstr = cur_entry->data.data.history_item.string; + hist->hisstrlen = strlen(cur_entry->data.data.history_item.string); hist->additional_data = cur_entry->data.additional_data; hist++; }) -- cgit From 772614f9cc44bfd4914d27698509077e762873c0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 22 Oct 2024 15:23:34 +0800 Subject: refactor(eval): fix clear_evalarg() called with wrong argument (#30899) --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d2a3584353..93cff80bd4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1047,7 +1047,7 @@ char *eval_to_string_eap(char *arg, const bool join_list, exarg_T *eap, retval = typval2string(&tv, join_list); tv_clear(&tv); } - clear_evalarg(&EVALARG_EVALUATE, NULL); + clear_evalarg(&evalarg, NULL); return retval; } -- cgit From 8c532a9ea8a0bb2ee93d772c9589d1a84afeb541 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 22 Oct 2024 16:10:15 +0800 Subject: fix(options): fix 'winhl' still accepting invalid value (#30896) --- src/nvim/option.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 2e6d317778..89753f7cf8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1853,6 +1853,9 @@ bool parse_winhl_opt(win_T *wp) return false; } int hl_id_link = nlen ? syn_check_group(p, nlen) : 0; + if (hl_id_link == 0) { + return false; + } HlAttrs attrs = HLATTRS_INIT; attrs.rgb_ae_attr |= HL_GLOBAL; -- cgit From 4c25e60767508a3f8bc0631d280407a08f24a67e Mon Sep 17 00:00:00 2001 From: dundargoc Date: Wed, 25 Sep 2024 16:07:37 +0200 Subject: test: port libvterm unit test to neovim test suite These were imported from the v0.3.3 git tag https://github.com/neovim/libvterm/tree/v0.3.3 and not the latest commit. This is for compatibility reasons as the libvterm code was imported from v0.3.3. --- src/vterm/vterm.c | 509 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/vterm/vterm.h | 37 +++- 2 files changed, 544 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vterm/vterm.c b/src/vterm/vterm.c index 870a61566e..e8c87929e2 100644 --- a/src/vterm/vterm.c +++ b/src/vterm/vterm.c @@ -1,8 +1,9 @@ #include "vterm_internal.h" +#include "auto/config.h" +#include #include #include -#include #include /***************** @@ -429,3 +430,509 @@ void vterm_check_version(int major, int minor) // Happy } + +// For unit tests. +#ifndef NDEBUG + +int parser_text(const char bytes[], size_t len, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "text "); + int i; + for(i = 0; i < len; i++) { + unsigned char b = bytes[i]; + if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0)) { + break; + } + fprintf(f, i ? ",%x" : "%x", b); + } + fprintf(f, "\n"); + fclose(f); + + return i; +} + +static void printchars(const char *s, size_t len, FILE *f) +{ + while(len--) { + fprintf(f, "%c", (s++)[0]); + } +} + +int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "csi %02x", command); + + if(leader && leader[0]) { + fprintf(f, " L="); + for(int i = 0; leader[i]; i++) { + fprintf(f, "%02x", leader[i]); + } + } + + for(int i = 0; i < argcount; i++) { + char sep = i ? ',' : ' '; + + if(args[i] == CSI_ARG_MISSING) { + fprintf(f, "%c*", sep); + } else { + fprintf(f, "%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : ""); + } + } + + if(intermed && intermed[0]) { + fprintf(f, " I="); + for(int i = 0; intermed[i]; i++) { + fprintf(f, "%02x", intermed[i]); + } + } + + fprintf(f, "\n"); + + fclose(f); + + return 1; +} + +int parser_osc(int command, VTermStringFragment frag, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "osc "); + + if(frag.initial) { + if(command == -1) { + fprintf(f, "["); + } else { + fprintf(f, "[%d;", command); + } + } + + printchars(frag.str, frag.len, f); + + if(frag.final) { + fprintf(f, "]"); + } + + fprintf(f, "\n"); + fclose(f); + + return 1; +} + +int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "dcs "); + + if(frag.initial) { + fprintf(f, "["); + for(int i = 0; i < commandlen; i++) { + fprintf(f, "%c", command[i]); + } + } + + printchars(frag.str, frag.len,f); + + if(frag.final) { + fprintf(f, "]"); + } + + fprintf(f, "\n"); + fclose(f); + + return 1; +} + +int parser_apc(VTermStringFragment frag, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "apc "); + + if(frag.initial) { + fprintf(f, "["); + } + + printchars(frag.str, frag.len, f); + + if(frag.final) { + fprintf(f, "]"); + } + + fprintf(f, "\n"); + fclose(f); + + return 1; +} + +int parser_pm(VTermStringFragment frag, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "pm "); + + if(frag.initial) { + fprintf(f, "["); + } + + printchars(frag.str, frag.len,f); + + if(frag.final) { + fprintf(f, "]"); + } + + fprintf(f, "\n"); + fclose(f); + + return 1; +} + +int parser_sos(VTermStringFragment frag, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "sos "); + + if(frag.initial) { + fprintf(f, "["); + } + + printchars(frag.str, frag.len,f); + + if(frag.final) { + fprintf(f, "]"); + } + + fprintf(f, "\n"); + fclose(f); + + return 1; +} + +int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "selection-set mask=%04X ", mask); + if(frag.initial) { + fprintf(f, "["); +} + printchars(frag.str, frag.len, f); + if(frag.final) { + fprintf(f, "]"); +} + fprintf(f,"\n"); + + fclose(f); + return 1; +} + +int selection_query(VTermSelectionMask mask, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f,"selection-query mask=%04X\n", mask); + + fclose(f); + return 1; +} + +bool want_state_putglyph; +int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) +{ + if(!want_state_putglyph) { + return 1; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "putglyph "); + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { + fprintf(f, i ? ",%x" : "%x", info->chars[i]); + } + fprintf(f, " %d %d,%d", info->width, pos.row, pos.col); + if(info->protected_cell) { + fprintf(f, " prot"); + } + if(info->dwl) { + fprintf(f, " dwl"); + } + if(info->dhl) { + fprintf(f, " dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" ); + } + fprintf(f, "\n"); + + fclose(f); + + return 1; +} + +bool want_state_movecursor; +VTermPos state_pos; +int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + state_pos = pos; + + if(want_state_movecursor) { + fprintf(f,"movecursor %d,%d\n", pos.row, pos.col); + } + + fclose(f); + return 1; +} + +bool want_state_scrollrect; +int state_scrollrect(VTermRect rect, int downward, int rightward, void *user) +{ + if(!want_state_scrollrect) { + return 0; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + + fprintf(f,"scrollrect %d..%d,%d..%d => %+d,%+d\n", + rect.start_row, rect.end_row, rect.start_col, rect.end_col, + downward, rightward); + + fclose(f); + return 1; +} + +bool want_state_moverect; +int state_moverect(VTermRect dest, VTermRect src, void *user) +{ + if(!want_state_moverect) { + return 0; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f,"moverect %d..%d,%d..%d -> %d..%d,%d..%d\n", + src.start_row, src.end_row, src.start_col, src.end_col, + dest.start_row, dest.end_row, dest.start_col, dest.end_col); + + fclose(f); + return 1; +} + +void print_color(const VTermColor *col) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + if (VTERM_COLOR_IS_RGB(col)) { + fprintf(f,"rgb(%d,%d,%d", col->rgb.red, col->rgb.green, col->rgb.blue); + } + else if (VTERM_COLOR_IS_INDEXED(col)) { + fprintf(f,"idx(%d", col->indexed.idx); + } + else { + fprintf(f,"invalid(%d", col->type); + } + if (VTERM_COLOR_IS_DEFAULT_FG(col)) { + fprintf(f,",is_default_fg"); + } + if (VTERM_COLOR_IS_DEFAULT_BG(col)) { + fprintf(f,",is_default_bg"); + } + fprintf(f,")"); + fclose(f); +} + +bool want_state_settermprop; +int state_settermprop(VTermProp prop, VTermValue *val, void *user) +{ + if(!want_state_settermprop) { + return 1; + } + + int errcode = 0; + FILE *f = fopen(VTERM_TEST_FILE, "a"); + + VTermValueType type = vterm_get_prop_type(prop); + switch(type) { + case VTERM_VALUETYPE_BOOL: + fprintf(f,"settermprop %d %s\n", prop, val->boolean ? "true" : "false"); + errcode = 1; + goto end; + case VTERM_VALUETYPE_INT: + fprintf(f,"settermprop %d %d\n", prop, val->number); + errcode = 1; + goto end; + case VTERM_VALUETYPE_STRING: + fprintf(f,"settermprop %d %s\"%.*s\"%s\n", prop, + val->string.initial ? "[" : "", (int)val->string.len, val->string.str, val->string.final ? "]" : ""); + errcode=0; + goto end; + case VTERM_VALUETYPE_COLOR: + fprintf(f,"settermprop %d ", prop); + print_color(&val->color); + fprintf(f,"\n"); + errcode=1; + goto end; + case VTERM_N_VALUETYPES: + goto end; + } + +end: + fclose(f); + return errcode; +} + +bool want_state_erase; +int state_erase(VTermRect rect, int selective, void *user) +{ + if(!want_state_erase) { + return 1; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + + fprintf(f,"erase %d..%d,%d..%d%s\n", + rect.start_row, rect.end_row, rect.start_col, rect.end_col, + selective ? " selective" : ""); + + fclose(f); + return 1; +} + +struct { + int bold; + int underline; + int italic; + int blink; + int reverse; + int conceal; + int strike; + int font; + int small; + int baseline; + VTermColor foreground; + VTermColor background; +} state_pen; + +int state_setpenattr(VTermAttr attr, VTermValue *val, void *user) +{ + switch(attr) { + case VTERM_ATTR_BOLD: + state_pen.bold = val->boolean; + break; + case VTERM_ATTR_UNDERLINE: + state_pen.underline = val->number; + break; + case VTERM_ATTR_ITALIC: + state_pen.italic = val->boolean; + break; + case VTERM_ATTR_BLINK: + state_pen.blink = val->boolean; + break; + case VTERM_ATTR_REVERSE: + state_pen.reverse = val->boolean; + break; + case VTERM_ATTR_CONCEAL: + state_pen.conceal = val->boolean; + break; + case VTERM_ATTR_STRIKE: + state_pen.strike = val->boolean; + break; + case VTERM_ATTR_FONT: + state_pen.font = val->number; + break; + case VTERM_ATTR_SMALL: + state_pen.small = val->boolean; + break; + case VTERM_ATTR_BASELINE: + state_pen.baseline = val->number; + break; + case VTERM_ATTR_FOREGROUND: + state_pen.foreground = val->color; + break; + case VTERM_ATTR_BACKGROUND: + state_pen.background = val->color; + break; + + case VTERM_N_ATTRS: + return 0; + default: + break; + } + + return 1; +} + +bool want_state_scrollback; +int state_sb_clear(void *user) { + if(!want_state_scrollback) { + return 1; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f,"sb_clear\n"); + fclose(f); + + return 0; +} + +bool want_screen_scrollback; +int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user) +{ + if(!want_screen_scrollback) { + return 1; + } + + int eol = cols; + while(eol && !cells[eol-1].chars[0]) { + eol--; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "sb_pushline %d =", cols); + for(int c = 0; c < eol; c++) { + fprintf(f, " %02X", cells[c].chars[0]); + } + fprintf(f, "\n"); + + fclose(f); + + return 1; +} + +int screen_sb_popline(int cols, VTermScreenCell *cells, void *user) +{ + if(!want_screen_scrollback) { + return 0; + } + + // All lines of scrollback contain "ABCDE" + for(int col = 0; col < cols; col++) { + if(col < 5) { + cells[col].chars[0] = 'A' + col; + } else { + cells[col].chars[0] = 0; + } + + cells[col].width = 1; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f,"sb_popline %d\n", cols); + fclose(f); + return 1; +} + +int screen_sb_clear(void *user) +{ + if(!want_screen_scrollback) { + return 1; + } + + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "sb_clear\n"); + fclose(f); + return 0; +} + +void term_output(const char *s, size_t len, void *user) +{ + FILE *f = fopen(VTERM_TEST_FILE, "a"); + fprintf(f, "output "); + for(int i = 0; i < len; i++) { + fprintf(f, "%x%s", (unsigned char)s[i], i < len-1 ? "," : "\n"); + } + fclose(f); +} + +#endif diff --git a/src/vterm/vterm.h b/src/vterm/vterm.h index 929418c63a..df6878f744 100644 --- a/src/vterm/vterm.h +++ b/src/vterm/vterm.h @@ -9,6 +9,7 @@ extern "C" { #include #include +#include "nvim/macros_defs.h" #include "vterm_keycodes.h" #define VTERM_VERSION_MAJOR 0 @@ -21,7 +22,7 @@ extern "C" { /* Any cell can contain at most one basic printing character and 5 combining * characters. This number could be changed but will be ABI-incompatible if * you do */ -#define VTERM_MAX_CHARS_PER_CELL 6 +enum{ VTERM_MAX_CHARS_PER_CELL=6}; typedef struct VTerm VTerm; typedef struct VTermState VTermState; @@ -634,6 +635,40 @@ void vterm_copy_cells(VTermRect dest, void (*copycell)(VTermPos dest, VTermPos src, void *user), void *user); +#ifndef NDEBUG +int parser_text(const char bytes[], size_t len, void *user); +int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); +int parser_osc(int command, VTermStringFragment frag, void *user); +int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user); +int parser_apc(VTermStringFragment frag, void *user); +int parser_pm(VTermStringFragment frag, void *user); +int parser_sos(VTermStringFragment frag, void *user); +int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user); +int selection_query(VTermSelectionMask mask, void *user); +int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user); +int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user); +int state_scrollrect(VTermRect rect, int downward, int rightward, void *user); +int state_moverect(VTermRect dest, VTermRect src, void *user); +int state_settermprop(VTermProp prop, VTermValue *val, void *user); +int state_erase(VTermRect rect, int selective, void *user); +int state_setpenattr(VTermAttr attr, VTermValue *val, void *user); +int state_sb_clear(void *user); +void print_color(const VTermColor *col); +int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user); +int screen_sb_popline(int cols, VTermScreenCell *cells, void *user); +int screen_sb_clear(void *user); +void term_output(const char *s, size_t len, void *user); +EXTERN VTermPos state_pos; +EXTERN bool want_state_putglyph INIT (=false); +EXTERN bool want_state_movecursor INIT(= false); +EXTERN bool want_state_erase INIT(= false); +EXTERN bool want_state_scrollrect INIT(= false); +EXTERN bool want_state_moverect INIT(= false); +EXTERN bool want_state_settermprop INIT(= false); +EXTERN bool want_state_scrollback INIT(= false); +EXTERN bool want_screen_scrollback INIT(= false); +#endif + #ifdef __cplusplus } #endif -- cgit From 3a86b60032bd659c2b12e984abb40cee93568558 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 29 Sep 2024 14:07:21 +0200 Subject: docs: misc Co-authored-by: David Pedersen Co-authored-by: Gregory Anders Co-authored-by: Leo Schlosser Co-authored-by: zeertzjq --- src/nvim/eval.lua | 2 +- src/nvim/mbyte.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 69f36796b9..5125bd0b88 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -6406,7 +6406,7 @@ M.funcs = { base = 1, desc = [=[ {expr1} must be a |List|, |String|, |Blob| or |Dictionary|. - When {expr1} is a |List|| or |Dictionary|, replace each + When {expr1} is a |List| or |Dictionary|, replace each item in {expr1} with the result of evaluating {expr2}. For a |Blob| each byte is replaced. For a |String|, each character, including composing diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 01e720283e..6340ff8c94 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -454,9 +454,6 @@ static bool prop_is_emojilike(const utf8proc_property_t *prop) /// Is only correct for characters >= 0x80. /// When p_ambw is "double", return 2 for a character with East Asian Width /// class 'A'(mbiguous). -/// -/// @note Tables `doublewidth` and `ambiguous` are generated by -/// gen_unicode_tables.lua, which must be manually invoked as needed. int utf_char2cells(int c) { if (c < 0x80) { -- cgit From 230b0c7f021a57647a658edce27fe115343f083f Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Wed, 23 Oct 2024 14:33:57 +0100 Subject: feat(stdlib): overload vim.str_byteindex, vim.str_utfindex #30735 PROBLEM: There are several limitations to vim.str_byteindex, vim.str_utfindex: 1. They throw given out-of-range indexes. An invalid (often user/lsp-provided) index doesn't feel exceptional and should be handled by the caller. `:help dev-error-patterns` suggests that `retval, errmsg` is the preferred way to handle this kind of failure. 2. They cannot accept an encoding. So LSP needs wrapper functions. #25272 3. The current signatures are not extensible. * Calling: The function currently uses a fairly opaque boolean value to indicate to identify the encoding. * Returns: The fact it can throw requires wrapping in pcall. 4. The current name doesn't follow suggestions in `:h dev-naming` and I think `get` would be suitable. SOLUTION: - Because these are performance-sensitive, don't introduce `opts`. - Introduce an "overload" that accepts `encoding:string` and `strict_indexing:bool` params. ```lua local col = vim.str_utfindex(line, encoding, [index, [no_out_of_range]]) ``` Support the old versions by dispatching on the type of argument 2, and deprecate that form. ```lua vim.str_utfindex(line) -- (utf-32 length, utf-16 length), deprecated vim.str_utfindex(line, index) -- (utf-32 index, utf-16 index), deprecated vim.str_utfindex(line, 'utf-16') -- utf-16 length vim.str_utfindex(line, 'utf-16', index) -- utf-16 index vim.str_utfindex(line, 'utf-16', math.huge) -- error: index out of range vim.str_utfindex(line, 'utf-16', math.huge, false) -- utf-16 length ``` --- src/nvim/lua/stdlib.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index ee0eabbebb..bf8b085458 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -181,7 +181,9 @@ int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL } else { idx = luaL_checkinteger(lstate, 2); if (idx < 0 || idx > (intptr_t)s1_len) { - return luaL_error(lstate, "index out of range"); + lua_pushnil(lstate); + lua_pushnil(lstate); + return 2; } } @@ -272,7 +274,8 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL const char *s1 = luaL_checklstring(lstate, 1, &s1_len); intptr_t idx = luaL_checkinteger(lstate, 2); if (idx < 0) { - return luaL_error(lstate, "index out of range"); + lua_pushnil(lstate); + return 1; } bool use_utf16 = false; if (lua_gettop(lstate) >= 3) { @@ -281,7 +284,8 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL ssize_t byteidx = mb_utf_index_to_bytes(s1, s1_len, (size_t)idx, use_utf16); if (byteidx == -1) { - return luaL_error(lstate, "index out of range"); + lua_pushnil(lstate); + return 1; } lua_pushinteger(lstate, (lua_Integer)byteidx); @@ -695,10 +699,10 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) lua_setfield(lstate, -2, "stricmp"); // str_utfindex lua_pushcfunction(lstate, &nlua_str_utfindex); - lua_setfield(lstate, -2, "str_utfindex"); + lua_setfield(lstate, -2, "__str_utfindex"); // str_byteindex lua_pushcfunction(lstate, &nlua_str_byteindex); - lua_setfield(lstate, -2, "str_byteindex"); + lua_setfield(lstate, -2, "__str_byteindex"); // str_utf_pos lua_pushcfunction(lstate, &nlua_str_utf_pos); lua_setfield(lstate, -2, "str_utf_pos"); -- cgit From 6d2cf5ad3112d12b4b55df9df1e0921086b54fec Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Oct 2024 06:04:13 +0800 Subject: vim-patch:9.1.0802: tests: no error check when setting global 'fdm' to empty value Problem: tests: no error check when setting global 'fdm' to empty value Solution: Also check global 'fdm' value for being empty (Milly). closes: vim/vim#15916 https://github.com/vim/vim/commit/142cad1f88d1d3aa34b6050151e620b66185112e Co-authored-by: Milly --- src/nvim/optionstr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index b560275de7..c801ec0a26 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -1448,8 +1448,7 @@ const char *did_set_foldmethod(optset_T *args) { win_T *win = (win_T *)args->os_win; char **varp = (char **)args->os_varp; - if (check_opt_strings(*varp, p_fdm_values, false) != OK - || *win->w_p_fdm == NUL) { + if (check_opt_strings(*varp, p_fdm_values, false) != OK || **varp == NUL) { return e_invarg; } foldUpdateAll(win); -- cgit From 3d2aca83de7f57ad0ba1c67acb87e55876569d0a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Oct 2024 06:10:06 +0800 Subject: vim-patch:9.1.0803: tests: no error check when setting global 'isk' Problem: tests: no error check when setting global 'isk' Solution: also parse and check global 'isk' value (Milly) closes: vim/vim#15915 https://github.com/vim/vim/commit/5e7a6a4a106923e45c67dae6810e4c9753f88025 Co-authored-by: Milly --- src/nvim/charset.c | 196 ++++++++++++++++++++++++++++----------------------- src/nvim/options.lua | 2 +- src/nvim/optionstr.c | 18 ++++- 3 files changed, 124 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 430f6b15fe..1afd590b0e 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -88,13 +88,11 @@ int init_chartab(void) /// an error, OK otherwise. int buf_init_chartab(buf_T *buf, bool global) { - int c; - if (global) { // Set the default size for printable characters: // From to '~' is 1 (printable), others are 2 (not printable). // This also inits all 'isident' and 'isfname' flags to false. - c = 0; + int c = 0; while (c < ' ') { g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; @@ -124,9 +122,7 @@ int buf_init_chartab(buf_T *buf, bool global) SET_CHARTAB(buf, '-'); } - // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' - // options Each option is a list of characters, character numbers or - // ranges, separated by commas, e.g.: "200-210,x,#-178,-" + // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' options. for (int i = global ? 0 : 3; i <= 3; i++) { const char *p; if (i == 0) { @@ -142,110 +138,130 @@ int buf_init_chartab(buf_T *buf, bool global) // fourth round: 'iskeyword' p = buf->b_p_isk; } + if (parse_isopt(p, buf, false) == FAIL) { + return FAIL; + } + } - while (*p) { - bool tilde = false; - bool do_isalpha = false; + chartab_initialized = true; + return OK; +} - if ((*p == '^') && (p[1] != NUL)) { - tilde = true; - p++; - } +/// Checks the format for the option settings 'iskeyword', 'isident', 'isfname' +/// or 'isprint'. +/// Returns FAIL if has an error, OK otherwise. +int check_isopt(char *var) +{ + return parse_isopt(var, NULL, true); +} + +/// @param only_check if false: refill g_chartab[] +static int parse_isopt(const char *var, buf_T *buf, bool only_check) +{ + const char *p = var; + + // Parses the 'isident', 'iskeyword', 'isfname' and 'isprint' options. + // Each option is a list of characters, character numbers or ranges, + // separated by commas, e.g.: "200-210,x,#-178,-" + while (*p) { + bool tilde = false; + bool do_isalpha = false; + + if (*p == '^' && p[1] != NUL) { + tilde = true; + p++; + } + + int c; + if (ascii_isdigit(*p)) { + c = getdigits_int((char **)&p, true, 0); + } else { + c = mb_ptr2char_adv(&p); + } + int c2 = -1; + + if (*p == '-' && p[1] != NUL) { + p++; if (ascii_isdigit(*p)) { - c = getdigits_int((char **)&p, true, 0); + c2 = getdigits_int((char **)&p, true, 0); } else { - c = mb_ptr2char_adv(&p); + c2 = mb_ptr2char_adv(&p); } - int c2 = -1; + } - if ((*p == '-') && (p[1] != NUL)) { - p++; + if (c <= 0 || c >= 256 || (c2 < c && c2 != -1) || c2 >= 256 + || !(*p == NUL || *p == ',')) { + return FAIL; + } - if (ascii_isdigit(*p)) { - c2 = getdigits_int((char **)&p, true, 0); - } else { - c2 = mb_ptr2char_adv(&p); - } - } + bool trail_comma = *p == ','; + p = skip_to_option_part(p); + if (trail_comma && *p == NUL) { + // Trailing comma is not allowed. + return FAIL; + } - if ((c <= 0) - || (c >= 256) - || ((c2 < c) && (c2 != -1)) - || (c2 >= 256) - || !((*p == NUL) || (*p == ','))) { - return FAIL; - } + if (only_check) { + continue; + } - if (c2 == -1) { // not a range - // A single '@' (not "@-@"): - // Decide on letters being ID/printable/keyword chars with - // standard function isalpha(). This takes care of locale for - // single-byte characters). - if (c == '@') { - do_isalpha = true; - c = 1; - c2 = 255; - } else { - c2 = c; - } + if (c2 == -1) { // not a range + // A single '@' (not "@-@"): + // Decide on letters being ID/printable/keyword chars with + // standard function isalpha(). This takes care of locale for + // single-byte characters). + if (c == '@') { + do_isalpha = true; + c = 1; + c2 = 255; + } else { + c2 = c; } + } - while (c <= c2) { - // Use the MB_ functions here, because isalpha() doesn't - // work properly when 'encoding' is "latin1" and the locale is - // "C". - if (!do_isalpha - || mb_islower(c) - || mb_isupper(c)) { - if (i == 0) { - // (re)set ID flag - if (tilde) { - g_chartab[c] &= (uint8_t) ~CT_ID_CHAR; - } else { - g_chartab[c] |= CT_ID_CHAR; - } - } else if (i == 1) { - // (re)set printable - if (c < ' ' || c > '~') { - if (tilde) { - g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) - + ((dy_flags & DY_UHEX) ? 4 : 2)); - g_chartab[c] &= (uint8_t) ~CT_PRINT_CHAR; - } else { - g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1); - g_chartab[c] |= CT_PRINT_CHAR; - } - } - } else if (i == 2) { - // (re)set fname flag - if (tilde) { - g_chartab[c] &= (uint8_t) ~CT_FNAME_CHAR; - } else { - g_chartab[c] |= CT_FNAME_CHAR; - } - } else { // i == 3 - // (re)set keyword flag + while (c <= c2) { + // Use the MB_ functions here, because isalpha() doesn't + // work properly when 'encoding' is "latin1" and the locale is + // "C". + if (!do_isalpha + || mb_islower(c) + || mb_isupper(c)) { + if (var == p_isi) { // (re)set ID flag + if (tilde) { + g_chartab[c] &= (uint8_t) ~CT_ID_CHAR; + } else { + g_chartab[c] |= CT_ID_CHAR; + } + } else if (var == p_isp) { // (re)set printable + if (c < ' ' || c > '~') { if (tilde) { - RESET_CHARTAB(buf, c); + g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + + ((dy_flags & DY_UHEX) ? 4 : 2)); + g_chartab[c] &= (uint8_t) ~CT_PRINT_CHAR; } else { - SET_CHARTAB(buf, c); + g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1); + g_chartab[c] |= CT_PRINT_CHAR; } } + } else if (var == p_isf) { // (re)set fname flag + if (tilde) { + g_chartab[c] &= (uint8_t) ~CT_FNAME_CHAR; + } else { + g_chartab[c] |= CT_FNAME_CHAR; + } + } else { // (var == p_isk || var == buf->b_p_isk) (re)set keyword flag + if (tilde) { + RESET_CHARTAB(buf, c); + } else { + SET_CHARTAB(buf, c); + } } - c++; - } - - c = (uint8_t)(*p); - p = skip_to_option_part(p); - - if ((c == ',') && (*p == NUL)) { - // Trailing comma is not allowed. - return FAIL; } + c++; } } - chartab_initialized = true; + return OK; } diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 4e4de1ba31..734d9a4a02 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -4459,7 +4459,7 @@ return { { abbreviation = 'isk', alloced = true, - cb = 'did_set_isopt', + cb = 'did_set_iskeyword', defaults = { if_true = '@,48-57,_,192-255' }, deny_duplicates = true, desc = [=[ diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index c801ec0a26..f9be1be3d2 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -1572,12 +1572,28 @@ int expand_set_inccommand(optexpand_T *args, int *numMatches, char ***matches) matches); } +/// The 'iskeyword' option is changed. +const char *did_set_iskeyword(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + if (varp == &p_isk) { // only check for global-value + if (check_isopt(*varp) == FAIL) { + return e_invarg; + } + } else { // fallthrough for local-value + return did_set_isopt(args); + } + + return NULL; +} + /// The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is /// changed. const char *did_set_isopt(optset_T *args) { buf_T *buf = (buf_T *)args->os_buf; - // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] + // 'isident', 'iskeyword', 'isprint' or 'isfname' option: refill g_chartab[] // If the new option is invalid, use old value. // 'lisp' option: refill g_chartab[] for '-' char if (buf_init_chartab(buf, true) == FAIL) { -- cgit From 5436d9b3c6c537b243ea6af4f1acc143bf94de1c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Oct 2024 06:23:00 +0800 Subject: vim-patch:9.1.0804: tests: no error check when setting global 'cc' Problem: tests: no error check when setting global 'cc' Solution: also parse and check global 'cc' value (Milly) closes: vim/vim#15914 https://github.com/vim/vim/commit/a441a3eaabbfc14b4772e07ecbecaaff3bd06a58 Co-authored-by: Milly --- src/nvim/buffer.c | 6 +++--- src/nvim/option.c | 4 ++-- src/nvim/optionstr.c | 3 ++- src/nvim/window.c | 43 +++++++++++++++++++++++++++++++------------ 4 files changed, 38 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ce47705aa6..2142b5b298 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -255,7 +255,7 @@ int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) emsg(_("E83: Cannot allocate buffer, using other one...")); enter_buffer(curbuf); if (old_tw != curbuf->b_p_tw) { - check_colorcolumn(curwin); + check_colorcolumn(NULL, curwin); } return FAIL; } @@ -1029,7 +1029,7 @@ void handle_swap_exists(bufref_T *old_curbuf) enter_buffer(buf); if (old_tw != curbuf->b_p_tw) { - check_colorcolumn(curwin); + check_colorcolumn(NULL, curwin); } } // If "old_curbuf" is NULL we are in big trouble here... @@ -1669,7 +1669,7 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist) // enter some buffer. Using the last one is hopefully OK. enter_buffer(valid ? buf : lastbuf); if (old_tw != curbuf->b_p_tw) { - check_colorcolumn(curwin); + check_colorcolumn(NULL, curwin); } } diff --git a/src/nvim/option.c b/src/nvim/option.c index 89753f7cf8..8e6e068e96 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2592,7 +2592,7 @@ static const char *did_set_swapfile(optset_T *args) static const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED) { FOR_ALL_TAB_WINDOWS(tp, wp) { - check_colorcolumn(wp); + check_colorcolumn(NULL, wp); } return NULL; @@ -5111,7 +5111,7 @@ void didset_window_options(win_T *wp, bool valid_cursor) } else { wp->w_skipcol = 0; } - check_colorcolumn(wp); + check_colorcolumn(NULL, wp); briopt_check(wp); fill_culopt_flags(NULL, wp); set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0); diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index f9be1be3d2..0e63a8089d 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -898,7 +898,8 @@ int expand_set_clipboard(optexpand_T *args, int *numMatches, char ***matches) const char *did_set_colorcolumn(optset_T *args) { win_T *win = (win_T *)args->os_win; - return check_colorcolumn(win); + char **varp = (char **)args->os_varp; + return check_colorcolumn(*varp, varp == &win->w_p_cc ? win : NULL); } /// The 'comments' option is changed. diff --git a/src/nvim/window.c b/src/nvim/window.c index 91a69c3ec4..73d31d3048 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -7371,18 +7371,37 @@ static int int_cmp(const void *pa, const void *pb) return a == b ? 0 : a < b ? -1 : 1; } -/// Handle setting 'colorcolumn' or 'textwidth' in window "wp". +/// Check "cc" as 'colorcolumn' and update the members of "wp". +/// This is called when 'colorcolumn' or 'textwidth' is changed. +/// +/// @param cc when NULL: use "wp->w_p_cc" +/// @param wp when NULL: only parse "cc" /// /// @return error message, NULL if it's OK. -const char *check_colorcolumn(win_T *wp) +const char *check_colorcolumn(char *cc, win_T *wp) { - if (wp->w_buffer == NULL) { + if (wp != NULL && wp->w_buffer == NULL) { return NULL; // buffer was closed } + char *s; + if (cc != NULL) { + s = cc; + } else { + s = wp->w_p_cc; + } + + OptInt tw; + if (wp != NULL) { + tw = wp->w_buffer->b_p_tw; + } else { + // buffer-local value not set, assume zero + tw = 0; + } + unsigned count = 0; int color_cols[256]; - for (char *s = wp->w_p_cc; *s != NUL && count < 255;) { + while (*s != NUL && count < 255) { int col; if (*s == '-' || *s == '+') { // -N and +N: add to 'textwidth' @@ -7392,16 +7411,12 @@ const char *check_colorcolumn(win_T *wp) return e_invarg; } col = col * getdigits_int(&s, true, 0); - if (wp->w_buffer->b_p_tw == 0) { + if (tw == 0) { goto skip; // 'textwidth' not set, skip this item } - assert((col >= 0 - && wp->w_buffer->b_p_tw <= INT_MAX - col - && wp->w_buffer->b_p_tw + col >= INT_MIN) - || (col < 0 - && wp->w_buffer->b_p_tw >= INT_MIN - col - && wp->w_buffer->b_p_tw + col <= INT_MAX)); - col += (int)wp->w_buffer->b_p_tw; + assert((col >= 0 && tw <= INT_MAX - col && tw + col >= INT_MIN) + || (col < 0 && tw >= INT_MIN - col && tw + col <= INT_MAX)); + col += (int)tw; if (col < 0) { goto skip; } @@ -7423,6 +7438,10 @@ skip: } } + if (wp == NULL) { + return NULL; // only parse "cc" + } + xfree(wp->w_p_cc_cols); if (count == 0) { wp->w_p_cc_cols = NULL; -- cgit From 6b63fe798b7481edd8e3b0ed75a33bf297ca2856 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Oct 2024 06:31:09 +0800 Subject: vim-patch:9.1.0806: tests: no error check when setting global 'briopt' Problem: tests: no error check when setting global 'briopt' Solution: also parse and check global 'briopt' value (Milly) closes: vim/vim#15911 https://github.com/vim/vim/commit/b38700ac81d90a652e5c8495056dd78df5babdde Co-authored-by: Milly --- src/nvim/indent.c | 20 ++++++++++++++++++-- src/nvim/option.c | 2 +- src/nvim/optionstr.c | 7 +++++-- 3 files changed, 24 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/indent.c b/src/nvim/indent.c index b7e3842aad..58215f738c 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -769,9 +769,15 @@ int get_number_indent(linenr_T lnum) return (int)col; } +/// Check "briopt" as 'breakindentopt' and update the members of "wp". /// This is called when 'breakindentopt' is changed and when a window is /// initialized -bool briopt_check(win_T *wp) +/// +/// @param briopt when NULL: use "wp->w_p_briopt" +/// @param wp when NULL: only check "briopt" +/// +/// @return FAIL for failure, OK otherwise. +bool briopt_check(char *briopt, win_T *wp) { int bri_shift = 0; int bri_min = 20; @@ -779,7 +785,13 @@ bool briopt_check(win_T *wp) int bri_list = 0; int bri_vcol = 0; - char *p = wp->w_p_briopt; + char *p = empty_string_option; + if (briopt != NULL) { + p = briopt; + } else if (wp != NULL) { + p = wp->w_p_briopt; + } + while (*p != NUL) { // Note: Keep this in sync with p_briopt_values if (strncmp(p, "shift:", 6) == 0 @@ -807,6 +819,10 @@ bool briopt_check(win_T *wp) } } + if (wp == NULL) { + return OK; + } + wp->w_briopt_shift = bri_shift; wp->w_briopt_min = bri_min; wp->w_briopt_sbr = bri_sbr; diff --git a/src/nvim/option.c b/src/nvim/option.c index 8e6e068e96..933ee4ba75 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5112,7 +5112,7 @@ void didset_window_options(win_T *wp, bool valid_cursor) wp->w_skipcol = 0; } check_colorcolumn(NULL, wp); - briopt_check(wp); + briopt_check(NULL, wp); fill_culopt_flags(NULL, wp); set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0); set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0); diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 0e63a8089d..23b70ab5ad 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -717,11 +717,14 @@ const char *did_set_breakat(optset_T *args FUNC_ATTR_UNUSED) const char *did_set_breakindentopt(optset_T *args) { win_T *win = (win_T *)args->os_win; - if (briopt_check(win) == FAIL) { + char **varp = (char **)args->os_varp; + + if (briopt_check(*varp, varp == &win->w_p_briopt ? win : NULL) == FAIL) { return e_invarg; } + // list setting requires a redraw - if (win == curwin && win->w_briopt_list) { + if (varp == &win->w_p_briopt && win->w_briopt_list) { redraw_all_later(UPD_NOT_VALID); } -- cgit From a0ad35e3bbb3eac12dae031ea8bea00feb92a8ca Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Oct 2024 06:39:15 +0800 Subject: vim-patch:9.1.0812: Coverity warns about dereferencing NULL ptr Problem: Coverity warns about dereferencing NULL ptr in check_colorcolumn() Solution: verify that wp is not null before accessing it related: vim/vim#15914 https://github.com/vim/vim/commit/d0809869d6445faecd323fb33dc271d8c74a94fb Co-authored-by: Christian Brabandt --- src/nvim/window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/window.c b/src/nvim/window.c index 73d31d3048..5147bbd23b 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -7384,10 +7384,10 @@ const char *check_colorcolumn(char *cc, win_T *wp) return NULL; // buffer was closed } - char *s; + char *s = empty_string_option; if (cc != NULL) { s = cc; - } else { + } else if (wp != NULL) { s = wp->w_p_cc; } -- cgit From 50e63c8171d47157cfad5c1b8f1958a4a7e9d9c7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Oct 2024 10:03:38 +0800 Subject: fix(options): missing error check for global 'scl' and 'winhl' (#30919) --- src/nvim/option.c | 59 +++++++++++++++++++++++++++++++++------------------- src/nvim/optionstr.c | 25 ++++++++++++++++++---- src/nvim/winfloat.c | 2 +- 3 files changed, 60 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 933ee4ba75..5f0115b46c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1816,12 +1816,22 @@ void check_blending(win_T *wp) } /// Handle setting `winhighlight' in window "wp" -bool parse_winhl_opt(win_T *wp) +/// +/// @param winhl when NULL: use "wp->w_p_winhl" +/// @param wp when NULL: only parse "winhl" +/// +/// @return whether the option value is valid. +bool parse_winhl_opt(const char *winhl, win_T *wp) { - const char *p = wp->w_p_winhl; + const char *p = empty_string_option; + if (winhl != NULL) { + p = winhl; + } else if (wp != NULL) { + p = wp->w_p_winhl; + } if (!*p) { - if (wp->w_ns_hl_winhl && wp->w_ns_hl == wp->w_ns_hl_winhl) { + if (wp != NULL && wp->w_ns_hl_winhl && wp->w_ns_hl == wp->w_ns_hl_winhl) { wp->w_ns_hl = 0; wp->w_hl_needs_update = true; } @@ -1829,24 +1839,27 @@ bool parse_winhl_opt(win_T *wp) return true; } - if (wp->w_ns_hl_winhl == 0) { - wp->w_ns_hl_winhl = (int)nvim_create_namespace(NULL_STRING); - } else { - // namespace already exist. invalidate existing items - DecorProvider *dp = get_decor_provider(wp->w_ns_hl_winhl, true); - dp->hl_valid++; + int ns_hl = 0; + if (wp != NULL) { + if (wp->w_ns_hl_winhl == 0) { + wp->w_ns_hl_winhl = (int)nvim_create_namespace(NULL_STRING); + } else { + // Namespace already exists. Invalidate existing items. + DecorProvider *dp = get_decor_provider(wp->w_ns_hl_winhl, true); + dp->hl_valid++; + } + wp->w_ns_hl = wp->w_ns_hl_winhl; + ns_hl = wp->w_ns_hl; } - wp->w_ns_hl = wp->w_ns_hl_winhl; - int ns_hl = wp->w_ns_hl; while (*p) { - char *colon = strchr(p, ':'); + const char *colon = strchr(p, ':'); if (!colon) { return false; } size_t nlen = (size_t)(colon - p); - char *hi = colon + 1; - char *commap = xstrchrnul(hi, ','); + const char *hi = colon + 1; + const char *commap = xstrchrnul(hi, ','); size_t len = (size_t)(commap - hi); int hl_id = len ? syn_check_group(hi, len) : -1; if (hl_id == 0) { @@ -1857,14 +1870,18 @@ bool parse_winhl_opt(win_T *wp) return false; } - HlAttrs attrs = HLATTRS_INIT; - attrs.rgb_ae_attr |= HL_GLOBAL; - ns_hl_def(ns_hl, hl_id_link, attrs, hl_id, NULL); + if (wp != NULL) { + HlAttrs attrs = HLATTRS_INIT; + attrs.rgb_ae_attr |= HL_GLOBAL; + ns_hl_def(ns_hl, hl_id_link, attrs, hl_id, NULL); + } p = *commap ? commap + 1 : ""; } - wp->w_hl_needs_update = true; + if (wp != NULL) { + wp->w_hl_needs_update = true; + } return true; } @@ -2281,7 +2298,7 @@ static const char *did_set_number_relativenumber(optset_T *args) // When 'relativenumber'/'number' is changed and 'statuscolumn' is set, reset width. win->w_nrwidth_line_count = 0; } - check_signcolumn(win); + check_signcolumn(NULL, win); return NULL; } @@ -5116,10 +5133,10 @@ void didset_window_options(win_T *wp, bool valid_cursor) fill_culopt_flags(NULL, wp); set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0); set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0); - parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl + parse_winhl_opt(NULL, wp); // sets w_hl_needs_update also for w_p_winbl check_blending(wp); set_winbar_win(wp, false, valid_cursor); - check_signcolumn(wp); + check_signcolumn(NULL, wp); wp->w_grid_alloc.blending = wp->w_p_winbl > 0; } diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 23b70ab5ad..21a3a3877b 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -283,15 +283,27 @@ static bool valid_filetype(const char *val) /// Handle setting 'signcolumn' for value 'val'. Store minimum and maximum width. /// +/// @param wcl when NULL: use "wp->w_p_scl" +/// @param wp when NULL: only parse "scl" +/// /// @return OK when the value is valid, FAIL otherwise -int check_signcolumn(win_T *wp) +int check_signcolumn(char *scl, win_T *wp) { - char *val = wp->w_p_scl; + char *val = empty_string_option; + if (scl != NULL) { + val = scl; + } else if (wp != NULL) { + val = wp->w_p_scl; + } + if (*val == NUL) { return FAIL; } if (check_opt_strings(val, p_scl_values, false) == OK) { + if (wp == NULL) { + return OK; + } if (!strncmp(val, "no", 2)) { // no wp->w_minscwidth = wp->w_maxscwidth = SCL_NO; } else if (!strncmp(val, "nu", 2) && (wp->w_p_nu || wp->w_p_rnu)) { // number @@ -321,6 +333,9 @@ int check_signcolumn(win_T *wp) if (min < 1 || max < 2 || min > 8 || min >= max) { return FAIL; } + if (wp == NULL) { + return OK; + } wp->w_minscwidth = min; wp->w_maxscwidth = max; } @@ -2099,8 +2114,9 @@ int expand_set_showcmdloc(optexpand_T *args, int *numMatches, char ***matches) const char *did_set_signcolumn(optset_T *args) { win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; const char *oldval = args->os_oldval.string.data; - if (check_signcolumn(win) != OK) { + if (check_signcolumn(*varp, varp == &win->w_p_scl ? win : NULL) != OK) { return e_invarg; } // When changing the 'signcolumn' to or from 'number', recompute the @@ -2568,7 +2584,8 @@ const char *did_set_winbar(optset_T *args) const char *did_set_winhighlight(optset_T *args) { win_T *win = (win_T *)args->os_win; - if (!parse_winhl_opt(win)) { + char **varp = (char **)args->os_varp; + if (!parse_winhl_opt(*varp, varp == &win->w_p_winhl ? win : NULL)) { return e_invarg; } return NULL; diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 054ef07fc5..4698487708 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -137,7 +137,7 @@ void win_set_minimal_style(win_T *wp) ? xstrdup("EndOfBuffer:") : concat_str(old, ",EndOfBuffer:")); free_string_option(old); - parse_winhl_opt(wp); + parse_winhl_opt(NULL, wp); // signcolumn: use 'auto' if (wp->w_p_scl[0] != 'a' || strlen(wp->w_p_scl) >= 8) { -- cgit From e4a74e986c40ca60ad49ea89020d6a9be36e928b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 25 Oct 2024 07:16:54 +0800 Subject: vim-patch:9.1.0814: mapset() may remove unrelated mapping (#30941) Problem: mapset() may remove unrelated mapping whose {rhs} matches the restored mapping's {lhs}. Solution: only match by {lhs} when unmapping for mapset() (zeertzjq). closes: vim/vim#15935 https://github.com/vim/vim/commit/fdf135a0525746cc0ff85bed2fbbde320ddb6d0d --- src/nvim/mapping.c | 20 ++++++++++++++------ src/nvim/mapping.h | 7 ++++--- 2 files changed, 18 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index e055ebc2fa..23efd2a841 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -568,6 +568,12 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, mapblock_T **abbr_table = args->buffer ? &buf->b_first_abbr : &first_abbr; mapblock_T *mp_result[2] = { NULL, NULL }; + bool unmap_lhs_only = false; + if (maptype == MAPTYPE_UNMAP_LHS) { + unmap_lhs_only = true; + maptype = MAPTYPE_UNMAP; + } + // For ":noremap" don't remap, otherwise do remap. int noremap = args->script ? REMAP_SCRIPT : maptype == MAPTYPE_NOREMAP ? REMAP_NONE : REMAP_YES; @@ -720,8 +726,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, // entry with a matching 'to' part. This was done to allow ":ab foo bar" // to be unmapped by typing ":unab foo", where "foo" will be replaced by // "bar" because of the abbreviation. - for (int round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1 - && !did_it && !got_int; round++) { + const int num_rounds = maptype == MAPTYPE_UNMAP && !unmap_lhs_only ? 2 : 1; + for (int round = 0; round < num_rounds && !did_it && !got_int; round++) { int hash_start, hash_end; if ((round == 0 && has_lhs) || is_abbrev) { // just use one hash @@ -935,9 +941,11 @@ theend: /// for :cabbr mode is MODE_CMDLINE /// ``` /// -/// @param maptype MAPTYPE_MAP for |:map| -/// MAPTYPE_UNMAP for |:unmap| -/// MAPTYPE_NOREMAP for |:noremap|. +/// @param maptype MAPTYPE_MAP for |:map| or |:abbr| +/// MAPTYPE_UNMAP for |:unmap| or |:unabbr| +/// MAPTYPE_NOREMAP for |:noremap| or |:noreabbr| +/// MAPTYPE_UNMAP_LHS is like MAPTYPE_UNMAP, but doesn't try to match +/// with {rhs} if there is no match with {lhs}. /// @param arg C-string containing the arguments of the map/abbrev /// command, i.e. everything except the initial `:[X][nore]map`. /// - Cannot be a read-only string; it will be modified. @@ -2348,7 +2356,7 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) MapArguments unmap_args = MAP_ARGUMENTS_INIT; set_maparg_lhs_rhs(lhs, strlen(lhs), "", 0, LUA_NOREF, p_cpo, &unmap_args); unmap_args.buffer = buffer; - buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, is_abbr, curbuf); + buf_do_map(MAPTYPE_UNMAP_LHS, &unmap_args, mode, is_abbr, curbuf); xfree(unmap_args.rhs); xfree(unmap_args.orig_rhs); diff --git a/src/nvim/mapping.h b/src/nvim/mapping.h index b82117ea86..fc120b683c 100644 --- a/src/nvim/mapping.h +++ b/src/nvim/mapping.h @@ -19,9 +19,10 @@ /// Used for the first argument of do_map() enum { - MAPTYPE_MAP = 0, - MAPTYPE_UNMAP = 1, - MAPTYPE_NOREMAP = 2, + MAPTYPE_MAP = 0, + MAPTYPE_UNMAP = 1, + MAPTYPE_NOREMAP = 2, + MAPTYPE_UNMAP_LHS = 3, }; /// Adjust chars in a language according to 'langmap' option. -- cgit From b922b7d6d7889cce863540df7b0da7d512f8a2a1 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Fri, 25 Oct 2024 20:10:40 +0600 Subject: refactor(options)!: use OptVal for option defaults #26691 Problem: We use `void *` for option default values, which is confusing and can cause problems with type-correctness. It also doesn't accomodate for multitype options. On top of that, it also leads to default boolean option values not behaving correctly on big endian systems. Solution: Use `OptVal` for option default values. BREAKING CHANGE: - `:set {option}<` removes the local value for all global-local options instead of just string global-local options. - `:setlocal {option}<` copies the global value to the local value for number and boolean global-local options instead of removing the local value. --- src/nvim/generators/gen_options.lua | 71 ++++-- src/nvim/option.c | 424 ++++++++++++++++-------------------- src/nvim/option.h | 8 +- src/nvim/options.lua | 58 +++-- 4 files changed, 264 insertions(+), 297 deletions(-) (limited to 'src') diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 591a6b93df..24121d7938 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -90,6 +90,12 @@ local function get_flags(o) return flags end +--- @param opt_type vim.option_type +--- @return string +local function opt_type_enum(opt_type) + return ('kOptValType%s'):format(lowercase_to_titlecase(opt_type)) +end + --- @param o vim.option_meta --- @return string local function get_type_flags(o) @@ -99,7 +105,7 @@ local function get_type_flags(o) for _, opt_type in ipairs(opt_types) do assert(type(opt_type) == 'string') - type_flags = ('%s | (1 << kOptValType%s)'):format(type_flags, lowercase_to_titlecase(opt_type)) + type_flags = ('%s | (1 << %s)'):format(type_flags, opt_type_enum(opt_type)) end return type_flags @@ -125,27 +131,48 @@ local function get_cond(c, base_string) return cond_string end +--- @param s string +--- @return string +local static_cstr_as_string = function(s) + return ('{ .data = %s, .size = sizeof(%s) - 1 }'):format(s, s) +end + +--- @param v vim.option_value|function +--- @return string +local get_opt_val = function(v) + --- @type vim.option_type + local v_type + + if type(v) == 'function' then + v, v_type = v() --[[ @as string, vim.option_type ]] + + if v_type == 'string' then + v = static_cstr_as_string(v) + end + else + v_type = type(v) --[[ @as vim.option_type ]] + + if v_type == 'boolean' then + v = v and 'true' or 'false' + elseif v_type == 'number' then + v = ('%iL'):format(v) + elseif v_type == 'string' then + v = static_cstr_as_string(cstr(v)) + end + end + + return ('{ .type = %s, .data.%s = %s }'):format(opt_type_enum(v_type), v_type, v) +end + +--- @param d vim.option_value|function +--- @param n string +--- @return string + local get_defaults = function(d, n) if d == nil then error("option '" .. n .. "' should have a default value") end - - local value_dumpers = { - ['function'] = function(v) - return v() - end, - string = function(v) - return '.string=' .. cstr(v) - end, - boolean = function(v) - return '.boolean=' .. (v and 'true' or 'false') - end, - number = function(v) - return ('.number=%iL'):format(v) - end, - } - - return value_dumpers[type(d)](d) + return get_opt_val(d) end --- @type [string,string][] @@ -173,7 +200,7 @@ local function dump_option(i, o) w(' .var=&' .. o.varname) elseif o.hidden or o.immutable then -- Hidden and immutable options can directly point to the default value. - w((' .var=&options[%u].def_val'):format(i - 1)) + w((' .var=&options[%u].def_val.data'):format(i - 1)) elseif #o.scope == 1 and o.scope[1] == 'window' then w(' .var=VAR_WIN') else @@ -219,14 +246,16 @@ local function dump_option(i, o) if o.defaults.condition then w(get_cond(o.defaults.condition)) end - w(' .def_val' .. get_defaults(o.defaults.if_true, o.full_name)) + w(' .def_val=' .. get_defaults(o.defaults.if_true, o.full_name)) if o.defaults.condition then if o.defaults.if_false then w('#else') - w(' .def_val' .. get_defaults(o.defaults.if_false, o.full_name)) + w(' .def_val=' .. get_defaults(o.defaults.if_false, o.full_name)) end w('#endif') end + else + w(' .def_val=NIL_OPTVAL') end w(' },') end diff --git a/src/nvim/option.c b/src/nvim/option.c index 5f0115b46c..a237689eb0 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -176,7 +176,7 @@ static int p_paste_dep_opts[] = { void set_init_tablocal(void) { // susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal! - p_ch = options[kOptCmdheight].def_val.number; + p_ch = options[kOptCmdheight].def_val.data.number; } /// Initialize the 'shell' option to a default value. @@ -291,8 +291,9 @@ static void set_init_default_cdpath(void) } } buf[j] = NUL; - options[kOptCdpath].def_val.string = buf; + options[kOptCdpath].def_val = CSTR_AS_OPTVAL(buf); options[kOptCdpath].flags |= P_DEF_ALLOCED; + xfree(cdpath); } @@ -317,12 +318,13 @@ static void set_init_expand_env(void) p = option_expand(opt_idx, NULL); } if (p != NULL) { - p = xstrdup(p); - *(char **)opt->var = p; + set_option_varp(opt_idx, opt->var, CSTR_TO_OPTVAL(p), opt->flags & P_ALLOCED); + opt->flags |= P_ALLOCED; + if (opt->flags & P_DEF_ALLOCED) { - xfree(opt->def_val.string); + optval_free(opt->def_val); } - opt->def_val.string = p; + opt->def_val = CSTR_TO_OPTVAL(p); opt->flags |= P_DEF_ALLOCED; } } @@ -430,71 +432,54 @@ void set_init_1(bool clean_arg) set_helplang_default(get_mess_lang()); } -/// Set an option to its default value. -/// This does not take care of side effects! +/// Get default value for option, based on the option's type and scope. /// -/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL. +/// @param opt_idx Option index in options[] table. +/// @param opt_flags Option flags. /// -/// TODO(famiu): Refactor this when def_val uses OptVal. -static void set_option_default(const OptIndex opt_idx, int opt_flags) +/// @return Default value of option for the scope specified in opt_flags. +static OptVal get_option_default(const OptIndex opt_idx, int opt_flags) { - bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; - - // pointer to variable for current option vimoption_T *opt = &options[opt_idx]; - void *varp = get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); - uint32_t flags = opt->flags; - if (varp != NULL) { // skip hidden option, nothing to do for it - if (option_has_type(opt_idx, kOptValTypeString)) { - // Use set_option_direct() for local options to handle freeing and allocating the value. - if (opt->indir != PV_NONE) { - set_option_direct(opt_idx, CSTR_AS_OPTVAL(opt->def_val.string), opt_flags, 0); - } else { - if (flags & P_ALLOCED) { - free_string_option(*(char **)(varp)); - } - *(char **)varp = opt->def_val.string; - opt->flags &= ~P_ALLOCED; - } - } else if (option_has_type(opt_idx, kOptValTypeNumber)) { - if (opt->indir == PV_SCROLL) { - win_comp_scroll(curwin); - } else { - OptInt def_val = opt->def_val.number; - if ((OptInt *)varp == &curwin->w_p_so - || (OptInt *)varp == &curwin->w_p_siso) { - // 'scrolloff' and 'sidescrolloff' local values have a - // different default value than the global default. - *(OptInt *)varp = -1; - } else { - *(OptInt *)varp = def_val; - } - // May also set global value for local option. - if (both) { - *(OptInt *)get_varp_scope(opt, OPT_GLOBAL) = def_val; - } - } - } else { // boolean - *(int *)varp = opt->def_val.boolean; + bool is_global_local_option = opt->indir & PV_BOTH; + #ifdef UNIX - // 'modeline' defaults to off for root - if (opt->indir == PV_ML && getuid() == ROOT_UID) { - *(int *)varp = false; - } + if (opt_idx == kOptModeline && getuid() == ROOT_UID) { + // 'modeline' defaults to off for root. + return BOOLEAN_OPTVAL(false); + } #endif - // May also set global value for local option. - if (both) { - *(int *)get_varp_scope(opt, OPT_GLOBAL) = - *(int *)varp; - } - } - // The default value is not insecure. - uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags); - *flagsp = *flagsp & ~P_INSECURE; + if ((opt_flags & OPT_LOCAL) && is_global_local_option) { + // Use unset local value instead of default value for local scope of global-local options. + return get_option_unset_value(opt_idx); + } else if (option_has_type(opt_idx, kOptValTypeString) && !(opt->flags & P_NO_DEF_EXP)) { + // For string options, expand environment variables and ~ since the default value was already + // expanded, only required when an environment variable was set later. + char *s = option_expand(opt_idx, opt->def_val.data.string.data); + return s == NULL ? opt->def_val : CSTR_AS_OPTVAL(s); + } else { + return opt->def_val; + } +} + +/// Set an option to its default value. +/// This does not take care of side effects! +/// +/// @param opt_idx Option index in options[] table. +/// @param opt_flags Option flags. +static void set_option_default(const OptIndex opt_idx, int opt_flags) +{ + OptVal def_val = get_option_default(opt_idx, opt_flags); + set_option_direct(opt_idx, def_val, opt_flags, current_sctx.sc_sid); + + if (opt_idx == kOptScroll) { + win_comp_scroll(curwin); } - set_option_sctx(opt_idx, opt_flags, current_sctx); + // The default value is not insecure. + uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags); + *flagsp = *flagsp & ~P_INSECURE; } /// Set all options (except terminal options) to their default value. @@ -522,6 +507,8 @@ static void set_options_default(int opt_flags) /// @param opt_idx Option index in options[] table. /// @param val The value of the option. /// @param allocated If true, do not copy default as it was already allocated. +/// +/// TODO(famiu): Remove this. static void set_string_default(OptIndex opt_idx, char *val, bool allocated) FUNC_ATTR_NONNULL_ALL { @@ -531,10 +518,10 @@ static void set_string_default(OptIndex opt_idx, char *val, bool allocated) vimoption_T *opt = &options[opt_idx]; if (opt->flags & P_DEF_ALLOCED) { - xfree(opt->def_val.string); + optval_free(opt->def_val); } - opt->def_val.string = allocated ? val : xstrdup(val); + opt->def_val = CSTR_AS_OPTVAL(allocated ? val : xstrdup(val)); opt->flags |= P_DEF_ALLOCED; } @@ -569,15 +556,6 @@ static char *find_dup_item(char *origval, const char *newval, const size_t newva return NULL; } -/// Set the Vi-default value of a number option. -/// Used for 'lines' and 'columns'. -void set_number_default(OptIndex opt_idx, OptInt val) -{ - if (opt_idx != kOptInvalid) { - options[opt_idx].def_val.number = val; - } -} - #if defined(EXITFREE) /// Free all options. void free_all_options(void) @@ -589,7 +567,7 @@ void free_all_options(void) optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } if (options[opt_idx].flags & P_DEF_ALLOCED) { - optval_free(optval_from_varp(opt_idx, &options[opt_idx].def_val)); + optval_free(options[opt_idx].def_val); } } else if (options[opt_idx].var != VAR_WIN) { // buffer-local option: free global value @@ -622,7 +600,7 @@ void set_init_2(bool headless) if (!option_was_set(kOptWindow)) { p_window = Rows - 1; } - set_number_default(kOptWindow, Rows - 1); + options[kOptWindow].def_val = NUMBER_OPTVAL(Rows - 1); } /// Initialize the options, part three: After reading the .vimrc @@ -640,43 +618,29 @@ void set_init_3(void) char *p = (char *)invocation_path_tail(p_sh, &len); p = xmemdupz(p, len); - { - // - // Default for p_sp is "| tee", for p_srr is ">". - // For known shells it is changed here to include stderr. - // - if (path_fnamecmp(p, "csh") == 0 - || path_fnamecmp(p, "tcsh") == 0) { - if (do_sp) { - p_sp = "|& tee"; - options[kOptShellpipe].def_val.string = p_sp; - } - if (do_srr) { - p_srr = ">&"; - options[kOptShellredir].def_val.string = p_srr; - } - } else if (path_fnamecmp(p, "sh") == 0 - || path_fnamecmp(p, "ksh") == 0 - || path_fnamecmp(p, "mksh") == 0 - || path_fnamecmp(p, "pdksh") == 0 - || path_fnamecmp(p, "zsh") == 0 - || path_fnamecmp(p, "zsh-beta") == 0 - || path_fnamecmp(p, "bash") == 0 - || path_fnamecmp(p, "fish") == 0 - || path_fnamecmp(p, "ash") == 0 - || path_fnamecmp(p, "dash") == 0) { - // Always use POSIX shell style redirection if we reach this - if (do_sp) { - p_sp = "2>&1| tee"; - options[kOptShellpipe].def_val.string = p_sp; - } - if (do_srr) { - p_srr = ">%s 2>&1"; - options[kOptShellredir].def_val.string = p_srr; - } + bool is_csh = path_fnamecmp(p, "csh") == 0 || path_fnamecmp(p, "tcsh") == 0; + bool is_known_shell = path_fnamecmp(p, "sh") == 0 || path_fnamecmp(p, "ksh") == 0 + || path_fnamecmp(p, "mksh") == 0 || path_fnamecmp(p, "pdksh") == 0 + || path_fnamecmp(p, "zsh") == 0 || path_fnamecmp(p, "zsh-beta") == 0 + || path_fnamecmp(p, "bash") == 0 || path_fnamecmp(p, "fish") == 0 + || path_fnamecmp(p, "ash") == 0 || path_fnamecmp(p, "dash") == 0; + + // Default for p_sp is "| tee", for p_srr is ">". + // For known shells it is changed here to include stderr. + if (is_csh || is_known_shell) { + if (do_sp) { + const OptVal sp = + is_csh ? STATIC_CSTR_AS_OPTVAL("|& tee") : STATIC_CSTR_AS_OPTVAL("2>&1| tee"); + set_option_direct(kOptShellpipe, sp, 0, SID_NONE); + options[kOptShellpipe].def_val = sp; + } + if (do_srr) { + const OptVal srr = is_csh ? STATIC_CSTR_AS_OPTVAL(">&") : STATIC_CSTR_AS_OPTVAL(">%s 2>&1"); + set_option_direct(kOptShellredir, srr, 0, SID_NONE); + options[kOptShellredir].def_val = srr; } - xfree(p); } + xfree(p); if (buf_is_empty(curbuf)) { int idx_ffs = find_option("ffs"); @@ -734,12 +698,12 @@ void set_title_defaults(void) // icon name. Saves a bit of time, because the X11 display server does // not need to be contacted. if (!(options[kOptTitle].flags & P_WAS_SET)) { - options[kOptTitle].def_val.boolean = false; - p_title = false; + options[kOptTitle].def_val = BOOLEAN_OPTVAL(false); + p_title = 0; } if (!(options[kOptIcon].flags & P_WAS_SET)) { - options[kOptIcon].def_val.boolean = false; - p_icon = false; + options[kOptIcon].def_val = BOOLEAN_OPTVAL(false); + p_icon = 0; } } @@ -758,27 +722,6 @@ void ex_set(exarg_T *eap) do_set(eap->arg, flags); } -/// Get the default value for a string option. -static char *stropt_get_default_val(OptIndex opt_idx, uint64_t flags) -{ - char *newval = options[opt_idx].def_val.string; - // expand environment variables and ~ since the default value was - // already expanded, only required when an environment variable was set - // later - if (newval == NULL) { - newval = empty_string_option; - } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) { - char *s = option_expand(opt_idx, newval); - if (s == NULL) { - s = newval; - } - newval = xstrdup(s); - } else { - newval = xstrdup(newval); - } - return newval; -} - /// Copy the new string value into allocated memory for the option. /// Can't use set_option_direct(), because we need to remove the backslashes. static char *stropt_copy_value(char *origval, char **argp, set_op_T op, @@ -922,10 +865,7 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags) } } -/// Get the string value specified for a ":set" command. The following set -/// options are supported: -/// set {opt}& -/// set {opt}< +/// Get the string value specified for a ":set" command. The following set options are supported: /// set {opt}={val} /// set {opt}:{val} static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void *varp, @@ -936,61 +876,56 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void char *save_arg = NULL; char *newval; char *s = NULL; - if (nextchar == '&') { // set to default val - newval = stropt_get_default_val(opt_idx, flags); - } else if (nextchar == '<') { // set to global val - newval = xstrdup(*(char **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL)); - } else { - arg++; // jump to after the '=' or ':' - // Set 'keywordprg' to ":help" if an empty - // value was passed to :set by the user. - if (varp == &p_kp && (*arg == NUL || *arg == ' ')) { - save_arg = arg; - arg = ":help"; - } + arg++; // jump to after the '=' or ':' - // Copy the new string into allocated memory. - newval = stropt_copy_value(origval, &arg, op, flags); + // Set 'keywordprg' to ":help" if an empty + // value was passed to :set by the user. + if (varp == &p_kp && (*arg == NUL || *arg == ' ')) { + save_arg = arg; + arg = ":help"; + } - // Expand environment variables and ~. - // Don't do it when adding without inserting a comma. - if (op == OP_NONE || (flags & P_COMMA)) { - newval = stropt_expand_envvar(opt_idx, origval, newval, op); - } + // Copy the new string into allocated memory. + newval = stropt_copy_value(origval, &arg, op, flags); - // locate newval[] in origval[] when removing it - // and when adding to avoid duplicates - int len = 0; - if (op == OP_REMOVING || (flags & P_NODUP)) { - len = (int)strlen(newval); - s = find_dup_item(origval, newval, (size_t)len, flags); + // Expand environment variables and ~. + // Don't do it when adding without inserting a comma. + if (op == OP_NONE || (flags & P_COMMA)) { + newval = stropt_expand_envvar(opt_idx, origval, newval, op); + } - // do not add if already there - if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) { - op = OP_NONE; - STRCPY(newval, origval); - } + // locate newval[] in origval[] when removing it + // and when adding to avoid duplicates + int len = 0; + if (op == OP_REMOVING || (flags & P_NODUP)) { + len = (int)strlen(newval); + s = find_dup_item(origval, newval, (size_t)len, flags); - // if no duplicate, move pointer to end of original value - if (s == NULL) { - s = origval + (int)strlen(origval); - } + // do not add if already there + if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) { + op = OP_NONE; + STRCPY(newval, origval); } - // concatenate the two strings; add a ',' if needed - if (op == OP_ADDING || op == OP_PREPENDING) { - stropt_concat_with_comma(origval, newval, op, flags); - } else if (op == OP_REMOVING) { - // Remove newval[] from origval[]. (Note: "len" has been set above - // and is used here). - stropt_remove_val(origval, newval, flags, s, len); + // if no duplicate, move pointer to end of original value + if (s == NULL) { + s = origval + (int)strlen(origval); } + } - if (flags & P_FLAGLIST) { - // Remove flags that appear twice. - stropt_remove_dupflags(newval, flags); - } + // concatenate the two strings; add a ',' if needed + if (op == OP_ADDING || op == OP_PREPENDING) { + stropt_concat_with_comma(origval, newval, op, flags); + } else if (op == OP_REMOVING) { + // Remove newval[] from origval[]. (Note: "len" has been set above + // and is used here). + stropt_remove_val(origval, newval, flags, s, len); + } + + if (flags & P_FLAGLIST) { + // Remove flags that appear twice. + stropt_remove_dupflags(newval, flags); } if (save_arg != NULL) { @@ -1152,6 +1087,7 @@ const char *find_option_end(const char *arg, OptIndex *opt_idxp) } /// Get new option value from argp. Allocated OptVal must be freed by caller. +/// Can unset local value of an option when ":set {option}<" is used. static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T prefix, char **argp, int nextchar, set_op_T op, uint32_t flags, void *varp, char *errbuf, const size_t errbuflen, const char **errmsg) @@ -1166,6 +1102,20 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr OptVal oldval = optval_from_varp(opt_idx, oldval_is_global ? get_varp(opt) : varp); OptVal newval = NIL_OPTVAL; + if (nextchar == '&') { + // ":set opt&": Reset to default value. + // NOTE: Use OPT_GLOBAL instead of opt_flags to ensure we don't use the unset local value for + // global-local options when OPT_LOCAL is used. + return optval_copy(get_option_default(opt_idx, OPT_GLOBAL)); + } else if (nextchar == '<') { + // ":set opt<": Reset to global value. + // ":setlocal opt<": Copy global value to local value. + if (option_is_global_local(opt_idx) && !(opt_flags & OPT_LOCAL)) { + unset_option_local_value(opt_idx); + } + return get_option_value(opt_idx, OPT_GLOBAL); + } + switch (oldval.type) { case kOptValTypeNil: abort(); @@ -1173,8 +1123,6 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr TriState newval_bool; // ":set opt!": invert - // ":set opt&": reset to default value - // ":set opt<": reset to global value if (nextchar == '!') { switch (oldval.data.boolean) { case kNone: @@ -1187,15 +1135,6 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr newval_bool = kTrue; break; } - } else if (nextchar == '&') { - newval_bool = TRISTATE_FROM_INT(options[opt_idx].def_val.boolean); - } else if (nextchar == '<') { - // For 'autoread', kNone means to use global value. - if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL) { - newval_bool = kNone; - } else { - newval_bool = TRISTATE_FROM_INT(*(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL)); - } } else { // ":set invopt": invert // ":set opt" or ":set noopt": set or reset @@ -1214,31 +1153,15 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr OptInt newval_num; // Different ways to set a number option: - // & set to default value - // < set to global value // accept special key codes for 'wildchar' or 'wildcharm' // ^x accept ctrl key codes for 'wildchar' or 'wildcharm' // c accept any non-digit for 'wildchar' or 'wildcharm' // [-]0-9 set number // other error arg++; - if (nextchar == '&') { - newval_num = options[opt_idx].def_val.number; - } else if (nextchar == '<') { - if ((OptInt *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) { - // for 'undolevels' NO_LOCAL_UNDOLEVEL means using the global newval_num - newval_num = NO_LOCAL_UNDOLEVEL; - } else if (opt_flags == OPT_LOCAL - && ((OptInt *)varp == &curwin->w_p_siso || (OptInt *)varp == &curwin->w_p_so)) { - // for 'scrolloff'/'sidescrolloff' -1 means using the global newval_num - newval_num = -1; - } else { - newval_num = *(OptInt *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); - } - } else if (((OptInt *)varp == &p_wc || (OptInt *)varp == &p_wcm) - && (*arg == '<' || *arg == '^' - || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) - && !ascii_isdigit(*arg)))) { + if (((OptInt *)varp == &p_wc || (OptInt *)varp == &p_wcm) + && (*arg == '<' || *arg == '^' + || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) && !ascii_isdigit(*arg)))) { newval_num = string_to_key(arg); if (newval_num == 0) { *errmsg = e_invarg; @@ -3218,6 +3141,19 @@ bool optval_equal(OptVal o1, OptVal o2) UNREACHABLE; } +/// Get type of option. Does not support multitype options. +static OptValType option_get_type(const OptIndex opt_idx) +{ + assert(!option_is_multitype(opt_idx)); + + // If the option only supports a single type, it means that the index of the option's type flag + // corresponds to the value of the type enum. So get the index of the type flag using xctz() and + // use that as the option's type. + OptValType type = xctz(options[opt_idx].type_flags); + assert(type > kOptValTypeNil && type < kOptValTypeSize); + return type; +} + /// Create OptVal from var pointer. /// /// @param opt_idx Option index in options[] table. @@ -3237,11 +3173,7 @@ OptVal optval_from_varp(OptIndex opt_idx, void *varp) return varp == NULL ? NIL_OPTVAL : *(OptVal *)varp; } - // If the option only supports a single type, it means that the index of the option's type flag - // corresponds to the value of the type enum. So get the index of the type flag using xctz() and - // use that as the option's type. - OptValType type = xctz(options[opt_idx].type_flags); - assert(type > kOptValTypeNil && type < kOptValTypeSize); + OptValType type = option_get_type(opt_idx); switch (type) { case kOptValTypeNil: @@ -3390,6 +3322,11 @@ bool is_option_hidden(OptIndex opt_idx) return opt_idx == kOptInvalid ? false : get_varp(&options[opt_idx]) == NULL; } +static inline bool option_is_global_local(OptIndex opt_idx) +{ + return opt_idx == kOptInvalid ? false : (options[opt_idx].indir & PV_BOTH); +} + /// Get option flags. /// /// @param opt_idx Option index in options[] table. @@ -3588,10 +3525,9 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value opt->flags |= P_ALLOCED; const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; - const bool opt_is_global_local = opt->indir & PV_BOTH; if (scope_both) { - if (opt_is_global_local) { + if (option_is_global_local(opt_idx)) { // Global option with local value set to use global value. // Free the local value and clear it. void *varp_local = get_varp_scope(opt, OPT_LOCAL); @@ -3678,7 +3614,6 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt if (opt_flags == OPT_GLOBAL) { errmsg = _("Cannot unset global option value"); } else { - optval_free(*newval); *newval = optval_copy(get_option_unset_value(opt_idx)); } } else if (!option_has_type(opt_idx, newval->type)) { @@ -3719,25 +3654,28 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, { assert(opt_idx != kOptInvalid); - const char *errmsg = validate_option_value(opt_idx, varp, &value, opt_flags, errbuf, errbuflen); + const char *errmsg = NULL; - if (errmsg != NULL) { - optval_free(value); - return errmsg; + if (!direct) { + errmsg = validate_option_value(opt_idx, varp, &value, opt_flags, errbuf, errbuflen); + + if (errmsg != NULL) { + optval_free(value); + return errmsg; + } } vimoption_T *opt = &options[opt_idx]; const bool scope_local = opt_flags & OPT_LOCAL; const bool scope_global = opt_flags & OPT_GLOBAL; const bool scope_both = !scope_local && !scope_global; - const bool opt_is_global_local = opt->indir & PV_BOTH; // Whether local value of global-local option is unset. - // NOTE: When this is true, it also implies that opt_is_global_local is true. + // NOTE: When this is true, it also implies that the option is global-local. const bool is_opt_local_unset = is_option_local_value_unset(opt_idx); // When using ":set opt=val" for a global option with a local value the local value will be reset, // use the global value here. - if (scope_both && opt_is_global_local) { + if (scope_both && option_is_global_local(opt_idx)) { varp = opt->var; } @@ -3823,8 +3761,10 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; void *varp = get_varp_scope(opt, scope_both ? OPT_LOCAL : opt_flags); - set_option(opt_idx, varp, optval_copy(value), opt_flags, set_sid, true, true, errbuf, - sizeof(errbuf)); + const char *errmsg = set_option(opt_idx, varp, optval_copy(value), opt_flags, set_sid, true, true, + errbuf, sizeof(errbuf)); + assert(errmsg == NULL); + (void)errmsg; // ignore unused warning } /// Set option value directly for buffer / window, without processing any side effects. @@ -3893,6 +3833,17 @@ const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt sizeof(errbuf)); } +/// Unset the local value of a global-local option. +/// +/// @param opt_idx Index in options[] table. Must not be kOptInvalid. +/// +/// @return NULL on success, an untranslated error message on error. +static inline const char *unset_option_local_value(const OptIndex opt_idx) +{ + assert(option_is_global_local(opt_idx)); + return set_option_value(opt_idx, get_option_unset_value(opt_idx), OPT_LOCAL); +} + /// Set the value of an option. Supports TTY options, unlike set_option_value(). /// /// @param name Option name. Used for error messages and for setting TTY options. @@ -4273,7 +4224,7 @@ static int optval_default(OptIndex opt_idx, void *varp) } OptVal current_val = optval_from_varp(opt_idx, varp); - OptVal default_val = optval_from_varp(opt_idx, &opt->def_val); + OptVal default_val = opt->def_val; return optval_equal(current_val, default_val); } @@ -5447,7 +5398,7 @@ void reset_modifiable(void) { curbuf->b_p_ma = false; p_ma = false; - options[kOptModifiable].def_val.boolean = false; + options[kOptModifiable].def_val = BOOLEAN_OPTVAL(false); } /// Set the global value for 'iminsert' to the local value. @@ -6537,11 +6488,8 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w PUT_C(dict, "last_set_linenr", INTEGER_OBJ(last_set.script_ctx.sc_lnum)); PUT_C(dict, "last_set_chan", INTEGER_OBJ((int64_t)last_set.channel_id)); - // TODO(bfredl): do you even nocp? - OptVal def = optval_from_varp(get_opt_idx(opt), &opt->def_val); - - PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(def.type))); - PUT_C(dict, "default", optval_as_object(def)); + PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(option_get_type(get_opt_idx(opt))))); + PUT_C(dict, "default", optval_as_object(opt->def_val)); PUT_C(dict, "allows_duplicates", BOOLEAN_OBJ(!(opt->flags & P_NODUP))); return dict; diff --git a/src/nvim/option.h b/src/nvim/option.h index 19764c0121..9b74429467 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -60,13 +60,7 @@ typedef struct { /// cmdline. Only useful for string options. opt_expand_cb_T opt_expand_cb; - // TODO(famiu): Use OptVal for def_val. - union { - int boolean; - OptInt number; - char *string; - } def_val; ///< default value for variable - + OptVal def_val; ///< default value LastSet last_set; ///< script in which the option was last set } vimoption_T; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 734d9a4a02..d49621490c 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -8,8 +8,7 @@ --- @field short_desc? string|fun(): string --- @field varname? string --- @field pv_name? string ---- @field type 'boolean'|'number'|'string' ---- @field hidden? boolean +--- @field type vim.option_type|vim.option_type[] --- @field immutable? boolean --- @field list? 'comma'|'onecomma'|'commacolon'|'onecommacolon'|'flags'|'flagscomma' --- @field scope vim.option_scope[] @@ -43,6 +42,8 @@ --- @field meta? integer|boolean|string Default to use in Lua meta files --- @alias vim.option_scope 'global'|'buffer'|'window' +--- @alias vim.option_type 'boolean'|'number'|'string' +--- @alias vim.option_value boolean|number|string --- @alias vim.option_redraw --- |'statuslines' @@ -61,18 +62,11 @@ local function cstr(s) end --- @param s string ---- @return fun(): string -local function macros(s) +--- @param t vim.option_type +--- @return fun(): string, vim.option_type +local function macros(s, t) return function() - return '.string=' .. s - end -end - ---- @param s string ---- @return fun(): string -local function imacros(s) - return function() - return '.number=' .. s + return s, t end end @@ -994,7 +988,7 @@ return { { cb = 'did_set_cedit', defaults = { - if_true = macros('CTRL_F_STR'), + if_true = macros('CTRL_F_STR', 'string'), doc = 'CTRL-F', }, desc = [=[ @@ -1288,7 +1282,7 @@ return { abbreviation = 'co', cb = 'did_set_lines_or_columns', defaults = { - if_true = imacros('DFLT_COLS'), + if_true = macros('DFLT_COLS', 'number'), doc = '80 or terminal width', }, desc = [=[ @@ -1630,7 +1624,7 @@ return { { abbreviation = 'cpo', cb = 'did_set_cpoptions', - defaults = { if_true = macros('CPO_VIM') }, + defaults = { if_true = macros('CPO_VIM', 'string') }, desc = [=[ A sequence of single character flags. When a character is present this indicates Vi-compatible behavior. This is used for things where @@ -2368,7 +2362,7 @@ return { { abbreviation = 'enc', cb = 'did_set_encoding', - defaults = { if_true = macros('ENC_DFLT') }, + defaults = { if_true = macros('ENC_DFLT', 'string') }, deny_in_modelines = true, desc = [=[ String-encoding used internally and for |RPC| communication. @@ -2492,7 +2486,7 @@ return { }, { abbreviation = 'ef', - defaults = { if_true = macros('DFLT_ERRORFILE') }, + defaults = { if_true = macros('DFLT_ERRORFILE', 'string') }, desc = [=[ Name of the errorfile for the QuickFix mode (see |:cf|). When the "-q" command-line argument is used, 'errorfile' is set to the @@ -2514,7 +2508,7 @@ return { { abbreviation = 'efm', defaults = { - if_true = macros('DFLT_EFM'), + if_true = macros('DFLT_EFM', 'string'), doc = 'is very long', }, deny_duplicates = true, @@ -2706,7 +2700,7 @@ return { alloced = true, cb = 'did_set_fileformat', defaults = { - if_true = macros('DFLT_FF'), + if_true = macros('DFLT_FF', 'string'), doc = 'Windows: "dos", Unix: "unix"', }, desc = [=[ @@ -2739,7 +2733,7 @@ return { abbreviation = 'ffs', cb = 'did_set_fileformats', defaults = { - if_true = macros('DFLT_FFS_VIM'), + if_true = macros('DFLT_FFS_VIM', 'string'), doc = 'Windows: "dos,unix", Unix: "unix,dos"', }, deny_duplicates = true, @@ -3316,7 +3310,7 @@ return { abbreviation = 'fo', alloced = true, cb = 'did_set_formatoptions', - defaults = { if_true = macros('DFLT_FO_VIM') }, + defaults = { if_true = macros('DFLT_FO_VIM', 'string') }, desc = [=[ This is a sequence of letters which describes how automatic formatting is to be done. @@ -3409,7 +3403,7 @@ return { }, { abbreviation = 'gfm', - defaults = { if_true = macros('DFLT_GREPFORMAT') }, + defaults = { if_true = macros('DFLT_GREPFORMAT', 'string') }, deny_duplicates = true, desc = [=[ Format to recognize for the ":grep" command output. @@ -3773,6 +3767,7 @@ return { }, { abbreviation = 'gtl', + defaults = { if_true = '' }, desc = [=[ When non-empty describes the text to use in a label of the GUI tab pages line. When empty and when the result is empty Vim will use a @@ -3798,6 +3793,7 @@ return { }, { abbreviation = 'gtt', + defaults = { if_true = '' }, desc = [=[ When non-empty describes the text to use in a tooltip for the GUI tab pages line. When empty Vim will use a default tooltip. @@ -3817,7 +3813,7 @@ return { abbreviation = 'hf', cb = 'did_set_helpfile', defaults = { - if_true = macros('DFLT_HELPFILE'), + if_true = macros('DFLT_HELPFILE', 'string'), doc = [[(MS-Windows) "$VIMRUNTIME\doc\help.txt" (others) "$VIMRUNTIME/doc/help.txt"]], }, @@ -3914,7 +3910,7 @@ return { { abbreviation = 'hl', cb = 'did_set_highlight', - defaults = { if_true = macros('HIGHLIGHT_INIT') }, + defaults = { if_true = macros('HIGHLIGHT_INIT', 'string') }, deny_duplicates = true, full_name = 'highlight', list = 'onecomma', @@ -4080,7 +4076,7 @@ return { { abbreviation = 'imi', cb = 'did_set_iminsert', - defaults = { if_true = imacros('B_IMODE_NONE') }, + defaults = { if_true = macros('B_IMODE_NONE', 'number') }, desc = [=[ Specifies whether :lmap or an Input Method (IM) is to be used in Insert mode. Valid values: @@ -4106,7 +4102,7 @@ return { }, { abbreviation = 'ims', - defaults = { if_true = imacros('B_IMODE_USE_INSERT') }, + defaults = { if_true = macros('B_IMODE_USE_INSERT', 'number') }, desc = [=[ Specifies whether :lmap or an Input Method (IM) is to be used when entering a search pattern. Valid values: @@ -4812,7 +4808,7 @@ return { { cb = 'did_set_lines_or_columns', defaults = { - if_true = imacros('DFLT_ROWS'), + if_true = macros('DFLT_ROWS', 'number'), doc = '24 or terminal height', }, desc = [=[ @@ -4900,7 +4896,7 @@ return { { abbreviation = 'lw', defaults = { - if_true = macros('LISPWORD_VALUE'), + if_true = macros('LISPWORD_VALUE', 'string'), doc = 'is very long', }, deny_duplicates = true, @@ -5210,7 +5206,7 @@ return { }, { abbreviation = 'mco', - defaults = { if_true = imacros('MAX_MCO') }, + defaults = { if_true = macros('MAX_MCO', 'number') }, full_name = 'maxcombine', scope = { 'global' }, short_desc = N_('maximum nr of combining characters displayed'), @@ -9613,7 +9609,7 @@ return { abbreviation = 'wc', cb = 'did_set_wildchar', defaults = { - if_true = imacros('TAB'), + if_true = macros('TAB', 'number'), doc = '', }, desc = [=[ -- cgit From 25b53b593ef6f229fbec5b3dc205a7539579d13a Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Sat, 26 Oct 2024 15:38:25 +0100 Subject: refactor(lsp): drop str_byteindex/str_utfindex wrappers #30915 * deprecate old signatures * move to new str_byteindex/str_utfindex signature * use single-underscore name (double-underscore is reserved for Lua itself) --- src/nvim/lua/stdlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index bf8b085458..e719d99640 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -699,10 +699,10 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) lua_setfield(lstate, -2, "stricmp"); // str_utfindex lua_pushcfunction(lstate, &nlua_str_utfindex); - lua_setfield(lstate, -2, "__str_utfindex"); + lua_setfield(lstate, -2, "_str_utfindex"); // str_byteindex lua_pushcfunction(lstate, &nlua_str_byteindex); - lua_setfield(lstate, -2, "__str_byteindex"); + lua_setfield(lstate, -2, "_str_byteindex"); // str_utf_pos lua_pushcfunction(lstate, &nlua_str_utf_pos); lua_setfield(lstate, -2, "str_utf_pos"); -- cgit From b136a9ee4c5689c655713ab006be84ae9e7a313a Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Sun, 27 Oct 2024 19:09:24 +0600 Subject: refactor(options): always allocate option values (#30917) Instead of keeping `P_ALLOCED` and `P_DEF_ALLOCED` flags to check if an option value is allocated, always allocate option values to simplify the logic. Ref: #25672 --- src/nvim/generators/gen_options.lua | 1 - src/nvim/globals.h | 6 --- src/nvim/option.c | 81 +++++++++++++++++-------------------- src/nvim/option_vars.h | 16 ++++---- src/nvim/options.lua | 51 ----------------------- src/nvim/optionstr.c | 1 - src/nvim/quickfix.c | 5 +-- 7 files changed, 47 insertions(+), 114 deletions(-) (limited to 'src') diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 24121d7938..b1018c1283 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -67,7 +67,6 @@ local function get_flags(o) end end for _, flag_desc in ipairs({ - { 'alloced' }, { 'nodefault' }, { 'no_mkrc' }, { 'secure' }, diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 45a31ce6b0..1cdb38f5f8 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -713,12 +713,6 @@ EXTERN char *escape_chars INIT( = " \t\\\"|"); // need backslash in cmd line EXTERN bool keep_help_flag INIT( = false); // doing :ta from help file -// When a string option is NULL (which only happens in out-of-memory situations), it is set to -// empty_string_option, to avoid having to check for NULL everywhere. -// -// TODO(famiu): Remove this when refcounted strings are used for string options. -EXTERN char *empty_string_option INIT( = ""); - EXTERN bool redir_off INIT( = false); // no redirection for a moment EXTERN FILE *redir_fd INIT( = NULL); // message redirection file EXTERN int redir_reg INIT( = 0); // message redirection register diff --git a/src/nvim/option.c b/src/nvim/option.c index a237689eb0..72f8a5d2f3 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -291,8 +291,7 @@ static void set_init_default_cdpath(void) } } buf[j] = NUL; - options[kOptCdpath].def_val = CSTR_AS_OPTVAL(buf); - options[kOptCdpath].flags |= P_DEF_ALLOCED; + change_option_default(kOptCdpath, CSTR_AS_OPTVAL(buf)); xfree(cdpath); } @@ -302,8 +301,6 @@ static void set_init_default_cdpath(void) /// only happen for non-indirect options. /// Also set the default to the expanded value, so ":set" does not list /// them. -/// Don't set the P_ALLOCED flag, because we don't want to free the -/// default. static void set_init_expand_env(void) { for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { @@ -318,14 +315,8 @@ static void set_init_expand_env(void) p = option_expand(opt_idx, NULL); } if (p != NULL) { - set_option_varp(opt_idx, opt->var, CSTR_TO_OPTVAL(p), opt->flags & P_ALLOCED); - opt->flags |= P_ALLOCED; - - if (opt->flags & P_DEF_ALLOCED) { - optval_free(opt->def_val); - } - opt->def_val = CSTR_TO_OPTVAL(p); - opt->flags |= P_DEF_ALLOCED; + set_option_varp(opt_idx, opt->var, CSTR_TO_OPTVAL(p), true); + change_option_default(opt_idx, CSTR_TO_OPTVAL(p)); } } } @@ -356,6 +347,9 @@ void set_init_1(bool clean_arg) { langmap_init(); + // Allocate the default option values. + alloc_options_default(); + set_init_default_shell(); set_init_default_backupskip(); set_init_default_cdpath(); @@ -463,6 +457,25 @@ static OptVal get_option_default(const OptIndex opt_idx, int opt_flags) } } +/// Allocate the default values for all options by copying them from the stack. +/// This ensures that we don't need to always check if the option default is allocated or not. +static void alloc_options_default(void) +{ + for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + options[opt_idx].def_val = optval_copy(options[opt_idx].def_val); + } +} + +/// Change the default value for an option. +/// +/// @param opt_idx Option index in options[] table. +/// @param value New default value. Must be allocated. +static void change_option_default(const OptIndex opt_idx, OptVal value) +{ + optval_free(options[opt_idx].def_val); + options[opt_idx].def_val = value; +} + /// Set an option to its default value. /// This does not take care of side effects! /// @@ -512,17 +525,8 @@ static void set_options_default(int opt_flags) static void set_string_default(OptIndex opt_idx, char *val, bool allocated) FUNC_ATTR_NONNULL_ALL { - if (opt_idx == kOptInvalid) { - return; - } - - vimoption_T *opt = &options[opt_idx]; - if (opt->flags & P_DEF_ALLOCED) { - optval_free(opt->def_val); - } - - opt->def_val = CSTR_AS_OPTVAL(allocated ? val : xstrdup(val)); - opt->flags |= P_DEF_ALLOCED; + assert(opt_idx != kOptInvalid); + change_option_default(opt_idx, CSTR_AS_OPTVAL(allocated ? val : xstrdup(val))); } /// For an option value that contains comma separated items, find "newval" in @@ -563,16 +567,14 @@ void free_all_options(void) for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { if (options[opt_idx].indir == PV_NONE) { // global option: free value and default value. - if ((options[opt_idx].flags & P_ALLOCED) && options[opt_idx].var != NULL) { + if (options[opt_idx].var != NULL) { optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } - if (options[opt_idx].flags & P_DEF_ALLOCED) { - optval_free(options[opt_idx].def_val); - } } else if (options[opt_idx].var != VAR_WIN) { // buffer-local option: free global value optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } + optval_free(options[opt_idx].def_val); } free_operatorfunc_option(); free_tagfunc_option(); @@ -600,7 +602,7 @@ void set_init_2(bool headless) if (!option_was_set(kOptWindow)) { p_window = Rows - 1; } - options[kOptWindow].def_val = NUMBER_OPTVAL(Rows - 1); + change_option_default(kOptWindow, NUMBER_OPTVAL(Rows - 1)); } /// Initialize the options, part three: After reading the .vimrc @@ -632,12 +634,12 @@ void set_init_3(void) const OptVal sp = is_csh ? STATIC_CSTR_AS_OPTVAL("|& tee") : STATIC_CSTR_AS_OPTVAL("2>&1| tee"); set_option_direct(kOptShellpipe, sp, 0, SID_NONE); - options[kOptShellpipe].def_val = sp; + change_option_default(kOptShellpipe, optval_copy(sp)); } if (do_srr) { const OptVal srr = is_csh ? STATIC_CSTR_AS_OPTVAL(">&") : STATIC_CSTR_AS_OPTVAL(">%s 2>&1"); set_option_direct(kOptShellredir, srr, 0, SID_NONE); - options[kOptShellredir].def_val = srr; + change_option_default(kOptShellredir, optval_copy(srr)); } } xfree(p); @@ -670,9 +672,7 @@ void set_helplang_default(const char *lang) return; } - if (options[kOptHelplang].flags & P_ALLOCED) { - free_string_option(p_hlg); - } + free_string_option(p_hlg); p_hlg = xmemdupz(lang, lang_len); // zh_CN becomes "cn", zh_TW becomes "tw". if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) { @@ -684,7 +684,6 @@ void set_helplang_default(const char *lang) p_hlg[1] = 'n'; } p_hlg[2] = NUL; - options[kOptHelplang].flags |= P_ALLOCED; } /// 'title' and 'icon' only default to true if they have not been set or reset @@ -698,11 +697,11 @@ void set_title_defaults(void) // icon name. Saves a bit of time, because the X11 display server does // not need to be contacted. if (!(options[kOptTitle].flags & P_WAS_SET)) { - options[kOptTitle].def_val = BOOLEAN_OPTVAL(false); + change_option_default(kOptTitle, BOOLEAN_OPTVAL(false)); p_title = 0; } if (!(options[kOptIcon].flags & P_WAS_SET)) { - options[kOptIcon].def_val = BOOLEAN_OPTVAL(false); + change_option_default(kOptIcon, BOOLEAN_OPTVAL(false)); p_icon = 0; } } @@ -3441,7 +3440,6 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value vimoption_T *opt = &options[opt_idx]; const char *errmsg = NULL; bool restore_chartab = false; - bool free_oldval = (opt->flags & P_ALLOCED); bool value_changed = false; bool value_checked = false; @@ -3517,12 +3515,7 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value set_option_sctx(opt_idx, opt_flags, script_ctx); } - // Free options that are in allocated memory. - // Use "free_oldval", because recursiveness may change the flags (esp. init_highlight()). - if (free_oldval) { - optval_free(old_value); - } - opt->flags |= P_ALLOCED; + optval_free(old_value); const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; @@ -5398,7 +5391,7 @@ void reset_modifiable(void) { curbuf->b_p_ma = false; p_ma = false; - options[kOptModifiable].def_val = BOOLEAN_OPTVAL(false); + change_option_default(kOptModifiable, BOOLEAN_OPTVAL(false)); } /// Set the global value for 'iminsert' to the local value. diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index bfdaa11ed9..24ec78ec61 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -8,16 +8,12 @@ // option_vars.h: definition of global variables for settable options // Option Flags -#define P_ALLOCED 0x01U ///< the option is in allocated memory, - ///< must use free_string_option() when - ///< assigning new value. Not set if default is - ///< the same. +// #define P_ALLOCED 0x01U ///< Not used #define P_EXPAND 0x02U ///< environment expansion. NOTE: P_EXPAND can ///< never be used for local or hidden options #define P_NO_DEF_EXP 0x04U ///< do not expand default value #define P_NODEFAULT 0x08U ///< don't set to default value -#define P_DEF_ALLOCED 0x10U ///< default value is in allocated memory, must - ///< use free() when assigning new value +// #define P_DEF_ALLOCED 0x10U ///< Not used #define P_WAS_SET 0x20U ///< option has been set/reset #define P_NO_MKRC 0x40U ///< don't include in :mkvimrc output @@ -348,6 +344,12 @@ enum { #define LISPWORD_VALUE \ "defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object" +// When a string option is NULL, it is set to empty_string_option, +// to avoid having to check for NULL everywhere. +// +// TODO(famiu): Remove this when refcounted strings are used for string options. +EXTERN char empty_string_option[] INIT( = ""); + // The following are actual variables for the options EXTERN char *p_ambw; ///< 'ambiwidth' @@ -770,7 +772,7 @@ EXTERN unsigned ve_flags; #define VE_NONEU 32U // "NONE" EXTERN OptInt p_verbose; ///< 'verbose' #ifdef IN_OPTION_C -char *p_vfile = ""; ///< used before options are initialized +char *p_vfile = empty_string_option; ///< used before options are initialized #else extern char *p_vfile; ///< 'verbosefile' #endif diff --git a/src/nvim/options.lua b/src/nvim/options.lua index d49621490c..a891d18364 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -735,7 +735,6 @@ return { }, { abbreviation = 'briopt', - alloced = true, cb = 'did_set_breakindentopt', defaults = { if_true = '' }, deny_duplicates = true, @@ -798,7 +797,6 @@ return { }, { abbreviation = 'bh', - alloced = true, cb = 'did_set_bufhidden', defaults = { if_true = '' }, desc = [=[ @@ -851,7 +849,6 @@ return { }, { abbreviation = 'bt', - alloced = true, cb = 'did_set_buftype', defaults = { if_true = '' }, desc = [=[ @@ -1103,7 +1100,6 @@ return { }, { abbreviation = 'cink', - alloced = true, defaults = { if_true = '0{,0},0),0],:,0#,!^F,o,O,e' }, deny_duplicates = true, desc = [=[ @@ -1122,7 +1118,6 @@ return { }, { abbreviation = 'cino', - alloced = true, cb = 'did_set_cinoptions', defaults = { if_true = '' }, deny_duplicates = true, @@ -1140,7 +1135,6 @@ return { }, { abbreviation = 'cinsd', - alloced = true, defaults = { if_true = 'public,protected,private' }, deny_duplicates = true, desc = [=[ @@ -1159,7 +1153,6 @@ return { }, { abbreviation = 'cinw', - alloced = true, defaults = { if_true = 'if,else,while,do,for,switch' }, deny_duplicates = true, desc = [=[ @@ -1309,7 +1302,6 @@ return { }, { abbreviation = 'com', - alloced = true, cb = 'did_set_comments', defaults = { if_true = 's1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-,fb:•' }, deny_duplicates = true, @@ -1328,7 +1320,6 @@ return { }, { abbreviation = 'cms', - alloced = true, cb = 'did_set_commentstring', defaults = { if_true = '' }, desc = [=[ @@ -1354,7 +1345,6 @@ return { }, { abbreviation = 'cpt', - alloced = true, cb = 'did_set_complete', defaults = { if_true = '.,w,b,u,t' }, deny_duplicates = true, @@ -1403,7 +1393,6 @@ return { }, { abbreviation = 'cfu', - alloced = true, cb = 'did_set_completefunc', defaults = { if_true = '' }, desc = [=[ @@ -1525,7 +1514,6 @@ return { }, { abbreviation = 'cocu', - alloced = true, cb = 'did_set_concealcursor', defaults = { if_true = '' }, desc = [=[ @@ -1968,7 +1956,6 @@ return { }, { abbreviation = 'def', - alloced = true, defaults = { if_true = '' }, desc = [=[ Pattern to be used to find a macro definition. It is a search @@ -2088,7 +2075,6 @@ return { }, { abbreviation = 'dip', - alloced = true, cb = 'did_set_diffopt', defaults = { if_true = 'internal,filler,closeoff' }, deny_duplicates = true, @@ -2583,7 +2569,6 @@ return { }, { abbreviation = 'fenc', - alloced = true, cb = 'did_set_encoding', defaults = { if_true = '' }, desc = [=[ @@ -2697,7 +2682,6 @@ return { }, { abbreviation = 'ff', - alloced = true, cb = 'did_set_fileformat', defaults = { if_true = macros('DFLT_FF', 'string'), @@ -2813,7 +2797,6 @@ return { }, { abbreviation = 'ft', - alloced = true, cb = 'did_set_filetype_or_syntax', defaults = { if_true = '' }, desc = [=[ @@ -2849,7 +2832,6 @@ return { }, { abbreviation = 'fcs', - alloced = true, cb = 'did_set_chars_option', defaults = { if_true = '' }, deny_duplicates = true, @@ -2964,7 +2946,6 @@ return { }, { abbreviation = 'fdc', - alloced = true, cb = 'did_set_foldcolumn', defaults = { if_true = '0' }, desc = [=[ @@ -3003,7 +2984,6 @@ return { }, { abbreviation = 'fde', - alloced = true, cb = 'did_set_foldexpr', defaults = { if_true = '0' }, desc = [=[ @@ -3029,7 +3009,6 @@ return { }, { abbreviation = 'fdi', - alloced = true, cb = 'did_set_foldignore', defaults = { if_true = '#' }, desc = [=[ @@ -3084,7 +3063,6 @@ return { }, { abbreviation = 'fmr', - alloced = true, cb = 'did_set_foldmarker', defaults = { if_true = '{{{,}}}' }, deny_duplicates = true, @@ -3104,7 +3082,6 @@ return { }, { abbreviation = 'fdm', - alloced = true, cb = 'did_set_foldmethod', defaults = { if_true = 'manual' }, desc = [=[ @@ -3205,7 +3182,6 @@ return { }, { abbreviation = 'fdt', - alloced = true, cb = 'did_set_optexpr', defaults = { if_true = 'foldtext()' }, desc = [=[ @@ -3233,7 +3209,6 @@ return { }, { abbreviation = 'fex', - alloced = true, cb = 'did_set_optexpr', defaults = { if_true = '' }, desc = [=[ @@ -3287,7 +3262,6 @@ return { }, { abbreviation = 'flp', - alloced = true, defaults = { if_true = '^\\s*\\d\\+[\\]:.)}\\t ]\\s*' }, desc = [=[ A pattern that is used to recognize a list header. This is used for @@ -3308,7 +3282,6 @@ return { }, { abbreviation = 'fo', - alloced = true, cb = 'did_set_formatoptions', defaults = { if_true = macros('DFLT_FO_VIM', 'string') }, desc = [=[ @@ -4151,7 +4124,6 @@ return { }, { abbreviation = 'inc', - alloced = true, defaults = { if_true = '' }, desc = [=[ Pattern to be used to find an include command. It is a search @@ -4173,7 +4145,6 @@ return { }, { abbreviation = 'inex', - alloced = true, cb = 'did_set_optexpr', defaults = { if_true = '' }, desc = [=[ @@ -4258,7 +4229,6 @@ return { }, { abbreviation = 'inde', - alloced = true, cb = 'did_set_optexpr', defaults = { if_true = '' }, desc = [=[ @@ -4312,7 +4282,6 @@ return { }, { abbreviation = 'indk', - alloced = true, defaults = { if_true = '0{,0},0),0],:,0#,!^F,o,O,e' }, deny_duplicates = true, desc = [=[ @@ -4454,7 +4423,6 @@ return { }, { abbreviation = 'isk', - alloced = true, cb = 'did_set_iskeyword', defaults = { if_true = '@,48-57,_,192-255' }, deny_duplicates = true, @@ -4563,7 +4531,6 @@ return { }, { abbreviation = 'kmp', - alloced = true, cb = 'did_set_keymap', defaults = { if_true = '' }, desc = [=[ @@ -4940,7 +4907,6 @@ return { }, { abbreviation = 'lcs', - alloced = true, cb = 'did_set_chars_option', defaults = { if_true = 'tab:> ,trail:-,nbsp:+' }, deny_duplicates = true, @@ -5162,7 +5128,6 @@ return { }, { abbreviation = 'mps', - alloced = true, cb = 'did_set_matchpairs', defaults = { if_true = '(:),{:},[:]' }, deny_duplicates = true, @@ -5730,7 +5695,6 @@ return { }, { abbreviation = 'nf', - alloced = true, cb = 'did_set_nrformats', defaults = { if_true = 'bin,hex' }, deny_duplicates = true, @@ -5841,7 +5805,6 @@ return { }, { abbreviation = 'ofu', - alloced = true, cb = 'did_set_omnifunc', defaults = { if_true = '' }, desc = [=[ @@ -6225,7 +6188,6 @@ return { }, { abbreviation = 'qe', - alloced = true, defaults = { if_true = '\\' }, desc = [=[ The characters that are used to escape quotes in a string. Used for @@ -6436,7 +6398,6 @@ return { }, { abbreviation = 'rlc', - alloced = true, cb = 'did_set_rightleftcmd', defaults = { if_true = 'search' }, desc = [=[ @@ -6491,7 +6452,6 @@ return { }, { abbreviation = 'ruf', - alloced = true, cb = 'did_set_rulerformat', defaults = { if_true = '' }, desc = [=[ @@ -7640,7 +7600,6 @@ return { }, { abbreviation = 'scl', - alloced = true, cb = 'did_set_signcolumn', defaults = { if_true = 'auto' }, desc = [=[ @@ -7797,7 +7756,6 @@ return { }, { abbreviation = 'spc', - alloced = true, cb = 'did_set_spellcapcheck', defaults = { if_true = '[.?!]\\_[\\])\'"\\t ]\\+' }, desc = [=[ @@ -7820,7 +7778,6 @@ return { }, { abbreviation = 'spf', - alloced = true, cb = 'did_set_spellfile', defaults = { if_true = '' }, deny_duplicates = true, @@ -7858,7 +7815,6 @@ return { }, { abbreviation = 'spl', - alloced = true, cb = 'did_set_spelllang', defaults = { if_true = 'en' }, deny_duplicates = true, @@ -8092,7 +8048,6 @@ return { }, { abbreviation = 'stc', - alloced = true, cb = 'did_set_statuscolumn', defaults = { if_true = '' }, desc = [=[ @@ -8158,7 +8113,6 @@ return { }, { abbreviation = 'stl', - alloced = true, cb = 'did_set_statusline', defaults = { if_true = '' }, desc = [=[ @@ -8407,7 +8361,6 @@ return { }, { abbreviation = 'sua', - alloced = true, defaults = { if_true = '' }, deny_duplicates = true, desc = [=[ @@ -8516,7 +8469,6 @@ return { }, { abbreviation = 'syn', - alloced = true, cb = 'did_set_filetype_or_syntax', defaults = { if_true = '' }, desc = [=[ @@ -9003,7 +8955,6 @@ return { }, { abbreviation = 'tsrfu', - alloced = true, cb = 'did_set_thesaurusfunc', defaults = { if_true = '' }, desc = [=[ @@ -9863,7 +9814,6 @@ return { }, { abbreviation = 'wbr', - alloced = true, cb = 'did_set_winbar', defaults = { if_true = '' }, desc = [=[ @@ -10006,7 +9956,6 @@ return { }, { abbreviation = 'winhl', - alloced = true, cb = 'did_set_winhighlight', defaults = { if_true = '' }, deny_duplicates = true, diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 21a3a3877b..651a9d20bf 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -250,7 +250,6 @@ void check_buf_options(buf_T *buf) /// Free the string allocated for an option. /// Checks for the string being empty_string_option. This may happen if we're out of memory, /// xstrdup() returned NULL, which was replaced by empty_string_option by check_options(). -/// Does NOT check for P_ALLOCED flag! void free_string_option(char *p) { if (p != empty_string_option) { diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 5bd81ce469..f037d5d924 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -7348,7 +7348,6 @@ void ex_helpgrep(exarg_T *eap) bool updated = false; // Make 'cpoptions' empty, the 'l' flag should not be used here. char *const save_cpo = p_cpo; - const bool save_cpo_allocated = (get_option(kOptCpoptions)->flags & P_ALLOCED); p_cpo = empty_string_option; bool new_qi = false; @@ -7388,9 +7387,7 @@ void ex_helpgrep(exarg_T *eap) if (*p_cpo == NUL) { set_option_value_give_err(kOptCpoptions, CSTR_AS_OPTVAL(save_cpo), 0); } - if (save_cpo_allocated) { - free_string_option(save_cpo); - } + free_string_option(save_cpo); } if (updated) { -- cgit From 7a20f93a929abda22f979e92fd75b92e447d1e2a Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Sun, 27 Oct 2024 13:02:31 -0400 Subject: fix(treesitter): correct condition in `__has_ancestor` --- src/nvim/lua/treesitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 1ebf835eb5..9ea55dbd0c 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -1151,7 +1151,7 @@ static int __has_ancestor(lua_State *L) int const pred_len = (int)lua_objlen(L, 2); TSNode node = ts_tree_root_node(descendant.tree); - while (node.id != descendant.id) { + while (node.id != descendant.id && !ts_node_is_null(node)) { char const *node_type = ts_node_type(node); size_t node_type_len = strlen(node_type); -- cgit From d24fb72c335be905d0b7f2c67f9b988f07703d1f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 28 Oct 2024 14:29:59 +0800 Subject: fix(pum): don't select item when clicking to the left/right (#30967) Problem: Selecting an item in the right-click menu when clicking to the left/right of it is confusing, especially in a UI that doesn't support 'mousemoveevent'. Solution: Don't select an item when clicking to the left/right of the right-click menu. --- src/nvim/popupmenu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 87ef6a27ad..529d65c5dc 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -1358,14 +1358,15 @@ static void pum_select_mouse_pos(void) if (mouse_grid == pum_grid.handle) { pum_selected = mouse_row; return; - } else if (mouse_grid != pum_anchor_grid) { + } else if (mouse_grid != pum_anchor_grid || mouse_col < pum_grid.comp_col + || mouse_col >= pum_grid.comp_col + pum_grid.comp_width) { pum_selected = -1; return; } - int idx = mouse_row - pum_row; + int idx = mouse_row - pum_grid.comp_row; - if (idx < 0 || idx >= pum_height) { + if (idx < 0 || idx >= pum_grid.comp_height) { pum_selected = -1; } else if (*pum_array[idx].pum_text != NUL) { pum_selected = idx; -- cgit From 34c44c355646311aa67fe53e1e5ce040789430c6 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Mon, 28 Oct 2024 19:49:16 +0600 Subject: refactor(options): option flags enum #30961 Problem: Currently we use macros with hardcoded flag values for option flags, which is messy and requires a lot of mental math for adding / removing option flags. Using macros for option flags also means that they cannot be used inside debuggers. Solution: Create a new `OptFlags` enum that stores all the option flags in an organized way that is easier to understand. --- src/nvim/buffer_defs.h | 2 +- src/nvim/cmdexpand.c | 2 +- src/nvim/eval/vars.c | 2 +- src/nvim/generators/gen_options.lua | 52 ++++++------- src/nvim/option.c | 151 ++++++++++++++++++------------------ src/nvim/option_defs.h | 36 ++++++++- src/nvim/option_vars.h | 41 ---------- src/nvim/optionstr.c | 8 +- 8 files changed, 144 insertions(+), 150 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 1fe5512708..134d69de96 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1249,7 +1249,7 @@ struct window_S { // transform a pointer to a "onebuf" option into a "allbuf" option #define GLOBAL_WO(p) ((char *)(p) + sizeof(winopt_T)) - // A few options have local flags for P_INSECURE. + // A few options have local flags for kOptFlagInsecure. uint32_t w_p_stl_flags; // flags for 'statusline' uint32_t w_p_wbr_flags; // flags for 'winbar' uint32_t w_p_fde_flags; // flags for 'foldexpr' diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 250d705ee6..549ed826bc 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -1350,7 +1350,7 @@ char *addstar(char *fname, size_t len, int context) /// it. /// EXPAND_BUFFERS Complete file names for :buf and :sbuf commands. /// EXPAND_FILES After command with EX_XFILE set, or after setting -/// with P_EXPAND set. eg :e ^I, :w>>^I +/// with kOptFlagExpand set. eg :e ^I, :w>>^I /// EXPAND_DIRECTORIES In some cases this is used instead of the latter /// when we know only directories are of interest. /// E.g. :set dir=^I and :cd ^I diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index d002bff321..d3f836f7f4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -1908,7 +1908,7 @@ static OptVal tv_to_optval(typval_T *tv, OptIndex opt_idx, const char *option, b const bool option_has_num = !is_tty_opt && option_has_type(opt_idx, kOptValTypeNumber); const bool option_has_str = is_tty_opt || option_has_type(opt_idx, kOptValTypeString); - if (!is_tty_opt && (get_option(opt_idx)->flags & P_FUNC) && tv_is_func(*tv)) { + if (!is_tty_opt && (get_option(opt_idx)->flags & kOptFlagFunc) && tv_is_func(*tv)) { // If the option can be set to a function reference or a lambda // and the passed value is a function reference, then convert it to // the name (string) of the function reference. diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index b1018c1283..0cb5fa8e95 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -16,23 +16,23 @@ local options = require('options') local cstr = options.cstr local redraw_flags = { - ui_option = 'P_UI_OPTION', - tabline = 'P_RTABL', - statuslines = 'P_RSTAT', - current_window = 'P_RWIN', - current_buffer = 'P_RBUF', - all_windows = 'P_RALL', - curswant = 'P_CURSWANT', - highlight_only = 'P_HLONLY', + ui_option = 'kOptFlagUIOption', + tabline = 'kOptFlagRedrTabl', + statuslines = 'kOptFlagRedrStat', + current_window = 'kOptFlagRedrWin', + current_buffer = 'kOptFlagRedrBuf', + all_windows = 'kOptFlagRedrAll', + curswant = 'kOptFlagCurswant', + highlight_only = 'kOptFlagHLOnly', } local list_flags = { - comma = 'P_COMMA', - onecomma = 'P_ONECOMMA', - commacolon = 'P_COMMA|P_COLON', - onecommacolon = 'P_ONECOMMA|P_COLON', - flags = 'P_FLAGLIST', - flagscomma = 'P_COMMA|P_FLAGLIST', + comma = 'kOptFlagComma', + onecomma = 'kOptFlagOneComma', + commacolon = 'kOptFlagComma|kOptFlagColon', + onecommacolon = 'kOptFlagOneComma|kOptFlagColon', + flags = 'kOptFlagFlagList', + flagscomma = 'kOptFlagComma|kOptFlagFlagList', } --- @param s string @@ -61,27 +61,27 @@ local function get_flags(o) end end if o.expand then - add_flag('P_EXPAND') + add_flag('kOptFlagExpand') if o.expand == 'nodefault' then - add_flag('P_NO_DEF_EXP') + add_flag('kOptFlagNoDefExp') end end for _, flag_desc in ipairs({ - { 'nodefault' }, - { 'no_mkrc' }, + { 'nodefault', 'NoDefault' }, + { 'no_mkrc', 'NoMkrc' }, { 'secure' }, { 'gettext' }, - { 'noglob' }, - { 'normal_fname_chars', 'P_NFNAME' }, - { 'normal_dname_chars', 'P_NDNAME' }, - { 'pri_mkrc' }, - { 'deny_in_modelines', 'P_NO_ML' }, - { 'deny_duplicates', 'P_NODUP' }, - { 'modelineexpr', 'P_MLE' }, + { 'noglob', 'NoGlob' }, + { 'normal_fname_chars', 'NFname' }, + { 'normal_dname_chars', 'NDname' }, + { 'pri_mkrc', 'PriMkrc' }, + { 'deny_in_modelines', 'NoML' }, + { 'deny_duplicates', 'NoDup' }, + { 'modelineexpr', 'MLE' }, { 'func' }, }) do local key_name = flag_desc[1] - local def_name = flag_desc[2] or ('P_' .. key_name:upper()) + local def_name = 'kOptFlag' .. (flag_desc[2] or lowercase_to_titlecase(key_name)) if o[key_name] then add_flag(def_name) end diff --git a/src/nvim/option.c b/src/nvim/option.c index 72f8a5d2f3..7c32c99d0e 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -305,11 +305,11 @@ static void set_init_expand_env(void) { for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { vimoption_T *opt = &options[opt_idx]; - if (opt->flags & P_NO_DEF_EXP) { + if (opt->flags & kOptFlagNoDefExp) { continue; } char *p; - if ((opt->flags & P_GETTEXT) && opt->var != NULL) { + if ((opt->flags & kOptFlagGettext) && opt->var != NULL) { p = _(*(char **)opt->var); } else { p = option_expand(opt_idx, NULL); @@ -447,7 +447,7 @@ static OptVal get_option_default(const OptIndex opt_idx, int opt_flags) if ((opt_flags & OPT_LOCAL) && is_global_local_option) { // Use unset local value instead of default value for local scope of global-local options. return get_option_unset_value(opt_idx); - } else if (option_has_type(opt_idx, kOptValTypeString) && !(opt->flags & P_NO_DEF_EXP)) { + } else if (option_has_type(opt_idx, kOptValTypeString) && !(opt->flags & kOptFlagNoDefExp)) { // For string options, expand environment variables and ~ since the default value was already // expanded, only required when an environment variable was set later. char *s = option_expand(opt_idx, opt->def_val.data.string.data); @@ -492,7 +492,7 @@ static void set_option_default(const OptIndex opt_idx, int opt_flags) // The default value is not insecure. uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags); - *flagsp = *flagsp & ~P_INSECURE; + *flagsp = *flagsp & ~(unsigned)kOptFlagInsecure; } /// Set all options (except terminal options) to their default value. @@ -501,7 +501,7 @@ static void set_option_default(const OptIndex opt_idx, int opt_flags) static void set_options_default(int opt_flags) { for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { - if (!(options[opt_idx].flags & P_NODEFAULT)) { + if (!(options[opt_idx].flags & kOptFlagNoDefault)) { set_option_default(opt_idx, opt_flags); } } @@ -542,9 +542,9 @@ static char *find_dup_item(char *origval, const char *newval, const size_t newva int bs = 0; for (char *s = origval; *s != NUL; s++) { - if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1))) + if ((!(flags & kOptFlagComma) || s == origval || (s[-1] == ',' && !(bs & 1))) && strncmp(s, newval, newvallen) == 0 - && (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) { + && (!(flags & kOptFlagComma) || s[newvallen] == ',' || s[newvallen] == NUL)) { return s; } // Count backslashes. Only a comma with an even number of backslashes @@ -592,7 +592,7 @@ void set_init_2(bool headless) // 'scroll' defaults to half the window height. The stored default is zero, // which results in the actual value computed from the window height. - if (!(options[kOptScroll].flags & P_WAS_SET)) { + if (!(options[kOptScroll].flags & kOptFlagWasSet)) { set_option_default(kOptScroll, OPT_LOCAL); } comp_col(); @@ -613,8 +613,8 @@ void set_init_3(void) // Set 'shellpipe' and 'shellredir', depending on the 'shell' option. // This is done after other initializations, where 'shell' might have been // set, but only if they have not been set before. - bool do_srr = !(options[kOptShellredir].flags & P_WAS_SET); - bool do_sp = !(options[kOptShellpipe].flags & P_WAS_SET); + bool do_srr = !(options[kOptShellredir].flags & kOptFlagWasSet); + bool do_sp = !(options[kOptShellpipe].flags & kOptFlagWasSet); size_t len = 0; char *p = (char *)invocation_path_tail(p_sh, &len); @@ -648,7 +648,7 @@ void set_init_3(void) int idx_ffs = find_option("ffs"); // Apply the first entry of 'fileformats' to the initial buffer. - if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET)) { + if (idx_ffs >= 0 && (options[idx_ffs].flags & kOptFlagWasSet)) { set_fileformat(default_fileformat(), OPT_LOCAL); } } @@ -668,7 +668,7 @@ void set_helplang_default(const char *lang) if (lang_len < 2) { // safety check return; } - if (options[kOptHelplang].flags & P_WAS_SET) { + if (options[kOptHelplang].flags & kOptFlagWasSet) { return; } @@ -696,11 +696,11 @@ void set_title_defaults(void) // If GUI is (going to be) used, we can always set the window title and // icon name. Saves a bit of time, because the X11 display server does // not need to be contacted. - if (!(options[kOptTitle].flags & P_WAS_SET)) { + if (!(options[kOptTitle].flags & kOptFlagWasSet)) { change_option_default(kOptTitle, BOOLEAN_OPTVAL(false)); p_title = 0; } - if (!(options[kOptIcon].flags & P_WAS_SET)) { + if (!(options[kOptIcon].flags & kOptFlagWasSet)) { change_option_default(kOptIcon, BOOLEAN_OPTVAL(false)); p_icon = 0; } @@ -744,7 +744,7 @@ static char *stropt_copy_value(char *origval, char **argp, set_op_T op, while (*arg != NUL && !ascii_iswhite(*arg)) { if (*arg == '\\' && arg[1] != NUL #ifdef BACKSLASH_IN_FILENAME - && !((flags & P_EXPAND) + && !((flags & kOptFlagExpand) && vim_isfilec((uint8_t)arg[1]) && !ascii_iswhite(arg[1]) && (arg[1] != '\\' @@ -793,12 +793,12 @@ static char *stropt_expand_envvar(OptIndex opt_idx, char *origval, char *newval, static void stropt_concat_with_comma(char *origval, char *newval, set_op_T op, uint32_t flags) { int len = 0; - int comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL); + int comma = ((flags & kOptFlagComma) && *origval != NUL && *newval != NUL); if (op == OP_ADDING) { len = (int)strlen(origval); // Strip a trailing comma, would get 2. if (comma && len > 1 - && (flags & P_ONECOMMA) == P_ONECOMMA + && (flags & kOptFlagOneComma) == kOptFlagOneComma && origval[len - 1] == ',' && origval[len - 2] != '\\') { len--; @@ -823,7 +823,7 @@ static void stropt_remove_val(char *origval, char *newval, uint32_t flags, char STRCPY(newval, origval); if (*strval) { // may need to remove a comma - if (flags & P_COMMA) { + if (flags & kOptFlagComma) { if (strval == origval) { // include comma after string if (strval[len] == ',') { @@ -845,8 +845,8 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags) char *s = newval; // Remove flags that appear twice. for (s = newval; *s;) { - // if options have P_FLAGLIST and P_ONECOMMA such as 'whichwrap' - if (flags & P_ONECOMMA) { + // if options have kOptFlagFlagList and kOptFlagOneComma such as 'whichwrap' + if (flags & kOptFlagOneComma) { if (*s != ',' && *(s + 1) == ',' && vim_strchr(s + 2, (uint8_t)(*s)) != NULL) { // Remove the duplicated value and the next comma. @@ -854,7 +854,7 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags) continue; } } else { - if ((!(flags & P_COMMA) || *s != ',') + if ((!(flags & kOptFlagComma) || *s != ',') && vim_strchr(s + 1, (uint8_t)(*s)) != NULL) { STRMOVE(s, s + 1); continue; @@ -890,14 +890,14 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void // Expand environment variables and ~. // Don't do it when adding without inserting a comma. - if (op == OP_NONE || (flags & P_COMMA)) { + if (op == OP_NONE || (flags & kOptFlagComma)) { newval = stropt_expand_envvar(opt_idx, origval, newval, op); } // locate newval[] in origval[] when removing it // and when adding to avoid duplicates int len = 0; - if (op == OP_REMOVING || (flags & P_NODUP)) { + if (op == OP_REMOVING || (flags & kOptFlagNoDup)) { len = (int)strlen(newval); s = find_dup_item(origval, newval, (size_t)len, flags); @@ -922,7 +922,7 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void stropt_remove_val(origval, newval, flags, s, len); } - if (flags & P_FLAGLIST) { + if (flags & kOptFlagFlagList) { // Remove flags that appear twice. stropt_remove_dupflags(newval, flags); } @@ -986,11 +986,11 @@ static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_ // Disallow changing some options from modelines. if (opt_flags & OPT_MODELINE) { - if (flags & (P_SECURE | P_NO_ML)) { + if (flags & (kOptFlagSecure | kOptFlagNoML)) { *errmsg = e_not_allowed_in_modeline; return FAIL; } - if ((flags & P_MLE) && !p_mle) { + if ((flags & kOptFlagMLE) && !p_mle) { *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; return FAIL; } @@ -1006,7 +1006,7 @@ static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_ } // Disallow changing some options in the sandbox - if (sandbox != 0 && (flags & P_SECURE)) { + if (sandbox != 0 && (flags & kOptFlagSecure)) { *errmsg = e_sandbox; return FAIL; } @@ -1586,7 +1586,7 @@ char *find_shada_parameter(int type) static char *option_expand(OptIndex opt_idx, char *val) { // if option doesn't need expansion nothing to do - if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) { + if (!(options[opt_idx].flags & kOptFlagExpand) || options[opt_idx].var == NULL) { return NULL; } @@ -1677,10 +1677,10 @@ int was_set_insecurely(win_T *const wp, OptIndex opt_idx, int opt_flags) assert(opt_idx != kOptInvalid); uint32_t *flagp = insecure_flag(wp, opt_idx, opt_flags); - return (*flagp & P_INSECURE) != 0; + return (*flagp & kOptFlagInsecure) != 0; } -/// Get a pointer to the flags used for the P_INSECURE flag of option +/// Get a pointer to the flags used for the kOptFlagInsecure flag of option /// "opt_idx". For some local options a local flags field is used. /// NOTE: Caller must make sure that "wp" is set to the window from which /// the option is used. @@ -2976,25 +2976,25 @@ static const char *validate_num_option(OptIndex opt_idx, void *varp, OptInt *new /// Called after an option changed: check if something needs to be redrawn. void check_redraw_for(buf_T *buf, win_T *win, uint32_t flags) { - // Careful: P_RALL is a combination of other P_ flags - bool all = (flags & P_RALL) == P_RALL; + // Careful: kOptFlagRedrAll is a combination of other redraw flags + bool all = (flags & kOptFlagRedrAll) == kOptFlagRedrAll; - if ((flags & P_RSTAT) || all) { // mark all status lines and window bars dirty + if ((flags & kOptFlagRedrStat) || all) { // mark all status lines and window bars dirty status_redraw_all(); } - if ((flags & P_RTABL) || all) { // mark tablines dirty + if ((flags & kOptFlagRedrTabl) || all) { // mark tablines dirty redraw_tabline = true; } - if ((flags & P_RBUF) || (flags & P_RWIN) || all) { - if (flags & P_HLONLY) { + if ((flags & kOptFlagRedrBuf) || (flags & kOptFlagRedrWin) || all) { + if (flags & kOptFlagHLOnly) { redraw_later(win, UPD_NOT_VALID); } else { changed_window_setting(win); } } - if (flags & P_RBUF) { + if (flags & kOptFlagRedrBuf) { redraw_buf_later(buf, UPD_NOT_VALID); } if (all) { @@ -3466,7 +3466,7 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value errmsg = e_unsupportedoption; } // Disallow changing some options from secure mode. - else if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) { + else if ((secure || sandbox != 0) && (opt->flags & kOptFlagSecure)) { errmsg = e_secure; } // Check for a "normal" directory or file name in some string options. @@ -3567,7 +3567,8 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value } if (curwin->w_curswant != MAXCOL - && (opt->flags & (P_CURSWANT | P_RALL)) != 0 && (opt->flags & P_HLONLY) == 0) { + && (opt->flags & (kOptFlagCurswant | kOptFlagRedrAll)) != 0 + && (opt->flags & kOptFlagHLOnly) == 0) { curwin->w_set_curswant = true; } @@ -3575,14 +3576,14 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value if (errmsg == NULL) { uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); - opt->flags |= P_WAS_SET; + opt->flags |= kOptFlagWasSet; - // When an option is set in the sandbox, from a modeline or in secure mode set the P_INSECURE + // When an option is set in the sandbox, from a modeline or in secure mode set the kOptFlagInsecure // flag. Otherwise, if a new value is stored reset the flag. if (!value_checked && (secure || sandbox != 0 || (opt_flags & OPT_MODELINE))) { - *p |= P_INSECURE; + *p |= kOptFlagInsecure; } else if (value_replaced) { - *p &= ~P_INSECURE; + *p &= ~(unsigned)kOptFlagInsecure; } } @@ -3700,9 +3701,9 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, const int secure_saved = secure; // When an option is set in the sandbox, from a modeline or in secure mode, then deal with side - // effects in secure mode. Also when the value was set with the P_INSECURE flag and is not + // effects in secure mode. Also when the value was set with the kOptFlagInsecure flag and is not // completely replaced. - if ((opt_flags & OPT_MODELINE) || sandbox != 0 || (!value_replaced && (*p & P_INSECURE))) { + if ((opt_flags & OPT_MODELINE) || sandbox != 0 || (!value_replaced && (*p & kOptFlagInsecure))) { secure = 1; } @@ -3719,7 +3720,7 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, apply_optionset_autocmd(opt_idx, opt_flags, saved_used_value, saved_old_global_value, saved_old_local_value, saved_new_value, errmsg); } - if (opt->flags & P_UI_OPTION) { + if (opt->flags & kOptFlagUIOption) { ui_call_option_set(cstr_as_string(opt->fullname), optval_as_object(saved_new_value)); } } @@ -3812,7 +3813,7 @@ const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt uint32_t flags = options[opt_idx].flags; // Disallow changing some options in the sandbox - if (sandbox > 0 && (flags & P_SECURE)) { + if (sandbox > 0 && (flags & kOptFlagSecure)) { return _(e_sandbox); } @@ -4050,7 +4051,7 @@ OptVal get_option_value_strict(OptIndex opt_idx, OptReqScope req_scope, void *fr /// Get option value for buffer / window. /// /// @param opt_idx Option index in options[] table. -/// @param[out] flagsp Set to the option flags (P_xxxx) (if not NULL). +/// @param[out] flagsp Set to the option flags (see OptFlags) (if not NULL). /// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination). /// @param[out] hidden Whether option is hidden. /// @param req_scope Requested option scope. See OptReqScope in option.h. @@ -4227,7 +4228,7 @@ void ui_refresh_options(void) { for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { uint32_t flags = options[opt_idx].flags; - if (!(flags & P_UI_OPTION)) { + if (!(flags & kOptFlagUIOption)) { continue; } String name = cstr_as_string(options[opt_idx].fullname); @@ -4302,14 +4303,14 @@ int makeset(FILE *fd, int opt_flags, int local_only) // - Hidden options. // // Do the loop over "options[]" twice: once for options with the - // P_PRI_MKRC flag and once without. + // kOptFlagPriMkrc flag and once without. for (int pri = 1; pri >= 0; pri--) { vimoption_T *opt; for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { opt = &options[opt_idx]; - if (!(opt->flags & P_NO_MKRC) - && ((pri == 1) == ((opt->flags & P_PRI_MKRC) != 0))) { + if (!(opt->flags & kOptFlagNoMkrc) + && ((pri == 1) == ((opt->flags & kOptFlagPriMkrc) != 0))) { // skip global option when only doing locals if (opt->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) { continue; @@ -4317,7 +4318,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) // Do not store options like 'bufhidden' and 'syntax' in a vimrc // file, they are always buffer-specific. - if ((opt_flags & OPT_GLOBAL) && (opt->flags & P_NOGLOB)) { + if ((opt_flags & OPT_GLOBAL) && (opt->flags & kOptFlagNoGlob)) { continue; } @@ -4432,7 +4433,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ char *part = NULL; if (*valuep != NULL) { - if ((flags & P_EXPAND) != 0) { + if ((flags & kOptFlagExpand) != 0) { size_t size = (size_t)strlen(*valuep) + 1; // replace home directory in the whole option value into "buf" @@ -4442,7 +4443,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ // If the option value is longer than MAXPATHL, we need to append // each comma separated part of the option separately, so that it // can be expanded when read back. - if (size >= MAXPATHL && (flags & P_COMMA) != 0 + if (size >= MAXPATHL && (flags & kOptFlagComma) != 0 && vim_strchr(*valuep, ',') != NULL) { part = xmalloc(size); @@ -5574,8 +5575,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) // Only string options below - // Options that have P_EXPAND are considered to all use file/dir expansion. - if (flags & P_EXPAND) { + // Options that have kOptFlagExpand are considered to all use file/dir expansion. + if (flags & kOptFlagExpand) { p = options[opt_idx].var; if (p == (char *)&p_bdir || p == (char *)&p_dir @@ -5599,7 +5600,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) xp->xp_backslash = XP_BS_ONE; } } - if (flags & P_COMMA) { + if (flags & kOptFlagComma) { xp->xp_backslash |= XP_BS_COMMA; } } @@ -5609,21 +5610,21 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) // pattern, while accounting for backslash-escaped space/commas/colons. // Triple-backslashed escaped file names (e.g. 'path') can also be // delimited by space. - if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) { + if ((flags & kOptFlagExpand) || (flags & kOptFlagComma) || (flags & kOptFlagColon)) { for (p = argend - 1; p > xp->xp_pattern; p--) { // count number of backslashes before ' ' or ',' - if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) { + if (*p == ' ' || *p == ',' || (*p == ':' && (flags & kOptFlagColon))) { char *s = p; while (s > xp->xp_pattern && *(s - 1) == '\\') { s--; } if ((*p == ' ' && ((xp->xp_backslash & XP_BS_THREE) && (p - s) < 3)) #if defined(BACKSLASH_IN_FILENAME) - || (*p == ',' && (flags & P_COMMA) && (p - s) < 1) + || (*p == ',' && (flags & kOptFlagComma) && (p - s) < 1) #else - || (*p == ',' && (flags & P_COMMA) && (p - s) < 2) + || (*p == ',' && (flags & kOptFlagComma) && (p - s) < 2) #endif - || (*p == ':' && (flags & P_COLON))) { + || (*p == ':' && (flags & kOptFlagColon))) { xp->xp_pattern = p + 1; break; } @@ -5633,7 +5634,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) // An option that is a list of single-character flags should always start // at the end as we don't complete words. - if (flags & P_FLAGLIST) { + if (flags & kOptFlagFlagList) { xp->xp_pattern = argend; } @@ -5786,7 +5787,7 @@ static char *escape_option_str_cmdline(char *var) for (var = buf; *var != NUL; MB_PTR_ADV(var)) { if (var[0] == '\\' && var[1] == '\\' && expand_option_idx != kOptInvalid - && (options[expand_option_idx].flags & P_EXPAND) + && (options[expand_option_idx].flags & kOptFlagExpand) && vim_isfilec((uint8_t)var[2]) && (var[2] != '\\' || (var == buf && var[4] != '\\'))) { STRMOVE(var, var + 1); @@ -5872,11 +5873,11 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c if (option_has_type(expand_option_idx, kOptValTypeNumber)) { return ExpandOldSetting(numMatches, matches); - } else if (option_flags & P_COMMA) { + } else if (option_flags & kOptFlagComma) { // Split the option by comma, then present each option to the user if // it matches the pattern. // This condition needs to go first, because 'whichwrap' has both - // P_COMMA and P_FLAGLIST. + // kOptFlagComma and kOptFlagFlagList. if (*option_val == NUL) { return FAIL; @@ -5923,7 +5924,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c *matches = ga.ga_data; *numMatches = ga.ga_len; return OK; - } else if (option_flags & P_FLAGLIST) { + } else if (option_flags & kOptFlagFlagList) { // Only present the flags that are set on the option as the other flags // are not meaningful to do set-= on. @@ -5988,7 +5989,7 @@ static void option_value2string(vimoption_T *opt, int scope) varp = *(char **)(varp); if (varp == NULL) { // Just in case. NameBuff[0] = NUL; - } else if (opt->flags & P_EXPAND) { + } else if (opt->flags & kOptFlagExpand) { home_replace(NULL, varp, NameBuff, MAXPATHL, false); } else { xstrlcpy(NameBuff, varp, MAXPATHL); @@ -6049,7 +6050,7 @@ void vimrc_found(char *fname, char *envname) bool option_was_set(OptIndex opt_idx) { assert(opt_idx != kOptInvalid); - return options[opt_idx].flags & P_WAS_SET; + return options[opt_idx].flags & kOptFlagWasSet; } /// Reset the flag indicating option "name" was set. @@ -6058,7 +6059,7 @@ bool option_was_set(OptIndex opt_idx) void reset_option_was_set(OptIndex opt_idx) { assert(opt_idx != kOptInvalid); - options[opt_idx].flags &= ~P_WAS_SET; + options[opt_idx].flags &= ~(unsigned)kOptFlagWasSet; } /// fill_culopt_flags() -- called when 'culopt' changes value @@ -6456,10 +6457,10 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w // welcome to the jungle PUT_C(dict, "global_local", BOOLEAN_OBJ(opt->indir & PV_BOTH)); - PUT_C(dict, "commalist", BOOLEAN_OBJ(opt->flags & P_COMMA)); - PUT_C(dict, "flaglist", BOOLEAN_OBJ(opt->flags & P_FLAGLIST)); + PUT_C(dict, "commalist", BOOLEAN_OBJ(opt->flags & kOptFlagComma)); + PUT_C(dict, "flaglist", BOOLEAN_OBJ(opt->flags & kOptFlagFlagList)); - PUT_C(dict, "was_set", BOOLEAN_OBJ(opt->flags & P_WAS_SET)); + PUT_C(dict, "was_set", BOOLEAN_OBJ(opt->flags & kOptFlagWasSet)); LastSet last_set = { .channel_id = 0 }; if (req_scope == OPT_GLOBAL) { @@ -6483,7 +6484,7 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(option_get_type(get_opt_idx(opt))))); PUT_C(dict, "default", optval_as_object(opt->def_val)); - PUT_C(dict, "allows_duplicates", BOOLEAN_OBJ(!(opt->flags & P_NODUP))); + PUT_C(dict, "allows_duplicates", BOOLEAN_OBJ(!(opt->flags & kOptFlagNoDup))); return dict; } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index ae9ccd371c..e32edbf727 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -11,6 +11,40 @@ # include "options_enum.generated.h" #endif +/// Option flags. +typedef enum { + kOptFlagExpand = 1 << 0, ///< Environment expansion. + ///< NOTE: kOptFlagExpand can never be used for local or hidden options. + kOptFlagNoDefExp = 1 << 1, ///< Don't expand default value. + kOptFlagNoDefault = 1 << 2, ///< Don't set to default value. + kOptFlagWasSet = 1 << 3, ///< Option has been set/reset. + kOptFlagNoMkrc = 1 << 4, ///< Don't include in :mkvimrc output. + kOptFlagUIOption = 1 << 5, ///< Send option to remote UI. + kOptFlagRedrTabl = 1 << 6, ///< Redraw tabline. + kOptFlagRedrStat = 1 << 7, ///< Redraw status lines. + kOptFlagRedrWin = 1 << 8, ///< Redraw current window and recompute text. + kOptFlagRedrBuf = 1 << 9, ///< Redraw current buffer and recompute text. + kOptFlagRedrAll = kOptFlagRedrBuf | kOptFlagRedrWin, ///< Redraw all windows and recompute text. + kOptFlagRedrClear = kOptFlagRedrAll | kOptFlagRedrStat, ///< Clear and redraw all and recompute text. + kOptFlagComma = 1 << 10, ///< Comma-separated list. + kOptFlagOneComma = (1 << 11) | kOptFlagComma, ///< Comma-separated list that cannot have two consecutive commas. + kOptFlagNoDup = 1 << 12, ///< Don't allow duplicate strings. + kOptFlagFlagList = 1 << 13, ///< List of single-char flags. + kOptFlagSecure = 1 << 14, ///< Cannot change in modeline or secure mode. + kOptFlagGettext = 1 << 15, ///< Expand default value with _(). + kOptFlagNoGlob = 1 << 16, ///< Do not use local value for global vimrc. + kOptFlagNFname = 1 << 17, ///< Only normal file name chars allowed. + kOptFlagInsecure = 1 << 18, ///< Option was set from a modeline. + kOptFlagPriMkrc = 1 << 19, ///< Priority for :mkvimrc (setting option has side effects). + kOptFlagNoML = 1 << 20, ///< Not allowed in modeline. + kOptFlagCurswant = 1 << 21, ///< Update curswant required; not needed when there is a redraw flag. + kOptFlagNDname = 1 << 22, ///< Only normal directory name chars allowed. + kOptFlagHLOnly = 1 << 23, ///< Option only changes highlight, not text. + kOptFlagMLE = 1 << 24, ///< Under control of 'modelineexpr'. + kOptFlagFunc = 1 << 25, ///< Accept a function reference or a lambda. + kOptFlagColon = 1 << 26, ///< Values use colons to create sublists. +} OptFlags; + /// Option value type. /// These types are also used as type flags by using the type value as an index for the type_flags /// bit field (@see option_has_type()). @@ -62,7 +96,7 @@ typedef struct { /// New value of the option. OptValData os_newval; - /// Option value was checked to be safe, no need to set P_INSECURE + /// Option value was checked to be safe, no need to set kOptFlagInsecure /// Used for the 'keymap', 'filetype' and 'syntax' options. bool os_value_checked; /// Option value changed. Used for the 'filetype' and 'syntax' options. diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index 24ec78ec61..5b630117ab 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -7,47 +7,6 @@ // option_vars.h: definition of global variables for settable options -// Option Flags -// #define P_ALLOCED 0x01U ///< Not used -#define P_EXPAND 0x02U ///< environment expansion. NOTE: P_EXPAND can - ///< never be used for local or hidden options -#define P_NO_DEF_EXP 0x04U ///< do not expand default value -#define P_NODEFAULT 0x08U ///< don't set to default value -// #define P_DEF_ALLOCED 0x10U ///< Not used -#define P_WAS_SET 0x20U ///< option has been set/reset -#define P_NO_MKRC 0x40U ///< don't include in :mkvimrc output - -// when option changed, what to display: -#define P_UI_OPTION 0x80U ///< send option to remote UI -#define P_RTABL 0x100U ///< redraw tabline -#define P_RSTAT 0x200U ///< redraw status lines -#define P_RWIN 0x400U ///< redraw current window and recompute text -#define P_RBUF 0x800U ///< redraw current buffer and recompute text -#define P_RALL 0xC00U ///< redraw all windows and recompute text -#define P_RCLR 0xE00U ///< clear and redraw all and recompute text - -#define P_COMMA 0x1000U ///< comma separated list -#define P_ONECOMMA 0x3000U ///< P_COMMA and cannot have two consecutive - ///< commas -#define P_NODUP 0x4000U ///< don't allow duplicate strings -#define P_FLAGLIST 0x8000U ///< list of single-char flags - -#define P_SECURE 0x10000U ///< cannot change in modeline or secure mode -#define P_GETTEXT 0x20000U ///< expand default value with _() -#define P_NOGLOB 0x40000U ///< do not use local value for global vimrc -#define P_NFNAME 0x80000U ///< only normal file name chars allowed -#define P_INSECURE 0x100000U ///< option was set from a modeline -#define P_PRI_MKRC 0x200000U ///< priority for :mkvimrc (setting option - ///< has side effects) -#define P_NO_ML 0x400000U ///< not allowed in modeline -#define P_CURSWANT 0x800000U ///< update curswant required; not needed - ///< when there is a redraw flag -#define P_NDNAME 0x1000000U ///< only normal dir name chars allowed -#define P_HLONLY 0x2000000U ///< option only changes highlight, not text -#define P_MLE 0x4000000U ///< under control of 'modelineexpr' -#define P_FUNC 0x8000000U ///< accept a function reference or a lambda -#define P_COLON 0x10000000U ///< values use colons to create sublists - #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \ "i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow," \ diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 651a9d20bf..e07fcf2f0e 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -419,9 +419,9 @@ const char *check_stl_option(char *s) /// often illegal in a file name. Be more permissive if "secure" is off. bool check_illegal_path_names(char *val, uint32_t flags) { - return (((flags & P_NFNAME) + return (((flags & kOptFlagNFname) && strpbrk(val, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) - || ((flags & P_NDNAME) + || ((flags & kOptFlagNDname) && strpbrk(val, "*?[|;&<>\r\n") != NULL)); } @@ -1377,7 +1377,7 @@ const char *did_set_filetype_or_syntax(optset_T *args) args->os_value_changed = strcmp(args->os_oldval.string.data, *varp) != 0; - // Since we check the value, there is no need to set P_INSECURE, + // Since we check the value, there is no need to set kOptFlagInsecure, // even when the value comes from a modeline. args->os_value_checked = true; @@ -1658,7 +1658,7 @@ const char *did_set_keymap(optset_T *args) secure = secure_save; - // Since we check the value, there is no need to set P_INSECURE, + // Since we check the value, there is no need to set kOptFlagInsecure, // even when the value comes from a modeline. args->os_value_checked = true; -- cgit From 42fa3d080ec170b7927e36ec563efdd526c712d7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 29 Oct 2024 07:57:25 +0800 Subject: refactor: sort various Lua tables in src/ alphabetically (#30977) --- src/nvim/auevents.lua | 6 +- src/nvim/eval.lua | 76 +++++++-------- src/nvim/vvars.lua | 258 +++++++++++++++++++++++++------------------------- 3 files changed, 170 insertions(+), 170 deletions(-) (limited to 'src') diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index e61f1a8ce2..84735c293a 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -73,10 +73,10 @@ return { 'InsertLeavePre', -- just before leaving Insert mode 'LspAttach', -- after an LSP client attaches to a buffer 'LspDetach', -- after an LSP client detaches from a buffer - 'LspRequest', -- after an LSP request is started, canceled, or completed 'LspNotify', -- after an LSP notice has been sent to the server - 'LspTokenUpdate', -- after a visible LSP token is updated 'LspProgress', -- after a LSP progress update + 'LspRequest', -- after an LSP request is started, canceled, or completed + 'LspTokenUpdate', -- after a visible LSP token is updated 'MenuPopup', -- just before popup menu is displayed 'ModeChanged', -- after changing the mode 'OptionSet', -- after setting any option @@ -160,8 +160,8 @@ return { LspAttach = true, LspDetach = true, LspNotify = true, - LspRequest = true, LspProgress = true, + LspRequest = true, LspTokenUpdate = true, RecordingEnter = true, RecordingLeave = true, diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 5125bd0b88..34045c7c9d 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -11015,6 +11015,44 @@ M.funcs = { params = { { 'expr', 'number' } }, signature = 'srand([{expr}])', }, + state = { + args = { 0, 1 }, + base = 1, + desc = [=[ + Return a string which contains characters indicating the + current state. Mostly useful in callbacks that want to do + work that may not always be safe. Roughly this works like: + - callback uses state() to check if work is safe to do. + Yes: then do it right away. + No: add to work queue and add a |SafeState| autocommand. + - When SafeState is triggered and executes your autocommand, + check with `state()` if the work can be done now, and if yes + remove it from the queue and execute. + Remove the autocommand if the queue is now empty. + Also see |mode()|. + + When {what} is given only characters in this string will be + added. E.g, this checks if the screen has scrolled: >vim + if state('s') == '' + " screen has not scrolled + < + These characters indicate the state, generally indicating that + something is busy: + m halfway a mapping, :normal command, feedkeys() or + stuffed command + o operator pending, e.g. after |d| + a Insert mode autocomplete active + x executing an autocommand + S not triggering SafeState, e.g. after |f| or a count + c callback invoked, including timer (repeats for + recursiveness up to "ccc") + s screen has scrolled for messages + ]=], + fast = true, + name = 'state', + params = { { 'what', 'string' } }, + signature = 'state([{what}])', + }, stdioopen = { args = 1, desc = [=[ @@ -11073,44 +11111,6 @@ M.funcs = { returns = 'string|string[]', signature = 'stdpath({what})', }, - state = { - args = { 0, 1 }, - base = 1, - desc = [=[ - Return a string which contains characters indicating the - current state. Mostly useful in callbacks that want to do - work that may not always be safe. Roughly this works like: - - callback uses state() to check if work is safe to do. - Yes: then do it right away. - No: add to work queue and add a |SafeState| autocommand. - - When SafeState is triggered and executes your autocommand, - check with `state()` if the work can be done now, and if yes - remove it from the queue and execute. - Remove the autocommand if the queue is now empty. - Also see |mode()|. - - When {what} is given only characters in this string will be - added. E.g, this checks if the screen has scrolled: >vim - if state('s') == '' - " screen has not scrolled - < - These characters indicate the state, generally indicating that - something is busy: - m halfway a mapping, :normal command, feedkeys() or - stuffed command - o operator pending, e.g. after |d| - a Insert mode autocomplete active - x executing an autocommand - S not triggering SafeState, e.g. after |f| or a count - c callback invoked, including timer (repeats for - recursiveness up to "ccc") - s screen has scrolled for messages - ]=], - fast = true, - name = 'state', - params = { { 'what', 'string' } }, - signature = 'state([{what}])', - }, str2float = { args = 1, base = 1, diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index 2f43f8b32b..ad139bbbfe 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -41,6 +41,15 @@ M.vars = { included here, because it will be executed anyway. ]=], }, + cmdbang = { + type = 'integer', + desc = [=[ + Set like v:cmdarg for a file read/write command. When a "!" + was used the value is 1, otherwise it is 0. Note that this + can only be used in autocommands. For user commands || + can be used. + ]=], + }, collate = { type = 'string', desc = [=[ @@ -53,15 +62,6 @@ M.vars = { See |multi-lang|. ]=], }, - cmdbang = { - type = 'integer', - desc = [=[ - Set like v:cmdarg for a file read/write command. When a "!" - was used the value is 1, otherwise it is 0. Note that this - can only be used in autocommands. For user commands || - can be used. - ]=], - }, completed_item = { desc = [=[ Dictionary containing the |complete-items| for the most @@ -118,15 +118,6 @@ M.vars = { VimLeave autocommands will not be executed. ]=], }, - exiting = { - desc = [=[ - Exit code, or |v:null| before invoking the |VimLeavePre| - and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|. - Example: >vim - :au VimLeave * echo "Exit value is " .. v:exiting - < - ]=], - }, echospace = { type = 'integer', desc = [=[ @@ -243,18 +234,13 @@ M.vars = { or |expr7| when used with numeric operators). Read-only. ]=], }, - fcs_reason = { - type = 'string', + exiting = { desc = [=[ - The reason why the |FileChangedShell| event was triggered. - Can be used in an autocommand to decide what to do and/or what - to set v:fcs_choice to. Possible values: - deleted file no longer exists - conflict file contents, mode or timestamp was - changed and buffer is modified - changed file contents has changed - mode mode of file changed - time only file timestamp changed + Exit code, or |v:null| before invoking the |VimLeavePre| + and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|. + Example: >vim + :au VimLeave * echo "Exit value is " .. v:exiting + < ]=], }, fcs_choice = { @@ -280,6 +266,20 @@ M.vars = { Vim behaves like it is empty, there is no warning message. ]=], }, + fcs_reason = { + type = 'string', + desc = [=[ + The reason why the |FileChangedShell| event was triggered. + Can be used in an autocommand to decide what to do and/or what + to set v:fcs_choice to. Possible values: + deleted file no longer exists + conflict file contents, mode or timestamp was + changed and buffer is modified + changed file contents has changed + mode mode of file changed + time only file timestamp changed + ]=], + }, fname = { type = 'string', desc = [=[ @@ -287,6 +287,13 @@ M.vars = { detected. Empty otherwise. ]=], }, + fname_diff = { + type = 'string', + desc = [=[ + The name of the diff (patch) file. Only valid while + evaluating 'patchexpr'. + ]=], + }, fname_in = { type = 'string', desc = [=[ @@ -298,6 +305,13 @@ M.vars = { And set to the swap file name for |SwapExists|. ]=], }, + fname_new = { + type = 'string', + desc = [=[ + The name of the new version of the file. Only valid while + evaluating 'diffexpr'. + ]=], + }, fname_out = { type = 'string', desc = [=[ @@ -313,20 +327,6 @@ M.vars = { file and different from v:fname_in. ]=], }, - fname_new = { - type = 'string', - desc = [=[ - The name of the new version of the file. Only valid while - evaluating 'diffexpr'. - ]=], - }, - fname_diff = { - type = 'string', - desc = [=[ - The name of the diff (patch) file. Only valid while - evaluating 'patchexpr'. - ]=], - }, folddashes = { type = 'string', desc = [=[ @@ -335,17 +335,17 @@ M.vars = { Read-only in the |sandbox|. |fold-foldtext| ]=], }, - foldlevel = { + foldend = { type = 'integer', desc = [=[ - Used for 'foldtext': foldlevel of closed fold. + Used for 'foldtext': last line of closed fold. Read-only in the |sandbox|. |fold-foldtext| ]=], }, - foldend = { + foldlevel = { type = 'integer', desc = [=[ - Used for 'foldtext': last line of closed fold. + Used for 'foldtext': foldlevel of closed fold. Read-only in the |sandbox|. |fold-foldtext| ]=], }, @@ -435,19 +435,12 @@ M.vars = { 2147483647 on all systems. ]=], }, - mouse_win = { - type = 'integer', - desc = [=[ - Window number for a mouse click obtained with |getchar()|. - First window has number 1, like with |winnr()|. The value is - zero when there was no mouse button click. - ]=], - }, - mouse_winid = { + mouse_col = { type = 'integer', desc = [=[ - |window-ID| for a mouse click obtained with |getchar()|. - The value is zero when there was no mouse button click. + Column number for a mouse click obtained with |getchar()|. + This is the screen column number, like with |virtcol()|. The + value is zero when there was no mouse button click. ]=], }, mouse_lnum = { @@ -458,12 +451,19 @@ M.vars = { value is zero when there was no mouse button click. ]=], }, - mouse_col = { + mouse_win = { type = 'integer', desc = [=[ - Column number for a mouse click obtained with |getchar()|. - This is the screen column number, like with |virtcol()|. The - value is zero when there was no mouse button click. + Window number for a mouse click obtained with |getchar()|. + First window has number 1, like with |winnr()|. The value is + zero when there was no mouse button click. + ]=], + }, + mouse_winid = { + type = 'integer', + desc = [=[ + |window-ID| for a mouse click obtained with |getchar()|. + The value is zero when there was no mouse button click. ]=], }, msgpack_types = { @@ -516,6 +516,35 @@ M.vars = { than String this will cause trouble. ]=], }, + operator = { + type = 'string', + desc = [=[ + The last operator given in Normal mode. This is a single + character except for commands starting with or , + in which case it is two characters. Best used alongside + |v:prevcount| and |v:register|. Useful if you want to cancel + Operator-pending mode and then use the operator, e.g.: >vim + :omap O :call MyMotion(v:operator) + < + The value remains set until another operator is entered, thus + don't expect it to be empty. + v:operator is not set for |:delete|, |:yank| or other Ex + commands. + Read-only. + ]=], + }, + option_command = { + type = 'string', + desc = [=[ + Command used to set the option. Valid while executing an + |OptionSet| autocommand. + value option was set via ~ + "setlocal" |:setlocal| or `:let l:xxx` + "setglobal" |:setglobal| or `:let g:xxx` + "set" |:set| or |:let| + "modeline" |modeline| + ]=], + }, option_new = { desc = [=[ New value of the option. Valid while executing an |OptionSet| @@ -530,15 +559,15 @@ M.vars = { global old value. ]=], }, - option_oldlocal = { + option_oldglobal = { desc = [=[ - Old local value of the option. Valid while executing an + Old global value of the option. Valid while executing an |OptionSet| autocommand. ]=], }, - option_oldglobal = { + option_oldlocal = { desc = [=[ - Old global value of the option. Valid while executing an + Old local value of the option. Valid while executing an |OptionSet| autocommand. ]=], }, @@ -549,35 +578,6 @@ M.vars = { |OptionSet| autocommand. Can be either "global" or "local" ]=], }, - option_command = { - type = 'string', - desc = [=[ - Command used to set the option. Valid while executing an - |OptionSet| autocommand. - value option was set via ~ - "setlocal" |:setlocal| or `:let l:xxx` - "setglobal" |:setglobal| or `:let g:xxx` - "set" |:set| or |:let| - "modeline" |modeline| - ]=], - }, - operator = { - type = 'string', - desc = [=[ - The last operator given in Normal mode. This is a single - character except for commands starting with or , - in which case it is two characters. Best used alongside - |v:prevcount| and |v:register|. Useful if you want to cancel - Operator-pending mode and then use the operator, e.g.: >vim - :omap O :call MyMotion(v:operator) - < - The value remains set until another operator is entered, thus - don't expect it to be empty. - v:operator is not set for |:delete|, |:yank| or other Ex - commands. - Read-only. - ]=], - }, prevcount = { type = 'integer', desc = [=[ @@ -641,6 +641,17 @@ M.vars = { hit-enter prompt. ]=], }, + searchforward = { + type = 'integer', + desc = [=[ + Search direction: 1 after a forward search, 0 after a + backward search. It is reset to forward when directly setting + the last search pattern, see |quote/|. + Note that the value is restored when returning from a + function. |function-search-undo|. + Read-write. + ]=], + }, servername = { type = 'string', desc = [=[ @@ -664,17 +675,6 @@ M.vars = { Note the contents of $NVIM may change in the future. ]=], }, - searchforward = { - type = 'integer', - desc = [=[ - Search direction: 1 after a forward search, 0 after a - backward search. It is reset to forward when directly setting - the last search pattern, see |quote/|. - Note that the value is restored when returning from a - function. |function-search-undo|. - Read-write. - ]=], - }, shell_error = { type = 'integer', desc = [=[ @@ -709,14 +709,6 @@ M.vars = { < ]=], }, - swapname = { - type = 'string', - desc = [=[ - Name of the swapfile found. - Only valid during |SwapExists| event. - Read-only. - ]=], - }, swapchoice = { type = 'string', desc = [=[ @@ -743,6 +735,14 @@ M.vars = { For ":edit +cmd file" the value is ":cmd\r". ]=], }, + swapname = { + type = 'string', + desc = [=[ + Name of the swapfile found. + Only valid during |SwapExists| event. + Read-only. + ]=], + }, t_blob = { type = 'integer', tags = { 'v:t_TYPE' }, @@ -776,22 +776,22 @@ M.vars = { type = 'integer', desc = 'Value of |String| type. Read-only. See: |type()|', }, - termresponse = { + termrequest = { type = 'string', desc = [=[ The value of the most recent OSC or DCS control sequence - received by Nvim from the terminal. This can be read in a - |TermResponse| event handler after querying the terminal using - another escape sequence. + sent from a process running in the embedded |terminal|. + This can be read in a |TermRequest| event handler to respond + to queries from embedded applications. ]=], }, - termrequest = { + termresponse = { type = 'string', desc = [=[ The value of the most recent OSC or DCS control sequence - sent from a process running in the embedded |terminal|. - This can be read in a |TermRequest| event handler to respond - to queries from embedded applications. + received by Nvim from the terminal. This can be read in a + |TermResponse| event handler after querying the terminal using + another escape sequence. ]=], }, testing = { @@ -849,20 +849,20 @@ M.vars = { < ]=], }, - virtnum = { + vim_did_enter = { type = 'integer', desc = [=[ - Virtual line number for the 'statuscolumn' expression. - Negative when drawing the status column for virtual lines, zero - when drawing an actual buffer line, and positive when drawing - the wrapped part of a buffer line. + 0 during startup, 1 just before |VimEnter|. Read-only. ]=], }, - vim_did_enter = { + virtnum = { type = 'integer', desc = [=[ - 0 during startup, 1 just before |VimEnter|. + Virtual line number for the 'statuscolumn' expression. + Negative when drawing the status column for virtual lines, zero + when drawing an actual buffer line, and positive when drawing + the wrapped part of a buffer line. Read-only. ]=], }, -- cgit From 378d9135e7ac0f91a4944be816dc9f693d5078af Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 28 Oct 2024 15:14:15 +0800 Subject: vim-patch:9.1.0810: cannot easily adjust the |:find| command Problem: cannot easily adjust the |:find| command Solution: Add support for the 'findexpr' option (Yegappan Lakshmanan) closes: vim/vim#15901 closes: vim/vim#15905 https://github.com/vim/vim/commit/aeb1c97db5b9de4f4903e7f288f2aa5ad6c49440 Co-authored-by: Yegappan Lakshmanan --- src/nvim/buffer.c | 1 + src/nvim/buffer_defs.h | 1 + src/nvim/errors.h | 5 ++ src/nvim/eval.c | 2 +- src/nvim/ex_docmd.c | 137 +++++++++++++++++++++++++++++++++++++++++-------- src/nvim/file_search.c | 8 +-- src/nvim/option.c | 15 ++++++ src/nvim/option_vars.h | 1 + src/nvim/options.lua | 53 +++++++++++++++++++ src/nvim/optionstr.c | 6 ++- src/nvim/vvars.lua | 3 +- 11 files changed, 202 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 2142b5b298..42cc745fe6 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2049,6 +2049,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff) clear_string_option(&buf->b_p_indk); clear_string_option(&buf->b_p_fp); clear_string_option(&buf->b_p_fex); + clear_string_option(&buf->b_p_fexpr); clear_string_option(&buf->b_p_kp); clear_string_option(&buf->b_p_mps); clear_string_option(&buf->b_p_fo); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 134d69de96..88e8d59faa 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -608,6 +608,7 @@ struct file_buffer { char *b_p_mp; ///< 'makeprg' local value char *b_p_efm; ///< 'errorformat' local value char *b_p_ep; ///< 'equalprg' local value + char *b_p_fexpr; ///< 'findexpr' local value char *b_p_path; ///< 'path' local value int b_p_ar; ///< 'autoread' local value char *b_p_tags; ///< 'tags' local value diff --git a/src/nvim/errors.h b/src/nvim/errors.h index 39095db952..bea56541a2 100644 --- a/src/nvim/errors.h +++ b/src/nvim/errors.h @@ -156,6 +156,11 @@ EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called i EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); +EXTERN const char e_cant_find_directory_str_in_cdpath[] INIT(= N_("E344: Can't find directory \"%s\" in cdpath")); +EXTERN const char e_cant_find_file_str_in_path[] INIT(= N_("E345: Can't find file \"%s\" in path")); +EXTERN const char e_no_more_directory_str_found_in_cdpath[] INIT(= N_("E346: No more directory \"%s\" found in cdpath")); +EXTERN const char e_no_more_file_str_found_in_path[] INIT(= N_("E347: No more file \"%s\" found in path")); + EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 93cff80bd4..6a455f70a6 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2631,7 +2631,7 @@ static int may_call_simple_func(const char *arg, typval_T *rettv) /// Handle zero level expression with optimization for a simple function call. /// Same arguments and return value as eval0(). -static int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) +int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) { int r = may_call_simple_func(arg, rettv); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 293aaac036..5c61399003 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5165,6 +5165,90 @@ static void ex_wrongmodifier(exarg_T *eap) eap->errmsg = _(e_invcmd); } +/// Evaluate the 'findexpr' expression and return the result. When evaluating +/// the expression, v:fname is set to the ":find" command argument. +static list_T *eval_findexpr(const char *ptr, size_t len) +{ + const sctx_T saved_sctx = current_sctx; + bool use_sandbox = false; + + char *findexpr; + if (*curbuf->b_p_fexpr == NUL) { + use_sandbox = was_set_insecurely(curwin, kOptFindexpr, OPT_GLOBAL); + findexpr = p_fexpr; + } else { + use_sandbox = was_set_insecurely(curwin, kOptFindexpr, OPT_LOCAL); + findexpr = curbuf->b_p_fexpr; + } + + set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); + current_sctx = curbuf->b_p_script_ctx[BV_FEXPR].script_ctx; + + char *arg = skipwhite(findexpr); + + if (use_sandbox) { + sandbox++; + } + textlock++; + + // Evaluate the expression. If the expression is "FuncName()" call the + // function directly. + typval_T tv; + list_T *retlist = NULL; + if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { + retlist = NULL; + } else { + if (tv.v_type == VAR_LIST) { + retlist = tv_list_copy(NULL, tv.vval.v_list, true, get_copyID()); + } + tv_clear(&tv); + } + if (use_sandbox) { + sandbox--; + } + textlock--; + clear_evalarg(&EVALARG_EVALUATE, NULL); + + set_vim_var_string(VV_FNAME, NULL, 0); + current_sctx = saved_sctx; + + return retlist; +} + +/// Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find +/// the n'th matching file. +static char *findexpr_find_file(char *findarg, size_t findarg_len, int count) +{ + char *ret_fname = NULL; + + const char cc = findarg[findarg_len]; + findarg[findarg_len] = NUL; + + list_T *fname_list = eval_findexpr(findarg, findarg_len); + int fname_count = tv_list_len(fname_list); + + if (fname_count == 0) { + semsg(_(e_cant_find_file_str_in_path), findarg); + } else { + if (count > fname_count) { + semsg(_(e_no_more_file_str_found_in_path), findarg); + } else { + listitem_T *li = tv_list_find(fname_list, count - 1); + if (li != NULL && TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) { + ret_fname = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string); + } + } + } + + if (fname_list != NULL) { + tv_list_free(fname_list); + } + + findarg[findarg_len] = cc; + + return ret_fname; +} + /// :sview [+command] file split window with new file, read-only /// :split [[+command] file] split window with current or new file /// :vsplit [[+command] file] split window vertically with current or new file @@ -5196,13 +5280,17 @@ void ex_splitview(exarg_T *eap) } if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { - char *file_to_find = NULL; - char *search_ctx = NULL; - fname = find_file_in_path(eap->arg, strlen(eap->arg), - FNAME_MESS, true, curbuf->b_ffname, - &file_to_find, &search_ctx); - xfree(file_to_find); - vim_findfile_cleanup(search_ctx); + if (*get_findexpr() != NUL) { + fname = findexpr_find_file(eap->arg, strlen(eap->arg), + eap->addr_count > 0 ? eap->line2 : 1); + } else { + char *file_to_find = NULL; + char *search_ctx = NULL; + fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true, + curbuf->b_ffname, &file_to_find, &search_ctx); + xfree(file_to_find); + vim_findfile_cleanup(search_ctx); + } if (fname == NULL) { goto theend; } @@ -5398,23 +5486,28 @@ static void ex_find(exarg_T *eap) return; } - char *file_to_find = NULL; - char *search_ctx = NULL; - char *fname = find_file_in_path(eap->arg, strlen(eap->arg), - FNAME_MESS, true, curbuf->b_ffname, - &file_to_find, &search_ctx); - if (eap->addr_count > 0) { - // Repeat finding the file "count" times. This matters when it appears - // several times in the path. - linenr_T count = eap->line2; - while (fname != NULL && --count > 0) { - xfree(fname); - fname = find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname, - &file_to_find, &search_ctx); + char *fname = NULL; + if (*get_findexpr() != NUL) { + fname = findexpr_find_file(eap->arg, strlen(eap->arg), + eap->addr_count > 0 ? eap->line2 : 1); + } else { + char *file_to_find = NULL; + char *search_ctx = NULL; + fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true, + curbuf->b_ffname, &file_to_find, &search_ctx); + if (eap->addr_count > 0) { + // Repeat finding the file "count" times. This matters when it appears + // several times in the path. + linenr_T count = eap->line2; + while (fname != NULL && --count > 0) { + xfree(fname); + fname = find_file_in_path(NULL, 0, FNAME_MESS, false, + curbuf->b_ffname, &file_to_find, &search_ctx); + } } + xfree(file_to_find); + vim_findfile_cleanup(search_ctx); } - xfree(file_to_find); - vim_findfile_cleanup(search_ctx); if (fname == NULL) { return; diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index cdfd281718..aeaf448a05 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1489,15 +1489,15 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch if (file_name == NULL && (options & FNAME_MESS)) { if (first == true) { if (find_what == FINDFILE_DIR) { - semsg(_("E344: Can't find directory \"%s\" in cdpath"), *file_to_find); + semsg(_(e_cant_find_directory_str_in_cdpath), *file_to_find); } else { - semsg(_("E345: Can't find file \"%s\" in path"), *file_to_find); + semsg(_(e_cant_find_file_str_in_path), *file_to_find); } } else { if (find_what == FINDFILE_DIR) { - semsg(_("E346: No more directory \"%s\" found in cdpath"), *file_to_find); + semsg(_(e_no_more_directory_str_found_in_cdpath), *file_to_find); } else { - semsg(_("E347: No more file \"%s\" found in path"), *file_to_find); + semsg(_(e_no_more_file_str_found_in_path), *file_to_find); } } } diff --git a/src/nvim/option.c b/src/nvim/option.c index 7c32c99d0e..65f03ca77f 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4530,6 +4530,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) switch ((int)p->indir) { case PV_FP: return &(buf->b_p_fp); + case PV_FEXPR: + return &(buf->b_p_fexpr); case PV_EFM: return &(buf->b_p_efm); case PV_GP: @@ -4651,6 +4653,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var; case PV_FP: return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var; + case PV_FEXPR: + return *buf->b_p_fexpr != NUL ? &(buf->b_p_fexpr) : p->var; case PV_EFM: return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var; case PV_GP: @@ -4922,6 +4926,15 @@ char *get_equalprg(void) return curbuf->b_p_ep; } +/// Get the value of 'findexpr', either the buffer-local one or the global one. +char *get_findexpr(void) +{ + if (*curbuf->b_p_fexpr == NUL) { + return p_fexpr; + } + return curbuf->b_p_fexpr; +} + /// Copy options from one window to another. /// Used when splitting a window. void win_copy_options(win_T *wp_from, win_T *wp_to) @@ -5320,6 +5333,8 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_mp = empty_string_option; buf->b_p_efm = empty_string_option; buf->b_p_ep = empty_string_option; + buf->b_p_fexpr = xstrdup(p_fexpr); + COPY_OPT_SCTX(buf, BV_FEXPR); buf->b_p_kp = empty_string_option; buf->b_p_path = empty_string_option; buf->b_p_tags = empty_string_option; diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index 5b630117ab..a88b51dae7 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -451,6 +451,7 @@ EXTERN char *p_ffs; ///< 'fileformats' EXTERN int p_fic; ///< 'fileignorecase' EXTERN char *p_ft; ///< 'filetype' EXTERN char *p_fcs; ///< 'fillchar' +EXTERN char *p_fexpr; ///< 'findexpr' EXTERN int p_fixeol; ///< 'fixendofline' EXTERN char *p_fcl; ///< 'foldclose' EXTERN OptInt p_fdls; ///< 'foldlevelstart' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index a891d18364..65401fb3a9 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2905,6 +2905,59 @@ return { type = 'string', varname = 'p_fcs', }, + { + abbreviation = 'fexpr', + cb = 'did_set_optexpr', + defaults = { if_true = '' }, + desc = [=[ + Expression that is evaluated to obtain the filename(s) for the |:find| + command. When this option is empty, the internal |file-searching| + mechanism is used. + + While evaluating the expression, the |v:fname| variable is set to the + argument of the |:find| command. + + The expression is evaluated only once per |:find| command invocation. + The expression can process all the directories specified in 'path'. + + If a match is found, the expression should return a |List| containing + one or more file names. If a match is not found, the expression + should return an empty List. + + If any errors are encountered during the expression evaluation, an + empty List is used as the return value. + + Using a function call without arguments is faster |expr-option-function| + + It is not allowed to change text or jump to another window while + evaluating 'findexpr' |textlock|. + + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. + + Examples: + >vim + " Use glob() + func FindExprGlob() + return glob(v:fname, v:false, v:true) + endfunc + set findexpr=FindExprGlob() + + " Use the 'git ls-files' output + func FindGitFiles() + let fnames = systemlist('git ls-files') + return fnames->filter('v:val =~? v:fname') + endfunc + set findexpr=FindGitFiles() + < + ]=], + full_name = 'findexpr', + scope = { 'global', 'buffer' }, + secure = true, + short_desc = N_('expression used for :find'), + type = 'string', + varname = 'p_fexpr', + }, { abbreviation = 'fixeol', cb = 'did_set_eof_eol_fixeol_bomb', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index e07fcf2f0e..c66849800c 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -233,6 +233,7 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_mp); check_string_option(&buf->b_p_efm); check_string_option(&buf->b_p_ep); + check_string_option(&buf->b_p_fexpr); check_string_option(&buf->b_p_path); check_string_option(&buf->b_p_tags); check_string_option(&buf->b_p_tfu); @@ -1885,8 +1886,9 @@ int expand_set_nrformats(optexpand_T *args, int *numMatches, char ***matches) matches); } -/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext', -/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'. +/// One of the '*expr' options is changed:, 'diffexpr', 'findexpr', +/// 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr', +/// 'patchexpr' and 'charconvert'. const char *did_set_optexpr(optset_T *args) { char **varp = (char **)args->os_varp; diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index ad139bbbfe..5c9f0f9e27 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -284,7 +284,8 @@ M.vars = { type = 'string', desc = [=[ When evaluating 'includeexpr': the file name that was - detected. Empty otherwise. + detected. When evaluating 'findexpr': the argument passed to + the |:find| command. Empty otherwise. ]=], }, fname_diff = { -- cgit From 6b8c3d146ec0308fd19a9142b23b5e342e2cdcf8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 28 Oct 2024 16:09:39 +0800 Subject: vim-patch:9.1.0811: :find expansion does not consider 'findexpr' Problem: :find expansion does not consider 'findexpr' Solution: Support expanding :find command argument using 'findexpr' (Yegappan Lakshmanan) closes: vim/vim#15929 https://github.com/vim/vim/commit/2f6efaccfd5c4e7df1f54ed0f41f329abbe05f60 Co-authored-by: Yegappan Lakshmanan --- src/nvim/cmdexpand.c | 30 ++++++++++++---------- src/nvim/errors.h | 1 + src/nvim/ex_docmd.c | 70 ++++++++++++++++++++++++++++++++++++++-------------- src/nvim/options.lua | 1 + 4 files changed, 71 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 549ed826bc..5b7017481e 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -2497,21 +2497,25 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int * } } - if (xp->xp_context == EXPAND_FILES) { - flags |= EW_FILE; - } else if (xp->xp_context == EXPAND_FILES_IN_PATH) { - flags |= (EW_FILE | EW_PATH); - } else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) { - flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE; + int ret = FAIL; + if (xp->xp_context == EXPAND_FILES_IN_PATH && *get_findexpr() != NUL) { + ret = expand_findexpr(pat, matches, numMatches); } else { - flags = (flags | EW_DIR) & ~EW_FILE; - } - if (options & WILD_ICASE) { - flags |= EW_ICASE; + if (xp->xp_context == EXPAND_FILES) { + flags |= EW_FILE; + } else if (xp->xp_context == EXPAND_FILES_IN_PATH) { + flags |= (EW_FILE | EW_PATH); + } else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) { + flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE; + } else { + flags = (flags | EW_DIR) & ~EW_FILE; + } + if (options & WILD_ICASE) { + flags |= EW_ICASE; + } + // Expand wildcards, supporting %:h and the like. + ret = expand_wildcards_eval(&pat, numMatches, matches, flags); } - - // Expand wildcards, supporting %:h and the like. - int ret = expand_wildcards_eval(&pat, numMatches, matches, flags); if (free_pat) { xfree(pat); } diff --git a/src/nvim/errors.h b/src/nvim/errors.h index bea56541a2..6bbec84ff9 100644 --- a/src/nvim/errors.h +++ b/src/nvim/errors.h @@ -186,6 +186,7 @@ INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch") EXTERN const char e_winfixbuf_cannot_go_to_buffer[] INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); +EXTERN const char e_invalid_return_type_from_findexpr[] INIT( = N_("E1514: findexpr did not return a List type")); EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 5c61399003..f89c992cf9 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5167,28 +5167,17 @@ static void ex_wrongmodifier(exarg_T *eap) /// Evaluate the 'findexpr' expression and return the result. When evaluating /// the expression, v:fname is set to the ":find" command argument. -static list_T *eval_findexpr(const char *ptr, size_t len) +static list_T *eval_findexpr(const char *ptr) { const sctx_T saved_sctx = current_sctx; - bool use_sandbox = false; - char *findexpr; - if (*curbuf->b_p_fexpr == NUL) { - use_sandbox = was_set_insecurely(curwin, kOptFindexpr, OPT_GLOBAL); - findexpr = p_fexpr; - } else { - use_sandbox = was_set_insecurely(curwin, kOptFindexpr, OPT_LOCAL); - findexpr = curbuf->b_p_fexpr; - } + char *findexpr = get_findexpr(); - set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); + set_vim_var_string(VV_FNAME, ptr, -1); current_sctx = curbuf->b_p_script_ctx[BV_FEXPR].script_ctx; char *arg = skipwhite(findexpr); - if (use_sandbox) { - sandbox++; - } textlock++; // Evaluate the expression. If the expression is "FuncName()" call the @@ -5200,12 +5189,11 @@ static list_T *eval_findexpr(const char *ptr, size_t len) } else { if (tv.v_type == VAR_LIST) { retlist = tv_list_copy(NULL, tv.vval.v_list, true, get_copyID()); + } else { + emsg(_(e_invalid_return_type_from_findexpr)); } tv_clear(&tv); } - if (use_sandbox) { - sandbox--; - } textlock--; clear_evalarg(&EVALARG_EVALUATE, NULL); @@ -5215,6 +5203,52 @@ static list_T *eval_findexpr(const char *ptr, size_t len) return retlist; } +/// Find file names matching "pat" using 'findexpr' and return it in "files". +/// Used for expanding the :find, :sfind and :tabfind command argument. +/// Returns OK on success and FAIL otherwise. +int expand_findexpr(const char *pat, char ***files, int *numMatches) +{ + *numMatches = 0; + *files = NULL; + + // File name expansion uses wildchars. But the 'findexpr' expression + // expects a regular expression argument. So convert wildchars in the + // argument to regular expression patterns. + char *regpat = file_pat_to_reg_pat(pat, NULL, NULL, false); + if (regpat == NULL) { + return FAIL; + } + + list_T *l = eval_findexpr(regpat); + + xfree(regpat); + + if (l == NULL) { + return FAIL; + } + + int len = tv_list_len(l); + if (len == 0) { // empty List + return FAIL; + } + + *files = xmalloc(sizeof(char *) * (size_t)len); + + // Copy all the List items + int idx = 0; + TV_LIST_ITER_CONST(l, li, { + if (TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) { + (*files)[idx] = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string); + idx++; + } + }); + + *numMatches = idx; + tv_list_free(l); + + return OK; +} + /// Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find /// the n'th matching file. static char *findexpr_find_file(char *findarg, size_t findarg_len, int count) @@ -5224,7 +5258,7 @@ static char *findexpr_find_file(char *findarg, size_t findarg_len, int count) const char cc = findarg[findarg_len]; findarg[findarg_len] = NUL; - list_T *fname_list = eval_findexpr(findarg, findarg_len); + list_T *fname_list = eval_findexpr(findarg); int fname_count = tv_list_len(fname_list); if (fname_count == 0) { diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 65401fb3a9..2e037d80d3 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2955,6 +2955,7 @@ return { scope = { 'global', 'buffer' }, secure = true, short_desc = N_('expression used for :find'), + tags = { 'E1514' }, type = 'string', varname = 'p_fexpr', }, -- cgit From 60b3ccd850ca038af6fc0a19cad12578f63d67ec Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 29 Oct 2024 07:02:04 +0800 Subject: vim-patch:9.1.0821: 'findexpr' completion doesn't set v:fname to cmdline argument Problem: 'findexpr' completion doesn't set v:fname to cmdline argument. Solution: Set v:fname to the cmdline argument as-is (zeertzjq). closes: vim/vim#15934 https://github.com/vim/vim/commit/20e045f78148c0ef0143c33ffe686fee72d29376 --- src/nvim/cmdexpand.c | 9 ++++++--- src/nvim/cmdexpand_defs.h | 1 + src/nvim/errors.h | 2 +- src/nvim/eval.c | 5 ++++- src/nvim/eval.h | 1 + src/nvim/ex_docmd.c | 21 ++++++--------------- src/nvim/options.lua | 7 ++++++- src/nvim/vvars.lua | 7 +++++++ 8 files changed, 32 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 5b7017481e..aeaed536fc 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -109,6 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp) && xp->xp_context != EXPAND_FILES && xp->xp_context != EXPAND_FILES_IN_PATH && xp->xp_context != EXPAND_FILETYPE + && xp->xp_context != EXPAND_FINDEXPR && xp->xp_context != EXPAND_HELP && xp->xp_context != EXPAND_KEYMAP && xp->xp_context != EXPAND_LUA @@ -1228,7 +1229,8 @@ char *addstar(char *fname, size_t len, int context) // For help tags the translation is done in find_help_tags(). // For a tag pattern starting with "/" no translation is needed. - if (context == EXPAND_HELP + if (context == EXPAND_FINDEXPR + || context == EXPAND_HELP || context == EXPAND_COLORS || context == EXPAND_COMPILER || context == EXPAND_OWNSYNTAX @@ -1827,7 +1829,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa case CMD_sfind: case CMD_tabfind: if (xp->xp_context == EXPAND_FILES) { - xp->xp_context = EXPAND_FILES_IN_PATH; + xp->xp_context = *get_findexpr() != NUL ? EXPAND_FINDEXPR : EXPAND_FILES_IN_PATH; } break; case CMD_cd: @@ -2498,7 +2500,7 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int * } int ret = FAIL; - if (xp->xp_context == EXPAND_FILES_IN_PATH && *get_findexpr() != NUL) { + if (xp->xp_context == EXPAND_FINDEXPR) { ret = expand_findexpr(pat, matches, numMatches); } else { if (xp->xp_context == EXPAND_FILES) { @@ -2720,6 +2722,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES || xp->xp_context == EXPAND_FILES_IN_PATH + || xp->xp_context == EXPAND_FINDEXPR || xp->xp_context == EXPAND_DIRS_IN_CDPATH) { return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options); } diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h index 86725eafd6..ce51f30bec 100644 --- a/src/nvim/cmdexpand_defs.h +++ b/src/nvim/cmdexpand_defs.h @@ -107,6 +107,7 @@ enum { EXPAND_KEYMAP, EXPAND_DIRS_IN_CDPATH, EXPAND_SHELLCMDLINE, + EXPAND_FINDEXPR, EXPAND_CHECKHEALTH, EXPAND_LUA, }; diff --git a/src/nvim/errors.h b/src/nvim/errors.h index 6bbec84ff9..6682a42d61 100644 --- a/src/nvim/errors.h +++ b/src/nvim/errors.h @@ -186,7 +186,7 @@ INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch") EXTERN const char e_winfixbuf_cannot_go_to_buffer[] INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); -EXTERN const char e_invalid_return_type_from_findexpr[] INIT( = N_("E1514: findexpr did not return a List type")); +EXTERN const char e_invalid_return_type_from_findexpr[] INIT( = N_("E1514: 'findexpr' did not return a List type")); EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6a455f70a6..bf85ed1646 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -270,6 +270,7 @@ static struct vimvar { VV(VV_COLLATE, "collate", VAR_STRING, VV_RO), VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO), VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO), + VV(VV_CMDCOMPLETE, "cmdcomplete", VAR_BOOL, VV_RO), // Neovim VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO), VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO), @@ -460,6 +461,9 @@ void eval_init(void) set_vim_var_nr(VV_SEARCHFORWARD, 1); set_vim_var_nr(VV_HLSEARCH, 1); set_vim_var_nr(VV_COUNT1, 1); + set_vim_var_special(VV_EXITING, kSpecialVarNull); + set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse); + set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER); set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING); set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC); @@ -475,7 +479,6 @@ void eval_init(void) set_vim_var_nr(VV_NUMBERMAX, VARNUMBER_MAX); set_vim_var_nr(VV_NUMBERMIN, VARNUMBER_MIN); set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8); - set_vim_var_special(VV_EXITING, kSpecialVarNull); set_vim_var_nr(VV_MAXCOL, MAXCOL); set_vim_var_nr(VV_ECHOSPACE, sc_col - 1); diff --git a/src/nvim/eval.h b/src/nvim/eval.h index bb9b00abc7..b5605bb644 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -167,6 +167,7 @@ typedef enum { VV_COLLATE, VV_EXITING, VV_MAXCOL, + VV_CMDCOMPLETE, // Nvim VV_STDERR, VV_MSGPACK_TYPES, diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index f89c992cf9..74ba19b30a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5167,13 +5167,14 @@ static void ex_wrongmodifier(exarg_T *eap) /// Evaluate the 'findexpr' expression and return the result. When evaluating /// the expression, v:fname is set to the ":find" command argument. -static list_T *eval_findexpr(const char *ptr) +static list_T *eval_findexpr(const char *pat, bool cmdcomplete) { const sctx_T saved_sctx = current_sctx; char *findexpr = get_findexpr(); - set_vim_var_string(VV_FNAME, ptr, -1); + set_vim_var_string(VV_FNAME, pat, -1); + set_vim_var_bool(VV_CMDCOMPLETE, cmdcomplete ? kBoolVarTrue : kBoolVarFalse); current_sctx = curbuf->b_p_script_ctx[BV_FEXPR].script_ctx; char *arg = skipwhite(findexpr); @@ -5198,6 +5199,7 @@ static list_T *eval_findexpr(const char *ptr) clear_evalarg(&EVALARG_EVALUATE, NULL); set_vim_var_string(VV_FNAME, NULL, 0); + set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse); current_sctx = saved_sctx; return retlist; @@ -5211,18 +5213,7 @@ int expand_findexpr(const char *pat, char ***files, int *numMatches) *numMatches = 0; *files = NULL; - // File name expansion uses wildchars. But the 'findexpr' expression - // expects a regular expression argument. So convert wildchars in the - // argument to regular expression patterns. - char *regpat = file_pat_to_reg_pat(pat, NULL, NULL, false); - if (regpat == NULL) { - return FAIL; - } - - list_T *l = eval_findexpr(regpat); - - xfree(regpat); - + list_T *l = eval_findexpr(pat, true); if (l == NULL) { return FAIL; } @@ -5258,7 +5249,7 @@ static char *findexpr_find_file(char *findarg, size_t findarg_len, int count) const char cc = findarg[findarg_len]; findarg[findarg_len] = NUL; - list_T *fname_list = eval_findexpr(findarg); + list_T *fname_list = eval_findexpr(findarg, false); int fname_count = tv_list_len(fname_list); if (fname_count == 0) { diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 2e037d80d3..d59958eaf2 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2920,6 +2920,10 @@ return { The expression is evaluated only once per |:find| command invocation. The expression can process all the directories specified in 'path'. + The expression may be evaluated for command-line completion as well, + in which case the |v:cmdcomplete| variable will be set to |v:true|, + otherwise it will be set to |v:false|. + If a match is found, the expression should return a |List| containing one or more file names. If a match is not found, the expression should return an empty List. @@ -2939,7 +2943,8 @@ return { >vim " Use glob() func FindExprGlob() - return glob(v:fname, v:false, v:true) + let pat = v:cmdcomplete ? $'{v:fname}*' : v:fname + return glob(pat, v:false, v:true) endfunc set findexpr=FindExprGlob() diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index 5c9f0f9e27..6c6edd4ee2 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -50,6 +50,13 @@ M.vars = { can be used. ]=], }, + cmdcomplete = { + type = 'boolean', + desc = [=[ + When evaluating 'findexpr': if 'findexpr' is used for cmdline + completion the value is |v:true|, otherwise it is |v:false|. + ]=], + }, collate = { type = 'string', desc = [=[ -- cgit From 4c7f5032af6baca61764cde5122765b2ec684e4a Mon Sep 17 00:00:00 2001 From: Kai Moschcau Date: Tue, 29 Oct 2024 15:36:58 +0100 Subject: docs(options): shell-powershell #30969 `-NonInteractive` at least somewhat hints to pwsh/powershell, that shell sessions created from :! are not interactive, though even that is not foolproof, because powershell is weird. `$PSStyle.OutputRendering='plaintext'` causes pwsh/powershell to omit ANSI escape sequences in its output. --- src/nvim/options.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index d59958eaf2..1b8e3ea256 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7111,7 +7111,7 @@ return { *shell-powershell* To use PowerShell: >vim let &shell = executable('pwsh') ? 'pwsh' : 'powershell' - let &shellcmdflag = '-NoLogo -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;' + let &shellcmdflag = '-NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';$PSStyle.OutputRendering=''plaintext'';Remove-Alias -Force -ErrorAction SilentlyContinue tee;' let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode' let &shellpipe = '2>&1 | %%{ "$_" } | tee %s; exit $LastExitCode' set shellquote= shellxquote= -- cgit From 05d9e6a9e850ee797a4a018e72156dd62831a4b6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 30 Oct 2024 09:05:11 +0800 Subject: vim-patch:9.1.0822: topline might be changed in diff mode unexpectedly (#30988) Problem: topline might be changed in diff mode unexpectedly (Jaehwang Jung) Solution: do not re-calculate topline, when using line() func in diff mode. fixes: vim/vim#15812 closes: vim/vim#15950 https://github.com/vim/vim/commit/05a40e07c2f0e41b708c4c75a6aa7d0e7f6201a3 Co-authored-by: Christian Brabandt --- src/nvim/eval/funcs.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e8b9288717..8f676d7906 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4351,9 +4351,17 @@ static void f_line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (wp != NULL && tp != NULL) { switchwin_T switchwin; if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { + // in diff mode, prevent that the window scrolls + // and keep the topline + if (curwin->w_p_diff && switchwin.sw_curwin->w_p_diff) { + skip_update_topline = true; + } check_cursor(curwin); fp = var2fpos(&argvars[0], true, &fnum, false); } + if (curwin->w_p_diff && switchwin.sw_curwin->w_p_diff) { + skip_update_topline = false; + } restore_win_noblock(&switchwin, true); } } else { -- cgit From 295920845ebd78b2bad210eba51824369de44b19 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Thu, 17 Oct 2024 14:01:29 +0300 Subject: feat(highlight): make `PmenuMatch` and `PmenuMatchSel` bold Problem: both `PmenuMatch` and `PmenuMatchSel` can provide helpful information about characters which actually match query in completion candidates. This is not as useful with default regular match, but much more useful with 'completopt+=fuzzy'. Solution: make both highlight groups bold. This will also affect (i.e. benefit) other color schemes which do not define groups separately. This is possible since the recently merged changes to `PmenuMatch` and `PmenuMatchSel` combine attributes with underlying "base" groups. See PR 29980. --- src/nvim/highlight_group.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 1a0ae3ac49..4243c7573e 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -144,6 +144,8 @@ static const char e_missing_argument_str[] static const char *highlight_init_both[] = { "Cursor guifg=bg guibg=fg", "CursorLineNr gui=bold cterm=bold", + "PmenuMatch gui=bold cterm=bold", + "PmenuMatchSel gui=bold cterm=bold", "PmenuSel gui=reverse cterm=reverse,underline blend=0", "RedrawDebugNormal gui=reverse cterm=reverse", "TabLineSel gui=bold cterm=bold", @@ -170,8 +172,6 @@ static const char *highlight_init_both[] = { "default link PmenuExtraSel PmenuSel", "default link PmenuKind Pmenu", "default link PmenuKindSel PmenuSel", - "default link PmenuMatch Pmenu", - "default link PmenuMatchSel PmenuSel", "default link PmenuSbar Pmenu", "default link Substitute Search", "default link StatusLineTerm StatusLine", -- cgit From b34e137e43d359c8db4fb76028dea3b410842aff Mon Sep 17 00:00:00 2001 From: errael Date: Thu, 31 Oct 2024 18:11:15 -0700 Subject: feat(lua): allow vim.on_key() callback to consume the key (#30939) --- src/nvim/getchar.c | 4 +++- src/nvim/lua/executor.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 472bc3a850..c346bce0b7 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1772,7 +1772,9 @@ int vgetc(void) // Execute Lua on_key callbacks. kvi_push(on_key_buf, NUL); - nlua_execute_on_key(c, on_key_buf.items); + if (nlua_execute_on_key(c, on_key_buf.items)) { + c = K_IGNORE; + } kvi_destroy(on_key_buf); kvi_init(on_key_buf); diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9392765f40..27ebfacc5f 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2063,12 +2063,13 @@ char *nlua_register_table_as_callable(const typval_T *const arg) return name; } -void nlua_execute_on_key(int c, char *typed_buf) +/// @return true to discard the key +bool nlua_execute_on_key(int c, char *typed_buf) { static bool recursive = false; if (recursive) { - return; + return false; } recursive = true; @@ -2097,9 +2098,15 @@ void nlua_execute_on_key(int c, char *typed_buf) int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C - if (nlua_pcall(lstate, 2, 0)) { + bool discard = false; + if (nlua_pcall(lstate, 2, 1)) { nlua_error(lstate, _("Error executing vim.on_key Lua callback: %.*s")); + } else { + if (lua_isboolean(lstate, -1)) { + discard = lua_toboolean(lstate, -1); + } + lua_pop(lstate, 1); } got_int |= save_got_int; @@ -2112,6 +2119,7 @@ void nlua_execute_on_key(int c, char *typed_buf) #endif recursive = false; + return discard; } // Sets the editor "script context" during Lua execution. Used by :verbose. -- cgit From cbd8b2c1622e0c1cb4d38b65730e259eb6c100df Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 1 Nov 2024 17:34:19 +0800 Subject: vim-patch:9.1.0824: too many strlen() calls in register.c (#31022) Problem: too many strlen() calls in register.c Solution: refactor code, add string_T struct to keep track of string lengths (John Marriott) closes: vim/vim#15952 https://github.com/vim/vim/commit/79f6ffd388299ef3b1c95cbe658785e6e66df144 Co-authored-by: John Marriott --- src/nvim/api/private/helpers.h | 6 + src/nvim/api/vim.c | 6 +- src/nvim/ops.c | 246 ++++++++++++++++++++++------------------- src/nvim/ops.h | 2 +- src/nvim/shada.c | 10 +- src/nvim/terminal.c | 8 +- 6 files changed, 152 insertions(+), 126 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 57932e067e..d06f5c9c65 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -111,6 +111,12 @@ typedef kvec_withinit_t(Object, 16) ArrayBuilder; #define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s)) #define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s)) +#define API_CLEAR_STRING(s) \ + do { \ + XFREE_CLEAR(s.data); \ + s.size = 0; \ + } while (0) + // Helpers used by the generated msgpack-rpc api wrappers #define api_init_boolean #define api_init_integer diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8c88a19147..943c67ac8e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1317,15 +1317,15 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, return; // Nothing to do. } - reg->y_array = arena_alloc(arena, lines.size * sizeof(uint8_t *), true); + reg->y_array = arena_alloc(arena, lines.size * sizeof(String), true); reg->y_size = lines.size; for (size_t i = 0; i < lines.size; i++) { VALIDATE_T("line", kObjectTypeString, lines.items[i].type, { return; }); String line = lines.items[i].data.string; - reg->y_array[i] = arena_memdupz(arena, line.data, line.size); - memchrsub(reg->y_array[i], NUL, NL, line.size); + reg->y_array[i] = copy_string(line, arena); + memchrsub(reg->y_array[i].data, NUL, NL, line.size); } finish_yankreg_from_object(reg, false); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 8faf0a6b47..1705c8b648 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -12,6 +12,7 @@ #include #include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/autocmd.h" @@ -841,9 +842,9 @@ yankreg_T *copy_register(int name) if (copy->y_size == 0) { copy->y_array = NULL; } else { - copy->y_array = xcalloc(copy->y_size, sizeof(char *)); + copy->y_array = xcalloc(copy->y_size, sizeof(String)); for (size_t i = 0; i < copy->y_size; i++) { - copy->y_array[i] = xstrdup(reg->y_array[i]); + copy->y_array[i] = copy_string(reg->y_array[i], NULL); } } return copy; @@ -946,23 +947,24 @@ static int stuff_yank(int regname, char *p) xfree(p); return OK; } + + const size_t plen = strlen(p); yankreg_T *reg = get_yank_register(regname, YREG_YANK); if (is_append_register(regname) && reg->y_array != NULL) { - char **pp = &(reg->y_array[reg->y_size - 1]); - const size_t ppl = strlen(*pp); - const size_t pl = strlen(p); - char *lp = xmalloc(ppl + pl + 1); - memcpy(lp, *pp, ppl); - memcpy(lp + ppl, p, pl); - *(lp + ppl + pl) = NUL; + String *pp = &(reg->y_array[reg->y_size - 1]); + const size_t tmplen = pp->size + plen; + char *tmp = xmalloc(tmplen + 1); + memcpy(tmp, pp->data, pp->size); + memcpy(tmp + pp->size, p, plen); + *(tmp + tmplen) = NUL; xfree(p); - xfree(*pp); - *pp = lp; + xfree(pp->data); + *pp = cbuf_as_string(tmp, tmplen); } else { free_register(reg); reg->additional_data = NULL; - reg->y_array = xmalloc(sizeof(char *)); - reg->y_array[0] = p; + reg->y_array = xmalloc(sizeof(String)); + reg->y_array[0] = cbuf_as_string(p, plen); reg->y_size = 1; reg->y_type = kMTCharWise; } @@ -983,7 +985,7 @@ static int execreg_lastc = NUL; /// with a \. Lines that start with a comment "\ character are ignored. /// @returns the concatenated line. The index of the line that should be /// processed next is returned in idx. -static char *execreg_line_continuation(char **lines, size_t *idx) +static char *execreg_line_continuation(String *lines, size_t *idx) { size_t i = *idx; assert(i > 0); @@ -996,7 +998,7 @@ static char *execreg_line_continuation(char **lines, size_t *idx) // Any line not starting with \ or "\ is the start of the // command. while (--i > 0) { - char *p = skipwhite(lines[i]); + char *p = skipwhite(lines[i].data); if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) { break; } @@ -1004,9 +1006,9 @@ static char *execreg_line_continuation(char **lines, size_t *idx) const size_t cmd_start = i; // join all the lines - ga_concat(&ga, lines[cmd_start]); + ga_concat(&ga, lines[cmd_start].data); for (size_t j = cmd_start + 1; j <= cmd_end; j++) { - char *p = skipwhite(lines[j]); + char *p = skipwhite(lines[j].data); if (*p == '\\') { // Adjust the growsize to the current length to // speed up concatenating many lines. @@ -1017,7 +1019,7 @@ static char *execreg_line_continuation(char **lines, size_t *idx) } } ga_append(&ga, NUL); - char *str = xstrdup(ga.ga_data); + char *str = xmemdupz(ga.ga_data, (size_t)ga.ga_len); ga_clear(&ga); *idx = i; @@ -1110,7 +1112,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) } // Handle line-continuation for :@ - char *str = reg->y_array[i]; + char *str = reg->y_array[i].data; bool free_str = false; if (colon && i > 0) { char *p = skipwhite(str); @@ -1248,7 +1250,7 @@ int insert_reg(int regname, bool literally_arg) if (u_save_cursor() == FAIL) { return FAIL; } - del_chars(mb_charlen(reg->y_array[0]), true); + del_chars(mb_charlen(reg->y_array[0].data), true); curpos = curwin->w_cursor; if (oneright() == FAIL) { // hit end of line, need to put forward (after the current position) @@ -1261,7 +1263,7 @@ int insert_reg(int regname, bool literally_arg) AppendCharToRedobuff(regname); do_put(regname, NULL, dir, 1, PUT_CURSEND); } else { - stuffescaped(reg->y_array[i], literally); + stuffescaped(reg->y_array[i].data, literally); } // Insert a newline between lines and after last line if // y_type is kMTLineWise. @@ -1384,7 +1386,7 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr) } for (size_t i = 0; i < reg->y_size; i++) { - cmdline_paste_str(reg->y_array[i], literally); + cmdline_paste_str(reg->y_array[i].data, literally); // Insert ^M between lines, unless `remcr` is true. if (i < reg->y_size - 1 && !remcr) { @@ -2504,7 +2506,7 @@ void free_register(yankreg_T *reg) } for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included - xfree(reg->y_array[i]); + API_CLEAR_STRING(reg->y_array[i]); } XFREE_CLEAR(reg->y_array); } @@ -2533,7 +2535,6 @@ bool op_yank(oparg_T *oap, bool message) op_yank_reg(oap, message, reg, is_append_register(oap->regname)); set_clipboard(oap->regname, reg); do_autocmd_textyankpost(oap, reg); - return true; } @@ -2569,7 +2570,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) reg->y_size = yanklines; reg->y_type = yank_type; // set the yank register type reg->y_width = 0; - reg->y_array = xcalloc(yanklines, sizeof(char *)); + reg->y_array = xcalloc(yanklines, sizeof(String)); reg->additional_data = NULL; reg->timestamp = os_time(); @@ -2593,11 +2594,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) break; case kMTLineWise: - reg->y_array[y_idx] = xstrdup(ml_get(lnum)); + reg->y_array[y_idx] = cbuf_to_string(ml_get(lnum), (size_t)ml_get_len(lnum)); break; case kMTCharWise: charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive); + // make sure bd.textlen is not longer than the text + int tmp = (int)strlen(bd.textstart); + if (tmp < bd.textlen) { + bd.textlen = tmp; + } yank_copy_line(reg, &bd, y_idx, false); break; @@ -2609,7 +2615,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) if (curr != reg) { // append the new block to the old block size_t j; - char **new_ptr = xmalloc(sizeof(char *) * (curr->y_size + reg->y_size)); + String *new_ptr = xmalloc(sizeof(String) * (curr->y_size + reg->y_size)); for (j = 0; j < curr->y_size; j++) { new_ptr[j] = curr->y_array[j]; } @@ -2625,13 +2631,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) // the new block, unless being Vi compatible. if (curr->y_type == kMTCharWise && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) { - char *pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1]) - + strlen(reg->y_array[0]) + 1); - STRCPY(pnew, curr->y_array[--j]); - strcat(pnew, reg->y_array[0]); - xfree(curr->y_array[j]); - xfree(reg->y_array[0]); - curr->y_array[j++] = pnew; + char *pnew = xmalloc(curr->y_array[curr->y_size - 1].size + + reg->y_array[0].size + 1); + j--; + STRCPY(pnew, curr->y_array[j].data); + STRCPY(pnew + curr->y_array[j].size, reg->y_array[0].data); + xfree(curr->y_array[j].data); + curr->y_array[j] = cbuf_as_string(pnew, + curr->y_array[j].size + reg->y_array[0].size); + j++; + API_CLEAR_STRING(reg->y_array[0]); y_idx = 1; } else { y_idx = 0; @@ -2698,7 +2707,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx, int size = bd->startspaces + bd->endspaces + bd->textlen; assert(size >= 0); char *pnew = xmallocz((size_t)size); - reg->y_array[y_idx] = pnew; + reg->y_array[y_idx].data = pnew; memset(pnew, ' ', (size_t)bd->startspaces); pnew += bd->startspaces; memmove(pnew, bd->textstart, (size_t)bd->textlen); @@ -2714,6 +2723,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx, } } *pnew = NUL; + reg->y_array[y_idx].size = (size_t)(pnew - reg->y_array[y_idx].data); } /// Execute autocommands for TextYankPost. @@ -2739,7 +2749,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) // The yanked text contents. list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size); for (size_t i = 0; i < reg->y_size; i++) { - tv_list_append_string(list, reg->y_array[i], -1); + tv_list_append_string(list, reg->y_array[i].data, -1); } tv_list_set_lock(list, VAR_FIXED); tv_dict_add_list(dict, S_LEN("regcontents"), list); @@ -2792,25 +2802,13 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) size_t y_size; int y_width = 0; colnr_T vcol = 0; - int incr = 0; - struct block_def bd; - char **y_array = NULL; + String *y_array = NULL; linenr_T nr_lines = 0; - int indent; - int orig_indent = 0; // init for gcc - int indent_diff = 0; // init for gcc - bool first_indent = true; - int lendiff = 0; - char *insert_string = NULL; bool allocated = false; const pos_T orig_start = curbuf->b_op_start; const pos_T orig_end = curbuf->b_op_end; unsigned cur_ve_flags = get_ve_flags(curwin); - if (flags & PUT_FIXINDENT) { - orig_indent = get_indent(); - } - curbuf->b_op_start = curwin->w_cursor; // default for '[ mark curbuf->b_op_end = curwin->w_cursor; // default for '] mark @@ -2898,8 +2896,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // For special registers '%' (file name), '#' (alternate file name) and // ':' (last command line), etc. we have to create a fake yank register. - if (!reg && get_spec_reg(regname, &insert_string, &allocated, true)) { - if (insert_string == NULL) { + String insert_string = STRING_INIT; + if (!reg && get_spec_reg(regname, &insert_string.data, &allocated, true)) { + if (insert_string.data == NULL) { return; } } @@ -2912,7 +2911,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } } - if (insert_string != NULL) { + if (insert_string.data != NULL) { + insert_string.size = strlen(insert_string.data); y_type = kMTCharWise; if (regname == '=') { // For the = register we need to split the string at NL @@ -2920,29 +2920,37 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // Loop twice: count the number of lines and save them. while (true) { y_size = 0; - char *ptr = insert_string; + char *ptr = insert_string.data; + size_t ptrlen = insert_string.size; while (ptr != NULL) { if (y_array != NULL) { - y_array[y_size] = ptr; + y_array[y_size].data = ptr; } y_size++; - ptr = vim_strchr(ptr, '\n'); - if (ptr != NULL) { + char *tmp = vim_strchr(ptr, '\n'); + if (tmp == NULL) { if (y_array != NULL) { - *ptr = NUL; + y_array[y_size - 1].size = ptrlen; } - ptr++; + } else { + if (y_array != NULL) { + *tmp = NUL; + y_array[y_size - 1].size = (size_t)(tmp - ptr); + ptrlen -= y_array[y_size - 1].size + 1; + } + tmp++; // A trailing '\n' makes the register linewise. - if (*ptr == NUL) { + if (*tmp == NUL) { y_type = kMTLineWise; break; } } + ptr = tmp; } if (y_array != NULL) { break; } - y_array = xmalloc(y_size * sizeof(char *)); + y_array = xmalloc(y_size * sizeof(String)); } } else { y_size = 1; // use fake one-line yank register @@ -2976,14 +2984,16 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) goto end; } char *curline = get_cursor_line_ptr(); - char *p = curline + curwin->w_cursor.col; + char *p = get_cursor_pos_ptr(); + char *const p_orig = p; + const size_t plen = (size_t)get_cursor_pos_len(); if (dir == FORWARD && *p != NUL) { MB_PTR_ADV(p); } // we need this later for the correct extmark_splice() event split_pos = (colnr_T)(p - curline); - char *ptr = xstrdup(p); + char *ptr = xmemdupz(p, plen - (size_t)(p - p_orig)); ml_append(curwin->w_cursor.lnum, ptr, 0, false); xfree(ptr); @@ -3047,8 +3057,6 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) goto end; } - int yanklen = (int)strlen(y_array[0]); - if (cur_ve_flags == VE_ALL && y_type == kMTCharWise) { if (gchar_cursor() == TAB) { int viscol = getviscol(); @@ -3072,6 +3080,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // Block mode if (y_type == kMTBlockWise) { + int incr = 0; + struct block_def bd; int c = gchar_cursor(); colnr_T endcol2 = 0; @@ -3164,14 +3174,14 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } } - yanklen = (int)strlen(y_array[i]); + const int yanklen = (int)y_array[i].size; if ((flags & PUT_BLOCK_INNER) == 0) { // calculate number of spaces required to fill right side of block spaces = y_width + 1; - cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i]); - ci = utf_ptr2StrCharInfo(y_array[i]); + cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i].data); + ci = utf_ptr2StrCharInfo(y_array[i].data); while (*ci.ptr != NUL) { spaces -= win_charsize(cstype, 0, ci.ptr, ci.chr.value, &csarg).width; ci = utfc_next(ci); @@ -3202,7 +3212,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // insert the new text for (int j = 0; j < count; j++) { - memmove(ptr, y_array[i], (size_t)yanklen); + memmove(ptr, y_array[i].data, (size_t)yanklen); ptr += yanklen; // insert block's trailing spaces only if there's text behind @@ -3254,6 +3264,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) curwin->w_cursor.lnum = lnum; } } else { + const int yanklen = (int)y_array[0].size; + // Character or Line mode if (y_type == kMTCharWise) { // if type is kMTCharWise, FORWARD is the same as BACKWARD on the next @@ -3326,10 +3338,10 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) memmove(newp, oldp, (size_t)col); char *ptr = newp + col; for (size_t i = 0; i < (size_t)count; i++) { - memmove(ptr, y_array[0], (size_t)yanklen); + memmove(ptr, y_array[0].data, (size_t)yanklen); ptr += yanklen; } - STRMOVE(ptr, oldp + col); + memmove(ptr, oldp + col, (size_t)(oldlen - col) + 1); // +1 for NUL ml_replace(lnum, newp, false); // compute the byte offset for the last character @@ -3367,6 +3379,15 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } } else { linenr_T new_lnum = new_cursor.lnum; + int indent; + int orig_indent = 0; + int indent_diff = 0; // init for gcc + bool first_indent = true; + int lendiff = 0; + + if (flags & PUT_FIXINDENT) { + orig_indent = get_indent(); + } // Insert at least one line. When y_type is kMTCharWise, break the first // line in two. @@ -3378,10 +3399,11 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // Then append y_array[0] to first line. lnum = new_cursor.lnum; char *ptr = ml_get(lnum) + col; - totlen = strlen(y_array[y_size - 1]); - char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1); - STRCPY(newp, y_array[y_size - 1]); - strcat(newp, ptr); + size_t ptrlen = (size_t)ml_get_len(lnum) - (size_t)col; + totlen = y_array[y_size - 1].size; + char *newp = xmalloc(ptrlen + totlen + 1); + STRCPY(newp, y_array[y_size - 1].data); + STRCPY(newp + totlen, ptr); // insert second line ml_append(lnum, newp, 0, false); new_lnum++; @@ -3392,7 +3414,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // copy first part of line memmove(newp, oldp, (size_t)col); // append to first line - memmove(newp + col, y_array[0], (size_t)yanklen + 1); + memmove(newp + col, y_array[0].data, (size_t)yanklen + 1); ml_replace(lnum, newp, false); curwin->w_cursor.lnum = lnum; @@ -3401,7 +3423,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) for (; i < y_size; i++) { if ((y_type != kMTCharWise || i < y_size - 1)) { - if (ml_append(lnum, y_array[i], 0, false) == FAIL) { + if (ml_append(lnum, y_array[i].data, 0, false) == FAIL) { goto error; } new_lnum++; @@ -3440,9 +3462,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) if (y_type == kMTCharWise || (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT))) { for (i = 0; i < y_size - 1; i++) { - totsize += (bcount_t)strlen(y_array[i]) + 1; + totsize += (bcount_t)y_array[i].size + 1; } - lastsize = (int)strlen(y_array[y_size - 1]); + lastsize = (int)y_array[y_size - 1].size; totsize += lastsize; } if (y_type == kMTCharWise) { @@ -3486,13 +3508,13 @@ error: // Put the '] mark on the first byte of the last inserted character. // Correct the length for change in indent. curbuf->b_op_end.lnum = new_lnum; - size_t len = strlen(y_array[y_size - 1]); - col = (colnr_T)len - lendiff; + col = (colnr_T)y_array[y_size - 1].size - lendiff; if (col > 1) { curbuf->b_op_end.col = col - 1; - if (len > 0) { - curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1], - y_array[y_size - 1] + len - 1); + if (y_array[y_size - 1].size > 0) { + curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1].data, + y_array[y_size - 1].data + + y_array[y_size - 1].size - 1); } } else { curbuf->b_op_end.col = 0; @@ -3550,7 +3572,7 @@ end: curbuf->b_op_end = orig_end; } if (allocated) { - xfree(insert_string); + xfree(insert_string.data); } if (regname == '=') { xfree(y_array); @@ -3672,7 +3694,7 @@ void ex_display(exarg_T *eap) bool do_show = false; for (size_t j = 0; !do_show && j < yb->y_size; j++) { - do_show = !message_filtered(yb->y_array[j]); + do_show = !message_filtered(yb->y_array[j].data); } if (do_show || yb->y_size == 0) { @@ -3690,7 +3712,7 @@ void ex_display(exarg_T *eap) msg_puts_attr("^J", attr); n -= 2; } - for (p = yb->y_array[j]; + for (p = yb->y_array[j].data; *p != NUL && (n -= ptr2cells(p)) >= 0; p++) { int clen = utfc_ptr2len(p); msg_outtrans_len(p, clen, 0); @@ -4849,7 +4871,7 @@ void *get_reg_contents(int regname, int flags) if (flags & kGRegList) { list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size); for (size_t i = 0; i < reg->y_size; i++) { - tv_list_append_string(list, reg->y_array[i], -1); + tv_list_append_string(list, reg->y_array[i].data, -1); } return list; @@ -4858,9 +4880,8 @@ void *get_reg_contents(int regname, int flags) // Compute length of resulting string. size_t len = 0; for (size_t i = 0; i < reg->y_size; i++) { - len += strlen(reg->y_array[i]); - // Insert a newline between lines and after last line if - // y_type is kMTLineWise. + len += reg->y_array[i].size; + // Insert a newline between lines and after last line if y_type is kMTLineWise. if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { len++; } @@ -4871,11 +4892,10 @@ void *get_reg_contents(int regname, int flags) // Copy the lines of the yank register into the string. len = 0; for (size_t i = 0; i < reg->y_size; i++) { - STRCPY(retval + len, reg->y_array[i]); - len += strlen(retval + len); + STRCPY(retval + len, reg->y_array[i].data); + len += reg->y_array[i].size; - // Insert a NL between lines and after the last line if y_type is - // kMTLineWise. + // Insert a newline between lines and after the last line if y_type is kMTLineWise. if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { retval[len++] = '\n'; } @@ -4993,8 +5013,7 @@ void write_reg_contents_ex(int name, const char *str, ssize_t len, bool must_app semsg(_(e_nobufnr), (int64_t)num); } } else { - buf = buflist_findnr(buflist_findpat(str, str + strlen(str), - true, false, false)); + buf = buflist_findnr(buflist_findpat(str, str + len, true, false, false)); } if (buf == NULL) { return; @@ -5090,7 +5109,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, } // Grow the register array to hold the pointers to the new lines. - char **pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(char *)); + String *pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(String)); y_ptr->y_array = pp; size_t lnum = y_ptr->y_size; // The current line number. @@ -5102,7 +5121,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, if (str_list) { for (char **ss = (char **)str; *ss != NULL; ss++, lnum++) { size_t ss_len = strlen(*ss); - pp[lnum] = xmemdupz(*ss, ss_len); + pp[lnum] = cbuf_to_string(*ss, ss_len); maxlen = MAX(maxlen, ss_len); } } else { @@ -5115,22 +5134,22 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, maxlen = MAX(maxlen, line_len); // When appending, copy the previous line and free it after. - size_t extra = append ? strlen(pp[--lnum]) : 0; + size_t extra = append ? pp[--lnum].size : 0; char *s = xmallocz(line_len + extra); if (extra > 0) { - memcpy(s, pp[lnum], extra); + memcpy(s, pp[lnum].data, extra); } memcpy(s + extra, start, line_len); size_t s_len = extra + line_len; if (append) { - xfree(pp[lnum]); + xfree(pp[lnum].data); append = false; // only first line is appended } - pp[lnum] = s; + pp[lnum] = cbuf_as_string(s, s_len); // Convert NULs to '\n' to prevent truncation. - memchrsub(pp[lnum], NUL, '\n', s_len); + memchrsub(pp[lnum].data, NUL, '\n', s_len); } } y_ptr->y_type = yank_type; @@ -6421,7 +6440,7 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines) void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust) { - if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) { + if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) { // a known-to-be charwise yank might have a final linebreak // but otherwise there is no line after the final newline if (reg->y_type != kMTCharWise) { @@ -6441,7 +6460,7 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust) if (reg->y_type == kMTBlockWise) { size_t maxlen = 0; for (size_t i = 0; i < reg->y_size; i++) { - size_t rowlen = strlen(reg->y_array[i]); + size_t rowlen = reg->y_array[i].size; maxlen = MAX(maxlen, rowlen); } assert(maxlen <= INT_MAX); @@ -6511,7 +6530,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) reg->y_type = kMTUnknown; } - reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(char *)); + reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(String)); reg->y_size = (size_t)tv_list_len(lines); reg->additional_data = NULL; reg->timestamp = 0; @@ -6523,14 +6542,15 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) { goto err; } - reg->y_array[tv_idx++] = xstrdupnul(TV_LIST_ITEM_TV(li)->vval.v_string); + const char *s = TV_LIST_ITEM_TV(li)->vval.v_string; + reg->y_array[tv_idx++] = cstr_to_string(s != NULL ? s : ""); }); - if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) { + if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) { // a known-to-be charwise yank might have a final linebreak // but otherwise there is no line after the final newline if (reg->y_type != kMTCharWise) { - xfree(reg->y_array[reg->y_size - 1]); + xfree(reg->y_array[reg->y_size - 1].data); reg->y_size--; if (reg->y_type == kMTUnknown) { reg->y_type = kMTLineWise; @@ -6545,7 +6565,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) if (reg->y_type == kMTBlockWise) { size_t maxlen = 0; for (size_t i = 0; i < reg->y_size; i++) { - size_t rowlen = strlen(reg->y_array[i]); + size_t rowlen = reg->y_array[i].size; maxlen = MAX(maxlen, rowlen); } assert(maxlen <= INT_MAX); @@ -6558,7 +6578,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) err: if (reg->y_array) { for (size_t i = 0; i < reg->y_size; i++) { - xfree(reg->y_array[i]); + xfree(reg->y_array[i].data); } xfree(reg->y_array); } @@ -6582,7 +6602,7 @@ static void set_clipboard(int name, yankreg_T *reg) list_T *const lines = tv_list_alloc((ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise)); for (size_t i = 0; i < reg->y_size; i++) { - tv_list_append_string(lines, reg->y_array[i], -1); + tv_list_append_string(lines, reg->y_array[i].data, -1); } char regtype; @@ -6666,7 +6686,7 @@ static inline bool reg_empty(const yankreg_T *const reg) || reg->y_size == 0 || (reg->y_size == 1 && reg->y_type == kMTCharWise - && *(reg->y_array[0]) == NUL)); + && reg->y_array[0].size == 0)); } /// Iterate over global registers. diff --git a/src/nvim/ops.h b/src/nvim/ops.h index dfa2d4b112..ed7e5f7466 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -105,7 +105,7 @@ enum GRegFlags { /// Definition of one register typedef struct { - char **y_array; ///< Pointer to an array of line pointers. + String *y_array; ///< Pointer to an array of Strings. size_t y_size; ///< Number of lines in y_array. MotionType y_type; ///< Register type colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise). diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 11fe291559..9e9f762cd5 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -246,7 +246,7 @@ typedef struct { struct reg { // yankreg_T char name; MotionType type; - char **contents; + String *contents; bool is_unnamed; size_t contents_size; size_t width; @@ -1491,7 +1491,7 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry PACK_KEY(REG_KEY_CONTENTS); mpack_array(&sbuf.ptr, (uint32_t)entry.data.reg.contents_size); for (size_t i = 0; i < entry.data.reg.contents_size; i++) { - mpack_bin(cstr_as_string(entry.data.reg.contents[i]), &sbuf); + mpack_bin(entry.data.reg.contents[i], &sbuf); } PACK_KEY(KEY_NAME_CHAR); mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.name); @@ -2930,7 +2930,7 @@ static void shada_free_shada_entry(ShadaEntry *const entry) break; case kSDItemRegister: for (size_t i = 0; i < entry->data.reg.contents_size; i++) { - xfree(entry->data.reg.contents[i]); + api_free_string(entry->data.reg.contents[i]); } xfree(entry->data.reg.contents); break; @@ -3312,9 +3312,9 @@ shada_read_next_item_start: goto shada_read_next_item_error; } entry->data.reg.contents_size = it.rc.size; - entry->data.reg.contents = xmalloc(it.rc.size * sizeof(char *)); + entry->data.reg.contents = xmalloc(it.rc.size * sizeof(String)); for (size_t j = 0; j < it.rc.size; j++) { - entry->data.reg.contents[j] = xmemdupz(it.rc.items[j].data, it.rc.items[j].size); + entry->data.reg.contents[j] = copy_string(it.rc.items[j], NULL); } kv_destroy(it.rc); diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index f444021b90..5ff7f721ba 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -895,13 +895,13 @@ static bool is_filter_char(int c) return !!(tpf_flags & flag); } -void terminal_paste(int count, char **y_array, size_t y_size) +void terminal_paste(int count, String *y_array, size_t y_size) { if (y_size == 0) { return; } vterm_keyboard_start_paste(curbuf->terminal->vt); - size_t buff_len = strlen(y_array[0]); + size_t buff_len = y_array[0].size; char *buff = xmalloc(buff_len); for (int i = 0; i < count; i++) { // feed the lines to the terminal @@ -914,13 +914,13 @@ void terminal_paste(int count, char **y_array, size_t y_size) terminal_send(curbuf->terminal, "\n", 1); #endif } - size_t len = strlen(y_array[j]); + size_t len = y_array[j].size; if (len > buff_len) { buff = xrealloc(buff, len); buff_len = len; } char *dst = buff; - char *src = y_array[j]; + char *src = y_array[j].data; while (*src != NUL) { len = (size_t)utf_ptr2len(src); int c = utf_ptr2char(src); -- cgit From 7bf3a616e18205d353d9c4a44e8c2f885d700129 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 1 Nov 2024 18:22:08 +0800 Subject: vim-patch:b5e7da1: runtime(doc): mention 'iskeyword' at :h charclass() (#31026) fixes: vim/vim#15965 https://github.com/vim/vim/commit/b5e7da1f27241f7d770d342009e2fb443e45e6ce Co-authored-by: Christian Brabandt --- src/nvim/eval.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 34045c7c9d..870eb17b9e 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -1111,7 +1111,7 @@ M.funcs = { The character class is one of: 0 blank 1 punctuation - 2 word character + 2 word character (depends on 'iskeyword') 3 emoji other specific Unicode class The class is used in patterns and word motions. -- cgit From ec0c53b3da5484f1068e476a477d3f96a0a1a811 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Sat, 2 Nov 2024 04:44:56 +0600 Subject: refactor(options): unify `put_set(num|bool|string)` (#30993) Problem: There are three separate functions for printing the `:set` command for an setting an option to a file descriptor. These functions are used when creating the session file for an option. Having a function for each type increase code duplication and also makes it harder to add logic for new option types. Solution: Replace `put_set(num|bool|string)` with a single `put_set` function which works for all option types, this reduces code duplication and also makes it trivial to add support for more option types in the future. --- src/nvim/option.c | 220 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 116 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 65f03ca77f..a8ec5b2919 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4368,35 +4368,24 @@ int makeset(FILE *fd, int opt_flags, int local_only) cmd = "setlocal"; } - if (option_has_type(opt_idx, kOptValTypeBoolean)) { - if (put_setbool(fd, cmd, opt->fullname, *(int *)varp) == FAIL) { + bool do_endif = false; + // Don't set 'syntax' and 'filetype' again if the value is + // already right, avoids reloading the syntax file. + if (opt->indir == PV_SYN || opt->indir == PV_FT) { + if (fprintf(fd, "if &%s != '%s'", opt->fullname, + *(char **)(varp)) < 0 + || put_eol(fd) < 0) { return FAIL; } - } else if (option_has_type(opt_idx, kOptValTypeNumber)) { - if (put_setnum(fd, cmd, opt->fullname, (OptInt *)varp) == FAIL) { - return FAIL; - } - } else { // string - bool do_endif = false; - - // Don't set 'syntax' and 'filetype' again if the value is - // already right, avoids reloading the syntax file. - if (opt->indir == PV_SYN || opt->indir == PV_FT) { - if (fprintf(fd, "if &%s != '%s'", opt->fullname, - *(char **)(varp)) < 0 - || put_eol(fd) < 0) { - return FAIL; - } - do_endif = true; - } - if (put_setstring(fd, cmd, opt->fullname, (char **)varp, opt->flags) == FAIL) { + do_endif = true; + } + if (put_set(fd, cmd, opt_idx, varp) == FAIL) { + return FAIL; + } + if (do_endif) { + if (put_line(fd, "endif") == FAIL) { return FAIL; } - if (do_endif) { - if (put_line(fd, "endif") == FAIL) { - return FAIL; - } - } } } } @@ -4409,110 +4398,133 @@ int makeset(FILE *fd, int opt_flags, int local_only) /// 'sessionoptions' or 'viewoptions' contains "folds" but not "options". int makefoldset(FILE *fd) { - if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, 0) == FAIL - || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0) == FAIL - || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0) == FAIL - || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0) == FAIL - || put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL - || put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL - || put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL - || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL) { + if (put_set(fd, "setlocal", kOptFoldmethod, &curwin->w_p_fdm) == FAIL + || put_set(fd, "setlocal", kOptFoldexpr, &curwin->w_p_fde) == FAIL + || put_set(fd, "setlocal", kOptFoldmarker, &curwin->w_p_fmr) == FAIL + || put_set(fd, "setlocal", kOptFoldignore, &curwin->w_p_fdi) == FAIL + || put_set(fd, "setlocal", kOptFoldlevel, &curwin->w_p_fdl) == FAIL + || put_set(fd, "setlocal", kOptFoldminlines, &curwin->w_p_fml) == FAIL + || put_set(fd, "setlocal", kOptFoldnestmax, &curwin->w_p_fdn) == FAIL + || put_set(fd, "setlocal", kOptFoldenable, &curwin->w_p_fen) == FAIL) { return FAIL; } return OK; } -static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_t flags) +/// Print the ":set" command to set a single option to file. +/// +/// @param fd File descriptor. +/// @param cmd Command name. +/// @param opt_idx Option index in options[] table. +/// @param varp Pointer to option variable. +/// +/// @return FAIL on error, OK otherwise. +static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp) { - if (fprintf(fd, "%s %s=", cmd, name) < 0) { - return FAIL; + OptVal value = optval_from_varp(opt_idx, varp); + vimoption_T *opt = &options[opt_idx]; + char *name = opt->fullname; + uint64_t flags = opt->flags; + + if ((opt->indir & PV_BOTH) && varp != opt->var + && optval_equal(value, get_option_unset_value(opt_idx))) { + // Processing unset local value of global-local option. Do nothing. + return OK; + } + + switch (value.type) { + case kOptValTypeNil: + abort(); + case kOptValTypeBoolean: { + assert(value.data.boolean != kNone); + bool value_bool = TRISTATE_TO_BOOL(value.data.boolean, false); + + if (fprintf(fd, "%s %s%s", cmd, value_bool ? "" : "no", name) < 0) { + return FAIL; + } + break; + } + case kOptValTypeNumber: { + if (fprintf(fd, "%s %s=", cmd, name) < 0) { + return FAIL; + } + + OptInt value_num = value.data.number; + + OptInt wc; + if (wc_use_keyname(varp, &wc)) { + // print 'wildchar' and 'wildcharm' as a key name + if (fputs(get_special_key_name((int)wc, 0), fd) < 0) { + return FAIL; + } + } else if (fprintf(fd, "%" PRId64, value_num) < 0) { + return FAIL; + } + break; } + case kOptValTypeString: { + if (fprintf(fd, "%s %s=", cmd, name) < 0) { + return FAIL; + } - char *buf = NULL; - char *part = NULL; + char *value_str = value.data.string.data; + char *buf = NULL; + char *part = NULL; - if (*valuep != NULL) { - if ((flags & kOptFlagExpand) != 0) { - size_t size = (size_t)strlen(*valuep) + 1; + if (value_str != NULL) { + if ((flags & kOptFlagExpand) != 0) { + size_t size = (size_t)strlen(value_str) + 1; - // replace home directory in the whole option value into "buf" - buf = xmalloc(size); - home_replace(NULL, *valuep, buf, size, false); + // replace home directory in the whole option value into "buf" + buf = xmalloc(size); + home_replace(NULL, value_str, buf, size, false); - // If the option value is longer than MAXPATHL, we need to append - // each comma separated part of the option separately, so that it - // can be expanded when read back. - if (size >= MAXPATHL && (flags & kOptFlagComma) != 0 - && vim_strchr(*valuep, ',') != NULL) { - part = xmalloc(size); + // If the option value is longer than MAXPATHL, we need to append + // each comma separated part of the option separately, so that it + // can be expanded when read back. + if (size >= MAXPATHL && (flags & kOptFlagComma) != 0 + && vim_strchr(value_str, ',') != NULL) { + part = xmalloc(size); - // write line break to clear the option, e.g. ':set rtp=' - if (put_eol(fd) == FAIL) { - goto fail; - } - char *p = buf; - while (*p != NUL) { - // for each comma separated option part, append value to - // the option, :set rtp+=value - if (fprintf(fd, "%s %s+=", cmd, name) < 0) { + // write line break to clear the option, e.g. ':set rtp=' + if (put_eol(fd) == FAIL) { goto fail; } - copy_option_part(&p, part, size, ","); - if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) { - goto fail; + char *p = buf; + while (*p != NUL) { + // for each comma separated option part, append value to + // the option, :set rtp+=value + if (fprintf(fd, "%s %s+=", cmd, name) < 0) { + goto fail; + } + copy_option_part(&p, part, size, ","); + if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) { + goto fail; + } } + xfree(buf); + xfree(part); + return OK; + } + if (put_escstr(fd, buf, 2) == FAIL) { + xfree(buf); + return FAIL; } xfree(buf); - xfree(part); - return OK; - } - if (put_escstr(fd, buf, 2) == FAIL) { - xfree(buf); + } else if (put_escstr(fd, value_str, 2) == FAIL) { return FAIL; } - xfree(buf); - } else if (put_escstr(fd, *valuep, 2) == FAIL) { - return FAIL; - } - } - if (put_eol(fd) < 0) { - return FAIL; - } - return OK; -fail: - xfree(buf); - xfree(part); - return FAIL; -} - -static int put_setnum(FILE *fd, char *cmd, char *name, OptInt *valuep) -{ - if (fprintf(fd, "%s %s=", cmd, name) < 0) { - return FAIL; - } - OptInt wc; - if (wc_use_keyname(valuep, &wc)) { - // print 'wildchar' and 'wildcharm' as a key name - if (fputs(get_special_key_name((int)wc, 0), fd) < 0) { - return FAIL; } - } else if (fprintf(fd, "%" PRId64, (int64_t)(*valuep)) < 0) { + break; + fail: + xfree(buf); + xfree(part); return FAIL; } - if (put_eol(fd) < 0) { - return FAIL; } - return OK; -} -static int put_setbool(FILE *fd, char *cmd, char *name, int value) -{ - if (value < 0) { // global/local option using global value - return OK; - } - if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0 - || put_eol(fd) < 0) { + if (put_eol(fd) < 0) { return FAIL; } return OK; -- cgit From 3688a333544251c887d78e6501eec55f0fb685f8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 2 Nov 2024 10:11:06 +0800 Subject: fix(lua): show stacktrace for error in vim.on_key() callback (#31021) --- src/nvim/lua/executor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 27ebfacc5f..e4da274204 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2099,9 +2099,9 @@ bool nlua_execute_on_key(int c, char *typed_buf) int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C bool discard = false; - if (nlua_pcall(lstate, 2, 1)) { - nlua_error(lstate, - _("Error executing vim.on_key Lua callback: %.*s")); + // Do not use nlua_pcall here to avoid duplicate stack trace information + if (lua_pcall(lstate, 2, 1, 0)) { + nlua_error(lstate, _("Error executing vim.on_key() callbacks: %.*s")); } else { if (lua_isboolean(lstate, -1)) { discard = lua_toboolean(lstate, -1); -- cgit From 86e54734bf9e05605d8b7146e7b0e79025138ba2 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Tue, 29 Oct 2024 03:21:33 +0600 Subject: refactor(options): remove `get_option_value_strict` Problem: `get_option_value_for` can perfectly replace `get_option_value_strict`, making the latter redundant. Solution: Remove `get_option_value_strict` --- src/nvim/api/deprecated.c | 46 +++++++++++++++++++++++++++++-- src/nvim/option.c | 70 ----------------------------------------------- 2 files changed, 43 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 6376011106..5c0d9c0cea 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -633,6 +633,40 @@ void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object set_option_to(channel_id, win, kOptReqWin, name, value, err); } +/// Check if option has a value in the requested scope. +/// +/// @param opt_idx Option index in options[] table. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// +/// @return true if option has a value in the requested scope, false otherwise. +static bool option_has_scope(OptIndex opt_idx, OptReqScope req_scope) +{ + if (opt_idx == kOptInvalid) { + return false; + } + + vimoption_T *opt = get_option(opt_idx); + + // Hidden option. + if (opt->var == NULL) { + return false; + } + // TTY option. + if (is_tty_option(opt->fullname)) { + return req_scope == kOptReqGlobal; + } + + switch (req_scope) { + case kOptReqGlobal: + return opt->var != VAR_WIN; + case kOptReqBuf: + return opt->indir & PV_BUF; + case kOptReqWin: + return opt->indir & PV_WIN; + } + UNREACHABLE; +} + /// Gets the value of a global or local (buffer, window) option. /// /// @param[in] from Pointer to buffer or window for local option value. @@ -647,9 +681,15 @@ static Object get_option_from(void *from, OptReqScope req_scope, String name, Er return (Object)OBJECT_INIT; }); - OptVal value = get_option_value_strict(find_option(name.data), req_scope, from, err); - if (ERROR_SET(err)) { - return (Object)OBJECT_INIT; + OptIndex opt_idx = find_option(name.data); + OptVal value = NIL_OPTVAL; + + if (option_has_scope(opt_idx, req_scope)) { + value = get_option_value_for(opt_idx, req_scope == kOptReqGlobal ? OPT_GLOBAL : OPT_LOCAL, + req_scope, from, err); + if (ERROR_SET(err)) { + return (Object)OBJECT_INIT; + } } VALIDATE_S(value.type != kOptValTypeNil, "option name", name.data, { diff --git a/src/nvim/option.c b/src/nvim/option.c index a8ec5b2919..a7e56d6d39 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3978,76 +3978,6 @@ int get_option_attrs(OptIndex opt_idx) return attrs; } -/// Check if option has a value in the requested scope. -/// -/// @param opt_idx Option index in options[] table. -/// @param req_scope Requested option scope. See OptReqScope in option.h. -/// -/// @return true if option has a value in the requested scope, false otherwise. -static bool option_has_scope(OptIndex opt_idx, OptReqScope req_scope) -{ - if (opt_idx == kOptInvalid) { - return false; - } - - vimoption_T *opt = get_option(opt_idx); - - // Hidden option. - if (opt->var == NULL) { - return false; - } - // TTY option. - if (is_tty_option(opt->fullname)) { - return req_scope == kOptReqGlobal; - } - - switch (req_scope) { - case kOptReqGlobal: - return opt->var != VAR_WIN; - case kOptReqBuf: - return opt->indir & PV_BUF; - case kOptReqWin: - return opt->indir & PV_WIN; - } - UNREACHABLE; -} - -/// Get the option value in the requested scope. -/// -/// @param opt_idx Option index in options[] table. -/// @param req_scope Requested option scope. See OptReqScope in option.h. -/// @param[in] from Pointer to buffer or window for local option value. -/// @param[out] err Error message, if any. -/// -/// @return Option value in the requested scope. Returns a Nil option value if option is not found, -/// hidden or if it isn't present in the requested scope. (i.e. has no global, window-local or -/// buffer-local value depending on opt_scope). -OptVal get_option_value_strict(OptIndex opt_idx, OptReqScope req_scope, void *from, Error *err) -{ - if (opt_idx == kOptInvalid || !option_has_scope(opt_idx, req_scope)) { - return NIL_OPTVAL; - } - - vimoption_T *opt = get_option(opt_idx); - switchwin_T switchwin; - aco_save_T aco; - void *ctx = req_scope == kOptReqWin ? (void *)&switchwin - : (req_scope == kOptReqBuf ? (void *)&aco : NULL); - bool switched = switch_option_context(ctx, req_scope, from, err); - if (ERROR_SET(err)) { - return NIL_OPTVAL; - } - - char *varp = get_varp_scope(opt, req_scope == kOptReqGlobal ? OPT_GLOBAL : OPT_LOCAL); - OptVal retv = optval_from_varp(opt_idx, varp); - - if (switched) { - restore_option_context(ctx, req_scope); - } - - return retv; -} - /// Get option value for buffer / window. /// /// @param opt_idx Option index in options[] table. -- cgit From ed3fb1bb9ad97435c50655ee8de71b2d7d67d01c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 3 Nov 2024 08:27:15 +0800 Subject: vim-patch:9.1.0830: using wrong highlight group for spaces for popupmenu (#31054) Problem: using wrong highlight group for spaces for popupmenu Solution: use original attribute instead of combined attributed (glepnir) closes: vim/vim#15978 https://github.com/vim/vim/commit/bc10be7a4060748ed1876ab91cf53a2a8701ac13 Co-authored-by: glepnir --- src/nvim/popupmenu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 529d65c5dc..7df6a1a5d7 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -657,11 +657,14 @@ void pum_redraw(void) pum_align_order(order); int basic_width = items_width_array[order[0]]; // first item width bool last_isabbr = order[2] == CPT_ABBR; + int orig_attr = -1; + for (int j = 0; j < 3; j++) { int item_type = order[j]; hlf = hlfs[item_type]; attr = win_hl_attr(curwin, (int)hlf); - int orig_attr = attr; + attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), attr); + orig_attr = attr; int user_abbr_hlattr = pum_array[idx].pum_user_abbr_hlattr; int user_kind_hlattr = pum_array[idx].pum_user_kind_hlattr; if (item_type == CPT_ABBR && user_abbr_hlattr > 0) { @@ -670,7 +673,6 @@ void pum_redraw(void) if (item_type == CPT_KIND && user_kind_hlattr > 0) { attr = hl_combine_attr(attr, user_kind_hlattr); } - attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), attr); int width = 0; char *s = NULL; p = pum_get_item(idx, item_type); @@ -796,9 +798,9 @@ void pum_redraw(void) } if (pum_rl) { - grid_line_fill(col_off - pum_width + 1, grid_col + 1, schar_from_ascii(' '), attr); + grid_line_fill(col_off - pum_width + 1, grid_col + 1, schar_from_ascii(' '), orig_attr); } else { - grid_line_fill(grid_col, col_off + pum_width, schar_from_ascii(' '), attr); + grid_line_fill(grid_col, col_off + pum_width, schar_from_ascii(' '), orig_attr); } if (pum_scrollbar > 0) { -- cgit From 3075c69ff02faf396e5efbdcb4a255b0b0309649 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 3 Nov 2024 10:06:41 +0800 Subject: vim-patch:9.1.0831: 'findexpr' can't be used as lambad or Funcref (#31058) Problem: 'findexpr' can't be used for lambads (Justin Keyes) Solution: Replace the findexpr option with the findfunc option (Yegappan Lakshmanan) related: vim/vim#15905 closes: vim/vim#15976 https://github.com/vim/vim/commit/a13f3a4f5de9c150f70298850e34747838904995 Co-authored-by: Yegappan Lakshmanan --- src/nvim/buffer.c | 3 +- src/nvim/buffer_defs.h | 5 +- src/nvim/cmdexpand.c | 12 ++-- src/nvim/cmdexpand_defs.h | 2 +- src/nvim/errors.h | 2 +- src/nvim/eval.c | 6 +- src/nvim/eval.h | 1 - src/nvim/ex_docmd.c | 128 ++++++++++++++++++++++++++---------- src/nvim/generators/gen_options.lua | 1 + src/nvim/option.c | 22 +++---- src/nvim/option_vars.h | 2 +- src/nvim/options.lua | 51 +++++++------- src/nvim/optionstr.c | 7 +- src/nvim/vvars.lua | 10 +-- 14 files changed, 153 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 42cc745fe6..fe22742a84 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2049,7 +2049,6 @@ void free_buf_options(buf_T *buf, bool free_p_ff) clear_string_option(&buf->b_p_indk); clear_string_option(&buf->b_p_fp); clear_string_option(&buf->b_p_fex); - clear_string_option(&buf->b_p_fexpr); clear_string_option(&buf->b_p_kp); clear_string_option(&buf->b_p_mps); clear_string_option(&buf->b_p_fo); @@ -2098,6 +2097,8 @@ void free_buf_options(buf_T *buf, bool free_p_ff) clear_string_option(&buf->b_p_tc); clear_string_option(&buf->b_p_tfu); callback_free(&buf->b_tfu_cb); + clear_string_option(&buf->b_p_ffu); + callback_free(&buf->b_ffu_cb); clear_string_option(&buf->b_p_dict); clear_string_option(&buf->b_p_tsr); clear_string_option(&buf->b_p_qe); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 88e8d59faa..e6bd63f4f8 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -543,8 +543,10 @@ struct file_buffer { Callback b_cfu_cb; ///< 'completefunc' callback char *b_p_ofu; ///< 'omnifunc' Callback b_ofu_cb; ///< 'omnifunc' callback - char *b_p_tfu; ///< 'tagfunc' + char *b_p_tfu; ///< 'tagfunc' option value Callback b_tfu_cb; ///< 'tagfunc' callback + char *b_p_ffu; ///< 'findfunc' option value + Callback b_ffu_cb; ///< 'findfunc' callback int b_p_eof; ///< 'endoffile' int b_p_eol; ///< 'endofline' int b_p_fixeol; ///< 'fixendofline' @@ -608,7 +610,6 @@ struct file_buffer { char *b_p_mp; ///< 'makeprg' local value char *b_p_efm; ///< 'errorformat' local value char *b_p_ep; ///< 'equalprg' local value - char *b_p_fexpr; ///< 'findexpr' local value char *b_p_path; ///< 'path' local value int b_p_ar; ///< 'autoread' local value char *b_p_tags; ///< 'tags' local value diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index aeaed536fc..8d1f87cbcf 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -109,7 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp) && xp->xp_context != EXPAND_FILES && xp->xp_context != EXPAND_FILES_IN_PATH && xp->xp_context != EXPAND_FILETYPE - && xp->xp_context != EXPAND_FINDEXPR + && xp->xp_context != EXPAND_FINDFUNC && xp->xp_context != EXPAND_HELP && xp->xp_context != EXPAND_KEYMAP && xp->xp_context != EXPAND_LUA @@ -1229,7 +1229,7 @@ char *addstar(char *fname, size_t len, int context) // For help tags the translation is done in find_help_tags(). // For a tag pattern starting with "/" no translation is needed. - if (context == EXPAND_FINDEXPR + if (context == EXPAND_FINDFUNC || context == EXPAND_HELP || context == EXPAND_COLORS || context == EXPAND_COMPILER @@ -1829,7 +1829,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa case CMD_sfind: case CMD_tabfind: if (xp->xp_context == EXPAND_FILES) { - xp->xp_context = *get_findexpr() != NUL ? EXPAND_FINDEXPR : EXPAND_FILES_IN_PATH; + xp->xp_context = *get_findfunc() != NUL ? EXPAND_FINDFUNC : EXPAND_FILES_IN_PATH; } break; case CMD_cd: @@ -2500,8 +2500,8 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int * } int ret = FAIL; - if (xp->xp_context == EXPAND_FINDEXPR) { - ret = expand_findexpr(pat, matches, numMatches); + if (xp->xp_context == EXPAND_FINDFUNC) { + ret = expand_findfunc(pat, matches, numMatches); } else { if (xp->xp_context == EXPAND_FILES) { flags |= EW_FILE; @@ -2722,7 +2722,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES || xp->xp_context == EXPAND_FILES_IN_PATH - || xp->xp_context == EXPAND_FINDEXPR + || xp->xp_context == EXPAND_FINDFUNC || xp->xp_context == EXPAND_DIRS_IN_CDPATH) { return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options); } diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h index ce51f30bec..dfda9fdaed 100644 --- a/src/nvim/cmdexpand_defs.h +++ b/src/nvim/cmdexpand_defs.h @@ -107,7 +107,7 @@ enum { EXPAND_KEYMAP, EXPAND_DIRS_IN_CDPATH, EXPAND_SHELLCMDLINE, - EXPAND_FINDEXPR, + EXPAND_FINDFUNC, EXPAND_CHECKHEALTH, EXPAND_LUA, }; diff --git a/src/nvim/errors.h b/src/nvim/errors.h index 6682a42d61..7897a71489 100644 --- a/src/nvim/errors.h +++ b/src/nvim/errors.h @@ -186,7 +186,7 @@ INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch") EXTERN const char e_winfixbuf_cannot_go_to_buffer[] INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); -EXTERN const char e_invalid_return_type_from_findexpr[] INIT( = N_("E1514: 'findexpr' did not return a List type")); +EXTERN const char e_invalid_return_type_from_findfunc[] INIT( = N_("E1514: 'findfunc' did not return a List type")); EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index bf85ed1646..58c98c42ff 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -270,7 +270,6 @@ static struct vimvar { VV(VV_COLLATE, "collate", VAR_STRING, VV_RO), VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO), VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO), - VV(VV_CMDCOMPLETE, "cmdcomplete", VAR_BOOL, VV_RO), // Neovim VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO), VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO), @@ -462,7 +461,6 @@ void eval_init(void) set_vim_var_nr(VV_HLSEARCH, 1); set_vim_var_nr(VV_COUNT1, 1); set_vim_var_special(VV_EXITING, kSpecialVarNull); - set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse); set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER); set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING); @@ -4793,6 +4791,7 @@ bool garbage_collect(bool testing) ABORTING(set_ref_in_callback)(&buf->b_ofu_cb, copyID, NULL, NULL); ABORTING(set_ref_in_callback)(&buf->b_tsrfu_cb, copyID, NULL, NULL); ABORTING(set_ref_in_callback)(&buf->b_tfu_cb, copyID, NULL, NULL); + ABORTING(set_ref_in_callback)(&buf->b_ffu_cb, copyID, NULL, NULL); } // 'completefunc', 'omnifunc' and 'thesaurusfunc' callbacks @@ -4804,6 +4803,9 @@ bool garbage_collect(bool testing) // 'tagfunc' callback ABORTING(set_ref_in_tagfunc)(copyID); + // 'findfunc' callback + ABORTING(set_ref_in_findfunc)(copyID); + FOR_ALL_TAB_WINDOWS(tp, wp) { // window-local variables ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL); diff --git a/src/nvim/eval.h b/src/nvim/eval.h index b5605bb644..bb9b00abc7 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -167,7 +167,6 @@ typedef enum { VV_COLLATE, VV_EXITING, VV_MAXCOL, - VV_CMDCOMPLETE, // Nvim VV_STDERR, VV_MSGPACK_TYPES, diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 74ba19b30a..1c215cd3e1 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5165,55 +5165,68 @@ static void ex_wrongmodifier(exarg_T *eap) eap->errmsg = _(e_invcmd); } -/// Evaluate the 'findexpr' expression and return the result. When evaluating -/// the expression, v:fname is set to the ":find" command argument. -static list_T *eval_findexpr(const char *pat, bool cmdcomplete) +/// callback function for 'findfunc' +static Callback ffu_cb; + +static Callback *get_findfunc_callback(void) +{ + return *curbuf->b_p_ffu != NUL ? &curbuf->b_ffu_cb : &ffu_cb; +} + +/// Call 'findfunc' to obtain the list of file names. +static list_T *call_findfunc(char *pat, BoolVarValue cmdcomplete) { const sctx_T saved_sctx = current_sctx; - char *findexpr = get_findexpr(); + typval_T args[3]; + args[0].v_type = VAR_STRING; + args[0].vval.v_string = pat; + args[1].v_type = VAR_BOOL; + args[1].vval.v_bool = cmdcomplete; + args[2].v_type = VAR_UNKNOWN; - set_vim_var_string(VV_FNAME, pat, -1); - set_vim_var_bool(VV_CMDCOMPLETE, cmdcomplete ? kBoolVarTrue : kBoolVarFalse); - current_sctx = curbuf->b_p_script_ctx[BV_FEXPR].script_ctx; + // Lock the text to prevent weird things from happening. Also disallow + // switching to another window, it should not be needed and may end up in + // Insert mode in another buffer. + textlock++; - char *arg = skipwhite(findexpr); + sctx_T *ctx = get_option_sctx(kOptFindfunc); + if (ctx != NULL) { + current_sctx = *ctx; + } - textlock++; + Callback *cb = get_findfunc_callback(); + typval_T rettv; + int retval = callback_call(cb, 2, args, &rettv); + + current_sctx = saved_sctx; + + textlock--; - // Evaluate the expression. If the expression is "FuncName()" call the - // function directly. - typval_T tv; list_T *retlist = NULL; - if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { - retlist = NULL; - } else { - if (tv.v_type == VAR_LIST) { - retlist = tv_list_copy(NULL, tv.vval.v_list, true, get_copyID()); + + if (retval == OK) { + if (rettv.v_type == VAR_LIST) { + retlist = tv_list_copy(NULL, rettv.vval.v_list, false, get_copyID()); } else { - emsg(_(e_invalid_return_type_from_findexpr)); + emsg(_(e_invalid_return_type_from_findfunc)); } - tv_clear(&tv); - } - textlock--; - clear_evalarg(&EVALARG_EVALUATE, NULL); - set_vim_var_string(VV_FNAME, NULL, 0); - set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse); - current_sctx = saved_sctx; + tv_clear(&rettv); + } return retlist; } -/// Find file names matching "pat" using 'findexpr' and return it in "files". +/// Find file names matching "pat" using 'findfunc' and return it in "files". /// Used for expanding the :find, :sfind and :tabfind command argument. /// Returns OK on success and FAIL otherwise. -int expand_findexpr(const char *pat, char ***files, int *numMatches) +int expand_findfunc(char *pat, char ***files, int *numMatches) { *numMatches = 0; *files = NULL; - list_T *l = eval_findexpr(pat, true); + list_T *l = call_findfunc(pat, kBoolVarTrue); if (l == NULL) { return FAIL; } @@ -5240,16 +5253,16 @@ int expand_findexpr(const char *pat, char ***files, int *numMatches) return OK; } -/// Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find +/// Use 'findfunc' to find file 'findarg'. The 'count' argument is used to find /// the n'th matching file. -static char *findexpr_find_file(char *findarg, size_t findarg_len, int count) +static char *findfunc_find_file(char *findarg, size_t findarg_len, int count) { char *ret_fname = NULL; const char cc = findarg[findarg_len]; findarg[findarg_len] = NUL; - list_T *fname_list = eval_findexpr(findarg, false); + list_T *fname_list = call_findfunc(findarg, kBoolVarFalse); int fname_count = tv_list_len(fname_list); if (fname_count == 0) { @@ -5274,6 +5287,51 @@ static char *findexpr_find_file(char *findarg, size_t findarg_len, int count) return ret_fname; } +/// Process the 'findfunc' option value. +/// Returns NULL on success and an error message on failure. +const char *did_set_findfunc(optset_T *args) +{ + buf_T *buf = (buf_T *)args->os_buf; + int retval; + + if (*buf->b_p_ffu != NUL) { + // buffer-local option set + retval = option_set_callback_func(buf->b_p_ffu, &buf->b_ffu_cb); + } else { + // global option set + retval = option_set_callback_func(p_ffu, &ffu_cb); + } + + if (retval == FAIL) { + return e_invarg; + } + + // If the option value starts with or s:, then replace that with + // the script identifier. + char **varp = (char **)args->os_varp; + char *name = get_scriptlocal_funcname(*varp); + if (name != NULL) { + free_string_option(*varp); + *varp = name; + } + + return NULL; +} + +void free_findfunc_option(void) +{ + callback_free(&ffu_cb); +} + +/// Mark the global 'findfunc' callback with "copyID" so that it is not +/// garbage collected. +bool set_ref_in_findfunc(int copyID) +{ + bool abort = false; + abort = set_ref_in_callback(&ffu_cb, copyID, NULL, NULL); + return abort; +} + /// :sview [+command] file split window with new file, read-only /// :split [[+command] file] split window with current or new file /// :vsplit [[+command] file] split window vertically with current or new file @@ -5305,8 +5363,8 @@ void ex_splitview(exarg_T *eap) } if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { - if (*get_findexpr() != NUL) { - fname = findexpr_find_file(eap->arg, strlen(eap->arg), + if (*get_findfunc() != NUL) { + fname = findfunc_find_file(eap->arg, strlen(eap->arg), eap->addr_count > 0 ? eap->line2 : 1); } else { char *file_to_find = NULL; @@ -5512,8 +5570,8 @@ static void ex_find(exarg_T *eap) } char *fname = NULL; - if (*get_findexpr() != NUL) { - fname = findexpr_find_file(eap->arg, strlen(eap->arg), + if (*get_findfunc() != NUL) { + fname = findfunc_find_file(eap->arg, strlen(eap->arg), eap->addr_count > 0 ? eap->line2 : 1); } else { char *file_to_find = NULL; diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 0cb5fa8e95..8397a434e4 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -260,6 +260,7 @@ local function dump_option(i, o) end w([[ +#include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/insexpand.h" #include "nvim/mapping.h" diff --git a/src/nvim/option.c b/src/nvim/option.c index a7e56d6d39..5d2e1ce4c6 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -578,6 +578,7 @@ void free_all_options(void) } free_operatorfunc_option(); free_tagfunc_option(); + free_findfunc_option(); XFREE_CLEAR(fenc_default); XFREE_CLEAR(p_term); XFREE_CLEAR(p_ttytype); @@ -4472,8 +4473,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) switch ((int)p->indir) { case PV_FP: return &(buf->b_p_fp); - case PV_FEXPR: - return &(buf->b_p_fexpr); + case PV_FFU: + return &(buf->b_p_ffu); case PV_EFM: return &(buf->b_p_efm); case PV_GP: @@ -4595,8 +4596,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var; case PV_FP: return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var; - case PV_FEXPR: - return *buf->b_p_fexpr != NUL ? &(buf->b_p_fexpr) : p->var; + case PV_FFU: + return *buf->b_p_ffu != NUL ? &(buf->b_p_ffu) : p->var; case PV_EFM: return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var; case PV_GP: @@ -4868,13 +4869,13 @@ char *get_equalprg(void) return curbuf->b_p_ep; } -/// Get the value of 'findexpr', either the buffer-local one or the global one. -char *get_findexpr(void) +/// Get the value of 'findfunc', either the buffer-local one or the global one. +char *get_findfunc(void) { - if (*curbuf->b_p_fexpr == NUL) { - return p_fexpr; + if (*curbuf->b_p_ffu == NUL) { + return p_ffu; } - return curbuf->b_p_fexpr; + return curbuf->b_p_ffu; } /// Copy options from one window to another. @@ -5275,8 +5276,7 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_mp = empty_string_option; buf->b_p_efm = empty_string_option; buf->b_p_ep = empty_string_option; - buf->b_p_fexpr = xstrdup(p_fexpr); - COPY_OPT_SCTX(buf, BV_FEXPR); + buf->b_p_ffu = empty_string_option; buf->b_p_kp = empty_string_option; buf->b_p_path = empty_string_option; buf->b_p_tags = empty_string_option; diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index a88b51dae7..d59a4549d1 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -451,7 +451,7 @@ EXTERN char *p_ffs; ///< 'fileformats' EXTERN int p_fic; ///< 'fileignorecase' EXTERN char *p_ft; ///< 'filetype' EXTERN char *p_fcs; ///< 'fillchar' -EXTERN char *p_fexpr; ///< 'findexpr' +EXTERN char *p_ffu; ///< 'findfunc' EXTERN int p_fixeol; ///< 'fixendofline' EXTERN char *p_fcl; ///< 'foldclose' EXTERN OptInt p_fdls; ///< 'foldlevelstart' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 1b8e3ea256..3c21436c3a 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2906,35 +2906,35 @@ return { varname = 'p_fcs', }, { - abbreviation = 'fexpr', - cb = 'did_set_optexpr', + abbreviation = 'ffu', + cb = 'did_set_findfunc', defaults = { if_true = '' }, desc = [=[ - Expression that is evaluated to obtain the filename(s) for the |:find| + Function that is called to obtain the filename(s) for the |:find| command. When this option is empty, the internal |file-searching| mechanism is used. - While evaluating the expression, the |v:fname| variable is set to the - argument of the |:find| command. + The value can be the name of a function, a |lambda| or a |Funcref|. + See |option-value-function| for more information. - The expression is evaluated only once per |:find| command invocation. - The expression can process all the directories specified in 'path'. + The function is called with two arguments. The first argument is a + |String| and is the |:find| command argument. The second argument is + a |Boolean| and is set to |v:true| when the function is called to get + a List of command-line completion matches for the |:find| command. + The function should return a List of strings. - The expression may be evaluated for command-line completion as well, - in which case the |v:cmdcomplete| variable will be set to |v:true|, - otherwise it will be set to |v:false|. + The function is called only once per |:find| command invocation. + The function can process all the directories specified in 'path'. - If a match is found, the expression should return a |List| containing - one or more file names. If a match is not found, the expression + If a match is found, the function should return a |List| containing + one or more file names. If a match is not found, the function should return an empty List. - If any errors are encountered during the expression evaluation, an + If any errors are encountered during the function invocation, an empty List is used as the return value. - Using a function call without arguments is faster |expr-option-function| - It is not allowed to change text or jump to another window while - evaluating 'findexpr' |textlock|. + executing the 'findfunc' |textlock|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. @@ -2942,27 +2942,28 @@ return { Examples: >vim " Use glob() - func FindExprGlob() - let pat = v:cmdcomplete ? $'{v:fname}*' : v:fname + func FindFuncGlob(cmdarg, cmdcomplete) + let pat = a:cmdcomplete ? $'{a:cmdarg}*' : a:cmdarg return glob(pat, v:false, v:true) endfunc - set findexpr=FindExprGlob() + set findfunc=FindFuncGlob " Use the 'git ls-files' output - func FindGitFiles() + func FindGitFiles(cmdarg, cmdcomplete) let fnames = systemlist('git ls-files') - return fnames->filter('v:val =~? v:fname') + return fnames->filter('v:val =~? a:cmdarg') endfunc - set findexpr=FindGitFiles() + set findfunc=FindGitFiles < ]=], - full_name = 'findexpr', + full_name = 'findfunc', + func = true, scope = { 'global', 'buffer' }, secure = true, - short_desc = N_('expression used for :find'), + short_desc = N_('function called for :find'), tags = { 'E1514' }, type = 'string', - varname = 'p_fexpr', + varname = 'p_ffu', }, { abbreviation = 'fixeol', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index c66849800c..307c4ae79f 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -233,9 +233,9 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_mp); check_string_option(&buf->b_p_efm); check_string_option(&buf->b_p_ep); - check_string_option(&buf->b_p_fexpr); check_string_option(&buf->b_p_path); check_string_option(&buf->b_p_tags); + check_string_option(&buf->b_p_ffu); check_string_option(&buf->b_p_tfu); check_string_option(&buf->b_p_tc); check_string_option(&buf->b_p_dict); @@ -1886,9 +1886,8 @@ int expand_set_nrformats(optexpand_T *args, int *numMatches, char ***matches) matches); } -/// One of the '*expr' options is changed:, 'diffexpr', 'findexpr', -/// 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr', -/// 'patchexpr' and 'charconvert'. +/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext', +/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'. const char *did_set_optexpr(optset_T *args) { char **varp = (char **)args->os_varp; diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index 6c6edd4ee2..ad139bbbfe 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -50,13 +50,6 @@ M.vars = { can be used. ]=], }, - cmdcomplete = { - type = 'boolean', - desc = [=[ - When evaluating 'findexpr': if 'findexpr' is used for cmdline - completion the value is |v:true|, otherwise it is |v:false|. - ]=], - }, collate = { type = 'string', desc = [=[ @@ -291,8 +284,7 @@ M.vars = { type = 'string', desc = [=[ When evaluating 'includeexpr': the file name that was - detected. When evaluating 'findexpr': the argument passed to - the |:find| command. Empty otherwise. + detected. Empty otherwise. ]=], }, fname_diff = { -- cgit From 981fa11c91d3655828b4f70ccf7d079d917d5b6b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 3 Nov 2024 16:52:20 +0800 Subject: vim-patch:9.1.0832: :set doesn't work for 'cot' and 'bkc' after :setlocal Problem: :set doesn't work for 'cot' and 'bkc' after :setlocal. Solution: clear the local flags when using :set (zeertzjq). closes: vim/vim#15981 https://github.com/vim/vim/commit/46dcd84d242db6b053cb5b777c896cede9ad9b27 --- src/nvim/optionstr.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 307c4ae79f..48423a1779 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -655,6 +655,9 @@ const char *did_set_backupcopy(optset_T *args) if (opt_flags & OPT_LOCAL) { bkc = buf->b_p_bkc; flags = &buf->b_bkc_flags; + } else if (!(opt_flags & OPT_GLOBAL)) { + // When using :set, clear the local flags. + buf->b_bkc_flags = 0; } if ((opt_flags & OPT_LOCAL) && *bkc == NUL) { @@ -1070,6 +1073,9 @@ const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED) if (args->os_flags & OPT_LOCAL) { cot = buf->b_p_cot; flags = &buf->b_cot_flags; + } else if (!(args->os_flags & OPT_GLOBAL)) { + // When using :set, clear the local flags. + buf->b_cot_flags = 0; } if (check_opt_strings(cot, p_cot_values, true) != OK) { -- cgit From fe565ca382bb6cc4cd9f1c01de42d62c48922bf6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 3 Nov 2024 16:54:25 +0800 Subject: vim-patch:9.1.0835: :setglobal doesn't work properly for 'ffu' and 'tsrfu' Problem: :setglobal doesn't work properly for 'ffu' and 'tsrfu' when the local value is set (after v9.1.0831) Solution: Check os_flags instead of buffer option variable (zeertzjq). closes: vim/vim#15980 https://github.com/vim/vim/commit/6eda269600b5ca952f28e808c662f67e581933d7 --- src/nvim/ex_docmd.c | 8 ++++++-- src/nvim/insexpand.c | 17 +++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1c215cd3e1..92695aa4de 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5173,7 +5173,7 @@ static Callback *get_findfunc_callback(void) return *curbuf->b_p_ffu != NUL ? &curbuf->b_ffu_cb : &ffu_cb; } -/// Call 'findfunc' to obtain the list of file names. +/// Call 'findfunc' to obtain a list of file names. static list_T *call_findfunc(char *pat, BoolVarValue cmdcomplete) { const sctx_T saved_sctx = current_sctx; @@ -5294,12 +5294,16 @@ const char *did_set_findfunc(optset_T *args) buf_T *buf = (buf_T *)args->os_buf; int retval; - if (*buf->b_p_ffu != NUL) { + if (args->os_flags & OPT_LOCAL) { // buffer-local option set retval = option_set_callback_func(buf->b_p_ffu, &buf->b_ffu_cb); } else { // global option set retval = option_set_callback_func(p_ffu, &ffu_cb); + // when using :set, free the local callback + if (!(args->os_flags & OPT_GLOBAL)) { + callback_free(&buf->b_ffu_cb); + } } if (retval == FAIL) { diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 2482cef7a1..c8314d1bb2 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -2368,13 +2368,13 @@ static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb) /// Invoked when the 'completefunc' option is set. The option value can be a /// name of a function (string), or function() or funcref() or a /// lambda expression. -const char *did_set_completefunc(optset_T *args FUNC_ATTR_UNUSED) +const char *did_set_completefunc(optset_T *args) { - if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL) { + buf_T *buf = (buf_T *)args->os_buf; + if (option_set_callback_func(buf->b_p_cfu, &cfu_cb) == FAIL) { return e_invarg; } - - set_buflocal_cfu_callback(curbuf); + set_buflocal_cfu_callback(buf); return NULL; } @@ -2412,14 +2412,19 @@ void set_buflocal_ofu_callback(buf_T *buf) /// lambda expression. const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED) { + buf_T *buf = (buf_T *)args->os_buf; int retval; - if (*curbuf->b_p_tsrfu != NUL) { + if (args->os_flags & OPT_LOCAL) { // buffer-local option set - retval = option_set_callback_func(curbuf->b_p_tsrfu, &curbuf->b_tsrfu_cb); + retval = option_set_callback_func(buf->b_p_tsrfu, &buf->b_tsrfu_cb); } else { // global option set retval = option_set_callback_func(p_tsrfu, &tsrfu_cb); + // when using :set, free the local callback + if (!(args->os_flags & OPT_GLOBAL)) { + callback_free(&buf->b_tsrfu_cb); + } } return retval == FAIL ? e_invarg : NULL; -- cgit From 23290e7676e6f0a5cb5d9dc9fa1933df815aed33 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 29 Sep 2024 10:05:27 +0200 Subject: feat(editor): handle new multibyte sequences in normal mode replacement while the implementation is not tied to screen chars, it is a reasonable expectation to support the same size. If nvim is able to display a multibyte character, it will accept the same character as input, including in normal mode commands like r{char} --- src/nvim/grid_defs.h | 4 ---- src/nvim/mbyte.c | 10 +++++++-- src/nvim/normal.c | 55 +++++++++++++++++++++++++++++--------------------- src/nvim/normal_defs.h | 5 +++-- src/nvim/search.c | 15 ++++++-------- src/nvim/types_defs.h | 4 ++++ 6 files changed, 53 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h index 19a79ff810..8fa3092fd6 100644 --- a/src/nvim/grid_defs.h +++ b/src/nvim/grid_defs.h @@ -7,10 +7,6 @@ #include "nvim/pos_defs.h" #include "nvim/types_defs.h" -// Includes final NUL. MAX_MCO is no longer used, but at least 4*(MAX_MCO+1)+1=29 -// ensures we can fit all composed chars which did fit before. -#define MAX_SCHAR_SIZE 32 - enum { kZIndexDefaultGrid = 0, kZIndexFloatDefault = 50, diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 6340ff8c94..65f718f925 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -839,6 +839,13 @@ bool utf_composinglike(const char *p1, const char *p2, GraphemeState *state) return arabic_combine(first, second); } +/// same as utf_composinglike but operating on UCS-4 values +bool utf_iscomposing(int c1, int c2, GraphemeState *state) +{ + return (!utf8proc_grapheme_break_stateful(c1, c2, state) + || arabic_combine(c1, c2)); +} + /// Get the screen char at the beginning of a string /// /// Caller is expected to check for things like unprintable chars etc @@ -1852,8 +1859,7 @@ StrCharInfo utfc_next_impl(StrCharInfo cur) while (true) { uint8_t const next_len = utf8len_tab[*next]; int32_t const next_code = utf_ptr2CharInfo_impl(next, (uintptr_t)next_len); - if (utf8proc_grapheme_break_stateful(prev_code, next_code, &state) - && !arabic_combine(prev_code, next_code)) { + if (!utf_iscomposing(prev_code, next_code, &state)) { return (StrCharInfo){ .ptr = (char *)next, .chr = (CharInfo){ .value = next_code, .len = (next_code < 0 ? 1 : next_len) }, diff --git a/src/nvim/normal.c b/src/nvim/normal.c index be9987cc7f..aa247e39e6 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -835,21 +835,29 @@ static void normal_get_additional_char(NormalState *s) // because if it's put back with vungetc() it's too late to apply // mapping. no_mapping--; + GraphemeState state = GRAPHEME_STATE_INIT; + int prev_code = s->ca.nchar; + while ((s->c = vpeekc()) > 0 && (s->c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) { s->c = plain_vgetc(); - // TODO(bfredl): only allowing up to two composing chars is cringe af. - // Could reuse/abuse schar_T to at least allow us to input anything we are able - // to display and use the stateful utf8proc algorithm like utf_composinglike - if (!utf_iscomposing_legacy(s->c)) { + + if (!utf_iscomposing(prev_code, s->c, &state)) { vungetc(s->c); // it wasn't, put it back break; - } else if (s->ca.ncharC1 == 0) { - s->ca.ncharC1 = s->c; - } else { - s->ca.ncharC2 = s->c; } + + // first composing char, first put base char into buffer + if (s->ca.nchar_len == 0) { + s->ca.nchar_len = utf_char2bytes(s->ca.nchar, s->ca.nchar_composing); + } + + if (s->ca.nchar_len + utf_char2len(s->c) < (int)sizeof(s->ca.nchar_composing)) { + s->ca.nchar_len += utf_char2bytes(s->c, s->ca.nchar_composing + s->ca.nchar_len); + } + prev_code = s->c; } + s->ca.nchar_composing[s->ca.nchar_len] = NUL; no_mapping++; // Vim may be in a different mode when the user types the next key, // but when replaying a recording the next key is already in the @@ -1735,7 +1743,12 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text static void prep_redo_cmd(cmdarg_T *cap) { prep_redo(cap->oap->regname, cap->count0, - NUL, cap->cmdchar, NUL, NUL, cap->nchar); + NUL, cap->cmdchar, NUL, NUL, NUL); + if (cap->nchar_len > 0) { + AppendToRedobuff(cap->nchar_composing); + } else { + AppendCharToRedobuff(cap->nchar); + } } /// Prepare for redo of any command. @@ -4548,17 +4561,15 @@ static void nv_replace(cmdarg_T *cap) // Give 'r' to edit(), to get the redo command right. invoke_edit(cap, true, 'r', false); } else { - prep_redo(cap->oap->regname, cap->count1, - NUL, 'r', NUL, had_ctrl_v, cap->nchar); + prep_redo(cap->oap->regname, cap->count1, NUL, 'r', NUL, had_ctrl_v, 0); curbuf->b_op_start = curwin->w_cursor; const int old_State = State; - if (cap->ncharC1 != 0) { - AppendCharToRedobuff(cap->ncharC1); - } - if (cap->ncharC2 != 0) { - AppendCharToRedobuff(cap->ncharC2); + if (cap->nchar_len > 0) { + AppendToRedobuff(cap->nchar_composing); + } else { + AppendCharToRedobuff(cap->nchar); } // This is slow, but it handles replacing a single-byte with a @@ -4576,15 +4587,13 @@ static void nv_replace(cmdarg_T *cap) curwin->w_cursor.col++; } } else { - ins_char(cap->nchar); + if (cap->nchar_len) { + ins_char_bytes(cap->nchar_composing, (size_t)cap->nchar_len); + } else { + ins_char(cap->nchar); + } } State = old_State; - if (cap->ncharC1 != 0) { - ins_char(cap->ncharC1); - } - if (cap->ncharC2 != 0) { - ins_char(cap->ncharC2); - } } curwin->w_cursor.col--; // cursor on the last replaced char // if the character on the left of the current cursor is a multi-byte diff --git a/src/nvim/normal_defs.h b/src/nvim/normal_defs.h index 0309f6bc80..7b49b28a0f 100644 --- a/src/nvim/normal_defs.h +++ b/src/nvim/normal_defs.h @@ -3,6 +3,7 @@ #include #include "nvim/pos_defs.h" +#include "nvim/types_defs.h" /// Motion types, used for operators and for yank/delete registers. /// @@ -47,8 +48,8 @@ typedef struct { int prechar; ///< prefix character (optional, always 'g') int cmdchar; ///< command character int nchar; ///< next command character (optional) - int ncharC1; ///< first composing character (optional) - int ncharC2; ///< second composing character (optional) + char nchar_composing[MAX_SCHAR_SIZE]; ///< next char with composing chars (optional) + int nchar_len; ///< len of nchar_composing (when zero, use nchar instead) int extra_char; ///< yet another character (optional) int opcount; ///< count before an operator int count0; ///< count before command, default 0 diff --git a/src/nvim/search.c b/src/nvim/search.c index 2a935f6878..5d3d3db3fe 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -113,7 +113,7 @@ static int last_idx = 0; // index in spats[] for RE_LAST static uint8_t lastc[2] = { NUL, NUL }; // last character searched for static Direction lastcdir = FORWARD; // last direction of character search static bool last_t_cmd = true; // last search t_cmd -static char lastc_bytes[MB_MAXBYTES + 1]; +static char lastc_bytes[MAX_SCHAR_SIZE + 1]; static int lastc_bytelen = 1; // >1 for multi-byte char // copy of spats[], for keeping the search patterns while executing autocmds @@ -1550,14 +1550,11 @@ int searchc(cmdarg_T *cap, bool t_cmd) *lastc = (uint8_t)c; set_csearch_direction(dir); set_csearch_until(t_cmd); - lastc_bytelen = utf_char2bytes(c, lastc_bytes); - if (cap->ncharC1 != 0) { - lastc_bytelen += utf_char2bytes(cap->ncharC1, - lastc_bytes + lastc_bytelen); - if (cap->ncharC2 != 0) { - lastc_bytelen += utf_char2bytes(cap->ncharC2, - lastc_bytes + lastc_bytelen); - } + if (cap->nchar_len) { + lastc_bytelen = cap->nchar_len; + memcpy(lastc_bytes, cap->nchar_composing, (size_t)cap->nchar_len); + } else { + lastc_bytelen = utf_char2bytes(c, lastc_bytes); } } } else { // repeat previous search diff --git a/src/nvim/types_defs.h b/src/nvim/types_defs.h index 2dd2b01adf..bec0950653 100644 --- a/src/nvim/types_defs.h +++ b/src/nvim/types_defs.h @@ -12,6 +12,10 @@ typedef int32_t sattr_T; // must be at least as big as the biggest of schar_T, sattr_T, colnr_T typedef int32_t sscratch_T; +// Includes final NUL. MAX_MCO is no longer used, but at least 4*(MAX_MCO+1)+1=29 +// ensures we can fit all composed chars which did fit before. +#define MAX_SCHAR_SIZE 32 + // Opaque handle used by API clients to refer to various objects in vim typedef int handle_T; -- cgit From a27419f3fc540f66567f4559a796cd6758f1bb1f Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Mon, 4 Nov 2024 19:00:12 +0600 Subject: feat(options)!: disallow setting hidden options #28400 Problem: There are three different ways of marking an option as hidden, `enable_if = false`, `hidden = true` and `immutable = true`. These also have different behaviors. Options hidden with `enable_if = false` can't have their value fetched using Vim script or the API, but options hidden with `hidden = true` or `immutable = true` can. On the other hand, options with `hidden = true` do not error when trying to set their value, but options with `immutable = true` do. Solution: Remove `enable_if = false`, remove the `hidden` property for options, and use `immutable = true` to mark an option as hidden instead. Also make hidden option variable pointers always point to the default value, which allows fetching the value of every hidden option using Vim script and the API. This does also mean that trying to set a hidden option will now give an error instead of just being ignored. --- src/nvim/api/deprecated.c | 4 -- src/nvim/api/options.c | 5 +-- src/nvim/generators/gen_options.lua | 19 ++++------ src/nvim/option.c | 76 ++++++++++++++++--------------------- src/nvim/option.h | 1 - src/nvim/option_vars.h | 1 + src/nvim/options.lua | 37 ++++++++++-------- 7 files changed, 65 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 5c0d9c0cea..b3ba832fec 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -647,10 +647,6 @@ static bool option_has_scope(OptIndex opt_idx, OptReqScope req_scope) vimoption_T *opt = get_option(opt_idx); - // Hidden option. - if (opt->var == NULL) { - return false; - } // TTY option. if (is_tty_option(opt->fullname)) { return req_scope == kOptReqGlobal; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 1a0edd551e..96866d80ba 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -80,7 +80,7 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * *opt_idxp = find_option(name); int flags = get_option_attrs(*opt_idxp); if (flags == 0) { - // hidden or unknown option + // unknown option api_set_error(err, kErrorTypeValidation, "Unknown option '%s'", name); } else if (*req_scope == kOptReqBuf || *req_scope == kOptReqWin) { // if 'buf' or 'win' is passed, make sure the option supports it @@ -175,7 +175,6 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) } OptVal value = get_option_value_for(opt_idx, scope, req_scope, from, err); - bool hidden = is_option_hidden(opt_idx); if (ftbuf != NULL) { // restore curwin/curbuf and a few other things @@ -189,7 +188,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) goto err; } - VALIDATE_S(!hidden && value.type != kOptValTypeNil, "option", name.data, { + VALIDATE_S(value.type != kOptValTypeNil, "option", name.data, { goto err; }); diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 8397a434e4..92349b5298 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -191,23 +191,17 @@ local function dump_option(i, o) w(get_cond(o.enable_if)) end - -- An option cannot be both hidden and immutable. - assert(not o.hidden or not o.immutable) - - local has_var = true if o.varname then w(' .var=&' .. o.varname) - elseif o.hidden or o.immutable then - -- Hidden and immutable options can directly point to the default value. + elseif o.immutable then + -- Immutable options can directly point to the default value. w((' .var=&options[%u].def_val.data'):format(i - 1)) elseif #o.scope == 1 and o.scope[1] == 'window' then w(' .var=VAR_WIN') else - has_var = false + -- Option must be immutable or have a variable. + assert(false) end - -- `enable_if = false` should be present iff there is no variable. - assert((o.enable_if == false) == not has_var) - w(' .hidden=' .. (o.hidden and 'true' or 'false')) w(' .immutable=' .. (o.immutable and 'true' or 'false')) if #o.scope == 1 and o.scope[1] == 'global' then w(' .indir=PV_NONE') @@ -237,7 +231,10 @@ local function dump_option(i, o) end if o.enable_if then w('#else') - w(' .var=NULL') + -- Hidden option directly points to default value. + w((' .var=&options[%u].def_val.data'):format(i - 1)) + -- Option is always immutable on the false branch of `enable_if`. + w(' .immutable=true') w(' .indir=PV_NONE') w('#endif') end diff --git a/src/nvim/option.c b/src/nvim/option.c index 5d2e1ce4c6..783ec0abf4 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -565,13 +565,16 @@ static char *find_dup_item(char *origval, const char *newval, const size_t newva void free_all_options(void) { for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { - if (options[opt_idx].indir == PV_NONE) { + bool hidden = is_option_hidden(opt_idx); + + if (options[opt_idx].indir == PV_NONE || hidden) { // global option: free value and default value. - if (options[opt_idx].var != NULL) { + // hidden option: free default value only. + if (!hidden) { optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } } else if (options[opt_idx].var != VAR_WIN) { - // buffer-local option: free global value + // buffer-local option: free global value. optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } optval_free(options[opt_idx].def_val); @@ -1244,16 +1247,6 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * uint32_t flags = 0; // flags for current option void *varp = NULL; // pointer to variable for current option - if (options[opt_idx].var == NULL) { // hidden option: skip - // Only give an error message when requesting the value of - // a hidden option, ignore setting it. - if (vim_strchr("=:!&<", nextchar) == NULL - && (!option_has_type(opt_idx, kOptValTypeBoolean) || nextchar == '?')) { - *errmsg = e_unsupportedoption; - } - return; - } - flags = options[opt_idx].flags; varp = get_varp_scope(&(options[opt_idx]), opt_flags); @@ -1325,11 +1318,6 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * } } - // Don't try to change hidden option. - if (varp == NULL) { - return; - } - OptVal newval = get_option_newval(opt_idx, opt_flags, prefix, argp, nextchar, op, flags, varp, errbuf, errbuflen, errmsg); @@ -1587,7 +1575,7 @@ char *find_shada_parameter(int type) static char *option_expand(OptIndex opt_idx, char *val) { // if option doesn't need expansion nothing to do - if (!(options[opt_idx].flags & kOptFlagExpand) || options[opt_idx].var == NULL) { + if (!(options[opt_idx].flags & kOptFlagExpand) || is_option_hidden(opt_idx)) { return NULL; } @@ -2863,6 +2851,8 @@ static const char *validate_num_option(OptIndex opt_idx, void *varp, OptInt *new } else if (value > p_wiw) { return e_winwidth; } + } else if (varp == &p_mco) { + *newval = MAX_MCO; } else if (varp == &p_titlelen) { if (value < 0) { return e_positive; @@ -3161,6 +3151,7 @@ static OptValType option_get_type(const OptIndex opt_idx) /// /// @return Option value stored in varp. OptVal optval_from_varp(OptIndex opt_idx, void *varp) + FUNC_ATTR_NONNULL_ARG(2) { // Special case: 'modified' is b_changed, but we also want to consider it set when 'ff' or 'fenc' // changed. @@ -3170,7 +3161,7 @@ OptVal optval_from_varp(OptIndex opt_idx, void *varp) if (option_is_multitype(opt_idx)) { // Multitype options are stored as OptVal. - return varp == NULL ? NIL_OPTVAL : *(OptVal *)varp; + return *(OptVal *)varp; } OptValType type = option_get_type(opt_idx); @@ -3179,11 +3170,11 @@ OptVal optval_from_varp(OptIndex opt_idx, void *varp) case kOptValTypeNil: return NIL_OPTVAL; case kOptValTypeBoolean: - return BOOLEAN_OPTVAL(varp == NULL ? false : TRISTATE_FROM_INT(*(int *)varp)); + return BOOLEAN_OPTVAL(TRISTATE_FROM_INT(*(int *)varp)); case kOptValTypeNumber: - return NUMBER_OPTVAL(varp == NULL ? 0 : *(OptInt *)varp); + return NUMBER_OPTVAL(*(OptInt *)varp); case kOptValTypeString: - return STRING_OPTVAL(varp == NULL ? (String)STRING_INIT : cstr_as_string(*(char **)varp)); + return STRING_OPTVAL(cstr_as_string(*(char **)varp)); } UNREACHABLE; } @@ -3319,7 +3310,10 @@ static char *option_get_valid_types(OptIndex opt_idx) /// @return True if option is hidden, false otherwise. Returns false if option name is invalid. bool is_option_hidden(OptIndex opt_idx) { - return opt_idx == kOptInvalid ? false : get_varp(&options[opt_idx]) == NULL; + // Hidden options are always immutable and point to their default value + return opt_idx == kOptInvalid + ? false + : (options[opt_idx].immutable && options[opt_idx].var == &options[opt_idx].def_val.data); } static inline bool option_is_global_local(OptIndex opt_idx) @@ -3459,8 +3453,8 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value .os_win = curwin }; - if (direct || opt->hidden) { - // Don't do any extra processing if setting directly or if option is hidden. + if (direct) { + // Don't do any extra processing if setting directly. } // Disallow changing immutable options. else if (opt->immutable && !optval_equal(old_value, new_value)) { @@ -3489,7 +3483,7 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value // If option is hidden or if an error is detected, restore the previous value and don't do any // further processing. - if (opt->hidden || errmsg != NULL) { + if (errmsg != NULL) { set_option_varp(opt_idx, varp, old_value, true); // When resetting some values, need to act on it. if (restore_chartab) { @@ -3749,7 +3743,7 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set vimoption_T *opt = get_option(opt_idx); - if (opt->var == NULL) { + if (is_option_hidden(opt_idx)) { return; } @@ -3960,11 +3954,6 @@ int get_option_attrs(OptIndex opt_idx) vimoption_T *opt = get_option(opt_idx); - // Hidden option - if (opt->var == NULL) { - return 0; - } - int attrs = 0; if (opt->indir == PV_NONE || (opt->indir & PV_BOTH)) { @@ -3976,6 +3965,7 @@ int get_option_attrs(OptIndex opt_idx) attrs |= SOPT_BUF; } + assert(attrs != 0); return attrs; } @@ -4143,8 +4133,8 @@ static int optval_default(OptIndex opt_idx, void *varp) { vimoption_T *opt = &options[opt_idx]; - // Hidden or immutable options always use their default value. - if (varp == NULL || opt->hidden || opt->immutable) { + // Hidden options always use their default value. + if (is_option_hidden(opt_idx)) { return true; } @@ -4554,9 +4544,9 @@ void *get_option_varp_scope_from(OptIndex opt_idx, int scope, buf_T *buf, win_T void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) { - // hidden option, always return NULL - if (p->var == NULL) { - return NULL; + // hidden options always use the same var pointer + if (is_option_hidden(get_opt_idx(p))) { + return p->var; } switch ((int)p->indir) { @@ -5456,7 +5446,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) } nextchar = *p; opt_idx = find_option_len(arg, (size_t)(p - arg)); - if (opt_idx == kOptInvalid || options[opt_idx].var == NULL) { + if (opt_idx == kOptInvalid || is_option_hidden(opt_idx)) { xp->xp_context = EXPAND_NOTHING; return; } @@ -5680,7 +5670,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM char *str; for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { str = options[opt_idx].fullname; - if (options[opt_idx].var == NULL) { + if (is_option_hidden(opt_idx)) { continue; } if (xp->xp_context == EXPAND_BOOL_SETTINGS @@ -5928,6 +5918,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c static void option_value2string(vimoption_T *opt, int scope) { void *varp = get_varp_scope(opt, scope); + assert(varp != NULL); if (option_has_type(get_opt_idx(opt), kOptValTypeNumber)) { OptInt wc = 0; @@ -5944,9 +5935,8 @@ static void option_value2string(vimoption_T *opt, int scope) } } else { // string varp = *(char **)(varp); - if (varp == NULL) { // Just in case. - NameBuff[0] = NUL; - } else if (opt->flags & kOptFlagExpand) { + + if (opt->flags & kOptFlagExpand) { home_replace(NULL, varp, NameBuff, MAXPATHL, false); } else { xstrlcpy(NameBuff, varp, MAXPATHL); diff --git a/src/nvim/option.h b/src/nvim/option.h index 9b74429467..138d90da97 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -49,7 +49,6 @@ typedef struct { ///< buffer-local option: global value idopt_T indir; ///< global option: PV_NONE; ///< local option: indirect option index - bool hidden; ///< option is hidden, any attempt to set its value will be ignored. bool immutable; ///< option is immutable, trying to set its value will give an error. /// callback function to invoke after an option is modified to validate and diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index d59a4549d1..435f919ec0 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -530,6 +530,7 @@ EXTERN char *p_mef; ///< 'makeef' EXTERN char *p_mp; ///< 'makeprg' EXTERN char *p_mps; ///< 'matchpairs' EXTERN OptInt p_mat; ///< 'matchtime' +EXTERN OptInt p_mco; ///< 'maxcombine' EXTERN OptInt p_mfd; ///< 'maxfuncdepth' EXTERN OptInt p_mmd; ///< 'maxmapdepth' EXTERN OptInt p_mmp; ///< 'maxmempattern' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 3c21436c3a..71f04a4dde 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -13,7 +13,7 @@ --- @field list? 'comma'|'onecomma'|'commacolon'|'onecommacolon'|'flags'|'flagscomma' --- @field scope vim.option_scope[] --- @field deny_duplicates? boolean ---- @field enable_if? string|false +--- @field enable_if? string --- @field defaults? vim.option_defaults --- @field secure? true --- @field noglob? true @@ -87,11 +87,11 @@ return { { abbreviation = 'al', defaults = { if_true = 224 }, - enable_if = false, full_name = 'aleph', scope = { 'global' }, short_desc = N_('ASCII code of the letter Aleph (Hebrew)'), type = 'number', + immutable = true, }, { abbreviation = 'ari', @@ -789,11 +789,11 @@ return { current Use the current directory. {path} Use the specified directory ]=], - enable_if = false, full_name = 'browsedir', scope = { 'global' }, short_desc = N_('which directory to start browsing in'), type = 'string', + immutable = true, }, { abbreviation = 'bh', @@ -1493,7 +1493,7 @@ return { cb = 'did_set_completeslash', defaults = { if_true = '' }, desc = [=[ - only for MS-Windows + only modifiable in MS-Windows When this option is set it overrules 'shellslash' for completion: - When this option is set to "slash", a forward slash is used for path completion in insert mode. This is useful when editing HTML tag, or @@ -3791,12 +3791,12 @@ return { try to keep 'lines' and 'columns' the same when adding and removing GUI components. ]=], - enable_if = false, full_name = 'guioptions', list = 'flags', scope = { 'global' }, short_desc = N_('GUI: Which components and options are used'), type = 'string', + immutable = true, }, { abbreviation = 'gtl', @@ -3816,13 +3816,13 @@ return { present in 'guioptions'. For the non-GUI tab pages line 'tabline' is used. ]=], - enable_if = false, full_name = 'guitablabel', modelineexpr = true, redraw = { 'current_window' }, scope = { 'global' }, short_desc = N_('GUI: custom label for a tab page'), type = 'string', + immutable = true, }, { abbreviation = 'gtt', @@ -3835,12 +3835,12 @@ return { let &guitabtooltip = "line one\nline two" < ]=], - enable_if = false, full_name = 'guitabtooltip', redraw = { 'current_window' }, scope = { 'global' }, short_desc = N_('GUI: custom tooltip for a tab page'), type = 'string', + immutable = true, }, { abbreviation = 'hf', @@ -4082,11 +4082,11 @@ return { English characters directly, e.g., when it's used to type accented characters with dead keys. ]=], - enable_if = false, full_name = 'imcmdline', scope = { 'global' }, short_desc = N_('use IM when starting to edit a command line'), type = 'boolean', + immutable = true, }, { abbreviation = 'imd', @@ -4100,11 +4100,11 @@ return { Currently this option is on by default for SGI/IRIX machines. This may change in later releases. ]=], - enable_if = false, full_name = 'imdisable', scope = { 'global' }, short_desc = N_('do not use the IM in any mode'), type = 'boolean', + immutable = true, }, { abbreviation = 'imi', @@ -5236,7 +5236,7 @@ return { scope = { 'global' }, short_desc = N_('maximum nr of combining characters displayed'), type = 'number', - hidden = true, + varname = 'p_mco', }, { abbreviation = 'mfd', @@ -5732,13 +5732,13 @@ return { indicate no input when the hit-enter prompt is displayed (since clicking the mouse has no effect in this state.) ]=], - enable_if = false, full_name = 'mouseshape', list = 'onecomma', scope = { 'global' }, short_desc = N_('shape of the mouse pointer in different modes'), tags = { 'E547' }, type = 'string', + immutable = true, }, { abbreviation = 'mouset', @@ -5898,11 +5898,11 @@ return { Note that on Windows editing "aux.h", "lpt1.txt" and the like also result in editing a device. ]=], - enable_if = false, full_name = 'opendevice', scope = { 'global' }, short_desc = N_('allow reading/writing devices on MS-Windows'), type = 'boolean', + immutable = true, }, { abbreviation = 'opfunc', @@ -5975,11 +5975,11 @@ return { { abbreviation = 'pt', defaults = { if_true = '' }, - enable_if = false, full_name = 'pastetoggle', scope = { 'global' }, short_desc = N_('No description'), type = 'string', + immutable = true, }, { abbreviation = 'pex', @@ -7270,9 +7270,14 @@ return { { abbreviation = 'ssl', cb = 'did_set_shellslash', - defaults = { if_true = false }, + defaults = { + condition = 'MSWIN', + if_true = false, + if_false = true, + doc = 'on, Windows: off', + }, desc = [=[ - only for MS-Windows + only modifiable in MS-Windows When set, a forward slash is used when expanding file names. This is useful when a Unix-like shell is used instead of cmd.exe. Backward slashes can still be typed, but they are changed to forward slashes by @@ -8885,11 +8890,11 @@ return { { abbreviation = 'tenc', defaults = { if_true = '' }, - enable_if = false, full_name = 'termencoding', scope = { 'global' }, short_desc = N_('Terminal encoding'), type = 'string', + immutable = true, }, { abbreviation = 'tgc', -- cgit From cbc9a03f58394bbb85bbe70c48856cc1efca4ab7 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Sun, 3 Nov 2024 16:36:26 +0600 Subject: refactor(options): remove fileformat macros --- src/nvim/diff.c | 2 +- src/nvim/option.c | 12 ++++++------ src/nvim/option_vars.h | 15 --------------- src/nvim/options.lua | 8 ++++++-- src/nvim/optionstr.c | 2 +- 5 files changed, 14 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index d22fb65827..a690c70875 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -801,7 +801,7 @@ static int diff_write(buf_T *buf, diffin_T *din) // Always use 'fileformat' set to "unix". char *save_ff = buf->b_p_ff; - buf->b_p_ff = xstrdup(FF_UNIX); + buf->b_p_ff = xstrdup("unix"); const bool save_cmod_flags = cmdmod.cmod_flags; // Writing the buffer is an implementation detail of performing the diff, // so it shouldn't update the '[ and '] marks. diff --git a/src/nvim/option.c b/src/nvim/option.c index 783ec0abf4..14553f9989 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5105,13 +5105,13 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_fenc = xstrdup(p_fenc); switch (*p_ffs) { case 'm': - buf->b_p_ff = xstrdup(FF_MAC); + buf->b_p_ff = xstrdup("mac"); break; case 'd': - buf->b_p_ff = xstrdup(FF_DOS); + buf->b_p_ff = xstrdup("dos"); break; case 'u': - buf->b_p_ff = xstrdup(FF_UNIX); + buf->b_p_ff = xstrdup("unix"); break; default: buf->b_p_ff = xstrdup(p_ff); @@ -6240,13 +6240,13 @@ void set_fileformat(int eol_style, int opt_flags) switch (eol_style) { case EOL_UNIX: - p = FF_UNIX; + p = "unix"; break; case EOL_MAC: - p = FF_MAC; + p = "mac"; break; case EOL_DOS: - p = FF_DOS; + p = "dos"; break; } diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index 435f919ec0..a60bd047c1 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -31,21 +31,6 @@ #define DFLT_GREPFORMAT "%f:%l:%m,%f:%l%m,%f %l%m" -// default values for b_p_ff 'fileformat' and p_ffs 'fileformats' -#define FF_DOS "dos" -#define FF_MAC "mac" -#define FF_UNIX "unix" - -#ifdef USE_CRNL -# define DFLT_FF "dos" -# define DFLT_FFS_VIM "dos,unix" -# define DFLT_FFS_VI "dos,unix" // also autodetect in compatible mode -#else -# define DFLT_FF "unix" -# define DFLT_FFS_VIM "unix,dos" -# define DFLT_FFS_VI "" -#endif - // Possible values for 'encoding' #define ENC_UCSBOM "ucs-bom" // check for BOM at start of file diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 71f04a4dde..e648d4350a 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2684,7 +2684,9 @@ return { abbreviation = 'ff', cb = 'did_set_fileformat', defaults = { - if_true = macros('DFLT_FF', 'string'), + condition = 'USE_CRNL', + if_true = 'dos', + if_false = 'unix', doc = 'Windows: "dos", Unix: "unix"', }, desc = [=[ @@ -2717,7 +2719,9 @@ return { abbreviation = 'ffs', cb = 'did_set_fileformats', defaults = { - if_true = macros('DFLT_FFS_VIM', 'string'), + condition = 'USE_CRNL', + if_true = 'dos,unix', + if_false = 'unix,dos', doc = 'Windows: "dos,unix", Unix: "unix,dos"', }, deny_duplicates = true, diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 48423a1779..af2b09513b 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -84,7 +84,7 @@ static char *(p_dip_values[]) = { "filler", "context:", "iblank", "icase", "indent-heuristic", "linematch:", "algorithm:", NULL }; static char *(p_dip_algorithm_values[]) = { "myers", "minimal", "patience", "histogram", NULL }; static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", "unsigned", "blank", NULL }; -static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL }; +static char *(p_ff_values[]) = { "unix", "dos", "mac", NULL }; static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL }; static char *(p_cmp_values[]) = { "internal", "keepascii", NULL }; // Note: Keep this in sync with fill_culopt_flags() -- cgit From 04274a417358a4eb9b3b3d1f7e1ea4a4b4419c5c Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Wed, 6 Nov 2024 04:07:29 +0600 Subject: refactor(options): remove unnecessary call to `find_option()` (#31088) --- src/nvim/option.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 783ec0abf4..cff8707edb 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -649,10 +649,8 @@ void set_init_3(void) xfree(p); if (buf_is_empty(curbuf)) { - int idx_ffs = find_option("ffs"); - // Apply the first entry of 'fileformats' to the initial buffer. - if (idx_ffs >= 0 && (options[idx_ffs].flags & kOptFlagWasSet)) { + if (options[kOptFileformats].flags & kOptFlagWasSet) { set_fileformat(default_fileformat(), OPT_LOCAL); } } -- cgit From 000129201c54d4ba391f7473d0c183f000246c3e Mon Sep 17 00:00:00 2001 From: errael Date: Thu, 7 Nov 2024 00:21:28 -0800 Subject: perf(mouse): only generate for a new cell positon (#31103) Problem: Can receive dozens of events for same cell position. #30965 Solution: Leverage check_multiclick() to detect if cell position is unchanged. --- src/nvim/os/input.c | 54 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 7c5293a8b8..f77a25768d 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -290,8 +290,9 @@ size_t input_enqueue(String keys) = trans_special(&ptr, (size_t)(end - ptr), (char *)buf, FSK_KEYCODE, true, NULL); if (new_size) { - new_size = handle_mouse_event(&ptr, buf, new_size); - input_enqueue_raw((char *)buf, new_size); + if ((new_size = handle_mouse_event(&ptr, buf, new_size))) { + input_enqueue_raw((char *)buf, new_size); + } continue; } @@ -326,7 +327,7 @@ size_t input_enqueue(String keys) return rv; } -static uint8_t check_multiclick(int code, int grid, int row, int col) +static uint8_t check_multiclick(int code, int grid, int row, int col, bool *skip_event) { static int orig_num_clicks = 0; static int orig_mouse_code = 0; @@ -335,24 +336,29 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) static int orig_mouse_row = 0; static uint64_t orig_mouse_time = 0; // time of previous mouse click - if ((code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) || code == KE_MOUSEMOVE) { + if (code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) { return 0; } - // For click events the number of clicks is updated. - if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE - || code == KE_X1MOUSE || code == KE_X2MOUSE) { + bool no_move = orig_mouse_grid == grid && orig_mouse_col == col && orig_mouse_row == row; + + if (code == KE_MOUSEMOVE) { + if (no_move) { + *skip_event = true; + return 0; + } + } else if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE + || code == KE_X1MOUSE || code == KE_X2MOUSE) { + // For click events the number of clicks is updated. uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) // compute the time elapsed since the previous mouse click and // convert p_mouse from ms to ns uint64_t timediff = mouse_time - orig_mouse_time; uint64_t mouset = (uint64_t)p_mouset * 1000000; if (code == orig_mouse_code + && no_move && timediff < mouset - && orig_num_clicks != 4 - && orig_mouse_grid == grid - && orig_mouse_col == col - && orig_mouse_row == row) { + && orig_num_clicks != 4) { orig_num_clicks++; } else { orig_num_clicks = 1; @@ -367,12 +373,14 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) orig_mouse_row = row; uint8_t modifiers = 0; - if (orig_num_clicks == 2) { - modifiers |= MOD_MASK_2CLICK; - } else if (orig_num_clicks == 3) { - modifiers |= MOD_MASK_3CLICK; - } else if (orig_num_clicks == 4) { - modifiers |= MOD_MASK_4CLICK; + if (code != KE_MOUSEMOVE) { + if (orig_num_clicks == 2) { + modifiers |= MOD_MASK_2CLICK; + } else if (orig_num_clicks == 3) { + modifiers |= MOD_MASK_3CLICK; + } else if (orig_num_clicks == 4) { + modifiers |= MOD_MASK_4CLICK; + } } return modifiers; } @@ -421,8 +429,12 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs *ptr += advance; } + bool skip_event = false; uint8_t modifiers = check_multiclick(mouse_code, mouse_grid, - mouse_row, mouse_col); + mouse_row, mouse_col, &skip_event); + if (skip_event) { + return 0; + } if (modifiers) { if (buf[1] != KS_MODIFIER) { @@ -443,7 +455,11 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) { - modifier |= check_multiclick(code, grid, row, col); + bool skip_event = false; + modifier |= check_multiclick(code, grid, row, col, &skip_event); + if (skip_event) { + return; + } uint8_t buf[7]; uint8_t *p = buf; if (modifier) { -- cgit From 5a86360400691e55fae66d60485b61360a1d3d6c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 7 Nov 2024 17:53:30 +0800 Subject: test: add test for key following ignored mouse move (#31104) --- src/nvim/os/input.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index f77a25768d..2d17581bac 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -289,8 +289,8 @@ size_t input_enqueue(String keys) unsigned new_size = trans_special(&ptr, (size_t)(end - ptr), (char *)buf, FSK_KEYCODE, true, NULL); - if (new_size) { - if ((new_size = handle_mouse_event(&ptr, buf, new_size))) { + if (new_size > 0) { + if ((new_size = handle_mouse_event(&ptr, buf, new_size)) > 0) { input_enqueue_raw((char *)buf, new_size); } continue; @@ -351,9 +351,9 @@ static uint8_t check_multiclick(int code, int grid, int row, int col, bool *skip || code == KE_X1MOUSE || code == KE_X2MOUSE) { // For click events the number of clicks is updated. uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) - // compute the time elapsed since the previous mouse click and - // convert p_mouse from ms to ns + // Compute the time elapsed since the previous mouse click. uint64_t timediff = mouse_time - orig_mouse_time; + // Convert 'mousetime' from ms to ns. uint64_t mouset = (uint64_t)p_mouset * 1000000; if (code == orig_mouse_code && no_move @@ -407,7 +407,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs return bufsize; } - // a <[COL],[ROW]> sequence can follow and will set the mouse_row/mouse_col + // A <[COL],[ROW]> sequence can follow and will set the mouse_row/mouse_col // global variables. This is ugly but its how the rest of the code expects to // find mouse coordinates, and it would be too expensive to refactor this // now. -- cgit From 59e130b6cacd71326ecc99ca180fd574abc8115c Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 2 Nov 2024 06:54:43 +0100 Subject: fix(inccommand): ensure cursor is where it belongs Problem: Inccommand preview callback may flush inaccurate cmdline cursor position. Solution: Ensure cursor is where it belongs when doing command preview. --- src/nvim/ex_getln.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 389e935557..dda1a18fa6 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2550,6 +2550,9 @@ static bool cmdpreview_may_show(CommandLineState *s) goto end; } + // Cursor may be at the end of the message grid rather than at cmdspos. + // Place it there in case preview callback flushes it. #30696 + cursorcmd(); // Flush now: external cmdline may itself wish to update the screen which is // currently disallowed during cmdpreview(no longer needed in case that changes). cmdline_ui_flush(); -- cgit From 8af1702647e865009db66a68aeb821ef185986a9 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Fri, 8 Nov 2024 11:28:18 +0600 Subject: refactor(options): remove `varp` argument for `set_option` (#31111) Problem: The `varp` argument for `set_option` is extraneous as the option's variable pointer can be retrieved using the option's index and flags. Solution: Remove the `varp` argument for `set_option` --- src/nvim/option.c | 196 ++++++++++++++++++++++++------------------------------ 1 file changed, 86 insertions(+), 110 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 635d26f123..7172584e52 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1242,11 +1242,10 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * } uint8_t nextchar = (uint8_t)(*p); // next non-white char after option name - uint32_t flags = 0; // flags for current option - void *varp = NULL; // pointer to variable for current option - - flags = options[opt_idx].flags; - varp = get_varp_scope(&(options[opt_idx]), opt_flags); + // flags for current option + uint32_t flags = options[opt_idx].flags; + // pointer to variable for current option + void *varp = get_varp_scope(&(options[opt_idx]), opt_flags); if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, prefix, errmsg) == FAIL) { return; @@ -1323,8 +1322,7 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * return; } - *errmsg = set_option(opt_idx, varp, newval, opt_flags, 0, false, op == OP_NONE, errbuf, - errbuflen); + *errmsg = set_option(opt_idx, newval, opt_flags, 0, false, op == OP_NONE, errbuf, errbuflen); } /// Parse 'arg' for option settings. @@ -2744,15 +2742,14 @@ static void do_spelllang_source(win_T *win) /// Check the bounds of numeric options. /// /// @param opt_idx Index in options[] table. Must not be kOptInvalid. -/// @param[in] varp Pointer to option variable. /// @param[in,out] newval Pointer to new option value. Will be set to bound checked value. /// @param[out] errbuf Buffer for error message. Cannot be NULL. /// @param errbuflen Length of error buffer. /// /// @return Error message, if any. -static const char *check_num_option_bounds(OptIndex opt_idx, void *varp, OptInt *newval, - char *errbuf, size_t errbuflen) - FUNC_ATTR_NONNULL_ARG(4) +static const char *check_num_option_bounds(OptIndex opt_idx, OptInt *newval, char *errbuf, + size_t errbuflen) + FUNC_ATTR_NONNULL_ARG(3) { const char *errmsg = NULL; @@ -2785,9 +2782,7 @@ static const char *check_num_option_bounds(OptIndex opt_idx, void *varp, OptInt } break; case kOptScroll: - if (varp == &(curwin->w_p_scr) - && (*newval <= 0 - || (*newval > curwin->w_height_inner && curwin->w_height_inner > 0)) + if ((*newval <= 0 || (*newval > curwin->w_height_inner && curwin->w_height_inner > 0)) && full_screen) { if (*newval != 0) { errmsg = e_scroll; @@ -2805,13 +2800,12 @@ static const char *check_num_option_bounds(OptIndex opt_idx, void *varp, OptInt /// Validate and bound check option value. /// /// @param opt_idx Index in options[] table. Must not be kOptInvalid. -/// @param[in] varp Pointer to option variable. /// @param[in,out] newval Pointer to new option value. Will be set to bound checked value. /// @param[out] errbuf Buffer for error message. Cannot be NULL. /// @param errbuflen Length of error buffer. /// /// @return Error message, if any. -static const char *validate_num_option(OptIndex opt_idx, void *varp, OptInt *newval, char *errbuf, +static const char *validate_num_option(OptIndex opt_idx, OptInt *newval, char *errbuf, size_t errbuflen) { OptInt value = *newval; @@ -2821,145 +2815,137 @@ static const char *validate_num_option(OptIndex opt_idx, void *varp, OptInt *new return e_invarg; } - if (varp == &p_wh) { + switch (opt_idx) { + case kOptHelpheight: + case kOptTitlelen: + case kOptUpdatecount: + case kOptReport: + case kOptUpdatetime: + case kOptSidescroll: + case kOptFoldlevel: + case kOptShiftwidth: + case kOptTextwidth: + case kOptWritedelay: + case kOptTimeoutlen: + if (value < 0) { + return e_positive; + } + break; + case kOptWinheight: if (value < 1) { return e_positive; } else if (p_wmh > value) { return e_winheight; } - } else if (varp == &p_hh) { - if (value < 0) { - return e_positive; - } - } else if (varp == &p_wmh) { + break; + case kOptWinminheight: if (value < 0) { return e_positive; } else if (value > p_wh) { return e_winheight; } - } else if (varp == &p_wiw) { + break; + case kOptWinwidth: if (value < 1) { return e_positive; } else if (p_wmw > value) { return e_winwidth; } - } else if (varp == &p_wmw) { + break; + case kOptWinminwidth: if (value < 0) { return e_positive; } else if (value > p_wiw) { return e_winwidth; } - } else if (varp == &p_mco) { + break; + case kOptMaxcombine: *newval = MAX_MCO; - } else if (varp == &p_titlelen) { - if (value < 0) { - return e_positive; - } - } else if (varp == &p_uc) { - if (value < 0) { - return e_positive; - } - } else if (varp == &p_ch) { + break; + case kOptCmdheight: if (value < 0) { return e_positive; } else { p_ch_was_zero = value == 0; } - } else if (varp == &p_tm) { - if (value < 0) { - return e_positive; - } - } else if (varp == &p_hi) { + break; + case kOptHistory: if (value < 0) { return e_positive; } else if (value > 10000) { return e_invarg; } - } else if (varp == &p_pyx) { + break; + case kOptPyxversion: if (value == 0) { *newval = 3; } else if (value != 3) { return e_invarg; } - } else if (varp == &p_re) { + break; + case kOptRegexpengine: if (value < 0 || value > 2) { return e_invarg; } - } else if (varp == &p_report) { - if (value < 0) { - return e_positive; - } - } else if (varp == &p_so) { + break; + case kOptScrolloff: if (value < 0 && full_screen) { return e_positive; } - } else if (varp == &p_siso) { + break; + case kOptSidescrolloff: if (value < 0 && full_screen) { return e_positive; } - } else if (varp == &p_cwh) { + break; + case kOptCmdwinheight: if (value < 1) { return e_positive; } - } else if (varp == &p_ut) { - if (value < 0) { - return e_positive; - } - } else if (varp == &p_ss) { - if (value < 0) { - return e_positive; - } - } else if (varp == &curwin->w_p_fdl || varp == &curwin->w_allbuf_opt.wo_fdl) { - if (value < 0) { - return e_positive; - } - } else if (varp == &curwin->w_p_cole || varp == &curwin->w_allbuf_opt.wo_cole) { + break; + case kOptConceallevel: if (value < 0) { return e_positive; } else if (value > 3) { return e_invarg; } - } else if (varp == &curwin->w_p_nuw || varp == &curwin->w_allbuf_opt.wo_nuw) { + break; + case kOptNumberwidth: if (value < 1) { return e_positive; } else if (value > MAX_NUMBERWIDTH) { return e_invarg; } - } else if (varp == &curbuf->b_p_iminsert || varp == &p_iminsert) { + break; + case kOptIminsert: if (value < 0 || value > B_IMODE_LAST) { return e_invarg; } - } else if (varp == &curbuf->b_p_imsearch || varp == &p_imsearch) { + break; + case kOptImsearch: if (value < -1 || value > B_IMODE_LAST) { return e_invarg; } - } else if (varp == &curbuf->b_p_channel || varp == &p_channel) { + break; + case kOptChannel: return e_invarg; - } else if (varp == &curbuf->b_p_scbk || varp == &p_scbk) { + case kOptScrollback: if (value < -1 || value > SB_MAX) { return e_invarg; } - } else if (varp == &curbuf->b_p_sw || varp == &p_sw) { - if (value < 0) { - return e_positive; - } - } else if (varp == &curbuf->b_p_ts || varp == &p_ts) { + break; + case kOptTabstop: if (value < 1) { return e_positive; } else if (value > TABSTOP_MAX) { return e_invarg; } - } else if (varp == &curbuf->b_p_tw || varp == &p_tw) { - if (value < 0) { - return e_positive; - } - } else if (varp == &p_wd) { - if (value < 0) { - return e_positive; - } + break; + default: + break; } - return check_num_option_bounds(opt_idx, varp, newval, errbuf, errbuflen); + return check_num_option_bounds(opt_idx, newval, errbuf, errbuflen); } /// Called after an option changed: check if something needs to be redrawn. @@ -3124,7 +3110,8 @@ bool optval_equal(OptVal o1, OptVal o2) return o1.data.number == o2.data.number; case kOptValTypeString: return o1.data.string.size == o2.data.string.size - && strnequal(o1.data.string.data, o2.data.string.data, o1.data.string.size); + && (o1.data.string.data == o2.data.string.data + || strnequal(o1.data.string.data, o2.data.string.data, o1.data.string.size)); } UNREACHABLE; } @@ -3586,14 +3573,19 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value /// Validate the new value for an option. /// /// @param opt_idx Index in options[] table. Must not be kOptInvalid. -/// @param varp Pointer to option variable. /// @param newval[in,out] New option value. Might be modified. -static const char *validate_option_value(const OptIndex opt_idx, void *varp, OptVal *newval, - int opt_flags, char *errbuf, size_t errbuflen) +static const char *validate_option_value(const OptIndex opt_idx, OptVal *newval, int opt_flags, + char *errbuf, size_t errbuflen) { const char *errmsg = NULL; vimoption_T *opt = &options[opt_idx]; + // Always allow unsetting local value of global-local option. + if (option_is_global_local(opt_idx) && (opt_flags & OPT_LOCAL) + && optval_equal(*newval, get_option_unset_value(opt_idx))) { + return NULL; + } + if (newval->type == kOptValTypeNil) { // Don't try to unset local value if scope is global. // TODO(famiu): Change this to forbid changing all non-local scopes when the API scope bug is @@ -3613,7 +3605,7 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt errmsg = errbuf; } else if (newval->type == kOptValTypeNumber) { // Validate and bound check num option values. - errmsg = validate_num_option(opt_idx, varp, &newval->data.number, errbuf, errbuflen); + errmsg = validate_num_option(opt_idx, &newval->data.number, errbuf, errbuflen); } return errmsg; @@ -3622,7 +3614,6 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt /// Set the value of an option using an OptVal. /// /// @param opt_idx Index in options[] table. Must not be kOptInvalid. -/// @param[in] varp Option variable pointer, cannot be NULL. /// @param value New option value. Might get freed. /// @param opt_flags Option flags. /// @param set_sid Script ID. Special values: @@ -3634,17 +3625,16 @@ static const char *validate_option_value(const OptIndex opt_idx, void *varp, Opt /// @param errbuflen Length of error buffer. /// /// @return NULL on success, an untranslated error message on error. -static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, int opt_flags, - scid_T set_sid, const bool direct, const bool value_replaced, - char *errbuf, size_t errbuflen) - FUNC_ATTR_NONNULL_ARG(2) +static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid, + const bool direct, const bool value_replaced, char *errbuf, + size_t errbuflen) { assert(opt_idx != kOptInvalid); const char *errmsg = NULL; if (!direct) { - errmsg = validate_option_value(opt_idx, varp, &value, opt_flags, errbuf, errbuflen); + errmsg = validate_option_value(opt_idx, &value, opt_flags, errbuf, errbuflen); if (errmsg != NULL) { optval_free(value); @@ -3661,11 +3651,9 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, const bool is_opt_local_unset = is_option_local_value_unset(opt_idx); // When using ":set opt=val" for a global option with a local value the local value will be reset, - // use the global value here. - if (scope_both && option_is_global_local(opt_idx)) { - varp = opt->var; - } - + // use the global value in that case. + void *varp + = scope_both && option_is_global_local(opt_idx) ? opt->var : get_varp_scope(opt, opt_flags); void *varp_local = get_varp_scope(opt, OPT_LOCAL); void *varp_global = get_varp_scope(opt, OPT_GLOBAL); @@ -3739,16 +3727,11 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set { static char errbuf[IOSIZE]; - vimoption_T *opt = get_option(opt_idx); - if (is_option_hidden(opt_idx)) { return; } - const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; - void *varp = get_varp_scope(opt, scope_both ? OPT_LOCAL : opt_flags); - - const char *errmsg = set_option(opt_idx, varp, optval_copy(value), opt_flags, set_sid, true, true, + const char *errmsg = set_option(opt_idx, optval_copy(value), opt_flags, set_sid, true, true, errbuf, sizeof(errbuf)); assert(errmsg == NULL); (void)errmsg; // ignore unused warning @@ -3810,14 +3793,7 @@ const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt return _(e_sandbox); } - void *varp = get_varp_scope(&(options[opt_idx]), opt_flags); - if (varp == NULL) { - // hidden option is not changed - return NULL; - } - - return set_option(opt_idx, varp, optval_copy(value), opt_flags, 0, false, true, errbuf, - sizeof(errbuf)); + return set_option(opt_idx, optval_copy(value), opt_flags, 0, false, true, errbuf, sizeof(errbuf)); } /// Unset the local value of a global-local option. -- cgit From f83a31b49d5d976cd39f7faa6356565cb0a4a97a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 8 Nov 2024 14:54:28 +0800 Subject: refactor(options): use os_win/os_buf for local options (#31060) Conversely, don't use them for global options. --- src/nvim/option.c | 38 ++++++++++++++++++-------------------- src/nvim/optionstr.c | 5 +++-- 2 files changed, 21 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 7172584e52..0396f7740e 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1886,7 +1886,7 @@ static const char *did_set_arabic(optset_T *args) // set rightleft mode if (!win->w_p_rl) { win->w_p_rl = true; - changed_window_setting(curwin); + changed_window_setting(win); } // Enable Arabic shaping (major part of what Arabic requires) @@ -1917,7 +1917,7 @@ static const char *did_set_arabic(optset_T *args) // reset rightleft mode if (win->w_p_rl) { win->w_p_rl = false; - changed_window_setting(curwin); + changed_window_setting(win); } // 'arabicshape' isn't reset, it is a global option and @@ -1928,8 +1928,8 @@ static const char *did_set_arabic(optset_T *args) // window may still want it "on". // Revert to the default keymap - curbuf->b_p_iminsert = B_IMODE_NONE; - curbuf->b_p_imsearch = B_IMODE_USE_INSERT; + win->w_buffer->b_p_iminsert = B_IMODE_NONE; + win->w_buffer->b_p_imsearch = B_IMODE_USE_INSERT; } return errmsg; @@ -2051,9 +2051,7 @@ static const char *did_set_helpheight(optset_T *args) { // Change window height NOW if (!ONE_WINDOW) { - buf_T *buf = (buf_T *)args->os_buf; - win_T *win = (win_T *)args->os_win; - if (buf->b_help && win->w_height < p_hh) { + if (curbuf->b_help && curwin->w_height < p_hh) { win_setheight((int)p_hh); } } @@ -2382,14 +2380,16 @@ static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'readonly' option value. static const char *did_set_readonly(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + // when 'readonly' is reset globally, also reset readonlymode - if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) { + if (!buf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) { readonlymode = false; } // when 'readonly' is set may give W10 again - if (curbuf->b_p_ro) { - curbuf->b_did_warn = false; + if (buf->b_p_ro) { + buf->b_did_warn = false; } redraw_titles(); @@ -2505,8 +2505,7 @@ static const char *did_set_swapfile(optset_T *args) if (buf->b_p_swf && p_uc) { ml_open_file(buf); // create the swap file } else { - // no need to reset curbuf->b_may_swap, ml_open_file() will check - // buf->b_p_swf + // no need to reset buf->b_may_swap, ml_open_file() will check buf->b_p_swf mf_close_file(buf, true); // remove the swap file } return NULL; @@ -2546,8 +2545,10 @@ static const char *did_set_titlelen(optset_T *args) /// Process the updated 'undofile' option value. static const char *did_set_undofile(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + // Only take action when the option was set. - if (!curbuf->b_p_udf && !p_udf) { + if (!buf->b_p_udf && !p_udf) { return NULL; } @@ -2560,7 +2561,7 @@ static const char *did_set_undofile(optset_T *args) // only for the current buffer: Try to read in the undofile, // if one exists, the buffer wasn't changed and the buffer was // loaded - if ((curbuf == bp + if ((buf == bp || (args->os_flags & OPT_GLOBAL) || args->os_flags == 0) && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) { u_compute_hash(bp, hash); @@ -2600,7 +2601,7 @@ static const char *did_set_undolevels(optset_T *args) if (pp == &p_ul) { // global 'undolevels' did_set_global_undolevels(args->os_newval.number, args->os_oldval.number); - } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels' + } else if (pp == &buf->b_p_ul) { // buffer local 'undolevels' did_set_buflocal_undolevels(buf, args->os_newval.number, args->os_oldval.number); } @@ -2665,8 +2666,7 @@ static const char *did_set_winheight(optset_T *args) { // Change window height NOW if (!ONE_WINDOW) { - win_T *win = (win_T *)args->os_win; - if (win->w_height < p_wh) { + if (curwin->w_height < p_wh) { win_setheight((int)p_wh); } } @@ -2677,9 +2677,7 @@ static const char *did_set_winheight(optset_T *args) /// Process the new 'winwidth' option value. static const char *did_set_winwidth(optset_T *args) { - win_T *win = (win_T *)args->os_win; - - if (!ONE_WINDOW && win->w_width < p_wiw) { + if (!ONE_WINDOW && curwin->w_width < p_wiw) { win_setwidth((int)p_wiw); } return NULL; diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index af2b09513b..bfb26a0be6 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -892,10 +892,11 @@ int expand_set_chars_option(optexpand_T *args, int *numMatches, char ***matches) } /// The 'cinoptions' option is changed. -const char *did_set_cinoptions(optset_T *args FUNC_ATTR_UNUSED) +const char *did_set_cinoptions(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; // TODO(vim): recognize errors - parse_cino(curbuf); + parse_cino(buf); return NULL; } -- cgit From 092042b43d58254807c9e1151d8b6efb4d6410c4 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 4 Nov 2024 14:07:10 +0100 Subject: fix(cmdline): simplify and correct grapheme cluster adjustment --- src/nvim/ex_getln.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index dda1a18fa6..9c606c9606 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3596,38 +3596,14 @@ void put_on_cmdline(const char *str, int len, bool redraw) memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len); ccline.cmdbuff[ccline.cmdlen] = NUL; - { - // When the inserted text starts with a composing character, - // backup to the character before it. There could be two of them. - int i = 0; - int c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); - // TODO(bfredl): this can be corrected/simplified as utf_head_off implements the - // correct grapheme cluster breaks - while (ccline.cmdpos > 0 && utf_iscomposing_legacy(c)) { - i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos - 1) + 1; + // When the inserted text starts with a composing character, + // backup to the character before it. + if (ccline.cmdpos > 0 && (uint8_t)ccline.cmdbuff[ccline.cmdpos] >= 0x80) { + int i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos); + if (i != 0) { ccline.cmdpos -= i; len += i; - c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); - } - if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c)) { - // Check the previous character for Arabic combining pair. - i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos - 1) + 1; - if (arabic_combine(utf_ptr2char(ccline.cmdbuff + ccline.cmdpos - i), c)) { - ccline.cmdpos -= i; - len += i; - } else { - i = 0; - } - } - if (i != 0) { - // Also backup the cursor position. - i = ptr2cells(ccline.cmdbuff + ccline.cmdpos); - ccline.cmdspos -= i; - msg_col -= i; - if (msg_col < 0) { - msg_col += Columns; - msg_row--; - } + ccline.cmdspos = cmd_screencol(ccline.cmdpos); } } -- cgit From 5cfa7a72f8c40cdcc0fa93693689915e913806f1 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Tue, 20 Feb 2024 17:25:57 +0100 Subject: refactor(message): propagate highlight id instead of attrs Problem: Highlight group id is not propagated to the end of the message call stack, where ext_messages are emitted. Solution: Refactor message functions to pass along highlight group id instead of attr id. --- src/nvim/api/private/helpers.c | 7 +- src/nvim/api/vim.c | 2 +- src/nvim/autocmd.c | 16 +-- src/nvim/buffer.c | 2 +- src/nvim/bufwrite.c | 14 +-- src/nvim/change.c | 4 +- src/nvim/cmdexpand.c | 17 ++- src/nvim/cmdhist.c | 2 +- src/nvim/decoration_defs.h | 2 +- src/nvim/digraph.c | 8 +- src/nvim/drawscreen.c | 57 +++++----- src/nvim/eval.c | 16 +-- src/nvim/eval/vars.c | 4 +- src/nvim/ex_cmds.c | 12 +- src/nvim/ex_cmds2.c | 2 +- src/nvim/ex_docmd.c | 6 +- src/nvim/ex_getln.c | 40 +++---- src/nvim/ex_getln_defs.h | 6 +- src/nvim/fileio.c | 28 ++--- src/nvim/globals.h | 2 +- src/nvim/highlight_group.c | 22 ++-- src/nvim/input.c | 2 +- src/nvim/insexpand.c | 10 +- src/nvim/mapping.c | 10 +- src/nvim/mark.c | 13 +-- src/nvim/memline.c | 51 ++++----- src/nvim/menu.c | 4 +- src/nvim/message.c | 246 ++++++++++++++++++++--------------------- src/nvim/message.h | 2 - src/nvim/message_defs.h | 6 +- src/nvim/normal.c | 4 +- src/nvim/ops.c | 14 +-- src/nvim/option.c | 6 +- src/nvim/os/shell.c | 8 +- src/nvim/quickfix.c | 44 ++++---- src/nvim/runtime.c | 2 +- src/nvim/search.c | 14 +-- src/nvim/sign.c | 6 +- src/nvim/syntax.c | 90 +++++++-------- src/nvim/tag.c | 26 ++--- src/nvim/ui.c | 4 +- src/nvim/undo.c | 16 ++- src/nvim/usercmd.c | 9 +- 43 files changed, 412 insertions(+), 444 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index e1fb4ed732..d21caf7ed0 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -824,16 +824,15 @@ HlMessage parse_hl_msg(Array chunks, Error *err) String str = copy_string(chunk.items[0].data.string, NULL); - int attr = 0; + int hl_id = 0; if (chunk.size == 2) { String hl = chunk.items[1].data.string; if (hl.size > 0) { // TODO(bfredl): use object_to_hl_id and allow integer - int hl_id = syn_check_group(hl.data, hl.size); - attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; + hl_id = syn_check_group(hl.data, hl.size); } } - kv_push(hl_msg, ((HlMessageChunk){ .text = str, .attr = attr })); + kv_push(hl_msg, ((HlMessageChunk){ .text = str, .hl_id = hl_id })); } return hl_msg; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 943c67ac8e..aacd7d754c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -796,7 +796,7 @@ void nvim_echo(Array chunks, Boolean history, Dict(echo_opts) *opts, Error *err) verbose_enter(); } - msg_multiattr(hl_msg, history ? "echomsg" : "echo", history); + msg_multihl(hl_msg, history ? "echomsg" : "echo", history); if (opts->verbose) { verbose_leave(); diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 5a4ade913d..a62ff6d8ec 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -220,14 +220,14 @@ static void au_show_for_event(int group, event_T event, const char *pat) // show the group name, if it's not the default group if (ac->pat->group != AUGROUP_DEFAULT) { if (last_group_name == NULL) { - msg_puts_attr(get_deleted_augroup(), HL_ATTR(HLF_E)); + msg_puts_hl(get_deleted_augroup(), HLF_E + 1, false); } else { - msg_puts_attr(last_group_name, HL_ATTR(HLF_T)); + msg_puts_hl(last_group_name, HLF_T + 1, false); } msg_puts(" "); } // show the event name - msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T)); + msg_puts_hl(event_nr2name(event), HLF_T + 1, false); } // Show pattern only if it changed. @@ -240,7 +240,7 @@ static void au_show_for_event(int group, event_T event, const char *pat) } msg_col = 4; - msg_outtrans(ac->pat->pat, 0); + msg_outtrans(ac->pat->pat, 0, false); } if (got_int) { @@ -260,17 +260,17 @@ static void au_show_for_event(int group, event_T event, const char *pat) size_t msglen = 100; char *msg = xmallocz(msglen); if (ac->exec.type == CALLABLE_CB) { - msg_puts_attr(exec_to_string, HL_ATTR(HLF_8)); + msg_puts_hl(exec_to_string, HLF_8 + 1, false); snprintf(msg, msglen, " [%s]", ac->desc); } else { snprintf(msg, msglen, "%s [%s]", exec_to_string, ac->desc); } - msg_outtrans(msg, 0); + msg_outtrans(msg, 0, false); XFREE_CLEAR(msg); } else if (ac->exec.type == CALLABLE_CB) { - msg_puts_attr(exec_to_string, HL_ATTR(HLF_8)); + msg_puts_hl(exec_to_string, HLF_8 + 1, false); } else { - msg_outtrans(exec_to_string, 0); + msg_outtrans(exec_to_string, 0, false); } XFREE_CLEAR(exec_to_string); if (p_verbose > 0) { diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index fe22742a84..abcce0dfe8 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2902,7 +2902,7 @@ void buflist_list(exarg_T *eap) buf == curbuf ? (int64_t)curwin->w_cursor.lnum : (int64_t)buflist_findlnum(buf)); } - msg_outtrans(IObuff, 0); + msg_outtrans(IObuff, 0, false); line_breakcheck(); } diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index fa0a55e7b6..2752ef5c59 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -350,7 +350,7 @@ static int check_mtime(buf_T *buf, FileInfo *file_info) msg_scroll = true; // Don't overwrite messages here. msg_silent = 0; // Must give this prompt. // Don't use emsg() here, don't want to flush the buffers. - msg(_("WARNING: The file has been changed since reading it!!!"), HL_ATTR(HLF_E)); + msg(_("WARNING: The file has been changed since reading it!!!"), HLF_E + 1); if (ask_yesno(_("Do you really want to write to it"), true) == 'n') { return FAIL; } @@ -1150,9 +1150,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if (!filtering) { // show that we are busy #ifndef UNIX - filemess(buf, sfname, "", 0); + filemess(buf, sfname, ""); #else - filemess(buf, fname, "", 0); + filemess(buf, fname, ""); #endif } msg_scroll = false; // always overwrite the file message now @@ -1881,11 +1881,9 @@ nofail: retval = FAIL; if (end == 0) { - const int attr = HL_ATTR(HLF_E); // Set highlight for error messages. - msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"), - attr | MSG_HIST); - msg_puts_attr(_("don't quit the editor until the file is successfully written!"), - attr | MSG_HIST); + const int hl_id = HLF_E + 1; // Set highlight for error messages. + msg_puts_hl(_("\nWARNING: Original file may be lost or damaged\n"), hl_id, true); + msg_puts_hl(_("don't quit the editor until the file is successfully written!"), hl_id, true); // Update the timestamp to avoid an "overwrite changed file" // prompt when writing again. diff --git a/src/nvim/change.c b/src/nvim/change.c index 51a13b80e7..3d78b17f2a 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -89,9 +89,9 @@ void change_warning(buf_T *buf, int col) if (msg_row == Rows - 1) { msg_col = col; } - msg_source(HL_ATTR(HLF_W)); + msg_source(HLF_W + 1); msg_ext_set_kind("wmsg"); - msg_puts_attr(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST); + msg_puts_hl(_(w_readonly), HLF_W + 1, true); set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1); msg_clr_eos(); msg_end(); diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 8d1f87cbcf..b64e4f3ab6 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -979,20 +979,19 @@ void ExpandCleanup(expand_T *xp) /// @param linenr line number of matches to display /// @param maxlen maximum number of characters in each line /// @param showtail display only the tail of the full path of a file name -/// @param dir_attr highlight attribute to use for directory names static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, int lines, int linenr, - int maxlen, bool showtail, int dir_attr) + int maxlen, bool showtail) { char *p; int lastlen = 999; for (int j = linenr; j < numMatches; j += lines) { if (xp->xp_context == EXPAND_TAGS_LISTFILES) { - msg_outtrans(matches[j], HL_ATTR(HLF_D)); + msg_outtrans(matches[j], HLF_D + 1, false); p = matches[j] + strlen(matches[j]) + 1; msg_advance(maxlen + 1); msg_puts(p); msg_advance(maxlen + 3); - msg_outtrans_long(p + 2, HL_ATTR(HLF_D)); + msg_outtrans_long(p + 2, HLF_D + 1); break; } for (int i = maxlen - lastlen; --i >= 0;) { @@ -1029,7 +1028,7 @@ static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, in isdir = false; p = SHOW_MATCH(j); } - lastlen = msg_outtrans(p, isdir ? dir_attr : 0); + lastlen = msg_outtrans(p, isdir ? HLF_D + 1 : 0, false); } if (msg_col > 0) { // when not wrapped around msg_clr_eos(); @@ -1119,18 +1118,16 @@ int showmatches(expand_T *xp, bool wildmenu) lines = (numMatches + columns - 1) / columns; } - int attr = HL_ATTR(HLF_D); // find out highlighting for directories - if (xp->xp_context == EXPAND_TAGS_LISTFILES) { - msg_puts_attr(_("tagname"), HL_ATTR(HLF_T)); + msg_puts_hl(_("tagname"), HLF_T + 1, false); msg_clr_eos(); msg_advance(maxlen - 3); - msg_puts_attr(_(" kind file\n"), HL_ATTR(HLF_T)); + msg_puts_hl(_(" kind file\n"), HLF_T + 1, false); } // list the files line by line for (int i = 0; i < lines; i++) { - showmatches_oneline(xp, matches, numMatches, lines, i, maxlen, showtail, attr); + showmatches_oneline(xp, matches, numMatches, lines, i, maxlen, showtail); if (got_int) { got_int = false; break; diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index fc3382f486..5993eefd67 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -667,7 +667,7 @@ void ex_history(exarg_T *eap) } else { xstrlcpy(IObuff + len, hist[i].hisstr, (size_t)(IOSIZE - len)); } - msg_outtrans(IObuff, 0); + msg_outtrans(IObuff, 0, false); } if (i == idx) { break; diff --git a/src/nvim/decoration_defs.h b/src/nvim/decoration_defs.h index 49dc4f9168..58ba93a7ba 100644 --- a/src/nvim/decoration_defs.h +++ b/src/nvim/decoration_defs.h @@ -55,7 +55,7 @@ typedef struct { schar_T conceal_char; } DecorHighlightInline; -#define DECOR_HIGHLIGHT_INLINE_INIT { 0, DECOR_PRIORITY_BASE, 0, 0 } +#define DECOR_HIGHLIGHT_INLINE_INIT { 0, DECOR_PRIORITY_BASE, 0, 0 } typedef struct { uint16_t flags; diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 7413d33fe4..97b47a5ee7 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1707,7 +1707,7 @@ static void digraph_header(const char *msg) if (msg_col > 0) { msg_putchar('\n'); } - msg_outtrans(msg, HL_ATTR(HLF_CM)); + msg_outtrans(msg, HLF_CM + 1, false); msg_putchar('\n'); } @@ -1861,7 +1861,7 @@ static void printdigraph(const digr_T *dp, result_T *previous) *p++ = (char)dp->char2; *p++ = ' '; *p = NUL; - msg_outtrans(buf, 0); + msg_outtrans(buf, 0, false); p = buf; // add a space to draw a composing char on @@ -1871,14 +1871,14 @@ static void printdigraph(const digr_T *dp, result_T *previous) p += utf_char2bytes(dp->result, p); *p = NUL; - msg_outtrans(buf, HL_ATTR(HLF_8)); + msg_outtrans(buf, HLF_8 + 1, false); p = buf; if (char2cells(dp->result) == 1) { *p++ = ' '; } assert(p >= buf); vim_snprintf(p, sizeof(buf) - (size_t)(p - buf), " %3d", dp->result); - msg_outtrans(buf, 0); + msg_outtrans(buf, 0, false); } /// Get the two digraph characters from a typval. diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index aa5c66465b..b5e2f4461b 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -952,7 +952,7 @@ int showmode(void) // Position on the last line in the window, column 0 msg_pos_mode(); - int attr = HL_ATTR(HLF_CM); // Highlight mode + int hl_id = HLF_CM + 1; // Highlight mode // When the screen is too narrow to show the entire mode message, // avoid scrolling and truncate instead. @@ -961,7 +961,7 @@ int showmode(void) lines_left = 0; if (do_mode) { - msg_puts_attr("--", attr); + msg_puts_hl("--", hl_id, false); // CTRL-X in Insert mode if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU)) { // These messages can get long, avoid a wrap in a narrow window. @@ -981,52 +981,49 @@ int showmode(void) } if (length - vim_strsize(edit_submode) > 0) { if (edit_submode_pre != NULL) { - msg_puts_attr(edit_submode_pre, attr); + msg_puts_hl(edit_submode_pre, hl_id, false); } - msg_puts_attr(edit_submode, attr); + msg_puts_hl(edit_submode, hl_id, false); } if (edit_submode_extra != NULL) { - msg_puts_attr(" ", attr); // Add a space in between. - int sub_attr = edit_submode_highl < HLF_COUNT - ? win_hl_attr(curwin, (int)edit_submode_highl) - : attr; - msg_puts_attr(edit_submode_extra, sub_attr); + msg_puts_hl(" ", hl_id, false); // Add a space in between. + int sub_id = edit_submode_highl < HLF_COUNT ? (int)edit_submode_highl + 1 : hl_id; + msg_puts_hl(edit_submode_extra, sub_id, false); } } } else { if (State & MODE_TERMINAL) { - msg_puts_attr(_(" TERMINAL"), attr); + msg_puts_hl(_(" TERMINAL"), hl_id, false); } else if (State & VREPLACE_FLAG) { - msg_puts_attr(_(" VREPLACE"), attr); + msg_puts_hl(_(" VREPLACE"), hl_id, false); } else if (State & REPLACE_FLAG) { - msg_puts_attr(_(" REPLACE"), attr); + msg_puts_hl(_(" REPLACE"), hl_id, false); } else if (State & MODE_INSERT) { if (p_ri) { - msg_puts_attr(_(" REVERSE"), attr); + msg_puts_hl(_(" REVERSE"), hl_id, false); } - msg_puts_attr(_(" INSERT"), attr); + msg_puts_hl(_(" INSERT"), hl_id, false); } else if (restart_edit == 'I' || restart_edit == 'i' || restart_edit == 'a' || restart_edit == 'A') { if (curbuf->terminal) { - msg_puts_attr(_(" (terminal)"), attr); + msg_puts_hl(_(" (terminal)"), hl_id, false); } else { - msg_puts_attr(_(" (insert)"), attr); + msg_puts_hl(_(" (insert)"), hl_id, false); } } else if (restart_edit == 'R') { - msg_puts_attr(_(" (replace)"), attr); + msg_puts_hl(_(" (replace)"), hl_id, false); } else if (restart_edit == 'V') { - msg_puts_attr(_(" (vreplace)"), attr); + msg_puts_hl(_(" (vreplace)"), hl_id, false); } if (State & MODE_LANGMAP) { if (curwin->w_p_arab) { - msg_puts_attr(_(" Arabic"), attr); - } else if (get_keymap_str(curwin, " (%s)", - NameBuff, MAXPATHL)) { - msg_puts_attr(NameBuff, attr); + msg_puts_hl(_(" Arabic"), hl_id, false); + } else if (get_keymap_str(curwin, " (%s)", NameBuff, MAXPATHL)) { + msg_puts_hl(NameBuff, hl_id, false); } } if ((State & MODE_INSERT) && p_paste) { - msg_puts_attr(_(" (paste)"), attr); + msg_puts_hl(_(" (paste)"), hl_id, false); } if (VIsual_active) { @@ -1050,9 +1047,9 @@ int showmode(void) default: p = N_(" SELECT BLOCK"); break; } - msg_puts_attr(_(p), attr); + msg_puts_hl(_(p), hl_id, false); } - msg_puts_attr(" --", attr); + msg_puts_hl(" --", hl_id, false); } need_clear = true; @@ -1060,7 +1057,7 @@ int showmode(void) if (reg_recording != 0 && edit_submode == NULL // otherwise it gets too long ) { - recording_mode(attr); + recording_mode(hl_id); need_clear = true; } @@ -1136,7 +1133,7 @@ void clearmode(void) msg_ext_ui_flush(); msg_pos_mode(); if (reg_recording != 0) { - recording_mode(HL_ATTR(HLF_CM)); + recording_mode(HLF_CM + 1); } msg_clr_eos(); msg_ext_flush_showmode(); @@ -1145,16 +1142,16 @@ void clearmode(void) msg_row = save_msg_row; } -static void recording_mode(int attr) +static void recording_mode(int hl_id) { if (shortmess(SHM_RECORDING)) { return; } - msg_puts_attr(_("recording"), attr); + msg_puts_hl(_("recording"), hl_id, false); char s[4]; snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording); - msg_puts_attr(s, attr); + msg_puts_hl(s, hl_id, false); } #define COL_RULER 17 // columns needed by standard ruler diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 58c98c42ff..1fb7666167 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -126,7 +126,7 @@ bool *eval_lavars_used = NULL; #define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars) #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) -static int echo_attr = 0; // attributes used for ":echo" +static int echo_hl_id = 0; // highlight id used for ":echo" /// Info used by a ":for" loop. typedef struct { @@ -7876,12 +7876,12 @@ void ex_echo(exarg_T *eap) msg_start(); } } else if (eap->cmdidx == CMD_echo) { - msg_puts_attr(" ", echo_attr); + msg_puts_hl(" ", echo_hl_id, false); } char *tofree = encode_tv2echo(&rettv, NULL); if (*tofree != NUL) { msg_ext_set_kind("echo"); - msg_multiline(tofree, echo_attr, true, &need_clear); + msg_multiline(tofree, echo_hl_id, true, false, &need_clear); } xfree(tofree); } @@ -7907,13 +7907,13 @@ void ex_echo(exarg_T *eap) /// ":echohl {name}". void ex_echohl(exarg_T *eap) { - echo_attr = syn_name2attr(eap->arg); + echo_hl_id = syn_name2id(eap->arg); } -/// Returns the :echo attribute -int get_echo_attr(void) +/// Returns the :echo highlight id +int get_echo_hl_id(void) { - return echo_attr; + return echo_hl_id; } /// ":execute expr1 ..." execute the result of an expression. @@ -7964,7 +7964,7 @@ void ex_execute(exarg_T *eap) if (ret != FAIL && ga.ga_data != NULL) { if (eap->cmdidx == CMD_echomsg) { msg_ext_set_kind("echomsg"); - msg(ga.ga_data, echo_attr); + msg(ga.ga_data, echo_hl_id); } else if (eap->cmdidx == CMD_echoerr) { // We don't want to abort following commands, restore did_emsg. int save_did_emsg = did_emsg; diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index d3f836f7f4..35ad00f373 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -1407,7 +1407,7 @@ static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t msg_start(); msg_puts(prefix); if (name != NULL) { // "a:" vars don't have a name stored - msg_puts_len(name, name_len, 0); + msg_puts_len(name, name_len, 0, false); } msg_putchar(' '); msg_advance(22); @@ -1429,7 +1429,7 @@ static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t msg_putchar(' '); } - msg_outtrans(string, 0); + msg_outtrans(string, 0, false); if (type == VAR_FUNC || type == VAR_PARTIAL) { msg_puts("()"); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 702dbeac27..bf43ce0a84 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -189,7 +189,7 @@ void do_ascii(exarg_T *eap) transchar(c), buf1, buf2, cval, cval, cval); } - msg_multiline(IObuff, 0, true, &need_clear); + msg_multiline(IObuff, 0, true, false, &need_clear); off += (size_t)utf_ptr2len(data); // needed for overlong ascii? } @@ -224,7 +224,7 @@ void do_ascii(exarg_T *eap) c, c, c); } - msg_multiline(IObuff, 0, true, &need_clear); + msg_multiline(IObuff, 0, true, false, &need_clear); off += (size_t)utf_ptr2len(data + off); // needed for overlong ascii? } @@ -1028,7 +1028,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out msg_start(); msg_putchar(':'); msg_putchar('!'); - msg_outtrans(newcmd, 0); + msg_outtrans(newcmd, 0, false); msg_clr_eos(); ui_cursor_goto(msg_row, msg_col); @@ -1469,7 +1469,7 @@ void print_line_no_prefix(linenr_T lnum, int use_number, bool list) if (curwin->w_p_nu || use_number) { vim_snprintf(numbuf, sizeof(numbuf), "%*" PRIdLINENR " ", number_width(curwin), lnum); - msg_puts_attr(numbuf, HL_ATTR(HLF_N)); // Highlight line nrs. + msg_puts_hl(numbuf, HLF_N + 1, false); // Highlight line nrs. } msg_prt_line(ml_get(lnum), list); } @@ -3805,7 +3805,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n msg_no_more = true; msg_ext_set_kind("confirm_sub"); // Same highlight as wait_return(). - smsg(HL_ATTR(HLF_R), _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); + smsg(HLF_R + 1, _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); msg_no_more = false; msg_scroll = i; if (!ui_has(kUIMessages)) { @@ -4796,7 +4796,7 @@ void ex_oldfiles(exarg_T *eap) if (!message_filtered(fname)) { msg_outnum(nr); msg_puts(": "); - msg_outtrans(tv_get_string(TV_LIST_ITEM_TV(li)), 0); + msg_outtrans(tv_get_string(TV_LIST_ITEM_TV(li)), 0, false); msg_clr_eos(); msg_putchar('\n'); os_breakcheck(); diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index aff9dce7c1..0ff4282884 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -450,7 +450,7 @@ int buf_write_all(buf_T *buf, bool forceit) 1, buf->b_ml.ml_line_count, NULL, false, forceit, true, false)); if (curbuf != old_curbuf) { - msg_source(HL_ATTR(HLF_W)); + msg_source(HLF_W + 1); msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"), 0); } return retval; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 92695aa4de..cdf977fce2 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5501,7 +5501,7 @@ static void ex_tabs(exarg_T *eap) msg_putchar('\n'); vim_snprintf(IObuff, IOSIZE, _("Tab page %d"), tabcount++); - msg_outtrans(IObuff, HL_ATTR(HLF_T)); + msg_outtrans(IObuff, HLF_T + 1, false); os_breakcheck(); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -5519,7 +5519,7 @@ static void ex_tabs(exarg_T *eap) } else { home_replace(wp->w_buffer, wp->w_buffer->b_fname, IObuff, IOSIZE, true); } - msg_outtrans(IObuff, 0); + msg_outtrans(IObuff, 0, false); os_breakcheck(); } } @@ -7776,7 +7776,7 @@ void verify_command(char *cmd) if (strcmp("smile", cmd) != 0) { return; // acceptable non-existing command } - int a = HL_ATTR(HLF_E); + int a = HLF_E + 1; msg(" #xxn` #xnxx` ,+x@##@Mz;` .xxx" "xxxxxxnz+, znnnnnnnnnnnnnnnn.", a); msg(" n###z x####` :x##########W+` ,###" diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 389e935557..17474f2642 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -811,7 +811,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); msg_scroll = true; - msg_puts_attr(err.msg, HL_ATTR(HLF_E)|MSG_HIST); + msg_puts_hl(err.msg, HLF_E + 1, true); api_clear_error(&err); redrawcmd(); } @@ -2657,7 +2657,7 @@ static void do_autocmd_cmdlinechanged(int firstc) if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); msg_scroll = true; - msg_puts_attr(err.msg, HL_ATTR(HLF_E)|MSG_HIST); + msg_puts_hl(err.msg, HLF_E + 1, true); api_clear_error(&err); redrawcmd(); } @@ -2755,13 +2755,13 @@ char *getcmdline(int firstc, int count, int indent, bool do_concat FUNC_ATTR_UNU /// /// @param[in] firstc Prompt type: e.g. '@' for input(), '>' for debug. /// @param[in] prompt Prompt string: what is displayed before the user text. -/// @param[in] attr Prompt highlighting. +/// @param[in] hl_id Prompt highlight id. /// @param[in] xp_context Type of expansion. /// @param[in] xp_arg User-defined expansion argument. /// @param[in] highlight_callback Callback used for highlighting user input. /// /// @return [allocated] Command line or NULL. -char *getcmdline_prompt(const int firstc, const char *const prompt, const int attr, +char *getcmdline_prompt(const int firstc, const char *const prompt, const int hl_id, const int xp_context, const char *const xp_arg, const Callback highlight_callback) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC @@ -2779,7 +2779,7 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at } ccline.prompt_id = last_prompt_id++; ccline.cmdprompt = (char *)prompt; - ccline.cmdattr = attr; + ccline.hl_id = hl_id; ccline.xp_context = xp_context; ccline.xp_arg = (char *)xp_arg; ccline.input_fn = (firstc == '@'); @@ -3095,15 +3095,13 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline, kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { .start = (int)prev_end, .end = (int)chunk.start.col, - .attr = 0, + .hl_id = 0, })); } - const int id = syn_name2id(chunk.group); - const int attr = (id == 0 ? 0 : syn_id2attr(id)); kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { .start = (int)chunk.start.col, .end = (int)chunk.end_col, - .attr = attr, + .hl_id = syn_name2id(chunk.group), })); prev_end = chunk.end_col; } @@ -3111,7 +3109,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline, kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { .start = (int)prev_end, .end = colored_ccline->cmdlen, - .attr = 0, + .hl_id = 0, })); } kvi_destroy(colors); @@ -3140,7 +3138,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) #define PRINT_ERRMSG(...) \ do { \ msg_putchar('\n'); \ - msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, __VA_ARGS__); \ + msg_printf_hl(HLF_E + 1, __VA_ARGS__); \ printed_errmsg = true; \ } while (0) bool ret = true; @@ -3275,7 +3273,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = (int)prev_end, .end = (int)start, - .attr = 0, + .hl_id = 0, })); } const varnumber_T end = @@ -3299,12 +3297,10 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) if (group == NULL) { goto color_cmdline_error; } - const int id = syn_name2id(group); - const int attr = (id == 0 ? 0 : syn_id2attr(id)); kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = (int)start, .end = (int)end, - .attr = attr, + .hl_id = syn_name2id(group), })); i++; }); @@ -3312,7 +3308,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = (int)prev_end, .end = colored_ccline->cmdlen, - .attr = 0, + .hl_id = 0, })); } prev_prompt_errors = 0; @@ -3374,10 +3370,10 @@ static void draw_cmdline(int start, int len) continue; } const int chunk_start = MAX(chunk.start, start); - msg_outtrans_len(ccline.cmdbuff + chunk_start, chunk.end - chunk_start, chunk.attr); + msg_outtrans_len(ccline.cmdbuff + chunk_start, chunk.end - chunk_start, chunk.hl_id, false); } } else { - msg_outtrans_len(ccline.cmdbuff + start, len, 0); + msg_outtrans_len(ccline.cmdbuff + start, len, 0, false); } } } @@ -3403,7 +3399,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) { CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i); Array item = arena_array(&arena, 2); - ADD_C(item, INTEGER_OBJ(chunk.attr)); + ADD_C(item, INTEGER_OBJ(chunk.hl_id == 0 ? 0 : syn_id2attr(chunk.hl_id))); assert(chunk.end >= chunk.start); ADD_C(item, STRING_OBJ(cbuf_as_string(line->cmdbuff + chunk.start, @@ -3813,7 +3809,7 @@ static void redrawcmdprompt(void) msg_putchar(ccline.cmdfirstc); } if (ccline.cmdprompt != NULL) { - msg_puts_attr(ccline.cmdprompt, ccline.cmdattr); + msg_puts_hl(ccline.cmdprompt, ccline.hl_id, false); ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; // do the reverse of cmd_startcol() if (ccline.cmdfirstc != NUL) { @@ -4801,7 +4797,7 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const p = lastnl + 1; msg_start(); msg_clr_eos(); - msg_puts_len(prompt, p - prompt, get_echo_attr()); + msg_puts_len(prompt, p - prompt, get_echo_hl_id(), false); msg_didout = false; msg_starthere(); } @@ -4812,7 +4808,7 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const const int save_ex_normal_busy = ex_normal_busy; ex_normal_busy = 0; - rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(), + rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_hl_id(), xp_type, xp_arg, input_callback); ex_normal_busy = save_ex_normal_busy; callback_free(&input_callback); diff --git a/src/nvim/ex_getln_defs.h b/src/nvim/ex_getln_defs.h index daba6cabb8..584c360450 100644 --- a/src/nvim/ex_getln_defs.h +++ b/src/nvim/ex_getln_defs.h @@ -10,8 +10,8 @@ /// Defines a region which has the same highlighting. typedef struct { int start; ///< Colored chunk start. - int end; ///< Colored chunk end (exclusive, > start). - int attr; ///< Highlight attr. + int end; ///< Colored chunk end (exclusive, > start). + int hl_id; ///< Highlight id. } CmdlineColorChunk; /// Command-line colors @@ -49,7 +49,7 @@ struct cmdline_info { int cmdfirstc; ///< ':', '/', '?', '=', '>' or NUL int cmdindent; ///< number of spaces before cmdline char *cmdprompt; ///< message in front of cmdline - int cmdattr; ///< attributes for prompt + int hl_id; ///< highlight id for prompt int overstrike; ///< Typing mode on the command line. Shared by ///< getcmdline() and put_on_cmdline(). expand_T *xpc; ///< struct being used for expansion, xp_pattern diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 724d754ca7..7c53150c11 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -99,7 +99,7 @@ static const char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); -void filemess(buf_T *buf, char *name, char *s, int attr) +void filemess(buf_T *buf, char *name, char *s) { int prev_msg_col = msg_col; @@ -129,7 +129,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) msg_scroll = msg_scroll_save; msg_scrolled_ign = true; // may truncate the message to avoid a hit-return prompt - msg_outtrans(msg_may_trunc(false, IObuff), attr); + msg_outtrans(msg_may_trunc(false, IObuff), 0, false); msg_clr_eos(); ui_flush(); msg_scrolled_ign = false; @@ -335,7 +335,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // If the name is too long we might crash further on, quit here. if (namelen >= MAXPATHL) { - filemess(curbuf, fname, _("Illegal file name"), 0); + filemess(curbuf, fname, _("Illegal file name")); msg_end(); msg_scroll = msg_save; goto theend; @@ -346,7 +346,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // swap file may destroy it! Reported on MS-DOS and Win 95. if (after_pathsep(fname, fname + namelen)) { if (!silent) { - filemess(curbuf, fname, _(msg_is_a_directory), 0); + filemess(curbuf, fname, _(msg_is_a_directory)); } msg_end(); msg_scroll = msg_save; @@ -374,11 +374,11 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, ) { if (S_ISDIR(perm)) { if (!silent) { - filemess(curbuf, fname, _(msg_is_a_directory), 0); + filemess(curbuf, fname, _(msg_is_a_directory)); } retval = NOTDONE; } else { - filemess(curbuf, fname, _("is not a file"), 0); + filemess(curbuf, fname, _("is not a file")); } msg_end(); msg_scroll = msg_save; @@ -467,9 +467,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } if (!silent) { if (dir_of_file_exists(fname)) { - filemess(curbuf, sfname, _("[New]"), 0); + filemess(curbuf, sfname, _("[New]")); } else { - filemess(curbuf, sfname, _("[New DIRECTORY]"), 0); + filemess(curbuf, sfname, _("[New DIRECTORY]")); } } // Even though this is a new file, it might have been @@ -497,10 +497,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // open() does not set // EOVERFLOW (fd == -EOVERFLOW) ? _("[File too big]") - : _("[Permission Denied]")), 0); + : _("[Permission Denied]"))); #else filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") - : _("[Permission Denied]")), 0); + : _("[Permission Denied]"))); #endif curbuf->b_p_ro = true; // must use "w!" now @@ -658,7 +658,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!recoverymode && !filtering && !(flags & READ_DUMMY) && !silent) { if (!read_stdin && !read_buffer) { - filemess(curbuf, sfname, "", 0); + filemess(curbuf, sfname, ""); } } @@ -1685,7 +1685,7 @@ failed: if (got_int) { if (!(flags & READ_DUMMY)) { - filemess(curbuf, sfname, _(e_interr), 0); + filemess(curbuf, sfname, _(e_interr)); if (newfile) { curbuf->b_p_ro = true; // must use "w!" now } @@ -3035,9 +3035,9 @@ int buf_check_timestamp(buf_T *buf) } else { if (!autocmd_busy) { msg_start(); - msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST); + msg_puts_hl(tbuf, HLF_E + 1, true); if (*mesg2 != NUL) { - msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST); + msg_puts_hl(mesg2, HLF_W + 1, true); } msg_clr_eos(); msg_end(); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 1cdb38f5f8..472b77ccbe 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -156,7 +156,7 @@ EXTERN bool msg_scrolled_ign INIT( = false); EXTERN bool msg_did_scroll INIT( = false); EXTERN char *keep_msg INIT( = NULL); // msg to be shown after redraw -EXTERN int keep_msg_attr INIT( = 0); // highlight attr for keep_msg +EXTERN int keep_msg_hl_id INIT( = 0); // highlight id for keep_msg EXTERN bool need_fileinfo INIT( = false); // do fileinfo() after redraw EXTERN int msg_scroll INIT( = false); // msg_start() will scroll EXTERN bool msg_didout INIT( = false); // msg_outstr() was used in line diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 4243c7573e..33d0c81e15 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1621,9 +1621,9 @@ static void highlight_list_one(const int id) if (sgp->sg_link && !got_int) { syn_list_header(didh, 0, id, true); didh = true; - msg_puts_attr("links to", HL_ATTR(HLF_D)); + msg_puts_hl("links to", HLF_D + 1, false); msg_putchar(' '); - msg_outtrans(hl_table[hl_table[id - 1].sg_link - 1].sg_name, 0); + msg_outtrans(hl_table[hl_table[id - 1].sg_link - 1].sg_name, 0, false); } if (!didh) { @@ -1751,10 +1751,10 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg didh = true; if (!got_int) { if (*name != NUL) { - msg_puts_attr(name, HL_ATTR(HLF_D)); - msg_puts_attr("=", HL_ATTR(HLF_D)); + msg_puts_hl(name, HLF_D + 1, false); + msg_puts_hl("=", HLF_D + 1, false); } - msg_outtrans(ts, 0); + msg_outtrans(ts, 0, false); } return didh; } @@ -1884,7 +1884,7 @@ bool syn_list_header(const bool did_header, const int outlen, const int id, bool if (got_int) { return true; } - msg_outtrans(hl_table[id - 1].sg_name, 0); + msg_outtrans(hl_table[id - 1].sg_name, 0, false); name_col = msg_col; endcol = 15; } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) { @@ -1915,7 +1915,7 @@ bool syn_list_header(const bool did_header, const int outlen, const int id, bool if (endcol == Columns - 1 && endcol <= name_col) { msg_putchar(' '); } - msg_puts_attr("xxx", syn_id2attr(id)); + msg_puts_hl("xxx", id, false); msg_putchar(' '); } @@ -2047,7 +2047,7 @@ static int syn_add_group(const char *name, size_t len) return 0; } else if (!ASCII_ISALNUM(c) && c != '_' && c != '.' && c != '@' && c != '-') { // '.' and '@' are allowed characters for use with treesitter capture names. - msg_source(HL_ATTR(HLF_W)); + msg_source(HLF_W + 1); emsg(_(e_highlight_group_name_invalid_char)); return 0; } @@ -2361,16 +2361,16 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg) static void highlight_list(void) { for (int i = 10; --i >= 0;) { - highlight_list_two(i, HL_ATTR(HLF_D)); + highlight_list_two(i, HLF_D + 1); } for (int i = 40; --i >= 0;) { highlight_list_two(99, 0); } } -static void highlight_list_two(int cnt, int attr) +static void highlight_list_two(int cnt, int id) { - msg_puts_attr(&("N \bI \b! \b"[cnt / 11]), attr); + msg_puts_hl(&("N \bI \b! \b"[cnt / 11]), id, false); msg_clr_eos(); ui_flush(); os_delay(cnt == 99 ? 40 : (uint64_t)cnt * 50, false); diff --git a/src/nvim/input.c b/src/nvim/input.c index ef400710fe..3f531e2b73 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -55,7 +55,7 @@ int ask_yesno(const char *const str, const bool direct) int r = ' '; while (r != 'y' && r != 'n') { // same highlighting as for wait_return() - smsg(HL_ATTR(HLF_R), "%s (y/n)?", str); + smsg(HLF_R + 1, "%s (y/n)?", str); if (direct) { r = get_keystroke(NULL); } else { diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index c8314d1bb2..9efcc2263a 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -473,7 +473,7 @@ bool check_compl_option(bool dict_opt) ctrl_x_mode = CTRL_X_NORMAL; edit_submode = NULL; msg((dict_opt ? _("'dictionary' option is empty") : _("'thesaurus' option is empty")), - HL_ATTR(HLF_E)); + HLF_E + 1); if (emsg_silent == 0 && !in_assert_fails) { vim_beep(BO_COMPL); setcursor(); @@ -1564,7 +1564,7 @@ static void ins_compl_files(int count, char **files, bool thesaurus, int flags, msg_hist_off = true; // reset in msg_trunc() vim_snprintf(IObuff, IOSIZE, _("Scanning dictionary: %s"), files[i]); - msg_trunc(IObuff, true, HL_ATTR(HLF_R)); + msg_trunc(IObuff, true, HLF_R + 1); } if (fp == NULL) { @@ -3046,7 +3046,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar : st->ins_buf->b_sfname == NULL ? st->ins_buf->b_fname : st->ins_buf->b_sfname); - msg_trunc(IObuff, true, HL_ATTR(HLF_R)); + msg_trunc(IObuff, true, HLF_R + 1); } } else if (*st->e_cpt == NUL) { status = INS_COMPL_CPT_END; @@ -3074,7 +3074,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar if (!shortmess(SHM_COMPLETIONSCAN)) { msg_hist_off = true; // reset in msg_trunc() vim_snprintf(IObuff, IOSIZE, "%s", _("Scanning tags.")); - msg_trunc(IObuff, true, HL_ATTR(HLF_R)); + msg_trunc(IObuff, true, HLF_R + 1); } } @@ -4568,7 +4568,7 @@ static void ins_compl_show_statusmsg(void) if (!p_smd) { msg_hist_off = true; msg(edit_submode_extra, (edit_submode_highl < HLF_COUNT - ? HL_ATTR(edit_submode_highl) : 0)); + ? (int)edit_submode_highl + 1 : 0)); msg_hist_off = false; } } else { diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 23efd2a841..0e83ae6fab 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -239,9 +239,9 @@ static void showmap(mapblock_T *mp, bool local) } while (len < 12); if (mp->m_noremap == REMAP_NONE) { - msg_puts_attr("*", HL_ATTR(HLF_8)); + msg_puts_hl("*", HLF_8 + 1, false); } else if (mp->m_noremap == REMAP_SCRIPT) { - msg_puts_attr("&", HL_ATTR(HLF_8)); + msg_puts_hl("&", HLF_8 + 1, false); } else { msg_putchar(' '); } @@ -256,10 +256,10 @@ static void showmap(mapblock_T *mp, bool local) // the rhs, and not M-x etc, true gets both -- webb if (mp->m_luaref != LUA_NOREF) { char *str = nlua_funcref_str(mp->m_luaref, NULL); - msg_puts_attr(str, HL_ATTR(HLF_8)); + msg_puts_hl(str, HLF_8 + 1, false); xfree(str); } else if (mp->m_str[0] == NUL) { - msg_puts_attr("", HL_ATTR(HLF_8)); + msg_puts_hl("", HLF_8 + 1, false); } else { msg_outtrans_special(mp->m_str, false, 0); } @@ -2657,7 +2657,7 @@ void ex_map(exarg_T *eap) // If we are in a secure mode we print the mappings for security reasons. if (secure) { secure = 2; - msg_outtrans(eap->cmd, 0); + msg_outtrans(eap->cmd, 0, false); msg_putchar('\n'); } do_exmap(eap, false); diff --git a/src/nvim/mark.c b/src/nvim/mark.c index a09ade2b03..b118e614f3 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -957,9 +957,9 @@ static void show_one_mark(int c, char *arg, pos_T *p, char *name_arg, int curren msg_putchar('\n'); if (!got_int) { snprintf(IObuff, IOSIZE, " %c %6" PRIdLINENR " %4d ", c, p->lnum, p->col); - msg_outtrans(IObuff, 0); + msg_outtrans(IObuff, 0, false); if (name != NULL) { - msg_outtrans(name, current ? HL_ATTR(HLF_D) : 0); + msg_outtrans(name, current ? HLF_D + 1 : 0, false); } } } @@ -1082,9 +1082,8 @@ void ex_jumps(exarg_T *eap) i == curwin->w_jumplistidx ? '>' : ' ', i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx : curwin->w_jumplistidx - i, curwin->w_jumplist[i].fmark.mark.lnum, curwin->w_jumplist[i].fmark.mark.col); - msg_outtrans(IObuff, 0); - msg_outtrans(name, - curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum ? HL_ATTR(HLF_D) : 0); + msg_outtrans(IObuff, 0, false); + msg_outtrans(name, curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum ? HLF_D + 1 : 0, false); xfree(name); os_breakcheck(); } @@ -1119,9 +1118,9 @@ void ex_changes(exarg_T *eap) curwin->w_changelistidx ? i - curwin->w_changelistidx : curwin->w_changelistidx - i, curbuf->b_changelist[i].mark.lnum, curbuf->b_changelist[i].mark.col); - msg_outtrans(IObuff, 0); + msg_outtrans(IObuff, 0, false); char *name = mark_line(&curbuf->b_changelist[i].mark, 17); - msg_outtrans(name, HL_ATTR(HLF_D)); + msg_outtrans(name, HLF_D + 1, false); xfree(name); os_breakcheck(); } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 92e2ef2b55..560d3cb167 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -775,7 +775,6 @@ void ml_recover(bool checkext) recoverymode = true; int called_from_main = (curbuf->b_ml.ml_mfp == NULL); - int attr = HL_ATTR(HLF_E); // If the file name ends in ".s[a-w][a-z]" we assume this is the swapfile. // Otherwise a search is done to find the swapfile(s). @@ -853,40 +852,39 @@ void ml_recover(bool checkext) // be set to the real value below. mfp->mf_page_size = MIN_SWAP_PAGE_SIZE; + int hl_id = HLF_E + 1; // try to read block 0 if ((hp = mf_get(mfp, 0, 1)) == NULL) { msg_start(); - msg_puts_attr(_("Unable to read block 0 from "), attr | MSG_HIST); - msg_outtrans(mfp->mf_fname, attr | MSG_HIST); - msg_puts_attr(_("\nMaybe no changes were made or Vim did not update the swap file."), - attr | MSG_HIST); + msg_puts_hl(_("Unable to read block 0 from "), hl_id, true); + msg_outtrans(mfp->mf_fname, hl_id, true); + msg_puts_hl(_("\nMaybe no changes were made or Nvim did not update the swap file."), hl_id, + true); msg_end(); goto theend; } ZeroBlock *b0p = hp->bh_data; if (strncmp(b0p->b0_version, "VIM 3.0", 7) == 0) { msg_start(); - msg_outtrans(mfp->mf_fname, MSG_HIST); - msg_puts_attr(_(" cannot be used with this version of Vim.\n"), - MSG_HIST); - msg_puts_attr(_("Use Vim version 3.0.\n"), MSG_HIST); + msg_outtrans(mfp->mf_fname, 0, true); + msg_puts_hl(_(" cannot be used with this version of Nvim.\n"), 0, true); + msg_puts_hl(_("Use Vim version 3.0.\n"), 0, true); msg_end(); goto theend; } if (ml_check_b0_id(b0p) == FAIL) { - semsg(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname); + semsg(_("E307: %s does not look like a Nvim swap file"), mfp->mf_fname); goto theend; } if (b0_magic_wrong(b0p)) { msg_start(); - msg_outtrans(mfp->mf_fname, attr | MSG_HIST); - msg_puts_attr(_(" cannot be used on this computer.\n"), - attr | MSG_HIST); - msg_puts_attr(_("The file was created on "), attr | MSG_HIST); + msg_outtrans(mfp->mf_fname, hl_id, true); + msg_puts_hl(_(" cannot be used on this computer.\n"), hl_id, true); + msg_puts_hl(_("The file was created on "), hl_id, true); // avoid going past the end of a corrupted hostname b0p->b0_fname[0] = NUL; - msg_puts_attr(b0p->b0_hname, attr | MSG_HIST); - msg_puts_attr(_(",\nor the file has been damaged."), attr | MSG_HIST); + msg_puts_hl(b0p->b0_hname, hl_id, true); + msg_puts_hl(_(",\nor the file has been damaged."), hl_id, true); msg_end(); goto theend; } @@ -899,9 +897,8 @@ void ml_recover(bool checkext) mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size)); if (mfp->mf_page_size < previous_page_size) { msg_start(); - msg_outtrans(mfp->mf_fname, attr | MSG_HIST); - msg_puts_attr(_(" has been damaged (page size is smaller than minimum value).\n"), - attr | MSG_HIST); + msg_outtrans(mfp->mf_fname, hl_id, true); + msg_puts_hl(_(" has been damaged (page size is smaller than minimum value).\n"), hl_id, true); msg_end(); goto theend; } @@ -1521,7 +1518,7 @@ static time_t swapfile_info(char *fname) // print name of owner of the file if (os_get_uname((uv_uid_t)file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) { msg_puts(_(" owned by: ")); - msg_outtrans(uname, 0); + msg_outtrans(uname, 0, false); msg_puts(_(" dated: ")); } else { msg_puts(_(" dated: ")); @@ -1541,7 +1538,7 @@ static time_t swapfile_info(char *fname) if (strncmp(b0.b0_version, "VIM 3.0", 7) == 0) { msg_puts(_(" [from Vim version 3.0]")); } else if (ml_check_b0_id(&b0) == FAIL) { - msg_puts(_(" [does not look like a Vim swap file]")); + msg_puts(_(" [does not look like a Nvim swap file]")); } else if (!ml_check_b0_strings(&b0)) { msg_puts(_(" [garbled strings (not nul terminated)]")); } else { @@ -1549,7 +1546,7 @@ static time_t swapfile_info(char *fname) if (b0.b0_fname[0] == NUL) { msg_puts(_("[No Name]")); } else { - msg_outtrans(b0.b0_fname, 0); + msg_outtrans(b0.b0_fname, 0, false); } msg_puts(_("\n modified: ")); @@ -1557,7 +1554,7 @@ static time_t swapfile_info(char *fname) if (*(b0.b0_uname) != NUL) { msg_puts(_("\n user name: ")); - msg_outtrans(b0.b0_uname, 0); + msg_outtrans(b0.b0_uname, 0, false); } if (*(b0.b0_hname) != NUL) { @@ -1566,7 +1563,7 @@ static time_t swapfile_info(char *fname) } else { msg_puts(_("\n host name: ")); } - msg_outtrans(b0.b0_hname, 0); + msg_outtrans(b0.b0_hname, 0, false); } if (char_to_long(b0.b0_pid) != 0) { @@ -3259,7 +3256,7 @@ static void attention_message(buf_T *buf, char *fname) msg_puts("\"\n"); const time_t swap_mtime = swapfile_info(fname); msg_puts(_("While opening file \"")); - msg_outtrans(buf->b_fname, 0); + msg_outtrans(buf->b_fname, 0, false); msg_puts("\"\n"); FileInfo file_info; if (!os_fileinfo(buf->b_fname, &file_info)) { @@ -3281,10 +3278,10 @@ static void attention_message(buf_T *buf, char *fname) " Quit, or continue with caution.\n")); msg_puts(_("(2) An edit session for this file crashed.\n")); msg_puts(_(" If this is the case, use \":recover\" or \"nvim -r ")); - msg_outtrans(buf->b_fname, 0); + msg_outtrans(buf->b_fname, 0, false); msg_puts(_("\"\n to recover the changes (see \":help recovery\").\n")); msg_puts(_(" If you did this already, delete the swap file \"")); - msg_outtrans(fname, 0); + msg_outtrans(fname, 0, false); msg_puts(_("\"\n to avoid this message.\n")); cmdline_row = msg_row; no_wait_return--; diff --git a/src/nvim/menu.c b/src/nvim/menu.c index c33d3cc712..77166e0733 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -808,7 +808,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) msg_puts(" "); } // Same highlighting as for directories!? - msg_outtrans(menu->name, HL_ATTR(HLF_D)); + msg_outtrans(menu->name, HLF_D + 1, false); } if (menu != NULL && menu->children == NULL) { @@ -841,7 +841,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) } msg_puts(" "); if (*menu->strings[bit] == NUL) { - msg_puts_attr("", HL_ATTR(HLF_8)); + msg_puts_hl("", HLF_8 + 1, false); } else { msg_outtrans_special(menu->strings[bit], false, 0); } diff --git a/src/nvim/message.c b/src/nvim/message.c index 151fb3d903..dc9c7d0c37 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -36,6 +36,7 @@ #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/highlight_defs.h" +#include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/input.h" #include "nvim/keycodes.h" @@ -73,7 +74,7 @@ struct msgchunk_S { msgchunk_T *sb_prev; char sb_eol; // true when line ends after this text int sb_msg_col; // column in which text starts - int sb_attr; // text attributes + int sb_hl_id; // text highlight id char sb_text[]; // text to be displayed }; @@ -118,7 +119,7 @@ bool keep_msg_more = false; // keep_msg was set by msgmore() // msg_scrolled How many lines the screen has been scrolled (because of // messages). Used in update_screen() to scroll the screen // back. Incremented each time the screen scrolls a line. -// msg_scrolled_ign true when msg_scrolled is non-zero and msg_puts_attr() +// msg_scrolled_ign true when msg_scrolled is non-zero and msg_puts_hl_id() // writes something without scrolling should not make // need_wait_return to be set. This is a hack to make ":ts" // work without an extra prompt. @@ -231,7 +232,7 @@ void msg_grid_validate(void) int verb_msg(const char *s) { verbose_enter(); - int n = msg_attr_keep(s, 0, false, false); + int n = msg_hl_keep(s, 0, false, false); verbose_leave(); return n; @@ -241,14 +242,14 @@ int verb_msg(const char *s) /// When terminal not initialized (yet) printf("%s", ..) is used. /// /// @return true if wait_return() not called -bool msg(const char *s, const int attr) +bool msg(const char *s, const int hl_id) FUNC_ATTR_NONNULL_ARG(1) { - return msg_attr_keep(s, attr, false, false); + return msg_hl_keep(s, hl_id, false, false); } /// Similar to msg_outtrans, but support newlines and tabs. -void msg_multiline(const char *s, int attr, bool check_int, bool *need_clear) +void msg_multiline(const char *s, int hl_id, bool check_int, bool hist, bool *need_clear) FUNC_ATTR_NONNULL_ALL { const char *next_spec = s; @@ -261,13 +262,13 @@ void msg_multiline(const char *s, int attr, bool check_int, bool *need_clear) if (next_spec != NULL) { // Printing all char that are before the char found by strpbrk - msg_outtrans_len(s, (int)(next_spec - s), attr); + msg_outtrans_len(s, (int)(next_spec - s), hl_id, hist); if (*next_spec != TAB && *need_clear) { msg_clr_eos(); *need_clear = false; } - msg_putchar_attr((uint8_t)(*next_spec), attr); + msg_putchar_hl((uint8_t)(*next_spec), hl_id); s = next_spec + 1; } } @@ -275,11 +276,11 @@ void msg_multiline(const char *s, int attr, bool check_int, bool *need_clear) // Print the rest of the message. We know there is no special // character because strpbrk returned NULL if (*s != NUL) { - msg_outtrans(s, attr); + msg_outtrans(s, hl_id, hist); } } -void msg_multiattr(HlMessage hl_msg, const char *kind, bool history) +void msg_multihl(HlMessage hl_msg, const char *kind, bool history) { no_wait_return++; msg_start(); @@ -288,17 +289,17 @@ void msg_multiattr(HlMessage hl_msg, const char *kind, bool history) msg_ext_set_kind(kind); for (uint32_t i = 0; i < kv_size(hl_msg); i++) { HlMessageChunk chunk = kv_A(hl_msg, i); - msg_multiline(chunk.text.data, chunk.attr, true, &need_clear); + msg_multiline(chunk.text.data, chunk.hl_id, true, false, &need_clear); } if (history && kv_size(hl_msg)) { - add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg); + add_msg_hist_multihl(NULL, 0, 0, true, hl_msg); } no_wait_return--; msg_end(); } /// @param keep set keep_msg if it doesn't scroll -bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) +bool msg_hl_keep(const char *s, int hl_id, bool keep, bool multiline) FUNC_ATTR_NONNULL_ALL { static int entered = 0; @@ -316,7 +317,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) return true; } - if (attr == 0) { + if (hl_id == 0) { set_vim_var_string(VV_STATUSMSG, s, -1); } @@ -335,7 +336,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) && last_msg_hist != NULL && last_msg_hist->msg != NULL && strcmp(s, last_msg_hist->msg) != 0)) { - add_msg_hist(s, -1, attr, multiline); + add_msg_hist(s, -1, hl_id, multiline); } // Truncate the message if needed. @@ -347,9 +348,9 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) bool need_clear = true; if (multiline) { - msg_multiline(s, attr, false, &need_clear); + msg_multiline(s, hl_id, false, false, &need_clear); } else { - msg_outtrans(s, attr); + msg_outtrans(s, hl_id, false); } if (need_clear) { msg_clr_eos(); @@ -484,7 +485,7 @@ void trunc_string(const char *s, char *buf, int room_in, int buflen) } } -/// Shows a printf-style message with attributes. +/// Shows a printf-style message with highlight id. /// /// Note: Caller must check the resulting string is shorter than IOSIZE!!! /// @@ -492,7 +493,7 @@ void trunc_string(const char *s, char *buf, int room_in, int buflen) /// @see swmsg /// /// @param s printf-style format message -int smsg(int attr, const char *s, ...) +int smsg(int hl_id, const char *s, ...) FUNC_ATTR_PRINTF(2, 3) { va_list arglist; @@ -500,10 +501,10 @@ int smsg(int attr, const char *s, ...) va_start(arglist, s); vim_vsnprintf(IObuff, IOSIZE, s, arglist); va_end(arglist); - return msg(IObuff, attr); + return msg(IObuff, hl_id); } -int smsg_attr_keep(int attr, const char *s, ...) +int smsg_hl_keep(int hl_id, const char *s, ...) FUNC_ATTR_PRINTF(2, 3) { va_list arglist; @@ -511,7 +512,7 @@ int smsg_attr_keep(int attr, const char *s, ...) va_start(arglist, s); vim_vsnprintf(IObuff, IOSIZE, s, arglist); va_end(arglist); - return msg_attr_keep(IObuff, attr, true, false); + return msg_hl_keep(IObuff, hl_id, true, false); } // Remember the last sourcing name/lnum used in an error message, so that it @@ -588,7 +589,7 @@ static char *get_emsg_lnum(void) /// Display name and line number for the source of an error. /// Remember the file name and line number, so that for the next error the info /// is only displayed if it changed. -void msg_source(int attr) +void msg_source(int hl_id) { static bool recursive = false; @@ -602,12 +603,12 @@ void msg_source(int attr) char *p = get_emsg_source(); if (p != NULL) { msg_scroll = true; // this will take more than one line - msg(p, attr); + msg(p, hl_id); xfree(p); } p = get_emsg_lnum(); if (p != NULL) { - msg(p, HL_ATTR(HLF_N)); + msg(p, HLF_N + 1); xfree(p); last_sourcing_lnum = SOURCING_LNUM; // only once for each line } @@ -736,7 +737,7 @@ bool emsg_multiline(const char *s, bool multiline) } emsg_on_display = true; // remember there is an error message - int attr = HL_ATTR(HLF_E); // set highlight mode for error messages + int hl_id = HLF_E + 1; // set highlight mode for error messages if (msg_scrolled != 0) { need_wait_return = true; // needed in case emsg() is called after } // wait_return() has reset need_wait_return @@ -748,11 +749,11 @@ bool emsg_multiline(const char *s, bool multiline) // Display name and line number for the source of the error. msg_scroll = true; - msg_source(attr); + msg_source(hl_id); // Display the error message itself. msg_nowait = false; // Wait for this msg. - return msg_attr_keep(s, attr, false, multiline); + return msg_hl_keep(s, hl_id, false, multiline); } /// emsg() - display an error message @@ -907,15 +908,15 @@ void msg_schedule_semsg_multiline(const char *const fmt, ...) /// Careful: The string may be changed by msg_may_trunc()! /// /// @return a pointer to the printed message, if wait_return() not called. -char *msg_trunc(char *s, bool force, int attr) +char *msg_trunc(char *s, bool force, int hl_id) { // Add message to history before truncating. - add_msg_hist(s, -1, attr, false); + add_msg_hist(s, -1, hl_id, false); char *ts = msg_may_trunc(force, s); msg_hist_off = true; - bool n = msg(ts, attr); + bool n = msg(ts, hl_id); msg_hist_off = false; if (n) { @@ -965,16 +966,16 @@ void hl_msg_free(HlMessage hl_msg) } /// @param[in] len Length of s or -1. -static void add_msg_hist(const char *s, int len, int attr, bool multiline) +static void add_msg_hist(const char *s, int len, int hl_id, bool multiline) { - add_msg_hist_multiattr(s, len, attr, multiline, (HlMessage)KV_INITIAL_VALUE); + add_msg_hist_multihl(s, len, hl_id, multiline, (HlMessage)KV_INITIAL_VALUE); } -static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multiline, - HlMessage multiattr) +static void add_msg_hist_multihl(const char *s, int len, int hl_id, bool multiline, + HlMessage multihl) { if (msg_hist_off || msg_silent != 0) { - hl_msg_free(multiattr); + hl_msg_free(multihl); return; } @@ -1002,9 +1003,9 @@ static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multil p->msg = NULL; } p->next = NULL; - p->attr = attr; + p->hl_id = hl_id; p->multiline = multiline; - p->multiattr = multiattr; + p->multihl = multihl; p->kind = msg_ext_kind; if (last_msg_hist != NULL) { last_msg_hist->next = p; @@ -1031,7 +1032,7 @@ int delete_first_msg(void) last_msg_hist = NULL; } xfree(p->msg); - hl_msg_free(p->multiattr); + hl_msg_free(p->multihl); xfree(p); msg_hist_len--; return OK; @@ -1077,21 +1078,21 @@ void ex_messages(exarg_T *eap) } Array entries = ARRAY_DICT_INIT; for (; p != NULL; p = p->next) { - if (kv_size(p->multiattr) || (p->msg && p->msg[0])) { + if (kv_size(p->multihl) || (p->msg && p->msg[0])) { Array entry = ARRAY_DICT_INIT; ADD(entry, CSTR_TO_OBJ(p->kind)); Array content = ARRAY_DICT_INIT; - if (kv_size(p->multiattr)) { - for (uint32_t i = 0; i < kv_size(p->multiattr); i++) { - HlMessageChunk chunk = kv_A(p->multiattr, i); + if (kv_size(p->multihl)) { + for (uint32_t i = 0; i < kv_size(p->multihl); i++) { + HlMessageChunk chunk = kv_A(p->multihl, i); Array content_entry = ARRAY_DICT_INIT; - ADD(content_entry, INTEGER_OBJ(chunk.attr)); + ADD(content_entry, INTEGER_OBJ(chunk.hl_id ? syn_id2attr(chunk.hl_id) : 0)); ADD(content_entry, STRING_OBJ(copy_string(chunk.text, NULL))); ADD(content, ARRAY_OBJ(content_entry)); } } else if (p->msg && p->msg[0]) { Array content_entry = ARRAY_DICT_INIT; - ADD(content_entry, INTEGER_OBJ(p->attr)); + ADD(content_entry, INTEGER_OBJ(p->hl_id ? syn_id2attr(p->hl_id) : 0)); ADD(content_entry, CSTR_TO_OBJ(p->msg)); ADD(content, ARRAY_OBJ(content_entry)); } @@ -1106,10 +1107,10 @@ void ex_messages(exarg_T *eap) } else { msg_hist_off = true; for (; p != NULL && !got_int; p = p->next) { - if (kv_size(p->multiattr)) { - msg_multiattr(p->multiattr, p->kind, false); + if (kv_size(p->multihl)) { + msg_multihl(p->multihl, p->kind, false); } else if (p->msg != NULL) { - msg_attr_keep(p->msg, p->attr, false, p->multiline); + msg_hl_keep(p->msg, p->hl_id, false, p->multiline); } } msg_hist_off = false; @@ -1338,7 +1339,7 @@ static void hit_return_msg(bool newline_sb) msg_puts(_("Interrupt: ")); } - msg_puts_attr(_("Press ENTER or type command to continue"), HL_ATTR(HLF_R)); + msg_puts_hl(_("Press ENTER or type command to continue"), HLF_R + 1, false); if (!msg_use_printf()) { msg_clr_eos(); } @@ -1346,7 +1347,7 @@ static void hit_return_msg(bool newline_sb) } /// Set "keep_msg" to "s". Free the old value and check for NULL pointer. -void set_keep_msg(const char *s, int attr) +void set_keep_msg(const char *s, int hl_id) { xfree(keep_msg); if (s != NULL && msg_silent == 0) { @@ -1355,7 +1356,7 @@ void set_keep_msg(const char *s, int attr) keep_msg = NULL; } keep_msg_more = false; - keep_msg_attr = attr; + keep_msg_hl_id = hl_id; } /// Return true if printing messages should currently be done. @@ -1480,10 +1481,10 @@ void msg_starthere(void) void msg_putchar(int c) { - msg_putchar_attr(c, 0); + msg_putchar_hl(c, 0); } -void msg_putchar_attr(int c, int attr) +void msg_putchar_hl(int c, int hl_id) { char buf[MB_MAXCHAR + 1]; @@ -1495,7 +1496,7 @@ void msg_putchar_attr(int c, int attr) } else { buf[utf_char2bytes(c, buf)] = NUL; } - msg_puts_attr(buf, attr); + msg_puts_hl(buf, hl_id, false); } void msg_outnum(int n) @@ -1508,48 +1509,42 @@ void msg_outnum(int n) void msg_home_replace(const char *fname) { - msg_home_replace_attr(fname, 0); + msg_home_replace_hl(fname, 0); } -void msg_home_replace_hl(const char *fname) -{ - msg_home_replace_attr(fname, HL_ATTR(HLF_D)); -} - -static void msg_home_replace_attr(const char *fname, int attr) +static void msg_home_replace_hl(const char *fname, int hl_id) { char *name = home_replace_save(NULL, fname); - msg_outtrans(name, attr); + msg_outtrans(name, hl_id, false); xfree(name); } -/// Output 'len' characters in 'str' (including NULs) with translation -/// if 'len' is -1, output up to a NUL character. -/// Use attributes 'attr'. +/// Output "len" characters in "str" (including NULs) with translation +/// if "len" is -1, output up to a NUL character. Use highlight "hl_id". /// /// @return the number of characters it takes on the screen. -int msg_outtrans(const char *str, int attr) +int msg_outtrans(const char *str, int hl_id, bool hist) { - return msg_outtrans_len(str, (int)strlen(str), attr); + return msg_outtrans_len(str, (int)strlen(str), hl_id, hist); } /// Output one character at "p". /// Handles multi-byte characters. /// /// @return pointer to the next character. -const char *msg_outtrans_one(const char *p, int attr) +const char *msg_outtrans_one(const char *p, int hl_id, bool hist) { int l; if ((l = utfc_ptr2len(p)) > 1) { - msg_outtrans_len(p, l, attr); + msg_outtrans_len(p, l, hl_id, hist); return p + l; } - msg_puts_attr(transchar_byte_buf(NULL, (uint8_t)(*p)), attr); + msg_puts_hl(transchar_byte_buf(NULL, (uint8_t)(*p)), hl_id, hist); return p + 1; } -int msg_outtrans_len(const char *msgstr, int len, int attr) +int msg_outtrans_len(const char *msgstr, int len, int hl_id, bool hist) { int retval = 0; const char *str = msgstr; @@ -1561,10 +1556,8 @@ int msg_outtrans_len(const char *msgstr, int len, int attr) // Only quit when got_int was set in here. got_int = false; - // if MSG_HIST flag set, add message to history - if (attr & MSG_HIST) { - add_msg_hist(str, len, attr, false); - attr &= ~MSG_HIST; + if (hist) { + add_msg_hist(str, len, hl_id, false); } // When drawing over the command line no need to clear it later or remove @@ -1588,10 +1581,10 @@ int msg_outtrans_len(const char *msgstr, int len, int attr) // Unprintable multi-byte char: print the printable chars so // far and the translation of the unprintable char. if (str > plain_start) { - msg_puts_len(plain_start, str - plain_start, attr); + msg_puts_len(plain_start, str - plain_start, hl_id, hist); } plain_start = str + mb_l; - msg_puts_attr(transchar_buf(NULL, c), attr == 0 ? HL_ATTR(HLF_8) : attr); + msg_puts_hl(transchar_buf(NULL, c), hl_id == 0 ? HLF_8 + 1 : hl_id, false); retval += char2cells(c); } len -= mb_l - 1; @@ -1602,10 +1595,10 @@ int msg_outtrans_len(const char *msgstr, int len, int attr) // Unprintable char: print the printable chars so far and the // translation of the unprintable char. if (str > plain_start) { - msg_puts_len(plain_start, str - plain_start, attr); + msg_puts_len(plain_start, str - plain_start, hl_id, hist); } plain_start = str + 1; - msg_puts_attr(s, attr == 0 ? HL_ATTR(HLF_8) : attr); + msg_puts_hl(s, hl_id == 0 ? HLF_8 + 1 : hl_id, false); retval += (int)strlen(s); } else { retval++; @@ -1616,7 +1609,7 @@ int msg_outtrans_len(const char *msgstr, int len, int attr) if (str > plain_start && !got_int) { // Print the printable chars at the end. - msg_puts_len(plain_start, str - plain_start, attr); + msg_puts_len(plain_start, str - plain_start, hl_id, hist); } got_int |= save_got_int; @@ -1666,7 +1659,7 @@ int msg_outtrans_special(const char *strstart, bool from, int maxlen) } const char *str = strstart; int retval = 0; - int attr = HL_ATTR(HLF_8); + int hl_id = HLF_8 + 1; while (*str != NUL) { const char *text; @@ -1686,9 +1679,7 @@ int msg_outtrans_special(const char *strstart, bool from, int maxlen) break; } // Highlight special keys - msg_puts_attr(text, (len > 1 - && utfc_ptr2len(text) <= 1 - ? attr : 0)); + msg_puts_hl(text, (len > 1 && utfc_ptr2len(text) <= 1 ? hl_id : 0), false); retval += len; } return retval; @@ -1856,7 +1847,7 @@ void msg_prt_line(const char *s, bool list) schar_T sc_final = 0; const char *p_extra = NULL; // init to make SASC shut up. ASCII only! int n; - int attr = 0; + int hl_id = 0; const char *lead = NULL; bool in_multispace = false; int multispace_pos = 0; @@ -1920,7 +1911,7 @@ void msg_prt_line(const char *s, bool list) s += l; continue; } else { - attr = 0; + hl_id = 0; int c = (uint8_t)(*s++); sc_extra = NUL; sc_final = NUL; @@ -1944,13 +1935,13 @@ void msg_prt_line(const char *s, bool list) : curwin->w_p_lcs_chars.tab1; sc_extra = curwin->w_p_lcs_chars.tab2; sc_final = curwin->w_p_lcs_chars.tab3; - attr = HL_ATTR(HLF_0); + hl_id = HLF_0 + 1; } } else if (c == NUL && list && curwin->w_p_lcs_chars.eol != NUL) { p_extra = ""; n_extra = 1; sc = curwin->w_p_lcs_chars.eol; - attr = HL_ATTR(HLF_AT); + hl_id = HLF_AT + 1; s--; } else if (c != NUL && (n = byte2cells(c)) > 1) { n_extra = n - 1; @@ -1958,7 +1949,7 @@ void msg_prt_line(const char *s, bool list) sc = schar_from_ascii(*p_extra++); // Use special coloring to be able to distinguish from // the same in plain text. - attr = HL_ATTR(HLF_0); + hl_id = HLF_0 + 1; } else if (c == ' ') { if (lead != NULL && s <= lead && in_multispace && curwin->w_p_lcs_chars.leadmultispace != NULL) { @@ -1966,23 +1957,23 @@ void msg_prt_line(const char *s, bool list) if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) { multispace_pos = 0; } - attr = HL_ATTR(HLF_0); + hl_id = HLF_0 + 1; } else if (lead != NULL && s <= lead && curwin->w_p_lcs_chars.lead != NUL) { sc = curwin->w_p_lcs_chars.lead; - attr = HL_ATTR(HLF_0); + hl_id = HLF_0 + 1; } else if (trail != NULL && s > trail) { sc = curwin->w_p_lcs_chars.trail; - attr = HL_ATTR(HLF_0); + hl_id = HLF_0 + 1; } else if (in_multispace && curwin->w_p_lcs_chars.multispace != NULL) { sc = curwin->w_p_lcs_chars.multispace[multispace_pos++]; if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) { multispace_pos = 0; } - attr = HL_ATTR(HLF_0); + hl_id = HLF_0 + 1; } else if (list && curwin->w_p_lcs_chars.space != NUL) { sc = curwin->w_p_lcs_chars.space; - attr = HL_ATTR(HLF_0); + hl_id = HLF_0 + 1; } else { sc = schar_from_ascii(' '); // SPACE! } @@ -1998,7 +1989,7 @@ void msg_prt_line(const char *s, bool list) // TODO(bfredl): this is such baloney. need msg_put_schar char buf[MAX_SCHAR_SIZE]; schar_get(buf, sc); - msg_puts_attr(buf, attr); + msg_puts_hl(buf, hl_id, false); col++; } msg_clr_eos(); @@ -2008,42 +1999,42 @@ void msg_prt_line(const char *s, bool list) /// Update msg_row and msg_col for the next message. void msg_puts(const char *s) { - msg_puts_attr(s, 0); + msg_puts_hl(s, 0, false); } void msg_puts_title(const char *s) { - msg_puts_attr(s, HL_ATTR(HLF_T)); + msg_puts_hl(s, HLF_T + 1, false); } /// Show a message in such a way that it always fits in the line. Cut out a /// part in the middle and replace it with "..." when necessary. /// Does not handle multi-byte characters! -void msg_outtrans_long(const char *longstr, int attr) +void msg_outtrans_long(const char *longstr, int hl_id) { int len = (int)strlen(longstr); int slen = len; int room = Columns - msg_col; if (len > room && room >= 20) { slen = (room - 3) / 2; - msg_outtrans_len(longstr, slen, attr); - msg_puts_attr("...", HL_ATTR(HLF_8)); + msg_outtrans_len(longstr, slen, hl_id, false); + msg_puts_hl("...", HLF_8 + 1, false); } - msg_outtrans_len(longstr + len - slen, slen, attr); + msg_outtrans_len(longstr + len - slen, slen, hl_id, len); } -/// Basic function for writing a message with highlight attributes. -void msg_puts_attr(const char *const s, const int attr) +/// Basic function for writing a message with highlight id. +void msg_puts_hl(const char *const s, const int hl_id, const bool hist) { - msg_puts_len(s, -1, attr); + msg_puts_len(s, -1, hl_id, hist); } -/// Write a message with highlight attributes +/// Write a message with highlight id. /// /// @param[in] str NUL-terminated message string. /// @param[in] len Length of the string or -1. -/// @param[in] attr Highlight attribute. -void msg_puts_len(const char *const str, const ptrdiff_t len, int attr) +/// @param[in] hl_id Highlight id. +void msg_puts_len(const char *const str, const ptrdiff_t len, int hl_id, bool hist) FUNC_ATTR_NONNULL_ALL { assert(len < 0 || memchr(str, 0, (size_t)len) == NULL); @@ -2055,10 +2046,8 @@ void msg_puts_len(const char *const str, const ptrdiff_t len, int attr) return; } - // if MSG_HIST flag set, add message to history - if (attr & MSG_HIST) { - add_msg_hist(str, (int)len, attr, false); - attr &= ~MSG_HIST; + if (hist) { + add_msg_hist(str, (int)len, hl_id, false); } // When writing something to the screen after it has scrolled, requires a @@ -2095,7 +2084,7 @@ void msg_puts_len(const char *const str, const ptrdiff_t len, int attr) } } if (!msg_use_printf() || (headless_mode && default_grid.chars)) { - msg_puts_display(str, (int)len, attr, false); + msg_puts_display(str, (int)len, hl_id, false); } need_fileinfo = false; @@ -2104,11 +2093,11 @@ void msg_puts_len(const char *const str, const ptrdiff_t len, int attr) /// Print a formatted message /// /// Message printed is limited by #IOSIZE. Must not be used from inside -/// msg_puts_attr(). +/// msg_puts_hl_id(). /// -/// @param[in] attr Highlight attributes. +/// @param[in] hl_id Highlight id. /// @param[in] fmt Format string. -void msg_printf_attr(const int attr, const char *const fmt, ...) +void msg_printf_hl(const int hl_id, const char *const fmt, ...) FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PRINTF(2, 3) { static char msgbuf[IOSIZE]; @@ -2119,7 +2108,7 @@ void msg_printf_attr(const int attr, const char *const fmt, ...) va_end(ap); msg_scroll = true; - msg_puts_len(msgbuf, (ptrdiff_t)len, attr); + msg_puts_len(msgbuf, (ptrdiff_t)len, hl_id, true); } static void msg_ext_emit_chunk(void) @@ -2141,11 +2130,12 @@ static void msg_ext_emit_chunk(void) /// The display part of msg_puts_len(). /// May be called recursively to display scroll-back text. -static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) +static void msg_puts_display(const char *str, int maxlen, int hl_id, int recurse) { const char *s = str; const char *sb_str = str; int sb_col = msg_col; + int attr = hl_id ? syn_id2attr(hl_id) : 0; did_wait_return = false; @@ -2172,7 +2162,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) if (msg_col >= Columns) { if (p_more && !recurse) { // Store text for scrolling back. - store_sb_text(&sb_str, s, attr, &sb_col, true); + store_sb_text(&sb_str, s, hl_id, &sb_col, true); } if (msg_no_more && lines_left == 0) { break; @@ -2262,7 +2252,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) msg_row++; if (p_more && !recurse) { // Store text for scrolling back. - store_sb_text(&sb_str, s, attr, &sb_col, true); + store_sb_text(&sb_str, s, hl_id, &sb_col, true); } } else if (c == '\r') { // go to column 0 msg_col = 0; @@ -2291,7 +2281,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) msg_cursor_goto(msg_row, msg_col); if (p_more && !recurse) { - store_sb_text(&sb_str, s, attr, &sb_col, false); + store_sb_text(&sb_str, s, hl_id, &sb_col, false); } msg_check(); @@ -2481,7 +2471,7 @@ static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE; /// @param sb_str start of string /// @param s just after string /// @param finish line ends -static void store_sb_text(const char **sb_str, const char *s, int attr, int *sb_col, int finish) +static void store_sb_text(const char **sb_str, const char *s, int hl_id, int *sb_col, int finish) { msgchunk_T *mp; @@ -2499,7 +2489,7 @@ static void store_sb_text(const char **sb_str, const char *s, int attr, int *sb_ mp = xmalloc(offsetof(msgchunk_T, sb_text) + (size_t)(s - *sb_str) + 1); mp->sb_eol = (char)finish; mp->sb_msg_col = *sb_col; - mp->sb_attr = attr; + mp->sb_hl_id = hl_id; memcpy(mp->sb_text, *sb_str, (size_t)(s - *sb_str)); mp->sb_text[s - *sb_str] = NUL; @@ -2637,7 +2627,7 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp) msg_row = row; msg_col = mp->sb_msg_col; char *p = mp->sb_text; - msg_puts_display(p, -1, mp->sb_attr, true); + msg_puts_display(p, -1, mp->sb_hl_id, true); if (mp->sb_eol || mp->sb_next == NULL) { break; } @@ -3321,17 +3311,17 @@ void give_warning(const char *message, bool hl) set_vim_var_string(VV_WARNINGMSG, message, -1); XFREE_CLEAR(keep_msg); if (hl) { - keep_msg_attr = HL_ATTR(HLF_W); + keep_msg_hl_id = HLF_W + 1; } else { - keep_msg_attr = 0; + keep_msg_hl_id = 0; } if (msg_ext_kind == NULL) { msg_ext_set_kind("wmsg"); } - if (msg(message, keep_msg_attr) && msg_scrolled == 0) { - set_keep_msg(message, keep_msg_attr); + if (msg(message, keep_msg_hl_id) && msg_scrolled == 0) { + set_keep_msg(message, keep_msg_hl_id); } msg_didout = false; // Overwrite this message. msg_nowait = true; // Don't wait for this message. @@ -3664,7 +3654,7 @@ void display_confirm_msg(void) confirm_msg_used++; if (confirm_msg != NULL) { msg_ext_set_kind("confirm"); - msg_puts_attr(confirm_msg, HL_ATTR(HLF_M)); + msg_puts_hl(confirm_msg, HLF_M + 1, false); } confirm_msg_used--; } diff --git a/src/nvim/message.h b/src/nvim/message.h index c11c33c039..13746406f9 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -28,8 +28,6 @@ enum { VIM_DISCARDALL = 6, }; -enum { MSG_HIST = 0x1000, }; ///< special attribute addition: Put message in history - /// First message extern MessageHistoryEntry *first_msg_hist; /// Last message diff --git a/src/nvim/message_defs.h b/src/nvim/message_defs.h index e60e60b3be..8d23b79385 100644 --- a/src/nvim/message_defs.h +++ b/src/nvim/message_defs.h @@ -6,7 +6,7 @@ typedef struct { String text; - int attr; + int hl_id; } HlMessageChunk; typedef kvec_t(HlMessageChunk) HlMessage; @@ -16,7 +16,7 @@ typedef struct msg_hist { struct msg_hist *next; ///< Next message. char *msg; ///< Message text. const char *kind; ///< Message kind (for msg_ext) - int attr; ///< Message highlighting. + int hl_id; ///< Message highlighting. bool multiline; ///< Multiline message. - HlMessage multiattr; ///< multiattr message. + HlMessage multihl; ///< Multihl message. } MessageHistoryEntry; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index aa247e39e6..d0517d5e4f 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -693,7 +693,7 @@ static void normal_redraw_mode_message(NormalState *s) keep_msg = kmsg; kmsg = xstrdup(keep_msg); - msg(kmsg, keep_msg_attr); + msg(kmsg, keep_msg_hl_id); xfree(kmsg); } setcursor(); @@ -1388,7 +1388,7 @@ static void normal_redraw(NormalState *s) // check for duplicates. Never put this message in // history. msg_hist_off = true; - msg(p, keep_msg_attr); + msg(p, keep_msg_hl_id); msg_hist_off = false; xfree(p); } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 1705c8b648..6bc2ce237b 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -257,7 +257,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) vim_snprintf(IObuff, IOSIZE, NGETTEXT(msg_line_single, msg_line_plural, oap->line_count), (int64_t)oap->line_count, op, amount); - msg_attr_keep(IObuff, 0, true, false); + msg_hl_keep(IObuff, 0, true, false); } if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { @@ -3653,7 +3653,7 @@ void ex_display(exarg_T *eap) if (arg != NULL && *arg == NUL) { arg = NULL; } - int attr = HL_ATTR(HLF_8); + int hl_id = HLF_8 + 1; // Highlight title msg_puts_title(_("\nType Name Content")); @@ -3709,18 +3709,18 @@ void ex_display(exarg_T *eap) int n = Columns - 11; for (size_t j = 0; j < yb->y_size && n > 1; j++) { if (j) { - msg_puts_attr("^J", attr); + msg_puts_hl("^J", hl_id, false); n -= 2; } for (p = yb->y_array[j].data; *p != NUL && (n -= ptr2cells(p)) >= 0; p++) { int clen = utfc_ptr2len(p); - msg_outtrans_len(p, clen, 0); + msg_outtrans_len(p, clen, 0, false); p += clen - 1; } } if (n > 1 && yb->y_type == kMTLineWise) { - msg_puts_attr("^J", attr); + msg_puts_hl("^J", hl_id, false); } } os_breakcheck(); @@ -3790,10 +3790,10 @@ static void dis_msg(const char *p, bool skip_esc) && (n -= ptr2cells(p)) >= 0) { int l; if ((l = utfc_ptr2len(p)) > 1) { - msg_outtrans_len(p, l, 0); + msg_outtrans_len(p, l, 0, false); p += l; } else { - msg_outtrans_len(p++, 1, 0); + msg_outtrans_len(p++, 1, 0, false); } } os_breakcheck(); diff --git a/src/nvim/option.c b/src/nvim/option.c index 635d26f123..0944a3041e 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1903,8 +1903,8 @@ static const char *did_set_arabic(optset_T *args) if (strcmp(p_enc, "utf-8") != 0) { static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"); - msg_source(HL_ATTR(HLF_W)); - msg(_(w_arabic), HL_ATTR(HLF_W)); + msg_source(HLF_W + 1); + msg(_(w_arabic), HLF_W + 1); set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1); } @@ -4187,7 +4187,7 @@ static void showoneopt(vimoption_T *opt, int opt_flags) msg_putchar('='); // put value string in NameBuff option_value2string(opt, opt_flags); - msg_outtrans(NameBuff, 0); + msg_outtrans(NameBuff, 0, false); } silent_mode = save_silent; diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index efcdee9c8b..81b75dc4d3 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -885,9 +885,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu // Failed, probably 'shell' is not executable. if (!silent) { msg_puts(_("\nshell failed to start: ")); - msg_outtrans(os_strerror(status), 0); + msg_outtrans(os_strerror(status), 0, false); msg_puts(": "); - msg_outtrans(prog, 0); + msg_outtrans(prog, 0, false); msg_putchar('\n'); } multiqueue_free(events); @@ -1102,7 +1102,7 @@ static void out_data_append_to_screen(const char *output, size_t *count, bool eo const char *end = output + *count; while (p < end) { if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) { - msg_putchar_attr((uint8_t)(*p), 0); + msg_putchar_hl((uint8_t)(*p), 0); p++; } else { // Note: this is not 100% precise: @@ -1118,7 +1118,7 @@ static void out_data_append_to_screen(const char *output, size_t *count, bool eo goto end; } - msg_outtrans_len(p, i, 0); + msg_outtrans_len(p, i, 0, false); p += i; } } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index f037d5d924..304b72ce12 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2937,7 +2937,7 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf msg_scroll = false; } msg_ext_set_kind("quickfix"); - msg_attr_keep(gap->ga_data, 0, true, false); + msg_hl_keep(gap->ga_data, 0, true, false); msg_scroll = (int)i; qfga_clear(); @@ -3144,10 +3144,10 @@ theend: decr_quickfix_busy(); } -// Highlight attributes used for displaying entries from the quickfix list. -static int qfFileAttr; -static int qfSepAttr; -static int qfLineAttr; +// Highlight ids used for displaying entries from the quickfix list. +static int qfFile_hl_id; +static int qfSep_hl_id; +static int qfLine_hl_id; /// Display information about a single entry from the quickfix/location list. /// Used by ":clist/:llist" commands. @@ -3195,10 +3195,10 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) } msg_putchar('\n'); - msg_outtrans(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr); + msg_outtrans(IObuff, cursel ? HLF_QFL + 1 : qfFile_hl_id, false); if (qfp->qf_lnum != 0) { - msg_puts_attr(":", qfSepAttr); + msg_puts_hl(":", qfSep_hl_id, false); } garray_T *gap = qfga_get(); if (qfp->qf_lnum != 0) { @@ -3206,14 +3206,14 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) } ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr)); ga_append(gap, NUL); - msg_puts_attr(gap->ga_data, qfLineAttr); - msg_puts_attr(":", qfSepAttr); + msg_puts_hl(gap->ga_data, qfLine_hl_id, false); + msg_puts_hl(":", qfSep_hl_id, false); if (qfp->qf_pattern != NULL) { gap = qfga_get(); qf_fmt_text(gap, qfp->qf_pattern); ga_append(gap, NUL); msg_puts(gap->ga_data); - msg_puts_attr(":", qfSepAttr); + msg_puts_hl(":", qfSep_hl_id, false); } msg_puts(" "); @@ -3275,17 +3275,17 @@ void qf_list(exarg_T *eap) // Get the attributes for the different quickfix highlight items. Note // that this depends on syntax items defined in the qf.vim syntax file - qfFileAttr = syn_name2attr("qfFileName"); - if (qfFileAttr == 0) { - qfFileAttr = HL_ATTR(HLF_D); + qfFile_hl_id = syn_name2id("qfFileName"); + if (qfFile_hl_id == 0) { + qfFile_hl_id = HLF_D + 1; } - qfSepAttr = syn_name2attr("qfSeparator"); - if (qfSepAttr == 0) { - qfSepAttr = HL_ATTR(HLF_D); + qfSep_hl_id = syn_name2id("qfSeparator"); + if (qfSep_hl_id == 0) { + qfSep_hl_id = HLF_D + 1; } - qfLineAttr = syn_name2attr("qfLineNr"); - if (qfLineAttr == 0) { - qfLineAttr = HL_ATTR(HLF_N); + qfLine_hl_id = syn_name2id("qfLineNr"); + if (qfLine_hl_id == 0) { + qfLine_hl_id = HLF_N + 1; } if (qfl->qf_nonevalid) { @@ -4396,7 +4396,7 @@ static char *make_get_fullcmd(const char *makecmd, const char *fname) } msg_start(); msg_puts(":!"); - msg_outtrans(cmd, 0); // show what we are doing + msg_outtrans(cmd, 0, false); // show what we are doing return cmd; } @@ -5243,9 +5243,9 @@ static void vgr_display_fname(char *fname) msg_start(); char *p = msg_strtrunc(fname, true); if (p == NULL) { - msg_outtrans(fname, 0); + msg_outtrans(fname, 0, false); } else { - msg_outtrans(p, 0); + msg_outtrans(p, 0, false); xfree(p); } msg_clr_eos(); diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 030bda4fa5..3f00b74e61 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -2348,7 +2348,7 @@ void ex_scriptnames(exarg_T *eap) vim_snprintf(IObuff, IOSIZE, "%3d: %s", i, NameBuff); if (!message_filtered(IObuff)) { msg_putchar('\n'); - msg_outtrans(IObuff, 0); + msg_outtrans(IObuff, 0, false); line_breakcheck(); } } diff --git a/src/nvim/search.c b/src/nvim/search.c index 5d3d3db3fe..bfa90ba24a 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1304,7 +1304,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen memset(msgbuf + pat_len, ' ', (size_t)(r - msgbuf)); } } - msg_outtrans(msgbuf, 0); + msg_outtrans(msgbuf, 0, false); msg_clr_eos(); msg_check(); @@ -3731,7 +3731,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool && action == ACTION_SHOW_ALL && files[i].matched) { msg_putchar('\n'); // cursor below last one if (!got_int) { // don't display if 'q' typed at "--more--" message - msg_home_replace_hl(new_fname); + msg_home_replace(new_fname); msg_puts(_(" (includes previously listed match)")); prev_fname = NULL; } @@ -3772,7 +3772,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool if (new_fname != NULL) { // using "new_fname" is more reliable, e.g., when // 'includeexpr' is set. - msg_outtrans(new_fname, HL_ATTR(HLF_D)); + msg_outtrans(new_fname, HLF_D + 1, false); } else { // Isolate the file name. // Include the surrounding "" or <> if present. @@ -3806,7 +3806,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool } char save_char = p[i]; p[i] = NUL; - msg_outtrans(p, HL_ATTR(HLF_D)); + msg_outtrans(p, HLF_D + 1, false); p[i] = save_char; } @@ -3858,7 +3858,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool vim_snprintf(IObuff, IOSIZE, _("Scanning included file: %s"), new_fname); - msg_trunc(IObuff, true, HL_ATTR(HLF_R)); + msg_trunc(IObuff, true, HLF_R + 1); } else if (p_verbose >= 5) { verbose_enter(); smsg(0, _("Searching included file %s"), new_fname); @@ -4032,7 +4032,7 @@ search_line: } if (!got_int) { // don't display if 'q' typed // at "--more--" message - msg_home_replace_hl(curr_fname); + msg_home_replace(curr_fname); } prev_fname = curr_fname; } @@ -4233,7 +4233,7 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI msg_puts(IObuff); snprintf(IObuff, IOSIZE, "%4" PRIdLINENR, *lnum); // Show line nr. // Highlight line numbers. - msg_puts_attr(IObuff, HL_ATTR(HLF_N)); + msg_puts_hl(IObuff, HLF_N + 1, false); msg_puts(" "); } msg_prt_line(line, false); diff --git a/src/nvim/sign.c b/src/nvim/sign.c index b4ba7833e9..ec342d8b50 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -270,7 +270,7 @@ static void sign_list_placed(buf_T *rbuf, char *group) while (buf != NULL && !got_int) { if (buf_has_signs(buf)) { vim_snprintf(lbuf, MSG_BUF_LEN, _("Signs for %s:"), buf->b_fname); - msg_puts_attr(lbuf, HL_ATTR(HLF_D)); + msg_puts_hl(lbuf, HLF_D + 1, false); msg_putchar('\n'); } @@ -481,14 +481,14 @@ static void sign_list_defined(sign_T *sp) smsg(0, "sign %s", sp->sn_name); if (sp->sn_icon != NULL) { msg_puts(" icon="); - msg_outtrans(sp->sn_icon, 0); + msg_outtrans(sp->sn_icon, 0, false); msg_puts(_(" (not supported)")); } if (sp->sn_text[0]) { msg_puts(" text="); char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; describe_sign_text(buf, sp->sn_text); - msg_outtrans(buf, 0); + msg_outtrans(buf, 0, false); } if (sp->sn_priority > 0) { char lbuf[MSG_BUF_LEN]; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 9eeed3fbd2..13bc2f0d50 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -2928,9 +2928,9 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing) msg_puts("\n"); if (curwin->w_s->b_syn_isk != empty_string_option) { msg_puts("syntax iskeyword "); - msg_outtrans(curwin->w_s->b_syn_isk, 0); + msg_outtrans(curwin->w_s->b_syn_isk, 0, false); } else { - msg_outtrans(_("syntax iskeyword not set"), 0); + msg_outtrans(_("syntax iskeyword not set"), 0, false); } } else { if (STRNICMP(arg, "clear", 5) == 0) { @@ -3346,13 +3346,12 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) KEYVALUE_ENTRY(HL_SKIPEMPTY, "skipempty"), }; - const int attr = HL_ATTR(HLF_D); // highlight like directories + const int hl_id = HLF_D + 1; // highlight like directories // list the keywords for "id" if (!syncing) { - did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab, false, attr); - did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab_ic, - did_header, attr); + did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab, false, hl_id); + did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab_ic, did_header, hl_id); } // list the patterns for "id" @@ -3368,46 +3367,46 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) did_header = true; last_matchgroup = 0; if (spp->sp_type == SPTYPE_MATCH) { - put_pattern("match", ' ', spp, attr); + put_pattern("match", ' ', spp, hl_id); msg_putchar(' '); } else if (spp->sp_type == SPTYPE_START) { while (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_START) { - put_pattern("start", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr); + put_pattern("start", '=', &SYN_ITEMS(curwin->w_s)[idx++], hl_id); } if (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_SKIP) { - put_pattern("skip", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr); + put_pattern("skip", '=', &SYN_ITEMS(curwin->w_s)[idx++], hl_id); } while (idx < curwin->w_s->b_syn_patterns.ga_len && SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_END) { - put_pattern("end", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr); + put_pattern("end", '=', &SYN_ITEMS(curwin->w_s)[idx++], hl_id); } idx--; msg_putchar(' '); } - syn_list_flags(namelist1, ARRAY_SIZE(namelist1), spp->sp_flags, attr); + syn_list_flags(namelist1, ARRAY_SIZE(namelist1), spp->sp_flags, hl_id); if (spp->sp_cont_list != NULL) { - put_id_list("contains", spp->sp_cont_list, attr); + put_id_list("contains", spp->sp_cont_list, hl_id); } if (spp->sp_syn.cont_in_list != NULL) { - put_id_list("containedin", spp->sp_syn.cont_in_list, attr); + put_id_list("containedin", spp->sp_syn.cont_in_list, hl_id); } if (spp->sp_next_list != NULL) { - put_id_list("nextgroup", spp->sp_next_list, attr); - syn_list_flags(namelist2, ARRAY_SIZE(namelist2), spp->sp_flags, attr); + put_id_list("nextgroup", spp->sp_next_list, hl_id); + syn_list_flags(namelist2, ARRAY_SIZE(namelist2), spp->sp_flags, hl_id); } if (spp->sp_flags & (HL_SYNC_HERE|HL_SYNC_THERE)) { if (spp->sp_flags & HL_SYNC_HERE) { - msg_puts_attr("grouphere", attr); + msg_puts_hl("grouphere", hl_id, false); } else { - msg_puts_attr("groupthere", attr); + msg_puts_hl("groupthere", hl_id, false); } msg_putchar(' '); if (spp->sp_sync_idx >= 0) { msg_outtrans(highlight_group_name(SYN_ITEMS(curwin->w_s) - [spp->sp_sync_idx].sp_syn.id - 1), 0); + [spp->sp_sync_idx].sp_syn.id - 1), 0, false); } else { msg_puts("NONE"); } @@ -3418,17 +3417,17 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) // list the link, if there is one if (highlight_link_id(id - 1) && (did_header || link_only) && !got_int) { syn_list_header(did_header, 0, id, true); - msg_puts_attr("links to", attr); + msg_puts_hl("links to", hl_id, false); msg_putchar(' '); - msg_outtrans(highlight_group_name(highlight_link_id(id - 1) - 1), 0); + msg_outtrans(highlight_group_name(highlight_link_id(id - 1) - 1), 0, false); } } -static void syn_list_flags(keyvalue_T *nlist, size_t nr_entries, int flags, int attr) +static void syn_list_flags(keyvalue_T *nlist, size_t nr_entries, int flags, int hl_id) { for (size_t i = 0; i < nr_entries; i++) { if (flags & nlist[i].key) { - msg_puts_attr(nlist[i].value, attr); + msg_puts_hl(nlist[i].value, hl_id, false); msg_putchar(' '); } } @@ -3441,7 +3440,7 @@ static void syn_list_cluster(int id) // slight hack: roughly duplicate the guts of syn_list_header() msg_putchar('\n'); - msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name, 0); + msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name, 0, false); if (msg_col >= endcol) { // output at least one space endcol = msg_col + 1; @@ -3452,16 +3451,16 @@ static void syn_list_cluster(int id) msg_advance(endcol); if (SYN_CLSTR(curwin->w_s)[id].scl_list != NULL) { - put_id_list("cluster", SYN_CLSTR(curwin->w_s)[id].scl_list, HL_ATTR(HLF_D)); + put_id_list("cluster", SYN_CLSTR(curwin->w_s)[id].scl_list, HLF_D + 1); } else { - msg_puts_attr("cluster", HL_ATTR(HLF_D)); + msg_puts_hl("cluster", HLF_D + 1, false); msg_puts("=NONE"); } } -static void put_id_list(const char *const name, const int16_t *const list, const int attr) +static void put_id_list(const char *const name, const int16_t *const list, const int hl_id) { - msg_puts_attr(name, attr); + msg_puts_hl(name, hl_id, false); msg_putchar('='); for (const int16_t *p = list; *p; p++) { if (*p >= SYNID_ALLBUT && *p < SYNID_TOP) { @@ -3478,9 +3477,9 @@ static void put_id_list(const char *const name, const int16_t *const list, const int scl_id = *p - SYNID_CLUSTER; msg_putchar('@'); - msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name, 0); + msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name, 0, false); } else { - msg_outtrans(highlight_group_name(*p - 1), 0); + msg_outtrans(highlight_group_name(*p - 1), 0, false); } if (p[1]) { msg_putchar(','); @@ -3489,7 +3488,8 @@ static void put_id_list(const char *const name, const int16_t *const list, const msg_putchar(' '); } -static void put_pattern(const char *const s, const int c, const synpat_T *const spp, const int attr) +static void put_pattern(const char *const s, const int c, const synpat_T *const spp, + const int hl_id) { static const char *const sepchars = "/+=-#@\"|'^&"; int i; @@ -3497,18 +3497,18 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const // May have to write "matchgroup=group" if (last_matchgroup != spp->sp_syn_match_id) { last_matchgroup = spp->sp_syn_match_id; - msg_puts_attr("matchgroup", attr); + msg_puts_hl("matchgroup", hl_id, false); msg_putchar('='); if (last_matchgroup == 0) { - msg_outtrans("NONE", 0); + msg_outtrans("NONE", 0, false); } else { - msg_outtrans(highlight_group_name(last_matchgroup - 1), 0); + msg_outtrans(highlight_group_name(last_matchgroup - 1), 0, false); } msg_putchar(' '); } // Output the name of the pattern and an '=' or ' '. - msg_puts_attr(s, attr); + msg_puts_hl(s, hl_id, false); msg_putchar(c); // output the pattern, in between a char that is not in the pattern @@ -3519,7 +3519,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const } } msg_putchar(sepchars[i]); - msg_outtrans(spp->sp_pattern, 0); + msg_outtrans(spp->sp_pattern, 0, false); msg_putchar(sepchars[i]); // output any pattern options @@ -3558,7 +3558,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const /// /// @return true if the header has been printed. static bool syn_list_keywords(const int id, const hashtab_T *const ht, bool did_header, - const int attr) + const int hl_id) { int prev_contained = 0; const int16_t *prev_next_list = NULL; @@ -3600,36 +3600,36 @@ static bool syn_list_keywords(const int id, const hashtab_T *const ht, bool did_ } did_header = true; if (prev_contained != (kp->flags & HL_CONTAINED)) { - msg_puts_attr("contained", attr); + msg_puts_hl("contained", hl_id, false); msg_putchar(' '); prev_contained = (kp->flags & HL_CONTAINED); } if (kp->k_syn.cont_in_list != prev_cont_in_list) { - put_id_list("containedin", kp->k_syn.cont_in_list, attr); + put_id_list("containedin", kp->k_syn.cont_in_list, hl_id); msg_putchar(' '); prev_cont_in_list = kp->k_syn.cont_in_list; } if (kp->next_list != prev_next_list) { - put_id_list("nextgroup", kp->next_list, attr); + put_id_list("nextgroup", kp->next_list, hl_id); msg_putchar(' '); prev_next_list = kp->next_list; if (kp->flags & HL_SKIPNL) { - msg_puts_attr("skipnl", attr); + msg_puts_hl("skipnl", hl_id, false); msg_putchar(' '); prev_skipnl = (kp->flags & HL_SKIPNL); } if (kp->flags & HL_SKIPWHITE) { - msg_puts_attr("skipwhite", attr); + msg_puts_hl("skipwhite", hl_id, false); msg_putchar(' '); prev_skipwhite = (kp->flags & HL_SKIPWHITE); } if (kp->flags & HL_SKIPEMPTY) { - msg_puts_attr("skipempty", attr); + msg_puts_hl("skipempty", hl_id, false); msg_putchar(' '); prev_skipempty = (kp->flags & HL_SKIPEMPTY); } } - msg_outtrans(kp->keyword, 0); + msg_outtrans(kp->keyword, 0, false); } } } @@ -5649,7 +5649,7 @@ static void syntime_report(void) msg_puts(profile_msg(p->average)); msg_puts(" "); msg_advance(50); - msg_outtrans(highlight_group_name(p->id - 1), 0); + msg_outtrans(highlight_group_name(p->id - 1), 0, false); msg_puts(" "); msg_advance(69); @@ -5661,7 +5661,7 @@ static void syntime_report(void) } int patlen = (int)strlen(p->pattern); len = MIN(len, patlen); - msg_outtrans_len(p->pattern, len, 0); + msg_outtrans_len(p->pattern, len, 0, false); msg_puts("\n"); } ga_clear(&ga); diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 7a0c1cd810..d721d06e4f 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -736,7 +736,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) } if ((num_matches > prev_num_matches || new_tag) && num_matches > 1) { - msg(IObuff, ic ? HL_ATTR(HLF_W) : 0); + msg(IObuff, ic ? HLF_W + 1 : 0); msg_scroll = true; // Don't overwrite this message. } else { give_warning(IObuff, ic); @@ -815,10 +815,10 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha msg_didout = false; // overwrite previous message } msg_start(); - msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T)); + msg_puts_hl(_(" # pri kind tag"), HLF_T + 1, false); msg_clr_eos(); taglen_advance(taglen); - msg_puts_attr(_("file\n"), HL_ATTR(HLF_T)); + msg_puts_hl(_("file\n"), HLF_T + 1, false); for (int i = 0; i < num_matches && !got_int; i++) { parse_match(matches[i], &tagp); @@ -836,10 +836,10 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha mt_names[matches[i][0] & MT_MASK]); msg_puts(IObuff); if (tagp.tagkind != NULL) { - msg_outtrans_len(tagp.tagkind, (int)(tagp.tagkind_end - tagp.tagkind), 0); + msg_outtrans_len(tagp.tagkind, (int)(tagp.tagkind_end - tagp.tagkind), 0, false); } msg_advance(13); - msg_outtrans_len(tagp.tagname, (int)(tagp.tagname_end - tagp.tagname), HL_ATTR(HLF_T)); + msg_outtrans_len(tagp.tagname, (int)(tagp.tagname_end - tagp.tagname), HLF_T + 1, false); msg_putchar(' '); taglen_advance(taglen); @@ -847,7 +847,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha // it and put "..." in the middle const char *p = tag_full_fname(&tagp); if (p != NULL) { - msg_outtrans(p, HL_ATTR(HLF_D)); + msg_outtrans(p, HLF_D + 1, false); XFREE_CLEAR(p); } if (msg_col > 0) { @@ -880,7 +880,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha continue; } // print all other extra fields - int attr = HL_ATTR(HLF_CM); + int hl_id = HLF_CM + 1; while (*p && *p != '\r' && *p != '\n') { if (msg_col + ptr2cells(p) >= Columns) { msg_putchar('\n'); @@ -889,13 +889,13 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha } msg_advance(15); } - p = msg_outtrans_one(p, attr); + p = msg_outtrans_one(p, hl_id, false); if (*p == TAB) { - msg_puts_attr(" ", attr); + msg_puts_hl(" ", hl_id, false); break; } if (*p == ':') { - attr = 0; + hl_id = 0; } } } @@ -947,7 +947,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha msg_putchar(' '); p++; } else { - p = msg_outtrans_one(p, 0); + p = msg_outtrans_one(p, 0, false); } // don't display the "$/;\"" and "$?;\"" @@ -1125,8 +1125,8 @@ void do_tags(exarg_T *eap) tagstack[i].cur_match + 1, tagstack[i].tagname, tagstack[i].fmark.mark.lnum); - msg_outtrans(IObuff, 0); - msg_outtrans(name, tagstack[i].fmark.fnum == curbuf->b_fnum ? HL_ATTR(HLF_D) : 0); + msg_outtrans(IObuff, 0, false); + msg_outtrans(name, tagstack[i].fmark.fnum == curbuf->b_fnum ? HLF_D + 1 : 0, false); xfree(name); } } diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 365aa5c74f..bd3679f708 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -358,8 +358,8 @@ void vim_beep(unsigned val) // a script or executing a function give the user a hint where the beep // comes from. if (vim_strchr(p_debug, 'e') != NULL) { - msg_source(HL_ATTR(HLF_W)); - msg(_("Beep!"), HL_ATTR(HLF_W)); + msg_source(HLF_W + 1); + msg(_("Beep!"), HLF_W + 1); } } diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 15c8e0b283..52581bea36 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2595,13 +2595,12 @@ static void u_undo_end(bool did_undo, bool absolute, bool quiet) check_pos(curbuf, &VIsual); } - smsg_attr_keep(0, - _("%" PRId64 " %s; %s #%" PRId64 " %s"), - u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount, - _(msgstr), - did_undo ? _("before") : _("after"), - uhp == NULL ? 0 : (int64_t)uhp->uh_seq, - msgbuf); + smsg_hl_keep(0, _("%" PRId64 " %s; %s #%" PRId64 " %s"), + u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount, + _(msgstr), + did_undo ? _("before") : _("after"), + uhp == NULL ? 0 : (int64_t)uhp->uh_seq, + msgbuf); } /// Put the timestamp of an undo header in "buf[buflen]" in a nice format. @@ -2713,8 +2712,7 @@ void ex_undolist(exarg_T *eap) sort_strings(ga.ga_data, ga.ga_len); msg_start(); - msg_puts_attr(_("number changes when saved"), - HL_ATTR(HLF_T)); + msg_puts_hl(_("number changes when saved"), HLF_T + 1, false); for (int i = 0; i < ga.ga_len && !got_int; i++) { msg_putchar('\n'); if (got_int) { diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 8404b2bc14..904dc4bfe8 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -464,8 +464,7 @@ static void uc_list(char *name, size_t name_len) // Put out the title first time if (!found) { - msg_puts_title(_("\n Name Args Address " - "Complete Definition")); + msg_puts_title(_("\n Name Args Address Complete Definition")); } found = true; msg_putchar('\n'); @@ -495,7 +494,7 @@ static void uc_list(char *name, size_t name_len) msg_putchar(' '); } - msg_outtrans(cmd->uc_name, HL_ATTR(HLF_D)); + msg_outtrans(cmd->uc_name, HLF_D + 1, false); len = strlen(cmd->uc_name) + 4; do { @@ -582,11 +581,11 @@ static void uc_list(char *name, size_t name_len) } while ((int64_t)len < 25 - over); IObuff[len] = NUL; - msg_outtrans(IObuff, 0); + msg_outtrans(IObuff, 0, false); if (cmd->uc_luaref != LUA_NOREF) { char *fn = nlua_funcref_str(cmd->uc_luaref, NULL); - msg_puts_attr(fn, HL_ATTR(HLF_8)); + msg_puts_hl(fn, HLF_8 + 1, false); xfree(fn); // put the description on a new line if (*cmd->uc_rep != NUL) { -- cgit From ad3472e291694b6c589d8a664459b03962eaac95 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 7 Nov 2024 16:21:49 +0000 Subject: fix(vim.system): resolve executable paths on windows Fixes #31107 --- src/nvim/eval.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 870eb17b9e..601c07cfab 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -2165,6 +2165,7 @@ M.funcs = { If {expr} starts with "./" the |current-directory| is used. ]=], + fast = true, name = 'exepath', params = { { 'expr', 'string' } }, signature = 'exepath({expr})', -- cgit From 5a27d02584656f35d757c01f10a1d3c88910c519 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 9 Nov 2024 01:10:56 +0100 Subject: docs: misc (#30914) Co-authored-by: Ernie Rael Co-authored-by: Famiu Haque Co-authored-by: Jade Co-authored-by: glepnir Co-authored-by: zeertzjq --- src/nvim/api/vim.c | 4 ++-- src/nvim/eval.lua | 6 +++--- src/nvim/option.c | 2 -- src/nvim/vvars.lua | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 943c67ac8e..97cda49a22 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -781,8 +781,8 @@ void nvim_set_vvar(String name, Object value, Error *err) /// can be omitted for no highlight. /// @param history if true, add to |message-history|. /// @param opts Optional parameters. -/// - verbose: Message was printed as a result of 'verbose' option -/// if Nvim was invoked with -V3log_file, the message will be +/// - verbose: Message is printed as a result of 'verbose' option. +/// If Nvim was invoked with -V3log_file, the message will be /// redirected to the log_file and suppressed from direct output. void nvim_echo(Array chunks, Boolean history, Dict(echo_opts) *opts, Error *err) FUNC_API_SINCE(7) diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 601c07cfab..a418b34909 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -1137,7 +1137,7 @@ M.funcs = { ]=], name = 'charcol', - params = { { 'expr', 'string|integer[]' }, { 'winid', 'integer' } }, + params = { { 'expr', 'string|any[]' }, { 'winid', 'integer' } }, returns = 'integer', signature = 'charcol({expr} [, {winid}])', }, @@ -1296,7 +1296,7 @@ M.funcs = { ]=], name = 'col', - params = { { 'expr', 'string|integer[]' }, { 'winid', 'integer' } }, + params = { { 'expr', 'string|any[]' }, { 'winid', 'integer' } }, returns = 'integer', signature = 'col({expr} [, {winid}])', }, @@ -12684,7 +12684,7 @@ M.funcs = { ]=], name = 'virtcol', - params = { { 'expr', 'string|integer[]' }, { 'list', 'boolean' }, { 'winid', 'integer' } }, + params = { { 'expr', 'string|any[]' }, { 'list', 'boolean' }, { 'winid', 'integer' } }, signature = 'virtcol({expr} [, {list} [, {winid}]])', }, virtcol2col = { diff --git a/src/nvim/option.c b/src/nvim/option.c index 0396f7740e..c7aaf7975d 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3282,8 +3282,6 @@ static char *option_get_valid_types(OptIndex opt_idx) // Ensure that the string is NUL-terminated. kv_push(str, NUL); return str.items; - -#undef OPTION_ADD_TYPE } /// Check if option is hidden. diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index ad139bbbfe..4936f62e3e 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -177,7 +177,7 @@ M.vars = { inclusive Motion is |inclusive|, else exclusive. scope Event-specific scope name. operator Current |operator|. Also set for Ex - commands (unlike |v:operator|). For + commands (unlike |v:operator|). For example if |TextYankPost| is triggered by the |:yank| Ex command then `v:event.operator` is "y". -- cgit From 07b14c8e2ed288dfca382719aeb26d544573f51a Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 8 Nov 2024 17:16:43 +0100 Subject: build: specify POST_BUILD when using add_custom_command This is needed specifically for the second signature of add_custom_command, which appends an operation to an existing target. This will prevent the cmake warning CMP0175. Reference: https://cmake.org/cmake/help/latest/policy/CMP0175.html --- src/nvim/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 0ba2eeb376..cb71144130 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -750,6 +750,7 @@ add_custom_target(nvim_runtime_deps) if(WIN32) # Copy DLLs and third-party tools to bin/ and install them along with nvim add_custom_command(TARGET nvim_runtime_deps + POST_BUILD COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${PROJECT_BINARY_DIR}/windows_runtime_deps/ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) install(DIRECTORY ${PROJECT_BINARY_DIR}/windows_runtime_deps/ @@ -791,7 +792,10 @@ file(MAKE_DIRECTORY ${BINARY_LIB_DIR}) # install treesitter parser if bundled if(EXISTS ${DEPS_PREFIX}/lib/nvim/parser) - add_custom_command(TARGET nvim_runtime_deps COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${DEPS_PREFIX}/lib/nvim/parser ${BINARY_LIB_DIR}/parser) + add_custom_command( + TARGET nvim_runtime_deps + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E ${COPY_DIRECTORY} ${DEPS_PREFIX}/lib/nvim/parser ${BINARY_LIB_DIR}/parser) endif() install(DIRECTORY ${BINARY_LIB_DIR} -- cgit From 4f9260d06a48216862ebb34fc33744486b058f58 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Fri, 8 Mar 2024 14:44:58 +0100 Subject: feat(ext_messages): add hl_id to ext_messages chunks Problem: Ext_messages chunks only contain the highlight attr id, which is not very useful for vim.ui_attach() consumers. Solotion: Add highlight group id to message chunks, which can easily be used to highlight text in the TUI through nvim_buf_set_extmark(): hl_group = synIDattr(id, "name"). --- src/nvim/message.c | 5 +++++ src/nvim/normal.c | 3 ++- src/nvim/statusline.c | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/message.c b/src/nvim/message.c index dc9c7d0c37..977b37f8c3 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -139,6 +139,7 @@ static const char *msg_ext_kind = NULL; static Array *msg_ext_chunks = NULL; static garray_T msg_ext_last_chunk = GA_INIT(sizeof(char), 40); static sattr_T msg_ext_last_attr = -1; +static int msg_ext_hl_id; static size_t msg_ext_cur_len = 0; static bool msg_ext_overwrite = false; ///< will overwrite last message @@ -1088,12 +1089,14 @@ void ex_messages(exarg_T *eap) Array content_entry = ARRAY_DICT_INIT; ADD(content_entry, INTEGER_OBJ(chunk.hl_id ? syn_id2attr(chunk.hl_id) : 0)); ADD(content_entry, STRING_OBJ(copy_string(chunk.text, NULL))); + ADD(content_entry, INTEGER_OBJ(chunk.hl_id)); ADD(content, ARRAY_OBJ(content_entry)); } } else if (p->msg && p->msg[0]) { Array content_entry = ARRAY_DICT_INIT; ADD(content_entry, INTEGER_OBJ(p->hl_id ? syn_id2attr(p->hl_id) : 0)); ADD(content_entry, CSTR_TO_OBJ(p->msg)); + ADD(content_entry, INTEGER_OBJ(p->hl_id)); ADD(content, ARRAY_OBJ(content_entry)); } ADD(entry, ARRAY_OBJ(content)); @@ -2125,6 +2128,7 @@ static void msg_ext_emit_chunk(void) msg_ext_last_attr = -1; String text = ga_take_string(&msg_ext_last_chunk); ADD(chunk, STRING_OBJ(text)); + ADD(chunk, INTEGER_OBJ(msg_ext_hl_id)); ADD(*msg_ext_chunks, ARRAY_OBJ(chunk)); } @@ -2141,6 +2145,7 @@ static void msg_puts_display(const char *str, int maxlen, int hl_id, int recurse if (ui_has(kUIMessages)) { if (attr != msg_ext_last_attr) { + msg_ext_hl_id = hl_id; msg_ext_emit_chunk(); msg_ext_last_attr = attr; } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index d0517d5e4f..d2716bf236 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -2081,11 +2081,12 @@ static void display_showcmd(void) if (ui_has(kUIMessages)) { MAXSIZE_TEMP_ARRAY(content, 1); - MAXSIZE_TEMP_ARRAY(chunk, 2); + MAXSIZE_TEMP_ARRAY(chunk, 3); if (!showcmd_is_clear) { // placeholder for future highlight support ADD_C(chunk, INTEGER_OBJ(0)); ADD_C(chunk, CSTR_AS_OBJ(showcmd_buf)); + ADD_C(chunk, INTEGER_OBJ(0)); ADD_C(content, ARRAY_OBJ(chunk)); } ui_call_msg_showcmd(content); diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 6b8f5e27a3..d9ac1aa347 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -582,9 +582,11 @@ void win_redr_ruler(win_T *wp) if (ui_has(kUIMessages) && !part_of_status) { MAXSIZE_TEMP_ARRAY(content, 1); - MAXSIZE_TEMP_ARRAY(chunk, 2); + MAXSIZE_TEMP_ARRAY(chunk, 3); ADD_C(chunk, INTEGER_OBJ(attr)); ADD_C(chunk, CSTR_AS_OBJ(buffer)); + ADD_C(chunk, INTEGER_OBJ(HLF_MSG + 1)); + assert(attr == HL_ATTR(HLF_MSG)); ADD_C(content, ARRAY_OBJ(chunk)); ui_call_msg_ruler(content); did_show_ext_ruler = true; -- cgit From adbffff5d0e9972253079140453b55d8f9273b29 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 11 Nov 2024 08:20:41 +0800 Subject: vim-patch:9.1.0849: there are a few typos in the source (#31159) Problem: there are a few typos in the source. Solution: Correct typos (zeertzjq). closes: vim/vim#16026 https://github.com/vim/vim/commit/7c5152826f61bc968ba539ff6db3a55e75556bf2 --- src/nvim/ex_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 702dbeac27..834370afe5 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2261,7 +2261,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum if (buf == NULL) { goto theend; } - // autocommands try to edit a file that is goind to be removed, abort + // autocommands try to edit a file that is going to be removed, abort if (buf_locked(buf)) { // window was split, but not editing the new buffer, reset b_nwindows again if (oldwin == NULL -- cgit From 9fa3a0964e9bf47932d350cdb53ef0364175a672 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 11 Nov 2024 15:13:01 +0100 Subject: fix(messages): pass previous highlight id to ext chunks --- src/nvim/message.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/message.c b/src/nvim/message.c index 977b37f8c3..4e06a050c9 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -139,7 +139,7 @@ static const char *msg_ext_kind = NULL; static Array *msg_ext_chunks = NULL; static garray_T msg_ext_last_chunk = GA_INIT(sizeof(char), 40); static sattr_T msg_ext_last_attr = -1; -static int msg_ext_hl_id; +static int msg_ext_last_hl_id; static size_t msg_ext_cur_len = 0; static bool msg_ext_overwrite = false; ///< will overwrite last message @@ -2128,7 +2128,7 @@ static void msg_ext_emit_chunk(void) msg_ext_last_attr = -1; String text = ga_take_string(&msg_ext_last_chunk); ADD(chunk, STRING_OBJ(text)); - ADD(chunk, INTEGER_OBJ(msg_ext_hl_id)); + ADD(chunk, INTEGER_OBJ(msg_ext_last_hl_id)); ADD(*msg_ext_chunks, ARRAY_OBJ(chunk)); } @@ -2145,9 +2145,9 @@ static void msg_puts_display(const char *str, int maxlen, int hl_id, int recurse if (ui_has(kUIMessages)) { if (attr != msg_ext_last_attr) { - msg_ext_hl_id = hl_id; msg_ext_emit_chunk(); msg_ext_last_attr = attr; + msg_ext_last_hl_id = hl_id; } // Concat pieces with the same highlight size_t len = maxlen < 0 ? strlen(str) : strnlen(str, (size_t)maxlen); -- cgit From 17e00d0cc63cf2a42a66b03f28bd567f11998c24 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 13 Nov 2024 13:22:40 +0800 Subject: fix(startup): report --startuptime error to stderr (#31131) Problem: Crash when initializing for --startuptime errors. Solution: Report the error to stderr, as neither logging nor messages have been initialized yet. --- src/nvim/profile.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/profile.c b/src/nvim/profile.c index 81207b4e39..1b4f4a2029 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -956,7 +956,7 @@ void time_init(const char *fname, const char *proc_name) const size_t bufsize = 8192; // Big enough for the entire --startuptime report. time_fd = fopen(fname, "a"); if (time_fd == NULL) { - semsg(_(e_notopen), fname); + fprintf(stderr, _(e_notopen), fname); return; } startuptime_buf = xmalloc(sizeof(char) * (bufsize + 1)); @@ -968,8 +968,7 @@ void time_init(const char *fname, const char *proc_name) XFREE_CLEAR(startuptime_buf); fclose(time_fd); time_fd = NULL; - ELOG("time_init: setvbuf failed: %d %s", r, uv_err_name(r)); - semsg("time_init: setvbuf failed: %d %s", r, uv_err_name(r)); + fprintf(stderr, "time_init: setvbuf failed: %d %s", r, uv_err_name(r)); return; } fprintf(time_fd, "--- Startup times for process: %s ---\n", proc_name); -- cgit From ff7518b83cb270f8fcaded19bf640cf4bdfb0ff0 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 11 Nov 2024 13:06:37 +0100 Subject: refactor(highlight): make enum of builtin highlights start with 1 This makes it possible to use HLF_ values directly as highlight id:s and avoids +1 adjustments especially around messages. --- src/nvim/api/vim.c | 6 +++--- src/nvim/autocmd.c | 10 +++++----- src/nvim/bufwrite.c | 4 ++-- src/nvim/change.c | 4 ++-- src/nvim/cmdexpand.c | 10 +++++----- src/nvim/digraph.c | 4 ++-- src/nvim/drawscreen.c | 6 +++--- src/nvim/eval/funcs.c | 2 +- src/nvim/ex_cmds.c | 2 +- src/nvim/ex_cmds2.c | 2 +- src/nvim/ex_docmd.c | 4 ++-- src/nvim/ex_getln.c | 6 +++--- src/nvim/fileio.c | 4 ++-- src/nvim/highlight.c | 12 ++++++------ src/nvim/highlight.h | 2 +- src/nvim/highlight_defs.h | 3 ++- src/nvim/highlight_group.c | 18 +++++++++--------- src/nvim/input.c | 2 +- src/nvim/insexpand.c | 8 ++++---- src/nvim/mapping.c | 8 ++++---- src/nvim/mark.c | 6 +++--- src/nvim/memline.c | 2 +- src/nvim/menu.c | 4 ++-- src/nvim/message.c | 36 ++++++++++++++++++------------------ src/nvim/ops.c | 2 +- src/nvim/option.c | 4 ++-- src/nvim/quickfix.c | 8 ++++---- src/nvim/search.c | 8 ++++---- src/nvim/sign.c | 2 +- src/nvim/statusline.c | 6 +++--- src/nvim/syntax.c | 6 +++--- src/nvim/tag.c | 14 +++++++------- src/nvim/ui.c | 4 ++-- src/nvim/undo.c | 2 +- src/nvim/usercmd.c | 4 ++-- 35 files changed, 113 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ee05ad28ac..998f911392 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2161,11 +2161,11 @@ Dict nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena, if (num_id) { stc_hl_id = num_id; } else if (statuscol.use_cul) { - stc_hl_id = HLF_CLN + 1; + stc_hl_id = HLF_CLN; } else if (wp->w_p_rnu) { - stc_hl_id = (lnum < wp->w_cursor.lnum ? HLF_LNA : HLF_LNB) + 1; + stc_hl_id = (lnum < wp->w_cursor.lnum ? HLF_LNA : HLF_LNB); } else { - stc_hl_id = HLF_N + 1; + stc_hl_id = HLF_N; } set_vim_var_nr(VV_LNUM, lnum); diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index a62ff6d8ec..c08ef7a4c1 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -220,14 +220,14 @@ static void au_show_for_event(int group, event_T event, const char *pat) // show the group name, if it's not the default group if (ac->pat->group != AUGROUP_DEFAULT) { if (last_group_name == NULL) { - msg_puts_hl(get_deleted_augroup(), HLF_E + 1, false); + msg_puts_hl(get_deleted_augroup(), HLF_E, false); } else { - msg_puts_hl(last_group_name, HLF_T + 1, false); + msg_puts_hl(last_group_name, HLF_T, false); } msg_puts(" "); } // show the event name - msg_puts_hl(event_nr2name(event), HLF_T + 1, false); + msg_puts_hl(event_nr2name(event), HLF_T, false); } // Show pattern only if it changed. @@ -260,7 +260,7 @@ static void au_show_for_event(int group, event_T event, const char *pat) size_t msglen = 100; char *msg = xmallocz(msglen); if (ac->exec.type == CALLABLE_CB) { - msg_puts_hl(exec_to_string, HLF_8 + 1, false); + msg_puts_hl(exec_to_string, HLF_8, false); snprintf(msg, msglen, " [%s]", ac->desc); } else { snprintf(msg, msglen, "%s [%s]", exec_to_string, ac->desc); @@ -268,7 +268,7 @@ static void au_show_for_event(int group, event_T event, const char *pat) msg_outtrans(msg, 0, false); XFREE_CLEAR(msg); } else if (ac->exec.type == CALLABLE_CB) { - msg_puts_hl(exec_to_string, HLF_8 + 1, false); + msg_puts_hl(exec_to_string, HLF_8, false); } else { msg_outtrans(exec_to_string, 0, false); } diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 2752ef5c59..5f830b4219 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -350,7 +350,7 @@ static int check_mtime(buf_T *buf, FileInfo *file_info) msg_scroll = true; // Don't overwrite messages here. msg_silent = 0; // Must give this prompt. // Don't use emsg() here, don't want to flush the buffers. - msg(_("WARNING: The file has been changed since reading it!!!"), HLF_E + 1); + msg(_("WARNING: The file has been changed since reading it!!!"), HLF_E); if (ask_yesno(_("Do you really want to write to it"), true) == 'n') { return FAIL; } @@ -1881,7 +1881,7 @@ nofail: retval = FAIL; if (end == 0) { - const int hl_id = HLF_E + 1; // Set highlight for error messages. + const int hl_id = HLF_E; // Set highlight for error messages. msg_puts_hl(_("\nWARNING: Original file may be lost or damaged\n"), hl_id, true); msg_puts_hl(_("don't quit the editor until the file is successfully written!"), hl_id, true); diff --git a/src/nvim/change.c b/src/nvim/change.c index 3d78b17f2a..f3a8e0b208 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -89,9 +89,9 @@ void change_warning(buf_T *buf, int col) if (msg_row == Rows - 1) { msg_col = col; } - msg_source(HLF_W + 1); + msg_source(HLF_W); msg_ext_set_kind("wmsg"); - msg_puts_hl(_(w_readonly), HLF_W + 1, true); + msg_puts_hl(_(w_readonly), HLF_W, true); set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1); msg_clr_eos(); msg_end(); diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index b64e4f3ab6..700d554821 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -986,12 +986,12 @@ static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, in int lastlen = 999; for (int j = linenr; j < numMatches; j += lines) { if (xp->xp_context == EXPAND_TAGS_LISTFILES) { - msg_outtrans(matches[j], HLF_D + 1, false); + msg_outtrans(matches[j], HLF_D, false); p = matches[j] + strlen(matches[j]) + 1; msg_advance(maxlen + 1); msg_puts(p); msg_advance(maxlen + 3); - msg_outtrans_long(p + 2, HLF_D + 1); + msg_outtrans_long(p + 2, HLF_D); break; } for (int i = maxlen - lastlen; --i >= 0;) { @@ -1028,7 +1028,7 @@ static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, in isdir = false; p = SHOW_MATCH(j); } - lastlen = msg_outtrans(p, isdir ? HLF_D + 1 : 0, false); + lastlen = msg_outtrans(p, isdir ? HLF_D : 0, false); } if (msg_col > 0) { // when not wrapped around msg_clr_eos(); @@ -1119,10 +1119,10 @@ int showmatches(expand_T *xp, bool wildmenu) } if (xp->xp_context == EXPAND_TAGS_LISTFILES) { - msg_puts_hl(_("tagname"), HLF_T + 1, false); + msg_puts_hl(_("tagname"), HLF_T, false); msg_clr_eos(); msg_advance(maxlen - 3); - msg_puts_hl(_(" kind file\n"), HLF_T + 1, false); + msg_puts_hl(_(" kind file\n"), HLF_T, false); } // list the files line by line diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 97b47a5ee7..ea0d1ba708 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1707,7 +1707,7 @@ static void digraph_header(const char *msg) if (msg_col > 0) { msg_putchar('\n'); } - msg_outtrans(msg, HLF_CM + 1, false); + msg_outtrans(msg, HLF_CM, false); msg_putchar('\n'); } @@ -1871,7 +1871,7 @@ static void printdigraph(const digr_T *dp, result_T *previous) p += utf_char2bytes(dp->result, p); *p = NUL; - msg_outtrans(buf, HLF_8 + 1, false); + msg_outtrans(buf, HLF_8, false); p = buf; if (char2cells(dp->result) == 1) { *p++ = ' '; diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index b5e2f4461b..e90a0d945f 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -952,7 +952,7 @@ int showmode(void) // Position on the last line in the window, column 0 msg_pos_mode(); - int hl_id = HLF_CM + 1; // Highlight mode + int hl_id = HLF_CM; // Highlight mode // When the screen is too narrow to show the entire mode message, // avoid scrolling and truncate instead. @@ -987,7 +987,7 @@ int showmode(void) } if (edit_submode_extra != NULL) { msg_puts_hl(" ", hl_id, false); // Add a space in between. - int sub_id = edit_submode_highl < HLF_COUNT ? (int)edit_submode_highl + 1 : hl_id; + int sub_id = edit_submode_highl < HLF_COUNT ? (int)edit_submode_highl : hl_id; msg_puts_hl(edit_submode_extra, sub_id, false); } } @@ -1133,7 +1133,7 @@ void clearmode(void) msg_ext_ui_flush(); msg_pos_mode(); if (reg_recording != 0) { - recording_mode(HLF_CM + 1); + recording_mode(HLF_CM); } msg_clr_eos(); msg_ext_flush_showmode(); diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8f676d7906..4828d67428 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1342,7 +1342,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) hlID = HLF_CHD; // Changed line. } } - rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (hlID + 1); + rettv->vval.v_number = hlID; } /// "empty({expr})" function diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a143dc6e49..e937961b44 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3805,7 +3805,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n msg_no_more = true; msg_ext_set_kind("confirm_sub"); // Same highlight as wait_return(). - smsg(HLF_R + 1, _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); + smsg(HLF_R, _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); msg_no_more = false; msg_scroll = i; if (!ui_has(kUIMessages)) { diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 0ff4282884..e37c37e8e6 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -450,7 +450,7 @@ int buf_write_all(buf_T *buf, bool forceit) 1, buf->b_ml.ml_line_count, NULL, false, forceit, true, false)); if (curbuf != old_curbuf) { - msg_source(HLF_W + 1); + msg_source(HLF_W); msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"), 0); } return retval; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index cdf977fce2..e8b9470391 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5501,7 +5501,7 @@ static void ex_tabs(exarg_T *eap) msg_putchar('\n'); vim_snprintf(IObuff, IOSIZE, _("Tab page %d"), tabcount++); - msg_outtrans(IObuff, HLF_T + 1, false); + msg_outtrans(IObuff, HLF_T, false); os_breakcheck(); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -7776,7 +7776,7 @@ void verify_command(char *cmd) if (strcmp("smile", cmd) != 0) { return; // acceptable non-existing command } - int a = HLF_E + 1; + int a = HLF_E; msg(" #xxn` #xnxx` ,+x@##@Mz;` .xxx" "xxxxxxnz+, znnnnnnnnnnnnnnnn.", a); msg(" n###z x####` :x##########W+` ,###" diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index dd107cd3bf..ace62ea729 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -811,7 +811,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); msg_scroll = true; - msg_puts_hl(err.msg, HLF_E + 1, true); + msg_puts_hl(err.msg, HLF_E, true); api_clear_error(&err); redrawcmd(); } @@ -2660,7 +2660,7 @@ static void do_autocmd_cmdlinechanged(int firstc) if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); msg_scroll = true; - msg_puts_hl(err.msg, HLF_E + 1, true); + msg_puts_hl(err.msg, HLF_E, true); api_clear_error(&err); redrawcmd(); } @@ -3141,7 +3141,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) #define PRINT_ERRMSG(...) \ do { \ msg_putchar('\n'); \ - msg_printf_hl(HLF_E + 1, __VA_ARGS__); \ + msg_printf_hl(HLF_E, __VA_ARGS__); \ printed_errmsg = true; \ } while (0) bool ret = true; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 7c53150c11..fc7fabc009 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3035,9 +3035,9 @@ int buf_check_timestamp(buf_T *buf) } else { if (!autocmd_busy) { msg_start(); - msg_puts_hl(tbuf, HLF_E + 1, true); + msg_puts_hl(tbuf, HLF_E, true); if (*mesg2 != NUL) { - msg_puts_hl(mesg2, HLF_W + 1, true); + msg_puts_hl(mesg2, HLF_W, true); } msg_clr_eos(); msg_end(); diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index d39ffcd177..5f0a2e0e4e 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -48,7 +48,7 @@ static Set(cstr_t) urls = SET_INIT; /// highlight entries private to a namespace static Map(ColorKey, ColorItem) ns_hls; -typedef int NSHlAttr[HLF_COUNT + 1]; +typedef int NSHlAttr[HLF_COUNT]; static PMap(int) ns_hl_attr; void highlight_init(void) @@ -371,8 +371,8 @@ void update_window_hl(win_T *wp, bool invalid) bool float_win = wp->w_floating && !wp->w_config.external; if (float_win && hl_def[HLF_NFLOAT] != 0 && ns_id > 0) { wp->w_hl_attr_normal = hl_def[HLF_NFLOAT]; - } else if (hl_def[HLF_COUNT] > 0) { - wp->w_hl_attr_normal = hl_def[HLF_COUNT]; + } else if (hl_def[HLF_NONE] > 0) { + wp->w_hl_attr_normal = hl_def[HLF_NONE]; } else if (float_win) { wp->w_hl_attr_normal = HL_ATTR(HLF_NFLOAT) > 0 ? HL_ATTR(HLF_NFLOAT) : highlight_attr[HLF_NFLOAT]; @@ -433,7 +433,7 @@ void update_ns_hl(int ns_id) } int *hl_attrs = **alloc; - for (int hlf = 0; hlf < HLF_COUNT; hlf++) { + for (int hlf = 1; hlf < HLF_COUNT; hlf++) { int id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf])); bool optional = (hlf == HLF_INACTIVE || hlf == HLF_NFLOAT); hl_attrs[hlf] = hl_get_ui_attr(ns_id, hlf, id, optional); @@ -444,7 +444,7 @@ void update_ns_hl(int ns_id) // // haha, tema engine go brrr int normality = syn_check_group(S_LEN("Normal")); - hl_attrs[HLF_COUNT] = hl_get_ui_attr(ns_id, -1, normality, true); + hl_attrs[HLF_NONE] = hl_get_ui_attr(ns_id, -1, normality, true); // hl_get_ui_attr might have invalidated the decor provider p = get_decor_provider(ns_id, true); @@ -461,7 +461,7 @@ int win_bg_attr(win_T *wp) } if (wp == curwin || hl_attr_active[HLF_INACTIVE] == 0) { - return hl_attr_active[HLF_COUNT]; + return hl_attr_active[HLF_NONE]; } else { return hl_attr_active[HLF_INACTIVE]; } diff --git a/src/nvim/highlight.h b/src/nvim/highlight.h index 2ba6cf5371..1be70100de 100644 --- a/src/nvim/highlight.h +++ b/src/nvim/highlight.h @@ -84,7 +84,7 @@ EXTERN const char *hlf_names[] INIT( = { [HLF_TSNC] = "StatusLineTermNC", }); -EXTERN int highlight_attr[HLF_COUNT + 1]; // Highl. attr for each context. +EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context. EXTERN int highlight_attr_last[HLF_COUNT]; // copy for detecting changed groups EXTERN int highlight_user[9]; // User[1-9] attributes EXTERN int highlight_stlnc[9]; // On top of user diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index e0cce81166..a3c4062714 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -58,7 +58,8 @@ typedef struct { /// Values for index in highlight_attr[]. /// When making changes, also update hlf_names in highlight.h! typedef enum { - HLF_8 = 0, ///< Meta & special keys listed with ":map", text that is + HLF_NONE = 0, ///< no UI highlight active + HLF_8, ///< Meta & special keys listed with ":map", text that is ///< displayed different from what it is HLF_EOB, ///< after the last line in the buffer HLF_TERM, ///< terminal cursor focused diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 33d0c81e15..65641f120f 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1621,7 +1621,7 @@ static void highlight_list_one(const int id) if (sgp->sg_link && !got_int) { syn_list_header(didh, 0, id, true); didh = true; - msg_puts_hl("links to", HLF_D + 1, false); + msg_puts_hl("links to", HLF_D, false); msg_putchar(' '); msg_outtrans(hl_table[hl_table[id - 1].sg_link - 1].sg_name, 0, false); } @@ -1751,8 +1751,8 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg didh = true; if (!got_int) { if (*name != NUL) { - msg_puts_hl(name, HLF_D + 1, false); - msg_puts_hl("=", HLF_D + 1, false); + msg_puts_hl(name, HLF_D, false); + msg_puts_hl("=", HLF_D, false); } msg_outtrans(ts, 0, false); } @@ -2047,7 +2047,7 @@ static int syn_add_group(const char *name, size_t len) return 0; } else if (!ASCII_ISALNUM(c) && c != '_' && c != '.' && c != '@' && c != '-') { // '.' and '@' are allowed characters for use with treesitter capture names. - msg_source(HLF_W + 1); + msg_source(HLF_W); emsg(_(e_highlight_group_name_invalid_char)); return 0; } @@ -2246,8 +2246,11 @@ void highlight_changed(void) need_highlight_changed = false; + // sentinel value. used when no highlight is active + highlight_attr[HLF_NONE] = 0; + /// Translate builtin highlight groups into attributes for quick lookup. - for (int hlf = 0; hlf < HLF_COUNT; hlf++) { + for (int hlf = 1; hlf < HLF_COUNT; hlf++) { int id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf])); if (id == 0) { abort(); @@ -2275,9 +2278,6 @@ void highlight_changed(void) } } - // sentinel value. used when no highlight namespace is active - highlight_attr[HLF_COUNT] = 0; - // Setup the user highlights // // Temporarily utilize 10 more hl entries: @@ -2361,7 +2361,7 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg) static void highlight_list(void) { for (int i = 10; --i >= 0;) { - highlight_list_two(i, HLF_D + 1); + highlight_list_two(i, HLF_D); } for (int i = 40; --i >= 0;) { highlight_list_two(99, 0); diff --git a/src/nvim/input.c b/src/nvim/input.c index 3f531e2b73..3d3240c59f 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -55,7 +55,7 @@ int ask_yesno(const char *const str, const bool direct) int r = ' '; while (r != 'y' && r != 'n') { // same highlighting as for wait_return() - smsg(HLF_R + 1, "%s (y/n)?", str); + smsg(HLF_R, "%s (y/n)?", str); if (direct) { r = get_keystroke(NULL); } else { diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 9efcc2263a..bd7ee55722 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -473,7 +473,7 @@ bool check_compl_option(bool dict_opt) ctrl_x_mode = CTRL_X_NORMAL; edit_submode = NULL; msg((dict_opt ? _("'dictionary' option is empty") : _("'thesaurus' option is empty")), - HLF_E + 1); + HLF_E); if (emsg_silent == 0 && !in_assert_fails) { vim_beep(BO_COMPL); setcursor(); @@ -1564,7 +1564,7 @@ static void ins_compl_files(int count, char **files, bool thesaurus, int flags, msg_hist_off = true; // reset in msg_trunc() vim_snprintf(IObuff, IOSIZE, _("Scanning dictionary: %s"), files[i]); - msg_trunc(IObuff, true, HLF_R + 1); + msg_trunc(IObuff, true, HLF_R); } if (fp == NULL) { @@ -3046,7 +3046,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar : st->ins_buf->b_sfname == NULL ? st->ins_buf->b_fname : st->ins_buf->b_sfname); - msg_trunc(IObuff, true, HLF_R + 1); + msg_trunc(IObuff, true, HLF_R); } } else if (*st->e_cpt == NUL) { status = INS_COMPL_CPT_END; @@ -3074,7 +3074,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar if (!shortmess(SHM_COMPLETIONSCAN)) { msg_hist_off = true; // reset in msg_trunc() vim_snprintf(IObuff, IOSIZE, "%s", _("Scanning tags.")); - msg_trunc(IObuff, true, HLF_R + 1); + msg_trunc(IObuff, true, HLF_R); } } diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 0e83ae6fab..1a6b2c3581 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -239,9 +239,9 @@ static void showmap(mapblock_T *mp, bool local) } while (len < 12); if (mp->m_noremap == REMAP_NONE) { - msg_puts_hl("*", HLF_8 + 1, false); + msg_puts_hl("*", HLF_8, false); } else if (mp->m_noremap == REMAP_SCRIPT) { - msg_puts_hl("&", HLF_8 + 1, false); + msg_puts_hl("&", HLF_8, false); } else { msg_putchar(' '); } @@ -256,10 +256,10 @@ static void showmap(mapblock_T *mp, bool local) // the rhs, and not M-x etc, true gets both -- webb if (mp->m_luaref != LUA_NOREF) { char *str = nlua_funcref_str(mp->m_luaref, NULL); - msg_puts_hl(str, HLF_8 + 1, false); + msg_puts_hl(str, HLF_8, false); xfree(str); } else if (mp->m_str[0] == NUL) { - msg_puts_hl("", HLF_8 + 1, false); + msg_puts_hl("", HLF_8, false); } else { msg_outtrans_special(mp->m_str, false, 0); } diff --git a/src/nvim/mark.c b/src/nvim/mark.c index b118e614f3..3dbcbbd47b 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -959,7 +959,7 @@ static void show_one_mark(int c, char *arg, pos_T *p, char *name_arg, int curren snprintf(IObuff, IOSIZE, " %c %6" PRIdLINENR " %4d ", c, p->lnum, p->col); msg_outtrans(IObuff, 0, false); if (name != NULL) { - msg_outtrans(name, current ? HLF_D + 1 : 0, false); + msg_outtrans(name, current ? HLF_D : 0, false); } } } @@ -1083,7 +1083,7 @@ void ex_jumps(exarg_T *eap) i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx : curwin->w_jumplistidx - i, curwin->w_jumplist[i].fmark.mark.lnum, curwin->w_jumplist[i].fmark.mark.col); msg_outtrans(IObuff, 0, false); - msg_outtrans(name, curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum ? HLF_D + 1 : 0, false); + msg_outtrans(name, curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum ? HLF_D : 0, false); xfree(name); os_breakcheck(); } @@ -1120,7 +1120,7 @@ void ex_changes(exarg_T *eap) curbuf->b_changelist[i].mark.col); msg_outtrans(IObuff, 0, false); char *name = mark_line(&curbuf->b_changelist[i].mark, 17); - msg_outtrans(name, HLF_D + 1, false); + msg_outtrans(name, HLF_D, false); xfree(name); os_breakcheck(); } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 560d3cb167..bfe90bb680 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -852,7 +852,7 @@ void ml_recover(bool checkext) // be set to the real value below. mfp->mf_page_size = MIN_SWAP_PAGE_SIZE; - int hl_id = HLF_E + 1; + int hl_id = HLF_E; // try to read block 0 if ((hp = mf_get(mfp, 0, 1)) == NULL) { msg_start(); diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 77166e0733..4d3058ee44 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -808,7 +808,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) msg_puts(" "); } // Same highlighting as for directories!? - msg_outtrans(menu->name, HLF_D + 1, false); + msg_outtrans(menu->name, HLF_D, false); } if (menu != NULL && menu->children == NULL) { @@ -841,7 +841,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) } msg_puts(" "); if (*menu->strings[bit] == NUL) { - msg_puts_hl("", HLF_8 + 1, false); + msg_puts_hl("", HLF_8, false); } else { msg_outtrans_special(menu->strings[bit], false, 0); } diff --git a/src/nvim/message.c b/src/nvim/message.c index 4e06a050c9..e8ba2a9aeb 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -609,7 +609,7 @@ void msg_source(int hl_id) } p = get_emsg_lnum(); if (p != NULL) { - msg(p, HLF_N + 1); + msg(p, HLF_N); xfree(p); last_sourcing_lnum = SOURCING_LNUM; // only once for each line } @@ -738,7 +738,7 @@ bool emsg_multiline(const char *s, bool multiline) } emsg_on_display = true; // remember there is an error message - int hl_id = HLF_E + 1; // set highlight mode for error messages + int hl_id = HLF_E; // set highlight mode for error messages if (msg_scrolled != 0) { need_wait_return = true; // needed in case emsg() is called after } // wait_return() has reset need_wait_return @@ -1342,7 +1342,7 @@ static void hit_return_msg(bool newline_sb) msg_puts(_("Interrupt: ")); } - msg_puts_hl(_("Press ENTER or type command to continue"), HLF_R + 1, false); + msg_puts_hl(_("Press ENTER or type command to continue"), HLF_R, false); if (!msg_use_printf()) { msg_clr_eos(); } @@ -1587,7 +1587,7 @@ int msg_outtrans_len(const char *msgstr, int len, int hl_id, bool hist) msg_puts_len(plain_start, str - plain_start, hl_id, hist); } plain_start = str + mb_l; - msg_puts_hl(transchar_buf(NULL, c), hl_id == 0 ? HLF_8 + 1 : hl_id, false); + msg_puts_hl(transchar_buf(NULL, c), hl_id == 0 ? HLF_8 : hl_id, false); retval += char2cells(c); } len -= mb_l - 1; @@ -1601,7 +1601,7 @@ int msg_outtrans_len(const char *msgstr, int len, int hl_id, bool hist) msg_puts_len(plain_start, str - plain_start, hl_id, hist); } plain_start = str + 1; - msg_puts_hl(s, hl_id == 0 ? HLF_8 + 1 : hl_id, false); + msg_puts_hl(s, hl_id == 0 ? HLF_8 : hl_id, false); retval += (int)strlen(s); } else { retval++; @@ -1662,7 +1662,7 @@ int msg_outtrans_special(const char *strstart, bool from, int maxlen) } const char *str = strstart; int retval = 0; - int hl_id = HLF_8 + 1; + int hl_id = HLF_8; while (*str != NUL) { const char *text; @@ -1938,13 +1938,13 @@ void msg_prt_line(const char *s, bool list) : curwin->w_p_lcs_chars.tab1; sc_extra = curwin->w_p_lcs_chars.tab2; sc_final = curwin->w_p_lcs_chars.tab3; - hl_id = HLF_0 + 1; + hl_id = HLF_0; } } else if (c == NUL && list && curwin->w_p_lcs_chars.eol != NUL) { p_extra = ""; n_extra = 1; sc = curwin->w_p_lcs_chars.eol; - hl_id = HLF_AT + 1; + hl_id = HLF_AT; s--; } else if (c != NUL && (n = byte2cells(c)) > 1) { n_extra = n - 1; @@ -1952,7 +1952,7 @@ void msg_prt_line(const char *s, bool list) sc = schar_from_ascii(*p_extra++); // Use special coloring to be able to distinguish from // the same in plain text. - hl_id = HLF_0 + 1; + hl_id = HLF_0; } else if (c == ' ') { if (lead != NULL && s <= lead && in_multispace && curwin->w_p_lcs_chars.leadmultispace != NULL) { @@ -1960,23 +1960,23 @@ void msg_prt_line(const char *s, bool list) if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) { multispace_pos = 0; } - hl_id = HLF_0 + 1; + hl_id = HLF_0; } else if (lead != NULL && s <= lead && curwin->w_p_lcs_chars.lead != NUL) { sc = curwin->w_p_lcs_chars.lead; - hl_id = HLF_0 + 1; + hl_id = HLF_0; } else if (trail != NULL && s > trail) { sc = curwin->w_p_lcs_chars.trail; - hl_id = HLF_0 + 1; + hl_id = HLF_0; } else if (in_multispace && curwin->w_p_lcs_chars.multispace != NULL) { sc = curwin->w_p_lcs_chars.multispace[multispace_pos++]; if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) { multispace_pos = 0; } - hl_id = HLF_0 + 1; + hl_id = HLF_0; } else if (list && curwin->w_p_lcs_chars.space != NUL) { sc = curwin->w_p_lcs_chars.space; - hl_id = HLF_0 + 1; + hl_id = HLF_0; } else { sc = schar_from_ascii(' '); // SPACE! } @@ -2007,7 +2007,7 @@ void msg_puts(const char *s) void msg_puts_title(const char *s) { - msg_puts_hl(s, HLF_T + 1, false); + msg_puts_hl(s, HLF_T, false); } /// Show a message in such a way that it always fits in the line. Cut out a @@ -2021,7 +2021,7 @@ void msg_outtrans_long(const char *longstr, int hl_id) if (len > room && room >= 20) { slen = (room - 3) / 2; msg_outtrans_len(longstr, slen, hl_id, false); - msg_puts_hl("...", HLF_8 + 1, false); + msg_puts_hl("...", HLF_8, false); } msg_outtrans_len(longstr + len - slen, slen, hl_id, len); } @@ -3316,7 +3316,7 @@ void give_warning(const char *message, bool hl) set_vim_var_string(VV_WARNINGMSG, message, -1); XFREE_CLEAR(keep_msg); if (hl) { - keep_msg_hl_id = HLF_W + 1; + keep_msg_hl_id = HLF_W; } else { keep_msg_hl_id = 0; } @@ -3659,7 +3659,7 @@ void display_confirm_msg(void) confirm_msg_used++; if (confirm_msg != NULL) { msg_ext_set_kind("confirm"); - msg_puts_hl(confirm_msg, HLF_M + 1, false); + msg_puts_hl(confirm_msg, HLF_M, false); } confirm_msg_used--; } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 6bc2ce237b..c100bc36b4 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -3653,7 +3653,7 @@ void ex_display(exarg_T *eap) if (arg != NULL && *arg == NUL) { arg = NULL; } - int hl_id = HLF_8 + 1; + int hl_id = HLF_8; // Highlight title msg_puts_title(_("\nType Name Content")); diff --git a/src/nvim/option.c b/src/nvim/option.c index 25e9fa471d..03b7c8cb14 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1901,8 +1901,8 @@ static const char *did_set_arabic(optset_T *args) if (strcmp(p_enc, "utf-8") != 0) { static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"); - msg_source(HLF_W + 1); - msg(_(w_arabic), HLF_W + 1); + msg_source(HLF_W); + msg(_(w_arabic), HLF_W); set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1); } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 304b72ce12..6526b0d0bf 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -3195,7 +3195,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) } msg_putchar('\n'); - msg_outtrans(IObuff, cursel ? HLF_QFL + 1 : qfFile_hl_id, false); + msg_outtrans(IObuff, cursel ? HLF_QFL : qfFile_hl_id, false); if (qfp->qf_lnum != 0) { msg_puts_hl(":", qfSep_hl_id, false); @@ -3277,15 +3277,15 @@ void qf_list(exarg_T *eap) // that this depends on syntax items defined in the qf.vim syntax file qfFile_hl_id = syn_name2id("qfFileName"); if (qfFile_hl_id == 0) { - qfFile_hl_id = HLF_D + 1; + qfFile_hl_id = HLF_D; } qfSep_hl_id = syn_name2id("qfSeparator"); if (qfSep_hl_id == 0) { - qfSep_hl_id = HLF_D + 1; + qfSep_hl_id = HLF_D; } qfLine_hl_id = syn_name2id("qfLineNr"); if (qfLine_hl_id == 0) { - qfLine_hl_id = HLF_N + 1; + qfLine_hl_id = HLF_N; } if (qfl->qf_nonevalid) { diff --git a/src/nvim/search.c b/src/nvim/search.c index bfa90ba24a..debc5697d1 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3772,7 +3772,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool if (new_fname != NULL) { // using "new_fname" is more reliable, e.g., when // 'includeexpr' is set. - msg_outtrans(new_fname, HLF_D + 1, false); + msg_outtrans(new_fname, HLF_D, false); } else { // Isolate the file name. // Include the surrounding "" or <> if present. @@ -3806,7 +3806,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool } char save_char = p[i]; p[i] = NUL; - msg_outtrans(p, HLF_D + 1, false); + msg_outtrans(p, HLF_D, false); p[i] = save_char; } @@ -3858,7 +3858,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool vim_snprintf(IObuff, IOSIZE, _("Scanning included file: %s"), new_fname); - msg_trunc(IObuff, true, HLF_R + 1); + msg_trunc(IObuff, true, HLF_R); } else if (p_verbose >= 5) { verbose_enter(); smsg(0, _("Searching included file %s"), new_fname); @@ -4233,7 +4233,7 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI msg_puts(IObuff); snprintf(IObuff, IOSIZE, "%4" PRIdLINENR, *lnum); // Show line nr. // Highlight line numbers. - msg_puts_hl(IObuff, HLF_N + 1, false); + msg_puts_hl(IObuff, HLF_N, false); msg_puts(" "); } msg_prt_line(line, false); diff --git a/src/nvim/sign.c b/src/nvim/sign.c index ec342d8b50..f8e7eeaca4 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -270,7 +270,7 @@ static void sign_list_placed(buf_T *rbuf, char *group) while (buf != NULL && !got_int) { if (buf_has_signs(buf)) { vim_snprintf(lbuf, MSG_BUF_LEN, _("Signs for %s:"), buf->b_fname); - msg_puts_hl(lbuf, HLF_D + 1, false); + msg_puts_hl(lbuf, HLF_D, false); msg_putchar('\n'); } diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index d9ac1aa347..ba64633df7 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -585,7 +585,7 @@ void win_redr_ruler(win_T *wp) MAXSIZE_TEMP_ARRAY(chunk, 3); ADD_C(chunk, INTEGER_OBJ(attr)); ADD_C(chunk, CSTR_AS_OBJ(buffer)); - ADD_C(chunk, INTEGER_OBJ(HLF_MSG + 1)); + ADD_C(chunk, INTEGER_OBJ(HLF_MSG)); assert(attr == HL_ATTR(HLF_MSG)); ADD_C(content, ARRAY_OBJ(chunk)); ui_call_msg_ruler(content); @@ -1632,7 +1632,7 @@ stcsign: schar_T fold_buf[9]; fill_foldcolumn(wp, stcp->foldinfo, (linenr_T)get_vim_var_nr(VV_LNUM), 0, fdc, NULL, fold_buf); - stl_items[curitem].minwid = -((stcp->use_cul ? HLF_CLF : HLF_FC) + 1); + stl_items[curitem].minwid = -(stcp->use_cul ? HLF_CLF : HLF_FC); size_t buflen = 0; // TODO(bfredl): this is very backwards. we must support schar_T // being used directly in 'statuscolumn' @@ -1653,7 +1653,7 @@ stcsign: buf_tmp[signlen++] = ' '; buf_tmp[signlen++] = ' '; buf_tmp[signlen] = NUL; - stl_items[curitem].minwid = -((stcp->use_cul ? HLF_CLS : HLF_SC) + 1); + stl_items[curitem].minwid = -(stcp->use_cul ? HLF_CLS : HLF_SC); } } stl_items[curitem++].type = Highlight; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 13bc2f0d50..03f20047a5 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -3346,7 +3346,7 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) KEYVALUE_ENTRY(HL_SKIPEMPTY, "skipempty"), }; - const int hl_id = HLF_D + 1; // highlight like directories + const int hl_id = HLF_D; // highlight like directories // list the keywords for "id" if (!syncing) { @@ -3451,9 +3451,9 @@ static void syn_list_cluster(int id) msg_advance(endcol); if (SYN_CLSTR(curwin->w_s)[id].scl_list != NULL) { - put_id_list("cluster", SYN_CLSTR(curwin->w_s)[id].scl_list, HLF_D + 1); + put_id_list("cluster", SYN_CLSTR(curwin->w_s)[id].scl_list, HLF_D); } else { - msg_puts_hl("cluster", HLF_D + 1, false); + msg_puts_hl("cluster", HLF_D, false); msg_puts("=NONE"); } } diff --git a/src/nvim/tag.c b/src/nvim/tag.c index d721d06e4f..3e0bb32391 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -736,7 +736,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) } if ((num_matches > prev_num_matches || new_tag) && num_matches > 1) { - msg(IObuff, ic ? HLF_W + 1 : 0); + msg(IObuff, ic ? HLF_W : 0); msg_scroll = true; // Don't overwrite this message. } else { give_warning(IObuff, ic); @@ -815,10 +815,10 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha msg_didout = false; // overwrite previous message } msg_start(); - msg_puts_hl(_(" # pri kind tag"), HLF_T + 1, false); + msg_puts_hl(_(" # pri kind tag"), HLF_T, false); msg_clr_eos(); taglen_advance(taglen); - msg_puts_hl(_("file\n"), HLF_T + 1, false); + msg_puts_hl(_("file\n"), HLF_T, false); for (int i = 0; i < num_matches && !got_int; i++) { parse_match(matches[i], &tagp); @@ -839,7 +839,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha msg_outtrans_len(tagp.tagkind, (int)(tagp.tagkind_end - tagp.tagkind), 0, false); } msg_advance(13); - msg_outtrans_len(tagp.tagname, (int)(tagp.tagname_end - tagp.tagname), HLF_T + 1, false); + msg_outtrans_len(tagp.tagname, (int)(tagp.tagname_end - tagp.tagname), HLF_T, false); msg_putchar(' '); taglen_advance(taglen); @@ -847,7 +847,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha // it and put "..." in the middle const char *p = tag_full_fname(&tagp); if (p != NULL) { - msg_outtrans(p, HLF_D + 1, false); + msg_outtrans(p, HLF_D, false); XFREE_CLEAR(p); } if (msg_col > 0) { @@ -880,7 +880,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha continue; } // print all other extra fields - int hl_id = HLF_CM + 1; + int hl_id = HLF_CM; while (*p && *p != '\r' && *p != '\n') { if (msg_col + ptr2cells(p) >= Columns) { msg_putchar('\n'); @@ -1126,7 +1126,7 @@ void do_tags(exarg_T *eap) tagstack[i].tagname, tagstack[i].fmark.mark.lnum); msg_outtrans(IObuff, 0, false); - msg_outtrans(name, tagstack[i].fmark.fnum == curbuf->b_fnum ? HLF_D + 1 : 0, false); + msg_outtrans(name, tagstack[i].fmark.fnum == curbuf->b_fnum ? HLF_D : 0, false); xfree(name); } } diff --git a/src/nvim/ui.c b/src/nvim/ui.c index bd3679f708..560f76d0bd 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -358,8 +358,8 @@ void vim_beep(unsigned val) // a script or executing a function give the user a hint where the beep // comes from. if (vim_strchr(p_debug, 'e') != NULL) { - msg_source(HLF_W + 1); - msg(_("Beep!"), HLF_W + 1); + msg_source(HLF_W); + msg(_("Beep!"), HLF_W); } } diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 52581bea36..0f8857a6bd 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2712,7 +2712,7 @@ void ex_undolist(exarg_T *eap) sort_strings(ga.ga_data, ga.ga_len); msg_start(); - msg_puts_hl(_("number changes when saved"), HLF_T + 1, false); + msg_puts_hl(_("number changes when saved"), HLF_T, false); for (int i = 0; i < ga.ga_len && !got_int; i++) { msg_putchar('\n'); if (got_int) { diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 904dc4bfe8..d27899b10f 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -494,7 +494,7 @@ static void uc_list(char *name, size_t name_len) msg_putchar(' '); } - msg_outtrans(cmd->uc_name, HLF_D + 1, false); + msg_outtrans(cmd->uc_name, HLF_D, false); len = strlen(cmd->uc_name) + 4; do { @@ -585,7 +585,7 @@ static void uc_list(char *name, size_t name_len) if (cmd->uc_luaref != LUA_NOREF) { char *fn = nlua_funcref_str(cmd->uc_luaref, NULL); - msg_puts_hl(fn, HLF_8 + 1, false); + msg_puts_hl(fn, HLF_8, false); xfree(fn); // put the description on a new line if (*cmd->uc_rep != NUL) { -- cgit From 36990f324de2cfb96a6d2450e9c3ddfc3fba8afa Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Fri, 8 Nov 2024 11:42:09 -0800 Subject: fix(treesitter): show proper node name error messages **Problem:** Currently node names with non-alphanumeric, non underscore/hyphen characters (only possible with anonymous nodes) are not given a proper error message. See tree-sitter issue 3892 for more details. **Solution:** Apply a different scanning logic to anonymous nodes to correctly identify the entire node name (i.e., up until the final double quote) --- src/nvim/lua/treesitter.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 9ea55dbd0c..c80e7b7672 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -1528,10 +1528,25 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err || error_type == TSQueryErrorField || error_type == TSQueryErrorCapture) { const char *suffix = src + error_offset; + bool is_anonymous = error_type == TSQueryErrorNodeType && suffix[-1] == '"'; int suffix_len = 0; char c = suffix[suffix_len]; - while (isalnum(c) || c == '_' || c == '-' || c == '.') { - c = suffix[++suffix_len]; + if (is_anonymous) { + int backslashes = 0; + // Stop when we hit an unescaped double quote + while (c != '"' || backslashes % 2 != 0) { + if (c == '\\') { + backslashes += 1; + } else { + backslashes = 0; + } + c = suffix[++suffix_len]; + } + } else { + // Stop when we hit the end of the identifier + while (isalnum(c) || c == '_' || c == '-' || c == '.') { + c = suffix[++suffix_len]; + } } snprintf(err, errlen, "\"%.*s\":\n", suffix_len, suffix); offset = strlen(err); -- cgit From de48fbbd5f8800bd7f1909a6fb41e53e871cf74c Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Thu, 20 Jun 2024 14:48:06 +0200 Subject: fix(messages)!: vim.ui_attach message callbacks are unsafe Problem: Lua callbacks for "msg_show" events with vim.ui_attach() are executed when it is not safe. Solution: Disallow non-fast API calls for "msg_show" event callbacks. Automatically detach callback after excessive errors. Make sure fast APIs do not modify Nvim state. --- src/nvim/api/ui_events.in.h | 2 +- src/nvim/api/vim.c | 8 +++-- src/nvim/errors.h | 2 +- src/nvim/eval.c | 2 +- src/nvim/generators/gen_api_dispatch.lua | 2 +- src/nvim/generators/gen_api_ui_events.lua | 4 +-- src/nvim/lua/executor.c | 39 ++++++++++++++++-------- src/nvim/ui.c | 49 ++++++++++++++++++------------- src/nvim/ui.h | 4 ++- 9 files changed, 69 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 865e84ab91..0ed208fc1a 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -159,7 +159,7 @@ void wildmenu_hide(void) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void msg_show(String kind, Array content, Boolean replace_last) - FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(6) FUNC_API_FAST FUNC_API_REMOTE_ONLY; void msg_clear(void) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; void msg_showcmd(Array content) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 998f911392..e6ec88c5e8 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -594,10 +594,12 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Arena *arena, Er kvi_init(cookie.rv); int flags = DIP_DIRFILE | (all ? DIP_ALL : 0); + TryState tstate; + + try_enter(&tstate); + do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie); + vim_ignored = try_leave(&tstate, err); - TRY_WRAP(err, { - do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie); - }); return arena_take_arraybuilder(arena, &cookie.rv); } diff --git a/src/nvim/errors.h b/src/nvim/errors.h index 7897a71489..df94945a3d 100644 --- a/src/nvim/errors.h +++ b/src/nvim/errors.h @@ -151,7 +151,7 @@ EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to ab EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); -EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); +EXTERN const char e_fast_api_disabled[] INIT(= N_("E5560: %s must not be called in a fast event context")); EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1fb7666167..9acbc05fdf 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8616,7 +8616,7 @@ bool eval_has_provider(const char *feat, bool throw_if_fast) } if (throw_if_fast && !nlua_is_deferred_safe()) { - semsg(e_luv_api_disabled, "Vimscript function"); + semsg(e_fast_api_disabled, "Vimscript function"); return false; } diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 9e0aa407a1..a78f746fee 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -750,7 +750,7 @@ local function process_function(fn) write_shifted_output( [[ if (!nlua_is_deferred_safe()) { - return luaL_error(lstate, e_luv_api_disabled, "%s"); + return luaL_error(lstate, e_fast_api_disabled, "%s"); } ]], fn.name diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua index 3e8ae19c9a..30a83330eb 100644 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -136,8 +136,8 @@ for i = 1, #events do call_output:write(' }\n') call_output:write(' entered = true;\n') write_arglist(call_output, ev) - call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n') - call_output:write(' entered = false;\n') + call_output:write((' ui_call_event("%s", %s, %s)'):format(ev.name, tostring(ev.fast), args)) + call_output:write(';\n entered = false;\n') elseif ev.compositor_impl then call_output:write(' ui_comp_' .. ev.name) write_signature(call_output, ev, '', true) diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index e4da274204..15f70fb725 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -187,7 +187,7 @@ static void nlua_luv_error_event(void **argv) msg_ext_set_kind("lua_error"); switch (type) { case kCallback: - semsg_multiline("Error executing luv callback:\n%s", error); + semsg_multiline("Error executing callback:\n%s", error); break; case kThread: semsg_multiline("Error in luv thread:\n%s", error); @@ -201,13 +201,13 @@ static void nlua_luv_error_event(void **argv) xfree(error); } -static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags) +/// Execute callback in "fast" context. Used for luv and some vim.ui_event +/// callbacks where using the API directly is not safe. +static int nlua_fast_cfpcall(lua_State *lstate, int nargs, int nresult, int flags) FUNC_ATTR_NONNULL_ALL { int retval; - // luv callbacks might be executed at any os_breakcheck/line_breakcheck - // call, so using the API directly here is not safe. in_fast_callback++; int top = lua_gettop(lstate); @@ -366,11 +366,13 @@ static int nlua_init_argv(lua_State *const L, char **argv, int argc, int lua_arg static void nlua_schedule_event(void **argv) { LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; + uint32_t ns_id = (uint32_t)(ptrdiff_t)argv[1]; lua_State *const lstate = global_lstate; nlua_pushref(lstate, cb); nlua_unref_global(lstate, cb); if (nlua_pcall(lstate, 0, 0)) { nlua_error(lstate, _("Error executing vim.schedule lua callback: %.*s")); + ui_remove_cb(ns_id, true); } } @@ -392,8 +394,9 @@ static int nlua_schedule(lua_State *const lstate) } LuaRef cb = nlua_ref_global(lstate, 1); - - multiqueue_put(main_loop.events, nlua_schedule_event, (void *)(ptrdiff_t)cb); + // Pass along UI event handler to disable on error. + multiqueue_put(main_loop.events, nlua_schedule_event, (void *)(ptrdiff_t)cb, + (void *)(ptrdiff_t)ui_event_ns_id); return 0; } @@ -425,7 +428,7 @@ static int nlua_wait(lua_State *lstate) FUNC_ATTR_NONNULL_ALL { if (in_fast_callback) { - return luaL_error(lstate, e_luv_api_disabled, "vim.wait"); + return luaL_error(lstate, e_fast_api_disabled, "vim.wait"); } intptr_t timeout = luaL_checkinteger(lstate, 1); @@ -598,7 +601,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_stan luv_set_cthread(lstate, nlua_luv_thread_cfcpcall); } else { luv_set_loop(lstate, &main_loop.uv); - luv_set_callback(lstate, nlua_luv_cfpcall); + luv_set_callback(lstate, nlua_fast_cfpcall); } luaopen_luv(lstate); lua_pushvalue(lstate, -1); @@ -724,7 +727,7 @@ static int nlua_ui_detach(lua_State *lstate) return luaL_error(lstate, "invalid ns_id"); } - ui_remove_cb(ns_id); + ui_remove_cb(ns_id, false); return 0; } @@ -1174,7 +1177,7 @@ int nlua_call(lua_State *lstate) size_t name_len; const char *name = luaL_checklstring(lstate, 1, &name_len); if (!nlua_is_deferred_safe() && !viml_func_is_fast(name)) { - return luaL_error(lstate, e_luv_api_disabled, "Vimscript function"); + return luaL_error(lstate, e_fast_api_disabled, "Vimscript function"); } int nargs = lua_gettop(lstate) - 1; @@ -1231,7 +1234,7 @@ free_vim_args: static int nlua_rpcrequest(lua_State *lstate) { if (!nlua_is_deferred_safe()) { - return luaL_error(lstate, e_luv_api_disabled, "rpcrequest"); + return luaL_error(lstate, e_fast_api_disabled, "rpcrequest"); } return nlua_rpc(lstate, true); } @@ -1593,6 +1596,12 @@ bool nlua_ref_is_function(LuaRef ref) /// @return Return value of function, as per mode Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode, Arena *arena, Error *err) +{ + return nlua_call_ref_ctx(false, ref, name, args, mode, arena, err); +} + +Object nlua_call_ref_ctx(bool fast, LuaRef ref, const char *name, Array args, LuaRetMode mode, + Arena *arena, Error *err) { lua_State *const lstate = global_lstate; nlua_pushref(lstate, ref); @@ -1605,7 +1614,13 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode, nlua_push_Object(lstate, &args.items[i], 0); } - if (nlua_pcall(lstate, nargs, 1)) { + if (fast) { + if (nlua_fast_cfpcall(lstate, nargs, 1, -1) < 0) { + // error is already scheduled, set anyways to convey failure. + api_set_error(err, kErrorTypeException, "fast context failure"); + } + return NIL; + } else if (nlua_pcall(lstate, nargs, 1)) { // if err is passed, the caller will deal with the error. if (err) { size_t len; diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 560f76d0bd..d50747e63f 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -44,6 +44,7 @@ typedef struct { LuaRef cb; + uint8_t errors; bool ext_widgets[kUIGlobalCount]; } UIEventCallback; @@ -212,21 +213,20 @@ void ui_refresh(void) cursor_row = cursor_col = 0; pending_cursor_update = true; + bool had_message = ui_ext[kUIMessages]; for (UIExtension i = 0; (int)i < kUIExtCount; i++) { + ui_ext[i] = ext_widgets[i] | ui_cb_ext[i]; if (i < kUIGlobalCount) { - ext_widgets[i] |= ui_cb_ext[i]; + ui_call_option_set(cstr_as_string(ui_ext_names[i]), BOOLEAN_OBJ(ui_ext[i])); } - // Set 'cmdheight' to zero for all tabpages when ext_messages becomes active. - if (i == kUIMessages && !ui_ext[i] && ext_widgets[i]) { - set_option_value(kOptCmdheight, NUMBER_OPTVAL(0), 0); - command_height(); - FOR_ALL_TABS(tp) { - tp->tp_ch_used = 0; - } - } - ui_ext[i] = ext_widgets[i]; - if (i < kUIGlobalCount) { - ui_call_option_set(cstr_as_string(ui_ext_names[i]), BOOLEAN_OBJ(ext_widgets[i])); + } + + // Reset 'cmdheight' for all tabpages when ext_messages toggles. + if (had_message != ui_ext[kUIMessages]) { + set_option_value(kOptCmdheight, NUMBER_OPTVAL(had_message), 0); + command_height(); + FOR_ALL_TABS(tp) { + tp->tp_ch_used = had_message; } } @@ -713,13 +713,15 @@ void ui_grid_resize(handle_T grid_handle, int width, int height, Error *err) } } -void ui_call_event(char *name, Array args) +void ui_call_event(char *name, bool fast, Array args) { - UIEventCallback *event_cb; bool handled = false; - map_foreach_value(&ui_event_cbs, event_cb, { + UIEventCallback *event_cb; + map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, { Error err = ERROR_INIT; - Object res = nlua_call_ref(event_cb->cb, name, args, kRetNilBool, NULL, &err); + uint32_t ns_id = ui_event_ns_id; + Object res = nlua_call_ref_ctx(fast, event_cb->cb, name, args, kRetNilBool, NULL, &err); + ui_event_ns_id = 0; // TODO(bfredl/luukvbaal): should this be documented or reconsidered? // Why does truthy return from Lua callback mean remote UI should not receive // the event. @@ -728,6 +730,7 @@ void ui_call_event(char *name, Array args) } if (ERROR_SET(&err)) { ELOG("Error executing UI event callback: %s", err.msg); + ui_remove_cb(ns_id, true); } api_clear_error(&err); }) @@ -780,12 +783,16 @@ void ui_add_cb(uint32_t ns_id, LuaRef cb, bool *ext_widgets) ui_refresh(); } -void ui_remove_cb(uint32_t ns_id) +void ui_remove_cb(uint32_t ns_id, bool checkerr) { - if (map_has(uint32_t, &ui_event_cbs, ns_id)) { - UIEventCallback *item = pmap_del(uint32_t)(&ui_event_cbs, ns_id, NULL); + UIEventCallback *item = pmap_get(uint32_t)(&ui_event_cbs, ns_id); + if (item && (!checkerr || ++item->errors > 10)) { + pmap_del(uint32_t)(&ui_event_cbs, ns_id, NULL); free_ui_event_callback(item); + ui_cb_update_ext(); + ui_refresh(); + if (checkerr) { + msg_schedule_semsg("Excessive errors in vim.ui_attach() callback from ns: %d.", ns_id); + } } - ui_cb_update_ext(); - ui_refresh(); } diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 8718c7b506..4aeb8ffda9 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -18,4 +18,6 @@ EXTERN Array noargs INIT(= ARRAY_DICT_INIT); #endif // uncrustify:on -EXTERN MultiQueue *resize_events; +// vim.ui_attach() namespace of currently executed callback. +EXTERN uint32_t ui_event_ns_id INIT( = 0); +EXTERN MultiQueue *resize_events INIT( = NULL); -- cgit From fa0dcde3d9f17f85baa9dd41aa751c123281ced3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 15 Nov 2024 08:04:49 +0800 Subject: vim-patch:9.1.0864: message history is fixed to 200 (#31215) Problem: message history is fixed to 200 Solution: Add the 'msghistory' option, increase the default value to 500 (Shougo Matsushita) closes: vim/vim#16048 https://github.com/vim/vim/commit/4bd9b2b2467e696061104a029000e9824c6c609e Co-authored-by: Shougo Matsushita Co-authored-by: Milly --- src/nvim/message.c | 2 +- src/nvim/option.c | 7 +++++++ src/nvim/option_vars.h | 1 + src/nvim/options.lua | 16 +++++++++++++++- src/nvim/vim_defs.h | 1 - 5 files changed, 24 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/message.c b/src/nvim/message.c index e8ba2a9aeb..e8f20916b8 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -981,7 +981,7 @@ static void add_msg_hist_multihl(const char *s, int len, int hl_id, bool multili } // Don't let the message history get too big - while (msg_hist_len > MAX_MSG_HIST_LEN) { + while (msg_hist_len > p_mhi) { delete_first_msg(); } diff --git a/src/nvim/option.c b/src/nvim/option.c index 03b7c8cb14..efd52f9233 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2874,6 +2874,13 @@ static const char *validate_num_option(OptIndex opt_idx, OptInt *newval, char *e return e_invarg; } break; + case kOptMsghistory: + if (value < 0) { + return e_positive; + } else if (value > 10000) { + return e_invarg; + } + break; case kOptPyxversion: if (value == 0) { *newval = 3; diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index a60bd047c1..e0a972f06c 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -536,6 +536,7 @@ EXTERN OptInt p_mousescroll_vert INIT( = MOUSESCROLL_VERT_DFLT); EXTERN OptInt p_mousescroll_hor INIT( = MOUSESCROLL_HOR_DFLT); EXTERN OptInt p_mouset; ///< 'mousetime' EXTERN int p_more; ///< 'more' +EXTERN OptInt p_mhi; ///< 'msghistory' EXTERN char *p_nf; ///< 'nrformats' EXTERN char *p_opfunc; ///< 'operatorfunc' EXTERN char *p_para; ///< 'paragraphs' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index e648d4350a..6fab0621f9 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -3962,7 +3962,8 @@ return { desc = [=[ A history of ":" commands, and a history of previous search patterns is remembered. This option decides how many entries may be stored in - each of these histories (see |cmdline-editing|). + each of these histories (see |cmdline-editing| and 'msghistory' for + the number of messages to remember). The maximum value is 10000. ]=], full_name = 'history', @@ -5757,6 +5758,19 @@ return { type = 'number', varname = 'p_mouset', }, + { + abbreviation = 'mhi', + defaults = { if_true = 500 }, + desc = [=[ + Determines how many entries are remembered in the |:messages| history. + The maximum value is 10000. + ]=], + full_name = 'msghistory', + scope = { 'global' }, + short_desc = N_('how many messages are remembered'), + type = 'number', + varname = 'p_mhi', + }, { abbreviation = 'nf', cb = 'did_set_nrformats', diff --git a/src/nvim/vim_defs.h b/src/nvim/vim_defs.h index f6b348e009..72aaa77533 100644 --- a/src/nvim/vim_defs.h +++ b/src/nvim/vim_defs.h @@ -2,7 +2,6 @@ // Some defines from the old feature.h #define SESSION_FILE "Session.vim" -#define MAX_MSG_HIST_LEN 200 #define SYS_OPTWIN_FILE "$VIMRUNTIME/optwin.vim" #define RUNTIME_DIRNAME "runtime" -- cgit From 54c85bcb6d55ae7fa749e9998b67ebbcda58f4b9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 15 Nov 2024 08:18:53 +0800 Subject: vim-patch:9.1.0855: setting 'cmdheight' may missing output (#31216) Problem: setting 'cmdheight' may cause hit-enter-prompt and echo output to be missing Solution: Before cleaning the cmdline, check the need_wait_return flag (nwounkn) closes: vim/vim#13432 https://github.com/vim/vim/commit/2e48567007f2becd484a3c3dd0706bf3a0beeae7 Co-authored-by: nwounkn --- src/nvim/window.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/window.c b/src/nvim/window.c index 5147bbd23b..5f17d3220d 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6814,11 +6814,13 @@ void command_height(void) // Recompute window positions. win_comp_pos(); - // clear the lines added to cmdline - if (full_screen) { - grid_clear(&default_grid, cmdline_row, Rows, 0, Columns, 0); + if (!need_wait_return) { + // clear the lines added to cmdline + if (full_screen) { + grid_clear(&default_grid, cmdline_row, Rows, 0, Columns, 0); + } + msg_row = cmdline_row; } - msg_row = cmdline_row; redraw_cmdline = true; return; } -- cgit From 6e4df18b457e9743c34068fd6e0a89fd04d3526c Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Fri, 15 Nov 2024 23:34:42 +0100 Subject: fix(ui): no fast context for prompt message kinds #31224 Problem: No longer able to show prompt messages with vim.ui_attach(). Solution: Do not execute callback in fast context for prompt message kinds. These events must be safe to show the incoming message so the event itself serves to indicate that the message should be shown immediately. --- src/nvim/ui.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/nvim/ui.c b/src/nvim/ui.c index d50747e63f..7c81110ae9 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -717,6 +717,13 @@ void ui_call_event(char *name, bool fast, Array args) { bool handled = false; UIEventCallback *event_cb; + + // Prompt messages should be shown immediately so must be safe + if (strcmp(name, "msg_show") == 0) { + char *kind = args.items[0].data.string.data; + fast = !kind || (strncmp(kind, "confirm", 7) != 0 && strcmp(kind, "return_prompt") != 0); + } + map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, { Error err = ERROR_INIT; uint32_t ns_id = ui_event_ns_id; -- cgit From 2f7b0018b0354447497e8496fa3745773df2f218 Mon Sep 17 00:00:00 2001 From: errael Date: Fri, 15 Nov 2024 17:37:36 -0800 Subject: docs: standardize doc for ChanInfo/ChanOpen autocmds/v:event (#31099) --- src/nvim/vvars.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index 4936f62e3e..5fc014a50c 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -171,6 +171,7 @@ M.vars = { an aborting condition (e.g. |c_Esc| or |c_CTRL-C| for |CmdlineLeave|). chan |channel-id| + info Dict of arbitrary event data. cmdlevel Level of cmdline. cmdtype Type of cmdline, |cmdline-char|. cwd Current working directory. -- cgit From f164e1e35c4144baa55dda1120be6c75fb250c4b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 16 Nov 2024 09:55:41 +0800 Subject: vim-patch:partial:9.1.0851: too many strlen() calls in getchar.c (#31230) Problem: too many strlen() calls in getchar.c Solution: refactor code and reduce strlen() calls (John Marriott) closes: vim/vim#16017 https://github.com/vim/vim/commit/e7a1bbf2102ecd2083613ff18d7d46c45d1e568e Co-authored-by: John Marriott --- src/nvim/getchar.c | 78 +++++++++++++++++++++++++++++-------------------- src/nvim/getchar_defs.h | 2 ++ 2 files changed, 49 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index c346bce0b7..82abd2888a 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -95,15 +95,15 @@ static FileDescriptor scriptin[NSCRIPT] = { 0 }; #define MINIMAL_SIZE 20 // minimal size for b_str -static buffheader_T redobuff = { { NULL, { NUL } }, NULL, 0, 0 }; -static buffheader_T old_redobuff = { { NULL, { NUL } }, NULL, 0, 0 }; -static buffheader_T recordbuff = { { NULL, { NUL } }, NULL, 0, 0 }; +static buffheader_T redobuff = { { NULL, 0, { NUL } }, NULL, 0, 0, false }; +static buffheader_T old_redobuff = { { NULL, 0, { NUL } }, NULL, 0, 0, false }; +static buffheader_T recordbuff = { { NULL, 0, { NUL } }, NULL, 0, 0, false }; /// First read ahead buffer. Used for translated commands. -static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 }; +static buffheader_T readbuf1 = { { NULL, 0, { NUL } }, NULL, 0, 0, false }; /// Second read ahead buffer. Used for redo. -static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 }; +static buffheader_T readbuf2 = { { NULL, 0, { NUL } }, NULL, 0, 0, false }; /// Buffer used to store typed characters for vim.on_key(). static kvec_withinit_t(char, MAXMAPLEN + 1) on_key_buf = KVI_INITIAL_VALUE(on_key_buf); @@ -183,15 +183,17 @@ static void free_buff(buffheader_T *buf) /// K_SPECIAL in the returned string is escaped. /// /// @param dozero count == zero is not an error -static char *get_buffcont(buffheader_T *buffer, int dozero) +/// @param len the length of the returned buffer +static char *get_buffcont(buffheader_T *buffer, int dozero, size_t *len) { size_t count = 0; char *p = NULL; + size_t i = 0; // compute the total length of the string for (const buffblock_T *bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) { - count += strlen(bp->b_str); + count += bp->b_strlen; } if (count > 0 || dozero) { @@ -204,7 +206,13 @@ static char *get_buffcont(buffheader_T *buffer, int dozero) } } *p2 = NUL; + i = (size_t)(p2 - p); } + + if (len != NULL) { + *len = i; + } + return p; } @@ -213,12 +221,12 @@ static char *get_buffcont(buffheader_T *buffer, int dozero) /// K_SPECIAL in the returned string is escaped. char *get_recorded(void) { - char *p = get_buffcont(&recordbuff, true); + size_t len; + char *p = get_buffcont(&recordbuff, true, &len); free_buff(&recordbuff); // Remove the characters that were added the last time, these must be the // (possibly mapped) characters that stopped the recording. - size_t len = strlen(p); if (len >= last_recorded_len) { len -= last_recorded_len; p[len] = NUL; @@ -237,7 +245,7 @@ char *get_recorded(void) /// K_SPECIAL in the returned string is escaped. char *get_inserted(void) { - return get_buffcont(&redobuff, false); + return get_buffcont(&redobuff, false, NULL); } /// Add string after the current block of the given buffer @@ -257,27 +265,31 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } if (buf->bh_first.b_next == NULL) { // first add to list - buf->bh_space = 0; buf->bh_curr = &(buf->bh_first); + buf->bh_create_newblock = true; } else if (buf->bh_curr == NULL) { // buffer has already been read iemsg(_("E222: Add to read buffer")); return; } else if (buf->bh_index != 0) { memmove(buf->bh_first.b_next->b_str, buf->bh_first.b_next->b_str + buf->bh_index, - strlen(buf->bh_first.b_next->b_str + buf->bh_index) + 1); + (buf->bh_first.b_next->b_strlen - buf->bh_index) + 1); + buf->bh_first.b_next->b_strlen -= buf->bh_index; + buf->bh_space += buf->bh_index; } buf->bh_index = 0; - if (buf->bh_space >= (size_t)slen) { - size_t len = strlen(buf->bh_curr->b_str); - xmemcpyz(buf->bh_curr->b_str + len, s, (size_t)slen); + if (!buf->bh_create_newblock && buf->bh_space >= (size_t)slen) { + xmemcpyz(buf->bh_curr->b_str + buf->bh_curr->b_strlen, s, (size_t)slen); + buf->bh_curr->b_strlen += (size_t)slen; buf->bh_space -= (size_t)slen; } else { size_t len = MAX(MINIMAL_SIZE, (size_t)slen); buffblock_T *p = xmalloc(offsetof(buffblock_T, b_str) + len + 1); - buf->bh_space = len - (size_t)slen; xmemcpyz(p->b_str, s, (size_t)slen); + p->b_strlen = (size_t)slen; + buf->bh_space = len - (size_t)slen; + buf->bh_create_newblock = false; p->b_next = buf->bh_curr->b_next; buf->bh_curr->b_next = p; @@ -292,12 +304,12 @@ static void delete_buff_tail(buffheader_T *buf, int slen) if (buf->bh_curr == NULL) { return; // nothing to delete } - int len = (int)strlen(buf->bh_curr->b_str); - if (len < slen) { + if (buf->bh_curr->b_strlen < (size_t)slen) { return; } - buf->bh_curr->b_str[len - slen] = NUL; + buf->bh_curr->b_str[buf->bh_curr->b_strlen - (size_t)slen] = NUL; + buf->bh_curr->b_strlen -= (size_t)slen; buf->bh_space += (size_t)slen; } @@ -305,8 +317,8 @@ static void delete_buff_tail(buffheader_T *buf, int slen) static void add_num_buff(buffheader_T *buf, int n) { char number[32]; - snprintf(number, sizeof(number), "%d", n); - add_buff(buf, number, -1); + int numberlen = snprintf(number, sizeof(number), "%d", n); + add_buff(buf, number, numberlen); } /// Add byte or special key 'c' to buffer "buf". @@ -314,17 +326,20 @@ static void add_num_buff(buffheader_T *buf, int n) static void add_byte_buff(buffheader_T *buf, int c) { char temp[4]; + ptrdiff_t templen; if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) { // Translate special key code into three byte sequence. temp[0] = (char)K_SPECIAL; temp[1] = (char)K_SECOND(c); temp[2] = (char)K_THIRD(c); temp[3] = NUL; + templen = 3; } else { temp[0] = (char)c; temp[1] = NUL; + templen = 1; } - add_buff(buf, temp, -1); + add_buff(buf, temp, templen); } /// Add character 'c' to buffer "buf". @@ -385,11 +400,11 @@ static void start_stuff(void) { if (readbuf1.bh_first.b_next != NULL) { readbuf1.bh_curr = &(readbuf1.bh_first); - readbuf1.bh_space = 0; + readbuf1.bh_create_newblock = true; // force a new block to be created (see add_buff()) } if (readbuf2.bh_first.b_next != NULL) { readbuf2.bh_curr = &(readbuf2.bh_first); - readbuf2.bh_space = 0; + readbuf2.bh_create_newblock = true; // force a new block to be created (see add_buff()) } } @@ -498,12 +513,13 @@ void saveRedobuff(save_redo_T *save_redo) old_redobuff.bh_first.b_next = NULL; // Make a copy, so that ":normal ." in a function works. - char *const s = get_buffcont(&save_redo->sr_redobuff, false); + size_t slen; + char *const s = get_buffcont(&save_redo->sr_redobuff, false, &slen); if (s == NULL) { return; } - add_buff(&redobuff, s, -1); + add_buff(&redobuff, s, (ptrdiff_t)slen); xfree(s); } @@ -1921,9 +1937,9 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) i += utf_char2bytes((int)n, temp + i); } assert(i < 10); - temp[i++] = NUL; + temp[i] = NUL; rettv->v_type = VAR_STRING; - rettv->vval.v_string = xstrdup(temp); + rettv->vval.v_string = xmemdupz(temp, (size_t)i); if (is_mouse_key((int)n)) { int row = mouse_row; @@ -1976,9 +1992,9 @@ void f_getcharstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) i += utf_char2bytes((int)n, temp); } assert(i < 7); - temp[i++] = NUL; + temp[i] = NUL; rettv->v_type = VAR_STRING; - rettv->vval.v_string = xstrdup(temp); + rettv->vval.v_string = xmemdupz(temp, (size_t)i); } /// "getcharmod()" function @@ -2373,7 +2389,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) buf[1] = (char)KS_EXTRA; buf[2] = KE_IGNORE; buf[3] = NUL; - map_str = xstrdup(buf); + map_str = xmemdupz(buf, 3); if (State & MODE_CMDLINE) { // redraw the command below the error msg_didout = true; diff --git a/src/nvim/getchar_defs.h b/src/nvim/getchar_defs.h index abf812fad3..fdfd0a9942 100644 --- a/src/nvim/getchar_defs.h +++ b/src/nvim/getchar_defs.h @@ -9,6 +9,7 @@ /// structure used to store one block of the stuff/redo/recording buffers typedef struct buffblock { struct buffblock *b_next; ///< pointer to next buffblock + size_t b_strlen; ///< length of b_str, excluding the NUL char b_str[1]; ///< contents (actually longer) } buffblock_T; @@ -18,6 +19,7 @@ typedef struct { buffblock_T *bh_curr; ///< buffblock for appending size_t bh_index; ///< index for reading size_t bh_space; ///< space in bh_curr for appending + bool bh_create_newblock; ///< create a new block? } buffheader_T; typedef struct { -- cgit From be8648f345aed5e403251990721918c8302be760 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 15 Nov 2024 08:58:31 +0100 Subject: build(deps): bump uncrustify to uncrustify-0.80.0 --- src/uncrustify.cfg | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg index 50cee638af..a3b0c4a9a5 100644 --- a/src/uncrustify.cfg +++ b/src/uncrustify.cfg @@ -1,4 +1,4 @@ -# Uncrustify-0.79.0_f +# Uncrustify-0.80.0_f # # General options @@ -422,6 +422,10 @@ sp_invariant_paren = ignore # ignore/add/remove/force sp_after_invariant_paren = ignore # ignore/add/remove/force # Add or remove space before empty statement ';' on 'if', 'for' and 'while'. +# examples: +# if (b) ; +# for (a=1; a<10; a++) ; +# while (*p++ = ' ') ; sp_special_semi = ignore # ignore/add/remove/force # Add or remove space before ';'. @@ -1103,6 +1107,10 @@ sp_after_emb_cmt = force # ignore/add/remove/force # Default: 1 sp_num_after_emb_cmt = 1 # unsigned number +# Embedded comment spacing options have higher priority (== override) +# than other spacing options (comma, parenthesis, braces, ...) +sp_emb_cmt_priority = false # true/false + # (Java) Add or remove space between an annotation and the open parenthesis. sp_annotation_paren = ignore # ignore/add/remove/force @@ -1127,6 +1135,15 @@ force_tab_after_define = false # true/false # Add or remove space between two strings. sp_string_string = force # ignore/add/remove/force +# Add or remove space 'struct' and a type. +sp_struct_type = ignore # ignore/add/remove/force + +# Add or remove space between '_Pragma' and the opening paarenthesis +sp_pragma_open_parenthesis = ignore # ignore/add/remove/force + +# Add or remove space inside '(' and ')' of _Pragma. +sp_inside_gparen = ignore # ignore/add/remove/force + # # Indenting options # -- cgit From 29ded889579a9d590e8ea885a9a402ff4bae87be Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Sun, 17 Nov 2024 02:56:16 +0600 Subject: refactor(options): remove `.indir`, redesign option scopes #31066 Problem: The way option scopes currently work is inflexible and does not allow for nested option scopes or easily finding the value of an option at any arbitrary scope without having to do long handwritten switch-case statements like in `get_varp()`. `.indir` is also confusing and redundant since option indices for each scope can be autogenerated. Solution: Expand option scopes in such a way that an option can support any amount of scopes using a set of scope flags, similarly to how it's already done for option types. Also make options contain information about its index at each scope it supports. This allows for massively simplifying `get_varp()` and `get_varp_scope()` in the future by just using a struct for options at each scope. This would be done by creating a table that stores the offset of an option's variable at a scope by using the option's index at that scope as a key. This PR also autogenerates enums for option indices at each scope to remove the need for `.indir` entirely, and also to allow easily iterating over options all options that support any scope. Ref: #29314 --- src/nvim/CMakeLists.txt | 10 +- src/nvim/api/deprecated.c | 60 +-- src/nvim/api/options.c | 42 +- src/nvim/api/vim.c | 8 +- src/nvim/buffer_defs.h | 4 +- src/nvim/diff.c | 4 +- src/nvim/eval.c | 2 +- src/nvim/file_search.c | 2 +- src/nvim/fold.c | 2 +- src/nvim/generators/gen_options.lua | 219 +++++++-- src/nvim/generators/gen_options_enum.lua | 129 ----- src/nvim/indent.c | 2 +- src/nvim/option.c | 803 +++++++++++++++---------------- src/nvim/option.h | 57 --- src/nvim/option_defs.h | 41 +- src/nvim/options.lua | 287 ++++++----- src/nvim/textformat.c | 2 +- src/nvim/window.c | 4 +- src/nvim/winfloat.c | 4 +- 19 files changed, 795 insertions(+), 887 deletions(-) delete mode 100644 src/nvim/generators/gen_options_enum.lua (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index cb71144130..344b4bef00 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -308,7 +308,6 @@ set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua) set(GENERATOR_HASHY ${GENERATOR_DIR}/hashy.lua) set(GENERATOR_PRELOAD ${GENERATOR_DIR}/preload.lua) set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua) -set(OPTIONS_ENUM_GENERATOR ${GENERATOR_DIR}/gen_options_enum.lua) set(OPTIONS_GENERATOR ${GENERATOR_DIR}/gen_options.lua) # GENERATED_DIR and GENERATED_INCLUDES_DIR @@ -687,16 +686,11 @@ add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP} DEPENDS ${LUA_GEN_DEPS} ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua ) -add_custom_command(OUTPUT ${GENERATED_OPTIONS} - COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS} +add_custom_command(OUTPUT ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP} + COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP} DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua ) -add_custom_command(OUTPUT ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP} - COMMAND ${LUA_GEN} ${OPTIONS_ENUM_GENERATOR} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP} - DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_ENUM_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua -) - # NVIM_GENERATED_FOR_SOURCES and NVIM_GENERATED_FOR_HEADERS must be mutually exclusive. foreach(hfile ${NVIM_GENERATED_FOR_HEADERS}) list(FIND NVIM_GENERATED_FOR_SOURCES ${hfile} hfile_idx) diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index b3ba832fec..b38a7d4173 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -533,7 +533,7 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(11) { - set_option_to(channel_id, NULL, kOptReqGlobal, name, value, err); + set_option_to(channel_id, NULL, kOptScopeGlobal, name, value, err); } /// Gets the global value of an option. @@ -546,7 +546,7 @@ Object nvim_get_option(String name, Error *err) FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(11) { - return get_option_from(NULL, kOptReqGlobal, name, err); + return get_option_from(NULL, kOptScopeGlobal, name, err); } /// Gets a buffer option value @@ -566,7 +566,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err) return (Object)OBJECT_INIT; } - return get_option_from(buf, kOptReqBuf, name, err); + return get_option_from(buf, kOptScopeBuf, name, err); } /// Sets a buffer option value. Passing `nil` as value deletes the option (only @@ -588,7 +588,7 @@ void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object return; } - set_option_to(channel_id, buf, kOptReqBuf, name, value, err); + set_option_to(channel_id, buf, kOptScopeBuf, name, value, err); } /// Gets a window option value @@ -608,7 +608,7 @@ Object nvim_win_get_option(Window window, String name, Error *err) return (Object)OBJECT_INIT; } - return get_option_from(win, kOptReqWin, name, err); + return get_option_from(win, kOptScopeWin, name, err); } /// Sets a window option value. Passing `nil` as value deletes the option (only @@ -630,48 +630,18 @@ void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object return; } - set_option_to(channel_id, win, kOptReqWin, name, value, err); -} - -/// Check if option has a value in the requested scope. -/// -/// @param opt_idx Option index in options[] table. -/// @param req_scope Requested option scope. See OptReqScope in option.h. -/// -/// @return true if option has a value in the requested scope, false otherwise. -static bool option_has_scope(OptIndex opt_idx, OptReqScope req_scope) -{ - if (opt_idx == kOptInvalid) { - return false; - } - - vimoption_T *opt = get_option(opt_idx); - - // TTY option. - if (is_tty_option(opt->fullname)) { - return req_scope == kOptReqGlobal; - } - - switch (req_scope) { - case kOptReqGlobal: - return opt->var != VAR_WIN; - case kOptReqBuf: - return opt->indir & PV_BUF; - case kOptReqWin: - return opt->indir & PV_WIN; - } - UNREACHABLE; + set_option_to(channel_id, win, kOptScopeWin, name, value, err); } /// Gets the value of a global or local (buffer, window) option. /// /// @param[in] from Pointer to buffer or window for local option value. -/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param req_scope Requested option scope. See OptScope in option.h. /// @param name The option name. /// @param[out] err Details of an error that may have occurred. /// /// @return the option value. -static Object get_option_from(void *from, OptReqScope req_scope, String name, Error *err) +static Object get_option_from(void *from, OptScope req_scope, String name, Error *err) { VALIDATE_S(name.size > 0, "option name", "", { return (Object)OBJECT_INIT; @@ -681,7 +651,7 @@ static Object get_option_from(void *from, OptReqScope req_scope, String name, Er OptVal value = NIL_OPTVAL; if (option_has_scope(opt_idx, req_scope)) { - value = get_option_value_for(opt_idx, req_scope == kOptReqGlobal ? OPT_GLOBAL : OPT_LOCAL, + value = get_option_value_for(opt_idx, req_scope == kOptScopeGlobal ? OPT_GLOBAL : OPT_LOCAL, req_scope, from, err); if (ERROR_SET(err)) { return (Object)OBJECT_INIT; @@ -698,11 +668,11 @@ static Object get_option_from(void *from, OptReqScope req_scope, String name, Er /// Sets the value of a global or local (buffer, window) option. /// /// @param[in] to Pointer to buffer or window for local option value. -/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param req_scope Requested option scope. See OptScope in option.h. /// @param name The option name. /// @param value New option value. /// @param[out] err Details of an error that may have occurred. -static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, String name, +static void set_option_to(uint64_t channel_id, void *to, OptScope req_scope, String name, Object value, Error *err) { VALIDATE_S(name.size > 0, "option name", "", { @@ -725,12 +695,12 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, return; }); - int attrs = get_option_attrs(opt_idx); // For global-win-local options -> setlocal // For win-local options -> setglobal and setlocal (opt_flags == 0) - const int opt_flags = (req_scope == kOptReqWin && !(attrs & SOPT_GLOBAL)) - ? 0 - : (req_scope == kOptReqGlobal) ? OPT_GLOBAL : OPT_LOCAL; + const int opt_flags + = (req_scope == kOptScopeWin && !option_has_scope(opt_idx, kOptScopeGlobal)) + ? 0 + : ((req_scope == kOptScopeGlobal) ? OPT_GLOBAL : OPT_LOCAL); WITH_SCRIPT_CONTEXT(channel_id, { set_option_value_for(name.data, opt_idx, optval, opt_flags, req_scope, to, err); diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 96866d80ba..bbfd00f2ea 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -23,8 +23,8 @@ #endif static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *opt_idxp, - int *scope, OptReqScope *req_scope, void **from, - char **filetype, Error *err) + int *scope, OptScope *req_scope, void **from, char **filetype, + Error *err) { #define HAS_KEY_X(d, v) HAS_KEY(d, option, v) if (HAS_KEY_X(opts, scope)) { @@ -39,14 +39,14 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * } } - *req_scope = kOptReqGlobal; + *req_scope = kOptScopeGlobal; if (filetype != NULL && HAS_KEY_X(opts, filetype)) { *filetype = opts->filetype.data; } if (HAS_KEY_X(opts, win)) { - *req_scope = kOptReqWin; + *req_scope = kOptScopeWin; *from = find_window_by_handle(opts->win, err); if (ERROR_SET(err)) { return FAIL; @@ -59,7 +59,7 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * return FAIL; }); *scope = OPT_LOCAL; - *req_scope = kOptReqBuf; + *req_scope = kOptScopeBuf; *from = find_buffer_by_handle(opts->buf, err); if (ERROR_SET(err)) { return FAIL; @@ -78,18 +78,17 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * }); *opt_idxp = find_option(name); - int flags = get_option_attrs(*opt_idxp); - if (flags == 0) { + if (*opt_idxp == kOptInvalid) { // unknown option api_set_error(err, kErrorTypeValidation, "Unknown option '%s'", name); - } else if (*req_scope == kOptReqBuf || *req_scope == kOptReqWin) { + } else if (*req_scope == kOptScopeBuf || *req_scope == kOptScopeWin) { // if 'buf' or 'win' is passed, make sure the option supports it - int req_flags = *req_scope == kOptReqBuf ? SOPT_BUF : SOPT_WIN; - if (!(flags & req_flags)) { - char *tgt = *req_scope & kOptReqBuf ? "buf" : "win"; - char *global = flags & SOPT_GLOBAL ? "global " : ""; - char *req = flags & SOPT_BUF ? "buffer-local " - : flags & SOPT_WIN ? "window-local " : ""; + if (!option_has_scope(*opt_idxp, *req_scope)) { + char *tgt = *req_scope == kOptScopeBuf ? "buf" : "win"; + char *global = option_has_scope(*opt_idxp, kOptScopeGlobal) ? "global " : ""; + char *req = option_has_scope(*opt_idxp, kOptScopeBuf) + ? "buffer-local " + : (option_has_scope(*opt_idxp, kOptScopeWin) ? "window-local " : ""); api_set_error(err, kErrorTypeValidation, "'%s' cannot be passed for %s%soption '%s'", tgt, global, req, name); @@ -153,7 +152,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) { OptIndex opt_idx = 0; int scope = 0; - OptReqScope req_scope = kOptReqGlobal; + OptScope req_scope = kOptScopeGlobal; void *from = NULL; char *filetype = NULL; @@ -218,7 +217,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( { OptIndex opt_idx = 0; int scope = 0; - OptReqScope req_scope = kOptReqGlobal; + OptScope req_scope = kOptScopeGlobal; void *to = NULL; if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &to, NULL, err)) { return; @@ -230,9 +229,8 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( // - option is global or local to window (global-local) // // Then force scope to local since we don't want to change the global option - if (req_scope == kOptReqWin && scope == 0) { - int flags = get_option_attrs(opt_idx); - if (flags & SOPT_GLOBAL) { + if (req_scope == kOptScopeWin && scope == 0) { + if (option_has_scope(opt_idx, kOptScopeGlobal)) { scope = OPT_LOCAL; } } @@ -305,15 +303,15 @@ Dict nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, Error { OptIndex opt_idx = 0; int scope = 0; - OptReqScope req_scope = kOptReqGlobal; + OptScope req_scope = kOptScopeGlobal; void *from = NULL; if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &from, NULL, err)) { return (Dict)ARRAY_DICT_INIT; } - buf_T *buf = (req_scope == kOptReqBuf) ? (buf_T *)from : curbuf; - win_T *win = (req_scope == kOptReqWin) ? (win_T *)from : curwin; + buf_T *buf = (req_scope == kOptScopeBuf) ? (buf_T *)from : curbuf; + win_T *win = (req_scope == kOptScopeWin) ? (win_T *)from : curwin; return get_vimoption(name, scope, buf, win, arena, err); } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index e6ec88c5e8..199b9a9690 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1004,10 +1004,10 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); if (scratch) { - set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, kOptReqBuf, - buf); - set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, kOptReqBuf, - buf); + set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, + kOptScopeBuf, buf); + set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, + kOptScopeBuf, buf); assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already buf->b_p_swf = false; buf->b_p_ml = false; diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index e6bd63f4f8..d33734ccfe 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -206,7 +206,7 @@ typedef struct { OptInt wo_winbl; #define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend' - LastSet wo_script_ctx[WV_COUNT]; // SCTXs for window-local options + LastSet wo_script_ctx[kWinOptCount]; // SCTXs for window-local options #define w_p_script_ctx w_onebuf_opt.wo_script_ctx } winopt_T; @@ -512,7 +512,7 @@ struct file_buffer { // or contents of the file being edited. bool b_p_initialized; // set when options initialized - LastSet b_p_script_ctx[BV_COUNT]; // SCTXs for buffer-local options + LastSet b_p_script_ctx[kBufOptCount]; // SCTXs for buffer-local options int b_p_ai; ///< 'autoindent' int b_p_ai_nopaste; ///< b_p_ai saved for paste mode diff --git a/src/nvim/diff.c b/src/nvim/diff.c index a690c70875..f1dd08f0e6 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1390,8 +1390,8 @@ void diff_win_options(win_T *wp, bool addbuf) } wp->w_p_fdm_save = xstrdup(wp->w_p_fdm); } - set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0, kOptReqWin, - wp); + set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0, + kOptScopeWin, wp); if (!wp->w_p_diff) { wp->w_p_fen_save = wp->w_p_fen; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9acbc05fdf..ab6115f145 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1368,7 +1368,7 @@ int eval_foldexpr(win_T *wp, int *cp) const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL); char *arg = skipwhite(wp->w_p_fde); - current_sctx = wp->w_p_script_ctx[WV_FDE].script_ctx; + current_sctx = wp->w_p_script_ctx[kWinOptFoldexpr].script_ctx; emsg_off++; if (use_sandbox) { diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index aeaf448a05..d183978d2d 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1648,7 +1648,7 @@ static char *eval_includeexpr(const char *const ptr, const size_t len) { const sctx_T save_sctx = current_sctx; set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); - current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx; + current_sctx = curbuf->b_p_script_ctx[kBufOptIncludeexpr].script_ctx; char *res = eval_to_string_safe(curbuf->b_p_inex, was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL), diff --git a/src/nvim/fold.c b/src/nvim/fold.c index e7231c31ab..c9699cb161 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -1731,7 +1731,7 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo curwin = wp; curbuf = wp->w_buffer; - current_sctx = wp->w_p_script_ctx[WV_FDT].script_ctx; + current_sctx = wp->w_p_script_ctx[kWinOptFoldtext].script_ctx; emsg_off++; // handle exceptions, but don't display errors diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 92349b5298..02f3ac3257 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -1,6 +1,10 @@ local options_file = arg[1] +local options_enum_file = arg[2] +local options_map_file = arg[3] local opt_fd = assert(io.open(options_file, 'w')) +local opt_enum_fd = assert(io.open(options_enum_file, 'w')) +local opt_map_fd = assert(io.open(options_map_file, 'w')) local w = function(s) if s:match('^ %.') then @@ -10,10 +14,129 @@ local w = function(s) end end +--- @param s string +local function enum_w(s) + opt_enum_fd:write(s .. '\n') +end + +--- @param s string +local function map_w(s) + opt_map_fd:write(s .. '\n') +end + --- @module 'nvim.options' local options = require('options') +local options_meta = options.options local cstr = options.cstr +local valid_scopes = options.valid_scopes + +--- Options for each scope. +--- @type table +local scope_options = {} +for _, scope in ipairs(valid_scopes) do + scope_options[scope] = {} +end + +--- @param s string +--- @return string +local lowercase_to_titlecase = function(s) + return s:sub(1, 1):upper() .. s:sub(2) +end + +-- Generate options enum file +enum_w('// IWYU pragma: private, include "nvim/option_defs.h"') +enum_w('') + +--- Map of option name to option index +--- @type table +local option_index = {} + +-- Generate option index enum and populate the `option_index` and `scope_option` dicts. +enum_w('typedef enum {') +enum_w(' kOptInvalid = -1,') + +for i, o in ipairs(options_meta) do + local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name) + enum_w((' %s = %u,'):format(enum_val_name, i - 1)) + + option_index[o.full_name] = enum_val_name + + if o.abbreviation then + option_index[o.abbreviation] = enum_val_name + end + + if o.alias then + o.alias = type(o.alias) == 'string' and { o.alias } or o.alias + + for _, v in ipairs(o.alias) do + option_index[v] = enum_val_name + end + end + + for _, scope in ipairs(o.scope) do + table.insert(scope_options[scope], o) + end +end + +enum_w(' // Option count') +enum_w('#define kOptCount ' .. tostring(#options_meta)) +enum_w('} OptIndex;') + +--- @param scope string +--- @param option_name string +--- @return string +local get_scope_option = function(scope, option_name) + return ('k%sOpt%s'):format(lowercase_to_titlecase(scope), lowercase_to_titlecase(option_name)) +end + +-- Generate option index enum for each scope +for _, scope in ipairs(valid_scopes) do + enum_w('') + + local scope_name = lowercase_to_titlecase(scope) + enum_w('typedef enum {') + enum_w((' %s = -1,'):format(get_scope_option(scope, 'Invalid'))) + + for idx, option in ipairs(scope_options[scope]) do + enum_w((' %s = %u,'):format(get_scope_option(scope, option.full_name), idx - 1)) + end + + enum_w((' // %s option count'):format(scope_name)) + enum_w(('#define %s %d'):format(get_scope_option(scope, 'Count'), #scope_options[scope])) + enum_w(('} %sOptIndex;'):format(scope_name)) +end + +-- Generate reverse lookup from option scope index to option index for each scope. +for _, scope in ipairs(valid_scopes) do + enum_w('') + enum_w(('EXTERN const OptIndex %s_opt_idx[] INIT( = {'):format(scope)) + for _, option in ipairs(scope_options[scope]) do + local idx = option_index[option.full_name] + enum_w((' [%s] = %s,'):format(get_scope_option(scope, option.full_name), idx)) + end + enum_w('});') +end + +opt_enum_fd:close() + +-- Generate option index map. +local hashy = require('generators.hashy') +local neworder, hashfun = hashy.hashy_hash('find_option', vim.tbl_keys(option_index), function(idx) + return ('option_hash_elems[%s].name'):format(idx) +end) + +map_w('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {') + +for _, name in ipairs(neworder) do + assert(option_index[name] ~= nil) + map_w((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name])) +end + +map_w('};\n') +map_w('static ' .. hashfun) + +opt_map_fd:close() local redraw_flags = { ui_option = 'kOptFlagUIOption', @@ -35,12 +158,6 @@ local list_flags = { flagscomma = 'kOptFlagComma|kOptFlagFlagList', } ---- @param s string ---- @return string -local lowercase_to_titlecase = function(s) - return s:sub(1, 1):upper() .. s:sub(2) -end - --- @param o vim.option_meta --- @return string local function get_flags(o) @@ -95,6 +212,12 @@ local function opt_type_enum(opt_type) return ('kOptValType%s'):format(lowercase_to_titlecase(opt_type)) end +--- @param scope vim.option_scope +--- @return string +local function opt_scope_enum(scope) + return ('kOptScope%s'):format(lowercase_to_titlecase(scope)) +end + --- @param o vim.option_meta --- @return string local function get_type_flags(o) @@ -110,6 +233,35 @@ local function get_type_flags(o) return type_flags end +--- @param o vim.option_meta +--- @return string +local function get_scope_flags(o) + local scope_flags = '0' + + for _, scope in ipairs(o.scope) do + scope_flags = ('%s | (1 << %s)'):format(scope_flags, opt_scope_enum(scope)) + end + + return scope_flags +end + +--- @param o vim.option_meta +--- @return string +local function get_scope_idx(o) + --- @type string[] + local strs = {} + + for _, scope in pairs(valid_scopes) do + local has_scope = vim.tbl_contains(o.scope, scope) + strs[#strs + 1] = (' [%s] = %s'):format( + opt_scope_enum(scope), + get_scope_option(scope, has_scope and o.full_name or 'Invalid') + ) + end + + return ('{\n%s\n }'):format(table.concat(strs, ',\n')) +end + --- @param c string|string[] --- @param base_string? string --- @return string @@ -166,7 +318,6 @@ end --- @param d vim.option_value|function --- @param n string --- @return string - local get_defaults = function(d, n) if d == nil then error("option '" .. n .. "' should have a default value") @@ -174,9 +325,6 @@ local get_defaults = function(d, n) return get_opt_val(d) end ---- @type [string,string][] -local defines = {} - --- @param i integer --- @param o vim.option_meta local function dump_option(i, o) @@ -187,42 +335,28 @@ local function dump_option(i, o) end w(' .flags=' .. get_flags(o)) w(' .type_flags=' .. get_type_flags(o)) + w(' .scope_flags=' .. get_scope_flags(o)) + w(' .scope_idx=' .. get_scope_idx(o)) if o.enable_if then w(get_cond(o.enable_if)) end - if o.varname then - w(' .var=&' .. o.varname) - elseif o.immutable then - -- Immutable options can directly point to the default value. - w((' .var=&options[%u].def_val.data'):format(i - 1)) - elseif #o.scope == 1 and o.scope[1] == 'window' then - w(' .var=VAR_WIN') + local is_window_local = #o.scope == 1 and o.scope[1] == 'win' + + if not is_window_local then + if o.varname then + w(' .var=&' .. o.varname) + elseif o.immutable then + -- Immutable options can directly point to the default value. + w((' .var=&options[%u].def_val.data'):format(i - 1)) + else + -- Option must be immutable or have a variable. + assert(false) + end else - -- Option must be immutable or have a variable. - assert(false) + w(' .var=NULL') end w(' .immutable=' .. (o.immutable and 'true' or 'false')) - if #o.scope == 1 and o.scope[1] == 'global' then - w(' .indir=PV_NONE') - else - assert(#o.scope == 1 or #o.scope == 2) - assert(#o.scope == 1 or o.scope[1] == 'global') - local min_scope = o.scope[#o.scope] - local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name)) - local pv_name = ( - 'OPT_' - .. min_scope:sub(1, 3):upper() - .. '(' - .. (min_scope:sub(1, 1):upper() .. 'V_' .. varname:sub(3):upper()) - .. ')' - ) - if #o.scope == 2 then - pv_name = 'OPT_BOTH(' .. pv_name .. ')' - end - table.insert(defines, { 'PV_' .. varname:sub(3):upper(), pv_name }) - w(' .indir=' .. pv_name) - end if o.cb then w(' .opt_did_set_cb=' .. o.cb) end @@ -235,7 +369,6 @@ local function dump_option(i, o) w((' .var=&options[%u].def_val.data'):format(i - 1)) -- Option is always immutable on the false branch of `enable_if`. w(' .immutable=true') - w(' .indir=PV_NONE') w('#endif') end if o.defaults then @@ -256,6 +389,7 @@ local function dump_option(i, o) w(' },') end +-- Generate options[] array. w([[ #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" @@ -274,8 +408,3 @@ for i, o in ipairs(options.options) do dump_option(i, o) end w('};') -w('') - -for _, v in ipairs(defines) do - w('#define ' .. v[1] .. ' ' .. v[2]) -end diff --git a/src/nvim/generators/gen_options_enum.lua b/src/nvim/generators/gen_options_enum.lua deleted file mode 100644 index d1419137d3..0000000000 --- a/src/nvim/generators/gen_options_enum.lua +++ /dev/null @@ -1,129 +0,0 @@ --- Generates option index enum and map of option name to option index. --- Handles option full name, short name and aliases. --- Also generates BV_ and WV_ enum constants. - -local options_enum_file = arg[1] -local options_map_file = arg[2] -local options_enum_fd = assert(io.open(options_enum_file, 'w')) -local options_map_fd = assert(io.open(options_map_file, 'w')) - ---- @param s string -local function enum_w(s) - options_enum_fd:write(s .. '\n') -end - ---- @param s string -local function map_w(s) - options_map_fd:write(s .. '\n') -end - -enum_w('// IWYU pragma: private, include "nvim/option_defs.h"') -enum_w('') - ---- @param s string ---- @return string -local lowercase_to_titlecase = function(s) - return s:sub(1, 1):upper() .. s:sub(2) -end - ---- @type vim.option_meta[] -local options = require('options').options - --- Generate BV_ enum constants. -enum_w('/// "indir" values for buffer-local options.') -enum_w('/// These need to be defined globally, so that the BV_COUNT can be used with') -enum_w('/// b_p_script_stx[].') -enum_w('enum {') - -local bv_val = 0 - -for _, o in ipairs(options) do - assert(#o.scope == 1 or #o.scope == 2) - assert(#o.scope == 1 or o.scope[1] == 'global') - local min_scope = o.scope[#o.scope] - if min_scope == 'buffer' then - local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name)) - local bv_name = 'BV_' .. varname:sub(3):upper() - enum_w((' %s = %u,'):format(bv_name, bv_val)) - bv_val = bv_val + 1 - end -end - -enum_w((' BV_COUNT = %u, ///< must be the last one'):format(bv_val)) -enum_w('};') -enum_w('') - --- Generate WV_ enum constants. -enum_w('/// "indir" values for window-local options.') -enum_w('/// These need to be defined globally, so that the WV_COUNT can be used in the') -enum_w('/// window structure.') -enum_w('enum {') - -local wv_val = 0 - -for _, o in ipairs(options) do - assert(#o.scope == 1 or #o.scope == 2) - assert(#o.scope == 1 or o.scope[1] == 'global') - local min_scope = o.scope[#o.scope] - if min_scope == 'window' then - local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name)) - local wv_name = 'WV_' .. varname:sub(3):upper() - enum_w((' %s = %u,'):format(wv_name, wv_val)) - wv_val = wv_val + 1 - end -end - -enum_w((' WV_COUNT = %u, ///< must be the last one'):format(wv_val)) -enum_w('};') -enum_w('') - ---- @type { [string]: string } -local option_index = {} - --- Generate option index enum and populate the `option_index` dict. -enum_w('typedef enum {') -enum_w(' kOptInvalid = -1,') - -for i, o in ipairs(options) do - local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name) - enum_w((' %s = %u,'):format(enum_val_name, i - 1)) - - option_index[o.full_name] = enum_val_name - - if o.abbreviation then - option_index[o.abbreviation] = enum_val_name - end - - if o.alias then - o.alias = type(o.alias) == 'string' and { o.alias } or o.alias - - for _, v in ipairs(o.alias) do - option_index[v] = enum_val_name - end - end -end - -enum_w(' // Option count, used when iterating through options') -enum_w('#define kOptIndexCount ' .. tostring(#options)) -enum_w('} OptIndex;') -enum_w('') - -options_enum_fd:close() - ---- Generate option index map. -local hashy = require('generators.hashy') -local neworder, hashfun = hashy.hashy_hash('find_option', vim.tbl_keys(option_index), function(idx) - return ('option_hash_elems[%s].name'):format(idx) -end) - -map_w('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {') - -for _, name in ipairs(neworder) do - assert(option_index[name] ~= nil) - map_w((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name])) -end - -map_w('};\n') -map_w('static ' .. hashfun) - -options_map_fd:close() diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 58215f738c..e487728901 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -1182,7 +1182,7 @@ int get_expr_indent(void) sandbox++; } textlock++; - current_sctx = curbuf->b_p_script_ctx[BV_INDE].script_ctx; + current_sctx = curbuf->b_p_script_ctx[kBufOptIndentexpr].script_ctx; // Need to make a copy, the 'indentexpr' option could be changed while // evaluating it. diff --git a/src/nvim/option.c b/src/nvim/option.c index efd52f9233..8e94c342f7 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -303,7 +303,7 @@ static void set_init_default_cdpath(void) /// them. static void set_init_expand_env(void) { - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { vimoption_T *opt = &options[opt_idx]; if (opt->flags & kOptFlagNoDefExp) { continue; @@ -435,7 +435,7 @@ void set_init_1(bool clean_arg) static OptVal get_option_default(const OptIndex opt_idx, int opt_flags) { vimoption_T *opt = &options[opt_idx]; - bool is_global_local_option = opt->indir & PV_BOTH; + bool is_global_local_option = option_is_global_local(opt_idx); #ifdef UNIX if (opt_idx == kOptModeline && getuid() == ROOT_UID) { @@ -461,7 +461,7 @@ static OptVal get_option_default(const OptIndex opt_idx, int opt_flags) /// This ensures that we don't need to always check if the option default is allocated or not. static void alloc_options_default(void) { - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { options[opt_idx].def_val = optval_copy(options[opt_idx].def_val); } } @@ -500,7 +500,7 @@ static void set_option_default(const OptIndex opt_idx, int opt_flags) /// @param opt_flags Option flags. static void set_options_default(int opt_flags) { - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { if (!(options[opt_idx].flags & kOptFlagNoDefault)) { set_option_default(opt_idx, opt_flags); } @@ -564,16 +564,16 @@ static char *find_dup_item(char *origval, const char *newval, const size_t newva /// Free all options. void free_all_options(void) { - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { bool hidden = is_option_hidden(opt_idx); - if (options[opt_idx].indir == PV_NONE || hidden) { + if (option_is_global_only(opt_idx) || hidden) { // global option: free value and default value. // hidden option: free default value only. if (!hidden) { optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } - } else if (options[opt_idx].var != VAR_WIN) { + } else if (!option_is_window_local(opt_idx)) { // buffer-local option: free global value. optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } @@ -977,12 +977,12 @@ static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_ // Skip all options that are not window-local (used when showing // an already loaded buffer in a window). - if ((opt_flags & OPT_WINONLY) && (opt_idx == kOptInvalid || options[opt_idx].var != VAR_WIN)) { + if ((opt_flags & OPT_WINONLY) && (opt_idx == kOptInvalid || !option_is_window_local(opt_idx))) { return FAIL; } // Skip all options that are window-local (used for :vimgrep). - if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid && options[opt_idx].var == VAR_WIN) { + if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid && option_is_window_local(opt_idx)) { return FAIL; } @@ -999,10 +999,7 @@ static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_ // In diff mode some options are overruled. This avoids that // 'foldmethod' becomes "marker" instead of "diff" and that // "wrap" gets set. - if (win->w_p_diff - && opt_idx != kOptInvalid // shut up coverity warning - && (options[opt_idx].indir == PV_FDM - || options[opt_idx].indir == PV_WRAP)) { + if (win->w_p_diff && (opt_idx == kOptFoldmethod || opt_idx == kOptWrap)) { return FAIL; } } @@ -1099,7 +1096,7 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr vimoption_T *opt = &options[opt_idx]; char *arg = *argp; // When setting the local value of a global option, the old value may be the global value. - const bool oldval_is_global = ((int)opt->indir & PV_BOTH) && (opt_flags & OPT_LOCAL); + const bool oldval_is_global = option_is_global_local(opt_idx) && (opt_flags & OPT_LOCAL); OptVal oldval = optval_from_varp(opt_idx, oldval_is_global ? get_varp(opt) : varp); OptVal newval = NIL_OPTVAL; @@ -1285,10 +1282,10 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * // Mention where the option was last set. if (varp == options[opt_idx].var) { option_last_set_msg(options[opt_idx].last_set); - } else if ((int)options[opt_idx].indir & PV_WIN) { - option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); - } else if ((int)options[opt_idx].indir & PV_BUF) { - option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); + } else if (option_has_scope(opt_idx, kOptScopeWin)) { + option_last_set_msg(curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)]); + } else if (option_has_scope(opt_idx, kOptScopeBuf)) { + option_last_set_msg(curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)]); } } @@ -1643,7 +1640,7 @@ static void didset_options2(void) /// Check for string options that are NULL (normally only termcap options). void check_options(void) { - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { if ((option_has_type(opt_idx, kOptValTypeString)) && options[opt_idx].var != NULL) { check_string_option((char **)get_varp(&(options[opt_idx]))); } @@ -1673,24 +1670,25 @@ uint32_t *insecure_flag(win_T *const wp, OptIndex opt_idx, int opt_flags) { if (opt_flags & OPT_LOCAL) { assert(wp != NULL); - switch ((int)options[opt_idx].indir) { - case PV_STL: + switch (opt_idx) { + case kOptStatusline: return &wp->w_p_stl_flags; - case PV_WBR: + case kOptWinbar: return &wp->w_p_wbr_flags; - case PV_FDE: + case kOptFoldexpr: return &wp->w_p_fde_flags; - case PV_FDT: + case kOptFoldtext: return &wp->w_p_fdt_flags; - case PV_INDE: + case kOptIndentexpr: return &wp->w_buffer->b_p_inde_flags; - case PV_FEX: + case kOptFormatexpr: return &wp->w_buffer->b_p_fex_flags; - case PV_INEX: + case kOptIncludeexpr: return &wp->w_buffer->b_p_inex_flags; + default: + break; } } - // Nothing special, return global flags field. return &options[opt_idx].flags; } @@ -1804,7 +1802,6 @@ sctx_T *get_option_sctx(OptIndex opt_idx) void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx) { bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; - int indir = (int)options[opt_idx].indir; nlua_set_sctx(&script_ctx); LastSet last_set = { .script_ctx = script_ctx, @@ -1818,17 +1815,17 @@ void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx) // Remember where the option was set. For local options need to do that // in the buffer or window structure. - if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) { + if (both || (opt_flags & OPT_GLOBAL) || option_is_global_only(opt_idx)) { options[opt_idx].last_set = last_set; } if (both || (opt_flags & OPT_LOCAL)) { - if (indir & PV_BUF) { - curbuf->b_p_script_ctx[indir & PV_MASK] = last_set; - } else if (indir & PV_WIN) { - curwin->w_p_script_ctx[indir & PV_MASK] = last_set; + if (option_has_scope(opt_idx, kOptScopeBuf)) { + curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)] = last_set; + } else if ((option_has_scope(opt_idx, kOptScopeWin))) { + curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set; if (both) { // also setting the "all buffers" value - curwin->w_allbuf_opt.wo_script_ctx[indir & PV_MASK] = last_set; + curwin->w_allbuf_opt.wo_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set; } } } @@ -3267,7 +3264,7 @@ OptVal object_as_optval(Object o, bool *error) /// Get an allocated string containing a list of valid types for an option. /// For options with a singular type, it returns the name of the type. For options with multiple /// possible types, it returns a slash separated list of types. For example, if an option can be a -/// number, boolean or string, the function returns "Number/Boolean/String" +/// number, boolean or string, the function returns "number/boolean/string" static char *option_get_valid_types(OptIndex opt_idx) { StringBuilder str = KV_INITIAL_VALUE; @@ -3299,14 +3296,73 @@ static char *option_get_valid_types(OptIndex opt_idx) bool is_option_hidden(OptIndex opt_idx) { // Hidden options are always immutable and point to their default value - return opt_idx == kOptInvalid - ? false - : (options[opt_idx].immutable && options[opt_idx].var == &options[opt_idx].def_val.data); + return opt_idx != kOptInvalid && options[opt_idx].immutable + && options[opt_idx].var == &options[opt_idx].def_val.data; +} + +/// Check if option is multitype (supports multiple types). +static bool option_is_multitype(OptIndex opt_idx) +{ + const OptTypeFlags type_flags = get_option(opt_idx)->type_flags; + assert(type_flags != 0); + return !is_power_of_two(type_flags); +} + +/// Check if option supports a specific type. +bool option_has_type(OptIndex opt_idx, OptValType type) +{ + // Ensure that type flags variable can hold all types. + STATIC_ASSERT(kOptValTypeSize <= sizeof(OptTypeFlags) * 8, + "Option type_flags cannot fit all option types"); + // Ensure that the type is valid before accessing type_flags. + assert(type > kOptValTypeNil && type < kOptValTypeSize); + // Bitshift 1 by the value of type to get the type's corresponding flag, and check if it's set in + // the type_flags bit field. + return get_option(opt_idx)->type_flags & (1 << type); } +/// Check if option supports a specific scope. +bool option_has_scope(OptIndex opt_idx, OptScope scope) +{ + // Ensure that scope flags variable can hold all scopes. + STATIC_ASSERT(kOptScopeSize <= sizeof(OptScopeFlags) * 8, + "Option scope_flags cannot fit all option scopes"); + // Ensure that the scope is valid before accessing scope_flags. + assert(scope >= kOptScopeGlobal && scope < kOptScopeSize); + // Bitshift 1 by the value of scope to get the scope's corresponding flag, and check if it's set + // in the scope_flags bit field. + return get_option(opt_idx)->scope_flags & (1 << scope); +} + +/// Check if option is global-local. static inline bool option_is_global_local(OptIndex opt_idx) { - return opt_idx == kOptInvalid ? false : (options[opt_idx].indir & PV_BOTH); + // Global-local options have at least two types, so their type flag cannot be a power of two. + return opt_idx != kOptInvalid && !is_power_of_two(options[opt_idx].scope_flags); +} + +/// Check if option only supports global scope. +static inline bool option_is_global_only(OptIndex opt_idx) +{ + // For an option to be global-only, it has to only have a single scope, which means the scope + // flags must be a power of two, and it must have the global scope. + return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags) + && option_has_scope(opt_idx, kOptScopeGlobal); +} + +/// Check if option only supports window scope. +static inline bool option_is_window_local(OptIndex opt_idx) +{ + // For an option to be window-local it has to only have a single scope, which means the scope + // flags must be a power of two, and it must have the window scope. + return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags) + && option_has_scope(opt_idx, kOptScopeWin); +} + +/// Get option index for scope. +ssize_t option_scope_idx(OptIndex opt_idx, OptScope scope) +{ + return options[opt_idx].scope_idx[scope]; } /// Get option flags. @@ -3357,7 +3413,7 @@ static OptVal get_option_unset_value(OptIndex opt_idx) vimoption_T *opt = &options[opt_idx]; // For global-local options, use the unset value of the local value. - if (opt->indir & PV_BOTH) { + if (option_is_global_local(opt_idx)) { // String global-local options always use an empty string for the unset value. if (option_has_type(opt_idx, kOptValTypeString)) { return STATIC_CSTR_AS_OPTVAL(""); @@ -3389,7 +3445,7 @@ static bool is_option_local_value_unset(OptIndex opt_idx) vimoption_T *opt = get_option(opt_idx); // Local value of option that isn't global-local is always considered set. - if (!((int)opt->indir & PV_BOTH)) { + if (!option_is_global_local(opt_idx)) { return false; } @@ -3748,10 +3804,10 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set /// @param set_sid Script ID. Special values: /// 0: Use current script ID. /// SID_NONE: Don't set script ID. -/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param req_scope Requested option scope. See OptScope in option.h. /// @param[in] from Target buffer/window. void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid, - OptReqScope req_scope, void *const from) + OptScope req_scope, void *const from) { buf_T *save_curbuf = curbuf; win_T *save_curwin = curwin; @@ -3760,15 +3816,15 @@ void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T // side-effects when setting an option directly. Just change the values of curbuf and curwin if // needed, no need to properly switch the window / buffer. switch (req_scope) { - case kOptReqGlobal: + case kOptScopeGlobal: break; - case kOptReqBuf: - curbuf = (buf_T *)from; - break; - case kOptReqWin: + case kOptScopeWin: curwin = (win_T *)from; curbuf = curwin->w_buffer; break; + case kOptScopeBuf: + curbuf = (buf_T *)from; + break; } set_option_direct(opt_idx, value, opt_flags, set_sid); @@ -3855,16 +3911,17 @@ void set_option_value_give_err(const OptIndex opt_idx, OptVal value, int opt_fla /// Switch current context to get/set option value for window/buffer. /// /// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer. -/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param req_scope Requested option scope. See OptScope in option.h. /// @param[in] from Target buffer/window. /// @param[out] err Error message, if any. /// /// @return true if context was switched, false otherwise. -static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *const from, - Error *err) +static bool switch_option_context(void *const ctx, OptScope req_scope, void *const from, Error *err) { switch (req_scope) { - case kOptReqWin: { + case kOptScopeGlobal: + return false; + case kOptScopeWin: { win_T *const win = (win_T *)from; switchwin_T *const switchwin = (switchwin_T *)ctx; @@ -3884,7 +3941,7 @@ static bool switch_option_context(void *const ctx, OptReqScope req_scope, void * } return true; } - case kOptReqBuf: { + case kOptScopeBuf: { buf_T *const buf = (buf_T *)from; aco_save_T *const aco = (aco_save_T *)ctx; @@ -3894,76 +3951,44 @@ static bool switch_option_context(void *const ctx, OptReqScope req_scope, void * aucmd_prepbuf(aco, buf); return true; } - case kOptReqGlobal: - return false; } UNREACHABLE; } /// Restore context after getting/setting option for window/buffer. See switch_option_context() for /// params. -static void restore_option_context(void *const ctx, OptReqScope req_scope) +static void restore_option_context(void *const ctx, OptScope req_scope) { switch (req_scope) { - case kOptReqWin: + case kOptScopeGlobal: + break; + case kOptScopeWin: restore_win_noblock((switchwin_T *)ctx, true); break; - case kOptReqBuf: + case kOptScopeBuf: aucmd_restbuf((aco_save_T *)ctx); break; - case kOptReqGlobal: - break; } } -/// Get attributes for an option. -/// -/// @param opt_idx Option index in options[] table. -/// -/// @return Option attributes. -/// 0 for hidden or unknown option. -/// See SOPT_* in option_defs.h for other flags. -int get_option_attrs(OptIndex opt_idx) -{ - if (opt_idx == kOptInvalid) { - return 0; - } - - vimoption_T *opt = get_option(opt_idx); - - int attrs = 0; - - if (opt->indir == PV_NONE || (opt->indir & PV_BOTH)) { - attrs |= SOPT_GLOBAL; - } - if (opt->indir & PV_WIN) { - attrs |= SOPT_WIN; - } else if (opt->indir & PV_BUF) { - attrs |= SOPT_BUF; - } - - assert(attrs != 0); - return attrs; -} - /// Get option value for buffer / window. /// /// @param opt_idx Option index in options[] table. /// @param[out] flagsp Set to the option flags (see OptFlags) (if not NULL). /// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination). /// @param[out] hidden Whether option is hidden. -/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param req_scope Requested option scope. See OptScope in option.h. /// @param[in] from Target buffer/window. /// @param[out] err Error message, if any. /// /// @return Option value. Must be freed by caller. -OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptReqScope req_scope, - void *const from, Error *err) +OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptScope req_scope, void *const from, + Error *err) { switchwin_T switchwin; aco_save_T aco; - void *ctx = req_scope == kOptReqWin ? (void *)&switchwin - : (req_scope == kOptReqBuf ? (void *)&aco : NULL); + void *ctx = req_scope == kOptScopeWin ? (void *)&switchwin + : (req_scope == kOptScopeBuf ? (void *)&aco : NULL); bool switched = switch_option_context(ctx, req_scope, from, err); if (ERROR_SET(err)) { @@ -3985,17 +4010,17 @@ OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptReqScope req_s /// @param opt_idx Option index in options[] table. /// @param[in] value Option value. /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). -/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param req_scope Requested option scope. See OptScope in option.h. /// @param[in] from Target buffer/window. /// @param[out] err Error message, if any. void set_option_value_for(const char *name, OptIndex opt_idx, OptVal value, const int opt_flags, - const OptReqScope req_scope, void *const from, Error *err) + const OptScope req_scope, void *const from, Error *err) FUNC_ATTR_NONNULL_ARG(1) { switchwin_T switchwin; aco_save_T aco; - void *ctx = req_scope == kOptReqWin ? (void *)&switchwin - : (req_scope == kOptReqBuf ? (void *)&aco : NULL); + void *ctx = req_scope == kOptScopeWin ? (void *)&switchwin + : (req_scope == kOptScopeBuf ? (void *)&aco : NULL); bool switched = switch_option_context(ctx, req_scope, from, err); if (ERROR_SET(err)) { @@ -4040,7 +4065,7 @@ static void showoptions(bool all, int opt_flags) // collect the items in items[] int item_count = 0; vimoption_T *opt; - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { opt = &options[opt_idx]; // apply :filter /pat/ if (message_filtered(opt->fullname)) { @@ -4049,7 +4074,7 @@ static void showoptions(bool all, int opt_flags) void *varp = NULL; if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) { - if (opt->indir != PV_NONE) { + if (!option_is_global_only(opt_idx)) { varp = get_varp_scope(opt, opt_flags); } } else { @@ -4124,7 +4149,7 @@ static int optval_default(OptIndex opt_idx, void *varp) /// Send update to UIs with values of UI relevant options void ui_refresh_options(void) { - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { uint32_t flags = options[opt_idx].flags; if (!(flags & kOptFlagUIOption)) { continue; @@ -4204,13 +4229,13 @@ int makeset(FILE *fd, int opt_flags, int local_only) // kOptFlagPriMkrc flag and once without. for (int pri = 1; pri >= 0; pri--) { vimoption_T *opt; - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { opt = &options[opt_idx]; if (!(opt->flags & kOptFlagNoMkrc) && ((pri == 1) == ((opt->flags & kOptFlagPriMkrc) != 0))) { // skip global option when only doing locals - if (opt->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) { + if (option_is_global_only(opt_idx) && !(opt_flags & OPT_GLOBAL)) { continue; } @@ -4237,21 +4262,19 @@ int makeset(FILE *fd, int opt_flags, int local_only) int round = 2; void *varp_local = NULL; // fresh value - if (opt->indir != PV_NONE) { - if (opt->var == VAR_WIN) { - // skip window-local option when only doing globals - if (!(opt_flags & OPT_LOCAL)) { - continue; - } - // When fresh value of window-local option is not at the - // default, need to write it too. - if (!(opt_flags & OPT_GLOBAL) && !local_only) { - void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value - if (!optval_default(opt_idx, varp_fresh)) { - round = 1; - varp_local = varp; - varp = varp_fresh; - } + if (option_is_window_local(opt_idx)) { + // skip window-local option when only doing globals + if (!(opt_flags & OPT_LOCAL)) { + continue; + } + // When fresh value of window-local option is not at the + // default, need to write it too. + if (!(opt_flags & OPT_GLOBAL) && !local_only) { + void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value + if (!optval_default(opt_idx, varp_fresh)) { + round = 1; + varp_local = varp; + varp = varp_fresh; } } } @@ -4267,9 +4290,9 @@ int makeset(FILE *fd, int opt_flags, int local_only) } bool do_endif = false; - // Don't set 'syntax' and 'filetype' again if the value is - // already right, avoids reloading the syntax file. - if (opt->indir == PV_SYN || opt->indir == PV_FT) { + // Don't set 'syntax' and 'filetype' again if the value is already right, avoids reloading + // the syntax file. + if (opt_idx == kOptSyntax || opt_idx == kOptFiletype) { if (fprintf(fd, "if &%s != '%s'", opt->fullname, *(char **)(varp)) < 0 || put_eol(fd) < 0) { @@ -4325,7 +4348,7 @@ static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp) char *name = opt->fullname; uint64_t flags = opt->flags; - if ((opt->indir & PV_BOTH) && varp != opt->var + if (option_is_global_local(opt_idx) && varp != opt->var && optval_equal(value, get_option_unset_value(opt_idx))) { // Processing unset local value of global-local option. Do nothing. return OK; @@ -4430,76 +4453,80 @@ static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp) void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) { - if ((scope & OPT_GLOBAL) && p->indir != PV_NONE) { - if (p->var == VAR_WIN) { + OptIndex opt_idx = get_opt_idx(p); + + if ((scope & OPT_GLOBAL) && !option_is_global_only(opt_idx)) { + if (option_is_window_local(opt_idx)) { return GLOBAL_WO(get_varp_from(p, buf, win)); } return p->var; } - if ((scope & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) { - switch ((int)p->indir) { - case PV_FP: + + if ((scope & OPT_LOCAL) && option_is_global_local(opt_idx)) { + switch (opt_idx) { + case kOptFormatprg: return &(buf->b_p_fp); - case PV_FFU: + case kOptFindfunc: return &(buf->b_p_ffu); - case PV_EFM: + case kOptErrorformat: return &(buf->b_p_efm); - case PV_GP: + case kOptGrepprg: return &(buf->b_p_gp); - case PV_MP: + case kOptMakeprg: return &(buf->b_p_mp); - case PV_EP: + case kOptEqualprg: return &(buf->b_p_ep); - case PV_KP: + case kOptKeywordprg: return &(buf->b_p_kp); - case PV_PATH: + case kOptPath: return &(buf->b_p_path); - case PV_AR: + case kOptAutoread: return &(buf->b_p_ar); - case PV_TAGS: + case kOptTags: return &(buf->b_p_tags); - case PV_TC: + case kOptTagcase: return &(buf->b_p_tc); - case PV_SISO: + case kOptSidescrolloff: return &(win->w_p_siso); - case PV_SO: + case kOptScrolloff: return &(win->w_p_so); - case PV_DEF: + case kOptDefine: return &(buf->b_p_def); - case PV_INC: + case kOptInclude: return &(buf->b_p_inc); - case PV_COT: + case kOptCompleteopt: return &(buf->b_p_cot); - case PV_DICT: + case kOptDictionary: return &(buf->b_p_dict); - case PV_TSR: + case kOptThesaurus: return &(buf->b_p_tsr); - case PV_TSRFU: + case kOptThesaurusfunc: return &(buf->b_p_tsrfu); - case PV_TFU: + case kOptTagfunc: return &(buf->b_p_tfu); - case PV_SBR: + case kOptShowbreak: return &(win->w_p_sbr); - case PV_STL: + case kOptStatusline: return &(win->w_p_stl); - case PV_WBR: + case kOptWinbar: return &(win->w_p_wbr); - case PV_UL: + case kOptUndolevels: return &(buf->b_p_ul); - case PV_LW: + case kOptLispwords: return &(buf->b_p_lw); - case PV_BKC: + case kOptBackupcopy: return &(buf->b_p_bkc); - case PV_MENC: + case kOptMakeencoding: return &(buf->b_p_menc); - case PV_FCS: + case kOptFillchars: return &(win->w_p_fcs); - case PV_LCS: + case kOptListchars: return &(win->w_p_lcs); - case PV_VE: + case kOptVirtualedit: return &(win->w_p_ve); + default: + abort(); } - return NULL; // "cannot happen" } return get_varp_from(p, buf, win); } @@ -4521,291 +4548,290 @@ void *get_option_varp_scope_from(OptIndex opt_idx, int scope, buf_T *buf, win_T void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) { - // hidden options always use the same var pointer - if (is_option_hidden(get_opt_idx(p))) { - return p->var; - } + OptIndex opt_idx = get_opt_idx(p); - switch ((int)p->indir) { - case PV_NONE: + // Hidden options and global-only options always use the same var pointer + if (is_option_hidden(opt_idx) || option_is_global_only(opt_idx)) { return p->var; + } + switch (opt_idx) { // global option with local value: use local value if it's been set - case PV_EP: + case kOptEqualprg: return *buf->b_p_ep != NUL ? &buf->b_p_ep : p->var; - case PV_KP: + case kOptKeywordprg: return *buf->b_p_kp != NUL ? &buf->b_p_kp : p->var; - case PV_PATH: + case kOptPath: return *buf->b_p_path != NUL ? &(buf->b_p_path) : p->var; - case PV_AR: + case kOptAutoread: return buf->b_p_ar >= 0 ? &(buf->b_p_ar) : p->var; - case PV_TAGS: + case kOptTags: return *buf->b_p_tags != NUL ? &(buf->b_p_tags) : p->var; - case PV_TC: + case kOptTagcase: return *buf->b_p_tc != NUL ? &(buf->b_p_tc) : p->var; - case PV_SISO: + case kOptSidescrolloff: return win->w_p_siso >= 0 ? &(win->w_p_siso) : p->var; - case PV_SO: + case kOptScrolloff: return win->w_p_so >= 0 ? &(win->w_p_so) : p->var; - case PV_BKC: + case kOptBackupcopy: return *buf->b_p_bkc != NUL ? &(buf->b_p_bkc) : p->var; - case PV_DEF: + case kOptDefine: return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var; - case PV_INC: + case kOptInclude: return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var; - case PV_COT: + case kOptCompleteopt: return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var; - case PV_DICT: + case kOptDictionary: return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var; - case PV_TSR: + case kOptThesaurus: return *buf->b_p_tsr != NUL ? &(buf->b_p_tsr) : p->var; - case PV_TSRFU: + case kOptThesaurusfunc: return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var; - case PV_FP: + case kOptFormatprg: return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var; - case PV_FFU: + case kOptFindfunc: return *buf->b_p_ffu != NUL ? &(buf->b_p_ffu) : p->var; - case PV_EFM: + case kOptErrorformat: return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var; - case PV_GP: + case kOptGrepprg: return *buf->b_p_gp != NUL ? &(buf->b_p_gp) : p->var; - case PV_MP: + case kOptMakeprg: return *buf->b_p_mp != NUL ? &(buf->b_p_mp) : p->var; - case PV_SBR: + case kOptShowbreak: return *win->w_p_sbr != NUL ? &(win->w_p_sbr) : p->var; - case PV_STL: + case kOptStatusline: return *win->w_p_stl != NUL ? &(win->w_p_stl) : p->var; - case PV_WBR: + case kOptWinbar: return *win->w_p_wbr != NUL ? &(win->w_p_wbr) : p->var; - case PV_UL: + case kOptUndolevels: return buf->b_p_ul != NO_LOCAL_UNDOLEVEL ? &(buf->b_p_ul) : p->var; - case PV_LW: + case kOptLispwords: return *buf->b_p_lw != NUL ? &(buf->b_p_lw) : p->var; - case PV_MENC: + case kOptMakeencoding: return *buf->b_p_menc != NUL ? &(buf->b_p_menc) : p->var; - case PV_FCS: + case kOptFillchars: return *win->w_p_fcs != NUL ? &(win->w_p_fcs) : p->var; - case PV_LCS: + case kOptListchars: return *win->w_p_lcs != NUL ? &(win->w_p_lcs) : p->var; - case PV_VE: + case kOptVirtualedit: return *win->w_p_ve != NUL ? &win->w_p_ve : p->var; - case PV_ARAB: + case kOptArabic: return &(win->w_p_arab); - case PV_LIST: + case kOptList: return &(win->w_p_list); - case PV_SPELL: + case kOptSpell: return &(win->w_p_spell); - case PV_CUC: + case kOptCursorcolumn: return &(win->w_p_cuc); - case PV_CUL: + case kOptCursorline: return &(win->w_p_cul); - case PV_CULOPT: + case kOptCursorlineopt: return &(win->w_p_culopt); - case PV_CC: + case kOptColorcolumn: return &(win->w_p_cc); - case PV_DIFF: + case kOptDiff: return &(win->w_p_diff); - case PV_FDC: + case kOptFoldcolumn: return &(win->w_p_fdc); - case PV_FEN: + case kOptFoldenable: return &(win->w_p_fen); - case PV_FDI: + case kOptFoldignore: return &(win->w_p_fdi); - case PV_FDL: + case kOptFoldlevel: return &(win->w_p_fdl); - case PV_FDM: + case kOptFoldmethod: return &(win->w_p_fdm); - case PV_FML: + case kOptFoldminlines: return &(win->w_p_fml); - case PV_FDN: + case kOptFoldnestmax: return &(win->w_p_fdn); - case PV_FDE: + case kOptFoldexpr: return &(win->w_p_fde); - case PV_FDT: + case kOptFoldtext: return &(win->w_p_fdt); - case PV_FMR: + case kOptFoldmarker: return &(win->w_p_fmr); - case PV_NU: + case kOptNumber: return &(win->w_p_nu); - case PV_RNU: + case kOptRelativenumber: return &(win->w_p_rnu); - case PV_NUW: + case kOptNumberwidth: return &(win->w_p_nuw); - case PV_WFB: + case kOptWinfixbuf: return &(win->w_p_wfb); - case PV_WFH: + case kOptWinfixheight: return &(win->w_p_wfh); - case PV_WFW: + case kOptWinfixwidth: return &(win->w_p_wfw); - case PV_PVW: + case kOptPreviewwindow: return &(win->w_p_pvw); - case PV_RL: + case kOptRightleft: return &(win->w_p_rl); - case PV_RLC: + case kOptRightleftcmd: return &(win->w_p_rlc); - case PV_SCROLL: + case kOptScroll: return &(win->w_p_scr); - case PV_SMS: + case kOptSmoothscroll: return &(win->w_p_sms); - case PV_WRAP: + case kOptWrap: return &(win->w_p_wrap); - case PV_LBR: + case kOptLinebreak: return &(win->w_p_lbr); - case PV_BRI: + case kOptBreakindent: return &(win->w_p_bri); - case PV_BRIOPT: + case kOptBreakindentopt: return &(win->w_p_briopt); - case PV_SCBIND: + case kOptScrollbind: return &(win->w_p_scb); - case PV_CRBIND: + case kOptCursorbind: return &(win->w_p_crb); - case PV_COCU: + case kOptConcealcursor: return &(win->w_p_cocu); - case PV_COLE: + case kOptConceallevel: return &(win->w_p_cole); - case PV_AI: + case kOptAutoindent: return &(buf->b_p_ai); - case PV_BIN: + case kOptBinary: return &(buf->b_p_bin); - case PV_BOMB: + case kOptBomb: return &(buf->b_p_bomb); - case PV_BH: + case kOptBufhidden: return &(buf->b_p_bh); - case PV_BT: + case kOptBuftype: return &(buf->b_p_bt); - case PV_BL: + case kOptBuflisted: return &(buf->b_p_bl); - case PV_CHANNEL: + case kOptChannel: return &(buf->b_p_channel); - case PV_CI: + case kOptCopyindent: return &(buf->b_p_ci); - case PV_CIN: + case kOptCindent: return &(buf->b_p_cin); - case PV_CINK: + case kOptCinkeys: return &(buf->b_p_cink); - case PV_CINO: + case kOptCinoptions: return &(buf->b_p_cino); - case PV_CINSD: + case kOptCinscopedecls: return &(buf->b_p_cinsd); - case PV_CINW: + case kOptCinwords: return &(buf->b_p_cinw); - case PV_COM: + case kOptComments: return &(buf->b_p_com); - case PV_CMS: + case kOptCommentstring: return &(buf->b_p_cms); - case PV_CPT: + case kOptComplete: return &(buf->b_p_cpt); #ifdef BACKSLASH_IN_FILENAME - case PV_CSL: + case kOptCompleteslash: return &(buf->b_p_csl); #endif - case PV_CFU: + case kOptCompletefunc: return &(buf->b_p_cfu); - case PV_OFU: + case kOptOmnifunc: return &(buf->b_p_ofu); - case PV_EOF: + case kOptEndoffile: return &(buf->b_p_eof); - case PV_EOL: + case kOptEndofline: return &(buf->b_p_eol); - case PV_FIXEOL: + case kOptFixendofline: return &(buf->b_p_fixeol); - case PV_ET: + case kOptExpandtab: return &(buf->b_p_et); - case PV_FENC: + case kOptFileencoding: return &(buf->b_p_fenc); - case PV_FF: + case kOptFileformat: return &(buf->b_p_ff); - case PV_FT: + case kOptFiletype: return &(buf->b_p_ft); - case PV_FO: + case kOptFormatoptions: return &(buf->b_p_fo); - case PV_FLP: + case kOptFormatlistpat: return &(buf->b_p_flp); - case PV_IMI: + case kOptIminsert: return &(buf->b_p_iminsert); - case PV_IMS: + case kOptImsearch: return &(buf->b_p_imsearch); - case PV_INF: + case kOptInfercase: return &(buf->b_p_inf); - case PV_ISK: + case kOptIskeyword: return &(buf->b_p_isk); - case PV_INEX: + case kOptIncludeexpr: return &(buf->b_p_inex); - case PV_INDE: + case kOptIndentexpr: return &(buf->b_p_inde); - case PV_INDK: + case kOptIndentkeys: return &(buf->b_p_indk); - case PV_FEX: + case kOptFormatexpr: return &(buf->b_p_fex); - case PV_LISP: + case kOptLisp: return &(buf->b_p_lisp); - case PV_LOP: + case kOptLispoptions: return &(buf->b_p_lop); - case PV_ML: + case kOptModeline: return &(buf->b_p_ml); - case PV_MPS: + case kOptMatchpairs: return &(buf->b_p_mps); - case PV_MA: + case kOptModifiable: return &(buf->b_p_ma); - case PV_MOD: + case kOptModified: return &(buf->b_changed); - case PV_NF: + case kOptNrformats: return &(buf->b_p_nf); - case PV_PI: + case kOptPreserveindent: return &(buf->b_p_pi); - case PV_QE: + case kOptQuoteescape: return &(buf->b_p_qe); - case PV_RO: + case kOptReadonly: return &(buf->b_p_ro); - case PV_SCBK: + case kOptScrollback: return &(buf->b_p_scbk); - case PV_SI: + case kOptSmartindent: return &(buf->b_p_si); - case PV_STS: + case kOptSofttabstop: return &(buf->b_p_sts); - case PV_SUA: + case kOptSuffixesadd: return &(buf->b_p_sua); - case PV_SWF: + case kOptSwapfile: return &(buf->b_p_swf); - case PV_SMC: + case kOptSynmaxcol: return &(buf->b_p_smc); - case PV_SYN: + case kOptSyntax: return &(buf->b_p_syn); - case PV_SPC: + case kOptSpellcapcheck: return &(win->w_s->b_p_spc); - case PV_SPF: + case kOptSpellfile: return &(win->w_s->b_p_spf); - case PV_SPL: + case kOptSpelllang: return &(win->w_s->b_p_spl); - case PV_SPO: + case kOptSpelloptions: return &(win->w_s->b_p_spo); - case PV_SW: + case kOptShiftwidth: return &(buf->b_p_sw); - case PV_TFU: + case kOptTagfunc: return &(buf->b_p_tfu); - case PV_TS: + case kOptTabstop: return &(buf->b_p_ts); - case PV_TW: + case kOptTextwidth: return &(buf->b_p_tw); - case PV_UDF: + case kOptUndofile: return &(buf->b_p_udf); - case PV_WM: + case kOptWrapmargin: return &(buf->b_p_wm); - case PV_VSTS: + case kOptVarsofttabstop: return &(buf->b_p_vsts); - case PV_VTS: + case kOptVartabstop: return &(buf->b_p_vts); - case PV_KMAP: + case kOptKeymap: return &(buf->b_p_keymap); - case PV_SCL: + case kOptSigncolumn: return &(win->w_p_scl); - case PV_WINHL: + case kOptWinhighlight: return &(win->w_p_winhl); - case PV_WINBL: + case kOptWinblend: return &(win->w_p_winbl); - case PV_STC: + case kOptStatuscolumn: return &(win->w_p_stc); default: iemsg(_("E356: get_varp ERROR")); @@ -5008,26 +5034,8 @@ void didset_window_options(win_T *wp, bool valid_cursor) wp->w_grid_alloc.blending = wp->w_p_winbl > 0; } -/// Index into the options table for a buffer-local option enum. -static OptIndex buf_opt_idx[BV_COUNT]; #define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].last_set -/// Initialize buf_opt_idx[] if not done already. -static void init_buf_opt_idx(void) -{ - static bool did_init_buf_opt_idx = false; - - if (did_init_buf_opt_idx) { - return; - } - did_init_buf_opt_idx = true; - for (OptIndex i = 0; i < kOptIndexCount; i++) { - if (options[i].indir & PV_BUF) { - buf_opt_idx[options[i].indir & PV_MASK] = i; - } - } -} - /// Copy global option values to local options for one buffer. /// Used when creating a new buffer and sometimes when entering a buffer. /// flags: @@ -5065,7 +5073,6 @@ void buf_copy_options(buf_T *buf, int flags) if (should_copy || (flags & BCO_ALWAYS)) { CLEAR_FIELD(buf->b_p_script_ctx); - init_buf_opt_idx(); // Don't copy the options specific to a help buffer when // BCO_NOHELP is given or the options were initialized already // (jumping back to a help file with CTRL-T or CTRL-O) @@ -5101,61 +5108,61 @@ void buf_copy_options(buf_T *buf, int flags) } buf->b_p_ai = p_ai; - COPY_OPT_SCTX(buf, BV_AI); + COPY_OPT_SCTX(buf, kBufOptAutoindent); buf->b_p_ai_nopaste = p_ai_nopaste; buf->b_p_sw = p_sw; - COPY_OPT_SCTX(buf, BV_SW); + COPY_OPT_SCTX(buf, kBufOptShiftwidth); buf->b_p_scbk = p_scbk; - COPY_OPT_SCTX(buf, BV_SCBK); + COPY_OPT_SCTX(buf, kBufOptScrollback); buf->b_p_tw = p_tw; - COPY_OPT_SCTX(buf, BV_TW); + COPY_OPT_SCTX(buf, kBufOptTextwidth); buf->b_p_tw_nopaste = p_tw_nopaste; buf->b_p_tw_nobin = p_tw_nobin; buf->b_p_wm = p_wm; - COPY_OPT_SCTX(buf, BV_WM); + COPY_OPT_SCTX(buf, kBufOptWrapmargin); buf->b_p_wm_nopaste = p_wm_nopaste; buf->b_p_wm_nobin = p_wm_nobin; buf->b_p_bin = p_bin; - COPY_OPT_SCTX(buf, BV_BIN); + COPY_OPT_SCTX(buf, kBufOptBinary); buf->b_p_bomb = p_bomb; - COPY_OPT_SCTX(buf, BV_BOMB); + COPY_OPT_SCTX(buf, kBufOptBomb); buf->b_p_et = p_et; - COPY_OPT_SCTX(buf, BV_ET); + COPY_OPT_SCTX(buf, kBufOptExpandtab); buf->b_p_fixeol = p_fixeol; - COPY_OPT_SCTX(buf, BV_FIXEOL); + COPY_OPT_SCTX(buf, kBufOptFixendofline); buf->b_p_et_nobin = p_et_nobin; buf->b_p_et_nopaste = p_et_nopaste; buf->b_p_ml = p_ml; - COPY_OPT_SCTX(buf, BV_ML); + COPY_OPT_SCTX(buf, kBufOptModeline); buf->b_p_ml_nobin = p_ml_nobin; buf->b_p_inf = p_inf; - COPY_OPT_SCTX(buf, BV_INF); + COPY_OPT_SCTX(buf, kBufOptInfercase); if (cmdmod.cmod_flags & CMOD_NOSWAPFILE) { buf->b_p_swf = false; } else { buf->b_p_swf = p_swf; - COPY_OPT_SCTX(buf, BV_SWF); + COPY_OPT_SCTX(buf, kBufOptSwapfile); } buf->b_p_cpt = xstrdup(p_cpt); - COPY_OPT_SCTX(buf, BV_CPT); + COPY_OPT_SCTX(buf, kBufOptComplete); #ifdef BACKSLASH_IN_FILENAME buf->b_p_csl = xstrdup(p_csl); - COPY_OPT_SCTX(buf, BV_CSL); + COPY_OPT_SCTX(buf, kBufOptCompleteslash); #endif buf->b_p_cfu = xstrdup(p_cfu); - COPY_OPT_SCTX(buf, BV_CFU); + COPY_OPT_SCTX(buf, kBufOptCompletefunc); set_buflocal_cfu_callback(buf); buf->b_p_ofu = xstrdup(p_ofu); - COPY_OPT_SCTX(buf, BV_OFU); + COPY_OPT_SCTX(buf, kBufOptOmnifunc); set_buflocal_ofu_callback(buf); buf->b_p_tfu = xstrdup(p_tfu); - COPY_OPT_SCTX(buf, BV_TFU); + COPY_OPT_SCTX(buf, kBufOptTagfunc); set_buflocal_tfu_callback(buf); buf->b_p_sts = p_sts; - COPY_OPT_SCTX(buf, BV_STS); + COPY_OPT_SCTX(buf, kBufOptSofttabstop); buf->b_p_sts_nopaste = p_sts_nopaste; buf->b_p_vsts = xstrdup(p_vsts); - COPY_OPT_SCTX(buf, BV_VSTS); + COPY_OPT_SCTX(buf, kBufOptVarsofttabstop); if (p_vsts && p_vsts != empty_string_option) { tabstop_set(p_vsts, &buf->b_p_vsts_array); } else { @@ -5163,75 +5170,75 @@ void buf_copy_options(buf_T *buf, int flags) } buf->b_p_vsts_nopaste = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : NULL; buf->b_p_com = xstrdup(p_com); - COPY_OPT_SCTX(buf, BV_COM); + COPY_OPT_SCTX(buf, kBufOptComments); buf->b_p_cms = xstrdup(p_cms); - COPY_OPT_SCTX(buf, BV_CMS); + COPY_OPT_SCTX(buf, kBufOptCommentstring); buf->b_p_fo = xstrdup(p_fo); - COPY_OPT_SCTX(buf, BV_FO); + COPY_OPT_SCTX(buf, kBufOptFormatoptions); buf->b_p_flp = xstrdup(p_flp); - COPY_OPT_SCTX(buf, BV_FLP); + COPY_OPT_SCTX(buf, kBufOptFormatlistpat); buf->b_p_nf = xstrdup(p_nf); - COPY_OPT_SCTX(buf, BV_NF); + COPY_OPT_SCTX(buf, kBufOptNrformats); buf->b_p_mps = xstrdup(p_mps); - COPY_OPT_SCTX(buf, BV_MPS); + COPY_OPT_SCTX(buf, kBufOptMatchpairs); buf->b_p_si = p_si; - COPY_OPT_SCTX(buf, BV_SI); + COPY_OPT_SCTX(buf, kBufOptSmartindent); buf->b_p_channel = 0; buf->b_p_ci = p_ci; - COPY_OPT_SCTX(buf, BV_CI); + COPY_OPT_SCTX(buf, kBufOptCopyindent); buf->b_p_cin = p_cin; - COPY_OPT_SCTX(buf, BV_CIN); + COPY_OPT_SCTX(buf, kBufOptCindent); buf->b_p_cink = xstrdup(p_cink); - COPY_OPT_SCTX(buf, BV_CINK); + COPY_OPT_SCTX(buf, kBufOptCinkeys); buf->b_p_cino = xstrdup(p_cino); - COPY_OPT_SCTX(buf, BV_CINO); + COPY_OPT_SCTX(buf, kBufOptCinoptions); buf->b_p_cinsd = xstrdup(p_cinsd); - COPY_OPT_SCTX(buf, BV_CINSD); + COPY_OPT_SCTX(buf, kBufOptCinscopedecls); buf->b_p_lop = xstrdup(p_lop); - COPY_OPT_SCTX(buf, BV_LOP); + COPY_OPT_SCTX(buf, kBufOptLispoptions); // Don't copy 'filetype', it must be detected buf->b_p_ft = empty_string_option; buf->b_p_pi = p_pi; - COPY_OPT_SCTX(buf, BV_PI); + COPY_OPT_SCTX(buf, kBufOptPreserveindent); buf->b_p_cinw = xstrdup(p_cinw); - COPY_OPT_SCTX(buf, BV_CINW); + COPY_OPT_SCTX(buf, kBufOptCinwords); buf->b_p_lisp = p_lisp; - COPY_OPT_SCTX(buf, BV_LISP); + COPY_OPT_SCTX(buf, kBufOptLisp); // Don't copy 'syntax', it must be set buf->b_p_syn = empty_string_option; buf->b_p_smc = p_smc; - COPY_OPT_SCTX(buf, BV_SMC); + COPY_OPT_SCTX(buf, kBufOptSynmaxcol); buf->b_s.b_syn_isk = empty_string_option; buf->b_s.b_p_spc = xstrdup(p_spc); - COPY_OPT_SCTX(buf, BV_SPC); + COPY_OPT_SCTX(buf, kBufOptSpellcapcheck); compile_cap_prog(&buf->b_s); buf->b_s.b_p_spf = xstrdup(p_spf); - COPY_OPT_SCTX(buf, BV_SPF); + COPY_OPT_SCTX(buf, kBufOptSpellfile); buf->b_s.b_p_spl = xstrdup(p_spl); - COPY_OPT_SCTX(buf, BV_SPL); + COPY_OPT_SCTX(buf, kBufOptSpelllang); buf->b_s.b_p_spo = xstrdup(p_spo); - COPY_OPT_SCTX(buf, BV_SPO); + COPY_OPT_SCTX(buf, kBufOptSpelloptions); buf->b_s.b_p_spo_flags = spo_flags; buf->b_p_inde = xstrdup(p_inde); - COPY_OPT_SCTX(buf, BV_INDE); + COPY_OPT_SCTX(buf, kBufOptIndentexpr); buf->b_p_indk = xstrdup(p_indk); - COPY_OPT_SCTX(buf, BV_INDK); + COPY_OPT_SCTX(buf, kBufOptIndentkeys); buf->b_p_fp = empty_string_option; buf->b_p_fex = xstrdup(p_fex); - COPY_OPT_SCTX(buf, BV_FEX); + COPY_OPT_SCTX(buf, kBufOptFormatexpr); buf->b_p_sua = xstrdup(p_sua); - COPY_OPT_SCTX(buf, BV_SUA); + COPY_OPT_SCTX(buf, kBufOptSuffixesadd); buf->b_p_keymap = xstrdup(p_keymap); - COPY_OPT_SCTX(buf, BV_KMAP); + COPY_OPT_SCTX(buf, kBufOptKeymap); buf->b_kmap_state |= KEYMAP_INIT; // This isn't really an option, but copying the langmap and IME // state from the current buffer is better than resetting it. buf->b_p_iminsert = p_iminsert; - COPY_OPT_SCTX(buf, BV_IMI); + COPY_OPT_SCTX(buf, kBufOptIminsert); buf->b_p_imsearch = p_imsearch; - COPY_OPT_SCTX(buf, BV_IMS); + COPY_OPT_SCTX(buf, kBufOptImsearch); // options that are normally global but also have a local value // are not copied, start using the global value @@ -5252,16 +5259,16 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_def = empty_string_option; buf->b_p_inc = empty_string_option; buf->b_p_inex = xstrdup(p_inex); - COPY_OPT_SCTX(buf, BV_INEX); + COPY_OPT_SCTX(buf, kBufOptIncludeexpr); buf->b_p_cot = empty_string_option; buf->b_cot_flags = 0; buf->b_p_dict = empty_string_option; buf->b_p_tsr = empty_string_option; buf->b_p_tsrfu = empty_string_option; buf->b_p_qe = xstrdup(p_qe); - COPY_OPT_SCTX(buf, BV_QE); + COPY_OPT_SCTX(buf, kBufOptQuoteescape); buf->b_p_udf = p_udf; - COPY_OPT_SCTX(buf, BV_UDF); + COPY_OPT_SCTX(buf, kBufOptUndofile); buf->b_p_lw = empty_string_option; buf->b_p_menc = empty_string_option; @@ -5278,12 +5285,12 @@ void buf_copy_options(buf_T *buf, int flags) } } else { buf->b_p_isk = xstrdup(p_isk); - COPY_OPT_SCTX(buf, BV_ISK); + COPY_OPT_SCTX(buf, kBufOptIskeyword); did_isk = true; buf->b_p_ts = p_ts; - COPY_OPT_SCTX(buf, BV_TS); + COPY_OPT_SCTX(buf, kBufOptTabstop); buf->b_p_vts = xstrdup(p_vts); - COPY_OPT_SCTX(buf, BV_VTS); + COPY_OPT_SCTX(buf, kBufOptVartabstop); if (p_vts && p_vts != empty_string_option && !buf->b_p_vts_array) { tabstop_set(p_vts, &buf->b_p_vts_array); } else { @@ -5294,7 +5301,7 @@ void buf_copy_options(buf_T *buf, int flags) clear_string_option(&buf->b_p_bt); } buf->b_p_ma = p_ma; - COPY_OPT_SCTX(buf, BV_MA); + COPY_OPT_SCTX(buf, kBufOptModifiable); } } @@ -5645,7 +5652,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM } } char *str; - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { str = options[opt_idx].fullname; if (is_option_hidden(opt_idx)) { continue; @@ -6306,11 +6313,11 @@ dict_T *get_winbuf_options(const int bufopt) { dict_T *const d = tv_dict_alloc(); - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { vimoption_T *opt = &options[opt_idx]; - if ((bufopt && (opt->indir & PV_BUF)) - || (!bufopt && (opt->indir & PV_WIN))) { + if ((bufopt && (option_has_scope(opt_idx, kOptScopeBuf))) + || (!bufopt && (option_has_scope(opt_idx, kOptScopeWin)))) { void *varp = get_varp(opt); if (varp != NULL) { @@ -6353,8 +6360,8 @@ Dict get_vimoption(String name, int scope, buf_T *buf, win_T *win, Arena *arena, Dict get_all_vimoptions(Arena *arena) { - Dict retval = arena_dict(arena, kOptIndexCount); - for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + Dict retval = arena_dict(arena, kOptCount); + for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { Dict opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena); PUT_C(retval, options[opt_idx].fullname, DICT_OBJ(opt_dict)); } @@ -6363,15 +6370,16 @@ Dict get_all_vimoptions(Arena *arena) static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *win, Arena *arena) { + OptIndex opt_idx = get_opt_idx(opt); Dict dict = arena_dict(arena, 13); PUT_C(dict, "name", CSTR_AS_OBJ(opt->fullname)); PUT_C(dict, "shortname", CSTR_AS_OBJ(opt->shortname)); const char *scope; - if (opt->indir & PV_BUF) { + if (option_has_scope(opt_idx, kOptScopeBuf)) { scope = "buf"; - } else if (opt->indir & PV_WIN) { + } else if (option_has_scope(opt_idx, kOptScopeWin)) { scope = "win"; } else { scope = "global"; @@ -6380,7 +6388,7 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w PUT_C(dict, "scope", CSTR_AS_OBJ(scope)); // welcome to the jungle - PUT_C(dict, "global_local", BOOLEAN_OBJ(opt->indir & PV_BOTH)); + PUT_C(dict, "global_local", BOOLEAN_OBJ(option_is_global_local(opt_idx))); PUT_C(dict, "commalist", BOOLEAN_OBJ(opt->flags & kOptFlagComma)); PUT_C(dict, "flaglist", BOOLEAN_OBJ(opt->flags & kOptFlagFlagList)); @@ -6391,11 +6399,11 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w last_set = opt->last_set; } else { // Scope is either OPT_LOCAL or a fallback mode was requested. - if (opt->indir & PV_BUF) { - last_set = buf->b_p_script_ctx[opt->indir & PV_MASK]; + if (option_has_scope(opt_idx, kOptScopeBuf)) { + last_set = buf->b_p_script_ctx[opt->scope_idx[kOptScopeBuf]]; } - if (opt->indir & PV_WIN) { - last_set = win->w_p_script_ctx[opt->indir & PV_MASK]; + if (option_has_scope(opt_idx, kOptScopeWin)) { + last_set = win->w_p_script_ctx[opt->scope_idx[kOptScopeWin]]; } if (req_scope != OPT_LOCAL && last_set.script_ctx.sc_sid == 0) { last_set = opt->last_set; @@ -6412,24 +6420,3 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w return dict; } - -/// Check if option is multitype (supports multiple types). -static bool option_is_multitype(OptIndex opt_idx) -{ - const OptTypeFlags type_flags = get_option(opt_idx)->type_flags; - assert(type_flags != 0); - return !is_power_of_two(type_flags); -} - -/// Check if option supports a specific type. -bool option_has_type(OptIndex opt_idx, OptValType type) -{ - // Ensure that type flags variable can hold all types. - STATIC_ASSERT(kOptValTypeSize <= sizeof(OptTypeFlags) * 8, - "Option type_flags cannot fit all option types"); - // Ensure that the type is valid before accessing type_flags. - assert(type > kOptValTypeNil && type < kOptValTypeSize); - // Bitshift 1 by the value of type to get the type's corresponding flag, and check if it's set in - // the type_flags bit field. - return get_option(opt_idx)->type_flags & (1 << type); -} diff --git a/src/nvim/option.h b/src/nvim/option.h index 138d90da97..cba5b00d95 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -13,56 +13,6 @@ #include "nvim/option_defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" // IWYU pragma: keep -/// The options that are local to a window or buffer have "indir" set to one of -/// these values. Special values: -/// PV_NONE: global option. -/// PV_WIN is added: window-local option -/// PV_BUF is added: buffer-local option -/// PV_BOTH is added: global option which also has a local value. -enum { - PV_BOTH = 0x1000, - PV_WIN = 0x2000, - PV_BUF = 0x4000, - PV_MASK = 0x0fff, -}; -#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x)) -#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) -#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) - -/// WV_ and BV_ values get typecasted to this for the "indir" field -typedef enum { - PV_NONE = 0, - PV_MAXVAL = 0xffff, ///< to avoid warnings for value out of range -} idopt_T; - -// Options local to a window have a value local to a buffer and global to all -// buffers. Indicate this by setting "var" to VAR_WIN. -#define VAR_WIN ((char *)-1) - -typedef struct { - char *fullname; ///< full option name - char *shortname; ///< permissible abbreviation - uint32_t flags; ///< see above - OptTypeFlags type_flags; ///< option type flags, see OptValType - void *var; ///< global option: pointer to variable; - ///< window-local option: VAR_WIN; - ///< buffer-local option: global value - idopt_T indir; ///< global option: PV_NONE; - ///< local option: indirect option index - bool immutable; ///< option is immutable, trying to set its value will give an error. - - /// callback function to invoke after an option is modified to validate and - /// apply the new value. - opt_did_set_cb_T opt_did_set_cb; - - /// callback function to invoke when expanding possible values on the - /// cmdline. Only useful for string options. - opt_expand_cb_T opt_expand_cb; - - OptVal def_val; ///< default value - LastSet last_set; ///< script in which the option was last set -} vimoption_T; - /// flags for buf_copy_options() enum { BCO_ENTER = 1, ///< going to enter the buffer @@ -85,13 +35,6 @@ typedef enum { OPT_SKIPRTP = 0x80, ///< "skiprtp" in 'sessionoptions' } OptionSetFlags; -/// Return value from get_option_attrs(). -enum { - SOPT_GLOBAL = 0x01, ///< Option has global value - SOPT_WIN = 0x02, ///< Option has window-local value - SOPT_BUF = 0x04, ///< Option has buffer-local value -}; - /// Get name of OptValType as a string. static inline const char *optval_type_get_name(const OptValType type) { diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index e32edbf727..832e03148a 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -54,12 +54,20 @@ typedef enum { kOptValTypeNumber, kOptValTypeString, } OptValType; - /// Always update this whenever a new option type is added. #define kOptValTypeSize (kOptValTypeString + 1) - typedef uint32_t OptTypeFlags; +/// Scopes that an option can support. +typedef enum { + kOptScopeGlobal = 0, ///< Request global option value + kOptScopeWin, ///< Request window-local option value + kOptScopeBuf, ///< Request buffer-local option value +} OptScope; +/// Always update this whenever a new option scope is added. +#define kOptScopeSize (kOptScopeBuf + 1) +typedef uint8_t OptScopeFlags; + typedef union { // boolean options are actually tri-states because they have a third "None" value. TriState boolean; @@ -161,9 +169,26 @@ typedef struct { /// caller. typedef int (*opt_expand_cb_T)(optexpand_T *args, int *numMatches, char ***matches); -/// Requested option scopes for various functions in option.c -typedef enum { - kOptReqGlobal = 0, ///< Request global option value - kOptReqWin = 1, ///< Request window-local option value - kOptReqBuf = 2, ///< Request buffer-local option value -} OptReqScope; +typedef struct { + char *fullname; ///< full option name + char *shortname; ///< permissible abbreviation + uint32_t flags; ///< see above + OptTypeFlags type_flags; ///< option type flags, see OptValType + OptScopeFlags scope_flags; ///< option scope flags, see OptScope + void *var; ///< global option: pointer to variable; + ///< window-local option: NULL; + ///< buffer-local option: global value + ssize_t scope_idx[kOptScopeSize]; ///< index of option at every scope. + bool immutable; ///< option is immutable, trying to set it will give an error. + + /// callback function to invoke after an option is modified to validate and + /// apply the new value. + opt_did_set_cb_T opt_did_set_cb; + + /// callback function to invoke when expanding possible values on the + /// cmdline. Only useful for string options. + opt_expand_cb_T opt_expand_cb; + + OptVal def_val; ///< default value + LastSet last_set; ///< script in which the option was last set +} vimoption_T; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 6fab0621f9..baacb2b858 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7,7 +7,6 @@ --- @field alias? string|string[] --- @field short_desc? string|fun(): string --- @field varname? string ---- @field pv_name? string --- @field type vim.option_type|vim.option_type[] --- @field immutable? boolean --- @field list? 'comma'|'onecomma'|'commacolon'|'onecommacolon'|'flags'|'flagscomma' @@ -41,7 +40,7 @@ --- @field doc? string Default to show in options.txt --- @field meta? integer|boolean|string Default to use in Lua meta files ---- @alias vim.option_scope 'global'|'buffer'|'window' +--- @alias vim.option_scope 'global'|'buf'|'win' --- @alias vim.option_type 'boolean'|'number'|'string' --- @alias vim.option_value boolean|number|string @@ -81,6 +80,8 @@ end -- luacheck: ignore 621 return { cstr = cstr, + --- @type string[] + valid_scopes = { 'global', 'buf', 'win' }, --- @type vim.option_meta[] --- The order of the options MUST be alphabetic for ":set all". options = { @@ -173,7 +174,7 @@ return { ]=], full_name = 'arabic', redraw = { 'curswant' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('Arabic as a default second language'), type = 'boolean', }, @@ -236,7 +237,7 @@ return { a different way. ]=], full_name = 'autoindent', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('take indent for new line from previous line'), type = 'boolean', varname = 'p_ai', @@ -256,7 +257,7 @@ return { < ]=], full_name = 'autoread', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('autom. read file when changed outside of Vim'), type = 'boolean', varname = 'p_ar', @@ -457,7 +458,7 @@ return { expand_cb = 'expand_set_backupcopy', full_name = 'backupcopy', list = 'onecomma', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_("make backup as a copy, don't rename the file"), type = 'string', varname = 'p_bkc', @@ -667,7 +668,7 @@ return { ]=], full_name = 'binary', redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('read/write/edit file in binary mode'), type = 'boolean', varname = 'p_bin', @@ -695,7 +696,7 @@ return { full_name = 'bomb', no_mkrc = true, redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('a Byte Order Mark to the file'), type = 'boolean', varname = 'p_bomb', @@ -729,7 +730,7 @@ return { ]=], full_name = 'breakindent', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('wrapped line repeats indent'), type = 'boolean', }, @@ -771,7 +772,7 @@ return { full_name = 'breakindentopt', list = 'onecomma', redraw = { 'current_buffer' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_("settings for 'breakindent'"), type = 'string', }, @@ -823,7 +824,7 @@ return { expand_cb = 'expand_set_bufhidden', full_name = 'bufhidden', noglob = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('what to do when buffer is no longer in window'), type = 'string', varname = 'p_bh', @@ -841,7 +842,7 @@ return { ]=], full_name = 'buflisted', noglob = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('whether the buffer shows up in the buffer list'), tags = { 'E85' }, type = 'boolean', @@ -900,7 +901,7 @@ return { expand_cb = 'expand_set_buftype', full_name = 'buftype', noglob = true, - scope = { 'buffer' }, + scope = { 'buf' }, tags = { 'E382' }, short_desc = N_('special type of buffer'), type = 'string', @@ -1015,7 +1016,7 @@ return { full_name = 'channel', no_mkrc = true, nodefault = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('Channel connected to the buffer'), type = 'number', varname = 'p_channel', @@ -1093,7 +1094,7 @@ return { option or 'indentexpr'. ]=], full_name = 'cindent', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('do C program indenting'), type = 'boolean', varname = 'p_cin', @@ -1111,7 +1112,7 @@ return { ]=], full_name = 'cinkeys', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_("keys that trigger indent when 'cindent' is set"), type = 'string', varname = 'p_cink', @@ -1128,7 +1129,7 @@ return { ]=], full_name = 'cinoptions', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_("how to do indenting when 'cindent' is set"), type = 'string', varname = 'p_cino', @@ -1146,7 +1147,7 @@ return { ]=], full_name = 'cinscopedecls', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_("words that are recognized by 'cino-g'"), type = 'string', varname = 'p_cinsd', @@ -1165,7 +1166,7 @@ return { ]=], full_name = 'cinwords', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_("words where 'si' and 'cin' add an indent"), type = 'string', varname = 'p_cinw', @@ -1267,7 +1268,7 @@ return { full_name = 'colorcolumn', list = 'onecomma', redraw = { 'current_window', 'highlight_only' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('columns to highlight'), type = 'string', }, @@ -1312,7 +1313,7 @@ return { ]=], full_name = 'comments', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('patterns that can start a comment line'), tags = { 'E524', 'E525' }, type = 'string', @@ -1328,7 +1329,7 @@ return { Used for |commenting| and to add markers for folding, see |fold-marker|. ]=], full_name = 'commentstring', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('template for comments; used for fold marker'), tags = { 'E537' }, type = 'string', @@ -1385,7 +1386,7 @@ return { expand_cb = 'expand_set_complete', full_name = 'complete', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('specify how Insert mode completion works'), tags = { 'E535' }, type = 'string', @@ -1407,7 +1408,7 @@ return { ]=], full_name = 'completefunc', func = true, - scope = { 'buffer' }, + scope = { 'buf' }, secure = true, short_desc = N_('function to be used for Insert mode completion'), type = 'string', @@ -1483,7 +1484,7 @@ return { expand_cb = 'expand_set_completeopt', full_name = 'completeopt', list = 'onecomma', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('options for Insert mode completion'), type = 'string', varname = 'p_cot', @@ -1508,7 +1509,7 @@ return { enable_if = 'BACKSLASH_IN_FILENAME', expand_cb = 'expand_set_completeslash', full_name = 'completeslash', - scope = { 'buffer' }, + scope = { 'buf' }, type = 'string', varname = 'p_csl', }, @@ -1537,7 +1538,7 @@ return { full_name = 'concealcursor', list = 'flags', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('whether concealable text is hidden in cursor line'), type = 'string', }, @@ -1566,7 +1567,7 @@ return { ]=], full_name = 'conceallevel', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('whether concealable text is shown or hidden'), type = 'number', }, @@ -1604,7 +1605,7 @@ return { See 'preserveindent'. ]=], full_name = 'copyindent', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_("make 'autoindent' use existing indent structure"), type = 'boolean', varname = 'p_ci', @@ -1865,8 +1866,7 @@ return { taken into account. ]=], full_name = 'cursorbind', - pv_name = 'p_crbind', - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('move cursor in window as it moves in other windows'), type = 'boolean', }, @@ -1885,7 +1885,7 @@ return { ]=], full_name = 'cursorcolumn', redraw = { 'current_window', 'highlight_only' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('highlight the screen column of the cursor'), type = 'boolean', }, @@ -1900,7 +1900,7 @@ return { ]=], full_name = 'cursorline', redraw = { 'current_window', 'highlight_only' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('highlight the screen line of the cursor'), type = 'boolean', }, @@ -1928,7 +1928,7 @@ return { full_name = 'cursorlineopt', list = 'onecomma', redraw = { 'current_window', 'highlight_only' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_("settings for 'cursorline'"), type = 'string', }, @@ -1979,7 +1979,7 @@ return { < ]=], full_name = 'define', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('pattern to be used to find a macro definition'), type = 'string', varname = 'p_def', @@ -2036,7 +2036,7 @@ return { full_name = 'dictionary', list = 'onecomma', normal_dname_chars = true, - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('list of file names used for keyword completion'), type = 'string', varname = 'p_dict', @@ -2051,7 +2051,7 @@ return { full_name = 'diff', noglob = true, redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('diff mode for the current window'), type = 'boolean', }, @@ -2377,7 +2377,7 @@ return { full_name = 'endoffile', no_mkrc = true, redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('write CTRL-Z for last line in file'), type = 'boolean', varname = 'p_eof', @@ -2403,7 +2403,7 @@ return { full_name = 'endofline', no_mkrc = true, redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('write for last line in file'), type = 'boolean', varname = 'p_eol', @@ -2448,7 +2448,7 @@ return { ]=], expand = true, full_name = 'equalprg', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, secure = true, short_desc = N_('external program to use for "=" command'), type = 'string', @@ -2504,7 +2504,7 @@ return { ]=], full_name = 'errorformat', list = 'onecomma', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('description of the lines in the error file'), type = 'string', varname = 'p_efm', @@ -2540,7 +2540,7 @@ return { on, use CTRL-V. See also |:retab| and |ins-expandtab|. ]=], full_name = 'expandtab', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('use spaces when is inserted'), type = 'boolean', varname = 'p_et', @@ -2614,7 +2614,7 @@ return { full_name = 'fileencoding', no_mkrc = true, redraw = { 'statuslines', 'current_buffer' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('file encoding for multi-byte text'), tags = { 'E213' }, type = 'string', @@ -2710,7 +2710,7 @@ return { full_name = 'fileformat', no_mkrc = true, redraw = { 'curswant', 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('file format used for file I/O'), type = 'string', varname = 'p_ff', @@ -2829,7 +2829,7 @@ return { full_name = 'filetype', noglob = true, normal_fname_chars = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('type of file, used for autocommands'), type = 'string', varname = 'p_ft', @@ -2904,7 +2904,7 @@ return { full_name = 'fillchars', list = 'onecomma', redraw = { 'current_window' }, - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('characters to use for displaying special items'), type = 'string', varname = 'p_fcs', @@ -2962,7 +2962,7 @@ return { ]=], full_name = 'findfunc', func = true, - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, secure = true, short_desc = N_('function called for :find'), tags = { 'E1514' }, @@ -2984,7 +2984,7 @@ return { ]=], full_name = 'fixendofline', redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('make sure last line in file has '), type = 'boolean', varname = 'p_fixeol', @@ -3024,7 +3024,7 @@ return { expand_cb = 'expand_set_foldcolumn', full_name = 'foldcolumn', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('width of the column used to indicate folds'), type = 'string', }, @@ -3042,7 +3042,7 @@ return { ]=], full_name = 'foldenable', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('set to display all folds open'), type = 'boolean', }, @@ -3067,7 +3067,7 @@ return { full_name = 'foldexpr', modelineexpr = true, redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('expression used when \'foldmethod\' is "expr"'), type = 'string', }, @@ -3083,7 +3083,7 @@ return { ]=], full_name = 'foldignore', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('ignore lines when \'foldmethod\' is "indent"'), type = 'string', }, @@ -3100,7 +3100,7 @@ return { ]=], full_name = 'foldlevel', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('close folds with a level higher than this'), type = 'number', }, @@ -3139,7 +3139,7 @@ return { full_name = 'foldmarker', list = 'onecomma', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('markers used when \'foldmethod\' is "marker"'), tags = { 'E536' }, type = 'string', @@ -3160,7 +3160,7 @@ return { expand_cb = 'expand_set_foldmethod', full_name = 'foldmethod', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('folding type'), type = 'string', }, @@ -3179,7 +3179,7 @@ return { ]=], full_name = 'foldminlines', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('minimum number of lines for a fold to be closed'), type = 'number', }, @@ -3194,7 +3194,7 @@ return { ]=], full_name = 'foldnestmax', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('maximum fold depth'), type = 'number', }, @@ -3267,7 +3267,7 @@ return { full_name = 'foldtext', modelineexpr = true, redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('expression used to display for a closed fold'), type = 'string', }, @@ -3319,7 +3319,7 @@ return { ]=], full_name = 'formatexpr', modelineexpr = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('expression used with "gq" command'), type = 'string', varname = 'p_fex', @@ -3339,7 +3339,7 @@ return { character and white space. ]=], full_name = 'formatlistpat', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('pattern used to recognize a list header'), type = 'string', varname = 'p_flp', @@ -3359,7 +3359,7 @@ return { expand_cb = 'expand_set_formatoptions', full_name = 'formatoptions', list = 'flags', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('how automatic formatting is to be done'), type = 'string', varname = 'p_fo', @@ -3382,7 +3382,7 @@ return { ]=], expand = true, full_name = 'formatprg', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, secure = true, short_desc = N_('name of external program used with "gq" command'), type = 'string', @@ -3490,7 +3490,7 @@ return { ]=], expand = true, full_name = 'grepprg', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, secure = true, short_desc = N_('program to use for ":grep"'), type = 'string', @@ -4132,8 +4132,7 @@ return { It is also used for the argument of commands like "r" and "f". ]=], full_name = 'iminsert', - pv_name = 'p_imi', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('use :lmap or IM in Insert mode'), type = 'number', varname = 'p_iminsert', @@ -4155,8 +4154,7 @@ return { option to a valid keymap name. ]=], full_name = 'imsearch', - pv_name = 'p_ims', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('use :lmap or IM when typing a search pattern'), type = 'number', varname = 'p_imsearch', @@ -4203,7 +4201,7 @@ return { See |option-backslash| about including spaces and backslashes. ]=], full_name = 'include', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('pattern to be used to find an include file'), type = 'string', varname = 'p_inc', @@ -4245,7 +4243,7 @@ return { ]=], full_name = 'includeexpr', modelineexpr = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('expression used to process an include line'), type = 'string', varname = 'p_inex', @@ -4340,7 +4338,7 @@ return { ]=], full_name = 'indentexpr', modelineexpr = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('expression used to obtain the indent of a line'), type = 'string', varname = 'p_inde', @@ -4357,7 +4355,7 @@ return { ]=], full_name = 'indentkeys', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_("keys that trigger indenting with 'indentexpr'"), type = 'string', varname = 'p_indk', @@ -4376,7 +4374,7 @@ return { With 'noinfercase' the match is used as-is. ]=], full_name = 'infercase', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('adjust case of match for keyword completion'), type = 'boolean', varname = 'p_inf', @@ -4507,7 +4505,7 @@ return { ]=], full_name = 'iskeyword', list = 'comma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('characters included in keywords'), type = 'string', varname = 'p_isk', @@ -4608,9 +4606,8 @@ return { full_name = 'keymap', normal_fname_chars = true, pri_mkrc = true, - pv_name = 'p_kmap', redraw = { 'statuslines', 'current_buffer' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('name of a keyboard mapping'), type = 'string', varname = 'p_keymap', @@ -4662,7 +4659,7 @@ return { ]=], expand = true, full_name = 'keywordprg', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, secure = true, short_desc = N_('program to use for the "K" command'), type = 'string', @@ -4833,7 +4830,7 @@ return { ]=], full_name = 'linebreak', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('wrap long lines at a blank'), type = 'boolean', }, @@ -4897,7 +4894,7 @@ return { calling an external program if 'equalprg' is empty. ]=], full_name = 'lisp', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('indenting for Lisp'), type = 'boolean', varname = 'p_lisp', @@ -4919,8 +4916,7 @@ return { expand_cb = 'expand_set_lispoptions', full_name = 'lispoptions', list = 'onecomma', - pv_name = 'p_lop', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('options for lisp indenting'), type = 'string', varname = 'p_lop', @@ -4938,8 +4934,7 @@ return { ]=], full_name = 'lispwords', list = 'onecomma', - pv_name = 'p_lw', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('words that change how lisp indenting works'), type = 'string', varname = 'p_lispwords', @@ -4966,7 +4961,7 @@ return { ]=], full_name = 'list', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_(' and '), type = 'boolean', }, @@ -5077,7 +5072,7 @@ return { full_name = 'listchars', list = 'onecomma', redraw = { 'current_window' }, - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('characters for displaying in list mode'), type = 'string', varname = 'p_lcs', @@ -5158,7 +5153,7 @@ return { ]=], expand_cb = 'expand_set_encoding', full_name = 'makeencoding', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('Converts the output of external commands'), type = 'string', varname = 'p_menc', @@ -5185,7 +5180,7 @@ return { ]=], expand = true, full_name = 'makeprg', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, secure = true, short_desc = N_('program to use for the ":make" command'), type = 'string', @@ -5215,7 +5210,7 @@ return { ]=], full_name = 'matchpairs', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('pairs of characters that "%" can match'), type = 'string', varname = 'p_mps', @@ -5377,7 +5372,7 @@ return { no lines are checked. See |modeline|. ]=], full_name = 'modeline', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('recognize modelines at start or end of file'), type = 'boolean', varname = 'p_ml', @@ -5425,7 +5420,7 @@ return { ]=], full_name = 'modifiable', noglob = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('changes to the text are not possible'), tags = { 'E21' }, type = 'boolean', @@ -5461,7 +5456,7 @@ return { full_name = 'modified', no_mkrc = true, redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('buffer has been modified'), type = 'boolean', varname = 'p_mod', @@ -5821,7 +5816,7 @@ return { expand_cb = 'expand_set_nrformats', full_name = 'nrformats', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('number formats recognized for CTRL-A command'), type = 'string', varname = 'p_nf', @@ -5855,7 +5850,7 @@ return { ]=], full_name = 'number', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('print the line number in front of each line'), type = 'boolean', }, @@ -5877,7 +5872,7 @@ return { ]=], full_name = 'numberwidth', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('number of columns used for the line number'), type = 'number', }, @@ -5899,7 +5894,7 @@ return { ]=], full_name = 'omnifunc', func = true, - scope = { 'buffer' }, + scope = { 'buf' }, secure = true, short_desc = N_('function for filetype-specific completion'), type = 'string', @@ -6102,7 +6097,7 @@ return { expand = true, full_name = 'path', list = 'comma', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('list of directories searched with "gf" et.al.'), tags = { 'E343', 'E345', 'E347', 'E854' }, type = 'string', @@ -6126,7 +6121,7 @@ return { Use |:retab| to clean up white space. ]=], full_name = 'preserveindent', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('preserve the indent structure when reindenting'), type = 'boolean', varname = 'p_pi', @@ -6156,7 +6151,7 @@ return { full_name = 'previewwindow', noglob = true, redraw = { 'statuslines' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('identifies the preview window'), tags = { 'E590' }, type = 'boolean', @@ -6275,7 +6270,7 @@ return { text "foo\"bar\\" considered to be one string. ]=], full_name = 'quoteescape', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('escape characters used in a string'), type = 'string', varname = 'p_qe', @@ -6297,7 +6292,7 @@ return { full_name = 'readonly', noglob = true, redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('disallow writing the buffer'), type = 'boolean', varname = 'p_ro', @@ -6413,7 +6408,7 @@ return { ]=], full_name = 'relativenumber', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('show relative line number in front of each line'), type = 'boolean', }, @@ -6470,7 +6465,7 @@ return { ]=], full_name = 'rightleft', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('window is right-to-left oriented'), type = 'boolean', }, @@ -6490,7 +6485,7 @@ return { expand_cb = 'expand_set_rightleftcmd', full_name = 'rightleftcmd', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('commands for which editing works right-to-left'), type = 'string', }, @@ -6672,8 +6667,7 @@ return { ]=], full_name = 'scroll', no_mkrc = true, - pv_name = 'p_scroll', - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('lines to scroll with CTRL-U and CTRL-D'), type = 'number', }, @@ -6695,7 +6689,7 @@ return { ]=], full_name = 'scrollback', redraw = { 'current_buffer' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('lines to scroll with CTRL-U and CTRL-D'), type = 'number', varname = 'p_scbk', @@ -6716,8 +6710,7 @@ return { with scroll-binding, but ":split file" does not. ]=], full_name = 'scrollbind', - pv_name = 'p_scbind', - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('scroll in window as other windows scroll'), type = 'boolean', }, @@ -6754,7 +6747,7 @@ return { < For scrolling horizontally see 'sidescrolloff'. ]=], full_name = 'scrolloff', - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('minimum nr. of lines above and below cursor'), type = 'number', varname = 'p_so', @@ -7404,7 +7397,7 @@ return { function to get the effective shiftwidth value. ]=], full_name = 'shiftwidth', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('number of spaces to use for (auto)indent step'), type = 'number', varname = 'p_sw', @@ -7502,7 +7495,7 @@ return { ]=], full_name = 'showbreak', redraw = { 'all_windows' }, - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('string to use at the start of wrapped lines'), tags = { 'E595' }, type = 'string', @@ -7676,7 +7669,7 @@ return { < ]=], full_name = 'sidescrolloff', - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('min. nr. of columns to left and right of cursor'), type = 'number', varname = 'p_siso', @@ -7706,7 +7699,7 @@ return { expand_cb = 'expand_set_signcolumn', full_name = 'signcolumn', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('when to display the sign column'), type = 'string', }, @@ -7752,7 +7745,7 @@ return { right. ]=], full_name = 'smartindent', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('smart autoindenting for C programs'), type = 'boolean', varname = 'p_si', @@ -7792,9 +7785,8 @@ return { NOTE: partly implemented, doesn't work yet for |gj| and |gk|. ]=], full_name = 'smoothscroll', - pv_name = 'p_sms', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_("scroll by screen lines when 'wrap' is set"), type = 'boolean', }, @@ -7819,7 +7811,7 @@ return { to anything other than an empty string. ]=], full_name = 'softtabstop', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('number of spaces that uses while editing'), type = 'number', varname = 'p_sts', @@ -7833,7 +7825,7 @@ return { ]=], full_name = 'spell', redraw = { 'current_window', 'highlight_only' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('spell checking'), type = 'boolean', }, @@ -7854,7 +7846,7 @@ return { ]=], full_name = 'spellcapcheck', redraw = { 'current_buffer', 'highlight_only' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('pattern to locate end of a sentence'), type = 'string', varname = 'p_spc', @@ -7890,7 +7882,7 @@ return { expand = true, full_name = 'spellfile', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, secure = true, short_desc = N_('files where |zg| and |zw| store words'), type = 'string', @@ -7943,7 +7935,7 @@ return { full_name = 'spelllang', list = 'onecomma', redraw = { 'current_buffer', 'highlight_only' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('language(s) to do spell checking for'), type = 'string', varname = 'p_spl', @@ -7968,7 +7960,7 @@ return { full_name = 'spelloptions', list = 'onecomma', redraw = { 'current_buffer', 'highlight_only' }, - scope = { 'buffer' }, + scope = { 'buf' }, secure = true, type = 'string', varname = 'p_spo', @@ -8189,7 +8181,7 @@ return { ]=], full_name = 'statuscolumn', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, secure = true, short_desc = N_('custom format for the status column'), type = 'string', @@ -8413,7 +8405,7 @@ return { full_name = 'statusline', modelineexpr = true, redraw = { 'statuslines' }, - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('custom format for the status line'), tags = { 'E540', 'E542' }, type = 'string', @@ -8454,7 +8446,7 @@ return { ]=], full_name = 'suffixesadd', list = 'onecomma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('suffixes added when searching for a file'), type = 'string', varname = 'p_sua', @@ -8485,7 +8477,7 @@ return { ]=], full_name = 'swapfile', redraw = { 'statuslines' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('whether to use a swapfile for a buffer'), type = 'boolean', varname = 'p_swf', @@ -8545,7 +8537,7 @@ return { ]=], full_name = 'synmaxcol', redraw = { 'current_buffer' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('maximum column to find syntax items'), type = 'number', varname = 'p_smc', @@ -8582,7 +8574,7 @@ return { full_name = 'syntax', noglob = true, normal_fname_chars = true, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('syntax to be loaded for current buffer'), type = 'string', varname = 'p_syn', @@ -8705,7 +8697,7 @@ return { ]=], full_name = 'tabstop', redraw = { 'current_buffer' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('number of spaces that in file uses'), type = 'number', varname = 'p_ts', @@ -8784,7 +8776,7 @@ return { ]=], expand_cb = 'expand_set_tagcase', full_name = 'tagcase', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('how to handle case when searching in tags files'), type = 'string', varname = 'p_tc', @@ -8805,7 +8797,7 @@ return { ]=], full_name = 'tagfunc', func = true, - scope = { 'buffer' }, + scope = { 'buf' }, secure = true, short_desc = N_('function used to perform tag searches'), type = 'string', @@ -8862,7 +8854,7 @@ return { expand = true, full_name = 'tags', list = 'onecomma', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('list of file names used by the tag command'), tags = { 'E433' }, type = 'string', @@ -9002,7 +8994,7 @@ return { ]=], full_name = 'textwidth', redraw = { 'current_buffer', 'highlight_only' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('maximum width of text that is being inserted'), type = 'number', varname = 'p_tw', @@ -9031,7 +9023,7 @@ return { full_name = 'thesaurus', list = 'onecomma', normal_dname_chars = true, - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('list of thesaurus files for keyword completion'), type = 'string', varname = 'p_tsr', @@ -9051,7 +9043,7 @@ return { ]=], full_name = 'thesaurusfunc', func = true, - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, secure = true, short_desc = N_('function used for thesaurus completion'), type = 'string', @@ -9285,7 +9277,7 @@ return { When 'undofile' is turned off the undo file is NOT deleted. ]=], full_name = 'undofile', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('save undo information in a file'), type = 'boolean', varname = 'p_udf', @@ -9314,7 +9306,7 @@ return { Also see |clear-undo|. ]=], full_name = 'undolevels', - scope = { 'global', 'buffer' }, + scope = { 'global', 'buf' }, short_desc = N_('maximum number of changes that can be undone'), type = 'number', varname = 'p_ul', @@ -9401,7 +9393,7 @@ return { ]=], full_name = 'varsofttabstop', list = 'comma', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('list of numbers of spaces that uses while editing'), type = 'string', varname = 'p_vsts', @@ -9424,7 +9416,7 @@ return { full_name = 'vartabstop', list = 'comma', redraw = { 'current_buffer' }, - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('list of numbers of spaces that in file uses'), type = 'string', varname = 'p_vts', @@ -9570,7 +9562,7 @@ return { full_name = 'virtualedit', list = 'onecomma', redraw = { 'curswant' }, - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('when to use virtual editing'), type = 'string', varname = 'p_ve', @@ -9917,7 +9909,7 @@ return { full_name = 'winbar', modelineexpr = true, redraw = { 'statuslines' }, - scope = { 'global', 'window' }, + scope = { 'global', 'win' }, short_desc = N_('custom format for the window bar'), type = 'string', varname = 'p_wbr', @@ -9935,7 +9927,7 @@ return { ]=], full_name = 'winblend', redraw = { 'current_window', 'highlight_only' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('Controls transparency level for floating windows'), type = 'number', }, @@ -9974,8 +9966,7 @@ return { command has a "!" modifier, it can force switching buffers. ]=], full_name = 'winfixbuf', - pv_name = 'p_wfb', - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('pin a window to a specific buffer'), type = 'boolean', }, @@ -9990,7 +9981,7 @@ return { ]=], full_name = 'winfixheight', redraw = { 'statuslines' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('keep window height when opening/closing windows'), type = 'boolean', }, @@ -10004,7 +9995,7 @@ return { ]=], full_name = 'winfixwidth', redraw = { 'statuslines' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('keep window width when opening/closing windows'), type = 'boolean', }, @@ -10065,7 +10056,7 @@ return { full_name = 'winhighlight', list = 'onecommacolon', redraw = { 'current_window', 'highlight_only' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('Setup window-local highlights'), type = 'string', }, @@ -10156,7 +10147,7 @@ return { ]=], full_name = 'wrap', redraw = { 'current_window' }, - scope = { 'window' }, + scope = { 'win' }, short_desc = N_('lines wrap and continue on the next line'), type = 'boolean', }, @@ -10173,7 +10164,7 @@ return { See also 'formatoptions' and |ins-textwidth|. ]=], full_name = 'wrapmargin', - scope = { 'buffer' }, + scope = { 'buf' }, short_desc = N_('chars from the right where wrapping starts'), type = 'number', varname = 'p_wm', diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index 9095d4e8c9..06b3aa0411 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -863,7 +863,7 @@ int fex_format(linenr_T lnum, long count, int c) // Make a copy, the option could be changed while calling it. char *fex = xstrdup(curbuf->b_p_fex); - current_sctx = curbuf->b_p_script_ctx[BV_FEX].script_ctx; + current_sctx = curbuf->b_p_script_ctx[kBufOptFormatexpr].script_ctx; // Evaluate the function. if (use_sandbox) { diff --git a/src/nvim/window.c b/src/nvim/window.c index 5f17d3220d..c3f3e075f1 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6755,8 +6755,8 @@ void win_comp_scroll(win_T *wp) if (wp->w_p_scr != old_w_p_scr) { // Used by "verbose set scroll". - wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_sid = SID_WINLAYOUT; - wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_lnum = 0; + wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_sid = SID_WINLAYOUT; + wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_lnum = 0; } } diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 4698487708..b8a51d686d 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -412,8 +412,8 @@ win_T *win_float_create(bool enter, bool new_buf) return handle_error_and_cleanup(wp, &err); } buf->b_p_bl = false; // unlist - set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, kOptReqBuf, - buf); + set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, + kOptScopeBuf, buf); win_set_buf(wp, buf, &err); if (ERROR_SET(&err)) { return handle_error_and_cleanup(wp, &err); -- cgit From f85bc41c800d7f5c0256f29aa347a53600a7c8d5 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 17 Nov 2024 00:32:36 +0100 Subject: feat(ui): don't show unfocusable windows in :tabs, 'tabline' #27984 Problem: Floating windows with focusable set to false can reasonably be expected to be UI elements but are listed in some outputs that should contain only regular windows. Solution: Hide unfocusable floating windows from the default tabline and :tabs. --- src/nvim/api/win_config.c | 2 +- src/nvim/ex_docmd.c | 2 ++ src/nvim/statusline.c | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 16811e0cd9..6f5a9a90c0 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -130,7 +130,7 @@ /// - focusable: Enable focus by user actions (wincmds, mouse events). /// Defaults to true. Non-focusable windows can be entered by /// |nvim_set_current_win()|, or, when the `mouse` field is set to true, -/// by mouse events. +/// by mouse events. See |focusable|. /// - mouse: Specify how this window interacts with mouse events. /// Defaults to `focusable` value. /// - If false, mouse events pass through this window. diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e8b9470391..f5ecedf827 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5507,6 +5507,8 @@ static void ex_tabs(exarg_T *eap) FOR_ALL_WINDOWS_IN_TAB(wp, tp) { if (got_int) { break; + } else if (!wp->w_config.focusable) { + continue; } msg_putchar('\n'); diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index ba64633df7..4e78067d46 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -760,7 +760,9 @@ void draw_tabline(void) bool modified = false; for (wincount = 0; wp != NULL; wp = wp->w_next, wincount++) { - if (bufIsChanged(wp->w_buffer)) { + if (!wp->w_config.focusable) { + wincount--; + } else if (bufIsChanged(wp->w_buffer)) { modified = true; } } -- cgit From 9c718bc2bce53b5be45061bff940f99e50c8bfcb Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 17 Nov 2024 00:36:11 +0100 Subject: fix(api): validation, documentation of hl_group #31195 Problem: Documentation for "hl_group" in nvim_buf_set_extmark() is unclear. "hl_group" in nvim_echo() does not accept highlight group id. Solution: Move documentation for highlight group name/id to first mention of hl_group. Update nvim_echo() to accept highlight group id. --- src/nvim/api/extmark.c | 24 ++++++++++-------------- src/nvim/api/private/helpers.c | 23 +++++++++-------------- src/nvim/api/vim.c | 4 ++-- 3 files changed, 21 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 7786c30624..c94b8df9ea 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -381,8 +381,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// - id : id of the extmark to edit. /// - end_row : ending line of the mark, 0-based inclusive. /// - end_col : ending col of the mark, 0-based exclusive. -/// - hl_group : name of the highlight group used to highlight -/// this mark. +/// - hl_group : highlight group used for the text range. This and below +/// highlight groups can be supplied either as a string or as an integer, +/// the latter of which can be obtained using |nvim_get_hl_id_by_name()|. /// - hl_eol : when true, for a multiline highlight covering the /// EOL of a line, continue the highlight for the rest /// of the screen line (just like for diff and @@ -392,9 +393,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// text chunk with specified highlight. `highlight` element /// can either be a single highlight group, or an array of /// multiple highlight groups that will be stacked -/// (highest priority last). A highlight group can be supplied -/// either as a string or as an integer, the latter which -/// can be obtained using |nvim_get_hl_id_by_name()|. +/// (highest priority last). /// - virt_text_pos : position of virtual text. Possible values: /// - "eol": right after eol character (default). /// - "overlay": display over the specified column, without @@ -465,15 +464,12 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// buffer or end of the line respectively. Defaults to true. /// - sign_text: string of length 1-2 used to display in the /// sign column. -/// - sign_hl_group: name of the highlight group used to -/// highlight the sign column text. -/// - number_hl_group: name of the highlight group used to -/// highlight the number column. -/// - line_hl_group: name of the highlight group used to -/// highlight the whole line. -/// - cursorline_hl_group: name of the highlight group used to -/// highlight the sign column text when the cursor is on -/// the same line as the mark and 'cursorline' is enabled. +/// - sign_hl_group: highlight group used for the sign column text. +/// - number_hl_group: highlight group used for the number column. +/// - line_hl_group: highlight group used for the whole line. +/// - cursorline_hl_group: highlight group used for the sign +/// column text when the cursor is on the same line as the +/// mark and 'cursorline' is enabled. /// - conceal: string which should be either empty or a single /// character. Enable concealing similar to |:syn-conceal|. /// When a character is supplied it is used as |:syn-cchar|. diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d21caf7ed0..88e1664c04 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -771,7 +771,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err) int id = (int)obj.data.integer; return (1 <= id && id <= highlight_num_groups()) ? id : 0; } else { - api_set_error(err, kErrorTypeValidation, "Invalid highlight: %s", what); + api_set_error(err, kErrorTypeValidation, "Invalid hl_group: %s", what); return 0; } } @@ -809,27 +809,22 @@ HlMessage parse_hl_msg(Array chunks, Error *err) { HlMessage hl_msg = KV_INITIAL_VALUE; for (size_t i = 0; i < chunks.size; i++) { - if (chunks.items[i].type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, "Chunk is not an array"); + VALIDATE_T("chunk", kObjectTypeArray, chunks.items[i].type, { goto free_exit; - } + }); Array chunk = chunks.items[i].data.array; - if (chunk.size == 0 || chunk.size > 2 - || chunk.items[0].type != kObjectTypeString - || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) { - api_set_error(err, kErrorTypeValidation, - "Chunk is not an array with one or two strings"); + VALIDATE((chunk.size > 0 && chunk.size <= 2 && chunk.items[0].type == kObjectTypeString), + "%s", "Invalid chunk: expected Array with 1 or 2 Strings", { goto free_exit; - } + }); String str = copy_string(chunk.items[0].data.string, NULL); int hl_id = 0; if (chunk.size == 2) { - String hl = chunk.items[1].data.string; - if (hl.size > 0) { - // TODO(bfredl): use object_to_hl_id and allow integer - hl_id = syn_check_group(hl.data, hl.size); + hl_id = object_to_hl_id(chunk.items[1], "text highlight", err); + if (ERROR_SET(err)) { + goto free_exit; } } kv_push(hl_msg, ((HlMessageChunk){ .text = str, .hl_id = hl_id })); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 199b9a9690..89e974c098 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -779,8 +779,8 @@ void nvim_set_vvar(String name, Object value, Error *err) /// Echo a message. /// /// @param chunks A list of `[text, hl_group]` arrays, each representing a -/// text chunk with specified highlight. `hl_group` element -/// can be omitted for no highlight. +/// text chunk with specified highlight group name or ID. +/// `hl_group` element can be omitted for no highlight. /// @param history if true, add to |message-history|. /// @param opts Optional parameters. /// - verbose: Message is printed as a result of 'verbose' option. -- cgit From 10beeee06f75941877199c192d45866029cdf5bf Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 17 Nov 2024 12:49:09 +0100 Subject: build(deps): bump uncrustify to uncrustify-0.80.1 --- src/uncrustify.cfg | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg index a3b0c4a9a5..91a72fa318 100644 --- a/src/uncrustify.cfg +++ b/src/uncrustify.cfg @@ -1,4 +1,4 @@ -# Uncrustify-0.80.0_f +# Uncrustify-0.80.1_f # # General options @@ -1138,12 +1138,6 @@ sp_string_string = force # ignore/add/remove/force # Add or remove space 'struct' and a type. sp_struct_type = ignore # ignore/add/remove/force -# Add or remove space between '_Pragma' and the opening paarenthesis -sp_pragma_open_parenthesis = ignore # ignore/add/remove/force - -# Add or remove space inside '(' and ')' of _Pragma. -sp_inside_gparen = ignore # ignore/add/remove/force - # # Indenting options # -- cgit From 6ea45031d5841d3227c545f213d0903b951e40be Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 17 Nov 2024 15:06:44 +0100 Subject: fix(api): nvim_echo free text memory with invalid highlight (#31243) Fix regression from #31195 --- src/nvim/api/private/helpers.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 88e1664c04..8ddaecc58e 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -823,9 +823,6 @@ HlMessage parse_hl_msg(Array chunks, Error *err) int hl_id = 0; if (chunk.size == 2) { hl_id = object_to_hl_id(chunk.items[1], "text highlight", err); - if (ERROR_SET(err)) { - goto free_exit; - } } kv_push(hl_msg, ((HlMessageChunk){ .text = str, .hl_id = hl_id })); } -- cgit From e025f5a5b30a1ef92e88fed0f0c548d2240d30c0 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 17 Nov 2024 19:21:50 +0100 Subject: fix(messages): proper multiline Lua print() messages #31205 Problem: Separate message emitted for each newline present in Lua print() arguments. Solution: Make msg_multiline() handle NUL bytes. Refactor print() to use msg_multiline(). Refactor vim.print() to use print(). --- src/nvim/eval.c | 2 +- src/nvim/ex_cmds.c | 4 ++-- src/nvim/lua/executor.c | 39 ++++----------------------------------- src/nvim/message.c | 39 +++++++++++++++++++-------------------- 4 files changed, 26 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ab6115f145..ef6e0940cf 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7881,7 +7881,7 @@ void ex_echo(exarg_T *eap) char *tofree = encode_tv2echo(&rettv, NULL); if (*tofree != NUL) { msg_ext_set_kind("echo"); - msg_multiline(tofree, echo_hl_id, true, false, &need_clear); + msg_multiline(cstr_as_string(tofree), echo_hl_id, true, false, &need_clear); } xfree(tofree); } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index e937961b44..8cccf08e11 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -189,7 +189,7 @@ void do_ascii(exarg_T *eap) transchar(c), buf1, buf2, cval, cval, cval); } - msg_multiline(IObuff, 0, true, false, &need_clear); + msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear); off += (size_t)utf_ptr2len(data); // needed for overlong ascii? } @@ -224,7 +224,7 @@ void do_ascii(exarg_T *eap) c, c, c); } - msg_multiline(IObuff, 0, true, false, &need_clear); + msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear); off += (size_t)utf_ptr2len(data + off); // needed for overlong ascii? } diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 15f70fb725..c4fa8b0fff 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -954,41 +954,10 @@ static void nlua_common_free_all_mem(lua_State *lstate) static void nlua_print_event(void **argv) { - char *str = argv[0]; - const size_t len = (size_t)(intptr_t)argv[1] - 1; // exclude final NUL - - for (size_t i = 0; i < len;) { - if (got_int) { - break; - } - const size_t start = i; - while (i < len) { - switch (str[i]) { - case NUL: - str[i] = NL; - i++; - continue; - case NL: - // TODO(bfredl): use proper multiline msg? Probably should implement - // print() in lua in terms of nvim_message(), when it is available. - str[i] = NUL; - i++; - break; - default: - i++; - continue; - } - break; - } - msg(str + start, 0); - if (msg_silent == 0) { - msg_didout = true; // Make blank lines work properly - } - } - if (len && str[len - 1] == NUL) { // Last was newline - msg("", 0); - } - xfree(str); + HlMessage msg = KV_INITIAL_VALUE; + HlMessageChunk chunk = { { .data = argv[0], .size = (size_t)(intptr_t)argv[1] - 1 }, 0 }; + kv_push(msg, chunk); + msg_multihl(msg, "lua_print", true); } /// Print as a Vim message diff --git a/src/nvim/message.c b/src/nvim/message.c index e8f20916b8..47f33c8967 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -249,35 +249,33 @@ bool msg(const char *s, const int hl_id) return msg_hl_keep(s, hl_id, false, false); } -/// Similar to msg_outtrans, but support newlines and tabs. -void msg_multiline(const char *s, int hl_id, bool check_int, bool hist, bool *need_clear) +/// Similar to msg_outtrans_len, but support newlines and tabs. +void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_clear) FUNC_ATTR_NONNULL_ALL { - const char *next_spec = s; - - while (next_spec != NULL) { + const char *s = str.data; + const char *chunk = s; + while ((size_t)(s - str.data) < str.size) { if (check_int && got_int) { return; } - next_spec = strpbrk(s, "\t\n\r"); - - if (next_spec != NULL) { - // Printing all char that are before the char found by strpbrk - msg_outtrans_len(s, (int)(next_spec - s), hl_id, hist); + if (*s == '\n' || *s == TAB || *s == '\r') { + // Print all chars before the delimiter + msg_outtrans_len(chunk, (int)(s - chunk), hl_id, hist); - if (*next_spec != TAB && *need_clear) { + if (*s != TAB && *need_clear) { msg_clr_eos(); *need_clear = false; } - msg_putchar_hl((uint8_t)(*next_spec), hl_id); - s = next_spec + 1; + msg_putchar_hl((uint8_t)(*s), hl_id); + chunk = s + 1; } + s++; } - // Print the rest of the message. We know there is no special - // character because strpbrk returned NULL - if (*s != NUL) { - msg_outtrans(s, hl_id, hist); + // Print the rest of the message + if (*chunk != NUL) { + msg_outtrans_len(chunk, (int)(str.size - (size_t)(chunk - str.data)), hl_id, hist); } } @@ -290,7 +288,7 @@ void msg_multihl(HlMessage hl_msg, const char *kind, bool history) msg_ext_set_kind(kind); for (uint32_t i = 0; i < kv_size(hl_msg); i++) { HlMessageChunk chunk = kv_A(hl_msg, i); - msg_multiline(chunk.text.data, chunk.hl_id, true, false, &need_clear); + msg_multiline(chunk.text, chunk.hl_id, true, false, &need_clear); } if (history && kv_size(hl_msg)) { add_msg_hist_multihl(NULL, 0, 0, true, hl_msg); @@ -349,7 +347,7 @@ bool msg_hl_keep(const char *s, int hl_id, bool keep, bool multiline) bool need_clear = true; if (multiline) { - msg_multiline(s, hl_id, false, false, &need_clear); + msg_multiline(cstr_as_string(s), hl_id, false, false, &need_clear); } else { msg_outtrans(s, hl_id, false); } @@ -2689,12 +2687,13 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen) // primitive way to compute the current column if (*s == '\r' || *s == '\n') { msg_col = 0; + msg_didout = false; } else { msg_col += cw; + msg_didout = true; } s += len; } - msg_didout = true; // assume that line is not empty } /// Show the more-prompt and handle the user response. -- cgit From 235cb5bc5f2553f5a46807267b8705e53f7a14af Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 17 Nov 2024 20:43:36 +0100 Subject: fix(api): update "range" windows in nvim__redraw #31042 Problem: nvim__redraw's "range" marks a buffer range for redraw, and subsequently flushes the UI without updating the windows containing that buffer. Solution: Implicitly update the screen, unless specified otherwise. Only update the screen with the last call of the treesitter on_changedtree() callback. --- src/nvim/api/vim.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 89e974c098..0d562f2276 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2396,13 +2396,13 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) last = rbuf->b_ml.ml_line_count; } redraw_buf_range_later(rbuf, first, last); + opts->flush = HAS_KEY(opts, redraw, flush) ? opts->flush : true; } - bool flush = opts->flush; if (opts->tabline) { // Flush later in case tabline was just hidden or shown for the first time. if (redraw_tabline && firstwin->w_lines_valid == 0) { - flush = true; + opts->flush = true; } else { draw_tabline(); } @@ -2416,23 +2416,23 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) if (win == NULL) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (buf == NULL || wp->w_buffer == buf) { - redraw_status(wp, opts, &flush); + redraw_status(wp, opts, &opts->flush); } } } else { - redraw_status(win, opts, &flush); + redraw_status(win, opts, &opts->flush); } } win_T *cwin = win ? win : curwin; // Allow moving cursor to recently opened window and make sure it is drawn #28868. if (opts->cursor && (!cwin->w_grid.target || !cwin->w_grid.target->valid)) { - flush = true; + opts->flush = true; } // Redraw pending screen updates when explicitly requested or when determined // that it is necessary to properly draw other requested components. - if (flush && !cmdpreview) { + if (opts->flush && !cmdpreview) { update_screen(); } -- cgit From 44229bb85b6cff00193164967126d85a7a785a7b Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 17 Nov 2024 12:31:32 -0800 Subject: feat(lsp): highlight hover target/range #31110 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem:** Despite the LSP providing the option for language servers to specify a range with a hover response (for highlighting), Neovim does not give the option to highlight this range. **Solution:** Add an option to `buf.hover()` which causes this range to be highlighted. Co-authored-by: Mathias Fußenegger --- src/nvim/highlight_group.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 65641f120f..b3c4aca1af 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -215,6 +215,7 @@ static const char *highlight_init_both[] = { "default link LspReferenceRead LspReferenceText", "default link LspReferenceText Visual", "default link LspReferenceWrite LspReferenceText", + "default link LspReferenceTarget LspReferenceText", "default link LspSignatureActiveParameter Visual", "default link SnippetTabstop Visual", -- cgit From 1763eddede82697a081d8741bd7e780c1b729de0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 18 Nov 2024 09:52:11 +0800 Subject: vim-patch:9.1.0869: Problem: curswant not set on gm in folded line (#31247) Problem: curswant not set on gm in folded line (citizenmatt) Solution: in a folded line, call update_curswant_force() fixes: vim/vim#11596 closes: vim/vim#11994 closes: vim/vim#15398 https://github.com/vim/vim/commit/9848face747ba91282d34a96dcb966bcb410bf2b Co-authored-by: Christian Brabandt --- src/nvim/normal.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/nvim/normal.c b/src/nvim/normal.c index d2716bf236..55aa385b33 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -5249,6 +5249,12 @@ void nv_g_home_m_cmd(cmdarg_T *cap) curwin->w_valid &= ~VALID_WCOL; } curwin->w_set_curswant = true; + if (hasAnyFolding(curwin)) { + validate_cheight(curwin); + if (curwin->w_cline_folded) { + update_curswant_force(); + } + } adjust_skipcol(); } -- cgit From 40347f6e27f1594797ecb0b268076a94630e4c1b Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Mon, 18 Nov 2024 15:35:21 +0100 Subject: fix(api): only flush nvim__redraw when necessary #31250 Problem: Not possible to only set a "redraw later" type with nvim__redraw, which seems to be desired for the treesitter highlighter. Solution: Do not update the screen when "flush" is explicitly set to false and only redraw later types are present. In that case, do not call ui_flush() either. --- src/nvim/api/vim.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 0d562f2276..83f9aa573d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2396,9 +2396,16 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) last = rbuf->b_ml.ml_line_count; } redraw_buf_range_later(rbuf, first, last); + } + + // Redraw later types require update_screen() so call implicitly unless set to false. + if (HAS_KEY(opts, redraw, valid) || HAS_KEY(opts, redraw, range)) { opts->flush = HAS_KEY(opts, redraw, flush) ? opts->flush : true; } + // When explicitly set to false and only "redraw later" types are present, + // don't call ui_flush() either. + bool flush_ui = opts->flush; if (opts->tabline) { // Flush later in case tabline was just hidden or shown for the first time. if (redraw_tabline && firstwin->w_lines_valid == 0) { @@ -2406,6 +2413,7 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } else { draw_tabline(); } + flush_ui = true; } bool save_lz = p_lz; @@ -2422,6 +2430,7 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } else { redraw_status(win, opts, &opts->flush); } + flush_ui = true; } win_T *cwin = win ? win : curwin; @@ -2438,9 +2447,12 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) if (opts->cursor) { setcursor_mayforce(cwin, true); + flush_ui = true; } - ui_flush(); + if (flush_ui) { + ui_flush(); + } RedrawingDisabled = save_rd; p_lz = save_lz; -- cgit From e2ad251c8d01726ecd54d925b5280ab32b448c13 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Mon, 18 Nov 2024 15:40:51 +0100 Subject: fix(api): nvim_get_option_value does not clean up on FileType error #31219 Problem: If there's an error in `FileType` autocmd, the filetype get-opt buffer doesn't get cleaned up. Solution: Call `aucmd_restbuf`. --- src/nvim/api/options.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index bbfd00f2ea..3289daeb6f 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -165,6 +165,14 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) buf_T *ftbuf = do_ft_buf(filetype, &aco, err); if (ERROR_SET(err)) { + if (ftbuf != NULL) { + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + + assert(curbuf != ftbuf); // safety check + wipe_buffer(ftbuf, false); + } + return (Object)OBJECT_INIT; } -- cgit From 0183c3247455a4c2364e5e78d6b716e98ef16aeb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 19 Nov 2024 19:03:29 +0800 Subject: vim-patch:9.1.0870: too many strlen() calls in eval.c (#31267) Problem: too many strlen() calls in eval.c Solution: Refactor eval.c to remove calls to STRLEN() (John Marriott) closes: vim/vim#16066 https://github.com/vim/vim/commit/bd4614f43d0eac4aff743132bab8e53b015ac801 Co-authored-by: John Marriott --- src/nvim/eval.c | 50 +++++++++++++++++++++++++++++++------------------- src/nvim/eval/funcs.c | 4 ++-- 2 files changed, 33 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ef6e0940cf..35f0bde871 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -922,13 +922,12 @@ int eval_expr_typval(const typval_T *expr, bool want_func, typval_T *argv, int a { if (expr->v_type == VAR_PARTIAL) { return eval_expr_partial(expr, argv, argc, rettv); - } else if (expr->v_type == VAR_FUNC || want_func) { + } + if (expr->v_type == VAR_FUNC || want_func) { return eval_expr_func(expr, argv, argc, rettv); - } else { - return eval_expr_string(expr, rettv); } - return OK; + return eval_expr_string(expr, rettv); } /// Like eval_to_bool() but using a typval_T instead of a string. @@ -1982,7 +1981,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, bool copy, const bool // handle +=, -=, *=, /=, %= and .= di = NULL; - if (eval_variable(lp->ll_name, (int)strlen(lp->ll_name), + if (eval_variable(lp->ll_name, (int)lp->ll_name_len, &tv, &di, true, false) == OK) { if ((di == NULL || (!var_check_ro(di->di_flags, lp->ll_name, TV_CSTRING) @@ -6857,11 +6856,11 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex char *temp_result = eval_to_string(expr_start + 1, false, false); if (temp_result != NULL) { - retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start) - + (size_t)(in_end - expr_end) + 1); - STRCPY(retval, in_start); - strcat(retval, temp_result); - strcat(retval, expr_end + 1); + size_t retvalsize = (size_t)(expr_start - in_start) + + strlen(temp_result) + + (size_t)(in_end - expr_end) + 1; + retval = xmalloc(retvalsize); + vim_snprintf(retval, retvalsize, "%s%s%s", in_start, temp_result, expr_end + 1); } xfree(temp_result); @@ -8350,9 +8349,10 @@ repeat: char *const sub = xmemdupz(s, (size_t)(p - s)); char *const str = xmemdupz(*fnamep, *fnamelen); *usedlen = (size_t)(p + 1 - src); - s = do_string_sub(str, pat, sub, NULL, flags); + size_t slen; + s = do_string_sub(str, *fnamelen, pat, sub, NULL, flags, &slen); *fnamep = s; - *fnamelen = strlen(s); + *fnamelen = slen; xfree(*bufp); *bufp = s; didit = true; @@ -8391,12 +8391,14 @@ repeat: /// When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL. /// "flags" can be "g" to do a global substitute. /// +/// @param ret_len length of returned buffer +/// /// @return an allocated string, NULL for error. -char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char *flags) +char *do_string_sub(char *str, size_t len, char *pat, char *sub, typval_T *expr, const char *flags, + size_t *ret_len) { regmatch_T regmatch; garray_T ga; - char *zero_width = NULL; // Make 'cpoptions' empty, so that the 'l' flag doesn't work here char *save_cpo = p_cpo; @@ -8404,14 +8406,15 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char ga_init(&ga, 1, 200); - int do_all = (flags[0] == 'g'); - regmatch.rm_ic = p_ic; regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { - int sublen; char *tail = str; - char *end = str + strlen(str); + char *end = str + len; + bool do_all = (flags[0] == 'g'); + int sublen; + char *zero_width = NULL; + while (vim_regexec_nl(®match, str, (colnr_T)(tail - str))) { // Skip empty match except for first match. if (regmatch.startp[0] == regmatch.endp[0]) { @@ -8458,12 +8461,17 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char if (ga.ga_data != NULL) { STRCPY((char *)ga.ga_data + ga.ga_len, tail); + ga.ga_len += (int)(end - tail); } vim_regfree(regmatch.regprog); } - char *ret = xstrdup(ga.ga_data == NULL ? str : ga.ga_data); + if (ga.ga_data != NULL) { + str = ga.ga_data; + len = (size_t)ga.ga_len; + } + char *ret = xstrnsave(str, len); ga_clear(&ga); if (p_cpo == empty_string_option) { p_cpo = save_cpo; @@ -8477,6 +8485,10 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char free_string_option(save_cpo); } + if (ret_len != NULL) { + *ret_len = len; + } + return ret; } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4828d67428..717280642d 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7848,8 +7848,8 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) || flg == NULL) { rettv->vval.v_string = NULL; } else { - rettv->vval.v_string = do_string_sub((char *)str, (char *)pat, - (char *)sub, expr, (char *)flg); + rettv->vval.v_string = do_string_sub((char *)str, strlen(str), (char *)pat, + (char *)sub, expr, (char *)flg, NULL); } } -- cgit