diff options
33 files changed, 540 insertions, 319 deletions
diff --git a/ci/build.ps1 b/ci/build.ps1 index 08fc76393d..dbc43aecf3 100644 --- a/ci/build.ps1 +++ b/ci/build.ps1 @@ -91,7 +91,14 @@ if ($compiler -eq 'MINGW') { & C:\msys64\usr\bin\mkdir -p /var/cache/pacman/pkg # Build third-party dependencies - C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" ; exitIfFailed + C:\msys64\usr\bin\bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" ; exitIfFailed + C:\msys64\usr\bin\bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig" ; exitIfFailed + C:\msys64\usr\bin\bash -lc "pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig" ; exitIfFailed + C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -U msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" ; exitIfFailed + # If there are still processes using msys-2.0.dll, after the base system update is finished, it will wait for input from the user. + # To prevent this, we will terminate all processes that use msys-2.0.dll. + Get-Process | Where-Object { $_.path -like 'C:\msys64*' } | Stop-Process + C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Syu" ; exitIfFailed C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S $mingwPackages" ; exitIfFailed } elseif ($compiler -eq 'MSVC') { diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 448df31798..b83d2c4484 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2918,6 +2918,8 @@ A jump table for the options with a short description can be found at |Q_op|. *'go-c'* 'c' Use console dialogs instead of popup dialogs for simple choices. + *'go-d'* + 'd' Use dark theme variant if available. *'go-e'* 'e' Add tab pages when indicated with 'showtabline'. 'guitablabel' can be used to change the text in the labels. @@ -5795,7 +5797,7 @@ A jump table for the options with a short description can be found at |Q_op|. normal text. Each status line item is of the form: %-0{minwid}.{maxwid}{item} All fields except the {item} are optional. A single percent sign can - be given as "%%". Up to 80 items can be specified. *E541* + be given as "%%". When the option starts with "%!" then it is used as an expression, evaluated and the result is used as the option value. Example: > diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 7f644486f7..aaf13d1640 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -136,6 +136,15 @@ tsnode:has_error() *tsnode:has_error()* tsnode:sexpr() *tsnode:sexpr()* Get an S-expression representing the node as a string. +tsnode:id() *tsnode:id()* + Get an unique identier for the node inside its own tree. + + No guarantees are made about this identifer's internal representation, + except for being a primitive lua type with value equality (so not a table). + Presently it is a (non-printable) string. + + NB: the id is not guaranteed to be unique for nodes from different trees. + tsnode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col}) *tsnode:descendant_for_range()* Get the smallest node within this node that spans the given range of diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 2773f59b45..70862320c5 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -632,15 +632,18 @@ function protocol.make_client_capabilities() codeActionLiteralSupport = { codeActionKind = { - valueSet = {}; + valueSet = vim.tbl_values(protocol.CodeActionKind); }; }; }; completion = { dynamicRegistration = false; completionItem = { + -- Until we can actually expand snippet, move cursor and allow for true snippet experience, + -- this should be disabled out of the box. + -- However, users can turn this back on if they have a snippet plugin. + snippetSupport = false; - snippetSupport = true; commitCharactersSupport = false; preselectSupport = false; deprecatedSupport = false; @@ -940,11 +943,9 @@ function protocol.resolve_capabilities(server_capabilities) if server_capabilities.codeActionProvider == nil then general_properties.code_action = false - elseif type(server_capabilities.codeActionProvider) == 'boolean' then + elseif type(server_capabilities.codeActionProvider) == 'boolean' + or type(server_capabilities.codeActionProvider) == 'table' then general_properties.code_action = server_capabilities.codeActionProvider - elseif type(server_capabilities.codeActionProvider) == 'table' then - -- TODO(ashkan) support CodeActionKind - general_properties.code_action = false else error("The server sent invalid codeActionProvider") end diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index decde08019..6714bb6354 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -157,7 +157,7 @@ local function on_line_impl(self, buf, line) a.nvim_buf_set_extmark(buf, ns, start_row, start_col, { end_line = end_row, end_col = end_col, hl_group = hl, - ephemeral = true + ephemeral = true, }) end if start_row > line then diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 9cd2fd4beb..469542ec9f 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3440,31 +3440,17 @@ int build_stl_str_hl( int use_sandbox, char_u fillchar, int maxwidth, - struct stl_hlrec *hltab, - StlClickRecord *tabtab + stl_hlrec_t **hltab, + StlClickRecord **tabtab ) { - int groupitems[STL_MAX_ITEM]; - struct stl_item { - // Where the item starts in the status line output buffer - char_u *start; - // Function to run for ClickFunc items. - char *cmd; - // The minimum width of the item - int minwid; - // The maximum width of the item - int maxwid; - enum { - Normal, - Empty, - Group, - Separate, - Highlight, - TabPage, - ClickFunc, - Trunc - } type; - } items[STL_MAX_ITEM]; + static size_t stl_items_len = 20; // Initial value, grows as needed. + static stl_item_t *stl_items = NULL; + static int *stl_groupitems = NULL; + static stl_hlrec_t *stl_hltab = NULL; + static StlClickRecord *stl_tabtab = NULL; + static int *stl_separator_locations = NULL; + #define TMPLEN 70 char_u buf_tmp[TMPLEN]; char_u win_tmp[TMPLEN]; @@ -3472,6 +3458,14 @@ int build_stl_str_hl( const int save_must_redraw = must_redraw; const int save_redr_type = curwin->w_redr_type; + if (stl_items == NULL) { + stl_items = xmalloc(sizeof(stl_item_t) * stl_items_len); + stl_groupitems = xmalloc(sizeof(int) * stl_items_len); + stl_hltab = xmalloc(sizeof(stl_hlrec_t) * stl_items_len); + stl_tabtab = xmalloc(sizeof(stl_hlrec_t) * stl_items_len); + stl_separator_locations = xmalloc(sizeof(int) * stl_items_len); + } + // When the format starts with "%!" then evaluate it as an expression and // use the result as the actual format string. if (fmt[0] == '%' && fmt[1] == '!') { @@ -3540,14 +3534,17 @@ int build_stl_str_hl( // Proceed character by character through the statusline format string // fmt_p is the current positon in the input buffer for (char_u *fmt_p = usefmt; *fmt_p; ) { - if (curitem == STL_MAX_ITEM) { - // There are too many items. Add the error code to the statusline - // to give the user a hint about what went wrong. - if (out_p + 5 < out_end_p) { - memmove(out_p, " E541", (size_t)5); - out_p += 5; - } - break; + if (curitem == (int)stl_items_len) { + size_t new_len = stl_items_len * 3 / 2; + + stl_items = xrealloc(stl_items, sizeof(stl_item_t) * new_len); + stl_groupitems = xrealloc(stl_groupitems, sizeof(int) * new_len); + stl_hltab = xrealloc(stl_hltab, sizeof(stl_hlrec_t) * new_len); + stl_tabtab = xrealloc(stl_tabtab, sizeof(StlClickRecord) * new_len); + stl_separator_locations = + xrealloc(stl_separator_locations, sizeof(int) * new_len); + + stl_items_len = new_len; } if (*fmt_p != NUL && *fmt_p != '%') { @@ -3591,16 +3588,16 @@ int build_stl_str_hl( if (groupdepth > 0) { continue; } - items[curitem].type = Separate; - items[curitem++].start = out_p; + stl_items[curitem].type = Separate; + stl_items[curitem++].start = out_p; continue; } // STL_TRUNCMARK: Where to begin truncating if the statusline is too long. if (*fmt_p == STL_TRUNCMARK) { fmt_p++; - items[curitem].type = Trunc; - items[curitem++].start = out_p; + stl_items[curitem].type = Trunc; + stl_items[curitem++].start = out_p; continue; } @@ -3616,7 +3613,7 @@ int build_stl_str_hl( // Determine how long the group is. // Note: We set the current output position to null // so `vim_strsize` will work. - char_u *t = items[groupitems[groupdepth]].start; + char_u *t = stl_items[stl_groupitems[groupdepth]].start; *out_p = NUL; long group_len = vim_strsize(t); @@ -3626,40 +3623,40 @@ int build_stl_str_hl( // move the output pointer back to where the group started. // Note: This erases any non-item characters that were in the group. // Otherwise there would be no reason to do this step. - if (curitem > groupitems[groupdepth] + 1 - && items[groupitems[groupdepth]].minwid == 0) { + if (curitem > stl_groupitems[groupdepth] + 1 + && stl_items[stl_groupitems[groupdepth]].minwid == 0) { // remove group if all items are empty and highlight group // doesn't change int group_start_userhl = 0; int group_end_userhl = 0; int n; - for (n = groupitems[groupdepth] - 1; n >= 0; n--) { - if (items[n].type == Highlight) { - group_start_userhl = group_end_userhl = items[n].minwid; + for (n = stl_groupitems[groupdepth] - 1; n >= 0; n--) { + if (stl_items[n].type == Highlight) { + group_start_userhl = group_end_userhl = stl_items[n].minwid; break; } } - for (n = groupitems[groupdepth] + 1; n < curitem; n++) { - if (items[n].type == Normal) { + for (n = stl_groupitems[groupdepth] + 1; n < curitem; n++) { + if (stl_items[n].type == Normal) { break; } - if (items[n].type == Highlight) { - group_end_userhl = items[n].minwid; + if (stl_items[n].type == Highlight) { + group_end_userhl = stl_items[n].minwid; } } if (n == curitem && group_start_userhl == group_end_userhl) { // empty group out_p = t; group_len = 0; - for (n = groupitems[groupdepth] + 1; n < curitem; n++) { + for (n = stl_groupitems[groupdepth] + 1; n < curitem; n++) { // do not use the highlighting from the removed group - if (items[n].type == Highlight) { - items[n].type = Empty; + if (stl_items[n].type == Highlight) { + stl_items[n].type = Empty; } // adjust the start position of TabPage to the next // item position - if (items[n].type == TabPage) { - items[n].start = out_p; + if (stl_items[n].type == TabPage) { + stl_items[n].start = out_p; } } } @@ -3667,18 +3664,19 @@ int build_stl_str_hl( // If the group is longer than it is allowed to be // truncate by removing bytes from the start of the group text. - if (group_len > items[groupitems[groupdepth]].maxwid) { + if (group_len > stl_items[stl_groupitems[groupdepth]].maxwid) { // { Determine the number of bytes to remove long n; if (has_mbyte) { // Find the first character that should be included. n = 0; - while (group_len >= items[groupitems[groupdepth]].maxwid) { + while (group_len >= stl_items[stl_groupitems[groupdepth]].maxwid) { group_len -= ptr2cells(t + n); n += (*mb_ptr2len)(t + n); } } else { - n = (long)(out_p - t) - items[groupitems[groupdepth]].maxwid + 1; + n = (long)(out_p - t) + - stl_items[stl_groupitems[groupdepth]].maxwid + 1; } // } @@ -3689,25 +3687,26 @@ int build_stl_str_hl( memmove(t + 1, t + n, (size_t)(out_p - (t + n))); out_p = out_p - n + 1; // Fill up space left over by half a double-wide char. - while (++group_len < items[groupitems[groupdepth]].minwid) { + while (++group_len < stl_items[stl_groupitems[groupdepth]].minwid) { *out_p++ = fillchar; } // } // correct the start of the items for the truncation - for (int idx = groupitems[groupdepth] + 1; idx < curitem; idx++) { + for (int idx = stl_groupitems[groupdepth] + 1; idx < curitem; idx++) { // Shift everything back by the number of removed bytes - items[idx].start -= n; + stl_items[idx].start -= n; // If the item was partially or completely truncated, set its // start to the start of the group - if (items[idx].start < t) { - items[idx].start = t; + if (stl_items[idx].start < t) { + stl_items[idx].start = t; } } // If the group is shorter than the minimum width, add padding characters. - } else if (abs(items[groupitems[groupdepth]].minwid) > group_len) { - long min_group_width = items[groupitems[groupdepth]].minwid; + } else if ( + abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) { + long min_group_width = stl_items[stl_groupitems[groupdepth]].minwid; // If the group is left-aligned, add characters to the right. if (min_group_width < 0) { min_group_width = 0 - min_group_width; @@ -3726,8 +3725,8 @@ int build_stl_str_hl( // } // Adjust item start positions - for (int n = groupitems[groupdepth] + 1; n < curitem; n++) { - items[n].start += group_len; + for (int n = stl_groupitems[groupdepth] + 1; n < curitem; n++) { + stl_items[n].start += group_len; } // Prepend the fill characters @@ -3763,9 +3762,9 @@ int build_stl_str_hl( // User highlight groups override the min width field // to denote the styling to use. if (*fmt_p == STL_USER_HL) { - items[curitem].type = Highlight; - items[curitem].start = out_p; - items[curitem].minwid = minwid > 9 ? 1 : minwid; + stl_items[curitem].type = Highlight; + stl_items[curitem].start = out_p; + stl_items[curitem].minwid = minwid > 9 ? 1 : minwid; fmt_p++; curitem++; continue; @@ -3799,8 +3798,8 @@ int build_stl_str_hl( if (minwid == 0) { // %X ends the close label, go back to the previous tab label nr. for (long n = curitem - 1; n >= 0; n--) { - if (items[n].type == TabPage && items[n].minwid >= 0) { - minwid = items[n].minwid; + if (stl_items[n].type == TabPage && stl_items[n].minwid >= 0) { + minwid = stl_items[n].minwid; break; } } @@ -3809,9 +3808,9 @@ int build_stl_str_hl( minwid = -minwid; } } - items[curitem].type = TabPage; - items[curitem].start = out_p; - items[curitem].minwid = minwid; + stl_items[curitem].type = TabPage; + stl_items[curitem].start = out_p; + stl_items[curitem].minwid = minwid; fmt_p++; curitem++; continue; @@ -3826,10 +3825,10 @@ int build_stl_str_hl( if (*fmt_p != STL_CLICK_FUNC) { break; } - items[curitem].type = ClickFunc; - items[curitem].start = out_p; - items[curitem].cmd = xmemdupz(t, (size_t)(((char *)fmt_p - t))); - items[curitem].minwid = minwid; + stl_items[curitem].type = ClickFunc; + stl_items[curitem].start = out_p; + stl_items[curitem].cmd = xmemdupz(t, (size_t)(((char *)fmt_p - t))); + stl_items[curitem].minwid = minwid; fmt_p++; curitem++; continue; @@ -3850,11 +3849,11 @@ int build_stl_str_hl( // Denotes the start of a new group if (*fmt_p == '(') { - groupitems[groupdepth++] = curitem; - items[curitem].type = Group; - items[curitem].start = out_p; - items[curitem].minwid = minwid; - items[curitem].maxwid = maxwid; + stl_groupitems[groupdepth++] = curitem; + stl_items[curitem].type = Group; + stl_items[curitem].start = out_p; + stl_items[curitem].minwid = minwid; + stl_items[curitem].maxwid = maxwid; fmt_p++; curitem++; continue; @@ -4149,9 +4148,9 @@ int build_stl_str_hl( // Create a highlight item based on the name if (*fmt_p == '#') { - items[curitem].type = Highlight; - items[curitem].start = out_p; - items[curitem].minwid = -syn_namen2id(t, (int)(fmt_p - t)); + stl_items[curitem].type = Highlight; + stl_items[curitem].start = out_p; + stl_items[curitem].minwid = -syn_namen2id(t, (int)(fmt_p - t)); curitem++; fmt_p++; } @@ -4162,8 +4161,8 @@ int build_stl_str_hl( // If we made it this far, the item is normal and starts at // our current position in the output buffer. // Non-normal items would have `continued`. - items[curitem].start = out_p; - items[curitem].type = Normal; + stl_items[curitem].start = out_p; + stl_items[curitem].type = Normal; // Copy the item string into the output buffer if (str != NULL && *str) { @@ -4321,7 +4320,7 @@ int build_stl_str_hl( // Otherwise, there was nothing to print so mark the item as empty } else { - items[curitem].type = Empty; + stl_items[curitem].type = Empty; } // Only free the string buffer if we allocated it. @@ -4362,13 +4361,13 @@ int build_stl_str_hl( // Otherwise, look for the truncation item } else { // Default to truncating at the first item - trunc_p = items[0].start; + trunc_p = stl_items[0].start; item_idx = 0; for (int i = 0; i < itemcnt; i++) { - if (items[i].type == Trunc) { - // Truncate at %< items. - trunc_p = items[i].start; + if (stl_items[i].type == Trunc) { + // Truncate at %< stl_items. + trunc_p = stl_items[i].start; item_idx = i; break; } @@ -4403,7 +4402,7 @@ int build_stl_str_hl( // Ignore any items in the statusline that occur after // the truncation point for (int i = 0; i < itemcnt; i++) { - if (items[i].start > trunc_p) { + if (stl_items[i].start > trunc_p) { itemcnt = i; break; } @@ -4458,12 +4457,12 @@ int build_stl_str_hl( for (int i = item_idx; i < itemcnt; i++) { // Items starting at or after the end of the truncated section need // to be moved backwards. - if (items[i].start >= trunc_end_p) { - items[i].start -= item_offset; + if (stl_items[i].start >= trunc_end_p) { + stl_items[i].start -= item_offset; // Anything inside the truncated area is set to start // at the `<` truncation character. } else { - items[i].start = trunc_p; + stl_items[i].start = trunc_p; } } // } @@ -4479,7 +4478,7 @@ int build_stl_str_hl( // figuring out how many groups there are. int num_separators = 0; for (int i = 0; i < itemcnt; i++) { - if (items[i].type == Separate) { + if (stl_items[i].type == Separate) { num_separators++; } } @@ -4488,11 +4487,10 @@ int build_stl_str_hl( if (num_separators) { // Create an array of the start location for each // separator mark. - int separator_locations[STL_MAX_ITEM]; int index = 0; for (int i = 0; i < itemcnt; i++) { - if (items[i].type == Separate) { - separator_locations[index] = i; + if (stl_items[i].type == Separate) { + stl_separator_locations[index] = i; index++; } } @@ -4504,16 +4502,17 @@ int build_stl_str_hl( for (int i = 0; i < num_separators; i++) { int dislocation = (i == (num_separators - 1)) ? final_spaces : standard_spaces; - char_u *seploc = items[separator_locations[i]].start + dislocation; - STRMOVE(seploc, items[separator_locations[i]].start); - for (char_u *s = items[separator_locations[i]].start; s < seploc; s++) { + char_u *start = stl_items[stl_separator_locations[i]].start; + char_u *seploc = start + dislocation; + STRMOVE(seploc, start); + for (char_u *s = start; s < seploc; s++) { *s = fillchar; } - for (int item_idx = separator_locations[i] + 1; + for (int item_idx = stl_separator_locations[i] + 1; item_idx < itemcnt; item_idx++) { - items[item_idx].start += dislocation; + stl_items[item_idx].start += dislocation; } } @@ -4523,11 +4522,12 @@ int build_stl_str_hl( // Store the info about highlighting. if (hltab != NULL) { - struct stl_hlrec *sp = hltab; + *hltab = stl_hltab; + stl_hlrec_t *sp = stl_hltab; for (long l = 0; l < itemcnt; l++) { - if (items[l].type == Highlight) { - sp->start = items[l].start; - sp->userhl = items[l].minwid; + if (stl_items[l].type == Highlight) { + sp->start = stl_items[l].start; + sp->userhl = stl_items[l].minwid; sp++; } } @@ -4537,16 +4537,17 @@ int build_stl_str_hl( // Store the info about tab pages labels. if (tabtab != NULL) { - StlClickRecord *cur_tab_rec = tabtab; + *tabtab = stl_tabtab; + StlClickRecord *cur_tab_rec = stl_tabtab; for (long l = 0; l < itemcnt; l++) { - if (items[l].type == TabPage) { - cur_tab_rec->start = (char *)items[l].start; - if (items[l].minwid == 0) { + if (stl_items[l].type == TabPage) { + cur_tab_rec->start = (char *)stl_items[l].start; + if (stl_items[l].minwid == 0) { cur_tab_rec->def.type = kStlClickDisabled; cur_tab_rec->def.tabnr = 0; } else { - int tabnr = items[l].minwid; - if (items[l].minwid > 0) { + int tabnr = stl_items[l].minwid; + if (stl_items[l].minwid > 0) { cur_tab_rec->def.type = kStlClickTabSwitch; } else { cur_tab_rec->def.type = kStlClickTabClose; @@ -4556,11 +4557,11 @@ int build_stl_str_hl( } cur_tab_rec->def.func = NULL; cur_tab_rec++; - } else if (items[l].type == ClickFunc) { - cur_tab_rec->start = (char *)items[l].start; + } else if (stl_items[l].type == ClickFunc) { + cur_tab_rec->start = (char *)stl_items[l].start; cur_tab_rec->def.type = kStlClickFuncRun; - cur_tab_rec->def.tabnr = items[l].minwid; - cur_tab_rec->def.func = items[l].cmd; + cur_tab_rec->def.tabnr = stl_items[l].minwid; + cur_tab_rec->def.func = stl_items[l].cmd; cur_tab_rec++; } } diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 8e855cb644..9d4a6ecbea 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -361,14 +361,36 @@ struct mapblock { sctx_T m_script_ctx; // SCTX where map was defined }; -/* - * Used for highlighting in the status line. - */ +/// Used for highlighting in the status line. +typedef struct stl_hlrec stl_hlrec_t; struct stl_hlrec { char_u *start; int userhl; // 0: no HL, 1-9: User HL, < 0 for syn ID }; +/// Used for building the status line. +typedef struct stl_item stl_item_t; +struct stl_item { + // Where the item starts in the status line output buffer + char_u *start; + // Function to run for ClickFunc items. + char *cmd; + // The minimum width of the item + int minwid; + // The maximum width of the item + int maxwid; + enum { + Normal, + Empty, + Group, + Separate, + Highlight, + TabPage, + ClickFunc, + Trunc + } type; +}; + // values for b_syn_spell: what to do with toplevel text #define SYNSPL_DEFAULT 0 // spell check if @Spell not defined #define SYNSPL_TOP 1 // spell check toplevel text diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 59e9f96c3a..d7ed2fe97d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1251,7 +1251,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, char_u *errormsg = NULL; // error message char_u *after_modifier = NULL; exarg_T ea; - int save_msg_scroll = msg_scroll; + const int save_msg_scroll = msg_scroll; cmdmod_T save_cmdmod; const int save_reg_executing = reg_executing; char_u *cmd; @@ -2003,34 +2003,10 @@ doend: ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); - if (ea.verbose_save >= 0) { - p_verbose = ea.verbose_save; - } - free_cmdmod(); - + undo_cmdmod(&ea, save_msg_scroll); cmdmod = save_cmdmod; reg_executing = save_reg_executing; - if (ea.save_msg_silent != -1) { - // messages could be enabled for a serious error, need to check if the - // counters don't become negative - if (!did_emsg || msg_silent > ea.save_msg_silent) { - msg_silent = ea.save_msg_silent; - } - emsg_silent -= ea.did_esilent; - if (emsg_silent < 0) { - emsg_silent = 0; - } - // Restore msg_scroll, it's set by file I/O commands, even when no - // message is actually displayed. - msg_scroll = save_msg_scroll; - - /* "silent reg" or "silent echo x" inside "redir" leaves msg_col - * somewhere in the line. Put it back in the first column. */ - if (redirecting()) - msg_col = 0; - } - if (ea.did_sandbox) { sandbox--; } @@ -2298,9 +2274,14 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only) return OK; } -// Free contents of "cmdmod". -static void free_cmdmod(void) +// Undo and free contents of "cmdmod". +static void undo_cmdmod(const exarg_T *eap, int save_msg_scroll) + FUNC_ATTR_NONNULL_ALL { + if (eap->verbose_save >= 0) { + p_verbose = eap->verbose_save; + } + if (cmdmod.save_ei != NULL) { /* Restore 'eventignore' to the value before ":noautocmd". */ set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei, @@ -2308,8 +2289,27 @@ static void free_cmdmod(void) free_string_option(cmdmod.save_ei); } - if (cmdmod.filter_regmatch.regprog != NULL) { - vim_regfree(cmdmod.filter_regmatch.regprog); + vim_regfree(cmdmod.filter_regmatch.regprog); + + if (eap->save_msg_silent != -1) { + // messages could be enabled for a serious error, need to check if the + // counters don't become negative + if (!did_emsg || msg_silent > eap->save_msg_silent) { + msg_silent = eap->save_msg_silent; + } + emsg_silent -= eap->did_esilent; + if (emsg_silent < 0) { + emsg_silent = 0; + } + // Restore msg_scroll, it's set by file I/O commands, even when no + // message is actually displayed. + msg_scroll = save_msg_scroll; + + // "silent reg" or "silent echo x" inside "redir" leaves msg_col + // somewhere in the line. Put it back in the first column. + if (redirecting()) { + msg_col = 0; + } } } @@ -4446,6 +4446,9 @@ void separate_nextcmd(exarg_T *eap) else if (p[0] == '`' && p[1] == '=' && (eap->argt & XFILE)) { p += 2; (void)skip_expr(&p); + if (*p == NUL) { // stop at NUL after CTRL-V + break; + } } /* Check for '"': start of comment or '|': next command */ /* :@" does not start a comment! diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 7f3e4a7dfc..31dd3fc848 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -945,8 +945,10 @@ EXTERN char_u e_readonly[] INIT(= N_( EXTERN char_u e_readonlyvar[] INIT(= N_( "E46: Cannot change read-only variable \"%.*s\"")); EXTERN char_u e_dictreq[] INIT(= N_("E715: Dictionary required")); -EXTERN char_u e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s")); -EXTERN char_u e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: %s")); +EXTERN char_u e_toomanyarg[] INIT(= N_( + "E118: Too many arguments for function: %s")); +EXTERN char_u e_dictkey[] INIT(= N_( + "E716: Key not present in Dictionary: \"%s\"")); EXTERN char_u e_listreq[] INIT(= N_("E714: List required")); EXTERN char_u e_listdictarg[] INIT(= N_( "E712: Argument of %s must be a List or Dictionary")); diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 5258352e72..c53e208b00 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -58,6 +58,7 @@ static struct luaL_Reg node_meta[] = { { "__tostring", node_tostring }, { "__eq", node_eq }, { "__len", node_child_count }, + { "id", node_id }, { "range", node_range }, { "start", node_start }, { "end_", node_end }, @@ -176,10 +177,11 @@ int tslua_add_language(lua_State *L) } uint32_t lang_version = ts_language_version(lang); - if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION) { + if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION + || lang_version > TREE_SITTER_LANGUAGE_VERSION) { return luaL_error( L, - "ABI version mismatch : expected %" PRIu32 ", found %" PRIu32, + "ABI version mismatch : expected %d, found %d", TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION, lang_version); } @@ -246,7 +248,12 @@ int tslua_push_parser(lua_State *L) } TSParser *parser = ts_parser_new(); - ts_parser_set_language(parser, lang); + + if (!ts_parser_set_language(parser, lang)) { + ts_parser_delete(parser); + return luaL_error(L, "Failed to load language : %s", lang_name); + } + TSLua_parser *p = lua_newuserdata(L, sizeof(TSLua_parser)); // [udata] p->parser = parser; p->tree = NULL; @@ -342,7 +349,7 @@ static int parser_parse(lua_State *L) return 0; } - TSTree *new_tree; + TSTree *new_tree = NULL; size_t len; const char *str; long bufnr; @@ -374,6 +381,12 @@ static int parser_parse(lua_State *L) return luaL_error(L, "invalid argument to parser:parse()"); } + // Sometimes parsing fails (timeout, or wrong parser ABI) + // In those case, just return an error. + if (!new_tree) { + return luaL_error(L, "An error occured when parsing."); + } + uint32_t n_ranges = 0; TSRange *changed = p->tree ? ts_tree_get_changed_ranges(p->tree, new_tree, &n_ranges) : NULL; @@ -621,6 +634,17 @@ static int node_eq(lua_State *L) return 1; } +static int node_id(lua_State *L) +{ + TSNode node; + if (!node_check(L, 1, &node)) { + return 0; + } + + lua_pushlstring(L, (const char *)&node.id, sizeof node.id); + return 1; +} + static int node_range(lua_State *L) { TSNode node; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index a2c7dfda55..11e8d354e4 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -903,6 +903,10 @@ normal_end: msg_nowait = false; + if (finish_op) { + set_reg_var(get_default_register_name()); + } + // Reset finish_op, in case it was set s->c = finish_op; finish_op = false; diff --git a/src/nvim/option.c b/src/nvim/option.c index 4f40749f7d..b935708c25 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2566,7 +2566,7 @@ static bool valid_spellfile(const char_u *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { for (const char_u *s = val; *s != NUL; s++) { - if (!vim_isfilec(*s) && *s != ',') { + if (!vim_isfilec(*s) && *s != ',' && *s != ' ') { return false; } } @@ -3751,11 +3751,10 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set) /// Return error message or NULL. char_u *check_stl_option(char_u *s) { - int itemcnt = 0; int groupdepth = 0; static char_u errbuf[80]; - while (*s && itemcnt < STL_MAX_ITEM) { + while (*s) { // Check for valid keys after % sequences while (*s && *s != '%') { s++; @@ -3764,9 +3763,6 @@ char_u *check_stl_option(char_u *s) break; } s++; - if (*s != '%' && *s != ')') { - itemcnt++; - } if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) { s++; continue; @@ -3808,9 +3804,6 @@ char_u *check_stl_option(char_u *s) } } } - if (itemcnt >= STL_MAX_ITEM) { - return (char_u *)N_("E541: too many items"); - } if (groupdepth != 0) { return (char_u *)N_("E542: unbalanced groups"); } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 4042b79262..af0ea7f4a2 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -188,6 +188,7 @@ enum { #define GO_ASELML 'A' // autoselect modeless selection #define GO_BOT 'b' // use bottom scrollbar #define GO_CONDIALOG 'c' // use console dialog +#define GO_DARKTHEME 'd' // use dark theme variant #define GO_TABLINE 'e' // may show tabline #define GO_FORG 'f' // start GUI in foreground #define GO_GREY 'g' // use grey menu items @@ -205,7 +206,7 @@ enum { #define GO_FOOTER 'F' // add footer #define GO_VERTICAL 'v' // arrange dialog buttons vertically #define GO_KEEPWINSIZE 'k' // keep GUI window size -#define GO_ALL "aAbcefFghilmMprTvk" // all possible flags for 'go' +#define GO_ALL "aAbcdefFghilmMprTvk" // all possible flags for 'go' // flags for 'comments' option #define COM_NEST 'n' // comments strings nest diff --git a/src/nvim/screen.c b/src/nvim/screen.c index cb75cba71a..36a6ae59f8 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -5194,8 +5194,8 @@ win_redr_custom ( char_u buf[MAXPATHL]; char_u *stl; char_u *p; - struct stl_hlrec hltab[STL_MAX_ITEM]; - StlClickRecord tabtab[STL_MAX_ITEM]; + stl_hlrec_t *hltab; + StlClickRecord *tabtab; int use_sandbox = false; win_T *ewp; int p_crb_save; @@ -5273,9 +5273,9 @@ win_redr_custom ( /* Make a copy, because the statusline may include a function call that * might change the option value and free the memory. */ stl = vim_strsave(stl); - width = build_stl_str_hl(ewp, buf, sizeof(buf), - stl, use_sandbox, - fillchar, maxwidth, hltab, tabtab); + width = + build_stl_str_hl(ewp, buf, sizeof(buf), stl, use_sandbox, + fillchar, maxwidth, &hltab, &tabtab); xfree(stl); ewp->w_p_crb = p_crb_save; diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h index 034c580b3e..05667f060e 100644 --- a/src/nvim/spell_defs.h +++ b/src/nvim/spell_defs.h @@ -119,6 +119,7 @@ struct slang_S { bool sl_add; // true if it's a .add file. char_u *sl_fbyts; // case-folded word bytes + long sl_fbyts_len; // length of sl_fbyts idx_T *sl_fidxs; // case-folded word indexes char_u *sl_kbyts; // keep-case word bytes idx_T *sl_kidxs; // keep-case word indexes diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 09d8646c6d..b415a4635b 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -764,20 +764,24 @@ truncerr: } // <LWORDTREE> - res = spell_read_tree(fd, &lp->sl_fbyts, &lp->sl_fidxs, false, 0); - if (res != 0) + res = spell_read_tree(fd, &lp->sl_fbyts, &lp->sl_fbyts_len, + &lp->sl_fidxs, false, 0); + if (res != 0) { goto someerror; + } // <KWORDTREE> - res = spell_read_tree(fd, &lp->sl_kbyts, &lp->sl_kidxs, false, 0); - if (res != 0) + res = spell_read_tree(fd, &lp->sl_kbyts, NULL, &lp->sl_kidxs, false, 0); + if (res != 0) { goto someerror; + } // <PREFIXTREE> - res = spell_read_tree(fd, &lp->sl_pbyts, &lp->sl_pidxs, true, - lp->sl_prefixcnt); - if (res != 0) + res = spell_read_tree(fd, &lp->sl_pbyts, NULL, &lp->sl_pidxs, true, + lp->sl_prefixcnt); + if (res != 0) { goto someerror; + } // For a new file link it in the list of spell files. if (old_lp == NULL && lang != NULL) { @@ -920,8 +924,8 @@ void suggest_load_files(void) // <SUGWORDTREE>: <wordtree> // Read the trie with the soundfolded words. - if (spell_read_tree(fd, &slang->sl_sbyts, &slang->sl_sidxs, - false, 0) != 0) { + if (spell_read_tree(fd, &slang->sl_sbyts, NULL, &slang->sl_sidxs, + false, 0) != 0) { someerror: EMSG2(_("E782: error while reading .sug file: %s"), slang->sl_fname); @@ -1630,10 +1634,12 @@ static int spell_read_tree ( FILE *fd, char_u **bytsp, + long *bytsp_len, idx_T **idxsp, bool prefixtree, // true for the prefix tree int prefixcnt // when "prefixtree" is true: prefix count ) + FUNC_ATTR_NONNULL_ARG(1, 2, 4) { int idx; char_u *bp; @@ -1653,6 +1659,9 @@ spell_read_tree ( // Allocate the byte array. bp = xmalloc(len); *bytsp = bp; + if (bytsp_len != NULL) { + *bytsp_len = len; + } // Allocate the index array. ip = xcalloc(len, sizeof(*ip)); @@ -4850,10 +4859,10 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang) spin->si_blocks_cnt = 0; // Skip over any other NUL bytes (same word with different - // flags). - while (byts[n + 1] == 0) { - ++n; - ++curi[depth]; + // flags). But don't go over the end. + while (n + 1 < slang->sl_fbyts_len && byts[n + 1] == 0) { + n++; + curi[depth]++; } } else { // Normal char, go one level deeper. diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 871143699a..e3c42a4fe3 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -722,7 +722,7 @@ func Test_verbosefile() endfunc func Test_verbose_option() - " See test/functional/ui/cmdline_spec.lua + " See test/functional/legacy/cmdline_spec.lua CheckScreendump let lines =<< trim [SCRIPT] @@ -842,6 +842,25 @@ func Test_buffers_lastused() bwipeout bufc endfunc +func Test_cmdlineclear_tabenter() + " See test/functional/legacy/cmdline_spec.lua + CheckScreendump + + let lines =<< trim [SCRIPT] + call setline(1, range(30)) + [SCRIPT] + + call writefile(lines, 'XtestCmdlineClearTabenter') + let buf = RunVimInTerminal('-S XtestCmdlineClearTabenter', #{rows: 10}) + call term_wait(buf, 50) + " in one tab make the command line higher with CTRL-W - + call term_sendkeys(buf, ":tabnew\<cr>\<C-w>-\<C-w>-gtgt") + call VerifyScreenDump(buf, 'Test_cmdlineclear_tabenter', {}) + + call StopVimInTerminal(buf) + call delete('XtestCmdlineClearTabenter') +endfunc + " test that ";" works to find a match at the start of the first line func Test_zero_line_search() new diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index 15c718b243..abad6983dc 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -1587,4 +1587,11 @@ func Test_edit_browse() bwipe! endfunc +func Test_read_invalid() + " set encoding=latin1 + " This was not properly checking for going past the end. + call assert_fails('r`=', 'E484') + set encoding=utf-8 +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim index 31a8b48d37..8e2a987e74 100644 --- a/src/nvim/testdir/test_listdict.vim +++ b/src/nvim/testdir/test_listdict.vim @@ -199,9 +199,9 @@ func Test_dict_big() try let n = d[1500] catch - let str=substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '') + let str = substitute(v:exception, '\v(.{14}).*( "\d{4}").*', '\1\2', '') endtry - call assert_equal('Vim(let):E716: 1500', str) + call assert_equal('Vim(let):E716: "1500"', str) " lookup each items for i in range(1500) diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index ca14494248..30239a90c2 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -1,20 +1,16 @@ " Tests for :messages, :echomsg, :echoerr -function Test_messages() +source shared.vim + +func Test_messages() let oldmore = &more try set nomore - " Avoid the "message maintainer" line. - let $LANG = '' - let $LC_ALL = '' - let $LC_MESSAGES = '' - let $LC_COLLATE = '' let arr = map(range(10), '"hello" . v:val') for s in arr echomsg s | redraw endfor - let result = '' " get last two messages redir => result @@ -25,22 +21,17 @@ function Test_messages() " clear messages without last one 1messages clear - redir => result - redraw | messages - redir END - let msg_list = split(result, "\n") + let msg_list = GetMessages() call assert_equal(['hello9'], msg_list) " clear all messages messages clear - redir => result - redraw | messages - redir END - call assert_equal('', result) + let msg_list = GetMessages() + call assert_equal([], msg_list) finally let &more = oldmore endtry -endfunction +endfunc " Patch 7.4.1696 defined the "clearmode()" command for clearing the mode " indicator (e.g., "-- INSERT --") when ":stopinsert" is invoked. Message diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 9e8da74db7..10e16f4198 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -267,7 +267,6 @@ func Test_set_errors() call assert_fails('set commentstring=x', 'E537:') call assert_fails('set complete=x', 'E539:') call assert_fails('set statusline=%{', 'E540:') - call assert_fails('set statusline=' . repeat("%p", 81), 'E541:') call assert_fails('set statusline=%(', 'E542:') if has('cursorshape') " This invalid value for 'guicursor' used to cause Vim to crash. diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim index d20f8d1eef..19a7c6c9d0 100644 --- a/src/nvim/testdir/test_registers.vim +++ b/src/nvim/testdir/test_registers.vim @@ -167,6 +167,75 @@ func Test_set_register() enew! endfunc +func Test_v_register() + enew + call setline(1, 'nothing') + + func s:Put() + let s:register = v:register + exec 'normal! "' .. v:register .. 'P' + endfunc + nnoremap <buffer> <plug>(test) :<c-u>call s:Put()<cr> + nmap <buffer> S <plug>(test) + + let @z = "testz\n" + let @" = "test@\n" + + let s:register = '' + call feedkeys('"_ddS', 'mx') + call assert_equal('test@', getline('.')) " fails before 8.2.0929 + call assert_equal('"', s:register) " fails before 8.2.0929 + + let s:register = '' + call feedkeys('"zS', 'mx') + call assert_equal('z', s:register) + + let s:register = '' + call feedkeys('"zSS', 'mx') + call assert_equal('"', s:register) + + let s:register = '' + call feedkeys('"_S', 'mx') + call assert_equal('_', s:register) + + let s:register = '' + normal "_ddS + call assert_equal('"', s:register) " fails before 8.2.0929 + call assert_equal('test@', getline('.')) " fails before 8.2.0929 + + let s:register = '' + execute 'normal "z:call' "s:Put()\n" + call assert_equal('z', s:register) + call assert_equal('testz', getline('.')) + + " Test operator and omap + let @b = 'testb' + func s:OpFunc(...) + let s:register2 = v:register + endfunc + set opfunc=s:OpFunc + + normal "bg@l + normal S + call assert_equal('"', s:register) " fails before 8.2.0929 + call assert_equal('b', s:register2) + + func s:Motion() + let s:register1 = v:register + normal! l + endfunc + onoremap <buffer> Q :<c-u>call s:Motion()<cr> + + normal "bg@Q + normal S + call assert_equal('"', s:register) + call assert_equal('b', s:register1) + call assert_equal('"', s:register2) + + set opfunc& + bwipe! +endfunc + func Test_ve_blockpaste() new set ve=all diff --git a/src/nvim/testdir/test_ruby.vim b/src/nvim/testdir/test_ruby.vim index 07ad8561c3..9c74c35049 100644 --- a/src/nvim/testdir/test_ruby.vim +++ b/src/nvim/testdir/test_ruby.vim @@ -1,8 +1,7 @@ " Tests for ruby interface -if !has('ruby') - finish -end +source check.vim +CheckFeature ruby func Test_ruby_change_buffer() call setline(line('$'), ['1 line 1']) @@ -36,7 +35,7 @@ func Test_rubyfile() call delete(tempfile) endfunc -func Test_set_cursor() +func Test_ruby_set_cursor() " Check that setting the cursor position works. new call setline(1, ['first line', 'second line']) @@ -56,7 +55,7 @@ func Test_set_cursor() endfunc " Test buffer.count and buffer.length (number of lines in buffer) -func Test_buffer_count() +func Test_ruby_buffer_count() new call setline(1, ['one', 'two', 'three']) call assert_equal(3, rubyeval('$curbuf.count')) @@ -65,7 +64,7 @@ func Test_buffer_count() endfunc " Test buffer.name (buffer name) -func Test_buffer_name() +func Test_ruby_buffer_name() new Xfoo call assert_equal(expand('%:p'), rubyeval('$curbuf.name')) bwipe @@ -73,7 +72,7 @@ func Test_buffer_name() endfunc " Test buffer.number (number of the buffer). -func Test_buffer_number() +func Test_ruby_buffer_number() new call assert_equal(bufnr('%'), rubyeval('$curbuf.number')) new @@ -83,7 +82,7 @@ func Test_buffer_number() endfunc " Test buffer.delete({n}) (delete line {n}) -func Test_buffer_delete() +func Test_ruby_buffer_delete() new call setline(1, ['one', 'two', 'three']) ruby $curbuf.delete(2) @@ -97,7 +96,7 @@ func Test_buffer_delete() endfunc " Test buffer.append({str}, str) (append line {str} after line {n}) -func Test_buffer_append() +func Test_ruby_buffer_append() new ruby $curbuf.append(0, 'one') ruby $curbuf.append(1, 'three') @@ -117,7 +116,7 @@ func Test_buffer_append() endfunc " Test buffer.line (get or set the current line) -func Test_buffer_line() +func Test_ruby_buffer_line() new call setline(1, ['one', 'two', 'three']) 2 @@ -130,7 +129,7 @@ func Test_buffer_line() endfunc " Test buffer.line_number (get current line number) -func Test_buffer_line_number() +func Test_ruby_buffer_line_number() new call setline(1, ['one', 'two', 'three']) 2 @@ -139,7 +138,7 @@ func Test_buffer_line_number() bwipe! endfunc -func Test_buffer_get() +func Test_ruby_buffer_get() new call setline(1, ['one', 'two']) call assert_equal('one', rubyeval('$curbuf[1]')) @@ -153,7 +152,7 @@ func Test_buffer_get() bwipe! endfunc -func Test_buffer_set() +func Test_ruby_buffer_set() new call setline(1, ['one', 'two']) ruby $curbuf[2] = 'TWO' @@ -169,7 +168,7 @@ func Test_buffer_set() endfunc " Test window.width (get or set window height). -func Test_window_height() +func Test_ruby_window_height() new " Test setting window height @@ -183,7 +182,7 @@ func Test_window_height() endfunc " Test window.width (get or set window width). -func Test_window_width() +func Test_ruby_window_width() vnew " Test setting window width @@ -197,7 +196,7 @@ func Test_window_width() endfunc " Test window.buffer (get buffer object of a window object). -func Test_window_buffer() +func Test_ruby_window_buffer() new Xfoo1 new Xfoo2 ruby $b2 = $curwin.buffer @@ -216,14 +215,14 @@ func Test_window_buffer() endfunc " Test Vim::Window.current (get current window object) -func Test_Vim_window_current() +func Test_ruby_Vim_window_current() let cw = rubyeval('$curwin.to_s') " call assert_equal(cw, rubyeval('Vim::Window.current')) call assert_match('^#<Neovim::Window:0x\x\+>$', cw) endfunc " Test Vim::Window.count (number of windows) -func Test_Vim_window_count() +func Test_ruby_Vim_window_count() new Xfoo1 new Xfoo2 split @@ -233,7 +232,7 @@ func Test_Vim_window_count() endfunc " Test Vim::Window[n] (get window object of window n) -func Test_Vim_window_get() +func Test_ruby_Vim_window_get() new Xfoo1 new Xfoo2 call assert_match('Xfoo2$', rubyeval('Vim::Window[0].buffer.name')) @@ -245,14 +244,14 @@ func Test_Vim_window_get() endfunc " Test Vim::Buffer.current (return the buffer object of current buffer) -func Test_Vim_buffer_current() +func Test_ruby_Vim_buffer_current() let cb = rubyeval('$curbuf.to_s') " call assert_equal(cb, rubyeval('Vim::Buffer.current')) call assert_match('^#<Neovim::Buffer:0x\x\+>$', cb) endfunc " Test Vim::Buffer:.count (return the number of buffers) -func Test_Vim_buffer_count() +func Test_ruby_Vim_buffer_count() new Xfoo1 new Xfoo2 call assert_equal(3, rubyeval('Vim::Buffer.count')) @@ -261,7 +260,7 @@ func Test_Vim_buffer_count() endfunc " Test Vim::buffer[n] (return the buffer object of buffer number n) -func Test_Vim_buffer_get() +func Test_ruby_Vim_buffer_get() new Xfoo1 new Xfoo2 @@ -276,7 +275,7 @@ endfunc " Test Vim::command({cmd}) (execute a Ex command)) " Test Vim::command({cmd}) -func Test_Vim_command() +func Test_ruby_Vim_command() new call setline(1, ['one', 'two', 'three', 'four']) ruby Vim::command('2,3d') @@ -285,7 +284,7 @@ func Test_Vim_command() endfunc " Test Vim::set_option (set a vim option) -func Test_Vim_set_option() +func Test_ruby_Vim_set_option() call assert_equal(0, &number) ruby Vim::set_option('number') call assert_equal(1, &number) @@ -293,14 +292,16 @@ func Test_Vim_set_option() call assert_equal(0, &number) endfunc -func Test_Vim_evaluate() +func Test_ruby_Vim_evaluate() call assert_equal(123, rubyeval('Vim::evaluate("123")')) " Vim::evaluate("123").class gives Integer or Fixnum depending " on versions of Ruby. call assert_match('^Integer\|Fixnum$', rubyeval('Vim::evaluate("123").class')) - call assert_equal(1.23, rubyeval('Vim::evaluate("1.23")')) - call assert_equal('Float', rubyeval('Vim::evaluate("1.23").class')) + if has('float') + call assert_equal(1.23, rubyeval('Vim::evaluate("1.23")')) + call assert_equal('Float', rubyeval('Vim::evaluate("1.23").class')) + endif call assert_equal('foo', rubyeval('Vim::evaluate("\"foo\"")')) call assert_equal('String', rubyeval('Vim::evaluate("\"foo\"").class')) @@ -323,7 +324,7 @@ func Test_Vim_evaluate() call assert_equal('FalseClass',rubyeval('Vim::evaluate("v:false").class')) endfunc -func Test_Vim_evaluate_list() +func Test_ruby_Vim_evaluate_list() call setline(line('$'), ['2 line 2']) ruby Vim.command("normal /^2\n") let l = ["abc", "def"] @@ -337,7 +338,7 @@ EOF call assert_equal('abc/def', getline('$')) endfunc -func Test_Vim_evaluate_dict() +func Test_ruby_Vim_evaluate_dict() let d = {'a': 'foo', 'b': 123} redir => l:out ruby d = Vim.evaluate("d"); print d @@ -346,14 +347,14 @@ func Test_Vim_evaluate_dict() endfunc " Test Vim::message({msg}) (display message {msg}) -func Test_Vim_message() +func Test_ruby_Vim_message() throw 'skipped: TODO: ' ruby Vim::message('A message') let messages = split(execute('message'), "\n") call assert_equal('A message', messages[-1]) endfunc -func Test_print() +func Test_ruby_print() func RubyPrint(expr) return trim(execute('ruby print ' . a:expr)) endfunc @@ -372,9 +373,9 @@ func Test_print() delfunc RubyPrint endfunc -func Test_p() +func Test_ruby_p() ruby p 'Just a test' - let messages = split(execute('message'), "\n") + let messages = GetMessages() call assert_equal('"Just a test"', messages[-1]) " Check return values of p method @@ -387,6 +388,6 @@ func Test_p() messages clear call assert_equal(v:true, rubyeval('p() == nil')) - let messages = split(execute('message'), "\n") + let messages = GetMessages() call assert_equal(0, len(messages)) endfunc diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim index 7efd181d04..4e38f7ebd8 100644 --- a/src/nvim/testdir/test_statusline.vim +++ b/src/nvim/testdir/test_statusline.vim @@ -354,6 +354,21 @@ func Test_statusline() delfunc GetNested delfunc GetStatusLine + " Test statusline works with 80+ items + function! StatusLabel() + redrawstatus + return '[label]' + endfunc + let statusline = '%{StatusLabel()}' + for i in range(150) + let statusline .= '%#TabLine' . (i % 2 == 0 ? 'Fill' : 'Sel') . '#' . string(i)[0] + endfor + let &statusline = statusline + redrawstatus + set statusline& + delfunc StatusLabel + + " Check statusline in current and non-current window " with the 'fillchars' option. set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:- diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 832703e83d..873bef32d3 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -259,7 +259,6 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext() #define PERROR(msg) (void) emsgf("%s: %s", msg, strerror(errno)) #define SHOWCMD_COLS 10 // columns needed by shown command -#define STL_MAX_ITEM 80 // max nr of %<flag> in statusline #include "nvim/path.h" diff --git a/src/nvim/window.c b/src/nvim/window.c index 863c1a7556..2147bd4fc7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4049,7 +4049,7 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au prevwin = next_prevwin; last_status(false); // status line may appear or disappear - (void)win_comp_pos(); // recompute w_winrow for all windows + const int row = win_comp_pos(); // recompute w_winrow for all windows diff_need_scrollbind = true; /* The tabpage line may have appeared or disappeared, may need to resize @@ -4060,11 +4060,20 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au clear_cmdline = true; } p_ch = curtab->tp_ch_used; - if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow - )) + + // When cmdheight is changed in a tab page with '<C-w>-', cmdline_row is + // changed but p_ch and tp_ch_used are not changed. Thus we also need to + // check cmdline_row. + if ((row < cmdline_row) && (cmdline_row <= Rows - p_ch)) { + clear_cmdline = true; + } + + if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow)) { shell_new_rows(); - if (curtab->tp_old_Columns != Columns && starting == 0) - shell_new_columns(); /* update window widths */ + } + if (curtab->tp_old_Columns != Columns && starting == 0) { + shell_new_columns(); // update window widths + } lastused_tabpage = old_curtab; diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua index db0a706319..fa8f7d873f 100644 --- a/test/functional/eval/null_spec.lua +++ b/test/functional/eval/null_spec.lua @@ -132,7 +132,7 @@ describe('NULL', function() end) describe('dict', function() it('does not crash when indexing NULL dict', function() - eq('\nE716: Key not present in Dictionary: test\nE15: Invalid expression: v:_null_dict.test', + eq('\nE716: Key not present in Dictionary: "test"\nE15: Invalid expression: v:_null_dict.test', redir_exec('echo v:_null_dict.test')) end) null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0) diff --git a/test/functional/legacy/055_list_and_dict_types_spec.lua b/test/functional/legacy/055_list_and_dict_types_spec.lua index 91ba8bb106..4d71a526c1 100644 --- a/test/functional/legacy/055_list_and_dict_types_spec.lua +++ b/test/functional/legacy/055_list_and_dict_types_spec.lua @@ -229,7 +229,7 @@ describe('list and dictionary types', function() try let n = d[1500] catch - $put =substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '') + $put = substitute(v:exception, '\v(.{14}).*( \"\d{4}\").*', '\1\2', '') endtry " Lookup each items. for i in range(1500) @@ -260,7 +260,7 @@ describe('list and dictionary types', function() expect([[ 3000 2900 2001 1600 1501 - Vim(let):E716: 1500 + Vim(let):E716: "1500" NONE 2999 33=999 {'33': 999}]]) diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua new file mode 100644 index 0000000000..9ebe9aeb91 --- /dev/null +++ b/test/functional/legacy/cmdline_spec.lua @@ -0,0 +1,66 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear = helpers.clear +local feed = helpers.feed +local feed_command = helpers.feed_command +local source = helpers.source + +describe('cmdline', function() + before_each(clear) + + it('is cleared when switching tabs', function() + local screen = Screen.new(30, 10) + screen:attach() + feed_command([[call setline(1, range(30))]]) + screen:expect([[ + ^0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + :call setline(1, range(30)) | + ]]) + feed([[:tabnew<cr><C-w>-<C-w>-gtgt]]) + screen:expect([[ + + [No Name] [No Name] X| + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + 6 | + 7 | + | + ]]) + end) + + it('prints every executed Ex command if verbose >= 16', function() + local screen = Screen.new(60, 12) + screen:attach() + source([[ + command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v + call feedkeys("\r", 't') " for the hit-enter prompt + set verbose=20 + ]]) + feed_command('DoSomething') + screen:expect([[ + | + ~ | + ~ | + | + Executing: DoSomething | + Executing: echo 'hello' |set ts=4 |let v = '123' |echo v | + hello | + Executing: set ts=4 |let v = '123' |echo v | + Executing: let v = '123' |echo v | + Executing: echo v | + 123 | + Press ENTER or type command to continue^ | + ]]) + end) +end) diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 3526b64395..9eb5c8b1dd 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -80,13 +80,6 @@ describe('treesitter API with C parser', function() eq({1,2,1,12}, exec_lua("return {descendant:range()}")) eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()")) - eq(true, exec_lua("return child == child")) - -- separate lua object, but represents same node - eq(true, exec_lua("return child == root:child(0)")) - eq(false, exec_lua("return child == descendant2")) - eq(false, exec_lua("return child == nil")) - eq(false, exec_lua("return child == tree")) - feed("2G7|ay") exec_lua([[ tree2 = parser:parse() @@ -98,6 +91,21 @@ describe('treesitter API with C parser', function() eq("<node declaration>", exec_lua("return tostring(descendant2)")) eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) + eq(true, exec_lua("return child == child")) + -- separate lua object, but represents same node + eq(true, exec_lua("return child == root:child(0)")) + eq(false, exec_lua("return child == descendant2")) + eq(false, exec_lua("return child == nil")) + eq(false, exec_lua("return child == tree")) + + eq("string", exec_lua("return type(child:id())")) + eq(true, exec_lua("return child:id() == child:id()")) + -- separate lua object, but represents same node + eq(true, exec_lua("return child:id() == root:child(0):id()")) + eq(false, exec_lua("return child:id() == descendant2:id()")) + eq(false, exec_lua("return child:id() == nil")) + eq(false, exec_lua("return child:id() == tree")) + -- orginal tree did not change eq({1,2,1,12}, exec_lua("return {descendant:range()}")) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 01f0d8a4d7..21c01b3458 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -3,7 +3,6 @@ local Screen = require('test.functional.ui.screen') local clear, feed = helpers.clear, helpers.feed local source = helpers.source local command = helpers.command -local feed_command = helpers.feed_command local function new_screen(opt) local screen = Screen.new(25, 5) @@ -843,34 +842,3 @@ describe('cmdline redraw', function() ]], unchanged=true} end) end) - -describe('cmdline', function() - before_each(function() - clear() - end) - - it('prints every executed Ex command if verbose >= 16', function() - local screen = Screen.new(50, 12) - screen:attach() - source([[ - command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v - call feedkeys("\r", 't') " for the hit-enter prompt - set verbose=20 - ]]) - feed_command('DoSomething') - screen:expect([[ - | - ~ | - | - Executing: DoSomething | - Executing: echo 'hello' |set ts=4 |let v = '123' || - echo v | - hello | - Executing: set ts=4 |let v = '123' |echo v | - Executing: let v = '123' |echo v | - Executing: echo v | - 123 | - Press ENTER or type command to continue^ | - ]]) - end) -end) diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua index bf4e5a0e6d..3692e19379 100644 --- a/test/unit/buffer_spec.lua +++ b/test/unit/buffer_spec.lua @@ -212,7 +212,7 @@ describe('buffer functions', function() describe('build_stl_str_hl', function() local buffer_byte_size = 100 - local STL_MAX_ITEM = 80 + local STL_INITIAL_ITEMS = 20 local output_buffer = '' -- This function builds the statusline @@ -431,31 +431,23 @@ describe('buffer functions', function() 'aaaa%=b%=c%=d%=e%=fg%=hi%=jk%=lmnop%=qrstuv%=wxyz', 'aaaa b c d e fg hi jk lmnop qrstuv wxyz') - -- maximum stl item testing - statusline_test('should handle a much larger amount of = than buffer locations', 20, - ('%='):rep(STL_MAX_ITEM - 1), - ' ') -- Should be fine, because within limit - statusline_test('should handle a much larger amount of = than stl max item', 20, - ('%='):rep(STL_MAX_ITEM + 1), - ' E541') -- Should show the VIM error + -- stl item testing + local tabline = '' + for i= 1, 1000 do + tabline = tabline .. (i % 2 == 0 and '%#TabLineSel#' or '%#TabLineFill#') .. tostring(i % 2) + end + statusline_test('should handle a large amount of any items', 20, + tabline, + '<1010101010101010101') -- Should not show any error + statusline_test('should handle a larger amount of = than stl initial item', 20, + ('%='):rep(STL_INITIAL_ITEMS * 5), + ' ') -- Should not show any error statusline_test('should handle many extra characters', 20, - 'a' .. ('a'):rep(STL_MAX_ITEM * 4), - '<aaaaaaaaaaaaaaaaaaa') -- Does not show the error because there are no items - statusline_test('should handle almost maximum of characters and flags', 20, - 'a' .. ('%=a'):rep(STL_MAX_ITEM - 1), - 'a<aaaaaaaaaaaaaaaaaa') -- Should not show the VIM error - statusline_test('should handle many extra characters and flags', 20, - 'a' .. ('%=a'):rep(STL_MAX_ITEM), - 'a<aaaaaaaaaaaaa E541') -- Should show the VIM error + 'a' .. ('a'):rep(STL_INITIAL_ITEMS * 5), + '<aaaaaaaaaaaaaaaaaaa') -- Does not show any error statusline_test('should handle many extra characters and flags', 20, - 'a' .. ('%=a'):rep(STL_MAX_ITEM * 2), - 'a<aaaaaaaaaaaaa E541') -- Should show the VIM error - statusline_test('should handle many extra characters and flags with truncation', 20, - 'aaa%<' .. ('%=a'):rep(STL_MAX_ITEM), - 'aaa<aaaaaaaaaaa E541') -- Should show the VIM error - statusline_test('should handle many characters and flags before and after truncation', 20, - 'a%=a%=a%<' .. ('%=a'):rep(STL_MAX_ITEM), - 'aaa<aaaaaaaaaaa E541') -- Should show the VIM error + 'a' .. ('%=a'):rep(STL_INITIAL_ITEMS * 2), + 'a<aaaaaaaaaaaaaaaaaa') -- Should not show any error -- multi-byte testing diff --git a/third-party/cmake/GetBinaryDeps.cmake b/third-party/cmake/GetBinaryDeps.cmake index f262ae7159..982bf62265 100644 --- a/third-party/cmake/GetBinaryDeps.cmake +++ b/third-party/cmake/GetBinaryDeps.cmake @@ -39,7 +39,6 @@ function(GetBinaryDep) -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake CONFIGURE_COMMAND "" BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin COMMAND "${_gettool_INSTALL_COMMAND}") |