diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/buffer.c | 233 | ||||
| -rw-r--r-- | src/nvim/buffer_defs.h | 28 | ||||
| -rw-r--r-- | src/nvim/ex_docmd.c | 63 | ||||
| -rw-r--r-- | src/nvim/lua/treesitter.c | 20 | ||||
| -rw-r--r-- | src/nvim/normal.c | 4 | ||||
| -rw-r--r-- | src/nvim/option.c | 9 | ||||
| -rw-r--r-- | src/nvim/option_defs.h | 3 | ||||
| -rw-r--r-- | src/nvim/screen.c | 10 | ||||
| -rw-r--r-- | src/nvim/spell_defs.h | 1 | ||||
| -rw-r--r-- | src/nvim/spellfile.c | 35 | ||||
| -rw-r--r-- | src/nvim/testdir/test_cmdline.vim | 21 | ||||
| -rw-r--r-- | src/nvim/testdir/test_edit.vim | 7 | ||||
| -rw-r--r-- | src/nvim/testdir/test_options.vim | 1 | ||||
| -rw-r--r-- | src/nvim/testdir/test_registers.vim | 69 | ||||
| -rw-r--r-- | src/nvim/testdir/test_statusline.vim | 15 | ||||
| -rw-r--r-- | src/nvim/vim.h | 1 | ||||
| -rw-r--r-- | src/nvim/window.c | 19 | 
17 files changed, 351 insertions, 188 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 8f631ae13b..3dee7f76d7 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 211791c19d..ad7db2ae98 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/lua/treesitter.c b/src/nvim/lua/treesitter.c index 2105beee2a..c53e208b00 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -177,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);    } @@ -247,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; @@ -343,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; @@ -375,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; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 1cc400166c..d364c178b2 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 ca902d5669..d5ea358184 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -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 df0c5ce791..713facfd1c 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -5191,8 +5191,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; @@ -5270,9 +5270,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_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_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 4931221e7a..96409304ab 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;  | 
