diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/command.c | 3 | ||||
-rw-r--r-- | src/nvim/api/keysets_defs.h | 7 | ||||
-rw-r--r-- | src/nvim/buffer.c | 40 | ||||
-rw-r--r-- | src/nvim/decoration.c | 18 | ||||
-rw-r--r-- | src/nvim/decoration.h | 1 | ||||
-rw-r--r-- | src/nvim/decoration_provider.c | 6 | ||||
-rw-r--r-- | src/nvim/digraph.c | 17 | ||||
-rw-r--r-- | src/nvim/drawline.c | 6 | ||||
-rw-r--r-- | src/nvim/drawscreen.c | 4 | ||||
-rw-r--r-- | src/nvim/extmark.c | 7 | ||||
-rw-r--r-- | src/nvim/generators/gen_vimvim.lua | 8 | ||||
-rw-r--r-- | src/nvim/highlight_group.c | 2 | ||||
-rw-r--r-- | src/nvim/insexpand.c | 323 | ||||
-rw-r--r-- | src/nvim/statusline.c | 103 | ||||
-rw-r--r-- | src/nvim/vterm/screen.c | 2 |
15 files changed, 299 insertions, 248 deletions
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 7e79133ed4..23e08bd3fe 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -931,6 +931,9 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) gap = &ucmds; } else { buf_T *buf = find_buffer_by_handle(buffer, err); + if (ERROR_SET(err)) { + return; + } gap = &buf->b_ucmds; } diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index 17287e083b..664406ab6e 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -13,10 +13,11 @@ typedef struct { typedef struct { OptionalKeys is_set__set_decoration_provider_; - LuaRefOf(("start" _, Integer tick)) on_start; + LuaRefOf(("start" _, Integer tick), *Boolean) on_start; LuaRefOf(("buf" _, Integer bufnr, Integer tick)) on_buf; - LuaRefOf(("win" _, Integer winid, Integer bufnr, Integer toprow, Integer botrow)) on_win; - LuaRefOf(("line" _, Integer winid, Integer bufnr, Integer row)) on_line; + LuaRefOf(("win" _, Integer winid, Integer bufnr, Integer toprow, Integer botrow), + *Boolean) on_win; + LuaRefOf(("line" _, Integer winid, Integer bufnr, Integer row), *Boolean) on_line; LuaRefOf(("end" _, Integer tick)) on_end; LuaRefOf(("hl_def" _)) _on_hl_def; LuaRefOf(("spell_nav" _)) _on_spell_nav; diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 5dcf7d8f49..9e6877cbfa 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3257,8 +3257,8 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) n); validate_virtcol(curwin); size_t len = strlen(buffer); - col_print(buffer + len, IOSIZE - len, - (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); + (void)col_print(buffer + len, IOSIZE - len, + (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); } append_arg_number(curwin, buffer, IOSIZE); @@ -3286,13 +3286,13 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) xfree(buffer); } -void col_print(char *buf, size_t buflen, int col, int vcol) +int col_print(char *buf, size_t buflen, int col, int vcol) { if (col == vcol) { - vim_snprintf(buf, buflen, "%d", col); - } else { - vim_snprintf(buf, buflen, "%d-%d", col, vcol); + return vim_snprintf(buf, buflen, "%d", col); } + + return vim_snprintf(buf, buflen, "%d-%d", col, vcol); } static char *lasttitle = NULL; @@ -3416,15 +3416,16 @@ void free_titles(void) /// Get relative cursor position in window into "buf[buflen]", in the localized /// percentage form like %99, 99%; using "Top", "Bot" or "All" when appropriate. -void get_rel_pos(win_T *wp, char *buf, int buflen) +int get_rel_pos(win_T *wp, char *buf, int buflen) { // Need at least 3 chars for writing. if (buflen < 3) { - return; + return 0; } linenr_T above; // number of lines above window linenr_T below; // number of lines below window + int len; above = wp->w_topline - 1; above += win_get_fill(wp, wp->w_topline) - wp->w_topfill; @@ -3435,25 +3436,24 @@ void get_rel_pos(win_T *wp, char *buf, int buflen) } below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1; if (below <= 0) { - xstrlcpy(buf, (above == 0 ? _("All") : _("Bot")), (size_t)buflen); + len = vim_snprintf(buf, (size_t)buflen, "%s", (above == 0) ? _("All") : _("Bot")); } else if (above <= 0) { - xstrlcpy(buf, _("Top"), (size_t)buflen); + len = vim_snprintf(buf, (size_t)buflen, "%s", _("Top")); } else { int perc = (above > 1000000 ? (above / ((above + below) / 100)) : (above * 100 / (above + below))); - - char *p = buf; - size_t l = (size_t)buflen; - if (perc < 10) { - // prepend one space - buf[0] = ' '; - p++; - l--; - } // localized percentage value - vim_snprintf(p, l, _("%d%%"), perc); + len = vim_snprintf(buf, (size_t)buflen, _("%s%d%%"), (perc < 10) ? " " : "", perc); } + if (len < 0) { + buf[0] = NUL; + len = 0; + } else if (len > buflen - 1) { + len = buflen - 1; + } + + return len; } /// Append (2 of 8) to "buf[buflen]", if editing more than one file. diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 728a917c22..a9f3ba0c3b 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -303,12 +303,24 @@ static void decor_free_inner(DecorVirtText *vt, uint32_t first_idx) } } +/// Check if we are in a callback while drawing, which might invalidate the marktree iterator. +/// +/// This should be called whenever a structural modification has been done to a +/// marktree in a public API function (i e any change which adds or deletes marks). +void decor_state_invalidate(buf_T *buf) +{ + if (decor_state.win && decor_state.win->w_buffer == buf) { + decor_state.itr_valid = false; + } +} + void decor_check_to_be_deleted(void) { assert(!decor_state.running_decor_provider); decor_free_inner(to_free_virt, to_free_sh); to_free_virt = NULL; to_free_sh = DECOR_ID_INVALID; + decor_state.win = NULL; } void decor_state_free(DecorState *state) @@ -447,6 +459,8 @@ bool decor_redraw_start(win_T *wp, int top_row, DecorState *state) { buf_T *buf = wp->w_buffer; state->top_row = top_row; + state->itr_valid = true; + if (!marktree_itr_get_overlap(buf->b_marktree, top_row, 0, state->itr)) { return false; } @@ -489,7 +503,11 @@ bool decor_redraw_line(win_T *wp, int row, DecorState *state) if (state->row == -1) { decor_redraw_start(wp, row, state); + } else if (!state->itr_valid) { + marktree_itr_get(wp->w_buffer->b_marktree, row, 0, state->itr); + state->itr_valid = true; } + state->row = row; state->col_until = -1; state->eol_col = -1; diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 1d268c982b..a2f4fefd45 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -96,6 +96,7 @@ typedef struct { TriState spell; bool running_decor_provider; + bool itr_valid; } DecorState; EXTERN DecorState decor_state INIT( = { 0 }); diff --git a/src/nvim/decoration_provider.c b/src/nvim/decoration_provider.c index e5d2658720..7c99fbf889 100644 --- a/src/nvim/decoration_provider.c +++ b/src/nvim/decoration_provider.c @@ -155,7 +155,7 @@ void decor_providers_invoke_win(win_T *wp) /// @param row Row to invoke line callback for /// @param[out] has_decor Set when at least one provider invokes a line callback /// @param[out] err Provider error -void decor_providers_invoke_line(win_T *wp, int row, bool *has_decor) +void decor_providers_invoke_line(win_T *wp, int row) { decor_state.running_decor_provider = true; for (size_t i = 0; i < kv_size(decor_providers); i++) { @@ -165,9 +165,7 @@ void decor_providers_invoke_line(win_T *wp, int row, bool *has_decor) ADD_C(args, WINDOW_OBJ(wp->handle)); ADD_C(args, BUFFER_OBJ(wp->w_buffer->handle)); ADD_C(args, INTEGER_OBJ(row)); - if (decor_provider_invoke((int)i, "line", p->redraw_line, args, true)) { - *has_decor = true; - } else { + if (!decor_provider_invoke((int)i, "line", p->redraw_line, args, true)) { // return 'false' or error: skip rest of this window kv_A(decor_providers, i).state = kDecorProviderWinDisabled; } diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index aaa77f5fcf..326e929fb6 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -2183,22 +2183,22 @@ static void keymap_unload(void) /// @param fmt format string containing one %s item /// @param buf buffer for the result /// @param len length of buffer -bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len) +int get_keymap_str(win_T *wp, char *fmt, char *buf, int len) { char *p; if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) { - return false; + return 0; } buf_T *old_curbuf = curbuf; win_T *old_curwin = curwin; + char to_evaluate[] = "b:keymap_name"; curbuf = wp->w_buffer; curwin = wp; - STRCPY(buf, "b:keymap_name"); // must be writable emsg_skip++; - char *s = p = eval_to_string(buf, false, false); + char *s = p = eval_to_string(to_evaluate, false, false); emsg_skip--; curbuf = old_curbuf; curwin = old_curwin; @@ -2209,9 +2209,12 @@ bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len) p = "lang"; } } - if (vim_snprintf(buf, (size_t)len, fmt, p) > len - 1) { + int plen = vim_snprintf(buf, (size_t)len, fmt, p); + xfree(s); + if (plen < 0 || plen > len - 1) { buf[0] = NUL; + plen = 0; } - xfree(s); - return buf[0] != NUL; + + return plen; } diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 3062b0f2a3..d5273ff3d1 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1051,12 +1051,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } - has_decor = decor_redraw_line(wp, lnum - 1, &decor_state); - if (!end_fill) { - decor_providers_invoke_line(wp, lnum - 1, &has_decor); + decor_providers_invoke_line(wp, lnum - 1); } + has_decor = decor_redraw_line(wp, lnum - 1, &decor_state); + if (has_decor) { extra_check = true; } diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index f8aeb02229..7f4de9eab8 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1045,7 +1045,7 @@ int showmode(void) if (State & MODE_LANGMAP) { if (curwin->w_p_arab) { msg_puts_hl(_(" Arabic"), hl_id, false); - } else if (get_keymap_str(curwin, " (%s)", NameBuff, MAXPATHL)) { + } else if (get_keymap_str(curwin, " (%s)", NameBuff, MAXPATHL) > 0) { msg_puts_hl(NameBuff, hl_id, false); } } @@ -1936,7 +1936,7 @@ static void win_update(win_T *wp) pos.lnum += cursor_above ? 1 : -1) { colnr_T t; - pos.col = (colnr_T)strlen(ml_get_buf(wp->w_buffer, pos.lnum)); + pos.col = ml_get_buf_len(wp->w_buffer, pos.lnum); getvvcol(wp, &pos, NULL, NULL, &t); toc = MAX(toc, t); } diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 6119d838f9..79eea718f4 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -95,6 +95,7 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col MTKey mark = { { row, col }, ns_id, id, flags, decor.data }; marktree_put(buf->b_marktree, mark, end_row, end_col, end_right_gravity); + decor_state_invalidate(buf); revised: if (decor_flags || decor.ext) { @@ -184,6 +185,8 @@ void extmark_del(buf_T *buf, MarkTreeIter *itr, MTKey key, bool restore) } } + decor_state_invalidate(buf); + // TODO(bfredl): delete it from current undo header, opportunistically? } @@ -237,6 +240,10 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r } } + if (marks_cleared_any) { + decor_state_invalidate(buf); + } + return marks_cleared_any; } diff --git a/src/nvim/generators/gen_vimvim.lua b/src/nvim/generators/gen_vimvim.lua index 0675f04b73..d8053822bf 100644 --- a/src/nvim/generators/gen_vimvim.lua +++ b/src/nvim/generators/gen_vimvim.lua @@ -52,11 +52,13 @@ local function is_special_cased_cmd(cmd) end local vimcmd_start = 'syn keyword vimCommand contained ' +local vimcmd_end = ' nextgroup=vimBang' w(vimcmd_start) + local prev_cmd = nil for _, cmd_desc in ipairs(ex_cmds.cmds) do if lld.line_length > 850 then - w('\n' .. vimcmd_start) + w(vimcmd_end .. '\n' .. vimcmd_start) end local cmd = cmd_desc.command if cmd:match('%w') and cmd ~= 'z' and not is_special_cased_cmd(cmd) then @@ -79,9 +81,11 @@ for _, cmd_desc in ipairs(ex_cmds.cmds) do prev_cmd = cmd end +w(vimcmd_end .. '\n') + local vimopt_start = 'syn keyword vimOption contained ' local vimopt_end = ' skipwhite nextgroup=vimSetEqual,vimSetMod' -w('\n\n' .. vimopt_start) +w('\n' .. vimopt_start) for _, opt_desc in ipairs(options.options) do if not opt_desc.immutable then diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 6575113e2f..ad4b2732f6 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -150,6 +150,7 @@ static const char *highlight_init_both[] = { "PmenuMatchSel gui=bold cterm=bold", "PmenuSel gui=reverse cterm=reverse,underline blend=0", "RedrawDebugNormal gui=reverse cterm=reverse", + "TabLineSel gui=bold cterm=NONE", "TermCursor gui=reverse cterm=reverse", "Underlined gui=underline cterm=underline", "lCursor guifg=bg guibg=fg", @@ -180,7 +181,6 @@ static const char *highlight_init_both[] = { "default link StatusLineTermNC StatusLineNC", "default link TabLine StatusLineNC", "default link TabLineFill TabLine", - "default link TabLineSel Normal", "default link VertSplit WinSeparator", "default link VisualNOS Visual", "default link Whitespace NonText", diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 9b77644085..419c806592 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -10,6 +10,7 @@ #include <string.h> #include "klib/kvec.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" @@ -156,7 +157,7 @@ struct compl_S { compl_T *cp_next; compl_T *cp_prev; compl_T *cp_match_next; ///< matched next compl_T - char *cp_str; ///< matched text + String cp_str; ///< matched text char *(cp_text[CPT_COUNT]); ///< text for the menu typval_T cp_user_data; char *cp_fname; ///< file containing the match, allocated when @@ -220,7 +221,7 @@ static bool compl_enter_selects = false; /// When "compl_leader" is not NULL only matches that start with this string /// are used. -static char *compl_leader = NULL; +static String compl_leader = STRING_INIT; static bool compl_get_longest = false; ///< put longest common string in compl_leader @@ -245,8 +246,7 @@ static bool compl_started = false; static int ctrl_x_mode = CTRL_X_NORMAL; static int compl_matches = 0; ///< number of completion matches -static char *compl_pattern = NULL; -static size_t compl_patternlen = 0; +static String compl_pattern = STRING_INIT; static Direction compl_direction = FORWARD; static Direction compl_shows_dir = FORWARD; static int compl_pending = 0; ///< > 1 for postponed CTRL-N @@ -257,8 +257,8 @@ static int compl_length = 0; static colnr_T compl_col = 0; ///< column where the text starts ///< that is being completed static colnr_T compl_ins_end_col = 0; -static char *compl_orig_text = NULL; ///< text as it was before - ///< completion started +static String compl_orig_text = STRING_INIT; ///< text as it was before + ///< completion started /// Undo information to restore extmarks for original text. static extmark_undo_vec_t compl_orig_extmarks; static int compl_cont_mode = 0; @@ -639,7 +639,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp // Rule 1: Were any chars converted to lower? { - const char *p = compl_orig_text; + const char *p = compl_orig_text.data; for (int i = 0; i < min_len; i++) { const int c = mb_ptr2char_adv(&p); if (mb_islower(c)) { @@ -659,7 +659,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp // upper case. if (!has_lower) { bool was_letter = false; - const char *p = compl_orig_text; + const char *p = compl_orig_text.data; for (int i = 0; i < min_len; i++) { const int c = mb_ptr2char_adv(&p); if (was_letter && mb_isupper(c) && mb_islower(wca[i])) { @@ -675,7 +675,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp // Copy the original case of the part we typed. { - const char *p = compl_orig_text; + const char *p = compl_orig_text.data; for (int i = 0; i < min_len; i++) { const int c = mb_ptr2char_adv(&p); if (mb_islower(c)) { @@ -705,7 +705,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp ga_grow(&gap, IOSIZE); *p = NUL; STRCPY(gap.ga_data, IObuff); - gap.ga_len = (int)strlen(IObuff); + gap.ga_len = (int)(p - IObuff); } else { p += utf_char2bytes(wca[i++], p); } @@ -752,7 +752,7 @@ int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Dir // Find actual length of original text. { - const char *p = compl_orig_text; + const char *p = compl_orig_text.data; compl_char_len = 0; while (*p != NUL) { MB_PTR_ADV(p); @@ -841,8 +841,8 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons match = compl_first_match; do { if (!match_at_original_text(match) - && strncmp(match->cp_str, str, (size_t)len) == 0 - && ((int)strlen(match->cp_str) <= len || match->cp_str[len] == NUL)) { + && strncmp(match->cp_str.data, str, (size_t)len) == 0 + && ((int)match->cp_str.size <= len || match->cp_str.data[len] == NUL)) { if (cptext_allocated) { free_cptext(cptext); } @@ -862,7 +862,7 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons if (flags & CP_ORIGINAL_TEXT) { match->cp_number = 0; } - match->cp_str = xstrnsave(str, (size_t)len); + match->cp_str = cbuf_to_string(str, (size_t)len); // match-fname is: // - compl_curr_match->cp_fname if it is a string equal to fname. @@ -944,9 +944,9 @@ static bool ins_compl_equal(compl_T *match, char *str, size_t len) return true; } if (match->cp_flags & CP_ICASE) { - return STRNICMP(match->cp_str, str, len) == 0; + return STRNICMP(match->cp_str.data, str, len) == 0; } - return strncmp(match->cp_str, str, len) == 0; + return strncmp(match->cp_str.data, str, len) == 0; } /// when len is -1 mean use whole length of p otherwise part of p @@ -976,13 +976,13 @@ int ins_compl_col_range_attr(int col) /// Reduce the longest common string for match "match". static void ins_compl_longest_match(compl_T *match) { - if (compl_leader == NULL) { + if (compl_leader.data == NULL) { // First match, use it as a whole. - compl_leader = xstrdup(match->cp_str); + compl_leader = copy_string(match->cp_str, NULL); bool had_match = (curwin->w_cursor.col > compl_col); ins_compl_delete(false); - ins_compl_insert_bytes(compl_leader + get_compl_len(), -1); + ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1); ins_redraw(false); // When the match isn't there (to avoid matching itself) remove it @@ -996,8 +996,8 @@ static void ins_compl_longest_match(compl_T *match) } // Reduce the text if this match differs from compl_leader. - char *p = compl_leader; - char *s = match->cp_str; + char *p = compl_leader.data; + char *s = match->cp_str.data; while (*p != NUL) { int c1 = utf_ptr2char(p); int c2 = utf_ptr2char(s); @@ -1014,9 +1014,11 @@ static void ins_compl_longest_match(compl_T *match) if (*p != NUL) { // Leader was shortened, need to change the inserted text. *p = NUL; + compl_leader.size = (size_t)(p - compl_leader.data); + bool had_match = (curwin->w_cursor.col > compl_col); ins_compl_delete(false); - ins_compl_insert_bytes(compl_leader + get_compl_len(), -1); + ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1); ins_redraw(false); // When the match isn't there (to avoid matching itself) remove it @@ -1078,8 +1080,8 @@ bool ins_compl_has_shown_match(void) /// Return whether the shown match is long enough. bool ins_compl_long_shown_match(void) { - return compl_shown_match != NULL && compl_shown_match->cp_str != NULL - && (colnr_T)strlen(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col; + return compl_shown_match != NULL && compl_shown_match->cp_str.data != NULL + && (colnr_T)compl_shown_match->cp_str.size > curwin->w_cursor.col - compl_col; } /// Get the local or global value of 'completeopt' flags. @@ -1134,7 +1136,7 @@ static dict_T *ins_compl_dict_alloc(compl_T *match) { // { word, abbr, menu, kind, info } dict_T *dict = tv_dict_alloc_lock(VAR_FIXED); - tv_dict_add_str(dict, S_LEN("word"), match->cp_str); + tv_dict_add_str(dict, S_LEN("word"), match->cp_str.data); tv_dict_add_str(dict, S_LEN("abbr"), match->cp_text[CPT_ABBR]); tv_dict_add_str(dict, S_LEN("menu"), match->cp_text[CPT_MENU]); tv_dict_add_str(dict, S_LEN("kind"), match->cp_text[CPT_KIND]); @@ -1203,7 +1205,6 @@ static int ins_compl_build_pum(void) XFREE_CLEAR(compl_leader); } - const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 0; int max_fuzzy_score = 0; unsigned cur_cot_flags = get_cot_flags(); bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0; @@ -1214,7 +1215,7 @@ static int ins_compl_build_pum(void) // match after it, don't highlight anything. bool shown_match_ok = match_at_original_text(compl_shown_match); - if (strequal(compl_leader, compl_orig_text) && !shown_match_ok) { + if (strequal(compl_leader.data, compl_orig_text.data) && !shown_match_ok) { compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next; } @@ -1227,13 +1228,13 @@ static int ins_compl_build_pum(void) comp->cp_in_match_array = false; // When 'completeopt' contains "fuzzy" and leader is not NULL or empty, // set the cp_score for later comparisons. - if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) { - comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader); + if (compl_fuzzy_match && compl_leader.data != NULL && compl_leader.size > 0) { + comp->cp_score = fuzzy_match_str(comp->cp_str.data, compl_leader.data); } if (!match_at_original_text(comp) - && (compl_leader == NULL - || ins_compl_equal(comp, compl_leader, (size_t)lead_len) + && (compl_leader.data == NULL + || ins_compl_equal(comp, compl_leader.data, compl_leader.size) || (compl_fuzzy_match && comp->cp_score > 0))) { compl_match_arraysize++; comp->cp_in_match_array = true; @@ -1305,7 +1306,7 @@ static int ins_compl_build_pum(void) comp = match_head; while (comp != NULL) { compl_match_array[i].pum_text = comp->cp_text[CPT_ABBR] != NULL - ? comp->cp_text[CPT_ABBR] : comp->cp_str; + ? comp->cp_text[CPT_ABBR] : comp->cp_str.data; compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND]; compl_match_array[i].pum_info = comp->cp_text[CPT_INFO]; compl_match_array[i].pum_score = comp->cp_score; @@ -1318,7 +1319,7 @@ static int ins_compl_build_pum(void) comp = match_next; } - if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) { + if (compl_fuzzy_match && compl_leader.data != NULL && compl_leader.size > 0) { for (i = 0; i < compl_match_arraysize; i++) { compl_match_array[i].pum_idx = i; } @@ -1356,7 +1357,7 @@ void ins_compl_show_pum(void) } else { // popup menu already exists, only need to find the current item. for (int i = 0; i < compl_match_arraysize; i++) { - if (compl_match_array[i].pum_text == compl_shown_match->cp_str + if (compl_match_array[i].pum_text == compl_shown_match->cp_str.data || compl_match_array[i].pum_text == compl_shown_match->cp_text[CPT_ABBR]) { cur = i; break; @@ -1425,7 +1426,13 @@ bool compl_match_curr_select(int selected) /// Get current completion leader char *ins_compl_leader(void) { - return compl_leader != NULL ? compl_leader : compl_orig_text; + return compl_leader.data != NULL ? compl_leader.data : compl_orig_text.data; +} + +/// Get current completion leader length +size_t ins_compl_leader_len(void) +{ + return compl_leader.data != NULL ? compl_leader.size : compl_orig_text.size; } /// Add any identifiers that match the given pattern "pat" in the list of @@ -1671,9 +1678,8 @@ static char *find_line_end(char *ptr) /// Free the list of completions static void ins_compl_free(void) { - XFREE_CLEAR(compl_pattern); - compl_patternlen = 0; - XFREE_CLEAR(compl_leader); + API_CLEAR_STRING(compl_pattern); + API_CLEAR_STRING(compl_leader); if (compl_first_match == NULL) { return; @@ -1686,7 +1692,7 @@ static void ins_compl_free(void) do { compl_T *match = compl_curr_match; compl_curr_match = compl_curr_match->cp_next; - xfree(match->cp_str); + API_CLEAR_STRING(match->cp_str); // several entries may use the same fname, free it just once. if (match->cp_flags & CP_FREE_FNAME) { xfree(match->cp_fname); @@ -1707,12 +1713,11 @@ void ins_compl_clear(void) compl_started = false; compl_matches = 0; compl_ins_end_col = 0; - XFREE_CLEAR(compl_pattern); - compl_patternlen = 0; - XFREE_CLEAR(compl_leader); + API_CLEAR_STRING(compl_pattern); + API_CLEAR_STRING(compl_leader); edit_submode_extra = NULL; kv_destroy(compl_orig_extmarks); - XFREE_CLEAR(compl_orig_text); + API_CLEAR_STRING(compl_orig_text); compl_enter_selects = false; // clear v:completed_item set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED)); @@ -1802,8 +1807,9 @@ int ins_compl_bs(void) // TODO(bfredl): get rid of random update_screen() calls deep inside completion logic line = get_cursor_line_ptr(); - xfree(compl_leader); - compl_leader = xstrnsave(line + compl_col, (size_t)(p_off - (ptrdiff_t)compl_col)); + API_CLEAR_STRING(compl_leader); + compl_leader = cbuf_to_string(line + compl_col, + (size_t)(p_off - (ptrdiff_t)compl_col)); ins_compl_new_leader(); if (compl_shown_match != NULL) { @@ -1837,11 +1843,11 @@ static void ins_compl_new_leader(void) { ins_compl_del_pum(); ins_compl_delete(true); - ins_compl_insert_bytes(compl_leader + get_compl_len(), -1); + ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1); compl_used_match = false; if (compl_started) { - ins_compl_set_original_text(compl_leader); + ins_compl_set_original_text(compl_leader.data, compl_leader.size); } else { spell_bad_len = 0; // need to redetect bad word // Matches were cleared, need to search for them now. @@ -1901,9 +1907,9 @@ void ins_compl_addleader(int c) ins_compl_restart(); } - xfree(compl_leader); - compl_leader = xstrnsave(get_cursor_line_ptr() + compl_col, - (size_t)(curwin->w_cursor.col - compl_col)); + API_CLEAR_STRING(compl_leader); + compl_leader = cbuf_to_string(get_cursor_line_ptr() + compl_col, + (size_t)(curwin->w_cursor.col - compl_col)); ins_compl_new_leader(); } @@ -1923,19 +1929,19 @@ static void ins_compl_restart(void) } /// Set the first match, the original text. -static void ins_compl_set_original_text(char *str) +static void ins_compl_set_original_text(char *str, size_t len) FUNC_ATTR_NONNULL_ALL { // Replace the original text entry. // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly // be at the last item for backward completion if (match_at_original_text(compl_first_match)) { // safety check - xfree(compl_first_match->cp_str); - compl_first_match->cp_str = xstrdup(str); + API_CLEAR_STRING(compl_first_match->cp_str); + compl_first_match->cp_str = cbuf_to_string(str, len); } else if (compl_first_match->cp_prev != NULL && match_at_original_text(compl_first_match->cp_prev)) { - xfree(compl_first_match->cp_prev->cp_str); - compl_first_match->cp_prev->cp_str = xstrdup(str); + API_CLEAR_STRING(compl_first_match->cp_prev->cp_str); + compl_first_match->cp_prev->cp_str = cbuf_to_string(str, len); } } @@ -1945,8 +1951,8 @@ void ins_compl_addfrommatch(void) { int len = (int)curwin->w_cursor.col - (int)compl_col; assert(compl_shown_match != NULL); - char *p = compl_shown_match->cp_str; - if ((int)strlen(p) <= len) { // the match is too short + char *p = compl_shown_match->cp_str.data; + if ((int)compl_shown_match->cp_str.size <= len) { // the match is too short // When still at the original match use the first entry that matches // the leader. if (!match_at_original_text(compl_shown_match)) { @@ -1954,15 +1960,17 @@ void ins_compl_addfrommatch(void) } p = NULL; + size_t plen = 0; for (compl_T *cp = compl_shown_match->cp_next; cp != NULL && !is_first_match(cp); cp = cp->cp_next) { - if (compl_leader == NULL - || ins_compl_equal(cp, compl_leader, strlen(compl_leader))) { - p = cp->cp_str; + if (compl_leader.data == NULL + || ins_compl_equal(cp, compl_leader.data, compl_leader.size)) { + p = cp->cp_str.data; + plen = cp->cp_str.size; break; } } - if (p == NULL || (int)strlen(p) <= len) { + if (p == NULL || (int)plen <= len) { return; } } @@ -2102,7 +2110,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) // Get here when we have finished typing a sequence of ^N and // ^P or other completion characters in CTRL-X mode. Free up // memory that was used, and make sure we can redo the insert. - if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E) { + if (compl_curr_match != NULL || compl_leader.data != NULL || c == Ctrl_E) { // If any of the original typed text has been changed, eg when // ignorecase is set, we must add back-spaces to the redo // buffer. We add as few as necessary to delete just the part @@ -2111,7 +2119,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) // CTRL-E then don't use the current match. char *ptr; if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) { - ptr = compl_curr_match->cp_str; + ptr = compl_curr_match->cp_str.data; } else { ptr = NULL; } @@ -2154,7 +2162,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) if ((c == Ctrl_Y || (compl_enter_selects && (c == CAR || c == K_KENTER || c == NL))) && pum_visible()) { - word = xstrdup(compl_shown_match->cp_str); + word = xstrdup(compl_shown_match->cp_str.data); retval = true; // May need to remove ComplMatchIns highlight. redrawWinline(curwin, curwin->w_cursor.lnum); @@ -2165,16 +2173,18 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) if (c == Ctrl_E) { ins_compl_delete(false); char *p = NULL; - if (compl_leader != NULL) { - p = compl_leader; + size_t plen = 0; + if (compl_leader.data != NULL) { + p = compl_leader.data; + plen = compl_leader.size; } else if (compl_first_match != NULL) { - p = compl_orig_text; + p = compl_orig_text.data; + plen = compl_orig_text.size; } if (p != NULL) { const int compl_len = get_compl_len(); - const int len = (int)strlen(p); - if (len > compl_len) { - ins_compl_insert_bytes(p + compl_len, len - compl_len); + if ((int)plen > compl_len) { + ins_compl_insert_bytes(p + compl_len, (int)plen - compl_len); } } restore_orig_extmarks(); @@ -2324,18 +2334,18 @@ bool ins_compl_prep(int c) /// "ptr" is the known leader text or NUL. static void ins_compl_fixRedoBufForLeader(char *ptr_arg) { - int len; + int len = 0; char *ptr = ptr_arg; if (ptr == NULL) { - if (compl_leader != NULL) { - ptr = compl_leader; + if (compl_leader.data != NULL) { + ptr = compl_leader.data; } else { return; // nothing to do } } - if (compl_orig_text != NULL) { - char *p = compl_orig_text; + if (compl_orig_text.data != NULL) { + char *p = compl_orig_text.data; for (len = 0; p[len] != NUL && p[len] == ptr[len]; len++) {} if (len > 0) { len -= utf_head_off(p, p + len); @@ -2343,8 +2353,6 @@ static void ins_compl_fixRedoBufForLeader(char *ptr_arg) for (p += len; *p != NUL; MB_PTR_ADV(p)) { AppendCharToRedobuff(K_BS); } - } else { - len = 0; } AppendToRedobuffLit(ptr + len, -1); } @@ -2730,12 +2738,14 @@ static void set_completion(colnr_T startcol, list_T *list) compl_col = startcol; compl_length = curwin->w_cursor.col - startcol; // compl_pattern doesn't need to be set - compl_orig_text = xstrnsave(get_cursor_line_ptr() + compl_col, (size_t)compl_length); + compl_orig_text = cbuf_to_string(get_cursor_line_ptr() + compl_col, + (size_t)compl_length); save_orig_extmarks(); if (p_ic) { flags |= CP_ICASE; } - if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0, + if (ins_compl_add(compl_orig_text.data, (int)compl_orig_text.size, + NULL, NULL, false, NULL, 0, flags | CP_FAST, false, NULL) != OK) { return; } @@ -2940,7 +2950,7 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) if (has_items || (has_matches && match->cp_in_match_array)) { dict_T *di = tv_dict_alloc(); tv_list_append_dict(li, di); - tv_dict_add_str(di, S_LEN("word"), match->cp_str); + tv_dict_add_str(di, S_LEN("word"), match->cp_str.data); tv_dict_add_str(di, S_LEN("abbr"), match->cp_text[CPT_ABBR]); tv_dict_add_str(di, S_LEN("menu"), match->cp_text[CPT_MENU]); tv_dict_add_str(di, S_LEN("kind"), match->cp_text[CPT_KIND]); @@ -3137,8 +3147,8 @@ done: /// included files. static void get_next_include_file_completion(int compl_type) { - find_pattern_in_path(compl_pattern, compl_direction, - compl_patternlen, false, false, + find_pattern_in_path(compl_pattern.data, compl_direction, + compl_pattern.size, false, false, ((compl_type == CTRL_X_PATH_DEFINES && !(compl_cont_status & CONT_SOL)) ? FIND_DEFINE : FIND_ANY), @@ -3150,14 +3160,14 @@ static void get_next_include_file_completion(int compl_type) static void get_next_dict_tsr_completion(int compl_type, char *dict, int dict_f) { if (thesaurus_func_complete(compl_type)) { - expand_by_function(compl_type, compl_pattern); + expand_by_function(compl_type, compl_pattern.data); } else { ins_compl_dictionaries(dict != NULL ? dict : (compl_type == CTRL_X_THESAURUS ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr) : (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)), - compl_pattern, + compl_pattern.data, dict != NULL ? dict_f : 0, compl_type == CTRL_X_THESAURUS); } @@ -3168,14 +3178,14 @@ static void get_next_tag_completion(void) { // set p_ic according to p_ic, p_scs and pat for find_tags(). const int save_p_ic = p_ic; - p_ic = ignorecase(compl_pattern); + p_ic = ignorecase(compl_pattern.data); // Find up to TAG_MANY matches. Avoids that an enormous number // of matches is found when compl_pattern is empty g_tag_at_cursor = true; char **matches; int num_matches; - if (find_tags(compl_pattern, &num_matches, &matches, + if (find_tags(compl_pattern.data, &num_matches, &matches, TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP | (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0), TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) { @@ -3190,13 +3200,13 @@ static void get_next_filename_completion(void) { char **matches; int num_matches; - if (expand_wildcards(1, &compl_pattern, &num_matches, &matches, + if (expand_wildcards(1, &compl_pattern.data, &num_matches, &matches, EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) { return; } // May change home directory back to "~". - tilde_replace(compl_pattern, num_matches, matches); + tilde_replace(compl_pattern.data, num_matches, matches); #ifdef BACKSLASH_IN_FILENAME if (curbuf->b_p_csl[0] != NUL) { for (int i = 0; i < num_matches; i++) { @@ -3220,8 +3230,8 @@ static void get_next_cmdline_completion(void) { char **matches; int num_matches; - if (expand_cmdline(&compl_xp, compl_pattern, - (int)compl_patternlen, &num_matches, &matches) == EXPAND_OK) { + if (expand_cmdline(&compl_xp, compl_pattern.data, + (int)compl_pattern.size, &num_matches, &matches) == EXPAND_OK) { ins_compl_add_matches(num_matches, matches, false); } } @@ -3230,7 +3240,7 @@ static void get_next_cmdline_completion(void) static void get_next_spell_completion(linenr_T lnum) { char **matches; - int num_matches = expand_spelling(lnum, compl_pattern, &matches); + int num_matches = expand_spelling(lnum, compl_pattern.data, &matches); if (num_matches > 0) { ins_compl_add_matches(num_matches, matches, p_ic); } else { @@ -3249,22 +3259,24 @@ static char *ins_compl_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_po { *match_len = 0; char *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum) + cur_match_pos->col; - int len; + int len = ml_get_buf_len(ins_buf, cur_match_pos->lnum) - cur_match_pos->col; if (ctrl_x_mode_line_or_eval()) { if (compl_status_adding()) { if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count) { return NULL; } ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1); + len = ml_get_buf_len(ins_buf, cur_match_pos->lnum + 1); if (!p_paste) { - ptr = skipwhite(ptr); + char *tmp_ptr = ptr; + ptr = skipwhite(tmp_ptr); + len -= (int)(ptr - tmp_ptr); } } - len = (int)strlen(ptr); } else { char *tmp_ptr = ptr; - if (compl_status_adding() && compl_length <= (int)strlen(tmp_ptr)) { + if (compl_status_adding() && compl_length <= len) { tmp_ptr += compl_length; // Skip if already inside a word. if (vim_iswordp(tmp_ptr)) { @@ -3360,10 +3372,11 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_ // has added a word that was at the beginning of the line. if (ctrl_x_mode_line_or_eval() || (compl_cont_status & CONT_SOL)) { found_new_match = search_for_exact_line(st->ins_buf, st->cur_match_pos, - compl_direction, compl_pattern); + compl_direction, compl_pattern.data); } else { found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos, - NULL, compl_direction, compl_pattern, compl_patternlen, + NULL, compl_direction, compl_pattern.data, + compl_pattern.size, 1, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); } msg_silent--; @@ -3460,7 +3473,7 @@ static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_ case CTRL_X_FUNCTION: case CTRL_X_OMNI: - expand_by_function(type, compl_pattern); + expand_by_function(type, compl_pattern.data); break; case CTRL_X_SPELL: @@ -3491,7 +3504,7 @@ static void get_next_bufname_token(void) FOR_ALL_BUFFERS(b) { if (b->b_p_bl && b->b_sfname != NULL) { char *tail = path_tail(b->b_sfname); - if (strncmp(tail, compl_orig_text, strlen(compl_orig_text)) == 0) { + if (strncmp(tail, compl_orig_text.data, compl_orig_text.size) == 0) { ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0, p_ic ? CP_ICASE : 0, false, NULL); } @@ -3559,7 +3572,7 @@ static int ins_compl_get_exp(pos_T *ini) // If complete() was called then compl_pattern has been reset. // The following won't work then, bail out. - if (compl_pattern == NULL) { + if (compl_pattern.data == NULL) { break; } @@ -3627,7 +3640,7 @@ static int ins_compl_get_exp(pos_T *ini) static void ins_compl_update_shown_match(void) { while (!ins_compl_equal(compl_shown_match, - compl_leader, strlen(compl_leader)) + compl_leader.data, compl_leader.size) && compl_shown_match->cp_next != NULL && !is_first_match(compl_shown_match->cp_next)) { compl_shown_match = compl_shown_match->cp_next; @@ -3636,10 +3649,10 @@ static void ins_compl_update_shown_match(void) // If we didn't find it searching forward, and compl_shows_dir is // backward, find the last match. if (compl_shows_dir_backward() - && !ins_compl_equal(compl_shown_match, compl_leader, strlen(compl_leader)) + && !ins_compl_equal(compl_shown_match, compl_leader.data, compl_leader.size) && (compl_shown_match->cp_next == NULL || is_first_match(compl_shown_match->cp_next))) { - while (!ins_compl_equal(compl_shown_match, compl_leader, strlen(compl_leader)) + while (!ins_compl_equal(compl_shown_match, compl_leader.data, compl_leader.size) && compl_shown_match->cp_prev != NULL && !is_first_match(compl_shown_match->cp_prev)) { compl_shown_match = compl_shown_match->cp_prev; @@ -3654,13 +3667,13 @@ void ins_compl_delete(bool new_leader) // allows marks present on the original text to shrink/grow appropriately. int orig_col = 0; if (new_leader) { - char *orig = compl_orig_text; + char *orig = compl_orig_text.data; char *leader = ins_compl_leader(); while (*orig != NUL && utf_ptr2char(orig) == utf_ptr2char(leader)) { leader += utf_ptr2len(leader); orig += utf_ptr2len(orig); } - orig_col = (int)(orig - compl_orig_text); + orig_col = (int)(orig - compl_orig_text.data); } // In insert mode: Delete the typed part. @@ -3688,8 +3701,8 @@ void ins_compl_insert(bool in_compl_func) int compl_len = get_compl_len(); // Make sure we don't go over the end of the string, this can happen with // illegal bytes. - if (compl_len < (int)strlen(compl_shown_match->cp_str)) { - ins_compl_insert_bytes(compl_shown_match->cp_str + compl_len, -1); + if (compl_len < (int)compl_shown_match->cp_str.size) { + ins_compl_insert_bytes(compl_shown_match->cp_str.data + compl_len, -1); } compl_used_match = !match_at_original_text(compl_shown_match); @@ -3759,7 +3772,7 @@ static compl_T *find_comp_when_fuzzy(void) comp = compl_first_match; do { if (comp->cp_score == score - && (str == comp->cp_str || str == comp->cp_text[CPT_ABBR])) { + && (str == comp->cp_str.data || str == comp->cp_text[CPT_ABBR])) { return comp; } comp = comp->cp_next; @@ -3842,9 +3855,9 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a found_end = false; } if (!match_at_original_text(compl_shown_match) - && compl_leader != NULL + && compl_leader.data != NULL && !ins_compl_equal(compl_shown_match, - compl_leader, strlen(compl_leader)) + compl_leader.data, compl_leader.size) && !(compl_fuzzy_match && compl_shown_match->cp_score > 0)) { todo++; } else { @@ -3900,7 +3913,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match return -1; } - if (compl_leader != NULL + if (compl_leader.data != NULL && !match_at_original_text(compl_shown_match) && !compl_fuzzy_match) { // Update "compl_shown_match" to the actually shown match @@ -3938,17 +3951,17 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match // Insert the text of the new completion, or the compl_leader. if (compl_no_insert && !started) { - ins_compl_insert_bytes(compl_orig_text + get_compl_len(), -1); + ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1); compl_used_match = false; restore_orig_extmarks(); } else if (insert_match) { if (!compl_get_longest || compl_used_match) { ins_compl_insert(in_compl_func); } else { - assert(compl_leader != NULL); - ins_compl_insert_bytes(compl_leader + get_compl_len(), -1); + assert(compl_leader.data != NULL); + ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1); } - if (!strcmp(compl_curr_match->cp_str, compl_orig_text)) { + if (strequal(compl_curr_match->cp_str.data, compl_orig_text.data)) { restore_orig_extmarks(); } } else { @@ -4112,8 +4125,7 @@ static bool ins_compl_use_match(int c) /// Get the pattern, column and length for normal completion (CTRL-N CTRL-P /// completion) -/// Sets the global variables: compl_col, compl_length, compl_pattern and -/// compl_patternlen. +/// Sets the global variables: compl_col, compl_length and compl_pattern. /// Uses the global variables: compl_cont_status and ctrl_x_mode static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) { @@ -4124,29 +4136,32 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) compl_length = curs_col - startcol; } if (p_ic) { - compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0); + compl_pattern = cstr_as_string(str_foldcase(line + compl_col, + compl_length, NULL, 0)); } else { - compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); + compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length); } } else if (compl_status_adding()) { char *prefix = "\\<"; size_t prefixlen = STRLEN_LITERAL("\\<"); - // we need up to 2 extra chars for the prefix - compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, - compl_length) + prefixlen); if (!vim_iswordp(line + compl_col) || (compl_col > 0 && (vim_iswordp(mb_prevptr(line, line + compl_col))))) { prefix = ""; prefixlen = 0; } - STRCPY(compl_pattern, prefix); - quote_meta(compl_pattern + prefixlen, line + compl_col, compl_length); + + // we need up to 2 extra chars for the prefix + size_t n = quote_meta(NULL, line + compl_col, compl_length) + prefixlen; + compl_pattern.data = xmalloc(n); + STRCPY(compl_pattern.data, prefix); + quote_meta(compl_pattern.data + prefixlen, line + compl_col, compl_length); + compl_pattern.size = n - 1; } else if (--startcol < 0 || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) { // Match any word of at least two chars - compl_pattern = xstrnsave(S_LEN("\\<\\k\\k")); + compl_pattern = cbuf_to_string(S_LEN("\\<\\k\\k")); compl_col += curs_col; compl_length = 0; } else { @@ -4167,19 +4182,20 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) // Only match word with at least two chars -- webb // there's no need to call quote_meta, // xmalloc(7) is enough -- Acevedo - compl_pattern = xmalloc(7); - STRCPY(compl_pattern, "\\<"); - quote_meta(compl_pattern + 2, line + compl_col, 1); - strcat(compl_pattern, "\\k"); + compl_pattern.data = xmalloc(7); + STRCPY(compl_pattern.data, "\\<"); + quote_meta(compl_pattern.data + 2, line + compl_col, 1); + strcat(compl_pattern.data, "\\k"); + compl_pattern.size = strlen(compl_pattern.data); } else { - compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2); - STRCPY(compl_pattern, "\\<"); - quote_meta(compl_pattern + 2, line + compl_col, compl_length); + size_t n = quote_meta(NULL, line + compl_col, compl_length) + 2; + compl_pattern.data = xmalloc(n); + STRCPY(compl_pattern.data, "\\<"); + quote_meta(compl_pattern.data + 2, line + compl_col, compl_length); + compl_pattern.size = n - 1; } } - compl_patternlen = strlen(compl_pattern); - return OK; } @@ -4194,13 +4210,12 @@ static int get_wholeline_compl_info(char *line, colnr_T curs_col) compl_length = 0; } if (p_ic) { - compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0); + compl_pattern = cstr_as_string(str_foldcase(line + compl_col, + compl_length, NULL, 0)); } else { - compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); + compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length); } - compl_patternlen = strlen(compl_pattern); - return OK; } @@ -4225,8 +4240,8 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col) compl_col += startcol; compl_length = (int)curs_col - startcol; - compl_pattern = addstar(line + compl_col, (size_t)compl_length, EXPAND_FILES); - compl_patternlen = strlen(compl_pattern); + compl_pattern = cstr_as_string(addstar(line + compl_col, + (size_t)compl_length, EXPAND_FILES)); return OK; } @@ -4235,9 +4250,9 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col) /// Sets the global variables: compl_col, compl_length and compl_pattern. static int get_cmdline_compl_info(char *line, colnr_T curs_col) { - compl_pattern = xstrnsave(line, (size_t)curs_col); - compl_patternlen = (size_t)curs_col; - set_cmd_context(&compl_xp, compl_pattern, (int)compl_patternlen, curs_col, false); + compl_pattern = cbuf_to_string(line, (size_t)curs_col); + set_cmd_context(&compl_xp, compl_pattern.data, + (int)compl_pattern.size, curs_col, false); if (compl_xp.xp_context == EXPAND_LUA) { nlua_expand_pat(&compl_xp); } @@ -4247,7 +4262,7 @@ static int get_cmdline_compl_info(char *line, colnr_T curs_col) // "pattern not found" message. compl_col = curs_col; } else { - compl_col = (int)(compl_xp.xp_pattern - compl_pattern); + compl_col = (int)(compl_xp.xp_pattern - compl_pattern.data); } compl_length = curs_col - compl_col; @@ -4325,8 +4340,7 @@ static int get_userdefined_compl_info(colnr_T curs_col) // it may have become invalid. char *line = ml_get(curwin->w_cursor.lnum); compl_length = curs_col - compl_col; - compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); - compl_patternlen = (size_t)compl_length; + compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length); return OK; } @@ -4351,8 +4365,7 @@ static int get_spell_compl_info(int startcol, colnr_T curs_col) } // Need to obtain "line" again, it may have become invalid. char *line = ml_get(curwin->w_cursor.lnum); - compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); - compl_patternlen = (size_t)compl_length; + compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length); return OK; } @@ -4537,19 +4550,19 @@ static int ins_compl_start(void) ins_compl_fixRedoBufForLeader(NULL); // Always add completion for the original text. - xfree(compl_orig_text); + API_CLEAR_STRING(compl_orig_text); kv_destroy(compl_orig_extmarks); - compl_orig_text = xstrnsave(line + compl_col, (size_t)compl_length); + compl_orig_text = cbuf_to_string(line + compl_col, (size_t)compl_length); save_orig_extmarks(); int flags = CP_ORIGINAL_TEXT; if (p_ic) { flags |= CP_ICASE; } - if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0, + if (ins_compl_add(compl_orig_text.data, (int)compl_orig_text.size, + NULL, NULL, false, NULL, 0, flags, false, NULL) != OK) { - XFREE_CLEAR(compl_pattern); - compl_patternlen = 0; - XFREE_CLEAR(compl_orig_text); + API_CLEAR_STRING(compl_pattern); + API_CLEAR_STRING(compl_orig_text); kv_destroy(compl_orig_extmarks); return FAIL; } @@ -4783,7 +4796,7 @@ static unsigned quote_meta(char *dest, char *src, int len) #if defined(EXITFREE) void free_insexpand_stuff(void) { - XFREE_CLEAR(compl_orig_text); + API_CLEAR_STRING(compl_orig_text); kv_destroy(compl_orig_extmarks); callback_free(&cfu_cb); callback_free(&ofu_cb); diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index d47340505a..fe6892cc27 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -96,53 +96,51 @@ void win_redr_status(win_T *wp) get_trans_bufname(wp->w_buffer); char *p = NameBuff; - int len = (int)strlen(p); + int plen = (int)strlen(p); if ((bt_help(wp->w_buffer) || wp->w_p_pvw || bufIsChanged(wp->w_buffer) || wp->w_buffer->b_p_ro) - && len < MAXPATHL - 1) { - *(p + len++) = ' '; + && plen < MAXPATHL - 1) { + *(p + plen++) = ' '; } if (bt_help(wp->w_buffer)) { - snprintf(p + len, MAXPATHL - (size_t)len, "%s", _("[Help]")); - len += (int)strlen(p + len); + plen += snprintf(p + plen, MAXPATHL - (size_t)plen, "%s", _("[Help]")); } if (wp->w_p_pvw) { - snprintf(p + len, MAXPATHL - (size_t)len, "%s", _("[Preview]")); - len += (int)strlen(p + len); + plen += snprintf(p + plen, MAXPATHL - (size_t)plen, "%s", _("[Preview]")); } if (bufIsChanged(wp->w_buffer)) { - snprintf(p + len, MAXPATHL - (size_t)len, "%s", "[+]"); - len += (int)strlen(p + len); + plen += snprintf(p + plen, MAXPATHL - (size_t)plen, "%s", "[+]"); } if (wp->w_buffer->b_p_ro) { - snprintf(p + len, MAXPATHL - (size_t)len, "%s", _("[RO]")); - // len += (int)strlen(p + len); // dead assignment + plen += snprintf(p + plen, MAXPATHL - (size_t)plen, "%s", _("[RO]")); } + (void)plen; - int this_ru_col = MAX(ru_col - (Columns - stl_width), (stl_width + 1) / 2); + int n = (stl_width + 1) / 2; + int this_ru_col = ru_col - (Columns - stl_width); + this_ru_col = MAX(this_ru_col, n); if (this_ru_col <= 1) { p = "<"; // No room for file name! - len = 1; + plen = 1; } else { int i; // Count total number of display cells. - int clen = (int)mb_string2cells(p); + plen = (int)mb_string2cells(p); // Find first character that will fit. // Going from start to end is much faster for DBCS. - for (i = 0; p[i] != NUL && clen >= this_ru_col - 1; + for (i = 0; p[i] != NUL && plen >= this_ru_col - 1; i += utfc_ptr2len(p + i)) { - clen -= utf_ptr2cells(p + i); + plen -= utf_ptr2cells(p + i); } - len = clen; if (i > 0) { p = p + i - 1; *p = '<'; - len++; + plen++; } } @@ -152,16 +150,17 @@ void win_redr_status(win_T *wp) int width = grid_line_puts(off, p, -1, attr); grid_line_fill(off + width, off + this_ru_col, fillchar, attr); - if (get_keymap_str(wp, "<%s>", NameBuff, MAXPATHL) - && this_ru_col - len > (int)strlen(NameBuff) + 1) { - grid_line_puts(off + this_ru_col - (int)strlen(NameBuff) - 1, NameBuff, -1, attr); + int NameBufflen = get_keymap_str(wp, "<%s>", NameBuff, MAXPATHL); + if (NameBufflen > 0 && this_ru_col - plen > NameBufflen + 1) { + grid_line_puts(off + this_ru_col - NameBufflen - 1, NameBuff, -1, attr); } win_redr_ruler(wp); // Draw the 'showcmd' information if 'showcmdloc' == "statusline". if (p_sc && *p_sloc == 's') { - const int sc_width = MIN(10, this_ru_col - len - 2); + n = this_ru_col - plen - 2; // perform the calculation here so we only do it once + const int sc_width = MIN(10, n); if (sc_width > 0) { grid_line_puts(off + this_ru_col - sc_width - 1, showcmd_buf, sc_width, attr); @@ -548,36 +547,40 @@ void win_redr_ruler(win_T *wp) #define RULER_BUF_LEN 70 char buffer[RULER_BUF_LEN]; - // Some sprintfs return the length, some return a pointer. - // To avoid portability problems we use strlen() here. - vim_snprintf(buffer, RULER_BUF_LEN, "%" PRId64 ",", - (wp->w_buffer->b_ml.ml_flags & - ML_EMPTY) ? 0 : (int64_t)wp->w_cursor.lnum); - size_t len = strlen(buffer); - col_print(buffer + len, RULER_BUF_LEN - len, - empty_line ? 0 : (int)wp->w_cursor.col + 1, - (int)virtcol + 1); + int bufferlen = vim_snprintf(buffer, RULER_BUF_LEN, "%" PRId64 ",", + (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) + ? 0 + : (int64_t)wp->w_cursor.lnum); + bufferlen += col_print(buffer + bufferlen, RULER_BUF_LEN - (size_t)bufferlen, + empty_line ? 0 : (int)wp->w_cursor.col + 1, + (int)virtcol + 1); // Add a "50%" if there is room for it. // On the last line, don't print in the last column (scrolls the // screen up on some terminals). - int i = (int)strlen(buffer); - get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1); - int o = i + vim_strsize(buffer + i + 1); + char rel_pos[RULER_BUF_LEN]; + int rel_poslen = get_rel_pos(wp, rel_pos, RULER_BUF_LEN); + int n1 = bufferlen + vim_strsize(rel_pos); if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen - o++; + n1++; } + + int this_ru_col = ru_col - (Columns - width); // Never use more than half the window/screen width, leave the other half // for the filename. - int this_ru_col = MAX(ru_col - (Columns - width), (width + 1) / 2); - if (this_ru_col + o < width) { - // Need at least 3 chars left for get_rel_pos() + NUL. - while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) { - i += (int)schar_get(buffer + i, fillchar); - o++; - } - get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i); + int n2 = (width + 1) / 2; + this_ru_col = MAX(this_ru_col, n2); + if (this_ru_col + n1 < width) { + // need at least space for rel_pos + NUL + while (this_ru_col + n1 < width + && RULER_BUF_LEN > bufferlen + rel_poslen + 1) { // +1 for NUL + bufferlen += (int)schar_get(buffer + bufferlen, fillchar); + n1++; + } + bufferlen += vim_snprintf(buffer + bufferlen, RULER_BUF_LEN - (size_t)bufferlen, + "%s", rel_pos); } + (void)bufferlen; if (ui_has(kUIMessages) && !part_of_status) { MAXSIZE_TEMP_ARRAY(content, 1); @@ -595,11 +598,11 @@ void win_redr_ruler(win_T *wp) did_show_ext_ruler = false; } // Truncate at window boundary. - o = 0; - for (i = 0; buffer[i] != NUL; i += utfc_ptr2len(buffer + i)) { - o += utf_ptr2cells(buffer + i); - if (this_ru_col + o > width) { - buffer[i] = NUL; + for (n1 = 0, n2 = 0; buffer[n1] != NUL; n1 += utfc_ptr2len(buffer + n1)) { + n2 += utf_ptr2cells(buffer + n1); + if (this_ru_col + n2 > width) { + bufferlen = n1; + buffer[bufferlen] = NUL; break; } } @@ -1536,7 +1539,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // Store the position percentage in our temporary buffer. // Note: We cannot store the value in `num` because // `get_rel_pos` can return a named position. Ex: "Top" - get_rel_pos(wp, buf_tmp, TMPLEN); + (void)get_rel_pos(wp, buf_tmp, TMPLEN); str = buf_tmp; break; @@ -1564,7 +1567,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op case STL_KEYMAP: fillable = false; - if (get_keymap_str(wp, "<%s>", buf_tmp, TMPLEN)) { + if (get_keymap_str(wp, "<%s>", buf_tmp, TMPLEN) > 0) { str = buf_tmp; } break; diff --git a/src/nvim/vterm/screen.c b/src/nvim/vterm/screen.c index f24e47e543..c91c6fb84f 100644 --- a/src/nvim/vterm/screen.c +++ b/src/nvim/vterm/screen.c @@ -909,7 +909,7 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe return 0; } - cell->schar = intcell->schar; + cell->schar = (intcell->schar == (uint32_t)-1) ? 0 : intcell->schar; cell->attrs.bold = intcell->pen.bold; cell->attrs.underline = intcell->pen.underline; |