From 06347a64cac5e33574713a59ace9d1d0ea4b6f82 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 05:19:46 +0800 Subject: vim-patch:9.1.0443: Can't use blockwise selection with width for getregion() (#28985) Problem: Can't use a blockwise selection with a width for getregion(). Solution: Add support for blockwise selection with width like the return value of getregtype() or the "regtype" value of TextYankPost (zeertzjq). closes: vim/vim#14842 https://github.com/vim/vim/commit/afc2295c2201ae87bfbb42d5f5315ad0583ccabf --- src/nvim/eval.lua | 11 +++++------ src/nvim/eval/funcs.c | 30 +++++++++++++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 7d4438ded6..4adf3ce959 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -4370,14 +4370,13 @@ M.funcs = { The optional argument {opts} is a Dict and supports the following items: - type Specify the region's selection type - (default: "v"): - "v" for |charwise| mode - "V" for |linewise| mode - "" for |blockwise-visual| mode + type Specify the region's selection type. + See |getregtype()| for possible values, + except it cannot be an empty string. + (default: "v") exclusive If |TRUE|, use exclusive selection - for the end position + for the end position. (default: follow 'selection') You can get the last selection type by |visualmode()|. diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e4cb63eb8e..3cb6ef41c0 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2824,7 +2824,7 @@ static char *block_def2str(struct block_def *bd) } static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2, - bool *const inclusive, MotionType *region_type, oparg_T *oa) + bool *const inclusive, MotionType *region_type, oparg_T *oap) FUNC_ATTR_NONNULL_ALL { tv_list_alloc_ret(rettv, kListLenMayKnow); @@ -2858,11 +2858,17 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 type = default_type; } + int block_width = 0; if (type[0] == 'v' && type[1] == NUL) { *region_type = kMTCharWise; } else if (type[0] == 'V' && type[1] == NUL) { *region_type = kMTLineWise; - } else if (type[0] == Ctrl_V && type[1] == NUL) { + } else if (type[0] == Ctrl_V) { + char *p = type + 1; + if (*p != NUL && ((block_width = getdigits_int(&p, false, 0)) <= 0 || *p != NUL)) { + semsg(_(e_invargNval), "type", type); + return FAIL; + } *region_type = kMTBlockWise; } else { semsg(_(e_invargNval), "type", type); @@ -2926,16 +2932,18 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 colnr_T sc1, ec1, sc2, ec2; getvvcol(curwin, p1, &sc1, NULL, &ec1); getvvcol(curwin, p2, &sc2, NULL, &ec2); - oa->motion_type = kMTBlockWise; - oa->inclusive = true; - oa->op_type = OP_NOP; - oa->start = *p1; - oa->end = *p2; - oa->start_vcol = MIN(sc1, sc2); - if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { - oa->end_vcol = sc2 - 1; + oap->motion_type = kMTBlockWise; + oap->inclusive = true; + oap->op_type = OP_NOP; + oap->start = *p1; + oap->end = *p2; + oap->start_vcol = MIN(sc1, sc2); + if (block_width > 0) { + oap->end_vcol = oap->start_vcol + block_width - 1; + } else if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { + oap->end_vcol = sc2 - 1; } else { - oa->end_vcol = MAX(ec1, ec2); + oap->end_vcol = MAX(ec1, ec2); } } -- cgit From 8b2b1fba2abfb99186e3a1f0123251a3e2eae3fe Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 3 May 2024 15:53:13 +0800 Subject: fix(float): missing default highlight for title Problem: there is missing default title highlight when highlight not defined in title text chunk. Solution: when attr is not set use default title highlight group. --- src/nvim/api/win_config.c | 9 +++------ src/nvim/drawscreen.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 3a9986a7d1..70235d8db6 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -189,13 +189,13 @@ /// ``` /// - title: Title (optional) in window border, string or list. /// List should consist of `[text, highlight]` tuples. -/// If string, the default highlight group is `FloatTitle`. +/// If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`. /// - title_pos: Title position. Must be set with `title` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. /// - footer: Footer (optional) in window border, string or list. /// List should consist of `[text, highlight]` tuples. -/// If string, the default highlight group is `FloatFooter`. +/// If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`. /// - footer_pos: Footer position. Must be set with `footer` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. @@ -851,7 +851,6 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, bool *is_present; VirtText *chunks; int *width; - int default_hl_id; switch (bordertext_type) { case kBorderTextTitle: if (fconfig->title) { @@ -861,7 +860,6 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, is_present = &fconfig->title; chunks = &fconfig->title_chunks; width = &fconfig->title_width; - default_hl_id = syn_check_group(S_LEN("FloatTitle")); break; case kBorderTextFooter: if (fconfig->footer) { @@ -871,7 +869,6 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, is_present = &fconfig->footer; chunks = &fconfig->footer_chunks; width = &fconfig->footer_width; - default_hl_id = syn_check_group(S_LEN("FloatFooter")); break; } @@ -881,7 +878,7 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, return; } kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data), - .hl_id = default_hl_id })); + .hl_id = -1 })); *width = (int)mb_string2cells(bordertext.data.string.data); *is_present = true; return; diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index bda0ccc870..039bbd219c 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -65,6 +65,7 @@ #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cursor.h" @@ -715,14 +716,17 @@ void end_search_hl(void) screen_search_hl.rm.regprog = NULL; } -static void win_redr_bordertext(win_T *wp, VirtText vt, int col) +static void win_redr_bordertext(win_T *wp, VirtText vt, int col, BorderTextType bt) { for (size_t i = 0; i < kv_size(vt);) { - int attr = 0; + int attr = -1; char *text = next_virt_text_chunk(vt, &i, &attr); if (text == NULL) { break; } + if (attr == -1) { // No highlight specified. + attr = wp->w_ns_hl_attr[bt == kBorderTextTitle ? HLF_BTITLE : HLF_BFOOTER]; + } attr = hl_apply_winblend(wp, attr); col += grid_line_puts(col, text, -1, attr); } @@ -773,7 +777,7 @@ static void win_redr_border(win_T *wp) if (wp->w_config.title) { int title_col = win_get_bordertext_col(icol, wp->w_config.title_width, wp->w_config.title_pos); - win_redr_bordertext(wp, wp->w_config.title_chunks, title_col); + win_redr_bordertext(wp, wp->w_config.title_chunks, title_col, kBorderTextTitle); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[2], attrs[2]); @@ -809,7 +813,7 @@ static void win_redr_border(win_T *wp) if (wp->w_config.footer) { int footer_col = win_get_bordertext_col(icol, wp->w_config.footer_width, wp->w_config.footer_pos); - win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col); + win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col, kBorderTextFooter); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[4], attrs[4]); -- cgit From 4757d497f3c85cc343f7dcbc09f95e43ba5c1314 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 16:53:10 +0800 Subject: vim-patch:9.1.0444: Not enough tests for getregion() with multibyte chars (#29000) Problem: Not enough tests for getregion() with multibyte chars. Solution: Add a few more tests (zeertzjq). closes: vim/vim#14844 https://github.com/vim/vim/commit/dff55a335889c746a79974f7c52cdcdebad682c2 --- src/nvim/eval.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 4adf3ce959..f0c8963459 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -4372,7 +4372,8 @@ M.funcs = { type Specify the region's selection type. See |getregtype()| for possible values, - except it cannot be an empty string. + except that the width can be omitted + and an empty string cannot be used. (default: "v") exclusive If |TRUE|, use exclusive selection -- cgit From fdeb01cd77404aba446c67af32134a2ff793a14b Mon Sep 17 00:00:00 2001 From: Rafael Kitover Date: Sat, 25 May 2024 12:44:39 +0000 Subject: feat(main): expand file ~\ or ~/ prefix on Windows (#28515) In command_line_scan() for MSWIN, expand "~\" or "~/" prefixed paths to the USERPROFILE environment variable for the user's profile directory. Fix #23901 Signed-off-by: Rafael Kitover --- src/nvim/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index 30b6b6e86b..17a0bbf082 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1444,6 +1444,19 @@ scripterror: ga_grow(&global_alist.al_ga, 1); char *p = xstrdup(argv[0]); + // On Windows expand "~\" or "~/" prefix in file names to profile directory. +#ifdef MSWIN + if (*p == '~' && (p[1] == '\\' || p[1] == '/')) { + char *profile_dir = vim_getenv("HOME"); + size_t size = strlen(profile_dir) + strlen(p); + char *tilde_expanded = xmalloc(size); + snprintf(tilde_expanded, size, "%s%s", profile_dir, p + 1); + xfree(p); + xfree(profile_dir); + p = tilde_expanded; + } +#endif + if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0 && !os_isdir(alist_name(&GARGLIST[0]))) { char *r = concat_fnames(p, path_tail(alist_name(&GARGLIST[0])), true); -- cgit From bc63ffcf39e8ad6c0925c0ad8503bfb3ed8497f3 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 26 May 2024 19:54:08 +0200 Subject: fix(tui): reset clear_region attributes during startup #28713 Problem: Fix added in #28676 worked accidentally(used variables were themselves uninitialized at this point during startup) and does not always work. Solution: Reset attributes when clearing regions during startup. --- src/nvim/tui/tui.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2a9530defb..dc8c8def5b 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -115,6 +115,7 @@ struct TUIData { kvec_t(HlAttrs) attrs; int print_attr_id; bool default_attr; + bool set_default_colors; bool can_clear_attr; ModeShape showing_mode; Integer verbose; @@ -166,14 +167,6 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb) tui->seen_error_exit = 0; tui->loop = &main_loop; tui->url = -1; - // Because setting the default colors is delayed until after startup to avoid - // flickering with the default colorscheme background, any flush that happens - // during startup in turn would result in clearing invalidated regions with - // uninitialized attrs(black). Instead initialize clear_attrs with current - // terminal background so that it is at least not perceived as flickering, even - // though it may be different from the colorscheme that is set during startup. - tui->clear_attrs.rgb_bg_color = normal_bg; - tui->clear_attrs.cterm_bg_color = (int16_t)cterm_normal_bg_color; kv_init(tui->invalid_regions); kv_init(tui->urlbuf); @@ -1016,7 +1009,16 @@ static void clear_region(TUIData *tui, int top, int bot, int left, int right, in { UGrid *grid = &tui->grid; - update_attrs(tui, attr_id); + // Setting the default colors is delayed until after startup to avoid flickering + // with the default colorscheme background. Consequently, any flush that happens + // during startup would result in clearing invalidated regions with zeroed + // clear_attrs, perceived as a black flicker. Reset attributes to clear with + // current terminal background instead(#28667, #28668). + if (tui->set_default_colors) { + update_attrs(tui, attr_id); + } else { + unibi_out(tui, unibi_exit_attribute_mode); + } // Background is set to the default color and the right edge matches the // screen end, try to use terminal codes for clearing the requested area. @@ -1419,6 +1421,7 @@ void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Intege tui->clear_attrs.cterm_bg_color = (int16_t)cterm_bg; tui->print_attr_id = -1; + tui->set_default_colors = true; invalidate(tui, 0, tui->grid.height, 0, tui->grid.width); } -- cgit From 43a2019f09e855c4eae33bfdbdec4cc7b2985075 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 26 May 2024 19:55:57 +0200 Subject: fix(extmarks): issues with revalidating marks #28961 Problem: Invalid marks appear to be revalidated multiple times, and decor is added at the old position for unpaired marks. Solution: Avoid revalidating already valid marks, and don't use old position to add to decor for unpaired marks. --- src/nvim/extmark.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 3236590010..4e47fa76fe 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -117,9 +117,16 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool MarkTreeIter itr[1] = { 0 }; MTKey key = marktree_lookup(buf->b_marktree, mark, itr); if (key.pos.row < 0 || (key.pos.row == row && key.pos.col == col)) { + // Does this hold? If it doesn't, we should still revalidate. + assert(!invalid || !mt_invalid(key)); return; } + // Key already revalidated(how?) Avoid adding to decor again. + if (invalid && !mt_invalid(key)) { + invalid = false; + } + // Only the position before undo needs to be redrawn here, // as the position after undo should be marked as changed. if (!invalid && mt_decor_any(key) && key.pos.row != row) { @@ -140,8 +147,8 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool marktree_move(buf->b_marktree, itr, row, col); if (invalid) { - MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL); - buf_put_decor(buf, mt_decor(key), row, end.row); + row2 = mt_paired(key) ? marktree_get_altpos(buf->b_marktree, key, NULL).row : row; + buf_put_decor(buf, mt_decor(key), row, row2); } else if (key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { buf_signcols_count_range(buf, row1, row2, 0, kNone); } -- cgit From 22fe04452e12944b409c8ee92cf4069ac8026987 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 May 2024 05:50:49 +0800 Subject: vim-patch:9.1.0446: getregionpos() inconsistent for partly-selected multibyte char (#29032) Problem: getregionpos() behaves inconsistently for a partly-selected multibyte char. Solution: Always use column of the first byte for a partly-selected multibyte char (zeertzjq). closes: vim/vim#14851 https://github.com/vim/vim/commit/ef73374dc3e4bf8104ba31d5b22517f8028b467a --- src/nvim/eval/funcs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3cb6ef41c0..8b22c7a797 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3042,6 +3042,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) { pos_T ret_p1, ret_p2; + char *line = ml_get(lnum); colnr_T line_len = ml_get_len(lnum); if (region_type == kMTLineWise) { @@ -3060,7 +3061,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr if (bd.is_oneChar) { // selection entirely inside one char if (region_type == kMTBlockWise) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - (bd.start_vcol - oa.start_vcol); } else { ret_p1.col = p1.col + 1; @@ -3072,7 +3073,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr ret_p1.coladd = oa.start_vcol - bd.start_vcol; bd.is_oneChar = true; } else if (bd.startspaces > 0) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - bd.startspaces; } else { ret_p1.col = bd.textcol + 1; -- cgit From 9a0239fdc8b380a8a32739a7c722fe90e3c2e910 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 May 2024 14:37:22 +0800 Subject: fix(drawline): don't draw beyond end of window (#29035) --- src/nvim/drawline.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 07944081da..4d534d78a2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1596,6 +1596,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // hide virt_text on text hidden by 'nowrap' or 'smoothscroll' decor_redraw_col(wp, (colnr_T)(ptr - line) - 1, wlv.off, true, &decor_state); } + if (wlv.col >= grid->cols) { + wlv.col = wlv.off = grid->cols; + goto end_check; + } } if (cul_screenline && wlv.filler_todo <= 0 @@ -2650,13 +2654,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s conceal_cursor_used = conceal_cursor_line(curwin); } - // When the window is too narrow draw all "@" lines. - if (leftcols_width >= wp->w_grid.cols && is_wrapped) { - win_draw_end(wp, schar_from_ascii('@'), true, wlv.row, wp->w_grid.rows, HLF_AT); - set_empty_rows(wp, wlv.row); - wlv.row = endrow; - } - break; } @@ -2844,10 +2841,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } +end_check: // At end of screen line and there is more to come: Display the line // so far. If there is no more to display it is caught above. if (wlv.col >= grid->cols && (!has_foldtext || virt_line_offset >= 0) - && (*ptr != NUL + && (wlv.col <= leftcols_width + || *ptr != NUL || wlv.filler_todo > 0 || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL && lcs_eol_todo) || (wlv.n_extra != 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL)) -- cgit From 104800ce2eadd21475b5a4897265a8a177e58d77 Mon Sep 17 00:00:00 2001 From: Malte Dehling Date: Mon, 27 May 2024 04:14:57 -0700 Subject: build: "popcount" name conflict on NetBSD #28983 Problem: NetBSD's libc already has a function by the same name. Solution: Rename popcount to xpopcount and add #if defined(__NetBSD__) to prefer NetBSD's own implementation. This fixes #28983. --- src/nvim/api/vim.c | 4 ++-- src/nvim/math.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index fc780e1248..52ab18cbff 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2354,8 +2354,8 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } } - int count = (win != NULL) + (buf != NULL); - VALIDATE(popcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { + unsigned count = (win != NULL) + (buf != NULL); + VALIDATE(xpopcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { return; }); diff --git a/src/nvim/math.c b/src/nvim/math.c index 1ccf4d7806..4ca212413b 100644 --- a/src/nvim/math.c +++ b/src/nvim/math.c @@ -78,13 +78,15 @@ int xctz(uint64_t x) } /// Count number of set bits in bit field. -int popcount(uint64_t x) +unsigned xpopcount(uint64_t x) { // Use compiler builtin if possible. -#if defined(__clang__) || defined(__GNUC__) - return __builtin_popcountll(x); +#if defined(__NetBSD__) + return popcount64(x); +#elif defined(__clang__) || defined(__GNUC__) + return (unsigned)__builtin_popcountll(x); #else - int count = 0; + unsigned count = 0; for (; x != 0; x >>= 1) { if (x & 1) { count++; -- cgit From dbc2678f46970703616765dadff1234fdcce27b7 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 27 May 2024 22:02:24 +0800 Subject: vim-patch:9.1.0447: completion may be wrong when deleting all chars (#29040) Problem: completion may be wrong when deleting all chars. Solution: reset compl_shown_match (glepnir). closes: https://github.com/vim/vim/pull/14854 https://github.com/vim/vim/commit/53387c55a13bc1013a6ab721d4bd0bd04c6935c4 --- src/nvim/insexpand.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index b557b9802e..8b1c09b32f 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -1198,6 +1198,10 @@ 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) { + compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next; + } + compl_T *shown_compl = NULL; bool did_find_shown_match = false; int cur = -1; -- cgit From 6e8a728e3dad747d0c46dc47a530b76e8997bc08 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 May 2024 20:35:37 +0200 Subject: refactor: fix luals type warnings --- src/nvim/eval.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index f0c8963459..ceaba11f41 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -2133,6 +2133,7 @@ M.funcs = { name = 'exepath', params = { { 'expr', 'any' } }, signature = 'exepath({expr})', + returns = 'string', }, exists = { args = 1, -- cgit From 5b6477be45c54ebac4dce6bda51028542167fd1f Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 28 May 2024 11:43:56 +0200 Subject: fix(ui): flush ext_cmdline events before doing cmdpreview #27950 Problem: Unable to update the screen for external cmdline during cmdpreview. Solution: Flush the cmdline UI before cmdpreview state. --- src/nvim/ex_getln.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index f18dc0f747..cc2608433d 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2532,6 +2532,10 @@ static bool cmdpreview_may_show(CommandLineState *s) goto end; } + // Flush now: external cmdline may itself wish to update the screen which is + // currently disallowed during cmdpreview(no longer needed in case that changes). + cmdline_ui_flush(); + // Swap invalid command range if needed if ((ea.argt & EX_RANGE) && ea.line1 > ea.line2) { linenr_T lnum = ea.line1; -- cgit From ff7f22c28b602c84350785624b4b6fc9ae35f950 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 28 May 2024 13:03:00 +0200 Subject: refactor(fileio): remove useless use of FileDescriptor FileDescriptor is used to buffer togheter many small writes to fewer syscalls. if the data to write already is in a single buffer, it is perfectly fine to just use os_write directly (which will take care of the reverse problem: splitting a too big write into many syscalls) --- src/nvim/main.c | 14 ++------------ src/nvim/os/fileio.c | 11 ----------- 2 files changed, 2 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index 17a0bbf082..cf1324d37f 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1100,23 +1100,13 @@ static void command_line_scan(mparm_T *parmp) // set stdout to binary to avoid crlf in --api-info output _setmode(STDOUT_FILENO, _O_BINARY); #endif - FileDescriptor fp; - const int fof_ret = file_open_fd(&fp, STDOUT_FILENO, - kFileWriteOnly); - if (fof_ret != 0) { - semsg(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret)); - } String data = api_metadata_raw(); - const ptrdiff_t written_bytes = file_write(&fp, data.data, data.size); + const ptrdiff_t written_bytes = os_write(STDOUT_FILENO, data.data, data.size, false); if (written_bytes < 0) { - msgpack_file_write_error((int)written_bytes); + semsg(_("E5420: Failed to write to file: %s"), os_strerror((int)written_bytes)); } - const int ff_ret = file_flush(&fp); - if (ff_ret < 0) { - msgpack_file_write_error(ff_ret); - } os_exit(0); } else if (STRICMP(argv[0] + argv_idx, "headless") == 0) { headless_mode = true; diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index da6fb13768..fbb2be5104 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -365,14 +365,3 @@ ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) return (ptrdiff_t)read_bytes; } - -/// Print error which occurs when failing to write msgpack data -/// -/// @param[in] error Error code of the error to print. -/// -/// @return -1 (error return for msgpack_packer callbacks). -int msgpack_file_write_error(const int error) -{ - semsg(_("E5420: Failed to write to file: %s"), os_strerror(error)); - return -1; -} -- cgit From b386334cdbbc3e9d79773243fdbd53091488e14d Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 26 May 2024 11:36:18 +0200 Subject: refactor(shada): remove ShaDaReadDef secondary wrapper `FileDescriptor` is already a wrapper around an fd and a buffer. By allowing to just use the buffer without an fd, it can already handle in-memory reads. --- src/nvim/os/fileio.c | 20 +++ src/nvim/os/fileio_defs.h | 2 + src/nvim/rbuffer.c | 19 ++- src/nvim/shada.c | 310 +++++++++++----------------------------------- 4 files changed, 113 insertions(+), 238 deletions(-) (limited to 'src') diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index da6fb13768..4575c394b8 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -126,6 +126,7 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags) ret_fp->rv->data = ret_fp; ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; } + ret_fp->bytes_read = 0; return 0; } @@ -140,6 +141,18 @@ int file_open_stdin(FileDescriptor *fp) return error; } +/// opens buffer for reading +void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len) +{ + ret_fp->wr = false; + ret_fp->non_blocking = false; + ret_fp->fd = -1; + ret_fp->eof = true; + ret_fp->rv = rbuffer_new_wrap_buf(data, len); + ret_fp->_error = 0; + ret_fp->bytes_read = 0; +} + /// Close file and free its buffer /// /// @param[in,out] fp File to close. @@ -149,6 +162,11 @@ int file_open_stdin(FileDescriptor *fp) int file_close(FileDescriptor *const fp, const bool do_fsync) FUNC_ATTR_NONNULL_ALL { + if (fp->fd < 0) { + rbuffer_free(fp->rv); + return 0; + } + const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp)); const int close_error = os_close(fp->fd); rbuffer_free(fp->rv); @@ -294,6 +312,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t fp->non_blocking); if (r_ret >= 0) { read_remaining -= (size_t)r_ret; + fp->bytes_read += (size - read_remaining); return (ptrdiff_t)(size - read_remaining); } else if (r_ret < 0) { return r_ret; @@ -314,6 +333,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t called_read = true; } } + fp->bytes_read += (size - read_remaining); return (ptrdiff_t)(size - read_remaining); } diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h index 3dc8c7b22a..10277d2a7a 100644 --- a/src/nvim/os/fileio_defs.h +++ b/src/nvim/os/fileio_defs.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "nvim/func_attr.h" #include "nvim/rbuffer_defs.h" @@ -13,6 +14,7 @@ typedef struct { bool wr; ///< True if file is in write mode. bool eof; ///< True if end of file was encountered. bool non_blocking; ///< True if EAGAIN should not restart syscalls. + uint64_t bytes_read; ///< total bytes read so far } FileDescriptor; static inline bool file_eof(const FileDescriptor *fp) diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c index 493c079d4c..cf2e10f90d 100644 --- a/src/nvim/rbuffer.c +++ b/src/nvim/rbuffer.c @@ -29,6 +29,23 @@ RBuffer *rbuffer_new(size_t capacity) return rv; } +/// Creates a new `RBuffer` instance for reading from a buffer. +/// +/// Must not be used with any write function like rbuffer_write_ptr or rbuffer_produced! +RBuffer *rbuffer_new_wrap_buf(char *data, size_t len) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET +{ + RBuffer *rv = xcalloc(1, sizeof(RBuffer)); + rv->full_cb = rv->nonfull_cb = NULL; + rv->data = NULL; + rv->size = len; + rv->read_ptr = data; + rv->write_ptr = data + len; + rv->end_ptr = NULL; + rv->temp = NULL; + return rv; +} + void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL { xfree(buf->temp); @@ -129,7 +146,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count) assert(count <= buf->size); buf->read_ptr += count; - if (buf->read_ptr >= buf->end_ptr) { + if (buf->end_ptr && buf->read_ptr >= buf->end_ptr) { buf->read_ptr -= rbuffer_capacity(buf); } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 6f2eefeb92..597c7551fd 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -356,35 +356,6 @@ typedef struct { PMap(cstr_t) file_marks; ///< All file marks. } WriteMergerState; -typedef struct sd_read_def ShaDaReadDef; - -/// Function used to close files defined by ShaDaReadDef -typedef void (*ShaDaReadCloser)(ShaDaReadDef *const sd_reader) - REAL_FATTR_NONNULL_ALL; - -/// Function used to read ShaDa files -typedef ptrdiff_t (*ShaDaFileReader)(ShaDaReadDef *const sd_reader, - void *const dest, - const size_t size) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - -/// Function used to skip in ShaDa files -typedef int (*ShaDaFileSkipper)(ShaDaReadDef *const sd_reader, - const size_t offset) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - -/// Structure containing necessary pointers for reading ShaDa files -struct sd_read_def { - ShaDaFileReader read; ///< Reader function. - ShaDaReadCloser close; ///< Close function. - ShaDaFileSkipper skip; ///< Function used to skip some bytes. - void *cookie; ///< Data describing object read from. - bool eof; ///< True if reader reached end of file. - const char *error; ///< Error message in case of error. - uintmax_t fpos; ///< Current position (amount of bytes read since - ///< reader structure initialization). May overflow. -}; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "shada.c.generated.h" #endif @@ -587,70 +558,6 @@ static inline void hmll_dealloc(HMLList *const hmll) xfree(hmll->entries); } -/// Wrapper for reading from file descriptors -/// -/// @return -1 or number of bytes read. -static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest, const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size); - sd_reader->eof = file_eof(sd_reader->cookie); - if (ret < 0) { - sd_reader->error = os_strerror((int)ret); - return -1; - } - sd_reader->fpos += (size_t)ret; - return ret; -} - -/// Read one character -static int read_char(ShaDaReadDef *const sd_reader) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - uint8_t ret; - ptrdiff_t read_bytes = sd_reader->read(sd_reader, &ret, 1); - if (read_bytes != 1) { - return EOF; - } - return (int)ret; -} - -/// Wrapper for closing file descriptors opened for reading -static void close_sd_reader(ShaDaReadDef *const sd_reader) - FUNC_ATTR_NONNULL_ALL -{ - close_file(sd_reader->cookie); - xfree(sd_reader->cookie); -} - -/// Wrapper for read that reads to IObuff and ignores bytes read -/// -/// Used for skipping. -/// -/// @param[in,out] sd_reader File read. -/// @param[in] offset Amount of bytes to skip. -/// -/// @return FAIL in case of failure, OK in case of success. May set -/// sd_reader->eof or sd_reader->error. -static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset); - if (skip_bytes < 0) { - sd_reader->error = os_strerror((int)skip_bytes); - return FAIL; - } else if (skip_bytes != (ptrdiff_t)offset) { - assert(skip_bytes < (ptrdiff_t)offset); - sd_reader->eof = file_eof(sd_reader->cookie); - if (!sd_reader->eof) { - sd_reader->error = _("too few bytes read"); - } - return FAIL; - } - sd_reader->fpos += (size_t)skip_bytes; - return OK; -} - /// Wrapper for read that can be used when lseek cannot be used /// /// E.g. when trying to read from a pipe. @@ -660,55 +567,30 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offse /// /// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or /// kSDReadStatusSuccess. -static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, const size_t offset) +static ShaDaReadResult sd_reader_skip(FileDescriptor *const sd_reader, const size_t offset) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - if (sd_reader->skip(sd_reader, offset) != OK) { - if (sd_reader->error != NULL) { - semsg(_(SERR "System error while skipping in ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { + const ptrdiff_t skip_bytes = file_skip(sd_reader, offset); + if (skip_bytes < 0) { + semsg(_(SERR "System error while skipping in ShaDa file: %s"), + os_strerror((int)skip_bytes)); + return kSDReadStatusReadError; + } else if (skip_bytes != (ptrdiff_t)offset) { + assert(skip_bytes < (ptrdiff_t)offset); + if (file_eof(sd_reader)) { semsg(_(RCERR "Error while reading ShaDa file: " "last entry specified that it occupies %" PRIu64 " bytes, " "but file ended earlier"), (uint64_t)offset); - return kSDReadStatusNotShaDa; + } else { + semsg(_(SERR "System error while skipping in ShaDa file: %s"), + _("too few bytes read")); } - abort(); + return kSDReadStatusNotShaDa; } return kSDReadStatusSuccess; } -/// Open ShaDa file for reading -/// -/// @param[in] fname File name to open. -/// @param[out] sd_reader Location where reader structure will be saved. -/// -/// @return libuv error in case of error, 0 otherwise. -static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL -{ - *sd_reader = (ShaDaReadDef) { - .read = &read_file, - .close = &close_sd_reader, - .skip = &sd_reader_skip_read, - .error = NULL, - .eof = false, - .fpos = 0, - .cookie = xmalloc(sizeof(FileDescriptor)), - }; - int error = file_open(sd_reader->cookie, fname, kFileReadOnly, 0); - if (error) { - XFREE_CLEAR(sd_reader->cookie); - return error; - } - - assert(strcmp(p_enc, "utf-8") == 0); - - return 0; -} - /// Wrapper for closing file descriptors static void close_file(FileDescriptor *cookie) { @@ -757,8 +639,8 @@ static int shada_read_file(const char *const file, const int flags) char *const fname = shada_filename(file); - ShaDaReadDef sd_reader; - const int of_ret = open_shada_file_for_reading(fname, &sd_reader); + FileDescriptor sd_reader; + int of_ret = file_open(&sd_reader, fname, kFileReadOnly, 0); if (p_verbose > 1) { verbose_enter(); @@ -782,7 +664,7 @@ static int shada_read_file(const char *const file, const int flags) xfree(fname); shada_read(&sd_reader, flags); - sd_reader.close(&sd_reader); + close_file(&sd_reader); return OK; } @@ -1094,7 +976,7 @@ static inline bool marks_equal(const pos_T a, const pos_T b) /// /// @param[in] sd_reader Structure containing file reader definition. /// @param[in] flags What to read, see ShaDaReadFileFlags enum. -static void shada_read(ShaDaReadDef *const sd_reader, const int flags) +static void shada_read(FileDescriptor *const sd_reader, const int flags) FUNC_ATTR_NONNULL_ALL { list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES); @@ -1849,13 +1731,13 @@ static int compare_file_marks(const void *a, const void *b) /// /// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or /// kSDReadStatusSuccess. -static inline ShaDaReadResult shada_parse_msgpack(ShaDaReadDef *const sd_reader, +static inline ShaDaReadResult shada_parse_msgpack(FileDescriptor *const sd_reader, const size_t length, msgpack_unpacked *ret_unpacked, char **const ret_buf) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { - const uintmax_t initial_fpos = sd_reader->fpos; + const uintmax_t initial_fpos = sd_reader->bytes_read; char *const buf = xmalloc(length); const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length); @@ -2021,7 +1903,7 @@ static const char *shada_format_pfreed_entry(const PossiblyFreedShadaEntry pfs_e /// @param[in,out] ret_wms Location where results are saved. /// @param[out] packer MessagePack packer for entries which are not /// merged. -static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_reader, +static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_reader, const unsigned srni_flags, const size_t max_kbyte, WriteMergerState *const wms, @@ -2483,7 +2365,8 @@ static int hist_type2char(const int type) /// @param[in] sd_reader Structure containing file reader definition. If it is /// not NULL then contents of this file will be merged /// with current Neovim runtime. -static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDef *const sd_reader) +static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, + FileDescriptor *const sd_reader) FUNC_ATTR_NONNULL_ARG(1) { ShaDaWriteResult ret = kSDWriteSuccessful; @@ -2958,12 +2841,13 @@ int shada_write_file(const char *const file, bool nomerge) char *const fname = shada_filename(file); char *tempname = NULL; FileDescriptor sd_writer; - ShaDaReadDef sd_reader = { .close = NULL }; + FileDescriptor sd_reader; bool did_open_writer = false; + bool did_open_reader = false; if (!nomerge) { int error; - if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) { + if ((error = file_open(&sd_reader, fname, kFileReadOnly, 0)) != 0) { if (error != UV_ENOENT) { semsg(_(SERR "System error while opening ShaDa file %s for reading " "to merge before writing it: %s"), @@ -2973,6 +2857,8 @@ int shada_write_file(const char *const file, bool nomerge) } nomerge = true; goto shada_write_file_nomerge; + } else { + did_open_reader = true; } tempname = modname(fname, ".tmp.a", false); if (tempname == NULL) { @@ -3001,8 +2887,9 @@ shada_write_file_open: {} fname); xfree(fname); xfree(tempname); - assert(sd_reader.close != NULL); - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); + } return FAIL; } (*wp)++; @@ -3047,8 +2934,8 @@ shada_write_file_nomerge: {} if (!did_open_writer) { xfree(fname); xfree(tempname); - if (sd_reader.cookie != NULL) { - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); } return FAIL; } @@ -3062,7 +2949,9 @@ shada_write_file_nomerge: {} const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge ? NULL : &sd_reader)); assert(sw_ret != kSDWriteIgnError); if (!nomerge) { - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); + } bool did_remove = false; if (sw_ret == kSDWriteSuccessful) { FileInfo old_info; @@ -3235,18 +3124,18 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits) /// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if /// there were not enough bytes to read or kSDReadStatusReadError if /// there was some error while reading. -static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buffer, +static ShaDaReadResult fread_len(FileDescriptor *const sd_reader, char *const buffer, const size_t length) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length); + const ptrdiff_t read_bytes = file_read(sd_reader, buffer, length); + if (read_bytes < 0) { + semsg(_(SERR "System error while reading ShaDa file: %s"), + os_strerror((int)read_bytes)); + return kSDReadStatusReadError; + } if (read_bytes != (ptrdiff_t)length) { - if (sd_reader->error != NULL) { - semsg(_(SERR "System error while reading ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } semsg(_(RCERR "Error while reading ShaDa file: " "last entry specified that it occupies %" PRIu64 " bytes, " "but file ended earlier"), @@ -3272,26 +3161,32 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buff /// @return kSDReadStatusSuccess if reading was successful, /// kSDReadStatusNotShaDa if there were not enough bytes to read or /// kSDReadStatusReadError if reading failed for whatever reason. -static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const int first_char, +/// kSDReadStatusFinished if eof and that was allowed +static ShaDaReadResult msgpack_read_uint64(FileDescriptor *const sd_reader, bool allow_eof, uint64_t *const result) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - const uintmax_t fpos = sd_reader->fpos - 1; - - if (first_char == EOF) { - if (sd_reader->error) { - semsg(_(SERR "System error while reading integer from ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { - semsg(_(RCERR "Error while reading ShaDa file: " - "expected positive integer at position %" PRIu64 - ", but got nothing"), - (uint64_t)fpos); - return kSDReadStatusNotShaDa; + const uintmax_t fpos = sd_reader->bytes_read; + + uint8_t ret; + ptrdiff_t read_bytes = file_read(sd_reader, (char *)&ret, 1); + + if (read_bytes < 0) { + semsg(_(SERR "System error while reading integer from ShaDa file: %s"), + os_strerror((int)read_bytes)); + return kSDReadStatusReadError; + } else if (read_bytes == 0) { + if (allow_eof && file_eof(sd_reader)) { + return kSDReadStatusFinished; } + semsg(_(RCERR "Error while reading ShaDa file: " + "expected positive integer at position %" PRIu64 + ", but got nothing"), + (uint64_t)fpos); + return kSDReadStatusNotShaDa; } + int first_char = (int)ret; if (~first_char & 0x80) { // Positive fixnum *result = (uint64_t)((uint8_t)first_char); @@ -3465,8 +3360,9 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const /// greater then given. /// /// @return Any value from ShaDaReadResult enum. -static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader, ShadaEntry *const entry, - const unsigned flags, const size_t max_kbyte) +static ShaDaReadResult shada_read_next_item(FileDescriptor *const sd_reader, + ShadaEntry *const entry, const unsigned flags, + const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { ShaDaReadResult ret = kSDReadStatusMalformed; @@ -3476,7 +3372,7 @@ shada_read_next_item_start: // somebody calls goto shada_read_next_item_error before anything is set in // the switch. CLEAR_POINTER(entry); - if (sd_reader->eof) { + if (file_eof(sd_reader)) { return kSDReadStatusFinished; } @@ -3486,19 +3382,15 @@ shada_read_next_item_start: uint64_t timestamp_u64; uint64_t length_u64; - const uint64_t initial_fpos = (uint64_t)sd_reader->fpos; - const int first_char = read_char(sd_reader); - if (first_char == EOF && sd_reader->eof) { - return kSDReadStatusFinished; - } + const uint64_t initial_fpos = sd_reader->bytes_read; ShaDaReadResult mru_ret; - if (((mru_ret = msgpack_read_uint64(sd_reader, first_char, &type_u64)) + if (((mru_ret = msgpack_read_uint64(sd_reader, true, &type_u64)) != kSDReadStatusSuccess) - || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader), + || ((mru_ret = msgpack_read_uint64(sd_reader, false, ×tamp_u64)) != kSDReadStatusSuccess) - || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader), + || ((mru_ret = msgpack_read_uint64(sd_reader, false, &length_u64)) != kSDReadStatusSuccess)) { return mru_ret; @@ -4158,63 +4050,6 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf) } while (var_iter != NULL); } -/// Wrapper for reading from msgpack_sbuffer. -/// -/// @return number of bytes read. -static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest, const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; - const uintmax_t bytes_read = MIN(size, sbuf->size - sd_reader->fpos); - if (bytes_read < size) { - sd_reader->eof = true; - } - memcpy(dest, sbuf->data + sd_reader->fpos, (size_t)bytes_read); - sd_reader->fpos += bytes_read; - return (ptrdiff_t)bytes_read; -} - -/// Wrapper for read that ignores bytes read from msgpack_sbuffer. -/// -/// Used for skipping. -/// -/// @param[in,out] sd_reader ShaDaReadDef with msgpack_sbuffer. -/// @param[in] offset Amount of bytes to skip. -/// -/// @return FAIL in case of failure, OK in case of success. May set -/// sd_reader->eof. -static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; - assert(sbuf->size >= sd_reader->fpos); - const uintmax_t skip_bytes = MIN(offset, sbuf->size - sd_reader->fpos); - if (skip_bytes < offset) { - sd_reader->eof = true; - return FAIL; - } - sd_reader->fpos += offset; - return OK; -} - -/// Prepare ShaDaReadDef with msgpack_sbuffer for reading. -/// -/// @param[in] sbuf msgpack_sbuffer to read from. -/// @param[out] sd_reader Location where reader structure will be saved. -static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf, ShaDaReadDef *sd_reader) - FUNC_ATTR_NONNULL_ALL -{ - *sd_reader = (ShaDaReadDef) { - .read = &read_sbuf, - .close = NULL, - .skip = &sd_sbuf_reader_skip_read, - .error = NULL, - .eof = false, - .fpos = 0, - .cookie = (void *)sbuf, - }; -} - /// Read ShaDa from msgpack_sbuffer. /// /// @param[in] file msgpack_sbuffer to read from. @@ -4226,7 +4061,8 @@ void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags) if (sbuf->data == NULL) { return; } - ShaDaReadDef sd_reader; - open_shada_sbuf_for_reading(sbuf, &sd_reader); + FileDescriptor sd_reader; + file_open_buffer(&sd_reader, sbuf->data, sbuf->size); shada_read(&sd_reader, flags); + close_file(&sd_reader); } -- cgit From 064483a2b4a3056baf8eee4424bb81127e531991 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 28 May 2024 12:52:24 +0200 Subject: refactor(fileio): use a linear buffer for FileDescriptor Using a ring buffer for buffered synchronous fileio is just unnecessary complexity. - when reading, we always consume the _entire_ buffer before getting into syscalls. Thus we reset the buffer to its initial position before when we actually read. - when writing and buffer is full, we always flush the entire buffer before starting to buffer again. So we can reset the buffer to its initial state. Also no static buffers are needed for writing and skipping. Needing an extra copy for each write completely defeated the purpose of a ring buffer (if there had been one) --- src/nvim/msgpack_rpc/packer.c | 1 - src/nvim/os/fileio.c | 274 +++++++++++++++++++++--------------------- src/nvim/os/fileio_defs.h | 9 +- src/nvim/rbuffer.c | 19 +-- 4 files changed, 144 insertions(+), 159 deletions(-) (limited to 'src') diff --git a/src/nvim/msgpack_rpc/packer.c b/src/nvim/msgpack_rpc/packer.c index cac68f76f0..9c0d2910fa 100644 --- a/src/nvim/msgpack_rpc/packer.c +++ b/src/nvim/msgpack_rpc/packer.c @@ -113,7 +113,6 @@ void mpack_handle(ObjectType type, handle_T handle, PackerBuffer *packer) mpack_w(&packer->ptr, 0xc7); mpack_w(&packer->ptr, packsize); mpack_w(&packer->ptr, exttype); - // check_buffer(packer); memcpy(packer->ptr, buf, (size_t)packsize); packer->ptr += packsize; } diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index e58eb96c2e..c87b2d359f 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -120,12 +120,9 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags) assert(!ret_fp->wr || !ret_fp->non_blocking); ret_fp->fd = fd; ret_fp->eof = false; - ret_fp->rv = rbuffer_new(kRWBufferSize); - ret_fp->_error = 0; - if (ret_fp->wr) { - ret_fp->rv->data = ret_fp; - ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; - } + ret_fp->buffer = alloc_block(); + ret_fp->read_pos = ret_fp->buffer; + ret_fp->write_pos = ret_fp->buffer; ret_fp->bytes_read = 0; return 0; } @@ -148,8 +145,9 @@ void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len) ret_fp->non_blocking = false; ret_fp->fd = -1; ret_fp->eof = true; - ret_fp->rv = rbuffer_new_wrap_buf(data, len); - ret_fp->_error = 0; + ret_fp->buffer = NULL; // we don't take ownership + ret_fp->read_pos = data; + ret_fp->write_pos = data + len; ret_fp->bytes_read = 0; } @@ -163,36 +161,18 @@ int file_close(FileDescriptor *const fp, const bool do_fsync) FUNC_ATTR_NONNULL_ALL { if (fp->fd < 0) { - rbuffer_free(fp->rv); return 0; } const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp)); const int close_error = os_close(fp->fd); - rbuffer_free(fp->rv); + free_block(fp->buffer); if (close_error != 0) { return close_error; } return flush_error; } -/// Flush file modifications to disk -/// -/// @param[in,out] fp File to work with. -/// -/// @return 0 or error code. -int file_flush(FileDescriptor *const fp) - FUNC_ATTR_NONNULL_ALL -{ - if (!fp->wr) { - return 0; - } - file_rb_write_full_cb(fp->rv, fp); - const int error = fp->_error; - fp->_error = 0; - return error; -} - /// Flush file modifications to disk and run fsync() /// /// @param[in,out] fp File to work with. @@ -218,36 +198,29 @@ int file_fsync(FileDescriptor *const fp) return 0; } -/// Buffer used for writing -/// -/// Like IObuff, but allows file_\* callers not to care about spoiling it. -static char writebuf[kRWBufferSize]; - -/// Function run when RBuffer is full when writing to a file -/// -/// Actually does writing to the file, may also be invoked directly. +/// Flush file modifications to disk /// -/// @param[in,out] rv RBuffer instance used. /// @param[in,out] fp File to work with. -static void file_rb_write_full_cb(RBuffer *const rv, void *const fp_in) +/// +/// @return 0 or error code. +int file_flush(FileDescriptor *fp) FUNC_ATTR_NONNULL_ALL { - FileDescriptor *const fp = fp_in; - assert(fp->wr); - assert(rv->data == (void *)fp); - if (rbuffer_size(rv) == 0) { - return; + if (!fp->wr) { + return 0; + } + + ptrdiff_t to_write = fp->write_pos - fp->read_pos; + if (to_write == 0) { + return 0; } - const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); - const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes, + const ptrdiff_t wres = os_write(fp->fd, fp->read_pos, (size_t)to_write, fp->non_blocking); - if (wres != (ptrdiff_t)read_bytes) { - if (wres >= 0) { - fp->_error = UV_EIO; - } else { - fp->_error = (int)wres; - } + fp->read_pos = fp->write_pos = fp->buffer; + if (wres != to_write) { + return (wres >= 0) ? UV_EIO : (int)wres; } + return 0; } /// Read from file @@ -262,77 +235,78 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { assert(!fp->wr); - char *buf = ret_buf; - size_t read_remaining = size; - RBuffer *const rv = fp->rv; + size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size); + memcpy(ret_buf, fp->read_pos, from_buffer); + + char *buf = ret_buf + from_buffer; + size_t read_remaining = size - from_buffer; + if (!read_remaining) { + fp->bytes_read += from_buffer; + fp->read_pos += from_buffer; + return (ptrdiff_t)from_buffer; + } + + // at this point, we have consumed all of an existing buffer. restart from the beginning + fp->read_pos = fp->write_pos = fp->buffer; + +#ifdef HAVE_READV bool called_read = false; while (read_remaining) { - const size_t rv_size = rbuffer_size(rv); - if (rv_size > 0) { - const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining)); - buf += rsize; - read_remaining -= rsize; - } - if (fp->eof - // Allow only at most one os_read[v] call. - || (called_read && fp->non_blocking)) { + // Allow only at most one os_read[v] call. + if (fp->eof || (called_read && fp->non_blocking)) { break; } - if (read_remaining) { - assert(rbuffer_size(rv) == 0); - rbuffer_reset(rv); -#ifdef HAVE_READV - // If there is readv() syscall, then take an opportunity to populate - // both target buffer and RBuffer at once, … - size_t write_count; - struct iovec iov[] = { - { .iov_base = buf, .iov_len = read_remaining }, - { .iov_base = rbuffer_write_ptr(rv, &write_count), - .iov_len = kRWBufferSize }, - }; - assert(write_count == kRWBufferSize); - const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, - ARRAY_SIZE(iov), fp->non_blocking); - if (r_ret > 0) { - if (r_ret > (ptrdiff_t)read_remaining) { - rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); - read_remaining = 0; - } else { - buf += (size_t)r_ret; - read_remaining -= (size_t)r_ret; - } - } else if (r_ret < 0) { - return r_ret; - } -#else - if (read_remaining >= kRWBufferSize) { - // …otherwise leave RBuffer empty and populate only target buffer, - // because filtering information through rbuffer will be more syscalls. - const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, - fp->non_blocking); - if (r_ret >= 0) { - read_remaining -= (size_t)r_ret; - fp->bytes_read += (size - read_remaining); - return (ptrdiff_t)(size - read_remaining); - } else if (r_ret < 0) { - return r_ret; - } + // If there is readv() syscall, then take an opportunity to populate + // both target buffer and RBuffer at once, … + struct iovec iov[] = { + { .iov_base = buf, .iov_len = read_remaining }, + { .iov_base = fp->write_pos, + .iov_len = ARENA_BLOCK_SIZE }, + }; + const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, + ARRAY_SIZE(iov), fp->non_blocking); + if (r_ret > 0) { + if (r_ret > (ptrdiff_t)read_remaining) { + fp->write_pos += (size_t)(r_ret - (ptrdiff_t)read_remaining); + read_remaining = 0; } else { - size_t write_count; - const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, - rbuffer_write_ptr(rv, &write_count), - kRWBufferSize, fp->non_blocking); - assert(write_count == kRWBufferSize); - if (r_ret > 0) { - rbuffer_produced(rv, (size_t)r_ret); - } else if (r_ret < 0) { - return r_ret; - } + buf += r_ret; + read_remaining -= (size_t)r_ret; } -#endif - called_read = true; + } else if (r_ret < 0) { + return r_ret; + } + called_read = true; + } +#else + if (fp->eof) { + // already eof, cannot read more + } else if (read_remaining >= ARENA_BLOCK_SIZE) { + // …otherwise leave fp->buffer empty and populate only target buffer, + // because filtering information through rbuffer will be more syscalls. + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, + fp->non_blocking); + if (r_ret >= 0) { + read_remaining -= (size_t)r_ret; + } else if (r_ret < 0) { + return r_ret; + } + } else { + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, + fp->write_pos, + ARENA_BLOCK_SIZE, fp->non_blocking); + if (r_ret < 0) { + return r_ret; + } else { + fp->write_pos += r_ret; + size_t to_copy = MIN((size_t)r_ret, read_remaining); + memcpy(ret_buf, fp->read_pos, to_copy); + fp->read_pos += to_copy; + read_remaining -= to_copy; } } +#endif + fp->bytes_read += (size - read_remaining); return (ptrdiff_t)(size - read_remaining); } @@ -348,40 +322,68 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { assert(fp->wr); - const size_t written = rbuffer_write(fp->rv, buf, size); - if (fp->_error != 0) { - const int error = fp->_error; - fp->_error = 0; - return error; - } else if (written != size) { - return UV_EIO; + ptrdiff_t space = (fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos; + // includes the trivial case of size==0 + if (size < (size_t)space) { + memcpy(fp->write_pos, buf, size); + fp->write_pos += size; + return (ptrdiff_t)size; + } + + // TODO(bfredl): just as for reading, use iovec to combine fp->buffer with buf + int status = file_flush(fp); + if (status < 0) { + return status; + } + + if (size < ARENA_BLOCK_SIZE) { + memcpy(fp->write_pos, buf, size); + fp->write_pos += size; + return (ptrdiff_t)size; } - return (ptrdiff_t)written; -} -/// Buffer used for skipping. Its contents is undefined and should never be -/// used. -static char skipbuf[kRWBufferSize]; + const ptrdiff_t wres = os_write(fp->fd, buf, size, + fp->non_blocking); + return (wres != (ptrdiff_t)size && wres >= 0) ? UV_EIO : wres; +} /// Skip some bytes /// /// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply -/// reads to a buffer and discards the result. +/// reads to the buffer and discards the result. ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) FUNC_ATTR_NONNULL_ALL { assert(!fp->wr); - size_t read_bytes = 0; - do { - const ptrdiff_t new_read_bytes = - file_read(fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf))); - if (new_read_bytes < 0) { - return new_read_bytes; - } else if (new_read_bytes == 0) { + size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size); + size_t skip_remaining = size - from_buffer; + if (skip_remaining == 0) { + fp->read_pos += from_buffer; + fp->bytes_read += from_buffer; + return (ptrdiff_t)from_buffer; + } + + fp->read_pos = fp->write_pos = fp->buffer; + bool called_read = false; + while (skip_remaining > 0) { + // Allow only at most one os_read[v] call. + if (fp->eof || (called_read && fp->non_blocking)) { break; } - read_bytes += (size_t)new_read_bytes; - } while (read_bytes < size && !file_eof(fp)); + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, fp->buffer, ARENA_BLOCK_SIZE, + fp->non_blocking); + if (r_ret < 0) { + return r_ret; + } else if ((size_t)r_ret > skip_remaining) { + fp->read_pos = fp->buffer + skip_remaining; + fp->write_pos = fp->buffer + r_ret; + fp->bytes_read += size; + return (ptrdiff_t)size; + } + skip_remaining -= (size_t)r_ret; + called_read = true; + } - return (ptrdiff_t)read_bytes; + fp->bytes_read += size - skip_remaining; + return (ptrdiff_t)(size - skip_remaining); } diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h index 10277d2a7a..63b6f51c17 100644 --- a/src/nvim/os/fileio_defs.h +++ b/src/nvim/os/fileio_defs.h @@ -8,9 +8,10 @@ /// Structure used to read from/write to file typedef struct { - int fd; ///< File descriptor. - int _error; ///< Error code for use with RBuffer callbacks or zero. - RBuffer *rv; ///< Read or write buffer. + int fd; ///< File descriptor. Can be -1 if no backing file (file_open_buffer) + char *buffer; ///< Read or write buffer. always ARENA_BLOCK_SIZE if allocated + char *read_pos; ///< read position in buffer + char *write_pos; ///< write position in buffer bool wr; ///< True if file is in write mode. bool eof; ///< True if end of file was encountered. bool non_blocking; ///< True if EAGAIN should not restart syscalls. @@ -28,7 +29,7 @@ static inline bool file_eof(const FileDescriptor *fp) /// performed. static inline bool file_eof(const FileDescriptor *const fp) { - return fp->eof && rbuffer_size(fp->rv) == 0; + return fp->eof && fp->read_pos == fp->write_pos; } static inline int file_fd(const FileDescriptor *fp) diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c index cf2e10f90d..493c079d4c 100644 --- a/src/nvim/rbuffer.c +++ b/src/nvim/rbuffer.c @@ -29,23 +29,6 @@ RBuffer *rbuffer_new(size_t capacity) return rv; } -/// Creates a new `RBuffer` instance for reading from a buffer. -/// -/// Must not be used with any write function like rbuffer_write_ptr or rbuffer_produced! -RBuffer *rbuffer_new_wrap_buf(char *data, size_t len) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET -{ - RBuffer *rv = xcalloc(1, sizeof(RBuffer)); - rv->full_cb = rv->nonfull_cb = NULL; - rv->data = NULL; - rv->size = len; - rv->read_ptr = data; - rv->write_ptr = data + len; - rv->end_ptr = NULL; - rv->temp = NULL; - return rv; -} - void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL { xfree(buf->temp); @@ -146,7 +129,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count) assert(count <= buf->size); buf->read_ptr += count; - if (buf->end_ptr && buf->read_ptr >= buf->end_ptr) { + if (buf->read_ptr >= buf->end_ptr) { buf->read_ptr -= rbuffer_capacity(buf); } -- cgit From df2c3b204b9622687d0cd7dd59cbd3f89d9383ce Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 30 May 2024 13:57:41 +0800 Subject: vim-patch:9.1.0449: MS-Windows: Compiler warnings Problem: MS-Windows: Compiler warnings Solution: Resolve size_t to int warnings closes: vim/vim#14874 A couple of warnings in ex_docmd.c have been resolved by modifying their function argument types, followed by some changes in various function call sites. This also allowed removal of some casts to cope with size_t/int conversion. https://github.com/vim/vim/commit/51024bbc1a9e298b1fb8f2e465fccb5db409551e Co-authored-by: Mike Williams --- src/nvim/strings.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 16ae35272b..485551da6e 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -266,11 +266,11 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli *d++ = *p++; continue; } - if (do_special && find_cmdline_var(p, &l) >= 0) { + if (do_special && find_cmdline_var(p, &l) >= 0 && l > 0) { *d++ = '\\'; // insert backslash - while (--l != SIZE_MAX) { // copy the var + do { // copy the var *d++ = *p++; - } + } while (--l > 0); continue; } if (*p == '\\' && fish_like) { -- cgit From 2de12e9bd7fe72eb4656a3c0f689caf6ce971451 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 31 May 2024 05:50:57 +0800 Subject: vim-patch:9.1.0451: No test for escaping '<' with shellescape() Problem: No test for escaping '<' with shellescape() Solution: Add a test. Use memcpy() in code to make it easier to understand. Fix a typo (zeertzjq). closes: vim/vim#14876 https://github.com/vim/vim/commit/88c8c547d5fc380e5685c2b01ec564ccdf9b259a --- src/nvim/search.h | 2 +- src/nvim/strings.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/search.h b/src/nvim/search.h index 783756b781..92ee5d6854 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -84,7 +84,7 @@ typedef struct { /// Structure containing last search pattern and its attributes. typedef struct { char *pat; ///< The pattern (in allocated memory) or NULL. - size_t patlen; ///< The length of the patten (0 is pat is NULL). + size_t patlen; ///< The length of the pattern (0 if pat is NULL). bool magic; ///< Magicness of the pattern. bool no_scs; ///< No smartcase for this pattern. Timestamp timestamp; ///< Time of the last change. diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 485551da6e..8fef4ba7fd 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -266,11 +266,11 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli *d++ = *p++; continue; } - if (do_special && find_cmdline_var(p, &l) >= 0 && l > 0) { + if (do_special && find_cmdline_var(p, &l) >= 0) { *d++ = '\\'; // insert backslash - do { // copy the var - *d++ = *p++; - } while (--l > 0); + memcpy(d, p, l); // copy the var + d += l; + p += l; continue; } if (*p == '\\' && fish_like) { -- cgit From c13c50b752dca322a5ec77dea6188c9e3694549b Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 30 May 2024 12:59:02 +0200 Subject: refactor(io): separate types for read and write streams This is a structural refactor with no logical changes, yet. Done in preparation for simplifying rstream/rbuffer which will require more state inline in RStream. The initial idea was to have RStream and WStream as sub-types symetrically but that doesn't work, as sockets are both reading and writing. Also there is very little write-specific state to start with, so the benefit of a separate WStream struct is a lot smaller. Just document what fields in `Stream` are write specific. --- src/nvim/channel.c | 32 ++++++++++---------- src/nvim/channel.h | 8 ++--- src/nvim/channel_defs.h | 2 +- src/nvim/event/defs.h | 31 +++++++++++++------- src/nvim/event/libuv_process.c | 8 ++--- src/nvim/event/process.c | 46 +++++++++++++++-------------- src/nvim/event/process.h | 4 +-- src/nvim/event/rstream.c | 66 +++++++++++++++++++++++------------------- src/nvim/event/socket.c | 16 +++++----- src/nvim/event/stream.c | 26 +++++++++-------- src/nvim/event/wstream.c | 7 ++++- src/nvim/msgpack_rpc/channel.c | 4 +-- src/nvim/os/input.c | 12 ++++---- src/nvim/os/pty_process_unix.c | 6 ++-- src/nvim/os/pty_process_win.c | 8 ++--- src/nvim/os/shell.c | 6 ++-- src/nvim/tui/input.c | 4 +-- src/nvim/tui/input.h | 2 +- 18 files changed, 157 insertions(+), 131 deletions(-) (limited to 'src') diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 41635747f8..e5492caf45 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -126,19 +126,19 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) *error = e_invstream; return false; } - stream_may_close(&chan->stream.socket); + rstream_may_close(&chan->stream.socket); break; case kChannelStreamProc: proc = &chan->stream.proc; if (part == kChannelPartStdin || close_main) { - stream_may_close(&proc->in); + wstream_may_close(&proc->in); } if (part == kChannelPartStdout || close_main) { - stream_may_close(&proc->out); + rstream_may_close(&proc->out); } if (part == kChannelPartStderr || part == kChannelPartAll) { - stream_may_close(&proc->err); + rstream_may_close(&proc->err); } if (proc->type == kProcessTypePty && part == kChannelPartAll) { pty_process_close_master(&chan->stream.pty); @@ -148,10 +148,10 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) case kChannelStreamStdio: if (part == kChannelPartStdin || close_main) { - stream_may_close(&chan->stream.stdio.in); + rstream_may_close(&chan->stream.stdio.in); } if (part == kChannelPartStdout || close_main) { - stream_may_close(&chan->stream.stdio.out); + wstream_may_close(&chan->stream.stdio.out); } if (part == kChannelPartStderr) { *error = e_invstream; @@ -480,9 +480,9 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader return 0; } - channel->stream.socket.internal_close_cb = close_cb; - channel->stream.socket.internal_data = channel; - wstream_init(&channel->stream.socket, 0); + channel->stream.socket.s.internal_close_cb = close_cb; + channel->stream.socket.s.internal_data = channel; + wstream_init(&channel->stream.socket.s, 0); rstream_init(&channel->stream.socket, 0); if (rpc) { @@ -505,9 +505,9 @@ void channel_from_connection(SocketWatcher *watcher) { Channel *channel = channel_alloc(kChannelStreamSocket); socket_watcher_accept(watcher, &channel->stream.socket); - channel->stream.socket.internal_close_cb = close_cb; - channel->stream.socket.internal_data = channel; - wstream_init(&channel->stream.socket, 0); + channel->stream.socket.s.internal_close_cb = close_cb; + channel->stream.socket.s.internal_data = channel; + wstream_init(&channel->stream.socket.s, 0); rstream_init(&channel->stream.socket, 0); rpc_start(channel); channel_create_event(channel, watcher->addr); @@ -647,19 +647,19 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) return l; } -void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +void on_channel_data(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; on_channel_output(stream, chan, buf, eof, &chan->on_data); } -void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +void on_job_stderr(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; on_channel_output(stream, chan, buf, eof, &chan->on_stderr); } -static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof, +static void on_channel_output(RStream *stream, Channel *chan, RBuffer *buf, bool eof, CallbackReader *reader) { size_t count; @@ -864,7 +864,7 @@ static void term_resize(uint16_t width, uint16_t height, void *data) static inline void term_delayed_free(void **argv) { Channel *chan = argv[0]; - if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.pending_reqs) { + if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.s.pending_reqs) { multiqueue_put(chan->events, term_delayed_free, chan); return; } diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 35d369e513..72480db0d5 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -30,7 +30,7 @@ struct Channel { Process proc; LibuvProcess uv; PtyProcess pty; - Stream socket; + RStream socket; StdioPair stdio; StderrState err; InternalState internal; @@ -73,7 +73,7 @@ static inline Stream *channel_instream(Channel *chan) return &chan->stream.proc.in; case kChannelStreamSocket: - return &chan->stream.socket; + return &chan->stream.socket.s; case kChannelStreamStdio: return &chan->stream.stdio.out; @@ -85,10 +85,10 @@ static inline Stream *channel_instream(Channel *chan) abort(); } -static inline Stream *channel_outstream(Channel *chan) +static inline RStream *channel_outstream(Channel *chan) REAL_FATTR_NONNULL_ALL; -static inline Stream *channel_outstream(Channel *chan) +static inline RStream *channel_outstream(Channel *chan) { switch (chan->streamtype) { case kChannelStreamProc: diff --git a/src/nvim/channel_defs.h b/src/nvim/channel_defs.h index d4f1895420..2df6edea7a 100644 --- a/src/nvim/channel_defs.h +++ b/src/nvim/channel_defs.h @@ -30,7 +30,7 @@ typedef enum { } ChannelStdinMode; typedef struct { - Stream in; + RStream in; Stream out; } StdioPair; diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h index 9b7d8708be..8563006159 100644 --- a/src/nvim/event/defs.h +++ b/src/nvim/event/defs.h @@ -55,14 +55,15 @@ struct wbuffer { }; typedef struct stream Stream; -/// Type of function called when the Stream buffer is filled with data +typedef struct rstream RStream; +/// Type of function called when the RStream buffer is filled with data /// /// @param stream The Stream instance /// @param buf The associated RBuffer instance /// @param count Number of bytes that was read. /// @param data User-defined data /// @param eof If the stream reached EOF. -typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof); +typedef void (*stream_read_cb)(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof); /// Type of function called when the Stream has information about a write /// request. @@ -71,11 +72,11 @@ typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void /// @param data User-defined data /// @param status 0 on success, anything else indicates failure typedef void (*stream_write_cb)(Stream *stream, void *data, int status); + typedef void (*stream_close_cb)(Stream *stream, void *data); struct stream { bool closed; - bool did_eof; union { uv_pipe_t pipe; uv_tcp_t tcp; @@ -85,20 +86,27 @@ struct stream { #endif } uv; uv_stream_t *uvstream; - uv_buf_t uvbuf; - RBuffer *buffer; uv_file fd; - stream_read_cb read_cb; - stream_write_cb write_cb; void *cb_data; stream_close_cb close_cb, internal_close_cb; void *close_cb_data, *internal_data; - size_t fpos; + size_t pending_reqs; + MultiQueue *events; + + // only used for writing: + stream_write_cb write_cb; size_t curmem; size_t maxmem; - size_t pending_reqs; +}; + +struct rstream { + Stream s; + bool did_eof; + RBuffer *buffer; + uv_buf_t uvbuf; + stream_read_cb read_cb; size_t num_bytes; - MultiQueue *events; + size_t fpos; }; #define ADDRESS_MAX_SIZE 256 @@ -147,7 +155,8 @@ struct process { char **argv; const char *exepath; dict_T *env; - Stream in, out, err; + Stream in; + RStream out, err; /// Exit handler. If set, user must call process_free(). process_exit_cb cb; internal_process_cb internal_exit_cb, internal_close_cb; diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index f77d686c10..0dead1f9b4 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -70,19 +70,19 @@ int libuv_process_spawn(LibuvProcess *uvproc) uvproc->uvstdio[0].data.stream = (uv_stream_t *)(&proc->in.uv.pipe); } - if (!proc->out.closed) { + if (!proc->out.s.closed) { uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; #ifdef MSWIN // pipe must be readable for IOCP to work on Windows. uvproc->uvstdio[1].flags |= proc->overlapped ? (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0; #endif - uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.uv.pipe); + uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.s.uv.pipe); } - if (!proc->err.closed) { + if (!proc->err.s.closed) { uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.uv.pipe); + uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.s.uv.pipe); } else if (proc->fwd_err) { uvproc->uvstdio[2].flags = UV_INHERIT_FD; uvproc->uvstdio[2].data.fd = STDERR_FILENO; diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 7460e92766..710376cd62 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -8,7 +8,9 @@ #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" #include "nvim/event/process.h" +#include "nvim/event/rstream.h" #include "nvim/event/stream.h" +#include "nvim/event/wstream.h" #include "nvim/globals.h" #include "nvim/log.h" #include "nvim/main.h" @@ -51,15 +53,15 @@ int process_spawn(Process *proc, bool in, bool out, bool err) } if (out) { - uv_pipe_init(&proc->loop->uv, &proc->out.uv.pipe, 0); + uv_pipe_init(&proc->loop->uv, &proc->out.s.uv.pipe, 0); } else { - proc->out.closed = true; + proc->out.s.closed = true; } if (err) { - uv_pipe_init(&proc->loop->uv, &proc->err.uv.pipe, 0); + uv_pipe_init(&proc->loop->uv, &proc->err.s.uv.pipe, 0); } else { - proc->err.closed = true; + proc->err.s.closed = true; } #ifdef USE_GCOV @@ -82,10 +84,10 @@ int process_spawn(Process *proc, bool in, bool out, bool err) uv_close((uv_handle_t *)&proc->in.uv.pipe, NULL); } if (out) { - uv_close((uv_handle_t *)&proc->out.uv.pipe, NULL); + uv_close((uv_handle_t *)&proc->out.s.uv.pipe, NULL); } if (err) { - uv_close((uv_handle_t *)&proc->err.uv.pipe, NULL); + uv_close((uv_handle_t *)&proc->err.s.uv.pipe, NULL); } if (proc->type == kProcessTypeUv) { @@ -106,16 +108,16 @@ int process_spawn(Process *proc, bool in, bool out, bool err) } if (out) { - stream_init(NULL, &proc->out, -1, (uv_stream_t *)&proc->out.uv.pipe); - proc->out.internal_data = proc; - proc->out.internal_close_cb = on_process_stream_close; + stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe); + proc->out.s.internal_data = proc; + proc->out.s.internal_close_cb = on_process_stream_close; proc->refcount++; } if (err) { - stream_init(NULL, &proc->err, -1, (uv_stream_t *)&proc->err.uv.pipe); - proc->err.internal_data = proc; - proc->err.internal_close_cb = on_process_stream_close; + stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe); + proc->err.s.internal_data = proc; + proc->err.s.internal_close_cb = on_process_stream_close; proc->refcount++; } @@ -148,9 +150,9 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL { - stream_may_close(&proc->in); - stream_may_close(&proc->out); - stream_may_close(&proc->err); + wstream_may_close(&proc->in); + rstream_may_close(&proc->out); + rstream_may_close(&proc->err); } /// Synchronously wait for a process to finish @@ -337,10 +339,10 @@ static void process_close(Process *proc) /// /// @param proc Process, for which an output stream should be flushed. /// @param stream Stream to flush. -static void flush_stream(Process *proc, Stream *stream) +static void flush_stream(Process *proc, RStream *stream) FUNC_ATTR_NONNULL_ARG(1) { - if (!stream || stream->closed) { + if (!stream || stream->s.closed) { return; } @@ -350,7 +352,7 @@ static void flush_stream(Process *proc, Stream *stream) // keeps sending data, we only accept as much data as the system buffer size. // Otherwise this would block cleanup/teardown. int system_buffer_size = 0; - int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe, + int err = uv_recv_buffer_size((uv_handle_t *)&stream->s.uv.pipe, &system_buffer_size); if (err) { system_buffer_size = (int)rbuffer_capacity(stream->buffer); @@ -359,14 +361,14 @@ static void flush_stream(Process *proc, Stream *stream) size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size; // Read remaining data. - while (!stream->closed && stream->num_bytes < max_bytes) { + while (!stream->s.closed && stream->num_bytes < max_bytes) { // Remember number of bytes before polling size_t num_bytes = stream->num_bytes; // Poll for data and process the generated events. loop_poll_events(proc->loop, 0); - if (stream->events) { - multiqueue_process_events(stream->events); + if (stream->s.events) { + multiqueue_process_events(stream->s.events); } // Stream can be closed if it is empty. @@ -374,7 +376,7 @@ static void flush_stream(Process *proc, Stream *stream) if (stream->read_cb && !stream->did_eof) { // Stream callback could miss EOF handling if a child keeps the stream // open. But only send EOF if we haven't already. - stream->read_cb(stream, stream->buffer, 0, stream->cb_data, true); + stream->read_cb(stream, stream->buffer, 0, stream->s.cb_data, true); } break; } diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index 421a470244..74b52cbbb1 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -21,8 +21,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data) .argv = NULL, .exepath = NULL, .in = { .closed = false }, - .out = { .closed = false }, - .err = { .closed = false }, + .out = { .s.closed = false }, + .err = { .s.closed = false }, .cb = NULL, .closed = false, .internal_close_cb = NULL, diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index 6b4ab472e4..6c7fa20bd8 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -19,23 +19,26 @@ # include "event/rstream.c.generated.h" #endif -void rstream_init_fd(Loop *loop, Stream *stream, int fd, size_t bufsize) +void rstream_init_fd(Loop *loop, RStream *stream, int fd, size_t bufsize) FUNC_ATTR_NONNULL_ARG(1, 2) { - stream_init(loop, stream, fd, NULL); + stream_init(loop, &stream->s, fd, NULL); rstream_init(stream, bufsize); } -void rstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t bufsize) +void rstream_init_stream(RStream *stream, uv_stream_t *uvstream, size_t bufsize) FUNC_ATTR_NONNULL_ARG(1, 2) { - stream_init(NULL, stream, -1, uvstream); + stream_init(NULL, &stream->s, -1, uvstream); rstream_init(stream, bufsize); } -void rstream_init(Stream *stream, size_t bufsize) +void rstream_init(RStream *stream, size_t bufsize) FUNC_ATTR_NONNULL_ARG(1) { + stream->fpos = 0; + stream->read_cb = NULL; + stream->num_bytes = 0; stream->buffer = rbuffer_new(bufsize); stream->buffer->data = stream; stream->buffer->full_cb = on_rbuffer_full; @@ -45,28 +48,28 @@ void rstream_init(Stream *stream, size_t bufsize) /// Starts watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance -void rstream_start(Stream *stream, stream_read_cb cb, void *data) +void rstream_start(RStream *stream, stream_read_cb cb, void *data) FUNC_ATTR_NONNULL_ARG(1) { stream->read_cb = cb; - stream->cb_data = data; - if (stream->uvstream) { - uv_read_start(stream->uvstream, alloc_cb, read_cb); + stream->s.cb_data = data; + if (stream->s.uvstream) { + uv_read_start(stream->s.uvstream, alloc_cb, read_cb); } else { - uv_idle_start(&stream->uv.idle, fread_idle_cb); + uv_idle_start(&stream->s.uv.idle, fread_idle_cb); } } /// Stops watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance -void rstream_stop(Stream *stream) +void rstream_stop(RStream *stream) FUNC_ATTR_NONNULL_ALL { - if (stream->uvstream) { - uv_read_stop(stream->uvstream); + if (stream->s.uvstream) { + uv_read_stop(stream->s.uvstream); } else { - uv_idle_stop(&stream->uv.idle); + uv_idle_stop(&stream->s.uv.idle); } } @@ -77,9 +80,9 @@ static void on_rbuffer_full(RBuffer *buf, void *data) static void on_rbuffer_nonfull(RBuffer *buf, void *data) { - Stream *stream = data; + RStream *stream = data; assert(stream->read_cb); - rstream_start(stream, stream->read_cb, stream->cb_data); + rstream_start(stream, stream->read_cb, stream->s.cb_data); } // Callbacks used by libuv @@ -87,7 +90,7 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data) /// Called by libuv to allocate memory for reading. static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) { - Stream *stream = handle->data; + RStream *stream = handle->data; // `uv_buf_t.len` happens to have different size on Windows. size_t write_count; buf->base = rbuffer_write_ptr(stream->buffer, &write_count); @@ -99,7 +102,7 @@ static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) /// 0-length buffer. static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) { - Stream *stream = uvstream->data; + RStream *stream = uvstream->data; if (cnt <= 0) { // cnt == 0 means libuv asked for a buffer and decided it wasn't needed: @@ -141,7 +144,7 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) static void fread_idle_cb(uv_idle_t *handle) { uv_fs_t req; - Stream *stream = handle->data; + RStream *stream = handle->data; // `uv_buf_t.len` happens to have different size on Windows. size_t write_count; @@ -160,7 +163,7 @@ static void fread_idle_cb(uv_idle_t *handle) // Synchronous read uv_fs_read(handle->loop, &req, - stream->fd, + stream->s.fd, &stream->uvbuf, 1, (int64_t)stream->fpos, @@ -169,7 +172,7 @@ static void fread_idle_cb(uv_idle_t *handle) uv_fs_req_cleanup(&req); if (req.result <= 0) { - uv_idle_stop(&stream->uv.idle); + uv_idle_stop(&stream->s.uv.idle); invoke_read_cb(stream, 0, true); return; } @@ -183,24 +186,29 @@ static void fread_idle_cb(uv_idle_t *handle) static void read_event(void **argv) { - Stream *stream = argv[0]; + RStream *stream = argv[0]; if (stream->read_cb) { size_t count = (uintptr_t)argv[1]; bool eof = (uintptr_t)argv[2]; stream->did_eof = eof; - stream->read_cb(stream, stream->buffer, count, stream->cb_data, eof); + stream->read_cb(stream, stream->buffer, count, stream->s.cb_data, eof); } - stream->pending_reqs--; - if (stream->closed && !stream->pending_reqs) { - stream_close_handle(stream); + stream->s.pending_reqs--; + if (stream->s.closed && !stream->s.pending_reqs) { + stream_close_handle(&stream->s, true); } } -static void invoke_read_cb(Stream *stream, size_t count, bool eof) +static void invoke_read_cb(RStream *stream, size_t count, bool eof) { // Don't let the stream be closed before the event is processed. - stream->pending_reqs++; + stream->s.pending_reqs++; - CREATE_EVENT(stream->events, read_event, + CREATE_EVENT(stream->s.events, read_event, stream, (void *)(uintptr_t *)count, (void *)(uintptr_t)eof); } + +void rstream_may_close(RStream *stream) +{ + stream_may_close(&stream->s, true); +} diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c index 4e878a2ecf..017f159fa1 100644 --- a/src/nvim/event/socket.c +++ b/src/nvim/event/socket.c @@ -135,17 +135,17 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb) return 0; } -int socket_watcher_accept(SocketWatcher *watcher, Stream *stream) +int socket_watcher_accept(SocketWatcher *watcher, RStream *stream) FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) { uv_stream_t *client; if (watcher->stream->type == UV_TCP) { - client = (uv_stream_t *)(&stream->uv.tcp); + client = (uv_stream_t *)(&stream->s.uv.tcp); uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client); uv_tcp_nodelay((uv_tcp_t *)client, true); } else { - client = (uv_stream_t *)&stream->uv.pipe; + client = (uv_stream_t *)&stream->s.uv.pipe; uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0); } @@ -156,7 +156,7 @@ int socket_watcher_accept(SocketWatcher *watcher, Stream *stream) return result; } - stream_init(NULL, stream, -1, client); + stream_init(NULL, &stream->s, -1, client); return 0; } @@ -197,7 +197,7 @@ static void connect_cb(uv_connect_t *req, int status) } } -bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address, int timeout, +bool socket_connect(Loop *loop, RStream *stream, bool is_tcp, const char *address, int timeout, const char **error) { bool success = false; @@ -206,7 +206,7 @@ bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address req.data = &status; uv_stream_t *uv_stream; - uv_tcp_t *tcp = &stream->uv.tcp; + uv_tcp_t *tcp = &stream->s.uv.tcp; uv_getaddrinfo_t addr_req; addr_req.addrinfo = NULL; const struct addrinfo *addrinfo = NULL; @@ -237,7 +237,7 @@ tcp_retry: uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb); uv_stream = (uv_stream_t *)tcp; } else { - uv_pipe_t *pipe = &stream->uv.pipe; + uv_pipe_t *pipe = &stream->s.uv.pipe; uv_pipe_init(&loop->uv, pipe, 0); uv_pipe_connect(&req, pipe, address, connect_cb); uv_stream = (uv_stream_t *)pipe; @@ -245,7 +245,7 @@ tcp_retry: status = 1; LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1); if (status == 0) { - stream_init(NULL, stream, -1, uv_stream); + stream_init(NULL, &stream->s, -1, uv_stream); success = true; } else if (is_tcp && addrinfo->ai_next) { addrinfo = addrinfo->ai_next; diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 0b9ed4f25b..3d26dd868f 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -85,21 +85,17 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream) } stream->internal_data = NULL; - stream->fpos = 0; stream->curmem = 0; stream->maxmem = 0; stream->pending_reqs = 0; - stream->read_cb = NULL; stream->write_cb = NULL; stream->close_cb = NULL; stream->internal_close_cb = NULL; stream->closed = false; - stream->buffer = NULL; stream->events = NULL; - stream->num_bytes = 0; } -void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) +void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, bool rstream) FUNC_ATTR_NONNULL_ARG(1) { assert(!stream->closed); @@ -116,18 +112,18 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) #endif if (!stream->pending_reqs) { - stream_close_handle(stream); + stream_close_handle(stream, rstream); } } -void stream_may_close(Stream *stream) +void stream_may_close(Stream *stream, bool rstream) { if (!stream->closed) { - stream_close(stream, NULL, NULL); + stream_close(stream, NULL, NULL, rstream); } } -void stream_close_handle(Stream *stream) +void stream_close_handle(Stream *stream, bool rstream) FUNC_ATTR_NONNULL_ALL { uv_handle_t *handle = NULL; @@ -145,16 +141,22 @@ void stream_close_handle(Stream *stream) assert(handle != NULL); if (!uv_is_closing(handle)) { - uv_close(handle, close_cb); + uv_close(handle, rstream ? rstream_close_cb : close_cb); } } -static void close_cb(uv_handle_t *handle) +static void rstream_close_cb(uv_handle_t *handle) { - Stream *stream = handle->data; + RStream *stream = handle->data; if (stream->buffer) { rbuffer_free(stream->buffer); } + close_cb(handle); +} + +static void close_cb(uv_handle_t *handle) +{ + Stream *stream = handle->data; if (stream->close_cb) { stream->close_cb(stream, stream->close_cb_data); } diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c index c67a9b96ed..07aab87e4d 100644 --- a/src/nvim/event/wstream.c +++ b/src/nvim/event/wstream.c @@ -141,7 +141,7 @@ static void write_cb(uv_write_t *req, int status) if (data->stream->closed && data->stream->pending_reqs == 0) { // Last pending write, free the stream; - stream_close_handle(data->stream); + stream_close_handle(data->stream, false); } xfree(data); @@ -158,3 +158,8 @@ void wstream_release_wbuffer(WBuffer *buffer) xfree(buffer); } } + +void wstream_may_close(Stream *stream) +{ + stream_may_close(stream, false); +} diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 5737a0440f..98d5d8c6cb 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -89,7 +89,7 @@ void rpc_start(Channel *channel) kv_init(rpc->call_stack); if (channel->streamtype != kChannelStreamInternal) { - Stream *out = channel_outstream(channel); + RStream *out = channel_outstream(channel); #ifdef NVIM_LOG_DEBUG Stream *in = channel_instream(channel); DLOG("rpc ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id, @@ -202,7 +202,7 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem return frame.errored ? NIL : frame.result; } -static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) +static void receive_msgpack(RStream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) { Channel *channel = data; channel_incref(channel); diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 60b5b48745..cfe8696cdd 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -41,7 +41,7 @@ typedef enum { kInputEof, } InbufPollResult; -static Stream read_stream = { .closed = true }; // Input before UI starts. +static RStream read_stream = { .s.closed = true }; // Input before UI starts. static RBuffer *input_buffer = NULL; static bool input_eof = false; static bool blocking = false; @@ -59,7 +59,7 @@ void input_init(void) void input_start(void) { - if (!read_stream.closed) { + if (!read_stream.s.closed) { return; } @@ -70,12 +70,12 @@ void input_start(void) void input_stop(void) { - if (read_stream.closed) { + if (read_stream.s.closed) { return; } rstream_stop(&read_stream); - stream_close(&read_stream, NULL, NULL); + rstream_may_close(&read_stream); } #ifdef EXITFREE @@ -138,7 +138,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e uint64_t wait_start = os_hrtime(); cursorhold_time = MIN(cursorhold_time, (int)p_ut); if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) { - if (read_stream.closed && silent_mode) { + if (read_stream.s.closed && silent_mode) { // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). read_error_exit(); } @@ -489,7 +489,7 @@ bool input_available(void) return rbuffer_size(input_buffer) != 0; } -static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) +static void input_read_cb(RStream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) { if (at_eof) { input_eof = true; diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 4d34e8fac4..cfa4dcada7 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -169,7 +169,7 @@ int pty_process_spawn(PtyProcess *ptyproc) int status = 0; // zero or negative error code (libuv convention) Process *proc = (Process *)ptyproc; - assert(proc->err.closed); + assert(proc->err.s.closed); uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD); ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 }; uv_disable_stdio_inheritance(); @@ -208,8 +208,8 @@ int pty_process_spawn(PtyProcess *ptyproc) && (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) { goto error; } - if (!proc->out.closed - && (status = set_duplicating_descriptor(master, &proc->out.uv.pipe))) { + if (!proc->out.s.closed + && (status = set_duplicating_descriptor(master, &proc->out.s.uv.pipe))) { goto error; } diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 12831ff05f..f73baed490 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -55,7 +55,7 @@ int pty_process_spawn(PtyProcess *ptyproc) wchar_t *env = NULL; const char *emsg = NULL; - assert(proc->err.closed); + assert(proc->err.s.closed); if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name, &out_name, ptyproc->width, @@ -72,10 +72,10 @@ int pty_process_spawn(PtyProcess *ptyproc) pty_process_connect_cb); } - if (!proc->out.closed) { + if (!proc->out.s.closed) { out_req = xmalloc(sizeof(uv_connect_t)); uv_pipe_connect(out_req, - &proc->out.uv.pipe, + &proc->out.s.uv.pipe, out_name, pty_process_connect_cb); } @@ -216,7 +216,7 @@ static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer) Process *proc = (Process *)ptyproc; assert(ptyproc->finish_wait != NULL); - if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) { + if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) { uv_timer_stop(&ptyproc->wait_eof_timer); pty_process_finish2(ptyproc); } diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 2a10510b0f..958faa4d22 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -987,7 +987,7 @@ static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired) buf->data = xrealloc(buf->data, buf->cap); } -static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +static void system_data_cb(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { DynamicBuffer *dbuf = data; @@ -1151,7 +1151,7 @@ end: ui_flush(); } -static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +static void out_data_cb(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { size_t cnt; char *ptr = rbuffer_read_ptr(buf, &cnt); @@ -1331,7 +1331,7 @@ static void shell_write_cb(Stream *stream, void *data, int status) msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"), uv_err_name(status)); } - stream_close(stream, NULL, NULL); + stream_close(stream, NULL, NULL, false); } /// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command. diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index f1594dfcb9..588fed2d90 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -167,7 +167,7 @@ void tinput_destroy(TermInput *input) map_destroy(int, &kitty_key_map); rbuffer_free(input->key_buffer); uv_close((uv_handle_t *)&input->timer_handle, NULL); - stream_close(&input->read_stream, NULL, NULL); + rstream_may_close(&input->read_stream); termkey_destroy(input->tk); } @@ -737,7 +737,7 @@ static void handle_raw_buffer(TermInput *input, bool force) } } -static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, bool eof) +static void tinput_read_cb(RStream *stream, RBuffer *buf, size_t count_, void *data, bool eof) { TermInput *input = data; diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index bf6d0f2978..646fbdd16a 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -33,7 +33,7 @@ typedef struct { TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook uv_timer_t timer_handle; Loop *loop; - Stream read_stream; + RStream read_stream; RBuffer *key_buffer; TUIData *tui_data; } TermInput; -- cgit From 0ba087df5e3c69e1f5a5e6551dc05d6793f5f64f Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 31 May 2024 17:51:52 +0200 Subject: refactor(tui): use a linear buffer for buffered keys This buffer is completely emptied every time it is read from. Thus there is no point in using a ring buffer. --- src/nvim/tui/input.c | 25 ++++++++----------------- src/nvim/tui/input.h | 4 +++- 2 files changed, 11 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 588fed2d90..5130678a81 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -28,7 +28,6 @@ #include "nvim/msgpack_rpc/channel.h" #define READ_STREAM_SIZE 0xfff -#define KEY_BUFFER_SIZE 0xfff /// Size of libtermkey's internal input buffer. The buffer may grow larger than /// this when processing very long escape sequences, but will shrink back to @@ -132,7 +131,6 @@ void tinput_init(TermInput *input, Loop *loop) input->key_encoding = kKeyEncodingLegacy; input->ttimeout = (bool)p_ttimeout; input->ttimeoutlen = p_ttm; - input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE); for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) { pmap_put(int)(&kitty_key_map, kitty_key_map_entry[i].key, (ptr_t)kitty_key_map_entry[i].name); @@ -165,7 +163,6 @@ void tinput_init(TermInput *input, Loop *loop) void tinput_destroy(TermInput *input) { map_destroy(int, &kitty_key_map); - rbuffer_free(input->key_buffer); uv_close((uv_handle_t *)&input->timer_handle, NULL); rstream_may_close(&input->read_stream); termkey_destroy(input->tk); @@ -191,44 +188,38 @@ static void tinput_done_event(void **argv) /// Send all pending input in key buffer to Nvim server. static void tinput_flush(TermInput *input) { + String keys = { .data = input->key_buffer, .size = input->key_buffer_len }; if (input->paste) { // produce exactly one paste event - const size_t len = rbuffer_size(input->key_buffer); - String keys = { .data = xmallocz(len), .size = len }; - rbuffer_read(input->key_buffer, keys.data, len); MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, STRING_OBJ(keys)); // 'data' ADD_C(args, BOOLEAN_OBJ(true)); // 'crlf' ADD_C(args, INTEGER_OBJ(input->paste)); // 'phase' rpc_send_event(ui_client_channel_id, "nvim_paste", args); - api_free_string(keys); if (input->paste == 1) { // Paste phase: "continue" input->paste = 2; } - rbuffer_reset(input->key_buffer); } else { // enqueue input - RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) { - const String keys = { .data = buf, .size = len }; + if (input->key_buffer_len > 0) { MAXSIZE_TEMP_ARRAY(args, 1); ADD_C(args, STRING_OBJ(keys)); // NOTE: This is non-blocking and won't check partially processed input, // but should be fine as all big sends are handled with nvim_paste, not nvim_input rpc_send_event(ui_client_channel_id, "nvim_input", args); - rbuffer_consumed(input->key_buffer, len); - rbuffer_reset(input->key_buffer); } } + input->key_buffer_len = 0; } static void tinput_enqueue(TermInput *input, char *buf, size_t size) { - if (rbuffer_size(input->key_buffer) > - rbuffer_capacity(input->key_buffer) - 0xff) { - // don't ever let the buffer get too full or we risk putting incomplete keys - // into it + if (input->key_buffer_len > KEY_BUFFER_SIZE - 0xff) { + // don't ever let the buffer get too full or we risk putting incomplete keys into it tinput_flush(input); } - rbuffer_write(input->key_buffer, buf, size); + size_t to_copy = MIN(size, KEY_BUFFER_SIZE - input->key_buffer_len); + memcpy(input->key_buffer + input->key_buffer_len, buf, to_copy); + input->key_buffer_len += to_copy; } /// Handle TERMKEY_KEYMOD_* modifiers, i.e. Shift, Alt and Ctrl. diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 646fbdd16a..c594228c07 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -17,6 +17,7 @@ typedef enum { kKeyEncodingXterm, ///< Xterm's modifyOtherKeys encoding (XTMODKEYS) } KeyEncoding; +#define KEY_BUFFER_SIZE 0xfff typedef struct { int in_fd; // Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk @@ -34,8 +35,9 @@ typedef struct { uv_timer_t timer_handle; Loop *loop; RStream read_stream; - RBuffer *key_buffer; TUIData *tui_data; + char key_buffer[KEY_BUFFER_SIZE]; + size_t key_buffer_len; } TermInput; typedef enum { -- cgit From 6d6974eae685feeccac027287b4dee58730a7464 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 31 May 2024 20:36:16 +0200 Subject: refactor(input): don't use a ring for input Since paste data is handled via a separate channel, the data processed via `input_buffer` is typically just explicit keys as typed in by the user. Therefore it should be fine to use `memmove()` to always put the remaining data in front when refilling the buffer. --- src/nvim/api/vim.c | 2 +- src/nvim/main.c | 1 - src/nvim/memory.c | 1 - src/nvim/os/input.c | 111 ++++++++++++++++++++++++++++------------------------ 4 files changed, 61 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 52ab18cbff..ae8f73fa2c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -313,7 +313,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) keys_esc = keys.data; } if (lowlevel) { - input_enqueue_raw(cstr_as_string(keys_esc)); + input_enqueue_raw(keys_esc, strlen(keys_esc)); } else { ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), insert ? 0 : typebuf.tb_len, !typed, false); diff --git a/src/nvim/main.c b/src/nvim/main.c index cf1324d37f..db7f16131b 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -154,7 +154,6 @@ void event_init(void) loop_init(&main_loop, NULL); resize_events = multiqueue_new_child(main_loop.events); - input_init(); signal_init(); // mspgack-rpc initialization channel_init(); diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 789535e270..6a60ca927e 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -882,7 +882,6 @@ void free_all_mem(void) decor_free_all_mem(); drawline_free_all_mem(); - input_free_all_mem(); if (ui_client_channel_id) { ui_client_free_all_mem(); diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index cfe8696cdd..63eca0b6da 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -33,7 +33,7 @@ #include "nvim/state_defs.h" #define READ_BUFFER_SIZE 0xfff -#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4) +#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN) typedef enum { kInputNone, @@ -42,7 +42,10 @@ typedef enum { } InbufPollResult; static RStream read_stream = { .s.closed = true }; // Input before UI starts. -static RBuffer *input_buffer = NULL; +static char input_buffer[INPUT_BUFFER_SIZE]; +static char *input_read_pos = input_buffer; +static char *input_write_pos = input_buffer; + static bool input_eof = false; static bool blocking = false; static int cursorhold_time = 0; ///< time waiting for CursorHold event @@ -52,11 +55,6 @@ static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting starte # include "os/input.c.generated.h" #endif -void input_init(void) -{ - input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); -} - void input_start(void) { if (!read_stream.s.closed) { @@ -78,13 +76,6 @@ void input_stop(void) rstream_may_close(&read_stream); } -#ifdef EXITFREE -void input_free_all_mem(void) -{ - rbuffer_free(input_buffer); -} -#endif - static void cursorhold_event(void **argv) { event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD; @@ -119,9 +110,12 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e restart_cursorhold_wait(tb_change_cnt); } - if (maxlen && rbuffer_size(input_buffer)) { + if (maxlen && input_available()) { restart_cursorhold_wait(tb_change_cnt); - return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); + size_t to_read = MIN((size_t)maxlen, input_available()); + memcpy(buf, input_read_pos, to_read); + input_read_pos += to_read; + return (int)to_read; } // No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped. @@ -161,11 +155,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e return 0; } - if (maxlen && rbuffer_size(input_buffer)) { + if (maxlen && input_available()) { restart_cursorhold_wait(tb_change_cnt); - // Safe to convert rbuffer_read to int, it will never overflow since we use - // relatively small buffers. - return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); + // Safe to convert rbuffer_read to int, it will never overflow since + // INPUT_BUFFER_SIZE fits in an int + size_t to_read = MIN((size_t)maxlen, input_available()); + memcpy(buf, input_read_pos, to_read); + input_read_pos += to_read; + return (int)to_read; } // If there are events, return the keys directly @@ -247,11 +244,28 @@ bool os_isatty(int fd) return uv_guess_handle(fd) == UV_TTY; } -void input_enqueue_raw(String keys) +size_t input_available(void) +{ + return (size_t)(input_write_pos - input_read_pos); +} + +static size_t input_space(void) +{ + return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos); +} + +void input_enqueue_raw(const char *data, size_t size) { - if (keys.size > 0) { - rbuffer_write(input_buffer, keys.data, keys.size); + if (input_read_pos > input_buffer) { + size_t available = input_available(); + memmove(input_buffer, input_read_pos, available); + input_read_pos = input_buffer; + input_write_pos = input_buffer + available; } + + size_t to_write = MIN(size, input_space()); + memcpy(input_write_pos, data, to_write); + input_write_pos += to_write; } size_t input_enqueue(String keys) @@ -259,7 +273,7 @@ size_t input_enqueue(String keys) const char *ptr = keys.data; const char *end = ptr + keys.size; - while (rbuffer_space(input_buffer) >= 19 && ptr < end) { + while (input_space() >= 19 && ptr < end) { // A "" form occupies at least 1 characters, and produces up // to 19 characters (1 + 5 * 3 for the char and 3 for a modifier). // In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed, @@ -272,7 +286,7 @@ size_t input_enqueue(String keys) if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); - rbuffer_write(input_buffer, (char *)buf, new_size); + input_enqueue_raw((char *)buf, new_size); continue; } @@ -293,11 +307,11 @@ size_t input_enqueue(String keys) // copy the character, escaping K_SPECIAL if ((uint8_t)(*ptr) == K_SPECIAL) { - rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1); + input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1); + input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1); + input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1); } else { - rbuffer_write(input_buffer, ptr, 1); + input_enqueue_raw(ptr, 1); } ptr++; } @@ -422,7 +436,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs return bufsize; } -size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) +void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) { modifier |= check_multiclick(code, grid, row, col); uint8_t buf[7]; @@ -442,8 +456,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co mouse_col = col; size_t written = 3 + (size_t)(p - buf); - rbuffer_write(input_buffer, (char *)buf, written); - return written; + input_enqueue_raw((char *)buf, written); } /// @return true if the main loop is blocked and waiting for input. @@ -484,20 +497,15 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events) return input_eof ? kInputEof : kInputNone; } -bool input_available(void) -{ - return rbuffer_size(input_buffer) != 0; -} - static void input_read_cb(RStream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) { if (at_eof) { input_eof = true; } - assert(rbuffer_space(input_buffer) >= rbuffer_size(buf)); + assert(input_space() >= rbuffer_size(buf)); RBUFFER_UNTIL_EMPTY(buf, ptr, len) { - (void)rbuffer_write(input_buffer, ptr, len); + input_enqueue_raw(ptr, len); rbuffer_consumed(buf, len); } } @@ -508,23 +516,24 @@ static void process_ctrl_c(void) return; } - size_t consume_count = 0; - RBUFFER_EACH_REVERSE(input_buffer, c, i) { - if ((uint8_t)c == Ctrl_C - || ((uint8_t)c == 'C' && i >= 3 - && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL - && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER - && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) { - *rbuffer_get(input_buffer, i) = Ctrl_C; + size_t available = input_available(); + ssize_t i; + for (i = (ssize_t)available - 1; i >= 0; i--) { + uint8_t c = (uint8_t)input_read_pos[i]; + if (c == Ctrl_C + || (c == 'C' && i >= 3 + && (uint8_t)input_read_pos[i - 3] == K_SPECIAL + && (uint8_t)input_read_pos[i - 2] == KS_MODIFIER + && (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) { + input_read_pos[i] = Ctrl_C; got_int = true; - consume_count = i; break; } } - if (got_int && consume_count) { + if (got_int && i > 0) { // Remove all unprocessed input (typeahead) before the CTRL-C. - rbuffer_consumed(input_buffer, consume_count); + input_read_pos += i; } } @@ -548,7 +557,7 @@ static int push_event_key(uint8_t *buf, int maxlen) bool os_input_ready(MultiQueue *events) { return (typebuf_was_filled // API call filled typeahead - || rbuffer_size(input_buffer) // Input buffer filled + || input_available() // Input buffer filled || pending_events(events)); // Events must be processed } -- cgit From f2083bd55cafe861e9dffb1c1658e5b0983c5ef6 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sat, 1 Jun 2024 12:10:35 +0200 Subject: fix(column): crash with 'signcolumn' set to "number" (#29003) Problem: Numberwidth may depend on number of signs with text in the buffer and is not handled correctly for extmark signs. Solution: Move legacy sign code for changed numberwidth so that it is handled properly for legacy and extmark signs alike. --- src/nvim/decoration.c | 18 ++++++++++++++++++ src/nvim/drawline.c | 1 + src/nvim/drawscreen.c | 1 + src/nvim/sign.c | 30 +----------------------------- 4 files changed, 21 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 303d0318b5..52a3fa5924 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -15,6 +15,7 @@ #include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/fold.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/grid_defs.h" #include "nvim/highlight.h" @@ -184,6 +185,21 @@ void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2) } } +/// When displaying signs in the 'number' column, if the width of the number +/// column is less than 2, then force recomputing the width after placing or +/// unplacing the first sign in "buf". +static void may_force_numberwidth_recompute(buf_T *buf, bool unplace) +{ + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf + && wp->w_minscwidth == SCL_NUM + && (wp->w_p_nu || wp->w_p_rnu) + && (unplace || wp->w_nrwidth_width < 2)) { + wp->w_nrwidth_line_count = 0; + } + } +} + static int sign_add_id = 0; void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2) { @@ -191,6 +207,7 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2) sh->sign_add_id = sign_add_id++; if (sh->text[0]) { buf_signcols_count_range(buf, row1, row2, 1, kFalse); + may_force_numberwidth_recompute(buf, false); } } } @@ -218,6 +235,7 @@ void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh) if (buf_meta_total(buf, kMTMetaSignText)) { buf_signcols_count_range(buf, row1, row2, -1, kFalse); } else { + may_force_numberwidth_recompute(buf, true); buf->b_signcols.resized = true; buf->b_signcols.max = buf->b_signcols.count[0] = 0; } diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 4d534d78a2..3bd00ee3f9 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -465,6 +465,7 @@ static void draw_sign(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, i int fill = nrcol ? number_width(wp) + 1 : SIGN_WIDTH; draw_col_fill(wlv, schar_from_ascii(' '), fill, attr); int sign_pos = wlv->off - SIGN_WIDTH - (int)nrcol; + assert(sign_pos >= 0); linebuf_char[sign_pos] = sattr.text[0]; linebuf_char[sign_pos + 1] = sattr.text[1]; } else { diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 039bbd219c..bd9a834869 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1548,6 +1548,7 @@ static void win_update(win_T *wp) // Force redraw when width of 'number' or 'relativenumber' column changes. if (wp->w_nrwidth != nrwidth_new) { type = UPD_NOT_VALID; + changed_line_abv_curs_win(wp); wp->w_nrwidth = nrwidth_new; } else { // Set mod_top to the first line that needs displaying because of diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 4e6672c5dd..be7a46b720 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -246,12 +246,6 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum) return FAIL; } - // When deleting the last sign need to redraw the windows to remove the - // sign column. Not when curwin is NULL (this means we're exiting). - if (!buf_meta_total(buf, kMTMetaSignText) && curwin != NULL) { - changed_line_abv_curs(); - } - return OK; } @@ -499,17 +493,6 @@ static void sign_list_by_name(char *name) } } -static void may_force_numberwidth_recompute(buf_T *buf, int unplace) -{ - FOR_ALL_TAB_WINDOWS(tp, wp) - if (wp->w_buffer == buf - && (wp->w_p_nu || wp->w_p_rnu) - && (unplace || wp->w_nrwidth_width < 2) - && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) { - wp->w_nrwidth_line_count = 0; - } -} - /// Place a sign at the specified file location or update a sign. static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_T lnum, int prio) { @@ -531,11 +514,7 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_ // ":sign place {id} file={fname}": change sign type and/or priority lnum = buf_mod_sign(buf, id, group, prio, sp); } - if (lnum > 0) { - // When displaying signs in the 'number' column, if the width of the - // number column is less than 2, then force recomputing the width. - may_force_numberwidth_recompute(buf, false); - } else { + if (lnum <= 0) { semsg(_("E885: Not possible to change sign %s"), name); return FAIL; } @@ -562,13 +541,6 @@ static int sign_unplace_inner(buf_T *buf, int id, char *group, linenr_T atlnum) } } - // When all the signs in a buffer are removed, force recomputing the - // number column width (if enabled) in all the windows displaying the - // buffer if 'signcolumn' is set to 'number' in that window. - if (!buf_meta_total(buf, kMTMetaSignText)) { - may_force_numberwidth_recompute(buf, true); - } - return OK; } -- cgit From bb6190bec5f18c1f9e2c1d29ef1f7cf7912ea625 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Jun 2024 08:19:41 -0700 Subject: refactor: move shared messages to errors.h #26214 --- src/nvim/api/vim.c | 1 + src/nvim/api/win_config.c | 1 + src/nvim/api/window.c | 1 + src/nvim/arglist.c | 1 + src/nvim/autocmd.c | 1 + src/nvim/buffer.c | 1 + src/nvim/bufwrite.c | 1 + src/nvim/channel.c | 1 + src/nvim/cmdexpand.c | 1 + src/nvim/cmdhist.c | 1 + src/nvim/debugger.c | 1 + src/nvim/diff.c | 1 + src/nvim/digraph.c | 1 + src/nvim/edit.c | 1 + src/nvim/errors.h | 193 ++++++++++++++++++++++++++++++ src/nvim/eval.c | 1 + src/nvim/eval/executor.c | 1 + src/nvim/eval/funcs.c | 1 + src/nvim/eval/typval.c | 1 + src/nvim/eval/userfunc.c | 1 + src/nvim/eval/vars.c | 1 + src/nvim/eval/window.c | 1 + src/nvim/ex_cmds.c | 1 + src/nvim/ex_cmds2.c | 1 + src/nvim/ex_docmd.c | 1 + src/nvim/ex_eval.c | 1 + src/nvim/ex_getln.c | 1 + src/nvim/ex_session.c | 1 + src/nvim/fileio.c | 1 + src/nvim/fold.c | 1 + src/nvim/generators/gen_api_dispatch.lua | 1 + src/nvim/getchar.c | 1 + src/nvim/globals.h | 196 +------------------------------ src/nvim/help.c | 1 + src/nvim/highlight_group.c | 1 + src/nvim/indent.c | 1 + src/nvim/insexpand.c | 1 + src/nvim/keycodes.c | 1 + src/nvim/lua/api_wrappers.c | 1 + src/nvim/lua/executor.c | 1 + src/nvim/lua/secure.c | 1 + src/nvim/lua/spell.c | 1 + src/nvim/main.c | 1 + src/nvim/mapping.c | 1 + src/nvim/mark.c | 1 + src/nvim/match.c | 1 + src/nvim/mbyte.c | 1 + src/nvim/memfile.c | 1 + src/nvim/memory.c | 1 + src/nvim/menu.c | 1 + src/nvim/message.c | 1 + src/nvim/move.c | 1 + src/nvim/normal.c | 1 + src/nvim/ops.c | 1 + src/nvim/option.c | 1 + src/nvim/optionstr.c | 1 + src/nvim/os/fs.c | 1 + src/nvim/os/shell.c | 1 + src/nvim/popupmenu.c | 1 + src/nvim/profile.c | 1 + src/nvim/quickfix.c | 1 + src/nvim/regexp.c | 1 + src/nvim/runtime.c | 1 + src/nvim/search.c | 1 + src/nvim/shada.c | 1 + src/nvim/sign.c | 1 + src/nvim/spell.c | 1 + src/nvim/spellfile.c | 1 + src/nvim/spellsuggest.c | 1 + src/nvim/strings.c | 1 + src/nvim/syntax.c | 1 + src/nvim/tag.c | 1 + src/nvim/testing.c | 1 + src/nvim/undo.c | 1 + src/nvim/window.c | 1 + src/nvim/winfloat.c | 1 + 76 files changed, 270 insertions(+), 193 deletions(-) create mode 100644 src/nvim/errors.h (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 52ab18cbff..f5c89fb283 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -28,6 +28,7 @@ #include "nvim/cursor.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 70235d8db6..f0b90d8512 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -17,6 +17,7 @@ #include "nvim/decoration.h" #include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/window.h" #include "nvim/extmark_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 54a19513db..92dc9dc7e3 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -13,6 +13,7 @@ #include "nvim/buffer_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/window.h" #include "nvim/ex_docmd.h" #include "nvim/gettext_defs.h" diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index 4d493c9d03..700bfc1655 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -13,6 +13,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/window.h" diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index c5d81d4cd2..e5872fcc76 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 39d0d24d47..5d0cd66133 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -43,6 +43,7 @@ #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 27de03954a..6fbcb2dbb8 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -18,6 +18,7 @@ #include "nvim/bufwrite.h" #include "nvim/change.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/channel.c b/src/nvim/channel.c index e5492caf45..05225cecd0 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -13,6 +13,7 @@ #include "nvim/autocmd_defs.h" #include "nvim/buffer_defs.h" #include "nvim/channel.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 808df44941..bb85620ce6 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -19,6 +19,7 @@ #include "nvim/cmdexpand.h" #include "nvim/cmdhist.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index 983ab8b59b..ab05ae1cfc 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -11,6 +11,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cmdhist.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 7d87b61ce5..b71ff23f57 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -13,6 +13,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/diff.c b/src/nvim/diff.c index ea846b46ec..54335fc93e 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -26,6 +26,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index a358a1723a..26fb77df30 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -12,6 +12,7 @@ #include "nvim/charset.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 220b92d099..146e95df87 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -18,6 +18,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/errors.h b/src/nvim/errors.h new file mode 100644 index 0000000000..39095db952 --- /dev/null +++ b/src/nvim/errors.h @@ -0,0 +1,193 @@ +#pragma once + +#include "nvim/gettext_defs.h" +#include "nvim/macros_defs.h" + +// +// Shared error messages. Excludes errors only used once and debugging messages. +// +// uncrustify:off +EXTERN const char e_abort[] INIT(= N_("E470: Command aborted")); +EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup")); +EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job")); +EXTERN const char e_argreq[] INIT(= N_("E471: Argument required")); +EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &")); +EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; executes, CTRL-C quits")); +EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search")); +EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s")); +EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive")); +EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded")); +EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif")); +EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry")); +EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile")); +EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor")); +EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while")); +EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for")); +EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)")); +EXTERN const char e_failed[] INIT(= N_("E472: Command failed")); +EXTERN const char e_internal[] INIT(= N_("E473: Internal error")); +EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s")); +EXTERN const char e_interr[] INIT(= N_("Interrupted")); +EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument")); +EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s")); +EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); +EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s")); +EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s")); +EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\"")); +EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range")); +EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command")); +EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); +EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible")); +EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id")); +EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job")); +EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full")); +EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\"")); +EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty")); +EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s")); +EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel")); +EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'")); +EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64)); +EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); +EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s")); +EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); +EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number")); +EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set")); +EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off")); +EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep")); +EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file")); +EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation")); +EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed")); +EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s")); +EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet")); +EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line")); +EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping")); +EXTERN const char e_nomatch[] INIT(= N_("E479: No match")); +EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s")); +EXTERN const char e_noname[] INIT(= N_("E32: No file name")); +EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression")); +EXTERN const char e_noprev[] INIT(= N_("E34: No previous command")); +EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression")); +EXTERN const char e_norange[] INIT(= N_("E481: No range allowed")); +EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room")); +EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name")); +EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s")); +EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s")); +EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s")); +EXTERN const char e_null[] INIT(= N_("E38: Null argument")); +EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected")); +EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s")); +EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!")); +EXTERN const char e_patnotf[] INIT(= N_("Pattern not found")); +EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s")); +EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive")); +EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory")); + +EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors")); +EXTERN const char e_loclist[] INIT(= N_("E776: No location list")); +EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string")); +EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program")); +EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)")); +EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s=")); +EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s")); +EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); +EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\"")); +EXTERN const char e_stringreq[] INIT(= N_("E928: String required")); +EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required")); +EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64)); +EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob")); +EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s")); +EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s")); +EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"")); +EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\"")); +EXTERN const char e_listreq[] INIT(= N_("E714: List required")); +EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required")); +EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); +EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); +EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); +EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); +EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here")); +EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window")); +EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); +EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size")); +EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty")); +EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!")); +EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file")); +EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex")); +EXTERN const char e_longname[] INIT(= N_("E75: Name too long")); +EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many [")); +EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names")); +EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters")); +EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s")); +EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark")); +EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards")); +EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); +EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); +EXTERN const char e_write[] INIT(= N_("E80: Error while writing")); +EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required")); +EXTERN const char e_usingsid[] INIT(= N_("E81: Using not in a script context")); +EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s")); +EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer")); +EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist")); + +EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function")); + +EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); +EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); +EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set")); +EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name")); +EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\"")); +EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior")); +EXTERN const char e_menu_only_exists_in_another_mode[] +INIT(= N_("E328: Menu only exists in another mode")); +EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window")); +EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List")); +EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); +EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long")); +EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String")); +EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); +EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); +EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); +EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); + +EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); + +EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); + +EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); +EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); + +EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); + +EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); + +EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range")); + +EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name")); + +EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); + +EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); +EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); + +EXTERN const char e_stray_closing_curly_str[] +INIT(= N_("E1278: Stray '}' without a matching '{': %s")); +EXTERN const char e_missing_close_curly_str[] +INIT(= N_("E1279: Missing '}': %s")); + +EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); + +EXTERN const char e_undobang_cannot_redo_or_move_branch[] +INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); + +EXTERN const char e_winfixbuf_cannot_go_to_buffer[] +INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); + +EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); + +EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); + +EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); +EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); + +EXTERN const char line_msg[] INIT(= N_(" line ")); +// uncrustify:on diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 48a58228ae..a8778b9489 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -24,6 +24,7 @@ #include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/executor.h" diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 1b8c057d7c..3255e78d09 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -1,6 +1,7 @@ #include #include +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/executor.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8b22c7a797..0165e4af60 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -38,6 +38,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/buffer.h" #include "nvim/eval/decode.h" diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index eb8c89c36e..1ea1fe46d2 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -10,6 +10,7 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/executor.h" diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 39bd63462c..00fb896797 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 1c15274acc..7b93a291c4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -15,6 +15,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 68de40f983..d7485c12a3 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -10,6 +10,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 834cc6698a..2f7673a6f4 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -34,6 +34,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index f4a6e61831..a602719f6d 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -17,6 +17,7 @@ #include "nvim/bufwrite.h" #include "nvim/change.h" #include "nvim/channel.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1fcfc505df..028ee8f6ae 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -29,6 +29,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 472741d537..2681beb228 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -11,6 +11,7 @@ #include "nvim/ascii_defs.h" #include "nvim/charset.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index cc2608433d..4323a9d221 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -28,6 +28,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 0e5d2fe4f5..50ee197ef4 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -15,6 +15,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index df9c4928c9..05c9114554 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -27,6 +27,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_eval.h" diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 59a4dc6aad..be1b6acf2c 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -22,6 +22,7 @@ #include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_session.h" diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 62c99ce082..61c80a3d2e 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -306,6 +306,7 @@ local keysets_defs = assert(io.open(keysets_outputf, 'wb')) -- so that the dispatcher can find the C functions that you are creating! -- =========================================================================== output:write([[ +#include "nvim/errors.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/globals.h" diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 9b19644b7e..ce2c85f174 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -19,6 +19,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 83fef1fe75..410e8f2e7c 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -793,195 +793,7 @@ EXTERN disptick_T display_tick INIT( = 0); // cursor position in Insert mode. EXTERN linenr_T spell_redraw_lnum INIT( = 0); -// uncrustify:off - -// The error messages that can be shared are included here. -// Excluded are errors that are only used once and debugging messages. -EXTERN const char e_abort[] INIT(= N_("E470: Command aborted")); -EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup")); -EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job")); -EXTERN const char e_argreq[] INIT(= N_("E471: Argument required")); -EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &")); -EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; executes, CTRL-C quits")); -EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search")); -EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s")); -EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive")); -EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded")); -EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif")); -EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry")); -EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile")); -EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor")); -EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while")); -EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for")); -EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)")); -EXTERN const char e_failed[] INIT(= N_("E472: Command failed")); -EXTERN const char e_internal[] INIT(= N_("E473: Internal error")); -EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s")); -EXTERN const char e_interr[] INIT(= N_("Interrupted")); -EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument")); -EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s")); -EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); -EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s")); -EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s")); -EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\"")); -EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range")); -EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command")); -EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); -EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible")); -EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id")); -EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job")); -EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full")); -EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\"")); -EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty")); -EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s")); -EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel")); -EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'")); -EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64)); -EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); -EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s")); -EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); -EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number")); -EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set")); -EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off")); -EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep")); -EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file")); -EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation")); -EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed")); -EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s")); -EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet")); -EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line")); -EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping")); -EXTERN const char e_nomatch[] INIT(= N_("E479: No match")); -EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s")); -EXTERN const char e_noname[] INIT(= N_("E32: No file name")); -EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression")); -EXTERN const char e_noprev[] INIT(= N_("E34: No previous command")); -EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression")); -EXTERN const char e_norange[] INIT(= N_("E481: No range allowed")); -EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room")); -EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name")); -EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s")); -EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s")); -EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s")); -EXTERN const char e_null[] INIT(= N_("E38: Null argument")); -EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected")); -EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s")); -EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!")); -EXTERN const char e_patnotf[] INIT(= N_("Pattern not found")); -EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s")); -EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive")); -EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory")); - -EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors")); -EXTERN const char e_loclist[] INIT(= N_("E776: No location list")); -EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string")); -EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program")); -EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)")); -EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s=")); -EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s")); -EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); -EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\"")); -EXTERN const char e_stringreq[] INIT(= N_("E928: String required")); -EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required")); -EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64)); -EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob")); -EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s")); -EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s")); -EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"")); -EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\"")); -EXTERN const char e_listreq[] INIT(= N_("E714: List required")); -EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required")); -EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); -EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); -EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); -EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); -EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here")); -EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window")); -EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); -EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size")); -EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty")); -EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!")); -EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file")); -EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex")); -EXTERN const char e_longname[] INIT(= N_("E75: Name too long")); -EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many [")); -EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names")); -EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters")); -EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s")); -EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark")); -EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards")); -EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); -EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); -EXTERN const char e_write[] INIT(= N_("E80: Error while writing")); -EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required")); -EXTERN const char e_usingsid[] INIT(= N_("E81: Using not in a script context")); -EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s")); -EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer")); -EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist")); - -EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function")); - -EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); -EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); -EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set")); -EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name")); -EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\"")); -EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior")); -EXTERN const char e_menu_only_exists_in_another_mode[] -INIT(= N_("E328: Menu only exists in another mode")); -EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window")); -EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List")); -EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); -EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long")); -EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String")); -EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); -EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); -EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); -EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); - -EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); - -EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); - -EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); -EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); - -EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); - -EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); - -EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range")); - -EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name")); - -EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); - -EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); -EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); - -EXTERN const char e_stray_closing_curly_str[] -INIT(= N_("E1278: Stray '}' without a matching '{': %s")); -EXTERN const char e_missing_close_curly_str[] -INIT(= N_("E1279: Missing '}': %s")); - -EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); - -EXTERN const char e_undobang_cannot_redo_or_move_branch[] -INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); - -EXTERN const char e_winfixbuf_cannot_go_to_buffer[] -INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); - -EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); - -EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); - -EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); -EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); - -EXTERN const char line_msg[] INIT(= N_(" line ")); - -EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report. +EXTERN FILE *time_fd INIT( = NULL); // Where to write --startuptime report. // Some compilers warn for not using a return value, but in some situations we // can't do anything useful with the value. Assign to this variable to avoid @@ -989,11 +801,9 @@ EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report. EXTERN int vim_ignored; // stdio is an RPC channel (--embed). -EXTERN bool embedded_mode INIT(= false); +EXTERN bool embedded_mode INIT( = false); // Do not start UI (--headless, -l) nor read/write to stdio (unless embedding). -EXTERN bool headless_mode INIT(= false); - -// uncrustify:on +EXTERN bool headless_mode INIT( = false); /// Only filled for Win32. EXTERN char windowsVersion[20] INIT( = { 0 }); diff --git a/src/nvim/help.c b/src/nvim/help.c index e9f67ca3e4..d28f195c00 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -13,6 +13,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index ccb093c116..b5e62e7f31 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -22,6 +22,7 @@ #include "nvim/cursor_shape.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/indent.c b/src/nvim/indent.c index d635c7d7bf..69c95e9038 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -13,6 +13,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 8b1c09b32f..7a652dff2a 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -22,6 +22,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index 44ddfbba00..f7215d3d12 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -8,6 +8,7 @@ #include "nvim/ascii_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/gettext_defs.h" diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c index 2b7b0c6471..36847d1fc9 100644 --- a/src/nvim/lua/api_wrappers.c +++ b/src/nvim/lua/api_wrappers.c @@ -5,6 +5,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" +#include "nvim/errors.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/func_attr.h" diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index a76b8213e5..6246452b92 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -22,6 +22,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c index f62e0ace04..a84d6c4d65 100644 --- a/src/nvim/lua/secure.c +++ b/src/nvim/lua/secure.c @@ -3,6 +3,7 @@ #include #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/ex_cmds_defs.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index ba83239dc5..f4dacd7a55 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -7,6 +7,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/highlight_defs.h" diff --git a/src/nvim/main.c b/src/nvim/main.c index cf1324d37f..ecd3274af4 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -37,6 +37,7 @@ #include "nvim/diff.h" #include "nvim/drawline.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 9320390d68..167111f3ae 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -19,6 +19,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 6ce42bb7fe..16f444a316 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -14,6 +14,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/match.c b/src/nvim/match.c index 580d7d1069..6ae4e41147 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -10,6 +10,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index a345795bbe..23fdd5eb16 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -43,6 +43,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/getchar.h" diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index a1713edb66..498d212da3 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -46,6 +46,7 @@ #include "nvim/assert_defs.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/fileio.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 789535e270..2afbd262ab 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -19,6 +19,7 @@ #include "nvim/context.h" #include "nvim/decoration_provider.h" #include "nvim/drawline.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/menu.c b/src/nvim/menu.c index ab28eeca1c..a4d49d041e 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -13,6 +13,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/message.c b/src/nvim/message.c index 10b90bde29..9941dcb254 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -18,6 +18,7 @@ #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/move.c b/src/nvim/move.c index 418ece09ed..a2bb1b4685 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -20,6 +20,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" #include "nvim/fold.h" diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 8ba375f29d..879131c9e8 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -28,6 +28,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 5c1e291ac6..47d302df43 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -24,6 +24,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds2.h" diff --git a/src/nvim/option.c b/src/nvim/option.c index 799513e018..32fabd4141 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -44,6 +44,7 @@ #include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 29433ddbb5..be3bec2256 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -14,6 +14,7 @@ #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 19bdf30311..13e87a1ca5 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -17,6 +17,7 @@ #endif #include "auto/config.h" +#include "nvim/errors.h" #include "nvim/os/fs.h" #include "nvim/os/os_defs.h" diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 958faa4d22..d572e9b933 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -10,6 +10,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/event/defs.h" diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 86f3611ec5..bf2fe0f72c 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -19,6 +19,7 @@ #include "nvim/charset.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/profile.c b/src/nvim/profile.c index b88b08d3f0..7ea7061b46 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -10,6 +10,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index e022184f2f..e1d35ab9d5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -20,6 +20,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 5600d6a2f8..b743664b69 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -18,6 +18,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index d913d311db..648e574b97 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -22,6 +22,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/search.c b/src/nvim/search.c index 746c253708..bee124e305 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -18,6 +18,7 @@ #include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 597c7551fd..d5655b1754 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -19,6 +19,7 @@ #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/cmdhist.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/decode.h" #include "nvim/eval/encode.h" diff --git a/src/nvim/sign.c b/src/nvim/sign.c index be7a46b720..be207f58b0 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -21,6 +21,7 @@ #include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/spell.c b/src/nvim/spell.c index d7a6adef58..f6c326075d 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -72,6 +72,7 @@ #include "nvim/decoration.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 046a0a56e5..9746c3df91 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -240,6 +240,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/ex_cmds_defs.h" #include "nvim/fileio.h" #include "nvim/garray.h" diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index a7de20d14e..0e674c3178 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -14,6 +14,7 @@ #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 8fef4ba7fd..329b66cea1 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -12,6 +12,7 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index b63d2a729d..c13619797a 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/tag.c b/src/nvim/tag.c index e7f483dd3d..ca3885b079 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -18,6 +18,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/testing.c b/src/nvim/testing.c index 343568d71e..8041cc2e33 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -7,6 +7,7 @@ #include #include "nvim/ascii_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/undo.c b/src/nvim/undo.c index ba720c9f6a..ed5c9a508c 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -92,6 +92,7 @@ #include "nvim/decoration.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/window.c b/src/nvim/window.c index 1a6c3f7263..9203dd1bdb 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -22,6 +22,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index e3ca0ff139..77bbaed105 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -11,6 +11,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/grid_defs.h" -- cgit From 7a8f42dc036f3bc6e8b106c580e0cd50dbed465e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 06:06:12 +0800 Subject: vim-patch:e299591: runtime(doc): clarify 'shortmess' flag "S" (#29131) fixes: vim/vim#14893 https://github.com/vim/vim/commit/e299591498a20c5c587364e4df57f947dfc02897 Co-authored-by: Christian Brabandt --- src/nvim/options.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 452cc6876b..0f3cf6c5b4 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7317,8 +7317,8 @@ return { message; also for quickfix message (e.g., ":cn") s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* "search hit TOP, continuing at BOTTOM" messages; when using - the search count do not show "W" after the count message (see - S below) + the search count do not show "W" before the count message + (see |shm-S| below) t truncate file message at the start if it is too long *shm-t* to fit on the command-line, "<" will appear in the left most column; ignored in Ex mode @@ -7340,7 +7340,11 @@ return { `:silent` was used for the command; note that this also affects messages from 'autoread' reloading S do not show search count message when searching, e.g. *shm-S* - "[1/5]" + "[1/5]". When the "S" flag is not present (e.g. search count + is shown), the "search hit BOTTOM, continuing at TOP" and + "search hit TOP, continuing at BOTTOM" messages are only + indicated by a "W" (Mnemonic: Wrapped) letter before the + search count statistics. This gives you the opportunity to avoid that a change between buffers requires you to hit , but still gives as useful a message as -- cgit From 0e49c3ad1a599376d0a5c229f304a06d48c56163 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 05:47:47 +0800 Subject: vim-patch:9.1.0456: Left shift is incorrect with vartabstop and shiftwidth=0 Problem: Left shift is incorrect with vartabstop and shiftwidth=0 Solution: make tabstop_at() function aware of shift direction (Gary Johnson) The problem was that with 'vartabstop' set and 'shiftwidth' equal 0, left shifts using << were shifting the line to the wrong column. The tabstop to the right of the first character in the line was being used as the shift amount instead of the tabstop to the left of that first character. The reason was that the tabstop_at() function always returned the value of the tabstop to the right of the given column and was not accounting for the direction of the shift. The solution was to make tabstop_at() aware of the direction of the shift and to choose the tabtop accordingly. A test was added to check this behavior and make sure it doesn't regress. While at it, also fix a few indentation/alignment issues. fixes: vim/vim#14864 closes: vim/vim#14887 https://github.com/vim/vim/commit/88d4f255b7b7a19bb4f6489e0ad0956e47d51fed Co-authored-by: Gary Johnson --- src/nvim/edit.c | 3 ++- src/nvim/eval/funcs.c | 2 +- src/nvim/indent.c | 47 ++++++++++++++++++++++++++++++++--------------- src/nvim/ops.c | 4 ++-- 4 files changed, 37 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 146e95df87..595b4da589 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -474,7 +474,8 @@ static int insert_check(VimState *state) if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(), curbuf->b_p_ts, - curbuf->b_p_vts_array) + curbuf->b_p_vts_array, + false) && curwin->w_wrow == curwin->w_height_inner - 1 - get_scrolloff_value(curwin) && (curwin->w_cursor.lnum != curwin->w_topline || curwin->w_topfill > 0)) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0165e4af60..e704135366 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8302,7 +8302,7 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (col < 0) { return; // type error; errmsg already given } - rettv->vval.v_number = get_sw_value_col(curbuf, col); + rettv->vval.v_number = get_sw_value_col(curbuf, col, false); return; } rettv->vval.v_number = get_sw_value(curbuf); diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 69c95e9038..66cb443e4d 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -147,25 +147,42 @@ int tabstop_padding(colnr_T col, OptInt ts_arg, const colnr_T *vts) } /// Find the size of the tab that covers a particular column. -int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts) +/// +/// If this is being called as part of a shift operation, col is not the cursor +/// column but is the column number to the left of the first non-whitespace +/// character in the line. If the shift is to the left (left == true), then +/// return the size of the tab interval to the left of the column. +int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts, bool left) { - colnr_T tabcol = 0; - int t; - int tab_size = 0; - if (vts == NULL || vts[0] == 0) { return (int)ts; } - const int tabcount = vts[0]; + colnr_T tabcol = 0; // Column of the tab stop under consideration. + int t; // Tabstop index in the list of variable tab stops. + int tab_size = 0; // Size of the tab stop interval to the right or left of the col. + const int tabcount // Number of tab stops in the list of variable tab stops. + = vts[0]; for (t = 1; t <= tabcount; t++) { tabcol += vts[t]; if (tabcol > col) { - tab_size = vts[t]; + // If shifting left (left == true), and if the column to the left of + // the first first non-blank character (col) in the line is + // already to the left of the first tabstop, set the shift amount + // (tab_size) to just enough to shift the line to the left margin. + // The value doesn't seem to matter as long as it is at least that + // distance. + if (left && (t == 1)) { + tab_size = col; + } else { + tab_size = vts[t - (left ? 1 : 0)]; + } break; } } - if (t > tabcount) { + if (t > tabcount) { // If the value of the index t is beyond the + // end of the list, use the tab stop value at + // the end of the list. tab_size = vts[tabcount]; } @@ -312,35 +329,35 @@ int tabstop_first(colnr_T *ts) /// 'tabstop' value when 'shiftwidth' is zero. int get_sw_value(buf_T *buf) { - int result = get_sw_value_col(buf, 0); + int result = get_sw_value_col(buf, 0, false); return result; } /// Idem, using "pos". -int get_sw_value_pos(buf_T *buf, pos_T *pos) +int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left) { pos_T save_cursor = curwin->w_cursor; curwin->w_cursor = *pos; - int sw_value = get_sw_value_col(buf, get_nolist_virtcol()); + int sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left); curwin->w_cursor = save_cursor; return sw_value; } /// Idem, using the first non-black in the current line. -int get_sw_value_indent(buf_T *buf) +int get_sw_value_indent(buf_T *buf, bool left) { pos_T pos = curwin->w_cursor; pos.col = (colnr_T)getwhitecols_curline(); - return get_sw_value_pos(buf, &pos); + return get_sw_value_pos(buf, &pos, left); } /// Idem, using virtual column "col". -int get_sw_value_col(buf_T *buf, colnr_T col) +int get_sw_value_col(buf_T *buf, colnr_T col, bool left) { return buf->b_p_sw ? (int)buf->b_p_sw - : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array); + : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left); } /// Return the effective softtabstop value for the current buffer, diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 47d302df43..8ae1d70882 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -282,7 +282,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) /// @param call_changed_bytes call changed_bytes() void shift_line(bool left, bool round, int amount, int call_changed_bytes) { - const int sw_val = get_sw_value_indent(curbuf); + const int sw_val = get_sw_value_indent(curbuf, left); int count = get_indent(); // get current indent @@ -328,7 +328,7 @@ static void shift_block(oparg_T *oap, int amount) const int oldstate = State; char *newp; const int oldcol = curwin->w_cursor.col; - const int sw_val = get_sw_value_indent(curbuf); + const int sw_val = get_sw_value_indent(curbuf, left); const int ts_val = (int)curbuf->b_p_ts; struct block_def bd; int incr; -- cgit From 4374ec83cd49d148fc788bdb43f49d4b0365cf9f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 14:58:12 +0800 Subject: vim-patch:8.2.0083: text properties wrong when tabs and spaces are exchanged Problem: Text properties wrong when tabs and spaces are exchanged. Solution: Take text properties into account. (Nobuhiro Takasaki, closes vim/vim#5427) https://github.com/vim/vim/commit/5cb0b93d52fa5c12ca50a18509947ee6459bb7a8 Co-authored-by: Bram Moolenaar --- src/nvim/edit.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 595b4da589..436d43a4db 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4421,18 +4421,21 @@ static bool ins_tab(void) // Delete following spaces. int i = cursor->col - fpos.col; if (i > 0) { - STRMOVE(ptr, ptr + i); + if (!(State & VREPLACE_FLAG)) { + memmove(ptr, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - i + - (ptr - curbuf->b_ml.ml_line_ptr))); + curbuf->b_ml.ml_line_len -= i; + inserted_bytes(fpos.lnum, change_col, + cursor->col - change_col, fpos.col - change_col); + } else { + STRMOVE(ptr, ptr + i); + } // correct replace stack. if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { for (temp = i; --temp >= 0;) { replace_join(repl_off); } } - if (!(State & VREPLACE_FLAG)) { - curbuf->b_ml.ml_line_len -= i; - inserted_bytes(fpos.lnum, change_col, - cursor->col - change_col, fpos.col - change_col); - } } cursor->col -= i; -- cgit From 97d9d71bf3ccc156b94acf988f6b2f60fb706fc9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 15:00:16 +0800 Subject: vim-patch:8.2.0109: corrupted text properties when expanding spaces Problem: Corrupted text properties when expanding spaces. Solution: Reallocate the line. (Nobuhiro Takasaki, closes vim/vim#5457) https://github.com/vim/vim/commit/ac15fd8c6761763c8feedef1a2fbd8309f0a823c Co-authored-by: Bram Moolenaar --- src/nvim/edit.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 436d43a4db..f6e2dbfa4e 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4422,9 +4422,18 @@ static bool ins_tab(void) int i = cursor->col - fpos.col; if (i > 0) { if (!(State & VREPLACE_FLAG)) { - memmove(ptr, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - i - - (ptr - curbuf->b_ml.ml_line_ptr))); + char *newp = xmalloc((size_t)(curbuf->b_ml.ml_line_len - i)); + ptrdiff_t col = ptr - curbuf->b_ml.ml_line_ptr; + if (col > 0) { + memmove(newp, ptr - col, (size_t)col); + } + memmove(newp + col, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - col - i)); + if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) { + xfree(curbuf->b_ml.ml_line_ptr); + } + curbuf->b_ml.ml_line_ptr = newp; curbuf->b_ml.ml_line_len -= i; + curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; inserted_bytes(fpos.lnum, change_col, cursor->col - change_col, fpos.col - change_col); } else { -- cgit From 0c9f7f5f96d6fedd2c5d9ec235c8b341f47c06f8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 3 Jun 2024 05:35:02 +0800 Subject: vim-patch:9.1.0458: Coverity complains about division by zero (#29149) Problem: Coverity complains about division by zero Solution: Check explicitly for sw_val being zero Shouldn't happen, since tabstop value should always be larger than zero. So just add this as a safety measure. https://github.com/vim/vim/commit/7737ce519b9cba8ef135154d76b69f715b1a0b4d Co-authored-by: Christian Brabandt --- src/nvim/ops.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 8ae1d70882..74c6e83495 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -282,8 +282,10 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) /// @param call_changed_bytes call changed_bytes() void shift_line(bool left, bool round, int amount, int call_changed_bytes) { - const int sw_val = get_sw_value_indent(curbuf, left); - + int sw_val = get_sw_value_indent(curbuf, left); + if (sw_val == 0) { + sw_val = 1; // shouldn't happen, just in case + } int count = get_indent(); // get current indent if (round) { // round off indent -- cgit From 3a1515bfee59710b4da9bfdf0fc4ecb5b13a00db Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 3 Jun 2024 05:38:06 +0800 Subject: vim-patch:partial:9.1.0461: too many strlen() calls in drawline.c (#29150) Problem: too many strlen() calls in drawline.c Solution: Refactor code to avoid strlen() (John Marriott) closes: vim/vim#14890 https://github.com/vim/vim/commit/f51ff96532ab8f97f779b44d17dccdda9d8ce566 Co-authored-by: John Marriott --- src/nvim/drawline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 3bd00ee3f9..4247705896 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1422,7 +1422,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s line = ml_get_buf(wp->w_buffer, lnum); ptr = line + linecol; - if (len == 0 || (int)wp->w_cursor.col > ptr - line) { + if (len == 0 || wp->w_cursor.col > linecol) { // no bad word found at line start, don't check until end of a // word spell_hlf = HLF_COUNT; -- cgit From 2f5b8a009280eba995aecf67d1e8d99b7c72c51c Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 4 Jun 2024 09:39:28 +0200 Subject: vim-patch:9.1.0464: no whitespace padding in commentstring option in ftplugins Problem: no whitespace padding in commentstring option in ftplugins Solution: Change default to include whitespace padding, update existing filetype plugins with the new default value (Riley Bruins) closes: vim/vim#14843 https://github.com/vim/vim/commit/0a0830624a260660c7fa692ecb7e6e5de09114ba Co-authored-by: Riley Bruins --- src/nvim/options.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 0f3cf6c5b4..0ec17088bb 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1324,8 +1324,8 @@ return { defaults = { if_true = '' }, desc = [=[ A template for a comment. The "%s" in the value is replaced with the - comment text. For example, C uses "/*%s*/". Used for |commenting| and to - add markers for folding, see |fold-marker|. + comment text, and should be padded with a space when possible. + Used for |commenting| and to add markers for folding, see |fold-marker|. ]=], full_name = 'commentstring', redraw = { 'curswant' }, -- cgit From a18982cb839d7f05e32b1026bbd99b8aa34ad189 Mon Sep 17 00:00:00 2001 From: James Tirta Halim Date: Mon, 3 Jun 2024 11:00:20 +0700 Subject: refactor: replace '\0' with NUL --- src/nvim/base64.c | 3 ++- src/nvim/buffer.c | 2 +- src/nvim/charset.c | 4 ++-- src/nvim/cmdexpand.c | 2 +- src/nvim/eval.c | 2 +- src/nvim/ex_docmd.c | 2 +- src/nvim/file_search.c | 2 +- src/nvim/fileio.c | 4 ++-- src/nvim/help.c | 4 ++-- src/nvim/highlight_group.c | 4 ++-- src/nvim/linematch.c | 3 ++- src/nvim/log.c | 10 +++++----- src/nvim/mbyte.c | 4 ++-- src/nvim/memory.c | 16 ++++++++-------- src/nvim/message.c | 2 +- src/nvim/ops.c | 2 +- src/nvim/quickfix.c | 2 +- src/nvim/regexp.c | 4 ++-- src/nvim/sha256.c | 5 +++-- src/nvim/sign.c | 16 ++++++++-------- src/nvim/strings.c | 26 +++++++++++++------------- src/nvim/terminal.c | 2 +- src/nvim/usercmd.c | 6 +++--- 23 files changed, 65 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/nvim/base64.c b/src/nvim/base64.c index a645c64fe3..39e4ec4872 100644 --- a/src/nvim/base64.c +++ b/src/nvim/base64.c @@ -4,6 +4,7 @@ #include #include "auto/config.h" // IWYU pragma: keep +#include "nvim/ascii_defs.h" #include "nvim/base64.h" #include "nvim/memory.h" @@ -125,7 +126,7 @@ char *base64_encode(const char *src, size_t src_len) dest[out_i] = '='; } - dest[out_len] = '\0'; + dest[out_len] = NUL; return dest; } diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 5d0cd66133..c0fbc36787 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4208,7 +4208,7 @@ int buf_open_scratch(handle_T bufnr, char *bufname) bool buf_is_empty(buf_T *buf) { - return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == '\0'; + return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == NUL; } /// Increment b:changedtick value diff --git a/src/nvim/charset.c b/src/nvim/charset.c index c611d4cfd6..430f6b15fe 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1470,7 +1470,7 @@ start: *dst++ = *p++; } } - *dst = '\0'; + *dst = NUL; } } @@ -1492,6 +1492,6 @@ char *backslash_halve_save(const char *p) *dst++ = *p++; } } - *dst = '\0'; + *dst = NUL; return res; } diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index bb85620ce6..0b88e2be11 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -3075,7 +3075,7 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T typval_T args[4]; const sctx_T save_current_sctx = current_sctx; - if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) { + if (xp->xp_arg == NULL || xp->xp_arg[0] == NUL || xp->xp_line == NULL) { return NULL; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a8778b9489..a4680b62ab 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8910,7 +8910,7 @@ bool eval_has_provider(const char *feat, bool throw_if_fast) char name[32]; // Normalized: "python3_compiled" => "python3". snprintf(name, sizeof(name), "%s", feat); - strchrsub(name, '_', '\0'); // Chop any "_xx" suffix. + strchrsub(name, '_', NUL); // Chop any "_xx" suffix. char buf[256]; typval_T tv; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 028ee8f6ae..2f54aa511b 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4118,7 +4118,7 @@ static char *getargcmd(char **argp) if (*arg == '+') { // +[command] arg++; - if (ascii_isspace(*arg) || *arg == '\0') { + if (ascii_isspace(*arg) || *arg == NUL) { command = dollar_command; } else { command = arg; diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index a8b0dbddee..51bea3111c 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -510,7 +510,7 @@ char *vim_findfile_stopdir(char *buf) while (*r_ptr != NUL && *r_ptr != ';') { if (r_ptr[0] == '\\' && r_ptr[1] == ';') { // Overwrite the escape char, - // use strlen(r_ptr) to move the trailing '\0'. + // use strlen(r_ptr) to move the trailing NUL. STRMOVE(r_ptr, r_ptr + 1); r_ptr++; } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 05c9114554..3078f00fbb 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2419,7 +2419,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) // the file name has at most BASENAMELEN characters. if (strlen(ptr) > BASENAMELEN) { - ptr[BASENAMELEN] = '\0'; + ptr[BASENAMELEN] = NUL; } char *s = ptr + strlen(ptr); @@ -3330,7 +3330,7 @@ static void vim_mktempdir(void) #endif // If our "root" tempdir is invalid or fails, proceed without "/". // Else user1 could break user2 by creating "/tmp/nvim.user2/". - tmp[strlen(tmp) - strlen(user)] = '\0'; + tmp[strlen(tmp) - strlen(user)] = NUL; } // Now try to create "/tmp/nvim./XXXXXX". diff --git a/src/nvim/help.c b/src/nvim/help.c index d28f195c00..0da846bb9f 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -958,8 +958,8 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool if (s == p2 && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t') && (vim_strchr(" \t\n\r", (uint8_t)s[1]) != NULL - || s[1] == '\0')) { - *p2 = '\0'; + || s[1] == NUL)) { + *p2 = NUL; p1++; size_t s_len = (size_t)(p2 - p1) + strlen(fname) + 2; s = xmalloc(s_len); diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index b5e62e7f31..c32e1f9657 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1174,7 +1174,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) break; } vim_memcpy_up(key, key_start, key_len); - key[key_len] = '\0'; + key[key_len] = NUL; linep = skipwhite(linep); if (strcmp(key, "NONE") == 0) { @@ -1967,7 +1967,7 @@ int syn_name2id_len(const char *name, size_t len) // Avoid using stricmp() too much, it's slow on some systems // Avoid alloc()/free(), these are slow too. vim_memcpy_up(name_u, name, len); - name_u[len] = '\0'; + name_u[len] = NUL; // map_get(..., int) returns 0 when no key is present, which is // the expected value for missing highlight group. diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c index c34b303193..24b2c82381 100644 --- a/src/nvim/linematch.c +++ b/src/nvim/linematch.c @@ -5,6 +5,7 @@ #include #include +#include "nvim/ascii_defs.h" #include "nvim/linematch.h" #include "nvim/macros_defs.h" #include "nvim/memory.h" @@ -61,7 +62,7 @@ static int matching_chars_iwhite(const char *s1, const char *s2) d++; } } - strsproc[k][i] = '\0'; + strsproc[k][i] = NUL; } int matching = matching_chars(strsproc[0], strsproc[1]); xfree(strsproc[0]); diff --git a/src/nvim/log.c b/src/nvim/log.c index fbb3e0385a..774f1c956d 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -46,7 +46,7 @@ static uv_mutex_t mutex; static bool log_try_create(char *fname) { - if (fname == NULL || fname[0] == '\0') { + if (fname == NULL || fname[0] == NUL) { return false; } FILE *log_file = fopen(fname, "a"); @@ -67,7 +67,7 @@ static void log_path_init(void) size_t size = sizeof(log_file_path); expand_env("$" ENV_LOGFILE, log_file_path, (int)size - 1); if (strequal("$" ENV_LOGFILE, log_file_path) - || log_file_path[0] == '\0' + || log_file_path[0] == NUL || os_isdir(log_file_path) || !log_try_create(log_file_path)) { // Make $XDG_STATE_HOME if it does not exist. @@ -88,7 +88,7 @@ static void log_path_init(void) } // Fall back to stderr if (len >= size || !log_try_create(log_file_path)) { - log_file_path[0] = '\0'; + log_file_path[0] = NUL; return; } os_setenv(ENV_LOGFILE, log_file_path, true); @@ -324,7 +324,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context, // Get a name for this Nvim instance. // TODO(justinmk): expose this as v:name ? - if (name[0] == '\0') { + if (name[0] == NUL) { // Parent servername. const char *parent = path_tail(os_getenv(ENV_NVIM)); // Servername. Empty until starting=false. @@ -350,7 +350,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context, func_name, line_num); if (name[0] == '?') { // No v:servername yet. Clear `name` so that the next log can try again. - name[0] = '\0'; + name[0] = NUL; } if (rv < 0) { diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 23fdd5eb16..07c0c846ed 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1500,7 +1500,7 @@ int utf8_to_utf16(const char *utf8, int utf8len, wchar_t **utf16) return uv_translate_sys_error(GetLastError()); } - (*utf16)[bufsize] = L'\0'; + (*utf16)[bufsize] = LNUL; return 0; } @@ -1546,7 +1546,7 @@ int utf16_to_utf8(const wchar_t *utf16, int utf16len, char **utf8) return uv_translate_sys_error(GetLastError()); } - (*utf8)[bufsize] = '\0'; + (*utf8)[bufsize] = NUL; return 0; } diff --git a/src/nvim/memory.c b/src/nvim/memory.c index c4774d68f3..50860c69d0 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -203,7 +203,7 @@ void *xmallocz(size_t size) } void *ret = xmalloc(total_size); - ((char *)ret)[size] = '\0'; + ((char *)ret)[size] = NUL; return ret; } @@ -233,7 +233,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { memcpy(dst, src, len); - ((char *)dst)[len] = '\0'; + ((char *)dst)[len] = NUL; return dst; } @@ -241,7 +241,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len) size_t xstrnlen(const char *s, size_t n) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE { - const char *end = memchr(s, '\0', n); + const char *end = memchr(s, NUL, n); if (end == NULL) { return n; } @@ -288,7 +288,7 @@ void *xmemscan(const void *addr, char c, size_t size) void strchrsub(char *str, char c, char x) FUNC_ATTR_NONNULL_ALL { - assert(c != '\0'); + assert(c != NUL); while ((str = strchr(str, c))) { *str++ = x; } @@ -388,7 +388,7 @@ char *xstpcpy(char *restrict dst, const char *restrict src) char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen) FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - const char *p = memchr(src, '\0', maxlen); + const char *p = memchr(src, NUL, maxlen); if (p) { size_t srclen = (size_t)(p - src); memcpy(dst, src, srclen); @@ -420,7 +420,7 @@ size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize) if (dsize) { size_t len = MIN(slen, dsize - 1); memcpy(dst, src, len); - dst[len] = '\0'; + dst[len] = NUL; } return slen; // Does not include NUL. @@ -450,7 +450,7 @@ size_t xstrlcat(char *const dst, const char *const src, const size_t dsize) if (slen > dsize - dlen - 1) { memmove(dst + dlen, src, dsize - dlen - 1); - dst[dsize - 1] = '\0'; + dst[dsize - 1] = NUL; } else { memmove(dst + dlen, src, slen + 1); } @@ -510,7 +510,7 @@ char *xstrndup(const char *str, size_t len) FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL { - char *p = memchr(str, '\0', len); + char *p = memchr(str, NUL, len); return xmemdupz(str, p ? (size_t)(p - str) : len); } diff --git a/src/nvim/message.c b/src/nvim/message.c index 9941dcb254..73712489ad 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2690,7 +2690,7 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen) *p++ = '\r'; } memcpy(p, s, (size_t)len); - *(p + len) = '\0'; + *(p + len) = NUL; if (info_message) { printf("%s", buf); } else { diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 74c6e83495..1448896146 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4725,7 +4725,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0'; } - buf2[i] = '\0'; + buf2[i] = NUL; } else if (pre == 0) { vim_snprintf(buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n); } else if (pre == '0') { diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index e1d35ab9d5..be2f41da14 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -724,7 +724,7 @@ static int qf_get_next_str_line(qfstate_T *state) state->linelen = len; } memcpy(state->linebuf, p_str, state->linelen); - state->linebuf[state->linelen] = '\0'; + state->linebuf[state->linelen] = NUL; // Increment using len in order to discard the rest of the line if it // exceeds LINE_MAXLEN. diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index b743664b69..2ff4dbee70 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -11495,7 +11495,7 @@ static void nfa_print_state(FILE *debugf, nfa_state_T *state) garray_T indent; ga_init(&indent, 1, 64); - ga_append(&indent, '\0'); + ga_append(&indent, NUL); nfa_print_state2(debugf, state, &indent); ga_clear(&indent); } @@ -14801,7 +14801,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } case NFA_ANY: - // Any char except '\0', (end of input) does not match. + // Any char except NUL, (end of input) does not match. if (curc > 0) { add_state = t->state->out; add_off = clen; diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c index d49224a987..5e0aac3f69 100644 --- a/src/nvim/sha256.c +++ b/src/nvim/sha256.c @@ -15,6 +15,7 @@ #include #include +#include "nvim/ascii_defs.h" #include "nvim/memory.h" #include "nvim/sha256.h" @@ -279,7 +280,7 @@ const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len, const uin for (size_t j = 0; j < SHA256_SUM_SIZE; j++) { snprintf(hexit + j * SHA_STEP, SHA_STEP + 1, "%02x", sha256sum[j]); } - hexit[sizeof(hexit) - 1] = '\0'; + hexit[sizeof(hexit) - 1] = NUL; return hexit; } @@ -340,7 +341,7 @@ bool sha256_self_test(void) if (memcmp(output, sha_self_test_vector[i], SHA256_BUFFER_SIZE) != 0) { failures = true; - output[sizeof(output) - 1] = '\0'; + output[sizeof(output) - 1] = NUL; // printf("sha256_self_test %d failed %s\n", i, output); } diff --git a/src/nvim/sign.c b/src/nvim/sign.c index be207f58b0..496913f9bf 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -292,8 +292,8 @@ static void sign_list_placed(buf_T *rbuf, char *group) qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_row_cmp); for (size_t i = 0; i < kv_size(signs); i++) { - namebuf[0] = '\0'; - groupbuf[0] = '\0'; + namebuf[0] = NUL; + groupbuf[0] = NUL; MTKey mark = kv_A(signs, i); DecorSignHighlight *sh = decor_find_sign(mt_decor(mark)); @@ -498,7 +498,7 @@ static void sign_list_by_name(char *name) static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_T lnum, int prio) { // Check for reserved character '*' in group name - if (group != NULL && (*group == '*' || *group == '\0')) { + if (group != NULL && (*group == '*' || *group == NUL)) { return FAIL; } @@ -649,14 +649,14 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char * // :sign place // :sign place group={group} // :sign place group=* - if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) { + if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) { emsg(_(e_invarg)); } else { sign_list_placed(buf, group); } } else { // Place a new sign - if (name == NULL || buf == NULL || (group != NULL && *group == '\0')) { + if (name == NULL || buf == NULL || (group != NULL && *group == NUL)) { emsg(_(e_invarg)); return; } @@ -668,7 +668,7 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char * /// ":sign unplace" command static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, char *group) { - if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) { + if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) { emsg(_(e_invarg)); return; } @@ -695,7 +695,7 @@ static void sign_jump_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, c return; } - if (buf == NULL || (group != NULL && *group == '\0') || lnum >= 0 || name != NULL) { + if (buf == NULL || (group != NULL && *group == NUL) || lnum >= 0 || name != NULL) { // File or buffer is not specified or an empty group is used // or a line number or a sign name is specified. emsg(_(e_invarg)); @@ -1316,7 +1316,7 @@ void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (group == NULL) { return; } - if (*group == '\0') { // empty string means global group + if (*group == NUL) { // empty string means global group group = NULL; } } diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 329b66cea1..bf7af40a38 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -333,7 +333,7 @@ void vim_strcpy_up(char *restrict dst, const char *restrict src) while ((c = (uint8_t)(*src++)) != NUL) { *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); } - *dst = '\0'; + *dst = NUL; } // strncpy (NUL-terminated) plus vim_strup. @@ -344,7 +344,7 @@ void vim_strncpy_up(char *restrict dst, const char *restrict src, size_t n) while (n-- && (c = (uint8_t)(*src++)) != NUL) { *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); } - *dst = '\0'; + *dst = NUL; } // memcpy (does not NUL-terminate) plus vim_strup. @@ -794,10 +794,10 @@ static int format_typeof(const char *type) FUNC_ATTR_NONNULL_ALL { // allowed values: \0, h, l, L - char length_modifier = '\0'; + char length_modifier = NUL; // current conversion specifier character - char fmt_spec = '\0'; + char fmt_spec = NUL; // parse 'h', 'l', 'll' and 'z' length modifiers if (*type == 'h' || *type == 'l' || *type == 'z') { @@ -865,7 +865,7 @@ static int format_typeof(const char *type) } else if (fmt_spec == 'd') { // signed switch (length_modifier) { - case '\0': + case NUL: case 'h': // char and short arguments are passed as int. return TYPE_INT; @@ -879,7 +879,7 @@ static int format_typeof(const char *type) } else { // unsigned switch (length_modifier) { - case '\0': + case NUL: case 'h': return TYPE_UNSIGNEDINT; case 'l': @@ -1050,7 +1050,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * p += n; } else { // allowed values: \0, h, l, L - char length_modifier = '\0'; + char length_modifier = NUL; // variable for positional arg int pos_arg = -1; @@ -1441,7 +1441,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st int space_for_positive = 1; // allowed values: \0, h, l, 2 (for ll), z, L - char length_modifier = '\0'; + char length_modifier = NUL; // temporary buffer for simple numeric->string conversion #define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable @@ -1466,7 +1466,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st size_t zero_padding_insertion_ind = 0; // current conversion specifier character - char fmt_spec = '\0'; + char fmt_spec = NUL; // buffer for 's' and 'S' specs char *tofree = NULL; @@ -1669,7 +1669,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st case 'o': case 'x': case 'X': - if (tvs && length_modifier == '\0') { + if (tvs && length_modifier == NUL) { length_modifier = 'L'; } } @@ -1790,7 +1790,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st } else if (fmt_spec == 'd') { // signed switch (length_modifier) { - case '\0': + case NUL: arg = (tvs ? (int)tv_nr(tvs, &arg_idx) : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, @@ -1836,7 +1836,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st } else { // unsigned switch (length_modifier) { - case '\0': + case NUL: uarg = (tvs ? (unsigned)tv_nr(tvs, &arg_idx) : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, @@ -2223,7 +2223,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (str_m > 0) { // make sure the string is nul-terminated even at the expense of // overwriting the last character (shouldn't happen, but just in case) - str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0'; + str[str_l <= str_m - 1 ? str_l : str_m - 1] = NUL; } if (tvs != NULL diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 2b05a8047e..2738eb874d 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -845,7 +845,7 @@ void terminal_paste(int count, char **y_array, size_t y_size) } char *dst = buff; char *src = y_array[j]; - while (*src != '\0') { + while (*src != NUL) { len = (size_t)utf_ptr2len(src); int c = utf_ptr2char(src); if (!is_filter_char(c)) { diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index e3d9dc5f54..79f897f020 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -580,7 +580,7 @@ static void uc_list(char *name, size_t name_len) IObuff[len++] = ' '; } while ((int64_t)len < 25 - over); - IObuff[len] = '\0'; + IObuff[len] = NUL; msg_outtrans(IObuff, 0); if (cmd->uc_luaref != LUA_NOREF) { @@ -831,7 +831,7 @@ invalid_count: } } else { char ch = attr[len]; - attr[len] = '\0'; + attr[len] = NUL; semsg(_("E181: Invalid attribute: %s"), attr); attr[len] = ch; return FAIL; @@ -1364,7 +1364,7 @@ size_t uc_mods(char *buf, const cmdmod_T *cmod, bool quote) if (quote) { *buf++ = '"'; } - *buf = '\0'; + *buf = NUL; } // the modifiers that are simple flags -- cgit From 4b3845be2e497f96f855782d52dd1d02a4cabb6f Mon Sep 17 00:00:00 2001 From: James Tirta Halim Date: Mon, 3 Jun 2024 11:04:54 +0700 Subject: fixup: LNUL --- src/nvim/mbyte.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 07c0c846ed..7975f351ee 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1500,7 +1500,7 @@ int utf8_to_utf16(const char *utf8, int utf8len, wchar_t **utf16) return uv_translate_sys_error(GetLastError()); } - (*utf16)[bufsize] = LNUL; + (*utf16)[bufsize] = L'\0'; return 0; } -- cgit From 200e7ad1578619e78c664bd0c6be024168433412 Mon Sep 17 00:00:00 2001 From: James Tirta Halim Date: Mon, 3 Jun 2024 11:10:30 +0700 Subject: fixup: apply the change on more files --- src/nvim/api/buffer.c | 6 +++--- src/nvim/api/command.c | 4 ++-- src/nvim/api/private/validate.c | 2 +- src/nvim/api/vimscript.c | 2 +- src/nvim/eval/encode.c | 6 +++--- src/nvim/eval/funcs.c | 6 +++--- src/nvim/eval/typval.c | 2 +- src/nvim/eval/window.c | 2 +- src/nvim/event/socket.c | 2 +- src/nvim/lua/secure.c | 4 ++-- src/nvim/lua/treesitter.c | 2 +- src/nvim/msgpack_rpc/server.c | 2 +- src/nvim/os/env.c | 28 ++++++++++++++-------------- src/nvim/os/fs.c | 6 +++--- src/nvim/os/pty_process_win.c | 2 +- src/nvim/os/shell.c | 8 ++++---- src/nvim/os/stdpaths.c | 2 +- src/nvim/tui/terminfo.c | 2 +- src/nvim/tui/tui.c | 2 +- 19 files changed, 45 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 7e64808709..e078d85f33 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1375,7 +1375,7 @@ static inline void init_line_array(lua_State *lstate, Array *a, size_t size, Are /// @param s String to push /// @param len Size of string /// @param idx 0-based index to place s (only used for Lua) -/// @param replace_nl Replace newlines ('\n') with null ('\0') +/// @param replace_nl Replace newlines ('\n') with null (NUL) static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, int idx, bool replace_nl, Arena *arena) { @@ -1384,7 +1384,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, if (s && replace_nl && strchr(s, '\n')) { // TODO(bfredl): could manage scratch space in the arena, for the NUL case char *tmp = xmemdupz(s, len); - strchrsub(tmp, '\n', '\0'); + strchrsub(tmp, '\n', NUL); lua_pushlstring(lstate, tmp, len); xfree(tmp); } else { @@ -1397,7 +1397,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, str = CBUF_TO_ARENA_STR(arena, s, len); if (replace_nl) { // Vim represents NULs as NLs, but this may confuse clients. - strchrsub(str.data, '\n', '\0'); + strchrsub(str.data, '\n', NUL); } } diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 779e216c74..5ad439af9c 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -193,7 +193,7 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err } else { nargs[0] = '0'; } - nargs[1] = '\0'; + nargs[1] = NUL; PUT_KEY(result, cmd, nargs, CSTR_TO_ARENA_OBJ(arena, nargs)); char *addr; @@ -391,7 +391,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena case kObjectTypeBoolean: data_str = arena_alloc(arena, 2, false); data_str[0] = elem.data.boolean ? '1' : '0'; - data_str[1] = '\0'; + data_str[1] = NUL; ADD_C(args, CSTR_AS_OBJ(data_str)); break; case kObjectTypeBuffer: diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c index e198c671eb..9fd7d3bfa6 100644 --- a/src/nvim/api/private/validate.c +++ b/src/nvim/api/private/validate.c @@ -17,7 +17,7 @@ void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t va char *has_space = strchr(name, ' '); // No value. - if (val_s && val_s[0] == '\0') { + if (val_s && val_s[0] == NUL) { api_set_error(err, errtype, has_space ? "Invalid %s" : "Invalid '%s'", name); return; } diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 477cbe2428..124c26d175 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -109,7 +109,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error * // redir usually (except :echon) prepends a newline. if (s.data[0] == '\n') { memmove(s.data, s.data + 1, s.size - 1); - s.data[s.size - 1] = '\0'; + s.data[s.size - 1] = NUL; s.size = s.size - 1; } return s; // Caller will free the memory. diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index d35ac4eb7b..e216dbdaa6 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -855,7 +855,7 @@ char *encode_tv2string(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } @@ -883,7 +883,7 @@ char *encode_tv2echo(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } @@ -908,7 +908,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e704135366..666d46cdad 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4318,7 +4318,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en // Set $NVIM (in the child process) to v:servername. #3118 char *nvim_addr = get_vim_var_str(VV_SEND_SERVER); - if (nvim_addr[0] != '\0') { + if (nvim_addr[0] != NUL) { dictitem_T *dv = tv_dict_find(env, S_LEN("NVIM")); if (dv) { tv_dict_item_remove(env, dv); @@ -9174,13 +9174,13 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true); // Trim slash. if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) { - IObuff[len - 1] = '\0'; + IObuff[len - 1] = NUL; } if (len == 1 && IObuff[0] == '/') { // Avoid ambiguity in the URI when CWD is root directory. IObuff[1] = '.'; - IObuff[2] = '\0'; + IObuff[2] = NUL; } // Terminal URI: "term://$CWD//$PID:$CMD" diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 1ea1fe46d2..13b31ab30f 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1824,7 +1824,7 @@ char *callback_to_string(Callback *cb, Arena *arena) snprintf(msg, msglen, "", cb->data.partial->pt_name); break; default: - *msg = '\0'; + *msg = NUL; break; } return msg; diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index d7485c12a3..86495f1cb6 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -272,7 +272,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar) // if count is not specified, default to 1 count = 1; } - if (endp != NULL && *endp != '\0') { + if (endp != NULL && *endp != NUL) { if (strequal(endp, "j")) { twin = win_vert_neighbor(tp, twin, false, count); } else if (strequal(endp, "k")) { diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c index 017f159fa1..1214c3e336 100644 --- a/src/nvim/event/socket.c +++ b/src/nvim/event/socket.c @@ -35,7 +35,7 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint if (host_end && addr != host_end) { // Split user specified address into two strings, addr(hostname) and port. // The port part in watcher->addr will be updated later. - *host_end = '\0'; + *host_end = NUL; char *port = host_end + 1; intmax_t iport; diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c index a84d6c4d65..61277949c4 100644 --- a/src/nvim/lua/secure.c +++ b/src/nvim/lua/secure.c @@ -104,12 +104,12 @@ void ex_trust(exarg_T *eap) action = "deny"; } else if (strcmp(arg1, "++remove") == 0) { action = "remove"; - } else if (*arg1 != '\0') { + } else if (*arg1 != NUL) { semsg(e_invarg2, arg1); goto theend; } - if (path[0] == '\0') { + if (path[0] == NUL) { path = NULL; } diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index e87cf756a8..b13a162074 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -279,7 +279,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position memcpy(buf, line + position.column, tocopy); // Translate embedded \n to NUL - memchrsub(buf, '\n', '\0', tocopy); + memchrsub(buf, '\n', NUL, tocopy); *bytes_read = (uint32_t)tocopy; if (tocopy < BUFSIZE) { // now add the final \n. If it didn't fit, input_cb will be called again diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index 56b03d67d0..341f638a55 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -131,7 +131,7 @@ bool server_owns_pipe_address(const char *path) /// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen. int server_start(const char *addr) { - if (addr == NULL || addr[0] == '\0') { + if (addr == NULL || addr[0] == NUL) { WLOG("Empty or NULL address"); return 1; } diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 5a79004c41..4689414559 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -63,13 +63,13 @@ const char *os_getenv(const char *name) FUNC_ATTR_NONNULL_ALL { char *e = NULL; - if (name[0] == '\0') { + if (name[0] == NUL) { return NULL; } int r = 0; if (map_has(cstr_t, &envmap, name) && !!(e = (char *)pmap_get(cstr_t)(&envmap, name))) { - if (e[0] != '\0') { + if (e[0] != NUL) { // Found non-empty cached env var. // NOTE: This risks incoherence if an in-process library changes the // environment without going through our os_setenv() wrapper. If @@ -85,11 +85,11 @@ const char *os_getenv(const char *name) if (r == UV_ENOBUFS) { e = xmalloc(size); r = uv_os_getenv(name, e, &size); - if (r != 0 || size == 0 || e[0] == '\0') { + if (r != 0 || size == 0 || e[0] == NUL) { XFREE_CLEAR(e); goto end; } - } else if (r != 0 || size == 0 || buf[0] == '\0') { + } else if (r != 0 || size == 0 || buf[0] == NUL) { e = NULL; goto end; } else { @@ -110,7 +110,7 @@ end: bool os_env_exists(const char *name) FUNC_ATTR_NONNULL_ALL { - if (name[0] == '\0') { + if (name[0] == NUL) { return false; } // Use a tiny buffer because we don't care about the value: if uv_os_getenv() @@ -134,14 +134,14 @@ bool os_env_exists(const char *name) int os_setenv(const char *name, const char *value, int overwrite) FUNC_ATTR_NONNULL_ALL { - if (name[0] == '\0') { + if (name[0] == NUL) { return -1; } #ifdef MSWIN if (!overwrite && os_getenv(name) != NULL) { return 0; } - if (value[0] == '\0') { + if (value[0] == NUL) { // Windows (Vim-compat): Empty string undefines the env var. return os_unsetenv(name); } @@ -174,7 +174,7 @@ int os_setenv(const char *name, const char *value, int overwrite) int os_unsetenv(const char *name) FUNC_ATTR_NONNULL_ALL { - if (name[0] == '\0') { + if (name[0] == NUL) { return -1; } pmap_del2(&envmap, name); @@ -366,7 +366,7 @@ void os_get_hostname(char *hostname, size_t size) struct utsname vutsname; if (uname(&vutsname) < 0) { - *hostname = '\0'; + *hostname = NUL; } else { xstrlcpy(hostname, vutsname.nodename, size); } @@ -374,12 +374,12 @@ void os_get_hostname(char *hostname, size_t size) wchar_t host_utf16[MAX_COMPUTERNAME_LENGTH + 1]; DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]); if (GetComputerNameW(host_utf16, &host_wsize) == 0) { - *hostname = '\0'; + *hostname = NUL; DWORD err = GetLastError(); semsg("GetComputerNameW failed: %d", err); return; } - host_utf16[host_wsize] = '\0'; + host_utf16[host_wsize] = NUL; char *host_utf8; int conversion_result = utf16_to_utf8(host_utf16, -1, &host_utf8); @@ -391,7 +391,7 @@ void os_get_hostname(char *hostname, size_t size) xfree(host_utf8); #else emsg("os_get_hostname failed: missing uname()"); - *hostname = '\0'; + *hostname = NUL; #endif } @@ -885,9 +885,9 @@ void vim_get_prefix_from_exepath(char *exe_name) // but c_grammar.lua does not recognize it (yet). xstrlcpy(exe_name, get_vim_var_str(VV_PROGPATH), MAXPATHL * sizeof(*exe_name)); char *path_end = path_tail_with_sep(exe_name); - *path_end = '\0'; // remove the trailing "nvim.exe" + *path_end = NUL; // remove the trailing "nvim.exe" path_end = path_tail(exe_name); - *path_end = '\0'; // remove the trailing "bin/" + *path_end = NUL; // remove the trailing "bin/" } /// Vim getenv() wrapper with special handling of $HOME, $VIM, $VIMRUNTIME, diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 13e87a1ca5..b681b2f832 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -302,7 +302,7 @@ static bool is_executable_ext(const char *name, char **abspath) char *nameext = strrchr(name, '.'); size_t nameext_len = nameext ? strlen(nameext) : 0; xstrlcpy(os_buf, name, sizeof(os_buf)); - char *buf_end = xstrchrnul(os_buf, '\0'); + char *buf_end = xstrchrnul(os_buf, NUL); const char *pathext = os_getenv("PATHEXT"); if (!pathext) { pathext = ".com;.exe;.bat;.cmd"; @@ -310,7 +310,7 @@ static bool is_executable_ext(const char *name, char **abspath) const char *ext = pathext; while (*ext) { // If $PATHEXT itself contains dot: - if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ENV_SEPCHAR)) { + if (ext[0] == '.' && (ext[1] == NUL || ext[1] == ENV_SEPCHAR)) { if (is_executable(name, abspath)) { return true; } @@ -436,7 +436,7 @@ FILE *os_fopen(const char *path, const char *flags) assert(flags != NULL && strlen(flags) > 0 && strlen(flags) <= 2); int iflags = 0; // Per table in fopen(3) manpage. - if (flags[1] == '\0' || flags[1] == 'b') { + if (flags[1] == NUL || flags[1] == 'b') { switch (flags[0]) { case 'r': iflags = O_RDONLY; diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index f73baed490..39c3966c1c 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -399,7 +399,7 @@ static int build_env_block(dict_T *denv, wchar_t **env_block) QUEUE_INSERT_TAIL(&env_q, &env_node->node); } - // Additional '\0' after the final entry + // Additional NUL after the final entry env_block_len++; *env_block = xmalloc(sizeof(**env_block) * env_block_len); diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index d572e9b933..026f14ebc8 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -648,13 +648,13 @@ char *shell_argv_to_str(char **const argv) p++; } if (n < maxsize) { - rv[n - 1] = '\0'; + rv[n - 1] = NUL; } else { // Command too long, show ellipsis: "/bin/bash 'foo' 'bar'..." rv[maxsize - 4] = '.'; rv[maxsize - 3] = '.'; rv[maxsize - 2] = '.'; - rv[maxsize - 1] = '\0'; + rv[maxsize - 1] = NUL; } return rv; } @@ -861,7 +861,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu { out_data_decide_throttle(0); // Initialize throttle decider. out_data_ring(NULL, 0); // Initialize output ring-buffer. - bool has_input = (input != NULL && input[0] != '\0'); + bool has_input = (input != NULL && input[0] != NUL); // the output buffer DynamicBuffer buf = DYNAMIC_BUFFER_INIT; @@ -1024,7 +1024,7 @@ static bool out_data_decide_throttle(size_t size) static uint64_t started = 0; // Start time of the current throttle. static size_t received = 0; // Bytes observed since last throttle. static size_t visit = 0; // "Pulse" count of the current throttle. - static char pulse_msg[] = { ' ', ' ', ' ', '\0' }; + static char pulse_msg[] = { ' ', ' ', ' ', NUL }; if (!size) { bool previous_decision = (visit > 0); diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index e5bdd56fe6..e4435bcaa8 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -69,7 +69,7 @@ static const char *const xdg_defaults[] = { const char *get_appname(void) { const char *env_val = os_getenv("NVIM_APPNAME"); - if (env_val == NULL || *env_val == '\0') { + if (env_val == NULL || *env_val == NUL) { env_val = "nvim"; } return env_val; diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index 3cf9650428..657bd6dd10 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -35,7 +35,7 @@ bool terminfo_is_term_family(const char *term, const char *family) // The screen terminfo may have a terminal name like screen.xterm. By making // the dot(.) a valid separator, such terminal names will also be the // terminal family of the screen. - && ('\0' == term[flen] || '-' == term[flen] || '.' == term[flen]); + && (NUL == term[flen] || '-' == term[flen] || '.' == term[flen]); } bool terminfo_is_bsd_console(const char *term) diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index dc8c8def5b..650133e6a2 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -2508,7 +2508,7 @@ static const char *tui_get_stty_erase(int fd) struct termios t; if (tcgetattr(fd, &t) != -1) { stty_erase[0] = (char)t.c_cc[VERASE]; - stty_erase[1] = '\0'; + stty_erase[1] = NUL; DLOG("stty/termios:erase=%s", stty_erase); } #endif -- cgit From 46b69aaf14a7da2c2ce800aa0eaec5eb019991b4 Mon Sep 17 00:00:00 2001 From: James Tirta Halim Date: Mon, 3 Jun 2024 11:13:55 +0700 Subject: fixup: include nvim/ascii_defs.h --- src/nvim/msgpack_rpc/server.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index 341f638a55..24bd343a34 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -4,6 +4,7 @@ #include #include +#include "nvim/ascii_defs.h" #include "nvim/channel.h" #include "nvim/eval.h" #include "nvim/event/defs.h" -- cgit From ae0d562644ad87607a321e71207f8bc88bae827b Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 4 Jun 2024 09:41:20 +0100 Subject: refactor(spell.c): reduce scope of locals --- src/nvim/spell.c | 168 ++++++++++++++++++++++++------------------------------- 1 file changed, 74 insertions(+), 94 deletions(-) (limited to 'src') diff --git a/src/nvim/spell.c b/src/nvim/spell.c index f6c326075d..39145d73ed 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -231,14 +231,6 @@ char *repl_to = NULL; /// caller can skip over the word. size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount) { - matchinf_T mi; // Most things are put in "mi" so that it can - // be passed to functions quickly. - size_t nrlen = 0; // found a number first - size_t wrongcaplen = 0; - bool count_word = docount; - bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0; - bool is_camel_case = false; - // A word never starts at a space or a control character. Return quickly // then, skipping over the character. if ((uint8_t)(*ptr) <= ' ') { @@ -250,6 +242,13 @@ size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount return 1; } + size_t nrlen = 0; // found a number first + size_t wrongcaplen = 0; + bool count_word = docount; + bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0; + bool is_camel_case = false; + + matchinf_T mi; // Most things are put in "mi" so that it can be passed to functions quickly. CLEAR_FIELD(mi); // A number is always OK. Also skip hexadecimal numbers 0xFF99 and @@ -541,7 +540,6 @@ static void find_word(matchinf_T *mip, int mode) int endlen[MAXWLEN]; // length at possible word endings idx_T endidx[MAXWLEN]; // possible word endings int endidxcnt = 0; - int c; // Repeat advancing in the tree until: // - there is a byte that doesn't match, @@ -583,7 +581,7 @@ static void find_word(matchinf_T *mip, int mode) } // Perform a binary search in the list of accepted bytes. - c = (uint8_t)ptr[wlen]; + int c = (uint8_t)ptr[wlen]; if (c == TAB) { // is handled like c = ' '; } @@ -627,9 +625,6 @@ static void find_word(matchinf_T *mip, int mode) } } - char *p; - bool word_ends; - // Verify that one of the possible endings is valid. Try the longest // first. while (endidxcnt > 0) { @@ -640,6 +635,7 @@ static void find_word(matchinf_T *mip, int mode) if (utf_head_off(ptr, ptr + wlen) > 0) { continue; // not at first byte of character } + bool word_ends; if (spell_iswordp(ptr + wlen, mip->mi_win)) { if (slang->sl_compprog == NULL && !slang->sl_nobreak) { continue; // next char is a word character @@ -656,7 +652,7 @@ static void find_word(matchinf_T *mip, int mode) // Compute byte length in original word, length may change // when folding case. This can be slow, take a shortcut when the // case-folded word is equal to the keep-case word. - p = mip->mi_word; + char *p = mip->mi_word; if (strncmp(ptr, p, (size_t)wlen) != 0) { for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { MB_PTR_ADV(p); @@ -692,10 +688,10 @@ static void find_word(matchinf_T *mip, int mode) // When mode is FIND_PREFIX the word must support the prefix: // check the prefix ID and the condition. Do that for the list at // mip->mi_prefarridx that find_prefix() filled. - c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx, - (int)flags, - mip->mi_word + mip->mi_cprefixlen, slang, - false); + int c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx, + (int)flags, + mip->mi_word + mip->mi_cprefixlen, slang, + false); if (c == 0) { continue; } @@ -766,6 +762,7 @@ static void find_word(matchinf_T *mip, int mode) if (mode == FIND_COMPOUND) { int capflags; + char *p; // Need to check the caps type of the appended compound // word. @@ -852,7 +849,7 @@ static void find_word(matchinf_T *mip, int mode) // byte length in keep-case word. Length may change when // folding case. This can be slow, take a shortcut when // the case-folded word is equal to the keep-case word. - p = mip->mi_fword; + char *p = mip->mi_fword; if (strncmp(ptr, p, (size_t)wlen) != 0) { for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { MB_PTR_ADV(p); @@ -1297,12 +1294,14 @@ static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col) /// @return 0 if not found, length of the badly spelled word otherwise. size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *attrp) { + if (no_spell_checking(wp)) { + return 0; + } + pos_T found_pos; size_t found_len = 0; hlf_T attr = HLF_COUNT; - size_t len; bool has_syntax = syntax_present(wp); - colnr_T col; char *buf = NULL; size_t buflen = 0; int skip = 0; @@ -1310,10 +1309,6 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a bool found_one = false; bool wrapped = false; - if (no_spell_checking(wp)) { - return 0; - } - size_t ret = 0; // Start looking for bad word at the start of the line, because we can't @@ -1343,7 +1338,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a while (!got_int) { char *line = ml_get_buf(wp->w_buffer, lnum); - len = (size_t)ml_get_buf_len(wp->w_buffer, lnum); + size_t len = (size_t)ml_get_buf_len(wp->w_buffer, lnum); if (buflen < len + MAXWLEN + 2) { xfree(buf); buflen = len + MAXWLEN + 2; @@ -1361,7 +1356,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a capcol = (colnr_T)getwhitecols(line); } else if (curline && wp == curwin) { // For spellbadword(): check if first word needs a capital. - col = (colnr_T)getwhitecols(line); + colnr_T col = (colnr_T)getwhitecols(line); if (check_need_cap(curwin, lnum, col)) { capcol = col; } @@ -1410,7 +1405,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a || ((colnr_T)(curline ? p - buf + (ptrdiff_t)len : p - buf) > wp->w_cursor.col)) { - col = (colnr_T)(p - buf); + colnr_T col = (colnr_T)(p - buf); bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0; bool can_spell = !no_plain_buffer; @@ -1817,17 +1812,16 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count) p = buf; } - wordcount_T *wc; hash_T hash = hash_hash(p); const size_t p_len = strlen(p); hashitem_T *hi = hash_lookup(&lp->sl_wordcount, p, p_len, hash); if (HASHITEM_EMPTY(hi)) { - wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1); + wordcount_T *wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1); memcpy(wc->wc_word, p, p_len + 1); wc->wc_count = count; hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash); } else { - wc = HI2WC(hi); + wordcount_T *wc = HI2WC(hi); wc->wc_count = (uint16_t)(wc->wc_count + count); if (wc->wc_count < count) { // check for overflow wc->wc_count = MAXWORDCOUNT; @@ -1883,14 +1877,14 @@ int init_syl_tab(slang_T *slang) static int count_syllables(slang_T *slang, const char *word) FUNC_ATTR_NONNULL_ALL { - int cnt = 0; - bool skip = false; - int len; - if (slang->sl_syllable == NULL) { return 0; } + int cnt = 0; + bool skip = false; + int len; + for (const char *p = word; *p != NUL; p += len) { // When running into a space reset counter. if (*p == ' ') { @@ -1930,25 +1924,14 @@ static int count_syllables(slang_T *slang, const char *word) /// @return NULL if it's OK, an untranslated error message otherwise. char *parse_spelllang(win_T *wp) { - garray_T ga; - char *splp; - char *region; char region_cp[3]; - bool filename; - int region_mask; - slang_T *slang; - int c; char lang[MAXWLEN + 1]; char spf_name[MAXPATHL]; - char *p; - int round; - char *spf; char *use_region = NULL; bool dont_use_region = false; bool nobreak = false; static bool recursive = false; char *ret_msg = NULL; - char *spl_copy; bufref_T bufref; set_bufref(&bufref, wp->w_buffer); @@ -1961,20 +1944,21 @@ char *parse_spelllang(win_T *wp) } recursive = true; + garray_T ga; ga_init(&ga, sizeof(langp_T), 2); clear_midword(wp); // Make a copy of 'spelllang', the SpellFileMissing autocommands may change // it under our fingers. - spl_copy = xstrdup(wp->w_s->b_p_spl); + char *spl_copy = xstrdup(wp->w_s->b_p_spl); wp->w_s->b_cjk = 0; // Loop over comma separated language names. - for (splp = spl_copy; *splp != NUL;) { + for (char *splp = spl_copy; *splp != NUL;) { // Get one language name. copy_option_part(&splp, lang, MAXWLEN, ","); - region = NULL; + char *region = NULL; int len = (int)strlen(lang); if (!valid_spelllang(lang)) { @@ -1986,6 +1970,8 @@ char *parse_spelllang(win_T *wp) continue; } + slang_T *slang; + bool filename; // If the name ends in ".spl" use it as the name of the spell file. // If there is a region name let "region" point to it and remove it // from the name. @@ -1993,7 +1979,7 @@ char *parse_spelllang(win_T *wp) filename = true; // Locate a region and remove it from the file name. - p = vim_strchr(path_tail(lang), '_'); + char *p = vim_strchr(path_tail(lang), '_'); if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2]) && !ASCII_ISALPHA(p[3])) { xstrlcpy(region_cp, p + 1, 3); @@ -2056,10 +2042,10 @@ char *parse_spelllang(win_T *wp) if (filename ? path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles : STRICMP(lang, slang->sl_name) == 0) { - region_mask = REGION_ALL; + int region_mask = REGION_ALL; if (!filename && region != NULL) { // find region in sl_regions - c = find_region(slang->sl_regions, region); + int c = find_region(slang->sl_regions, region); if (c == REGION_ALL) { if (slang->sl_add) { if (*slang->sl_regions != NUL) { @@ -2095,8 +2081,8 @@ char *parse_spelllang(win_T *wp) // round 1: load first name in 'spellfile'. // round 2: load second name in 'spellfile. // etc. - spf = curwin->w_s->b_p_spf; - for (round = 0; round == 0 || *spf != NUL; round++) { + char *spf = curwin->w_s->b_p_spf; + for (int round = 0; round == 0 || *spf != NUL; round++) { if (round == 0) { // Internal wordlist, if there is one. if (int_wordlist == NULL) { @@ -2107,10 +2093,11 @@ char *parse_spelllang(win_T *wp) // One entry in 'spellfile'. copy_option_part(&spf, spf_name, MAXPATHL - 5, ","); STRCAT(spf_name, ".spl"); + int c; // If it was already found above then skip it. for (c = 0; c < ga.ga_len; c++) { - p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; + char *p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; if (p != NULL && path_full_compare(spf_name, p, false, true) == kEqualFiles) { break; @@ -2121,6 +2108,8 @@ char *parse_spelllang(win_T *wp) } } + slang_T *slang; + // Check if it was loaded already. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { if (path_full_compare(spf_name, slang->sl_fname, false, true) @@ -2136,7 +2125,7 @@ char *parse_spelllang(win_T *wp) STRCPY(lang, "internal wordlist"); } else { xstrlcpy(lang, path_tail(spf_name), MAXWLEN + 1); - p = vim_strchr(lang, '.'); + char *p = vim_strchr(lang, '.'); if (p != NULL) { *p = NUL; // truncate at ".encoding.add" } @@ -2150,10 +2139,10 @@ char *parse_spelllang(win_T *wp) } } if (slang != NULL) { - region_mask = REGION_ALL; + int region_mask = REGION_ALL; if (use_region != NULL && !dont_use_region) { // find region in sl_regions - c = find_region(slang->sl_regions, use_region); + int c = find_region(slang->sl_regions, use_region); if (c != REGION_ALL) { region_mask = 1 << c; } else if (*slang->sl_regions != NUL) { @@ -2903,19 +2892,7 @@ static void spell_soundfold_sofo(slang_T *slang, const char *inword, char *res) // Multi-byte version of spell_soundfold(). static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) { - salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; int word[MAXWLEN] = { 0 }; - int wres[MAXWLEN] = { 0 }; - int *ws; - int *pf; - int j, z; - int reslen; - int k = 0; - int k0; - int n0; - int pri; - int p0 = -333; - int c0; bool did_white = false; // Convert the multi-byte string to a wide-character string. @@ -2943,17 +2920,24 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } word[wordlen] = NUL; + salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; + int wres[MAXWLEN] = { 0 }; + int k = 0; + int p0 = -333; int c; // This algorithm comes from Aspell phonet.cpp. // Converted from C++ to C. Added support for multi-byte chars. // Changed to keep spaces. - int i = reslen = z = 0; + int i = 0; + int reslen = 0; + int z = 0; while ((c = word[i]) != NUL) { // Start with the first rule that has the character in the word. int n = slang->sl_sal_first[c & 0xff]; int z0 = 0; if (n >= 0) { + int *ws; // Check all rules for the same index byte. // If c is 0x300 need extra check for the end of the array, as // (c & 0xff) is NUL. @@ -2970,6 +2954,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) continue; } if (k > 2) { + int j; for (j = 2; j < k; j++) { if (word[i + j] != ws[j]) { break; @@ -2981,6 +2966,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } } + int *pf; if ((pf = smp[n].sm_oneof_w) != NULL) { // Check for match with one of the chars in "sm_oneof". while (*pf != NUL && *pf != word[i + k]) { @@ -2992,10 +2978,10 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) k++; } char *s = smp[n].sm_rules; - pri = 5; // default priority + int pri = 5; // default priority p0 = (uint8_t)(*s); - k0 = k; + int k0 = k; while (*s == '-' && k > 1) { k--; s++; @@ -3023,8 +3009,8 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) && (!spell_iswordp_w(word + i + k0, curwin)))) { // search for followup rules, if: // followup and k > 1 and NO '-' in searchstring - c0 = word[i + k - 1]; - n0 = slang->sl_sal_first[c0 & 0xff]; + int c0 = word[i + k - 1]; + int n0 = slang->sl_sal_first[c0 & 0xff]; if (slang->sl_followup && k > 1 && n0 >= 0 && p0 != '-' && word[i + k] != NUL) { @@ -3043,6 +3029,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } if (k0 > 2) { pf = word + i + k + 1; + int j; for (j = 2; j < k0; j++) { if (*pf++ != ws[j]) { break; @@ -3263,23 +3250,13 @@ void ex_spelldump(exarg_T *eap) /// @param dumpflags_arg DUMPFLAG_* void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) { - langp_T *lp; - slang_T *slang; idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; char word[MAXWLEN]; - int c; - uint8_t *byts; - idx_T *idxs; linenr_T lnum = 0; - int depth; - int n; - int flags; char *region_names = NULL; // region names being used bool do_region = true; // dump region names and numbers - char *p; int dumpflags = dumpflags_arg; - int patlen; // When ignoring case or when the pattern starts with capital pass this on // to dump_word(). @@ -3287,7 +3264,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) if (ic) { dumpflags |= DUMPFLAG_ICASE; } else { - n = captype(pat, NULL); + int n = captype(pat, NULL); if (n == WF_ONECAP) { dumpflags |= DUMPFLAG_ONECAP; } else if (n == WF_ALLCAP @@ -3300,8 +3277,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // Find out if we can support regions: All languages must support the same // regions or none at all. for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { - lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); - p = lp->lp_slang->sl_regions; + langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); + char *p = lp->lp_slang->sl_regions; if (p[0] != 0) { if (region_names == NULL) { // first language with regions region_names = p; @@ -3321,8 +3298,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // Loop over all files loaded for the entries in 'spelllang'. for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { - lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); - slang = lp->lp_slang; + langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); + slang_T *slang = lp->lp_slang; if (slang->sl_fbyts == NULL) { // reloading failed continue; } @@ -3332,6 +3309,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) ml_append(lnum++, IObuff, 0, false); } + int patlen; // When matching with a pattern and there are no prefixes only use // parts of the tree that match "pat". if (pat != NULL && slang->sl_pbyts == NULL) { @@ -3343,6 +3321,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // round 1: case-folded tree // round 2: keep-case tree for (int round = 1; round <= 2; round++) { + uint8_t *byts; + idx_T *idxs; if (round == 1) { dumpflags &= ~DUMPFLAG_KEEPCASE; byts = slang->sl_fbyts; @@ -3355,7 +3335,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) if (byts == NULL) { continue; // array is empty } - depth = 0; + int depth = 0; arridx[0] = 0; curi[0] = 1; while (depth >= 0 && !got_int @@ -3367,16 +3347,16 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) ins_compl_check_keys(50, false); } else { // Do one more byte at this node. - n = arridx[depth] + curi[depth]; + int n = arridx[depth] + curi[depth]; curi[depth]++; - c = byts[n]; + int c = byts[n]; if (c == 0 || depth >= MAXWLEN - 1) { // End of word or reached maximum length, deal with the // word. // Don't use keep-case words in the fold-case tree, // they will appear in the keep-case tree. // Only use the word when the region matches. - flags = (int)idxs[n]; + int flags = (int)idxs[n]; if ((round == 2 || (flags & WF_KEEPCAP) == 0) && (flags & WF_NEEDCOMP) == 0 && (do_region -- cgit From 8cbb1f20e557461c8417583a7f69d53aaaef920b Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Tue, 4 Jun 2024 09:06:02 -0400 Subject: refactor(lua): use tuple syntax everywhere #29111 --- src/nvim/eval.lua | 4 ++-- src/nvim/generators/gen_options.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index ceaba11f41..3c99ba22c2 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -19,7 +19,7 @@ --- @field returns_desc? string --- @field signature? string --- @field desc? string ---- @field params {[1]:string, [2]:string, [3]:string}[] +--- @field params [string, string, string][] --- @field lua? false Do not render type information --- @field tags? string[] Extra tags --- @field data? string Used by gen_eval.lua @@ -11672,7 +11672,7 @@ M.funcs = { ]=], name = 'synconcealed', params = { { 'lnum', 'integer' }, { 'col', 'integer' } }, - returns = '{[1]: integer, [2]: string, [3]: integer}', + returns = '[integer, string, integer]', signature = 'synconcealed({lnum}, {col})', }, synstack = { diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 0718d965c6..591a6b93df 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -148,7 +148,7 @@ local get_defaults = function(d, n) return value_dumpers[type(d)](d) end ---- @type {[1]:string,[2]:string}[] +--- @type [string,string][] local defines = {} --- @param i integer -- cgit From b66106a46c5c6180c7f80852a8c822b400e73100 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 4 Jun 2024 15:09:12 +0200 Subject: fix(ui): superfluous showmode / excessive grid_cursor_goto #29089 Problem: Unsetting global variables earlier in #28578 to avoid recursiveness, caused superfluous or even unlimited showmode(). Solution: Partly revert #28578 so that the globals are unset at the end of showmode(), and avoid recursiveness for ext UI by adding a recursive function guard to each generated UI call that may call a Lua callback. --- src/nvim/drawscreen.c | 22 ++++++++++------------ src/nvim/ex_getln.c | 5 +---- src/nvim/generators/gen_api_ui_events.lua | 8 ++++++++ 3 files changed, 19 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index bd9a834869..88e1f302da 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -931,13 +931,7 @@ int showmode(void) msg_ext_clear(true); } - // Don't make non-flushed message part of the showmode and reset global - // variables before flushing to to avoid recursiveness. - bool draw_mode = redraw_mode; - bool clear_cmd = clear_cmdline; - redraw_cmdline = false; - redraw_mode = false; - clear_cmdline = false; + // Don't make non-flushed message part of the showmode. msg_ext_ui_flush(); msg_grid_validate(); @@ -960,8 +954,8 @@ int showmode(void) msg_check_for_delay(false); // if the cmdline is more than one line high, erase top lines - bool need_clear = clear_cmd; - if (clear_cmd && cmdline_row < Rows - 1) { + bool need_clear = clear_cmdline; + if (clear_cmdline && cmdline_row < Rows - 1) { msg_clr_cmdline(); // will reset clear_cmdline } @@ -1083,7 +1077,7 @@ int showmode(void) } mode_displayed = true; - if (need_clear || clear_cmd || draw_mode) { + if (need_clear || clear_cmdline || redraw_mode) { msg_clr_eos(); } msg_didout = false; // overwrite this message @@ -1092,10 +1086,10 @@ int showmode(void) msg_no_more = false; lines_left = save_lines_left; need_wait_return = nwr_save; // never ask for hit-return for this - } else if (clear_cmd && msg_silent == 0) { + } else if (clear_cmdline && msg_silent == 0) { // Clear the whole command line. Will reset "clear_cmdline". msg_clr_cmdline(); - } else if (draw_mode) { + } else if (redraw_mode) { msg_pos_mode(); msg_clr_eos(); } @@ -1118,6 +1112,10 @@ int showmode(void) grid_line_flush(); } + redraw_cmdline = false; + redraw_mode = false; + clear_cmdline = false; + return length; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 4323a9d221..cef1868fc8 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3455,11 +3455,9 @@ void cmdline_screen_cleared(void) /// called by ui_flush, do what redraws necessary to keep cmdline updated. void cmdline_ui_flush(void) { - static bool flushing = false; - if (!ui_has(kUICmdline) || flushing) { + if (!ui_has(kUICmdline)) { return; } - flushing = true; int level = ccline.level; CmdlineInfo *line = &ccline; while (level > 0 && line) { @@ -3474,7 +3472,6 @@ void cmdline_ui_flush(void) } line = line->prev_ccline; } - flushing = false; } // Put a character on the command line. Shifts the following text to the diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua index 516b5ad5ae..c5b37672bf 100644 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -128,8 +128,16 @@ for i = 1, #events do write_signature(call_output, ev, '') call_output:write('\n{\n') if ev.remote_only then + -- Lua callbacks may emit other events or the same event again. Avoid the latter + -- by adding a recursion guard to each generated function that may call a Lua callback. + call_output:write(' static bool entered = false;\n') + call_output:write(' if (entered) {\n') + call_output:write(' return;\n') + call_output:write(' }\n') + call_output:write(' entered = true;\n') write_arglist(call_output, ev) call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n') + call_output:write(' entered = false;\n') elseif ev.compositor_impl then call_output:write(' ui_comp_' .. ev.name) write_signature(call_output, ev, '', true) -- cgit From 164338330b74e6e7c7cbb61e49c810dd82599236 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 5 Jun 2024 14:44:31 +0800 Subject: vim-patch:9.1.0463: no fuzzy-matching support for insert-completion Problem: no fuzzy-matching support for insert-completion Solution: enable insert-mode completion with fuzzy-matching using :set completopt+=fuzzy (glepnir). closes: vim/vim#14878 https://github.com/vim/vim/commit/a218cc6cdabae1113647b817c4eefc2b60a6902f Co-authored-by: glepnir --- src/nvim/insexpand.c | 108 +++++++++++++++++++++++++++++++++++++++++++++------ src/nvim/options.lua | 11 ++++-- src/nvim/optionstr.c | 4 +- src/nvim/popupmenu.h | 9 +++-- 4 files changed, 111 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 7a652dff2a..783156dc2b 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -168,6 +168,7 @@ struct compl_S { ///< cp_flags has CP_FREE_FNAME int cp_flags; ///< CP_ values int cp_number; ///< sequence number + int cp_score; ///< fuzzy match score }; /// state information used for getting the next set of insert completion @@ -231,6 +232,7 @@ static bool compl_no_select = false; ///< false: select & insert ///< true: noselect static bool compl_longest = false; ///< false: insert full match ///< true: insert longest prefix +static bool compl_fuzzy_match = false; ///< true: fuzzy match enabled /// Selected one of the matches. When false the match was edited or using the /// longest common string. @@ -288,7 +290,7 @@ static bool compl_opt_refresh_always = false; static size_t spell_bad_len = 0; // length of located bad word -static int pum_selected_item = -1; +static int compl_selected_item = -1; /// CTRL-X pressed in Insert mode. void ins_ctrl_x(void) @@ -1056,6 +1058,7 @@ void completeopt_was_set(void) compl_no_insert = false; compl_no_select = false; compl_longest = false; + compl_fuzzy_match = false; if (strstr(p_cot, "noselect") != NULL) { compl_no_select = true; } @@ -1065,6 +1068,9 @@ void completeopt_was_set(void) if (strstr(p_cot, "longest") != NULL) { compl_longest = true; } + if (strstr(p_cot, "fuzzy") != NULL) { + compl_fuzzy_match = true; + } } /// "compl_match_array" points the currently displayed list of entries in the @@ -1161,6 +1167,14 @@ static void trigger_complete_changed_event(int cur) restore_v_event(v_event, &save_v_event); } +/// pumitem qsort compare func +static int ins_compl_fuzzy_sort(const void *a, const void *b) +{ + const int sa = (*(pumitem_T *)a).pum_score; + const int sb = (*(pumitem_T *)b).pum_score; + return sa == sb ? 0 : sa < sb ? 1 : -1; +} + /// Build a popup menu to show the completion matches. /// /// @return the popup menu entry that should be selected, @@ -1178,11 +1192,19 @@ static int ins_compl_build_pum(void) } const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 0; + int max_fuzzy_score = 0; do { + // when completeopt include fuzzy option and leader is not null or empty + // set the cp_score for after compare. + if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) { + comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader); + } + if (!match_at_original_text(comp) && (compl_leader == NULL - || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) { + || ins_compl_equal(comp, compl_leader, (size_t)lead_len) + || (compl_fuzzy_match && comp->cp_score > 0))) { compl_match_arraysize++; } comp = comp->cp_next; @@ -1211,8 +1233,9 @@ static int ins_compl_build_pum(void) do { if (!match_at_original_text(comp) && (compl_leader == NULL - || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) { - if (!shown_match_ok) { + || ins_compl_equal(comp, compl_leader, (size_t)lead_len) + || (compl_fuzzy_match && comp->cp_score > 0))) { + if (!shown_match_ok && !compl_fuzzy_match) { if (comp == compl_shown_match || did_find_shown_match) { // This item is the shown match or this is the // first displayed item after the shown match. @@ -1225,6 +1248,20 @@ static int ins_compl_build_pum(void) shown_compl = comp; } cur = i; + } else if (compl_fuzzy_match) { + if (comp->cp_score > max_fuzzy_score) { + did_find_shown_match = true; + max_fuzzy_score = comp->cp_score; + compl_shown_match = comp; + shown_match_ok = true; + } + + if (!compl_no_select + && (max_fuzzy_score > 0 + || (compl_leader == NULL || lead_len == 0))) { + shown_match_ok = true; + cur = 0; + } } if (comp->cp_text[CPT_ABBR] != NULL) { @@ -1234,6 +1271,7 @@ static int ins_compl_build_pum(void) } compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND]; compl_match_array[i].pum_info = comp->cp_text[CPT_INFO]; + compl_match_array[i].pum_score = comp->cp_score; if (comp->cp_text[CPT_MENU] != NULL) { compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU]; } else { @@ -1241,7 +1279,7 @@ static int ins_compl_build_pum(void) } } - if (comp == compl_shown_match) { + if (comp == compl_shown_match && !compl_fuzzy_match) { did_find_shown_match = true; // When the original text is the shown match don't set @@ -1260,6 +1298,12 @@ static int ins_compl_build_pum(void) comp = comp->cp_next; } while (comp != NULL && !is_first_match(comp)); + if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) { + // sort by the largest score of fuzzy match + qsort(compl_match_array, (size_t)compl_match_arraysize, sizeof(pumitem_T), + ins_compl_fuzzy_sort); + } + if (!shown_match_ok) { // no displayed match at all cur = -1; } @@ -1311,7 +1355,7 @@ void ins_compl_show_pum(void) // Use the cursor to get all wrapping and other settings right. const colnr_T col = curwin->w_cursor.col; curwin->w_cursor.col = compl_col; - pum_selected_item = cur; + compl_selected_item = cur; pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0); curwin->w_cursor.col = col; @@ -3589,6 +3633,41 @@ static void ins_compl_show_filename(void) redraw_cmdline = false; // don't overwrite! } +static compl_T *find_comp_when_fuzzy(void) +{ + int target_idx = -1; + const bool is_forward = compl_shows_dir_forward(); + const bool is_backward = compl_shows_dir_backward(); + compl_T *comp = NULL; + + if (compl_match_array == NULL + || (is_forward && compl_selected_item == compl_match_arraysize - 1) + || (is_backward && compl_selected_item == 0)) { + return compl_first_match; + } + + if (is_forward) { + target_idx = compl_selected_item + 1; + } else if (is_backward) { + target_idx = compl_selected_item == -1 ? compl_match_arraysize - 1 + : compl_selected_item - 1; + } + + const int score = compl_match_array[target_idx].pum_score; + char *const str = compl_match_array[target_idx].pum_text; + + comp = compl_first_match; + do { + if (comp->cp_score == score + && (str == comp->cp_str || str == comp->cp_text[CPT_ABBR])) { + return comp; + } + comp = comp->cp_next; + } while (comp != NULL && !is_first_match(comp)); + + return NULL; +} + /// Find the next set of matches for completion. Repeat the completion "todo" /// times. The number of matches found is returned in 'num_matches'. /// @@ -3609,14 +3688,16 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a while (--todo >= 0) { if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL) { - compl_shown_match = compl_shown_match->cp_next; + compl_shown_match = !compl_fuzzy_match ? compl_shown_match->cp_next + : find_comp_when_fuzzy(); found_end = (compl_first_match != NULL && (is_first_match(compl_shown_match->cp_next) || is_first_match(compl_shown_match))); } else if (compl_shows_dir_backward() && compl_shown_match->cp_prev != NULL) { found_end = is_first_match(compl_shown_match); - compl_shown_match = compl_shown_match->cp_prev; + compl_shown_match = !compl_fuzzy_match ? compl_shown_match->cp_prev + : find_comp_when_fuzzy(); found_end |= is_first_match(compl_shown_match); } else { if (!allow_get_expansion) { @@ -3660,7 +3741,8 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a if (!match_at_original_text(compl_shown_match) && compl_leader != NULL && !ins_compl_equal(compl_shown_match, - compl_leader, strlen(compl_leader))) { + compl_leader, strlen(compl_leader)) + && !(compl_fuzzy_match && compl_shown_match->cp_score > 0)) { todo++; } else { // Remember a matching item. @@ -3712,7 +3794,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match return -1; } - if (compl_leader != NULL && !match_at_original_text(compl_shown_match)) { + if (compl_leader != NULL + && !match_at_original_text(compl_shown_match) + && !compl_fuzzy_match) { // Update "compl_shown_match" to the actually shown match ins_compl_update_shown_match(); } @@ -3854,7 +3938,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func) static int ins_compl_key2dir(int c) { if (c == K_EVENT || c == K_COMMAND || c == K_LUA) { - return pum_want.item < pum_selected_item ? BACKWARD : FORWARD; + return pum_want.item < compl_selected_item ? BACKWARD : FORWARD; } if (c == Ctrl_P || c == Ctrl_L || c == K_PAGEUP || c == K_KPAGEUP @@ -3880,7 +3964,7 @@ static bool ins_compl_pum_key(int c) static int ins_compl_key2count(int c) { if (c == K_EVENT || c == K_COMMAND || c == K_LUA) { - int offset = pum_want.item - pum_selected_item; + int offset = pum_want.item - compl_selected_item; return abs(offset); } diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 0ec17088bb..64a3307f46 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1443,6 +1443,10 @@ return { completion in the preview window. Only works in combination with "menu" or "menuone". + popup Show extra information about the currently selected + completion in a popup window. Only works in combination + with "menu" or "menuone". Overrides "preview". + noinsert Do not insert any text for a match until the user selects a match from the menu. Only works in combination with "menu" or "menuone". No effect if "longest" is present. @@ -1451,9 +1455,10 @@ return { select one from the menu. Only works in combination with "menu" or "menuone". - popup Show extra information about the currently selected - completion in a popup window. Only works in combination - with "menu" or "menuone". Overrides "preview". + fuzzy Enable |fuzzy-matching| for completion candidates. This + allows for more flexible and intuitive matching, where + characters can be skipped and matches can be found even + if the exact sequence is not typed. ]=], expand_cb = 'expand_set_completeopt', full_name = 'completeopt', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index be3bec2256..050cb1fe98 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -122,8 +122,8 @@ static char *(p_bs_values[]) = { "indent", "eol", "start", "nostop", NULL }; static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent", "syntax", "diff", NULL }; static char *(p_fcl_values[]) = { "all", NULL }; -static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect", - "popup", NULL }; +static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "popup", + "noinsert", "noselect", "fuzzy", NULL }; #ifdef BACKSLASH_IN_FILENAME static char *(p_csl_values[]) = { "slash", "backslash", NULL }; #endif diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h index 20a342b841..9e3f8f5a7f 100644 --- a/src/nvim/popupmenu.h +++ b/src/nvim/popupmenu.h @@ -10,10 +10,11 @@ /// Used for popup menu items. typedef struct { - char *pum_text; // main menu text - char *pum_kind; // extra kind text (may be truncated) - char *pum_extra; // extra menu text (may be truncated) - char *pum_info; // extra info + char *pum_text; ///< main menu text + char *pum_kind; ///< extra kind text (may be truncated) + char *pum_extra; ///< extra menu text (may be truncated) + char *pum_info; ///< extra info + int pum_score; ///< fuzzy match score } pumitem_T; EXTERN ScreenGrid pum_grid INIT( = SCREEN_GRID_INIT); -- cgit From c2e836c41cabef3c5e269b5f6401f272112c75e1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 5 Jun 2024 15:01:23 +0800 Subject: vim-patch:2a2c4ff: runtime(doc): clarify how fuzzy 'completeopt' should work related: vim/vim#14912 https://github.com/vim/vim/commit/2a2c4fffd7e04f74b316209404767f128684a9e1 Co-authored-by: Christian Brabandt --- src/nvim/options.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 64a3307f46..aa43c4cf3d 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1458,7 +1458,10 @@ return { fuzzy Enable |fuzzy-matching| for completion candidates. This allows for more flexible and intuitive matching, where characters can be skipped and matches can be found even - if the exact sequence is not typed. + if the exact sequence is not typed. Only makes a + difference how completion candidates are reduced from the + list of alternatives, but not how the candidates are + collected (using different completion types). ]=], expand_cb = 'expand_set_completeopt', full_name = 'completeopt', -- cgit From 818cb27e4843e410df9cc6db11efb33e26bc1b41 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 5 Jun 2024 15:02:20 +0800 Subject: vim-patch:9.1.0466: Missing comments for fuzzy completion Problem: Missing comments for fuzzy completion (after 9.1.0463) Solution: Add more comments, adjust indentation slightly (glepnir) closes: vim/vim#14910 https://github.com/vim/vim/commit/dca57fb54200530a0874c90fab799a689c00c597 Co-authored-by: glepnir --- src/nvim/insexpand.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 783156dc2b..77fae4dd18 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -1249,6 +1249,8 @@ static int ins_compl_build_pum(void) } cur = i; } else if (compl_fuzzy_match) { + // Update the maximum fuzzy score and the shown match + // if the current item's score is higher if (comp->cp_score > max_fuzzy_score) { did_find_shown_match = true; max_fuzzy_score = comp->cp_score; @@ -1256,6 +1258,10 @@ static int ins_compl_build_pum(void) shown_match_ok = true; } + // If there is no "no select" condition and the max fuzzy + // score is positive, or there is no completion leader or the + // leader length is zero, mark the shown match as valid and + // reset the current index. if (!compl_no_select && (max_fuzzy_score > 0 || (compl_leader == NULL || lead_len == 0))) { @@ -3633,6 +3639,7 @@ static void ins_compl_show_filename(void) redraw_cmdline = false; // don't overwrite! } +/// find a completion item in when completeopt include fuzzy option static compl_T *find_comp_when_fuzzy(void) { int target_idx = -1; -- cgit From d7651b27d54a87c5783c0a579af11da9a16a39aa Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 5 Jun 2024 08:27:56 -0500 Subject: fix(tui): move $COLORTERM check to _defaults.lua (#29197) We currently check $COLORTERM in the TUI process to determine if the terminal supports 24 bit color (truecolor). If $COLORTERM is "truecolor" or "24bit" then we automatically assume that the terminal supports truecolor, but if $COLORTERM is set to any other value we still query the terminal. The `rgb` flag of the UI struct is a boolean which only indicates whether the UI supports truecolor, but does not have a 3rd state that we can use to represent "we don't know if the UI supports truecolor". We currently use `rgb=false` to represent this "we don't know" state, and we use XTGETTCAP and DECRQSS queries to determine at runtime if the terminal supports truecolor. However, if $COLORTERM is set to a value besides "truecolor" or "24bit" (e.g. "256" or "16) that is a clear indication that the terminal _does not_ support truecolor, so it is incorrect to treat `rgb=false` as "we don't know" in that case. Instead, in the TUI process we only check for the terminfo capabilities. This must be done in the TUI process because we do not have access to this information in the core Neovim process when `_defaults.lua` runs. If the TUI cannot determine truecolor support from terminfo alone, we set `rgb=false` to indicate "we don't know if the terminal supports truecolor yet, keep checking". When we get to `_defaults.lua`, we can then check $COLORTERM and only query the terminal if it is unset. This means that users can explicitly opt out of truecolor determination by setting `COLORTERM=256` (or similar) in their environment. --- src/nvim/tui/tui.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 650133e6a2..57696b1839 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1855,20 +1855,12 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name) return -1; } -/// Determine if the terminal supports truecolor or not: +/// Determine if the terminal supports truecolor or not. /// -/// 1. If $COLORTERM is "24bit" or "truecolor", return true -/// 2. Else, check terminfo for Tc, RGB, setrgbf, or setrgbb capabilities. If -/// found, return true -/// 3. Else, return false +/// If terminfo contains Tc, RGB, or both setrgbf and setrgbb capabilities, return true. static bool term_has_truecolor(TUIData *tui, const char *colorterm) { - // Check $COLORTERM - if (strequal(colorterm, "truecolor") || strequal(colorterm, "24bit")) { - return true; - } - - // Check for Tc and RGB + // Check for Tc or RGB for (size_t i = 0; i < unibi_count_ext_bool(tui->ut); i++) { const char *n = unibi_get_ext_bool_name(tui->ut, i); if (n && (!strcmp(n, "Tc") || !strcmp(n, "RGB"))) { -- cgit From c235a063d6ead447f13076be50ddd9fae6223913 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 6 Jun 2024 05:49:04 +0800 Subject: vim-patch:9.1.0467: typos in some comments Problem: typos in some comments (after v9.1.0466) Solution: fix comments (zeertzjq) closes: vim/vim#14919 https://github.com/vim/vim/commit/551d8c372e49ed630fd95c6422a0ee62d00902c5 --- src/nvim/insexpand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 77fae4dd18..9f39c7d581 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -1195,8 +1195,8 @@ static int ins_compl_build_pum(void) int max_fuzzy_score = 0; do { - // when completeopt include fuzzy option and leader is not null or empty - // set the cp_score for after compare. + // 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); } @@ -3639,7 +3639,7 @@ static void ins_compl_show_filename(void) redraw_cmdline = false; // don't overwrite! } -/// find a completion item in when completeopt include fuzzy option +/// Find a completion item when 'completeopt' contains "fuzzy". static compl_T *find_comp_when_fuzzy(void) { int target_idx = -1; -- cgit From 1d4e894403638a94ac58766cdcbc7f3128db318b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 6 Jun 2024 05:50:44 +0800 Subject: vim-patch:9.1.0469: Cannot have buffer-local value for 'completeopt' Problem: Cannot have buffer-local value for 'completeopt' (Nick Jensen). Solution: Make 'completeopt' global-local (zeertzjq). Also for some reason test Test_ColonEight_MultiByte seems to be failing sporadically now. Let's mark it as flaky. fixes: vim/vim#5487 closes: vim/vim#14922 https://github.com/vim/vim/commit/529b9ad62a0e843ee56ef609aef7e51b7dc8a4c8 --- src/nvim/buffer.c | 1 + src/nvim/buffer_defs.h | 2 ++ src/nvim/insexpand.c | 51 ++++++++++++++++++++------------------------------ src/nvim/option.c | 6 ++++++ src/nvim/option_vars.h | 13 +++++++++++++ src/nvim/options.lua | 2 +- src/nvim/optionstr.c | 19 +++++++++++++++++-- src/nvim/popupmenu.c | 7 ++++--- 8 files changed, 64 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index c0fbc36787..57245ce3f5 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2077,6 +2077,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff) clear_string_option(&buf->b_p_lop); clear_string_option(&buf->b_p_cinsd); clear_string_option(&buf->b_p_cinw); + clear_string_option(&buf->b_p_cot); clear_string_option(&buf->b_p_cpt); clear_string_option(&buf->b_p_cfu); callback_free(&buf->b_cfu_cb); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 512247047c..221a86a907 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -533,6 +533,8 @@ struct file_buffer { char *b_p_cinsd; ///< 'cinscopedecls' char *b_p_com; ///< 'comments' char *b_p_cms; ///< 'commentstring' + char *b_p_cot; ///< 'completeopt' local value + unsigned b_cot_flags; ///< flags for 'completeopt' char *b_p_cpt; ///< 'complete' #ifdef BACKSLASH_IN_FILENAME char *b_p_csl; ///< 'completeslash' diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 9f39c7d581..574c9a9e3a 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -226,14 +226,6 @@ static char *compl_leader = NULL; static bool compl_get_longest = false; ///< put longest common string in compl_leader -static bool compl_no_insert = false; ///< false: select & insert - ///< true: noinsert -static bool compl_no_select = false; ///< false: select & insert - ///< true: noselect -static bool compl_longest = false; ///< false: insert full match - ///< true: insert longest prefix -static bool compl_fuzzy_match = false; ///< true: fuzzy match enabled - /// Selected one of the matches. When false the match was edited or using the /// longest common string. static bool compl_used_match; @@ -1051,26 +1043,10 @@ bool ins_compl_long_shown_match(void) && (colnr_T)strlen(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col; } -/// Set variables that store noselect and noinsert behavior from the -/// 'completeopt' value. -void completeopt_was_set(void) +/// Get the local or global value of 'completeopt' flags. +unsigned get_cot_flags(void) { - compl_no_insert = false; - compl_no_select = false; - compl_longest = false; - compl_fuzzy_match = false; - if (strstr(p_cot, "noselect") != NULL) { - compl_no_select = true; - } - if (strstr(p_cot, "noinsert") != NULL) { - compl_no_insert = true; - } - if (strstr(p_cot, "longest") != NULL) { - compl_longest = true; - } - if (strstr(p_cot, "fuzzy") != NULL) { - compl_fuzzy_match = true; - } + return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags; } /// "compl_match_array" points the currently displayed list of entries in the @@ -1094,7 +1070,7 @@ bool pum_wanted(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { // "completeopt" must contain "menu" or "menuone" - return vim_strchr(p_cot, 'm') != NULL; + return (get_cot_flags() & COT_ANY_MENU) != 0; } /// Check that there are two or more matches to be shown in the popup menu. @@ -1113,7 +1089,7 @@ static bool pum_enough_matches(void) comp = comp->cp_next; } while (!is_first_match(comp)); - if (strstr(p_cot, "menuone") != NULL) { + if (get_cot_flags() & COT_MENUONE) { return i >= 1; } return i >= 2; @@ -1193,6 +1169,9 @@ static int ins_compl_build_pum(void) 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 & COT_NOSELECT) != 0; + bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; do { // When 'completeopt' contains "fuzzy" and leader is not NULL or empty, @@ -2229,7 +2208,7 @@ bool ins_compl_prep(int c) // Set "compl_get_longest" when finding the first matches. if (ctrl_x_mode_not_defined_yet() || (ctrl_x_mode_normal() && !compl_started)) { - compl_get_longest = compl_longest; + compl_get_longest = (get_cot_flags() & COT_LONGEST) != 0; compl_used_match = true; } @@ -2649,6 +2628,10 @@ static void restore_orig_extmarks(void) static void set_completion(colnr_T startcol, list_T *list) { int flags = CP_ORIGINAL_TEXT; + unsigned cur_cot_flags = get_cot_flags(); + bool compl_longest = (cur_cot_flags & COT_LONGEST) != 0; + bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0; + bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; // If already doing completions stop it. if (ctrl_x_mode_not_default()) { @@ -3692,6 +3675,9 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a { bool found_end = false; compl_T *found_compl = NULL; + unsigned cur_cot_flags = get_cot_flags(); + bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; + bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; while (--todo >= 0) { if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL) { @@ -3794,6 +3780,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match int todo = count; const bool started = compl_started; buf_T *const orig_curbuf = curbuf; + unsigned cur_cot_flags = get_cot_flags(); + bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0; + bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; // When user complete function return -1 for findstart which is next // time of 'always', compl_shown_match become NULL. @@ -3932,7 +3921,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func) } } } - if (compl_pending != 0 && !got_int && !compl_no_insert) { + if (compl_pending != 0 && !got_int && !(cot_flags & COT_NOINSERT)) { int todo = compl_pending > 0 ? compl_pending : -compl_pending; compl_pending = 0; diff --git a/src/nvim/option.c b/src/nvim/option.c index 32fabd4141..41b9aaf9a7 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4570,6 +4570,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) return &(buf->b_p_def); case PV_INC: return &(buf->b_p_inc); + case PV_COT: + return &(buf->b_p_cot); case PV_DICT: return &(buf->b_p_dict); case PV_TSR: @@ -4653,6 +4655,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var; case PV_INC: return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var; + case PV_COT: + return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var; case PV_DICT: return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var; case PV_TSR: @@ -5332,6 +5336,8 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_inc = empty_string_option; buf->b_p_inex = xstrdup(p_inex); COPY_OPT_SCTX(buf, BV_INEX); + buf->b_p_cot = empty_string_option; + buf->b_cot_flags = 0; buf->b_p_dict = empty_string_option; buf->b_p_tsr = empty_string_option; buf->b_p_tsrfu = empty_string_option; diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index c98c84d34e..bd0fe699d9 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -430,6 +430,19 @@ EXTERN char *p_cpt; ///< 'complete' EXTERN OptInt p_columns; ///< 'columns' EXTERN int p_confirm; ///< 'confirm' EXTERN char *p_cot; ///< 'completeopt' +EXTERN unsigned cot_flags; ///< flags from 'completeopt' +// Keep in sync with p_cot_values in optionstr.c +#define COT_MENU 0x001 +#define COT_MENUONE 0x002 +#define COT_ANY_MENU 0x003 // combination of menu flags +#define COT_LONGEST 0x004 // false: insert full match, + // true: insert longest prefix +#define COT_PREVIEW 0x008 +#define COT_POPUP 0x010 +#define COT_ANY_PREVIEW 0x018 // combination of preview flags +#define COT_NOINSERT 0x020 // false: select & insert, true: noinsert +#define COT_NOSELECT 0x040 // false: select & insert, true: noselect +#define COT_FUZZY 0x080 // true: fuzzy match enabled #ifdef BACKSLASH_IN_FILENAME EXTERN char *p_csl; ///< 'completeslash' #endif diff --git a/src/nvim/options.lua b/src/nvim/options.lua index aa43c4cf3d..f323926015 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1466,7 +1466,7 @@ return { expand_cb = 'expand_set_completeopt', full_name = 'completeopt', list = 'onecomma', - scope = { 'global' }, + scope = { 'global', 'buffer' }, short_desc = N_('options for Insert mode completion'), type = 'string', varname = 'p_cot', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 050cb1fe98..4cd830a2fc 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -158,6 +158,7 @@ void didset_string_options(void) opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true); opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true); opt_strings_flags(p_bo, p_bo_values, &bo_flags, true); + opt_strings_flags(p_cot, p_cot_values, &cot_flags, true); opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true); opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true); opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true); @@ -219,6 +220,7 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_ft); check_string_option(&buf->b_p_cinw); check_string_option(&buf->b_p_cinsd); + check_string_option(&buf->b_p_cot); check_string_option(&buf->b_p_cpt); check_string_option(&buf->b_p_cfu); check_string_option(&buf->b_p_ofu); @@ -993,10 +995,23 @@ int expand_set_complete(optexpand_T *args, int *numMatches, char ***matches) /// The 'completeopt' option is changed. const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED) { - if (check_opt_strings(p_cot, p_cot_values, true) != OK) { + buf_T *buf = (buf_T *)args->os_buf; + char *cot = p_cot; + unsigned *flags = &cot_flags; + + if (args->os_flags & OPT_LOCAL) { + cot = buf->b_p_cot; + flags = &buf->b_cot_flags; + } + + if (check_opt_strings(cot, p_cot_values, true) != OK) { return e_invarg; } - completeopt_was_set(); + + if (opt_strings_flags(cot, p_cot_values, flags, true) != OK) { + return e_invarg; + } + return NULL; } diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index bf2fe0f72c..324254a188 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -700,7 +700,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma } // delete the empty last line ml_delete_buf(buf, buf->b_ml.ml_line_count, false); - if (strstr(p_cot, "popup") != NULL) { + if (get_cot_flags() & COT_POPUP) { extmark_splice(buf, 1, 0, 1, 0, 0, buf->b_ml.ml_line_count, 0, inserted_bytes, kExtmarkNoUndo); } } @@ -795,7 +795,8 @@ static bool pum_set_selected(int n, int repeat) int prev_selected = pum_selected; pum_selected = n; - bool use_float = strstr(p_cot, "popup") != NULL; + unsigned cur_cot_flags = get_cot_flags(); + bool use_float = (cur_cot_flags & COT_POPUP) != 0; // when new leader add and info window is shown and no selected we still // need use the first index item to update the info float window position. bool force_select = use_float && pum_selected < 0 && win_float_find_preview(); @@ -861,7 +862,7 @@ static bool pum_set_selected(int n, int repeat) if ((pum_array[pum_selected].pum_info != NULL) && (Rows > 10) && (repeat <= 1) - && (vim_strchr(p_cot, 'p') != NULL)) { + && (cur_cot_flags & COT_ANY_PREVIEW)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; -- cgit From 84ad95fdc9d437fee711b5b8ac0acb6c1c950685 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 6 Jun 2024 13:48:05 +0200 Subject: fix(fileio): copy to correct buffer position when reading fixes #29186 (likely) fixup for #29093 064483a2b --- src/nvim/os/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index c87b2d359f..5f372b2376 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -300,7 +300,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t } else { fp->write_pos += r_ret; size_t to_copy = MIN((size_t)r_ret, read_remaining); - memcpy(ret_buf, fp->read_pos, to_copy); + memcpy(buf, fp->read_pos, to_copy); fp->read_pos += to_copy; read_remaining -= to_copy; } -- cgit From 8c5af0eb85a3932f6ca018d2aa681521369a26be Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Fri, 7 Jun 2024 04:55:14 +0200 Subject: docs: misc (#28837) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danymat Co-authored-by: Gregory Anders Co-authored-by: Jakub Okoński Co-authored-by: John L. Villalovos Co-authored-by: Maria José Solano Co-authored-by: Michaili K Co-authored-by: TheLeoP Co-authored-by: Tobias Schmitz Co-authored-by: W20MC <157727813+W20MC@users.noreply.github.com> Co-authored-by: Will Hopkins Co-authored-by: Yifan Hu <141280278+b0ae989c@users.noreply.github.com> Co-authored-by: glepnir Co-authored-by: prljav <74116121+prljav@users.noreply.github.com> --- src/man/nvim.1 | 4 ++-- src/nvim/api/buffer.c | 6 +++--- src/nvim/api/extmark.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/man/nvim.1 b/src/man/nvim.1 index 4dc099f98c..9b7680d011 100644 --- a/src/man/nvim.1 +++ b/src/man/nvim.1 @@ -387,10 +387,10 @@ features like .El .Sh FILES .Bl -tag -width "~/.config/nvim/init.vim" -.It Pa ~/.config/nvim/init.vim +.It Pa ~/.config/nvim/init.lua User-local .Nm -configuration file. +Lua configuration file. .It Pa ~/.config/nvim User-local .Nm diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index e078d85f33..a0678dc3e4 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1183,12 +1183,12 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena, return rv; } -/// call a function with buffer as temporary current buffer +/// Call a function with buffer as temporary current buffer. /// /// This temporarily switches current buffer to "buffer". -/// If the current window already shows "buffer", the window is not switched +/// If the current window already shows "buffer", the window is not switched. /// If a window inside the current tabpage (including a float) already shows the -/// buffer One of these windows will be set as current window temporarily. +/// buffer, then one of these windows will be set as current window temporarily. /// Otherwise a temporary scratch window (called the "autocmd window" for /// historical reasons) will be used. /// diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 85cce45560..3c8fded2f6 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1038,7 +1038,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// ``` /// - on_win: called when starting to redraw a specific window. /// ``` -/// ["win", winid, bufnr, topline, botline] +/// ["win", winid, bufnr, toprow, botrow] /// ``` /// - on_line: called for each buffer line being redrawn. /// (The interaction with fold lines is subject to change) -- cgit From f3632e14e3a75114415050ab01c2d04a06036009 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:33:40 +0200 Subject: feat: get/set namespace properties #28728 ref https://github.com/neovim/neovim/pull/28432 ref https://github.com/neovim/neovim/issues/28469 --- src/nvim/api/deprecated.c | 2 +- src/nvim/api/extmark.c | 155 +++++++++++++++++++++++++++----------------- src/nvim/api/extmark.h | 15 +++++ src/nvim/api/keysets_defs.h | 5 ++ src/nvim/decoration.c | 8 +-- src/nvim/extmark.c | 4 +- src/nvim/marktree.c | 2 +- src/nvim/marktree.h | 20 +----- src/nvim/plines.c | 3 +- src/nvim/sign.c | 2 +- 10 files changed, 128 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index af3bfe2c03..a1af354577 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -170,7 +170,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A DecorInline decor = { .ext = true, .data.ext.vt = vt, .data.ext.sh_idx = DECOR_ID_INVALID }; extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, 0, true, - false, false, false, false, NULL); + false, false, false, NULL); return src_id; } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 3c8fded2f6..ab6ff5ff1f 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -18,6 +18,7 @@ #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" #include "nvim/extmark.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight_group.h" #include "nvim/map_defs.h" @@ -41,6 +42,7 @@ void api_extmark_free_all_mem(void) xfree(name.data); }) map_destroy(String, &namespace_ids); + set_destroy(uint32_t, &namespace_localscope); } /// Creates a new namespace or gets an existing one. [namespace]() @@ -179,10 +181,6 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na PUT_C(dict, "invalid", BOOLEAN_OBJ(true)); } - if (mt_scoped(start)) { - PUT_C(dict, "scoped", BOOLEAN_OBJ(true)); - } - decor_to_dict_legacy(&dict, mt_decor(start), hl_name, arena); ADD_C(rv, DICTIONARY_OBJ(dict)); @@ -489,8 +487,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// used together with virt_text. /// - url: A URL to associate with this extmark. In the TUI, the OSC 8 control /// sequence is used to generate a clickable hyperlink to this URL. -/// - scoped: boolean (EXPERIMENTAL) enables "scoping" for the extmark. See -/// |nvim__win_add_ns()| /// /// @param[out] err Error details, if any /// @return Id of the created/updated extmark @@ -749,11 +745,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) { - if (opts->scoped) { - api_set_error(err, kErrorTypeException, "not yet implemented"); - goto error; - } - int r = (int)line; int c = (int)col; if (line2 == -1) { @@ -834,7 +825,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2, decor, decor_flags, right_gravity, opts->end_right_gravity, !GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore), - opts->invalidate, opts->scoped, err); + opts->invalidate, err); if (ERROR_SET(err)) { decor_free(decor); return 0; @@ -960,7 +951,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In decor.data.hl.hl_id = hl_id; extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, - decor, MT_FLAG_DECOR_HL, true, false, false, false, false, NULL); + decor, MT_FLAG_DECOR_HL, true, false, false, false, NULL); return ns_id; } @@ -1217,77 +1208,119 @@ String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error /// EXPERIMENTAL: this API will change in the future. /// -/// Scopes a namespace to the a window, so extmarks in the namespace will be active only in the -/// given window. +/// Set some properties for namespace /// -/// @param window Window handle, or 0 for current window /// @param ns_id Namespace -/// @return true if the namespace was added, else false -Boolean nvim__win_add_ns(Window window, Integer ns_id, Error *err) +/// @param opts Optional parameters to set: +/// - wins: a list of windows to be scoped in +/// +void nvim__ns_set(Integer ns_id, Dict(ns_opts) *opts, Error *err) { - win_T *win = find_window_by_handle(window, err); - if (!win) { - return false; - } - VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { - return false; + return; }); - set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id); + bool set_scoped = true; - if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { - changed_window_setting(win); - } + if (HAS_KEY(opts, ns_opts, wins)) { + if (opts->wins.size == 0) { + set_scoped = false; + } - return true; -} + Set(ptr_t) windows = SET_INIT; + for (size_t i = 0; i < opts->wins.size; i++) { + Integer win = opts->wins.items[i].data.integer; -/// EXPERIMENTAL: this API will change in the future. -/// -/// Gets the namespace scopes for a given window. -/// -/// @param window Window handle, or 0 for current window -/// @return a list of namespaces ids -ArrayOf(Integer) nvim__win_get_ns(Window window, Arena *arena, Error *err) -{ - win_T *win = find_window_by_handle(window, err); - if (!win) { - return (Array)ARRAY_DICT_INIT; + win_T *wp = find_window_by_handle((Window)win, err); + if (!wp) { + return; + } + + set_put(ptr_t, &windows, wp); + } + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (set_has(ptr_t, &windows, wp) && !set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) { + set_put(uint32_t, &wp->w_ns_set, (uint32_t)ns_id); + + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + + if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id) && !set_has(ptr_t, &windows, wp)) { + set_del(uint32_t, &wp->w_ns_set, (uint32_t)ns_id); + + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + } + + set_destroy(ptr_t, &windows); } - Array rv = arena_array(arena, set_size(&win->w_ns_set)); - uint32_t i; - set_foreach(&win->w_ns_set, i, { - ADD_C(rv, INTEGER_OBJ((Integer)(i))); - }); + if (set_scoped && !set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) { + set_put(uint32_t, &namespace_localscope, (uint32_t)ns_id); - return rv; + // When a namespace becomes scoped, any window which contains + // elements associated with namespace needs to be redrawn + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + } else if (!set_scoped && set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) { + set_del(uint32_t, &namespace_localscope, (uint32_t)ns_id); + + // When a namespace becomes unscoped, any window which does not + // contain elements associated with namespace needs to be redrawn + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + } } /// EXPERIMENTAL: this API will change in the future. /// -/// Unscopes a namespace (un-binds it from the given scope). +/// Get the properties for namespace /// -/// @param window Window handle, or 0 for current window -/// @param ns_id the namespace to remove -/// @return true if the namespace was removed, else false -Boolean nvim__win_del_ns(Window window, Integer ns_id, Error *err) +/// @param ns_id Namespace +/// @return Map defining the namespace properties, see |nvim__ns_set()| +Dict(ns_opts) nvim__ns_get(Integer ns_id, Arena *arena, Error *err) { - win_T *win = find_window_by_handle(window, err); - if (!win) { - return false; + Dict(ns_opts) opts = KEYDICT_INIT; + + Array windows = ARRAY_DICT_INIT; + + PUT_KEY(opts, ns_opts, wins, windows); + + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { + return opts; + }); + + if (!set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) { + return opts; } - if (!set_has(uint32_t, &win->w_ns_set, (uint32_t)ns_id)) { - return false; + size_t count = 0; + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) { + count++; + } } - set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id); + windows = arena_array(arena, count); - if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { - changed_window_setting(win); + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) { + ADD(windows, INTEGER_OBJ(wp->handle)); + } } - return true; + PUT_KEY(opts, ns_opts, wins, windows); + + return opts; } diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 124feaabfb..af2d51c95c 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -4,14 +4,29 @@ #include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep +#include "nvim/buffer_defs.h" #include "nvim/decoration_defs.h" // IWYU pragma: keep #include "nvim/macros_defs.h" #include "nvim/map_defs.h" #include "nvim/types_defs.h" EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT); +/// Non-global namespaces. A locally-scoped namespace may be "orphaned" if all +/// window(s) it was scoped to, are destroyed. Such orphans are tracked here to +/// avoid being mistaken as "global scope". +EXTERN Set(uint32_t) namespace_localscope INIT( = SET_INIT); EXTERN handle_T next_namespace_id INIT( = 1); +/// Returns true if the namespace is global or scoped in the given window. +static inline bool ns_in_win(uint32_t ns_id, win_T *wp) +{ + if (!set_has(uint32_t, &namespace_localscope, ns_id)) { + return true; + } + + return set_has(uint32_t, &wp->w_ns_set, ns_id); +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/extmark.h.generated.h" #endif diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index 00d8aa8428..cc2ef981b5 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -387,3 +387,8 @@ typedef struct { Window win; Buffer buf; } Dict(redraw); + +typedef struct { + OptionalKeys is_set__ns_opts_; + Array wins; +} Dict(ns_opts); diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 52a3fa5924..0cf02d96da 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -89,7 +89,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start extmark_set(buf, (uint32_t)src_id, NULL, (int)lnum - 1, hl_start, (int)lnum - 1 + end_off, hl_end, - decor, MT_FLAG_DECOR_HL, true, false, true, false, false, NULL); + decor, MT_FLAG_DECOR_HL, true, false, true, false, NULL); } } @@ -598,7 +598,7 @@ int decor_redraw_col(win_T *wp, int col, int win_col, bool hidden, DecorState *s break; } - if (!mt_scoped_in_win(mark, wp)) { + if (!ns_in_win(mark.ns, wp)) { goto next_mark; } @@ -747,7 +747,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], break; } if (!mt_end(mark) && !mt_invalid(mark) && mt_decor_sign(mark) - && mt_scoped_in_win(mark, wp)) { + && ns_in_win(mark.ns, wp)) { DecorSignHighlight *sh = decor_find_sign(mt_decor(mark)); num_text += (sh->text[0] != NUL); kv_push(signs, ((SignItem){ sh, mark.id })); @@ -927,7 +927,7 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo while (true) { MTKey mark = marktree_itr_current(itr); DecorVirtText *vt = mt_decor_virt(mark); - if (mt_scoped_in_win(mark, wp)) { + if (ns_in_win(mark.ns, wp)) { while (vt) { if (vt->flags & kVTIsLines) { bool above = vt->flags & kVTLinesAbove; diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 4e47fa76fe..b592283d92 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -54,12 +54,12 @@ /// must not be used during iteration! void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col, int end_row, colnr_T end_col, DecorInline decor, uint16_t decor_flags, bool right_gravity, - bool end_right_gravity, bool no_undo, bool invalidate, bool scoped, Error *err) + bool end_right_gravity, bool no_undo, bool invalidate, Error *err) { uint32_t *ns = map_put_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL, NULL); uint32_t id = idp ? *idp : 0; - uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext, scoped) | decor_flags; + uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext) | decor_flags; if (id == 0) { id = ++*ns; } else { diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 34d6cd118f..9e3005b6a3 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -2286,7 +2286,7 @@ static void marktree_itr_fix_pos(MarkTree *b, MarkTreeIter *itr) void marktree_put_test(MarkTree *b, uint32_t ns, uint32_t id, int row, int col, bool right_gravity, int end_row, int end_col, bool end_right, bool meta_inline) { - uint16_t flags = mt_flags(right_gravity, false, false, false, false); + uint16_t flags = mt_flags(right_gravity, false, false, false); // The specific choice is irrelevant here, we pick one counted decor // type to test the counting and filtering logic. flags |= meta_inline ? MT_FLAG_DECOR_VIRT_TEXT_INLINE : 0; diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h index 8e5cf30ff3..15df57ef63 100644 --- a/src/nvim/marktree.h +++ b/src/nvim/marktree.h @@ -35,8 +35,6 @@ #define MT_FLAG_DECOR_VIRT_LINES (((uint16_t)1) << 11) #define MT_FLAG_DECOR_VIRT_TEXT_INLINE (((uint16_t)1) << 12) -#define MT_FLAG_SCOPED (((uint16_t)1) << 13) - // These _must_ be last to preserve ordering of marks #define MT_FLAG_RIGHT_GRAVITY (((uint16_t)1) << 14) #define MT_FLAG_LAST (((uint16_t)1) << 15) @@ -46,7 +44,7 @@ | MT_FLAG_DECOR_VIRT_TEXT_INLINE) #define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_NO_UNDO \ - | MT_FLAG_INVALIDATE | MT_FLAG_INVALID | MT_FLAG_SCOPED) + | MT_FLAG_INVALIDATE | MT_FLAG_INVALID) // this is defined so that start and end of the same range have adjacent ids #define MARKTREE_END_FLAG ((uint64_t)1) @@ -110,24 +108,12 @@ static inline bool mt_decor_sign(MTKey key) return key.flags & (MT_FLAG_DECOR_SIGNTEXT | MT_FLAG_DECOR_SIGNHL); } -static inline bool mt_scoped(MTKey key) -{ - return key.flags & MT_FLAG_SCOPED; -} - -static inline bool mt_scoped_in_win(MTKey key, win_T *wp) -{ - return !mt_scoped(key) || set_has(uint32_t, &wp->w_ns_set, key.ns); -} - -static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext, - bool scoped) +static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext) { return (uint16_t)((right_gravity ? MT_FLAG_RIGHT_GRAVITY : 0) | (no_undo ? MT_FLAG_NO_UNDO : 0) | (invalidate ? MT_FLAG_INVALIDATE : 0) - | (decor_ext ? MT_FLAG_DECOR_EXT : 0) - | (scoped ? MT_FLAG_SCOPED : 0)); + | (decor_ext ? MT_FLAG_DECOR_EXT : 0)); } static inline MTPair mtpair_from(MTKey start, MTKey end) diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 5881d34c48..f273f88dd1 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -5,6 +5,7 @@ #include #include +#include "nvim/api/extmark.h" #include "nvim/ascii_defs.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" @@ -158,7 +159,7 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco break; } else if (mark.pos.col == col) { if (!mt_end(mark) && (mark.flags & MT_FLAG_DECOR_VIRT_TEXT_INLINE) - && mt_scoped_in_win(mark, wp)) { + && ns_in_win(mark.ns, wp)) { DecorInline decor = mt_decor(mark); DecorVirtText *vt = decor.ext ? decor.data.ext.vt : NULL; while (vt) { diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 496913f9bf..1ca0e846a9 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -127,7 +127,7 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } }; extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, decor, decor_flags, true, - false, true, true, false, NULL); + false, true, true, NULL); } /// For an existing, placed sign with "id", modify the sign, group or priority. -- cgit From 4881211097aba7f5d17700362ec0967e3024f074 Mon Sep 17 00:00:00 2001 From: James <89495599+IAKOBVS@users.noreply.github.com> Date: Sat, 8 Jun 2024 09:12:39 +0700 Subject: refactor: quadratic behavior in vim_findfile_stopdir (#29232) Copies characters in-places instead. Related #27827 --- src/nvim/file_search.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 51bea3111c..30a80773e3 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -505,24 +505,36 @@ error_return: /// @return the stopdir string. Check that ';' is not escaped. char *vim_findfile_stopdir(char *buf) { - char *r_ptr = buf; - - while (*r_ptr != NUL && *r_ptr != ';') { - if (r_ptr[0] == '\\' && r_ptr[1] == ';') { - // Overwrite the escape char, - // use strlen(r_ptr) to move the trailing NUL. - STRMOVE(r_ptr, r_ptr + 1); - r_ptr++; + for (; *buf != NUL && *buf != ';' && (buf[0] != '\\' || buf[1] != ';'); buf++) {} + char *dst = buf; + if (*buf == ';') { + goto is_semicolon; + } + if (*buf == NUL) { + goto is_nul; + } + goto start; + while (*buf != NUL && *buf != ';') { + if (buf[0] == '\\' && buf[1] == ';') { +start: + // Overwrite the escape char. + *dst++ = ';'; + buf += 2; + } else { + *dst++ = *buf++; } - r_ptr++; } - if (*r_ptr == ';') { - *r_ptr = 0; - r_ptr++; - } else if (*r_ptr == NUL) { - r_ptr = NULL; + assert(dst < buf); + *dst = NUL; + if (*buf == ';') { +is_semicolon: + *buf = NUL; + buf++; + } else { // if (*buf == NUL) +is_nul: + buf = NULL; } - return r_ptr; + return buf; } /// Clean up the given search context. Can handle a NULL pointer. -- cgit From 78d21593a35cf89692224f1000a04d3c9fff8add Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 31 May 2024 14:40:53 +0200 Subject: refactor(io): make rstream use a linear buffer If you like it you shouldn't put a ring on it. This is what _every_ consumer of RStream used anyway, either by calling rbuffer_reset, or rbuffer_consumed_compact (same as rbuffer_reset without needing a scratch buffer), or by consuming everything in each stream_read_cb call directly. --- src/nvim/channel.c | 50 ++++----- src/nvim/event/defs.h | 16 ++- src/nvim/event/process.c | 3 +- src/nvim/event/rstream.c | 163 ++++++++++++++++------------- src/nvim/event/stream.c | 3 +- src/nvim/msgpack_rpc/channel.c | 36 +++---- src/nvim/os/fileio.c | 2 - src/nvim/os/fileio_defs.h | 1 - src/nvim/os/input.c | 16 ++- src/nvim/os/shell.c | 45 +++----- src/nvim/rbuffer.c | 230 ----------------------------------------- src/nvim/rbuffer.h | 71 ------------- src/nvim/rbuffer_defs.h | 45 -------- src/nvim/tui/input.c | 146 +++++++++++++------------- src/nvim/tui/input.h | 9 +- 15 files changed, 240 insertions(+), 596 deletions(-) delete mode 100644 src/nvim/rbuffer.c delete mode 100644 src/nvim/rbuffer.h delete mode 100644 src/nvim/rbuffer_defs.h (limited to 'src') diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 05225cecd0..5f9bfc3a73 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -39,8 +39,6 @@ #include "nvim/os/os_defs.h" #include "nvim/os/shell.h" #include "nvim/path.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/terminal.h" #include "nvim/types_defs.h" @@ -432,7 +430,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s wstream_init(&proc->in, 0); } if (has_out) { - rstream_init(&proc->out, 0); + rstream_init(&proc->out); } if (rpc) { @@ -447,7 +445,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s if (has_err) { callback_reader_start(&chan->on_stderr, "stderr"); - rstream_init(&proc->err, 0); + rstream_init(&proc->err); rstream_start(&proc->err, on_job_stderr, chan); } @@ -484,7 +482,7 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader channel->stream.socket.s.internal_close_cb = close_cb; channel->stream.socket.s.internal_data = channel; wstream_init(&channel->stream.socket.s, 0); - rstream_init(&channel->stream.socket, 0); + rstream_init(&channel->stream.socket); if (rpc) { rpc_start(channel); @@ -509,7 +507,7 @@ void channel_from_connection(SocketWatcher *watcher) channel->stream.socket.s.internal_close_cb = close_cb; channel->stream.socket.s.internal_data = channel; wstream_init(&channel->stream.socket.s, 0); - rstream_init(&channel->stream.socket, 0); + rstream_init(&channel->stream.socket); rpc_start(channel); channel_create_event(channel, watcher->addr); } @@ -554,7 +552,7 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **err dup2(STDERR_FILENO, STDIN_FILENO); } #endif - rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd, 0); + rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd); wstream_init_fd(&main_loop, &channel->stream.stdio.out, stdout_dup_fd, 0); if (rpc) { @@ -648,51 +646,38 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) return l; } -void on_channel_data(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) +size_t on_channel_data(RStream *stream, const char *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, eof, &chan->on_data); + return on_channel_output(stream, chan, buf, count, eof, &chan->on_data); } -void on_job_stderr(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) +size_t on_job_stderr(RStream *stream, const char *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, eof, &chan->on_stderr); + return on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr); } -static void on_channel_output(RStream *stream, Channel *chan, RBuffer *buf, bool eof, - CallbackReader *reader) +static size_t on_channel_output(RStream *stream, Channel *chan, const char *buf, size_t count, + bool eof, CallbackReader *reader) { - size_t count; - char *output = rbuffer_read_ptr(buf, &count); - if (chan->term) { - if (!eof) { - char *p = output; - char *end = output + count; + if (count) { + const char *p = buf; + const char *end = buf + count; while (p < end) { // Don't pass incomplete UTF-8 sequences to libvterm. #16245 // Composing chars can be passed separately, so utf_ptr2len_len() is enough. int clen = utf_ptr2len_len(p, (int)(end - p)); if (clen > end - p) { - count = (size_t)(p - output); + count = (size_t)(p - buf); break; } p += clen; } } - terminal_receive(chan->term, output, count); - } - - if (count) { - rbuffer_consumed(buf, count); - } - // Move remaining data to start of buffer, so the buffer can never wrap around. - rbuffer_reset(buf); - - if (callback_reader_set(*reader)) { - ga_concat_len(&reader->buffer, output, count); + terminal_receive(chan->term, buf, count); } if (eof) { @@ -700,8 +685,11 @@ static void on_channel_output(RStream *stream, Channel *chan, RBuffer *buf, bool } if (callback_reader_set(*reader)) { + ga_concat_len(&reader->buffer, buf, count); schedule_channel_event(chan); } + + return count; } /// schedule the necessary callbacks to be invoked as a deferred event diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h index 8563006159..41690ead88 100644 --- a/src/nvim/event/defs.h +++ b/src/nvim/event/defs.h @@ -6,7 +6,6 @@ #include #include "nvim/eval/typval_defs.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" enum { EVENT_HANDLER_MAX_ARGC = 10, }; @@ -59,11 +58,13 @@ typedef struct rstream RStream; /// Type of function called when the RStream buffer is filled with data /// /// @param stream The Stream instance -/// @param buf The associated RBuffer instance +/// @param read_data data that was read /// @param count Number of bytes that was read. /// @param data User-defined data /// @param eof If the stream reached EOF. -typedef void (*stream_read_cb)(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof); +/// @return number of bytes which were consumed +typedef size_t (*stream_read_cb)(RStream *stream, const char *read_data, size_t count, void *data, + bool eof); /// Type of function called when the Stream has information about a write /// request. @@ -102,11 +103,16 @@ struct stream { struct rstream { Stream s; bool did_eof; - RBuffer *buffer; + bool want_read; + bool pending_read; + bool paused_full; + char *buffer; // ARENA_BLOCK_SIZE + char *read_pos; + char *write_pos; uv_buf_t uvbuf; stream_read_cb read_cb; size_t num_bytes; - size_t fpos; + int64_t fpos; }; #define ADDRESS_MAX_SIZE 256 diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 710376cd62..70fc31ba21 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -18,7 +18,6 @@ #include "nvim/os/pty_process.h" #include "nvim/os/shell.h" #include "nvim/os/time.h" -#include "nvim/rbuffer_defs.h" #include "nvim/ui_client.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -355,7 +354,7 @@ static void flush_stream(Process *proc, RStream *stream) int err = uv_recv_buffer_size((uv_handle_t *)&stream->s.uv.pipe, &system_buffer_size); if (err) { - system_buffer_size = (int)rbuffer_capacity(stream->buffer); + system_buffer_size = ARENA_BLOCK_SIZE; } size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size; diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index 6c7fa20bd8..71290d0c0d 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -11,38 +11,44 @@ #include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/os/os_defs.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/rstream.c.generated.h" #endif -void rstream_init_fd(Loop *loop, RStream *stream, int fd, size_t bufsize) +void rstream_init_fd(Loop *loop, RStream *stream, int fd) FUNC_ATTR_NONNULL_ARG(1, 2) { stream_init(loop, &stream->s, fd, NULL); - rstream_init(stream, bufsize); + rstream_init(stream); } -void rstream_init_stream(RStream *stream, uv_stream_t *uvstream, size_t bufsize) +void rstream_init_stream(RStream *stream, uv_stream_t *uvstream) FUNC_ATTR_NONNULL_ARG(1, 2) { stream_init(NULL, &stream->s, -1, uvstream); - rstream_init(stream, bufsize); + rstream_init(stream); } -void rstream_init(RStream *stream, size_t bufsize) +void rstream_init(RStream *stream) FUNC_ATTR_NONNULL_ARG(1) { stream->fpos = 0; stream->read_cb = NULL; stream->num_bytes = 0; - stream->buffer = rbuffer_new(bufsize); - stream->buffer->data = stream; - stream->buffer->full_cb = on_rbuffer_full; - stream->buffer->nonfull_cb = on_rbuffer_nonfull; + stream->buffer = alloc_block(); + stream->read_pos = stream->write_pos = stream->buffer; +} + +void rstream_start_inner(RStream *stream) + FUNC_ATTR_NONNULL_ARG(1) +{ + if (stream->s.uvstream) { + uv_read_start(stream->s.uvstream, alloc_cb, read_cb); + } else { + uv_idle_start(&stream->s.uv.idle, fread_idle_cb); + } } /// Starts watching for events from a `Stream` instance. @@ -53,17 +59,16 @@ void rstream_start(RStream *stream, stream_read_cb cb, void *data) { stream->read_cb = cb; stream->s.cb_data = data; - if (stream->s.uvstream) { - uv_read_start(stream->s.uvstream, alloc_cb, read_cb); - } else { - uv_idle_start(&stream->s.uv.idle, fread_idle_cb); + stream->want_read = true; + if (!stream->paused_full) { + rstream_start_inner(stream); } } /// Stops watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance -void rstream_stop(RStream *stream) +void rstream_stop_inner(RStream *stream) FUNC_ATTR_NONNULL_ALL { if (stream->s.uvstream) { @@ -73,16 +78,14 @@ void rstream_stop(RStream *stream) } } -static void on_rbuffer_full(RBuffer *buf, void *data) -{ - rstream_stop(data); -} - -static void on_rbuffer_nonfull(RBuffer *buf, void *data) +/// Stops watching for events from a `Stream` instance. +/// +/// @param stream The `Stream` instance +void rstream_stop(RStream *stream) + FUNC_ATTR_NONNULL_ALL { - RStream *stream = data; - assert(stream->read_cb); - rstream_start(stream, stream->read_cb, stream->s.cb_data); + rstream_stop_inner(stream); + stream->want_read = false; } // Callbacks used by libuv @@ -91,10 +94,9 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data) static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) { RStream *stream = handle->data; - // `uv_buf_t.len` happens to have different size on Windows. - size_t write_count; - buf->base = rbuffer_write_ptr(stream->buffer, &write_count); - buf->len = UV_BUF_LEN(write_count); + buf->base = stream->write_pos; + // `uv_buf_t.len` happens to have different size on Windows (as a treat) + buf->len = UV_BUF_LEN(rstream_space(stream)); } /// Callback invoked by libuv after it copies the data into the buffer provided @@ -108,21 +110,21 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) // cnt == 0 means libuv asked for a buffer and decided it wasn't needed: // http://docs.libuv.org/en/latest/stream.html#c.uv_read_start. // - // We don't need to do anything with the RBuffer because the next call + // We don't need to do anything with the buffer because the next call // to `alloc_cb` will return the same unused pointer (`rbuffer_produced` // won't be called) if (cnt == UV_ENOBUFS || cnt == 0) { return; } else if (cnt == UV_EOF && uvstream->type == UV_TTY) { // The TTY driver might signal EOF without closing the stream - invoke_read_cb(stream, 0, true); + invoke_read_cb(stream, true); } else { DLOG("closing Stream (%p): %s (%s)", (void *)stream, uv_err_name((int)cnt), os_strerror((int)cnt)); // Read error or EOF, either way stop the stream and invoke the callback // with eof == true uv_read_stop(uvstream); - invoke_read_cb(stream, 0, true); + invoke_read_cb(stream, true); } return; } @@ -130,10 +132,13 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) // at this point we're sure that cnt is positive, no error occurred size_t nread = (size_t)cnt; stream->num_bytes += nread; - // Data was already written, so all we need is to update 'wpos' to reflect - // the space actually used in the buffer. - rbuffer_produced(stream->buffer, nread); - invoke_read_cb(stream, nread, false); + stream->write_pos += cnt; + invoke_read_cb(stream, false); +} + +static size_t rstream_space(RStream *stream) +{ + return (size_t)((stream->buffer + ARENA_BLOCK_SIZE) - stream->write_pos); } /// Called by the by the 'idle' handle to emulate a reading event @@ -146,52 +151,37 @@ static void fread_idle_cb(uv_idle_t *handle) uv_fs_t req; RStream *stream = handle->data; + stream->uvbuf.base = stream->write_pos; // `uv_buf_t.len` happens to have different size on Windows. - size_t write_count; - stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &write_count); - stream->uvbuf.len = UV_BUF_LEN(write_count); - - // the offset argument to uv_fs_read is int64_t, could someone really try - // to read more than 9 quintillion (9e18) bytes? - // upcast is meant to avoid tautological condition warning on 32 bits - uintmax_t fpos_intmax = stream->fpos; - if (fpos_intmax > INT64_MAX) { - ELOG("stream offset overflow"); - preserve_exit("stream offset overflow"); - } + stream->uvbuf.len = UV_BUF_LEN(rstream_space(stream)); // Synchronous read - uv_fs_read(handle->loop, - &req, - stream->s.fd, - &stream->uvbuf, - 1, - (int64_t)stream->fpos, - NULL); + uv_fs_read(handle->loop, &req, stream->s.fd, &stream->uvbuf, 1, stream->fpos, NULL); uv_fs_req_cleanup(&req); if (req.result <= 0) { uv_idle_stop(&stream->s.uv.idle); - invoke_read_cb(stream, 0, true); + invoke_read_cb(stream, true); return; } - // no errors (req.result (ssize_t) is positive), it's safe to cast. - size_t nread = (size_t)req.result; - rbuffer_produced(stream->buffer, nread); - stream->fpos += nread; - invoke_read_cb(stream, nread, false); + // no errors (req.result (ssize_t) is positive), it's safe to use. + stream->write_pos += req.result; + stream->fpos += req.result; + invoke_read_cb(stream, false); } static void read_event(void **argv) { RStream *stream = argv[0]; + stream->pending_read = false; if (stream->read_cb) { - size_t count = (uintptr_t)argv[1]; - bool eof = (uintptr_t)argv[2]; - stream->did_eof = eof; - stream->read_cb(stream, stream->buffer, count, stream->s.cb_data, eof); + size_t available = rstream_available(stream); + size_t consumed = stream->read_cb(stream, stream->read_pos, available, stream->s.cb_data, + stream->did_eof); + assert(consumed <= available); + rstream_consume(stream, consumed); } stream->s.pending_reqs--; if (stream->s.closed && !stream->s.pending_reqs) { @@ -199,13 +189,48 @@ static void read_event(void **argv) } } -static void invoke_read_cb(RStream *stream, size_t count, bool eof) +size_t rstream_available(RStream *stream) { + return (size_t)(stream->write_pos - stream->read_pos); +} + +void rstream_consume(RStream *stream, size_t consumed) +{ + stream->read_pos += consumed; + size_t remaining = (size_t)(stream->write_pos - stream->read_pos); + if (remaining > 0 && stream->read_pos > stream->buffer) { + memmove(stream->buffer, stream->read_pos, remaining); + stream->read_pos = stream->buffer; + stream->write_pos = stream->buffer + remaining; + } else if (remaining == 0) { + stream->read_pos = stream->write_pos = stream->buffer; + } + + if (stream->want_read && stream->paused_full && rstream_space(stream)) { + assert(stream->read_cb); + stream->paused_full = false; + rstream_start_inner(stream); + } +} + +static void invoke_read_cb(RStream *stream, bool eof) +{ + stream->did_eof |= eof; + + if (!rstream_space(stream)) { + rstream_stop_inner(stream); + stream->paused_full = true; + } + + // we cannot use pending_reqs as a socket can have both pending reads and writes + if (stream->pending_read) { + return; + } + // Don't let the stream be closed before the event is processed. stream->s.pending_reqs++; - - CREATE_EVENT(stream->s.events, read_event, - stream, (void *)(uintptr_t *)count, (void *)(uintptr_t)eof); + stream->pending_read = true; + CREATE_EVENT(stream->s.events, read_event, stream); } void rstream_may_close(RStream *stream) diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 3d26dd868f..bc1b503f4c 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -8,7 +8,6 @@ #include "nvim/event/loop.h" #include "nvim/event/stream.h" #include "nvim/log.h" -#include "nvim/rbuffer.h" #include "nvim/types_defs.h" #ifdef MSWIN # include "nvim/os/os_win_console.h" @@ -149,7 +148,7 @@ static void rstream_close_cb(uv_handle_t *handle) { RStream *stream = handle->data; if (stream->buffer) { - rbuffer_free(stream->buffer); + free_block(stream->buffer); } close_cb(handle); } diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 98d5d8c6cb..6a0dc10214 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -31,8 +31,6 @@ #include "nvim/msgpack_rpc/packer.h" #include "nvim/msgpack_rpc/unpacker.h" #include "nvim/os/input.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/ui_client.h" @@ -202,10 +200,25 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem return frame.errored ? NIL : frame.result; } -static void receive_msgpack(RStream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) +static size_t receive_msgpack(RStream *stream, const char *rbuf, size_t c, void *data, bool eof) { Channel *channel = data; channel_incref(channel); + size_t consumed = 0; + + DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p", + channel->id, c, (void *)stream); + + if (c > 0) { + Unpacker *p = channel->rpc.unpacker; + p->read_ptr = rbuf; + p->read_size = c; + parse_msgpack(channel); + + if (!unpacker_closed(p)) { + consumed = c - p->read_size; + } + } if (eof) { channel_close(channel->id, kChannelPartRpc, NULL); @@ -213,25 +226,10 @@ static void receive_msgpack(RStream *stream, RBuffer *rbuf, size_t c, void *data snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client", channel->id); chan_close_with_error(channel, buf, LOGLVL_INF); - goto end; - } - - DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p", - channel->id, rbuffer_size(rbuf), (void *)stream); - - Unpacker *p = channel->rpc.unpacker; - size_t size = 0; - p->read_ptr = rbuffer_read_ptr(rbuf, &size); - p->read_size = size; - parse_msgpack(channel); - - if (!unpacker_closed(p)) { - size_t consumed = size - p->read_size; - rbuffer_consumed_compact(rbuf, consumed); } -end: channel_decref(channel); + return consumed; } static ChannelCallFrame *find_call_frame(RpcState *rpc, uint32_t request_id) diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index 5f372b2376..585c4964e2 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -21,8 +21,6 @@ #include "nvim/os/fileio.h" #include "nvim/os/fs.h" #include "nvim/os/os_defs.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" #ifdef HAVE_SYS_UIO_H diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h index 63b6f51c17..0f76fdb2aa 100644 --- a/src/nvim/os/fileio_defs.h +++ b/src/nvim/os/fileio_defs.h @@ -4,7 +4,6 @@ #include #include "nvim/func_attr.h" -#include "nvim/rbuffer_defs.h" /// Structure used to read from/write to file typedef struct { diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 63eca0b6da..ea21a32230 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -27,8 +27,6 @@ #include "nvim/os/os_defs.h" #include "nvim/os/time.h" #include "nvim/profile.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/state.h" #include "nvim/state_defs.h" @@ -62,7 +60,7 @@ void input_start(void) } used_stdin = true; - rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE); + rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO); rstream_start(&read_stream, input_read_cb, NULL); } @@ -157,7 +155,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e if (maxlen && input_available()) { restart_cursorhold_wait(tb_change_cnt); - // Safe to convert rbuffer_read to int, it will never overflow since + // Safe to convert `to_read` to int, it will never overflow since // INPUT_BUFFER_SIZE fits in an int size_t to_read = MIN((size_t)maxlen, input_available()); memcpy(buf, input_read_pos, to_read); @@ -497,17 +495,15 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events) return input_eof ? kInputEof : kInputNone; } -static void input_read_cb(RStream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) +static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof) { if (at_eof) { input_eof = true; } - assert(input_space() >= rbuffer_size(buf)); - RBUFFER_UNTIL_EMPTY(buf, ptr, len) { - input_enqueue_raw(ptr, len); - rbuffer_consumed(buf, len); - } + assert(input_space() >= c); + input_enqueue_raw(buf, c); + return c; } static void process_ctrl_c(void) diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 026f14ebc8..ee9b6ec68c 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -40,8 +40,6 @@ #include "nvim/path.h" #include "nvim/pos_defs.h" #include "nvim/profile.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/state_defs.h" #include "nvim/strings.h" #include "nvim/tag.h" @@ -907,9 +905,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu if (has_input) { wstream_init(&proc->in, 0); } - rstream_init(&proc->out, 0); + rstream_init(&proc->out); rstream_start(&proc->out, data_cb, &buf); - rstream_init(&proc->err, 0); + rstream_init(&proc->err); rstream_start(&proc->err, data_cb, &buf); // write the input, if any @@ -988,14 +986,14 @@ static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired) buf->data = xrealloc(buf->data, buf->cap); } -static void system_data_cb(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) +static size_t system_data_cb(RStream *stream, const char *buf, size_t count, void *data, bool eof) { DynamicBuffer *dbuf = data; - size_t nread = buf->size; - dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1); - rbuffer_read(buf, dbuf->data + dbuf->len, nread); - dbuf->len += nread; + dynamic_buffer_ensure(dbuf, dbuf->len + count + 1); + memcpy(dbuf->data + dbuf->len, buf, count); + dbuf->len += count; + return count; } /// Tracks output received for the current executing shell command, and displays @@ -1078,7 +1076,7 @@ static bool out_data_decide_throttle(size_t size) /// /// @param output Data to save, or NULL to invoke a special mode. /// @param size Length of `output`. -static void out_data_ring(char *output, size_t size) +static void out_data_ring(const char *output, size_t size) { #define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2) static char last_skipped[MAX_CHUNK_SIZE]; // Saved output. @@ -1120,11 +1118,11 @@ static void out_data_ring(char *output, size_t size) /// @param output Data to append to screen lines. /// @param count Size of data. /// @param eof If true, there will be no more data output. -static void out_data_append_to_screen(char *output, size_t *count, bool eof) +static void out_data_append_to_screen(const char *output, size_t *count, bool eof) FUNC_ATTR_NONNULL_ALL { - char *p = output; - char *end = output + *count; + const char *p = output; + const char *end = output + *count; while (p < end) { if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) { msg_putchar_attr((uint8_t)(*p), 0); @@ -1152,25 +1150,16 @@ end: ui_flush(); } -static void out_data_cb(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) +static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *data, bool eof) { - size_t cnt; - char *ptr = rbuffer_read_ptr(buf, &cnt); - - if (ptr != NULL && cnt > 0 - && out_data_decide_throttle(cnt)) { // Skip output above a threshold. + if (count > 0 && out_data_decide_throttle(count)) { // Skip output above a threshold. // Save the skipped output. If it is the final chunk, we display it later. - out_data_ring(ptr, cnt); - } else if (ptr != NULL) { - out_data_append_to_screen(ptr, &cnt, eof); - } - - if (cnt) { - rbuffer_consumed(buf, cnt); + out_data_ring(ptr, count); + } else if (count > 0) { + out_data_append_to_screen(ptr, &count, eof); } - // Move remaining data to start of buffer, so the buffer can never wrap around. - rbuffer_reset(buf); + return count; } /// Parses a command string into a sequence of words, taking quotes into diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c deleted file mode 100644 index 493c079d4c..0000000000 --- a/src/nvim/rbuffer.c +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include -#include - -#include "nvim/macros_defs.h" -#include "nvim/memory.h" -#include "nvim/rbuffer.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "rbuffer.c.generated.h" -#endif - -/// Creates a new `RBuffer` instance. -RBuffer *rbuffer_new(size_t capacity) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET -{ - if (!capacity) { - capacity = 0x10000; - } - - RBuffer *rv = xcalloc(1, sizeof(RBuffer) + capacity); - rv->full_cb = rv->nonfull_cb = NULL; - rv->data = NULL; - rv->size = 0; - rv->write_ptr = rv->read_ptr = rv->start_ptr; - rv->end_ptr = rv->start_ptr + capacity; - rv->temp = NULL; - return rv; -} - -void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL -{ - xfree(buf->temp); - xfree(buf); -} - -/// Return a pointer to a raw buffer containing the first empty slot available -/// for writing. The second argument is a pointer to the maximum number of -/// bytes that could be written. -/// -/// It is necessary to call this function twice to ensure all empty space was -/// used. See RBUFFER_UNTIL_FULL for a macro that simplifies this task. -char *rbuffer_write_ptr(RBuffer *buf, size_t *write_count) FUNC_ATTR_NONNULL_ALL -{ - if (buf->size == rbuffer_capacity(buf)) { - *write_count = 0; - return NULL; - } - - if (buf->write_ptr >= buf->read_ptr) { - *write_count = (size_t)(buf->end_ptr - buf->write_ptr); - } else { - *write_count = (size_t)(buf->read_ptr - buf->write_ptr); - } - - return buf->write_ptr; -} - -// Reset an RBuffer so read_ptr is at the beginning of the memory. If -// necessary, this moves existing data by allocating temporary memory. -void rbuffer_reset(RBuffer *buf) FUNC_ATTR_NONNULL_ALL -{ - size_t temp_size; - if ((temp_size = rbuffer_size(buf))) { - if (buf->temp == NULL) { - buf->temp = xcalloc(1, rbuffer_capacity(buf)); - } - rbuffer_read(buf, buf->temp, buf->size); - } - buf->read_ptr = buf->write_ptr = buf->start_ptr; - if (temp_size) { - rbuffer_write(buf, buf->temp, temp_size); - } -} - -/// Adjust `rbuffer` write pointer to reflect produced data. This is called -/// automatically by `rbuffer_write`, but when using `rbuffer_write_ptr` -/// directly, this needs to called after the data was copied to the internal -/// buffer. The write pointer will be wrapped if required. -void rbuffer_produced(RBuffer *buf, size_t count) FUNC_ATTR_NONNULL_ALL -{ - assert(count && count <= rbuffer_space(buf)); - - buf->write_ptr += count; - if (buf->write_ptr >= buf->end_ptr) { - // wrap around - buf->write_ptr -= rbuffer_capacity(buf); - } - - buf->size += count; - if (buf->full_cb && !rbuffer_space(buf)) { - buf->full_cb(buf, buf->data); - } -} - -/// Return a pointer to a raw buffer containing the first byte available -/// for reading. The second argument is a pointer to the maximum number of -/// bytes that could be read. -/// -/// It is necessary to call this function twice to ensure all available bytes -/// were read. See RBUFFER_UNTIL_EMPTY for a macro that simplifies this task. -char *rbuffer_read_ptr(RBuffer *buf, size_t *read_count) FUNC_ATTR_NONNULL_ALL -{ - if (!buf->size) { - *read_count = 0; - return buf->read_ptr; - } - - if (buf->read_ptr < buf->write_ptr) { - *read_count = (size_t)(buf->write_ptr - buf->read_ptr); - } else { - *read_count = (size_t)(buf->end_ptr - buf->read_ptr); - } - - return buf->read_ptr; -} - -/// Adjust `rbuffer` read pointer to reflect consumed data. This is called -/// automatically by `rbuffer_read`, but when using `rbuffer_read_ptr` -/// directly, this needs to called after the data was copied from the internal -/// buffer. The read pointer will be wrapped if required. -void rbuffer_consumed(RBuffer *buf, size_t count) - FUNC_ATTR_NONNULL_ALL -{ - if (count == 0) { - return; - } - assert(count <= buf->size); - - buf->read_ptr += count; - if (buf->read_ptr >= buf->end_ptr) { - buf->read_ptr -= rbuffer_capacity(buf); - } - - bool was_full = buf->size == rbuffer_capacity(buf); - buf->size -= count; - if (buf->nonfull_cb && was_full) { - buf->nonfull_cb(buf, buf->data); - } -} - -/// Use instead of rbuffer_consumed to use rbuffer in a linear, non-cyclic fashion. -/// -/// This is generally useful if we can guarantee to parse all input -/// except some small incomplete token, like when parsing msgpack. -void rbuffer_consumed_compact(RBuffer *buf, size_t count) - FUNC_ATTR_NONNULL_ALL -{ - assert(buf->read_ptr <= buf->write_ptr); - rbuffer_consumed(buf, count); - if (buf->read_ptr > buf->start_ptr) { - assert((size_t)(buf->write_ptr - buf->read_ptr) == buf->size - || buf->write_ptr == buf->start_ptr); - memmove(buf->start_ptr, buf->read_ptr, buf->size); - buf->read_ptr = buf->start_ptr; - buf->write_ptr = buf->read_ptr + buf->size; - } -} - -// Higher level functions for copying from/to RBuffer instances and data -// pointers -size_t rbuffer_write(RBuffer *buf, const char *src, size_t src_size) - FUNC_ATTR_NONNULL_ALL -{ - size_t size = src_size; - - RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { - size_t copy_count = MIN(src_size, wcnt); - memcpy(wptr, src, copy_count); - rbuffer_produced(buf, copy_count); - - if (!(src_size -= copy_count)) { - return size; - } - - src += copy_count; - } - - return size - src_size; -} - -size_t rbuffer_read(RBuffer *buf, char *dst, size_t dst_size) - FUNC_ATTR_NONNULL_ALL -{ - size_t size = dst_size; - - RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) { - size_t copy_count = MIN(dst_size, rcnt); - memcpy(dst, rptr, copy_count); - rbuffer_consumed(buf, copy_count); - - if (!(dst_size -= copy_count)) { - return size; - } - - dst += copy_count; - } - - return size - dst_size; -} - -char *rbuffer_get(RBuffer *buf, size_t index) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET -{ - assert(index < buf->size); - char *rptr = buf->read_ptr + index; - if (rptr >= buf->end_ptr) { - rptr -= rbuffer_capacity(buf); - } - return rptr; -} - -int rbuffer_cmp(RBuffer *buf, const char *str, size_t count) - FUNC_ATTR_NONNULL_ALL -{ - assert(count <= buf->size); - size_t rcnt; - rbuffer_read_ptr(buf, &rcnt); - size_t n = MIN(count, rcnt); - int rv = memcmp(str, buf->read_ptr, n); - count -= n; - size_t remaining = buf->size - rcnt; - - if (rv || !count || !remaining) { - return rv; - } - - return memcmp(str + n, buf->start_ptr, count); -} diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h deleted file mode 100644 index 942e1f2365..0000000000 --- a/src/nvim/rbuffer.h +++ /dev/null @@ -1,71 +0,0 @@ -// Specialized ring buffer. This is basically an array that wraps read/write -// pointers around the memory region. It should be more efficient than the old -// RBuffer which required memmove() calls to relocate read/write positions. -// -// The main purpose of RBuffer is simplify memory management when reading from -// uv_stream_t instances: -// -// - The event loop writes data to a RBuffer, advancing the write pointer -// - The main loop reads data, advancing the read pointer -// - If the buffer becomes full(size == capacity) the rstream is temporarily -// stopped(automatic backpressure handling) -// -// Reference: http://en.wikipedia.org/wiki/Circular_buffer -#pragma once - -#include -#include - -#include "nvim/rbuffer_defs.h" // IWYU pragma: keep - -// Macros that simplify working with the read/write pointers directly by hiding -// ring buffer wrap logic. Some examples: -// -// - Pass the write pointer to a function(write_data) that incrementally -// produces data, returning the number of bytes actually written to the -// ring buffer: -// -// RBUFFER_UNTIL_FULL(rbuf, ptr, cnt) -// rbuffer_produced(rbuf, write_data(state, ptr, cnt)); -// -// - Pass the read pointer to a function(read_data) that incrementally -// consumes data, returning the number of bytes actually read from the -// ring buffer: -// -// RBUFFER_UNTIL_EMPTY(rbuf, ptr, cnt) -// rbuffer_consumed(rbuf, read_data(state, ptr, cnt)); -// -// Note that the rbuffer_{produced,consumed} calls are necessary or these macros -// create infinite loops -#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \ - for (size_t rcnt = 0, _r = 1; _r; _r = 0) \ - for (char *rptr = rbuffer_read_ptr(buf, &rcnt); \ - buf->size; \ - rptr = rbuffer_read_ptr(buf, &rcnt)) - -#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \ - for (size_t wcnt = 0, _r = 1; _r; _r = 0) \ - for (char *wptr = rbuffer_write_ptr(buf, &wcnt); \ - rbuffer_space(buf); \ - wptr = rbuffer_write_ptr(buf, &wcnt)) - -// Iteration -#define RBUFFER_EACH(buf, c, i) \ - for (size_t i = 0; \ - i < buf->size; \ - i = buf->size) \ - for (char c = 0; \ - i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ - i++) - -#define RBUFFER_EACH_REVERSE(buf, c, i) \ - for (size_t i = buf->size; \ - i != SIZE_MAX; \ - i = SIZE_MAX) \ - for (char c = 0; \ - i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ - ) - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "rbuffer.h.generated.h" -#endif diff --git a/src/nvim/rbuffer_defs.h b/src/nvim/rbuffer_defs.h deleted file mode 100644 index 51dc349846..0000000000 --- a/src/nvim/rbuffer_defs.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -#include "nvim/func_attr.h" - -typedef struct rbuffer RBuffer; -/// Type of function invoked during certain events: -/// - When the RBuffer switches to the full state -/// - When the RBuffer switches to the non-full state -typedef void (*rbuffer_callback)(RBuffer *buf, void *data); - -struct rbuffer { - rbuffer_callback full_cb, nonfull_cb; - void *data; - size_t size; - // helper memory used to by rbuffer_reset if required - char *temp; - char *end_ptr, *read_ptr, *write_ptr; - char start_ptr[]; -}; - -static inline size_t rbuffer_size(RBuffer *buf) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - -static inline size_t rbuffer_size(RBuffer *buf) -{ - return buf->size; -} - -static inline size_t rbuffer_capacity(RBuffer *buf) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - -static inline size_t rbuffer_capacity(RBuffer *buf) -{ - return (size_t)(buf->end_ptr - buf->start_ptr); -} - -static inline size_t rbuffer_space(RBuffer *buf) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - -static inline size_t rbuffer_space(RBuffer *buf) -{ - return rbuffer_capacity(buf) - buf->size; -} diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 5130678a81..a5768cfc06 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -15,7 +15,6 @@ #include "nvim/option_vars.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" -#include "nvim/rbuffer.h" #include "nvim/strings.h" #include "nvim/tui/input.h" #include "nvim/tui/input_defs.h" @@ -153,7 +152,7 @@ void tinput_init(TermInput *input, Loop *loop) termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS); // setup input handle - rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE); + rstream_init_fd(loop, &input->read_stream, input->in_fd); // initialize a timer handle for handling ESC with libtermkey uv_timer_init(&loop->uv, &input->timer_handle); @@ -211,9 +210,9 @@ static void tinput_flush(TermInput *input) input->key_buffer_len = 0; } -static void tinput_enqueue(TermInput *input, char *buf, size_t size) +static void tinput_enqueue(TermInput *input, const char *buf, size_t size) { - if (input->key_buffer_len > KEY_BUFFER_SIZE - 0xff) { + if (input->key_buffer_len > KEY_BUFFER_SIZE - size) { // don't ever let the buffer get too full or we risk putting incomplete keys into it tinput_flush(input); } @@ -463,8 +462,10 @@ static void tinput_timer_cb(uv_timer_t *handle) TermInput *input = handle->data; // If the raw buffer is not empty, process the raw buffer first because it is // processing an incomplete bracketed paster sequence. - if (rbuffer_size(input->read_stream.buffer)) { - handle_raw_buffer(input, true); + size_t size = rstream_available(&input->read_stream); + if (size) { + size_t consumed = handle_raw_buffer(input, true, input->read_stream.read_pos, size); + rstream_consume(&input->read_stream, consumed); } tk_getkeys(input, true); tinput_flush(input); @@ -478,39 +479,37 @@ static void tinput_timer_cb(uv_timer_t *handle) /// /// @param input the input stream /// @return true iff handle_focus_event consumed some input -static bool handle_focus_event(TermInput *input) +static size_t handle_focus_event(TermInput *input, const char *ptr, size_t size) { - if (rbuffer_size(input->read_stream.buffer) > 2 - && (!rbuffer_cmp(input->read_stream.buffer, "\x1b[I", 3) - || !rbuffer_cmp(input->read_stream.buffer, "\x1b[O", 3))) { - bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I'; - // Advance past the sequence - rbuffer_consumed(input->read_stream.buffer, 3); + if (size >= 3 + && (!memcmp(ptr, "\x1b[I", 3) + || !memcmp(ptr, "\x1b[O", 3))) { + bool focus_gained = ptr[2] == 'I'; MAXSIZE_TEMP_ARRAY(args, 1); ADD_C(args, BOOLEAN_OBJ(focus_gained)); rpc_send_event(ui_client_channel_id, "nvim_ui_set_focus", args); - return true; + return 3; // Advance past the sequence } - return false; + return 0; } #define START_PASTE "\x1b[200~" #define END_PASTE "\x1b[201~" -static HandleState handle_bracketed_paste(TermInput *input) +static size_t handle_bracketed_paste(TermInput *input, const char *ptr, size_t size, + bool *incomplete) { - size_t buf_size = rbuffer_size(input->read_stream.buffer); - if (buf_size > 5 - && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, 6) - || !rbuffer_cmp(input->read_stream.buffer, END_PASTE, 6))) { - bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0'; + if (size >= 6 + && (!memcmp(ptr, START_PASTE, 6) + || !memcmp(ptr, END_PASTE, 6))) { + bool enable = ptr[4] == '0'; if (input->paste && enable) { - return kNotApplicable; // Pasting "start paste" code literally. + return 0; // Pasting "start paste" code literally. } + // Advance past the sequence - rbuffer_consumed(input->read_stream.buffer, 6); if (!!input->paste == enable) { - return kComplete; // Spurious "disable paste" code. + return 6; // Spurious "disable paste" code. } if (enable) { @@ -525,15 +524,15 @@ static HandleState handle_bracketed_paste(TermInput *input) // Paste phase: "disabled". input->paste = 0; } - return kComplete; - } else if (buf_size < 6 - && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, buf_size) - || !rbuffer_cmp(input->read_stream.buffer, - END_PASTE, buf_size))) { + return 6; + } else if (size < 6 + && (!memcmp(ptr, START_PASTE, size) + || !memcmp(ptr, END_PASTE, size))) { // Wait for further input, as the sequence may be split. - return kIncomplete; + *incomplete = true; + return 0; } - return kNotApplicable; + return 0; } /// Handle an OSC or DCS response sequence from the terminal. @@ -644,20 +643,31 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key) } } -static void handle_raw_buffer(TermInput *input, bool force) +static size_t handle_raw_buffer(TermInput *input, bool force, const char *data, size_t size) { - HandleState is_paste = kNotApplicable; + const char *ptr = data; do { - if (!force - && (handle_focus_event(input) - || (is_paste = handle_bracketed_paste(input)) != kNotApplicable)) { - if (is_paste == kIncomplete) { + if (!force) { + size_t consumed = handle_focus_event(input, ptr, size); + if (consumed) { + ptr += consumed; + size -= consumed; + continue; + } + + bool incomplete = false; + consumed = handle_bracketed_paste(input, ptr, size, &incomplete); + if (incomplete) { + assert(consumed == 0); // Wait for the next input, leaving it in the raw buffer due to an // incomplete sequence. - return; + return (size_t)(ptr - data); + } else if (consumed) { + ptr += consumed; + size -= consumed; + continue; } - continue; } // @@ -666,55 +676,47 @@ static void handle_raw_buffer(TermInput *input, bool force) // calls (above) depend on this. // size_t count = 0; - RBUFFER_EACH(input->read_stream.buffer, c, i) { + for (size_t i = 0; i < size; i++) { count = i + 1; - if (c == '\x1b' && count > 1) { + if (ptr[i] == '\x1b' && count > 1) { count--; break; } } // Push bytes directly (paste). if (input->paste) { - RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) { - size_t consumed = MIN(count, len); - assert(consumed <= input->read_stream.buffer->size); - tinput_enqueue(input, ptr, consumed); - rbuffer_consumed(input->read_stream.buffer, consumed); - if (!(count -= consumed)) { - break; - } - } + tinput_enqueue(input, ptr, count); + ptr += count; + size -= count; continue; } + // Push through libtermkey (translates to "" strings, etc.). - RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) { - const size_t size = MIN(count, len); - if (size > termkey_get_buffer_remaining(input->tk)) { + { + const size_t to_use = MIN(count, size); + if (to_use > termkey_get_buffer_remaining(input->tk)) { // We are processing a very long escape sequence. Increase termkey's // internal buffer size. We don't handle out of memory situations so // abort if it fails - const size_t delta = size - termkey_get_buffer_remaining(input->tk); + const size_t delta = to_use - termkey_get_buffer_remaining(input->tk); const size_t bufsize = termkey_get_buffer_size(input->tk); if (!termkey_set_buffer_size(input->tk, MAX(bufsize + delta, bufsize * 2))) { abort(); } } - size_t consumed = termkey_push_bytes(input->tk, ptr, size); + size_t consumed = termkey_push_bytes(input->tk, ptr, to_use); // We resize termkey's buffer when it runs out of space, so this should // never happen - assert(consumed <= rbuffer_size(input->read_stream.buffer)); - rbuffer_consumed(input->read_stream.buffer, consumed); + assert(consumed <= to_use); + ptr += consumed; + size -= consumed; // Process the input buffer now for any keys tk_getkeys(input, false); - - if (!(count -= consumed)) { - break; - } } - } while (rbuffer_size(input->read_stream.buffer)); + } while (size); const size_t tk_size = termkey_get_buffer_size(input->tk); const size_t tk_remaining = termkey_get_buffer_remaining(input->tk); @@ -726,23 +728,25 @@ static void handle_raw_buffer(TermInput *input, bool force) abort(); } } + + return (size_t)(ptr - data); } -static void tinput_read_cb(RStream *stream, RBuffer *buf, size_t count_, void *data, bool eof) +static size_t tinput_read_cb(RStream *stream, const char *buf, size_t count_, void *data, bool eof) { TermInput *input = data; + size_t consumed = handle_raw_buffer(input, false, buf, count_); + tinput_flush(input); + if (eof) { loop_schedule_fast(&main_loop, event_create(tinput_done_event, NULL)); - return; + return consumed; } - handle_raw_buffer(input, false); - tinput_flush(input); - // An incomplete sequence was found. Leave it in the raw buffer and wait for // the next input. - if (rbuffer_size(input->read_stream.buffer)) { + if (consumed < count_) { // If 'ttimeout' is not set, start the timer with a timeout of 0 to process // the next input. int64_t ms = input->ttimeout @@ -750,11 +754,7 @@ static void tinput_read_cb(RStream *stream, RBuffer *buf, size_t count_, void *d // Stop the current timer if already running uv_timer_stop(&input->timer_handle); uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0); - return; } - // Make sure the next input escape sequence fits into the ring buffer without - // wraparound, else it could be misinterpreted (because rbuffer_read_ptr() - // exposes the underlying buffer to callers unaware of the wraparound). - rbuffer_reset(input->read_stream.buffer); + return consumed; } diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index c594228c07..8d0c0c20e9 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -5,7 +5,6 @@ #include #include "nvim/event/defs.h" -#include "nvim/rbuffer_defs.h" #include "nvim/tui/input_defs.h" // IWYU pragma: keep #include "nvim/tui/tui_defs.h" #include "nvim/types_defs.h" @@ -17,7 +16,7 @@ typedef enum { kKeyEncodingXterm, ///< Xterm's modifyOtherKeys encoding (XTMODKEYS) } KeyEncoding; -#define KEY_BUFFER_SIZE 0xfff +#define KEY_BUFFER_SIZE 0x1000 typedef struct { int in_fd; // Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk @@ -40,12 +39,6 @@ typedef struct { size_t key_buffer_len; } TermInput; -typedef enum { - kIncomplete = -1, - kNotApplicable = 0, - kComplete = 1, -} HandleState; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tui/input.h.generated.h" #endif -- cgit From 9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 3 Jun 2024 19:04:28 +0200 Subject: feat(lua): add `vim._with` It's a function to perform operations in their own sealed context, similar to pythons `with`. This helps ease operations where you need to perform an operation in a specific context, and then restore the context. Marked as private for now as it's not ready for public use. The current plan is to start using this internally so we can discover and fix any problems. Once this is ready to be exposed it will be renamed to `vim.with`. Usage: ```lua local ret = vim._with({context = val}, function() return "hello" end) ``` , where `context` is any combination of: - `buf` - `emsg_silent` - `hide` - `horizontal` - `keepalt` - `keepjumps` - `keepmarks` - `keeppatterns` - `lockmarks` - `noautocmd` - `options` - `sandbox` - `silent` - `unsilent` - `win` (except for `win` and `buf` which can't be used at the same time). This list will most likely be expanded in the future. Work on https://github.com/neovim/neovim/issues/19832. Co-authored-by: Lewis Russell --- src/nvim/ex_docmd.c | 18 ++++----- src/nvim/lua/stdlib.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2f54aa511b..1e2c515195 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1729,12 +1729,6 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) } const char *errormsg = NULL; -#undef ERROR -#define ERROR(msg) \ - do { \ - errormsg = msg; \ - goto end; \ - } while (0) cmdmod_T save_cmdmod = cmdmod; cmdmod = cmdinfo->cmdmod; @@ -1745,16 +1739,19 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY) // allow :put in terminals && !(curbuf->terminal && eap->cmdidx == CMD_put)) { - ERROR(_(e_modifiable)); + errormsg = _(e_modifiable); + goto end; } if (!IS_USER_CMDIDX(eap->cmdidx)) { if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) { // Command not allowed in the command line window - ERROR(_(e_cmdwin)); + errormsg = _(e_cmdwin); + goto end; } if (text_locked() && !(eap->argt & EX_LOCK_OK)) { // Command not allowed when text is locked - ERROR(_(get_text_locked_msg())); + errormsg = _(get_text_locked_msg()); + goto end; } } // Disallow editing another buffer when "curbuf->b_ro_locked" is set. @@ -1802,7 +1799,6 @@ end: do_cmdline_end(); return retv; -#undef ERROR } static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie) @@ -2696,7 +2692,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, /// Apply the command modifiers. Saves current state in "cmdmod", call /// undo_cmdmod() later. -static void apply_cmdmod(cmdmod_T *cmod) +void apply_cmdmod(cmdmod_T *cmod) { if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) { sandbox++; diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 22ee0a1c98..ee0eabbebb 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -17,10 +17,13 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" +#include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" +#include "nvim/eval/window.h" +#include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/fold.h" #include "nvim/globals.h" @@ -40,6 +43,7 @@ #include "nvim/runtime.h" #include "nvim/strings.h" #include "nvim/types_defs.h" +#include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/stdlib.c.generated.h" @@ -568,6 +572,99 @@ static int nlua_foldupdate(lua_State *lstate) return 0; } +static int nlua_with(lua_State *L) +{ + int flags = 0; + buf_T *buf = NULL; + win_T *win = NULL; + +#define APPLY_FLAG(key, flag) \ + if (strequal((key), k) && (v)) { \ + flags |= (flag); \ + } + + luaL_argcheck(L, lua_istable(L, 1), 1, "table expected"); + lua_pushnil(L); // [dict, ..., nil] + while (lua_next(L, 1)) { + // [dict, ..., key, value] + if (lua_type(L, -2) == LUA_TSTRING) { + const char *k = lua_tostring(L, -2); + bool v = lua_toboolean(L, -1); + if (strequal("buf", k)) { \ + buf = handle_get_buffer((int)luaL_checkinteger(L, -1)); + } else if (strequal("win", k)) { \ + win = handle_get_window((int)luaL_checkinteger(L, -1)); + } else { + APPLY_FLAG("sandbox", CMOD_SANDBOX); + APPLY_FLAG("silent", CMOD_SILENT); + APPLY_FLAG("emsg_silent", CMOD_ERRSILENT); + APPLY_FLAG("unsilent", CMOD_UNSILENT); + APPLY_FLAG("noautocmd", CMOD_NOAUTOCMD); + APPLY_FLAG("hide", CMOD_HIDE); + APPLY_FLAG("keepalt", CMOD_KEEPALT); + APPLY_FLAG("keepmarks", CMOD_KEEPMARKS); + APPLY_FLAG("keepjumps", CMOD_KEEPJUMPS); + APPLY_FLAG("lockmarks", CMOD_LOCKMARKS); + APPLY_FLAG("keeppatterns", CMOD_KEEPPATTERNS); + } + } + // pop the value; lua_next will pop the key. + lua_pop(L, 1); // [dict, ..., key] + } + int status = 0; + int rets = 0; + + cmdmod_T save_cmdmod = cmdmod; + cmdmod.cmod_flags = flags; + apply_cmdmod(&cmdmod); + + if (buf || win) { + try_start(); + } + + aco_save_T aco; + win_execute_T win_execute_args; + Error err = ERROR_INIT; + + if (win) { + tabpage_T *tabpage = win_find_tabpage(win); + if (!win_execute_before(&win_execute_args, win, tabpage)) { + goto end; + } + } else if (buf) { + aucmd_prepbuf(&aco, buf); + } + + int s = lua_gettop(L); + lua_pushvalue(L, 2); + status = lua_pcall(L, 0, LUA_MULTRET, 0); + rets = lua_gettop(L) - s; + + if (win) { + win_execute_after(&win_execute_args); + } else if (buf) { + aucmd_restbuf(&aco); + } + +end: + if (buf || win) { + try_end(&err); + } + + undo_cmdmod(&cmdmod); + cmdmod = save_cmdmod; + + if (status) { + return lua_error(L); + } else if (ERROR_SET(&err)) { + nlua_push_errstr(L, "%s", err.msg); + api_clear_error(&err); + return lua_error(L); + } + + return rets; +} + // Access to internal functions. For use in runtime/ static void nlua_state_add_internal(lua_State *const lstate) { @@ -582,6 +679,9 @@ static void nlua_state_add_internal(lua_State *const lstate) // _updatefolds lua_pushcfunction(lstate, &nlua_foldupdate); lua_setfield(lstate, -2, "_foldupdate"); + + lua_pushcfunction(lstate, &nlua_with); + lua_setfield(lstate, -2, "_with_c"); } void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) -- cgit From caa2e842a1d67972210824aa5758c6d50f46ca52 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 2 Jun 2024 14:21:37 +0200 Subject: refactor(os/shell): we have DynamicBuffer at home MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DynamicBuffer at home: KVÄCK --- src/nvim/os/shell.c | 63 +++++++++++++++-------------------------------------- 1 file changed, 17 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index ee9b6ec68c..b66faa2285 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -47,17 +47,11 @@ #include "nvim/ui.h" #include "nvim/vim_defs.h" -#define DYNAMIC_BUFFER_INIT { NULL, 0, 0 } #define NS_1_SECOND 1000000000U // 1 second, in nanoseconds #define OUT_DATA_THRESHOLD 1024 * 10U // 10KB, "a few screenfuls" of data. #define SHELL_SPECIAL "\t \"&'$;<>()\\|" -typedef struct { - char *data; - size_t cap, len; -} DynamicBuffer; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/shell.c.generated.h" #endif @@ -667,7 +661,7 @@ char *shell_argv_to_str(char **const argv) /// @return shell command exit code int os_call_shell(char *cmd, ShellOpts opts, char *extra_args) { - DynamicBuffer input = DYNAMIC_BUFFER_INIT; + StringBuilder input = KV_INITIAL_VALUE; char *output = NULL; char **output_ptr = NULL; int current_state = State; @@ -696,9 +690,9 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args) size_t nread; int exitcode = do_os_system(shell_build_argv(cmd, extra_args), - input.data, input.len, output_ptr, &nread, + input.items, input.size, output_ptr, &nread, emsg_silent, forward_output); - xfree(input.data); + kv_destroy(input); if (output) { write_output(output, nread, true); @@ -862,7 +856,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu bool has_input = (input != NULL && input[0] != NUL); // the output buffer - DynamicBuffer buf = DYNAMIC_BUFFER_INIT; + StringBuilder buf = KV_INITIAL_VALUE; stream_read_cb data_cb = system_data_cb; if (nread) { *nread = 0; @@ -950,18 +944,17 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu // prepare the out parameters if requested if (output) { - if (buf.len == 0) { + assert(nread); + if (buf.size == 0) { // no data received from the process, return NULL *output = NULL; - xfree(buf.data); + *nread = 0; + kv_destroy(buf); } else { + *nread = buf.size; // NUL-terminate to make the output directly usable as a C string - buf.data[buf.len] = NUL; - *output = buf.data; - } - - if (nread) { - *nread = buf.len; + kv_push(buf, NUL); + *output = buf.items; } } @@ -971,28 +964,10 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu return exitcode; } -/// - ensures at least `desired` bytes in buffer -/// -/// TODO(aktau): fold with kvec/garray -static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired) -{ - if (buf->cap >= desired) { - assert(buf->data); - return; - } - - buf->cap = desired; - kv_roundup32(buf->cap); - buf->data = xrealloc(buf->data, buf->cap); -} - static size_t system_data_cb(RStream *stream, const char *buf, size_t count, void *data, bool eof) { - DynamicBuffer *dbuf = data; - - dynamic_buffer_ensure(dbuf, dbuf->len + count + 1); - memcpy(dbuf->data + dbuf->len, buf, count); - dbuf->len += count; + StringBuilder *dbuf = data; + kv_concat_len(*dbuf, buf, count); return count; } @@ -1223,7 +1198,7 @@ static size_t word_length(const char *str) /// event loop starts. If we don't (by writing in chunks returned by `ml_get`) /// the buffer being modified might get modified by reading from the process /// before we finish writing. -static void read_input(DynamicBuffer *buf) +static void read_input(StringBuilder *buf) { size_t written = 0; size_t len = 0; @@ -1237,14 +1212,11 @@ static void read_input(DynamicBuffer *buf) } else if (lp[written] == NL) { // NL -> NUL translation len = 1; - dynamic_buffer_ensure(buf, buf->len + len); - buf->data[buf->len++] = NUL; + kv_push(*buf, NUL); } else { char *s = vim_strchr(lp + written, NL); len = s == NULL ? l : (size_t)(s - (lp + written)); - dynamic_buffer_ensure(buf, buf->len + len); - memcpy(buf->data + buf->len, lp + written, len); - buf->len += len; + kv_concat_len(*buf, lp + written, len); } if (len == l) { @@ -1253,8 +1225,7 @@ static void read_input(DynamicBuffer *buf) || (!curbuf->b_p_bin && curbuf->b_p_fixeol) || (lnum != curbuf->b_no_eol_lnum && (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) { - dynamic_buffer_ensure(buf, buf->len + 1); - buf->data[buf->len++] = NL; + kv_push(*buf, NL); } lnum++; if (lnum > curbuf->b_op_end.lnum) { -- cgit From a056cc1300ef062d4f757873a647b20b8331ab03 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 10 Jun 2024 06:37:56 +0800 Subject: vim-patch:9.1.0472: Inconsistencies between functions for option flags (#29262) Problem: Inconsistencies between functions for option flags. Solution: Consistently use "unsigned int" as return type and rename get_bkc_value() to get_bkc_flags() (zeertzjq). closes: vim/vim#14925 https://github.com/vim/vim/commit/aa925eeb97bd294d4a5253a3194949a37cbc8365 --- src/nvim/bufwrite.c | 2 +- src/nvim/option.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 6fbcb2dbb8..5522ab1ca3 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -1066,7 +1066,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bool whole = (start == 1 && end == buf->b_ml.ml_line_count); bool write_undo_file = false; context_sha256_T sha_ctx; - unsigned bkc = get_bkc_value(buf); + unsigned bkc = get_bkc_flags(buf); if (fname == NULL || *fname == NUL) { // safety check return FAIL; diff --git a/src/nvim/option.c b/src/nvim/option.c index 41b9aaf9a7..301e6e9cea 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -6192,10 +6192,10 @@ bool can_bs(int what) return vim_strchr(p_bs, what) != NULL; } -/// Get the local or global value of 'backupcopy'. +/// Get the local or global value of 'backupcopy' flags. /// /// @param buf The buffer. -unsigned get_bkc_value(buf_T *buf) +unsigned get_bkc_flags(buf_T *buf) { return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags; } @@ -6211,7 +6211,7 @@ char *get_flp_value(buf_T *buf) return buf->b_p_flp; } -/// Get the local or global value of the 'virtualedit' flags. +/// Get the local or global value of 'virtualedit' flags. unsigned get_ve_flags(win_T *wp) { return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU); -- cgit From 743c5808b616daece73145ddd12b39ae07bbd87a Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 9 Jun 2024 15:59:44 +0200 Subject: fix(api): allow `scope = 'local'` with `buf` when using `nvim_get_option_value` `nvim_get_option_value` throws a warning if both `scope` and `buf` options are used at the same time. This is because using `buf` always implies `scope` is local, and is therefore not needed. There's however no need to error if `scope` is already set "local" as it's the correct value. --- src/nvim/api/options.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index d9bc0ccc92..5adaff8449 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -54,6 +54,10 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * } if (HAS_KEY_X(opts, buf)) { + VALIDATE(!(HAS_KEY_X(opts, scope) && *scope == OPT_GLOBAL), "%s", + "cannot use both global 'scope' and 'buf'", { + return FAIL; + }); *scope = OPT_LOCAL; *req_scope = kOptReqBuf; *from = find_buffer_by_handle(opts->buf, err); @@ -68,11 +72,6 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * return FAIL; }); - VALIDATE((!HAS_KEY_X(opts, scope) || !HAS_KEY_X(opts, buf)), "%s", - "cannot use both 'scope' and 'buf'", { - return FAIL; - }); - VALIDATE((!HAS_KEY_X(opts, win) || !HAS_KEY_X(opts, buf)), "%s", "cannot use both 'buf' and 'win'", { return FAIL; -- cgit From 1dcda865591b9bdda2fec1a1860efb4df56ea533 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 10 Jun 2024 16:55:16 +0200 Subject: fix(column): clamp line number for legacy signs Problem: Legacy :sign API still allows placing signs beyond the end of the buffer. This is unaccounted for by the signcolumn tracking logic and is disallowed in general for the extmark API which implements it now. Solution: Clamp legacy sign line number to the length of the buffer. --- src/nvim/sign.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 1ca0e846a9..605098fb66 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -126,8 +126,8 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr | (has_hl ? MT_FLAG_DECOR_SIGNHL : 0); DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } }; - extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, decor, decor_flags, true, - false, true, true, NULL); + extmark_set(buf, ns, id, MIN(buf->b_ml.ml_line_count, lnum) - 1, 0, -1, -1, + decor, decor_flags, true, false, true, true, NULL); } /// For an existing, placed sign with "id", modify the sign, group or priority. -- cgit From 19052e0a06240be018a234d87f51113eca6d17fa Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 8 Jun 2024 14:19:30 +0200 Subject: refactor(shada): use msgpack_sbuffer less Work towards getting rid of libmsgpack depedency eventually. msgpack_sbuffer is just a string buffer, we can use our own String type. --- src/nvim/api/private/helpers.c | 4 - src/nvim/context.c | 126 ++++++--------------------- src/nvim/context.h | 22 ++--- src/nvim/memory.h | 2 - src/nvim/memory_defs.h | 2 + src/nvim/msgpack_rpc/channel.c | 8 +- src/nvim/msgpack_rpc/packer.c | 27 ++++-- src/nvim/msgpack_rpc/packer.h | 5 ++ src/nvim/msgpack_rpc/packer_defs.h | 2 +- src/nvim/os/fileio.c | 3 +- src/nvim/os/fileio.h | 6 ++ src/nvim/shada.c | 169 ++++++++++++++++++++++--------------- src/nvim/shada.h | 2 + 13 files changed, 174 insertions(+), 204 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a17e78cc31..ac621b1486 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -548,10 +548,6 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col void api_free_string(String value) { - if (!value.data) { - return; - } - xfree(value.data); } diff --git a/src/nvim/context.c b/src/nvim/context.c index 95e2618f62..2e3634329a 100644 --- a/src/nvim/context.c +++ b/src/nvim/context.c @@ -66,21 +66,11 @@ Context *ctx_get(size_t index) void ctx_free(Context *ctx) FUNC_ATTR_NONNULL_ALL { - if (ctx->regs.data) { - msgpack_sbuffer_destroy(&ctx->regs); - } - if (ctx->jumps.data) { - msgpack_sbuffer_destroy(&ctx->jumps); - } - if (ctx->bufs.data) { - msgpack_sbuffer_destroy(&ctx->bufs); - } - if (ctx->gvars.data) { - msgpack_sbuffer_destroy(&ctx->gvars); - } - if (ctx->funcs.items) { - api_free_array(ctx->funcs); - } + api_free_string(ctx->regs); + api_free_string(ctx->jumps); + api_free_string(ctx->bufs); + api_free_string(ctx->gvars); + api_free_array(ctx->funcs); } /// Saves the editor state to a context. @@ -98,19 +88,19 @@ void ctx_save(Context *ctx, const int flags) } if (flags & kCtxRegs) { - ctx_save_regs(ctx); + ctx->regs = shada_encode_regs(); } if (flags & kCtxJumps) { - ctx_save_jumps(ctx); + ctx->jumps = shada_encode_jumps(); } if (flags & kCtxBufs) { - ctx_save_bufs(ctx); + ctx->bufs = shada_encode_buflist(); } if (flags & kCtxGVars) { - ctx_save_gvars(ctx); + ctx->gvars = shada_encode_gvars(); } if (flags & kCtxFuncs) { @@ -173,33 +163,13 @@ bool ctx_restore(Context *ctx, const int flags) return true; } -/// Saves the global registers to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_regs(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->regs); - shada_encode_regs(&ctx->regs); -} - /// Restores the global registers from a context. /// /// @param ctx Restore from this context. static inline void ctx_restore_regs(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->regs, kShaDaWantInfo | kShaDaForceit); -} - -/// Saves the jumplist to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_jumps(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->jumps); - shada_encode_jumps(&ctx->jumps); + shada_read_string(ctx->regs, kShaDaWantInfo | kShaDaForceit); } /// Restores the jumplist from a context. @@ -208,17 +178,7 @@ static inline void ctx_save_jumps(Context *ctx) static inline void ctx_restore_jumps(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->jumps, kShaDaWantInfo | kShaDaForceit); -} - -/// Saves the buffer list to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_bufs(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->bufs); - shada_encode_buflist(&ctx->bufs); + shada_read_string(ctx->jumps, kShaDaWantInfo | kShaDaForceit); } /// Restores the buffer list from a context. @@ -227,17 +187,7 @@ static inline void ctx_save_bufs(Context *ctx) static inline void ctx_restore_bufs(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->bufs, kShaDaWantInfo | kShaDaForceit); -} - -/// Saves global variables to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_gvars(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->gvars); - shada_encode_gvars(&ctx->gvars); + shada_read_string(ctx->bufs, kShaDaWantInfo | kShaDaForceit); } /// Restores global variables from a context. @@ -246,7 +196,7 @@ static inline void ctx_save_gvars(Context *ctx) static inline void ctx_restore_gvars(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->gvars, kShaDaWantInfo | kShaDaForceit); + shada_read_string(ctx->gvars, kShaDaWantInfo | kShaDaForceit); } /// Saves functions to a context. @@ -291,41 +241,16 @@ static inline void ctx_restore_funcs(Context *ctx) } } -/// Convert msgpack_sbuffer to readfile()-style array. -/// -/// @param[in] sbuf msgpack_sbuffer to convert. -/// -/// @return readfile()-style array representation of "sbuf". -static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena) -{ - list_T *const list = tv_list_alloc(kListLenMayKnow); - tv_list_append_string(list, "", 0); - if (sbuf.size > 0) { - encode_list_write(list, sbuf.data, sbuf.size); - } - - typval_T list_tv = (typval_T) { - .v_lock = VAR_UNLOCKED, - .v_type = VAR_LIST, - .vval.v_list = list - }; - - Array array = vim_to_object(&list_tv, arena, false).data.array; - tv_clear(&list_tv); - return array; -} - -/// Convert readfile()-style array to msgpack_sbuffer. +/// Convert readfile()-style array to String /// /// @param[in] array readfile()-style array to convert. /// @param[out] err Error object. /// -/// @return msgpack_sbuffer with conversion result. -static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err) +/// @return String with conversion result. +static inline String array_to_string(Array array, Error *err) FUNC_ATTR_NONNULL_ALL { - msgpack_sbuffer sbuf; - msgpack_sbuffer_init(&sbuf); + String sbuf = STRING_INIT; typval_T list_tv; object_to_vim(ARRAY_OBJ(array), &list_tv, err); @@ -335,7 +260,6 @@ static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err) api_set_error(err, kErrorTypeException, "%s", "E474: Failed to convert list to msgpack string buffer"); } - sbuf.alloc = sbuf.size; tv_clear(&list_tv); return sbuf; @@ -353,10 +277,10 @@ Dictionary ctx_to_dict(Context *ctx, Arena *arena) Dictionary rv = arena_dict(arena, 5); - PUT_C(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs, arena))); - PUT_C(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps, arena))); - PUT_C(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs, arena))); - PUT_C(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars, arena))); + PUT_C(rv, "regs", ARRAY_OBJ(string_to_array(ctx->regs, false, arena))); + PUT_C(rv, "jumps", ARRAY_OBJ(string_to_array(ctx->jumps, false, arena))); + PUT_C(rv, "bufs", ARRAY_OBJ(string_to_array(ctx->bufs, false, arena))); + PUT_C(rv, "gvars", ARRAY_OBJ(string_to_array(ctx->gvars, false, arena))); PUT_C(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, arena))); return rv; @@ -382,16 +306,16 @@ int ctx_from_dict(Dictionary dict, Context *ctx, Error *err) } if (strequal(item.key.data, "regs")) { types |= kCtxRegs; - ctx->regs = array_to_sbuf(item.value.data.array, err); + ctx->regs = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "jumps")) { types |= kCtxJumps; - ctx->jumps = array_to_sbuf(item.value.data.array, err); + ctx->jumps = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "bufs")) { types |= kCtxBufs; - ctx->bufs = array_to_sbuf(item.value.data.array, err); + ctx->bufs = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "gvars")) { types |= kCtxGVars; - ctx->gvars = array_to_sbuf(item.value.data.array, err); + ctx->gvars = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "funcs")) { types |= kCtxFuncs; ctx->funcs = copy_object(item.value, NULL).data.array; diff --git a/src/nvim/context.h b/src/nvim/context.h index 1c18a1af7c..0bb7138b6c 100644 --- a/src/nvim/context.h +++ b/src/nvim/context.h @@ -7,25 +7,19 @@ #include "nvim/api/private/defs.h" typedef struct { - msgpack_sbuffer regs; ///< Registers. - msgpack_sbuffer jumps; ///< Jumplist. - msgpack_sbuffer bufs; ///< Buffer list. - msgpack_sbuffer gvars; ///< Global variables. + String regs; ///< Registers. + String jumps; ///< Jumplist. + String bufs; ///< Buffer list. + String gvars; ///< Global variables. Array funcs; ///< Functions. } Context; typedef kvec_t(Context) ContextVec; -#define MSGPACK_SBUFFER_INIT (msgpack_sbuffer) { \ - .size = 0, \ - .data = NULL, \ - .alloc = 0, \ -} - #define CONTEXT_INIT (Context) { \ - .regs = MSGPACK_SBUFFER_INIT, \ - .jumps = MSGPACK_SBUFFER_INIT, \ - .bufs = MSGPACK_SBUFFER_INIT, \ - .gvars = MSGPACK_SBUFFER_INIT, \ + .regs = STRING_INIT, \ + .jumps = STRING_INIT, \ + .bufs = STRING_INIT, \ + .gvars = STRING_INIT, \ .funcs = ARRAY_DICT_INIT, \ } diff --git a/src/nvim/memory.h b/src/nvim/memory.h index 0788670142..e98a5dc228 100644 --- a/src/nvim/memory.h +++ b/src/nvim/memory.h @@ -45,8 +45,6 @@ EXTERN size_t arena_alloc_count INIT( = 0); ((v).capacity = (s), \ (v).items = (void *)arena_alloc(a, sizeof((v).items[0]) * (v).capacity, true)) -#define ARENA_BLOCK_SIZE 4096 - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "memory.h.generated.h" #endif diff --git a/src/nvim/memory_defs.h b/src/nvim/memory_defs.h index bde0e54f54..df271ceca5 100644 --- a/src/nvim/memory_defs.h +++ b/src/nvim/memory_defs.h @@ -11,5 +11,7 @@ typedef struct { size_t pos, size; } Arena; +#define ARENA_BLOCK_SIZE 4096 + // inits an empty arena. #define ARENA_EMPTY { .cur_blk = NULL, .pos = 0, .size = 0 } diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 6a0dc10214..0930f0c7b3 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -590,16 +590,16 @@ static void packer_buffer_init_channels(Channel **chans, size_t nchans, PackerBu packer->endptr = packer->startptr + ARENA_BLOCK_SIZE; packer->packer_flush = channel_flush_callback; packer->anydata = chans; - packer->anylen = nchans; + packer->anyint = (int64_t)nchans; } static void packer_buffer_finish_channels(PackerBuffer *packer) { size_t len = (size_t)(packer->ptr - packer->startptr); if (len > 0) { - WBuffer *buf = wstream_new_buffer(packer->startptr, len, packer->anylen, free_block); + WBuffer *buf = wstream_new_buffer(packer->startptr, len, (size_t)packer->anyint, free_block); Channel **chans = packer->anydata; - for (size_t i = 0; i < packer->anylen; i++) { + for (int64_t i = 0; i < packer->anyint; i++) { channel_write(chans[i], buf); } } else { @@ -610,7 +610,7 @@ static void packer_buffer_finish_channels(PackerBuffer *packer) static void channel_flush_callback(PackerBuffer *packer) { packer_buffer_finish_channels(packer); - packer_buffer_init_channels(packer->anydata, packer->anylen, packer); + packer_buffer_init_channels(packer->anydata, (size_t)packer->anyint, packer); } void rpc_set_client_info(uint64_t id, Dictionary info) diff --git a/src/nvim/msgpack_rpc/packer.c b/src/nvim/msgpack_rpc/packer.c index 9c0d2910fa..58318b88b0 100644 --- a/src/nvim/msgpack_rpc/packer.c +++ b/src/nvim/msgpack_rpc/packer.c @@ -10,8 +10,7 @@ static void check_buffer(PackerBuffer *packer) { - ptrdiff_t remaining = packer->endptr - packer->ptr; - if (remaining < MPACK_ITEM_SIZE) { + if (mpack_remaining(packer) < MPACK_ITEM_SIZE) { packer->packer_flush(packer); } } @@ -28,15 +27,20 @@ static void mpack_w8(char **b, const char *data) #endif } +void mpack_uint64(char **ptr, uint64_t i) +{ + if (i > 0xfffffff) { + mpack_w(ptr, 0xcf); + mpack_w8(ptr, (char *)&i); + } else { + mpack_uint(ptr, (uint32_t)i); + } +} + void mpack_integer(char **ptr, Integer i) { if (i >= 0) { - if (i > 0xfffffff) { - mpack_w(ptr, 0xcf); - mpack_w8(ptr, (char *)&i); - } else { - mpack_uint(ptr, (uint32_t)i); - } + mpack_uint64(ptr, (uint64_t)i); } else { if (i < -0x80000000LL) { mpack_w(ptr, 0xd3); @@ -80,11 +84,16 @@ void mpack_str(String str, PackerBuffer *packer) abort(); } + mpack_raw(str.data, len, packer); +} + +void mpack_raw(char *data, size_t len, PackerBuffer *packer) +{ size_t pos = 0; while (pos < len) { ptrdiff_t remaining = packer->endptr - packer->ptr; size_t to_copy = MIN(len - pos, (size_t)remaining); - memcpy(packer->ptr, str.data + pos, to_copy); + memcpy(packer->ptr, data + pos, to_copy); packer->ptr += to_copy; pos += to_copy; diff --git a/src/nvim/msgpack_rpc/packer.h b/src/nvim/msgpack_rpc/packer.h index 8117bd09bd..299962bab4 100644 --- a/src/nvim/msgpack_rpc/packer.h +++ b/src/nvim/msgpack_rpc/packer.h @@ -71,6 +71,11 @@ static inline void mpack_map(char **buf, uint32_t len) } } +static inline size_t mpack_remaining(PackerBuffer *packer) +{ + return (size_t)(packer->endptr - packer->ptr); +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/packer.h.generated.h" #endif diff --git a/src/nvim/msgpack_rpc/packer_defs.h b/src/nvim/msgpack_rpc/packer_defs.h index 420f3dc424..95d86caaab 100644 --- a/src/nvim/msgpack_rpc/packer_defs.h +++ b/src/nvim/msgpack_rpc/packer_defs.h @@ -19,6 +19,6 @@ struct packer_buffer_t { // these are free to be used by packer_flush for any purpose, if want void *anydata; - size_t anylen; + int64_t anyint; PackerBufferFlush packer_flush; }; diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index 585c4964e2..89834bed80 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -320,9 +320,8 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { assert(fp->wr); - ptrdiff_t space = (fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos; // includes the trivial case of size==0 - if (size < (size_t)space) { + if (size < file_space(fp)) { memcpy(fp->write_pos, buf, size); fp->write_pos += size; return (ptrdiff_t)size; diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h index e8fd2209db..523f9657a4 100644 --- a/src/nvim/os/fileio.h +++ b/src/nvim/os/fileio.h @@ -2,6 +2,7 @@ #include // IWYU pragma: keep +#include "nvim/memory_defs.h" #include "nvim/os/fileio_defs.h" // IWYU pragma: keep /// file_open() flags @@ -32,6 +33,11 @@ enum { kRWBufferSize = 1024, }; +static inline size_t file_space(FileDescriptor *fp) +{ + return (size_t)((fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos); +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fileio.h.generated.h" #endif diff --git a/src/nvim/shada.c b/src/nvim/shada.c index d5655b1754..5736ea0f09 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -42,6 +42,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/msgpack_rpc/packer.h" #include "nvim/normal_defs.h" #include "nvim/ops.h" #include "nvim/option.h" @@ -602,20 +603,6 @@ static void close_file(FileDescriptor *cookie) } } -/// Msgpack callback for writing to FileDescriptor* -static int msgpack_sd_writer_write(void *data, const char *buf, size_t len) -{ - FileDescriptor *const sd_writer = (FileDescriptor *)data; - const ptrdiff_t ret = file_write(sd_writer, buf, len); - if (ret < 0) { - semsg(_(SERR "System error while writing ShaDa file: %s"), - os_strerror((int)ret)); - return -1; - } - - return 0; -} - /// Check whether writing to shada file was disabled ("-i NONE" or "--clean"). /// /// @return true if it was disabled, false otherwise. @@ -1365,6 +1352,8 @@ static char *shada_filename(const char *file) } \ } while (0) +#define SHADA_MPACK_FREE_SPACE (4 * MPACK_ITEM_SIZE) + /// Write single ShaDa entry /// /// @param[in] packer Packer used to write entry. @@ -1373,7 +1362,7 @@ static char *shada_filename(const char *file) /// restrictions. /// /// @return kSDWriteSuccessful, kSDWriteFailed or kSDWriteIgnError. -static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntry entry, +static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry entry, const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL { @@ -1657,29 +1646,26 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr #undef CHECK_DEFAULT #undef ONE_IF_NOT_DEFAULT if (!max_kbyte || sbuf.size <= max_kbyte * 1024) { + if (mpack_remaining(packer) < SHADA_MPACK_FREE_SPACE) { + packer->packer_flush(packer); + } + if (entry.type == kSDItemUnknown) { - if (msgpack_pack_uint64(packer, entry.data.unknown_item.type) == -1) { - goto shada_pack_entry_error; - } + mpack_uint64(&packer->ptr, entry.data.unknown_item.type); } else { - if (msgpack_pack_uint64(packer, (uint64_t)entry.type) == -1) { - goto shada_pack_entry_error; - } - } - if (msgpack_pack_uint64(packer, (uint64_t)entry.timestamp) == -1) { - goto shada_pack_entry_error; + mpack_uint64(&packer->ptr, (uint64_t)entry.type); } + mpack_uint64(&packer->ptr, (uint64_t)entry.timestamp); if (sbuf.size > 0) { - if ((msgpack_pack_uint64(packer, (uint64_t)sbuf.size) == -1) - || (packer->callback(packer->data, sbuf.data, - (unsigned)sbuf.size) == -1)) { - goto shada_pack_entry_error; - } + mpack_uint64(&packer->ptr, (uint64_t)sbuf.size); + mpack_raw(sbuf.data, sbuf.size, packer); + } + + if (packer->anyint != 0) { // error code + goto shada_pack_entry_error; } } - msgpack_packer_free(spacker); - msgpack_sbuffer_destroy(&sbuf); - return kSDWriteSuccessful; + ret = kSDWriteSuccessful; shada_pack_entry_error: msgpack_packer_free(spacker); msgpack_sbuffer_destroy(&sbuf); @@ -1694,7 +1680,7 @@ shada_pack_entry_error: /// @param[in] entry Entry written. /// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no /// restrictions. -static inline ShaDaWriteResult shada_pack_pfreed_entry(msgpack_packer *const packer, +static inline ShaDaWriteResult shada_pack_pfreed_entry(PackerBuffer *const packer, PossiblyFreedShadaEntry entry, const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE @@ -1908,7 +1894,7 @@ static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_ const unsigned srni_flags, const size_t max_kbyte, WriteMergerState *const wms, - msgpack_packer *const packer) + PackerBuffer *const packer) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { ShaDaWriteResult ret = kSDWriteSuccessful; @@ -2360,6 +2346,29 @@ static int hist_type2char(const int type) return NUL; } +static PackerBuffer packer_buffer_for_file(FileDescriptor *file) +{ + if (file_space(file) < SHADA_MPACK_FREE_SPACE) { + file_flush(file); + } + return (PackerBuffer) { + .startptr = file->buffer, + .ptr = file->write_pos, + .endptr = file->buffer + ARENA_BLOCK_SIZE, + .anydata = file, + .anyint = 0, // set to nonzero if error + .packer_flush = flush_file_buffer, + }; +} + +static void flush_file_buffer(PackerBuffer *buffer) +{ + FileDescriptor *fd = buffer->anydata; + fd->write_pos = buffer->ptr; + buffer->anyint = file_flush(fd); + buffer->ptr = fd->write_pos; +} + /// Write ShaDa file /// /// @param[in] sd_writer Structure containing file writer definition. @@ -2408,8 +2417,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, } } - const unsigned srni_flags = (unsigned)( - kSDReadUndisableableData + const unsigned srni_flags = (unsigned)(kSDReadUndisableableData | kSDReadUnknown | (dump_history ? kSDReadHistory : 0) | (dump_registers ? kSDReadRegisters : 0) @@ -2418,8 +2426,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, | (num_marked_files ? kSDReadLocalMarks | kSDReadChanges : 0)); - msgpack_packer *const packer = msgpack_packer_new(sd_writer, - &msgpack_sd_writer_write); + PackerBuffer packer = packer_buffer_for_file(sd_writer); // Set b_last_cursor for all the buffers that have a window. // @@ -2433,7 +2440,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, find_removable_bufs(&removable_bufs); // Write header - if (shada_pack_entry(packer, (ShadaEntry) { + if (shada_pack_entry(&packer, (ShadaEntry) { .type = kSDItemHeader, .timestamp = os_time(), .data = { @@ -2462,7 +2469,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, // Write buffer list if (find_shada_parameter('%') != NULL) { ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); - if (shada_pack_entry(packer, buflist_entry, 0) == kSDWriteFailed) { + if (shada_pack_entry(&packer, buflist_entry, 0) == kSDWriteFailed) { xfree(buflist_entry.data.buffer_list.buffers); ret = kSDWriteFailed; goto shada_write_exit; @@ -2512,7 +2519,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, typval_T tgttv; tv_copy(&vartv, &tgttv); ShaDaWriteResult spe_ret; - if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) { + if ((spe_ret = shada_pack_entry(&packer, (ShadaEntry) { .type = kSDItemVariable, .timestamp = cur_timestamp, .data = { @@ -2689,7 +2696,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, if (sd_reader != NULL) { const ShaDaWriteResult srww_ret = shada_read_when_writing(sd_reader, srni_flags, max_kbyte, wms, - packer); + &packer); if (srww_ret != kSDWriteSuccessful) { ret = srww_ret; } @@ -2720,7 +2727,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, do { \ for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \ if ((wms_array)[i_].data.type != kSDItemMissing) { \ - if (shada_pack_pfreed_entry(packer, (wms_array)[i_], max_kbyte) \ + if (shada_pack_pfreed_entry(&packer, (wms_array)[i_], max_kbyte) \ == kSDWriteFailed) { \ ret = kSDWriteFailed; \ goto shada_write_exit; \ @@ -2732,7 +2739,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, PACK_WMS_ARRAY(wms->numbered_marks); PACK_WMS_ARRAY(wms->registers); for (size_t i = 0; i < wms->jumps_size; i++) { - if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte) + if (shada_pack_pfreed_entry(&packer, wms->jumps[i], max_kbyte) == kSDWriteFailed) { ret = kSDWriteFailed; goto shada_write_exit; @@ -2741,7 +2748,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, #define PACK_WMS_ENTRY(wms_entry) \ do { \ if ((wms_entry).data.type != kSDItemMissing) { \ - if (shada_pack_pfreed_entry(packer, wms_entry, max_kbyte) \ + if (shada_pack_pfreed_entry(&packer, wms_entry, max_kbyte) \ == kSDWriteFailed) { \ ret = kSDWriteFailed; \ goto shada_write_exit; \ @@ -2767,14 +2774,14 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, for (size_t i = 0; i < file_markss_to_dump; i++) { PACK_WMS_ARRAY(all_file_markss[i]->marks); for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) { - if (shada_pack_pfreed_entry(packer, all_file_markss[i]->changes[j], + if (shada_pack_pfreed_entry(&packer, all_file_markss[i]->changes[j], max_kbyte) == kSDWriteFailed) { ret = kSDWriteFailed; goto shada_write_exit; } } for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) { - if (shada_pack_entry(packer, all_file_markss[i]->additional_marks[j], + if (shada_pack_entry(&packer, all_file_markss[i]->additional_marks[j], 0) == kSDWriteFailed) { shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]); ret = kSDWriteFailed; @@ -2792,7 +2799,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, if (dump_one_history[i]) { hms_insert_whole_neovim_history(&wms->hms[i]); HMS_ITER(&wms->hms[i], cur_entry, { - if (shada_pack_pfreed_entry(packer, (PossiblyFreedShadaEntry) { + if (shada_pack_pfreed_entry(&packer, (PossiblyFreedShadaEntry) { .data = cur_entry->data, .can_free_entry = cur_entry->can_free_entry, }, max_kbyte) == kSDWriteFailed) { @@ -2818,7 +2825,7 @@ shada_write_exit: }) map_destroy(cstr_t, &wms->file_marks); set_destroy(ptr_t, &removable_bufs); - msgpack_packer_free(packer); + packer.packer_flush(&packer); set_destroy(cstr_t, &wms->dumped_variables); xfree(wms); return ret; @@ -3953,16 +3960,43 @@ static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps, return jumps_size; } +static PackerBuffer packer_string_buffer(void) +{ + const size_t initial_size = 64; // must be larger than SHADA_MPACK_FREE_SPACE + char *alloc = xmalloc(initial_size); + return (PackerBuffer) { + .startptr = alloc, + .ptr = alloc, + .endptr = alloc + initial_size, + .packer_flush = flush_string_buffer, + }; +} + +static void flush_string_buffer(PackerBuffer *buffer) +{ + size_t current_capacity = (size_t)(buffer->endptr - buffer->startptr); + size_t new_capacity = 2 * current_capacity; + size_t len = (size_t)(buffer->ptr - buffer->startptr); + + buffer->startptr = xrealloc(buffer->startptr, new_capacity); + buffer->ptr = buffer->startptr + len; + buffer->endptr = buffer->startptr + new_capacity; +} + +static String packer_take_string(PackerBuffer *buffer) +{ + return (String){ .data = buffer->startptr, .size = (size_t)(buffer->ptr - buffer->startptr) }; +} + /// Write registers ShaDa entries in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_regs(msgpack_sbuffer *const sbuf) +String shada_encode_regs(void) FUNC_ATTR_NONNULL_ALL { WriteMergerState *const wms = xcalloc(1, sizeof(*wms)); shada_initialize_registers(wms, -1); - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + PackerBuffer packer = packer_string_buffer(); for (size_t i = 0; i < ARRAY_SIZE(wms->registers); i++) { if (wms->registers[i].data.type == kSDItemRegister) { if (kSDWriteFailed @@ -3972,52 +4006,53 @@ void shada_encode_regs(msgpack_sbuffer *const sbuf) } } xfree(wms); + return packer_take_string(&packer); } /// Write jumplist ShaDa entries in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_jumps(msgpack_sbuffer *const sbuf) +String shada_encode_jumps(void) FUNC_ATTR_NONNULL_ALL { Set(ptr_t) removable_bufs = SET_INIT; find_removable_bufs(&removable_bufs); PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; size_t jumps_size = shada_init_jumps(jumps, &removable_bufs); - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + PackerBuffer packer = packer_string_buffer(); for (size_t i = 0; i < jumps_size; i++) { if (kSDWriteFailed == shada_pack_pfreed_entry(&packer, jumps[i], 0)) { abort(); } } + return packer_take_string(&packer); } /// Write buffer list ShaDa entry in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_buflist(msgpack_sbuffer *const sbuf) +String shada_encode_buflist(void) FUNC_ATTR_NONNULL_ALL { Set(ptr_t) removable_bufs = SET_INIT; find_removable_bufs(&removable_bufs); ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + + PackerBuffer packer = packer_string_buffer(); if (kSDWriteFailed == shada_pack_entry(&packer, buflist_entry, 0)) { abort(); } xfree(buflist_entry.data.buffer_list.buffers); + return packer_take_string(&packer); } /// Write global variables ShaDa entries in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_gvars(msgpack_sbuffer *const sbuf) +String shada_encode_gvars(void) FUNC_ATTR_NONNULL_ALL { - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + PackerBuffer packer = packer_string_buffer(); const void *var_iter = NULL; const Timestamp cur_timestamp = os_time(); do { @@ -4049,21 +4084,21 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf) } tv_clear(&vartv); } while (var_iter != NULL); + return packer_take_string(&packer); } -/// Read ShaDa from msgpack_sbuffer. +/// Read ShaDa from String. /// -/// @param[in] file msgpack_sbuffer to read from. +/// @param[in] string string to read from. /// @param[in] flags Flags, see ShaDaReadFileFlags enum. -void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags) +void shada_read_string(String string, const int flags) FUNC_ATTR_NONNULL_ALL { - assert(sbuf != NULL); - if (sbuf->data == NULL) { + if (string.size == 0) { return; } FileDescriptor sd_reader; - file_open_buffer(&sd_reader, sbuf->data, sbuf->size); + file_open_buffer(&sd_reader, string.data, string.size); shada_read(&sd_reader, flags); close_file(&sd_reader); } diff --git a/src/nvim/shada.h b/src/nvim/shada.h index d7cac24afc..58689a5bd7 100644 --- a/src/nvim/shada.h +++ b/src/nvim/shada.h @@ -2,6 +2,8 @@ #include // IWYU pragma: keep +#include "nvim/api/private/defs.h" + /// Flags for shada_read_file and children typedef enum { kShaDaWantInfo = 1, ///< Load non-mark information -- cgit From 5e49ef0af3cb8dba658e5d0dc6a807f8edebf590 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 11 Jun 2024 12:05:18 +0100 Subject: refactor(lua): improve type annotations --- src/nvim/eval.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 3c99ba22c2..f303878897 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -4047,8 +4047,9 @@ M.funcs = { ]=], name = 'getmarklist', - params = { { 'buf', 'any' } }, + params = { { 'buf', 'integer?' } }, signature = 'getmarklist([{buf}])', + returns = 'vim.fn.getmarklist.ret.item[]', }, getmatches = { args = { 0, 1 }, -- cgit From bbd2f340a2895ed59785f952b2585e6590602cad Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 11 Jun 2024 10:25:32 +0200 Subject: refactor(memory): use builtin strcat() instead of STRCAT() The latter was mostly relevant with the past char_u madness. NOTE: STRCAT also functioned as a counterfeit "NOLINT" for clint apparently. But NOLINT-ing every usecase is just the same as disabling the check entirely. --- src/clint.py | 2 +- src/nvim/autocmd.c | 2 +- src/nvim/change.c | 4 ++-- src/nvim/cmdexpand.c | 2 +- src/nvim/diff.c | 6 +++--- src/nvim/eval.c | 4 ++-- src/nvim/eval/userfunc.c | 4 ++-- src/nvim/ex_cmds.c | 12 ++++++------ src/nvim/ex_docmd.c | 6 +++--- src/nvim/ex_eval.c | 4 ++-- src/nvim/file_search.c | 10 +++++----- src/nvim/fold.c | 2 +- src/nvim/insexpand.c | 2 +- src/nvim/memory.h | 2 -- src/nvim/menu.c | 2 +- src/nvim/normal.c | 2 +- src/nvim/ops.c | 6 +++--- src/nvim/option.c | 6 +++--- src/nvim/os/shell.c | 26 +++++++++++++------------- src/nvim/path.c | 4 ++-- src/nvim/quickfix.c | 4 ++-- src/nvim/regexp.c | 2 +- src/nvim/runtime.c | 2 +- src/nvim/spell.c | 12 ++++++------ src/nvim/spellfile.c | 20 ++++++++++---------- src/nvim/spellsuggest.c | 4 ++-- src/nvim/syntax.c | 2 +- src/nvim/tag.c | 2 +- src/nvim/usercmd.c | 4 ++-- 29 files changed, 79 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/clint.py b/src/clint.py index 41058469b1..051f0e91e5 100755 --- a/src/clint.py +++ b/src/clint.py @@ -1995,7 +1995,7 @@ def CheckLanguage(filename, clean_lines, linenum, error): if match: error(filename, linenum, 'runtime/printf', 4, 'Use xstrlcpy, xmemcpyz or snprintf instead of %s' % match.group(1)) - match = Search(r'\b(STRNCAT|strncat|strcat|vim_strcat)\b', line) + match = Search(r'\b(STRNCAT|strncat|vim_strcat)\b', line) if match: error(filename, linenum, 'runtime/printf', 4, 'Use xstrlcat or snprintf instead of %s' % match.group(1)) diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index e5872fcc76..c32d33080e 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -711,7 +711,7 @@ char *au_event_disable(char *what) if (*what == ',' && *p_ei == NUL) { STRCPY(new_ei, what + 1); } else { - STRCAT(new_ei, what); + strcat(new_ei, what); } set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(new_ei), 0, SID_NONE); xfree(new_ei); diff --git a/src/nvim/change.c b/src/nvim/change.c index 05772d39e9..6c979df1fe 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -1723,12 +1723,12 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // Below, set_indent(newindent, SIN_INSERT) will insert the // whitespace needed before the comment char. for (int i = 0; i < padding; i++) { - STRCAT(leader, " "); + strcat(leader, " "); less_cols--; newcol++; } } - STRCAT(leader, p_extra); + strcat(leader, p_extra); p_extra = leader; did_ai = true; // So truncating blanks works with comments less_cols -= lead_len; diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 0b88e2be11..f75b84c77b 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -3257,7 +3257,7 @@ void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dir copy_option_part(&path, buf, MAXPATHL, ","); if (strlen(buf) + strlen(file) + 2 < MAXPATHL) { add_pathsep(buf); - STRCAT(buf, file); + strcat(buf, file); char **p; int num_p = 0; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 54335fc93e..0fe1729029 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1273,10 +1273,10 @@ void ex_diffpatch(exarg_T *eap) // Delete any .orig or .rej file created. STRCPY(buf, tmp_new); - STRCAT(buf, ".orig"); + strcat(buf, ".orig"); os_remove(buf); STRCPY(buf, tmp_new); - STRCAT(buf, ".rej"); + strcat(buf, ".rej"); os_remove(buf); // Only continue if the output file was created. @@ -1288,7 +1288,7 @@ void ex_diffpatch(exarg_T *eap) } else { if (curbuf->b_fname != NULL) { newname = xstrnsave(curbuf->b_fname, strlen(curbuf->b_fname) + 4); - STRCAT(newname, ".new"); + strcat(newname, ".new"); } // don't use a new tab page, each tab page has its own diffs diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a4680b62ab..d52e10f61b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7154,8 +7154,8 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start) + (size_t)(in_end - expr_end) + 1); STRCPY(retval, in_start); - STRCAT(retval, temp_result); - STRCAT(retval, expr_end + 1); + strcat(retval, temp_result); + strcat(retval, expr_end + 1); } xfree(temp_result); diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 00fb896797..122a1ac8ab 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -265,7 +265,7 @@ static void set_ufunc_name(ufunc_T *fp, char *name) if ((uint8_t)name[0] == K_SPECIAL) { fp->uf_name_exp = xmalloc(strlen(name) + 3); STRCPY(fp->uf_name_exp, ""); - STRCAT(fp->uf_name_exp, fp->uf_name + 3); + strcat(fp->uf_name_exp, fp->uf_name + 3); } } @@ -2062,7 +2062,7 @@ char *get_scriptlocal_funcname(char *funcname) const int off = *funcname == 's' ? 2 : 5; char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1); STRCPY(newname, sid_buf); - STRCAT(newname, funcname + off); + strcat(newname, funcname + off); return newname; } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 2f7673a6f4..0aa897105e 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -970,13 +970,13 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out char *t = xmalloc(len); *t = NUL; if (newcmd != NULL) { - STRCAT(t, newcmd); + strcat(t, newcmd); } if (ins_prevcmd) { - STRCAT(t, prevcmd); + strcat(t, prevcmd); } char *p = t + strlen(t); - STRCAT(t, trailarg); + strcat(t, trailarg); xfree(newcmd); newcmd = t; @@ -1029,8 +1029,8 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out } newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1); STRCPY(newcmd, p_shq); - STRCAT(newcmd, prevcmd); - STRCAT(newcmd, p_shq); + strcat(newcmd, prevcmd); + strcat(newcmd, p_shq); free_newcmd = true; } if (addr_count == 0) { // :! @@ -4108,7 +4108,7 @@ skip: // the line as reference, because the substitute may // have changed the number of characters. Same for // "prev_matchcol". - STRCAT(new_start, sub_firstline + copycol); + strcat(new_start, sub_firstline + copycol); matchcol = (colnr_T)strlen(sub_firstline) - matchcol; prev_matchcol = (colnr_T)strlen(sub_firstline) - prev_matchcol; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1e2c515195..a6246afb41 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3826,8 +3826,8 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) // No $* in arg, build " " instead new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2); STRCPY(new_cmdline, program); - STRCAT(new_cmdline, " "); - STRCAT(new_cmdline, arg); + strcat(new_cmdline, " "); + strcat(new_cmdline, arg); } msg_make(arg); @@ -7236,7 +7236,7 @@ char *expand_sfile(char *arg) memmove(newres, result, (size_t)(p - result)); STRCPY(newres + (p - result), repl); len = strlen(newres); - STRCAT(newres, p + srclen); + strcat(newres, p + srclen); xfree(repl); xfree(result); result = newres; diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 2681beb228..6e7c1ff21c 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -406,7 +406,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool || (ascii_isdigit(p[3]) && p[4] == ':')))))) { if (*p == NUL || p == mesg) { - STRCAT(val, mesg); // 'E123' missing or at beginning + strcat(val, mesg); // 'E123' missing or at beginning } else { // '"filename" E123: message text' if (mesg[0] != '"' || p - 2 < &mesg[1] @@ -415,7 +415,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool continue; } - STRCAT(val, p); + strcat(val, p); p[-2] = NUL; snprintf(val + strlen(p), strlen(" (%s)"), " (%s)", &mesg[1]); p[-2] = '"'; diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 30a80773e3..b6a039af5e 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -451,7 +451,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i STRCPY(buf, ff_expand_buffer); STRCPY(buf + eb_len, search_ctx->ffsc_fix_path); if (os_isdir(buf)) { - STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path); + strcat(ff_expand_buffer, search_ctx->ffsc_fix_path); add_pathsep(ff_expand_buffer); } else { char *p = path_tail(search_ctx->ffsc_fix_path); @@ -479,7 +479,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i + strlen(search_ctx->ffsc_fix_path + len) + 1); STRCPY(temp, search_ctx->ffsc_fix_path + len); - STRCAT(temp, search_ctx->ffsc_wc_path); + strcat(temp, search_ctx->ffsc_wc_path); xfree(search_ctx->ffsc_wc_path); xfree(wc_path); search_ctx->ffsc_wc_path = temp; @@ -681,7 +681,7 @@ char *vim_findfile(void *search_ctx_arg) ff_free_stack_element(stackp); goto fail; } - STRCAT(file_path, stackp->ffs_fix_path); + strcat(file_path, stackp->ffs_fix_path); if (!add_pathsep(file_path)) { ff_free_stack_element(stackp); goto fail; @@ -781,7 +781,7 @@ char *vim_findfile(void *search_ctx_arg) ff_free_stack_element(stackp); goto fail; } - STRCAT(file_path, search_ctx->ffsc_file_to_search); + strcat(file_path, search_ctx->ffsc_file_to_search); // Try without extra suffix and then with suffixes // from 'suffixesadd'. @@ -922,7 +922,7 @@ char *vim_findfile(void *search_ctx_arg) if (!add_pathsep(file_path)) { goto fail; } - STRCAT(file_path, search_ctx->ffsc_fix_path); + strcat(file_path, search_ctx->ffsc_fix_path); // create a new stack entry sptr = ff_create_stack_element(file_path, diff --git a/src/nvim/fold.c b/src/nvim/fold.c index be1b6acf2c..78fe33cc78 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -3315,7 +3315,7 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char *r = xmalloc(len); snprintf(r, len, txt, dashes, count); len = strlen(r); - STRCAT(r, s); + strcat(r, s); // remove 'foldmarker' and 'commentstring' foldtext_cleanup(r + len); rettv->vval.v_string = r; diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 574c9a9e3a..711e2292b1 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -4059,7 +4059,7 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) compl_pattern = xmalloc(7); STRCPY(compl_pattern, "\\<"); quote_meta(compl_pattern + 2, line + compl_col, 1); - STRCAT(compl_pattern, "\\k"); + strcat(compl_pattern, "\\k"); } else { compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2); STRCPY(compl_pattern, "\\<"); diff --git a/src/nvim/memory.h b/src/nvim/memory.h index 0788670142..277ffe97aa 100644 --- a/src/nvim/memory.h +++ b/src/nvim/memory.h @@ -72,5 +72,3 @@ EXTERN size_t arena_alloc_count INIT( = 0); // Like strcpy() but allows overlapped source and destination. #define STRMOVE(d, s) memmove((d), (s), strlen(s) + 1) - -#define STRCAT(d, s) strcat((char *)(d), (char *)(s)) // NOLINT(runtime/printf) diff --git a/src/nvim/menu.c b/src/nvim/menu.c index a4d49d041e..c33d3cc712 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1057,7 +1057,7 @@ char *get_menu_names(expand_T *xp, int idx) } // hack on menu separators: use a 'magic' char for the separator // so that '.' in names gets escaped properly - STRCAT(tbuffer, "\001"); + strcat(tbuffer, "\001"); str = tbuffer; } else { if (should_advance) { diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 879131c9e8..3343803bb1 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1987,7 +1987,7 @@ bool add_to_showcmd(int c) size_t overflow = old_len + extra_len - limit; memmove(showcmd_buf, showcmd_buf + overflow, old_len - overflow + 1); } - STRCAT(showcmd_buf, p); + strcat(showcmd_buf, p); if (char_avail()) { return false; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 1448896146..8f8baaf619 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -2666,7 +2666,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) char *pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1]) + strlen(reg->y_array[0]) + 1); STRCPY(pnew, curr->y_array[--j]); - STRCAT(pnew, reg->y_array[0]); + strcat(pnew, reg->y_array[0]); xfree(curr->y_array[j]); xfree(reg->y_array[0]); curr->y_array[j++] = pnew; @@ -3431,7 +3431,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) totlen = strlen(y_array[y_size - 1]); char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1); STRCPY(newp, y_array[y_size - 1]); - STRCAT(newp, ptr); + strcat(newp, ptr); // insert second line ml_append(lnum, newp, 0, false); new_lnum++; @@ -4747,7 +4747,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } } *ptr = NUL; - STRCAT(buf1, buf2); + strcat(buf1, buf2); ins_str(buf1); // insert the new number endpos = curwin->w_cursor; if (curwin->w_cursor.col) { diff --git a/src/nvim/option.c b/src/nvim/option.c index 301e6e9cea..8fb97ed979 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -236,11 +236,11 @@ static void set_init_default_backupskip(void) == NULL) { ga_grow(&ga, (int)len); if (!GA_EMPTY(&ga)) { - STRCAT(ga.ga_data, ","); + strcat(ga.ga_data, ","); } - STRCAT(ga.ga_data, p); + strcat(ga.ga_data, p); add_pathsep(ga.ga_data); - STRCAT(ga.ga_data, "*"); + strcat(ga.ga_data, "*"); ga.ga_len += (int)len; } xfree(item); diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index b66faa2285..4b34ed1c4e 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -248,11 +248,11 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in } else { STRCPY(command, "("); } - STRCAT(command, pat[0] + 1); // exclude first backtick + strcat(command, pat[0] + 1); // exclude first backtick p = command + strlen(command) - 1; if (is_fish_shell) { *p-- = ';'; - STRCAT(command, " end"); + strcat(command, " end"); } else { *p-- = ')'; // remove last backtick } @@ -263,7 +263,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in ampersand = true; *p = ' '; } - STRCAT(command, ">"); + strcat(command, ">"); } else { STRCPY(command, ""); if (shell_style == STYLE_GLOB) { @@ -271,26 +271,26 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // otherwise, this may set the positional parameters for the shell, // e.g. "$*". if (flags & EW_NOTFOUND) { - STRCAT(command, "set nonomatch; "); + strcat(command, "set nonomatch; "); } else { - STRCAT(command, "unset nonomatch; "); + strcat(command, "unset nonomatch; "); } } if (shell_style == STYLE_GLOB) { - STRCAT(command, "glob >"); + strcat(command, "glob >"); } else if (shell_style == STYLE_PRINT) { - STRCAT(command, "print -N >"); + strcat(command, "print -N >"); } else if (shell_style == STYLE_VIMGLOB) { - STRCAT(command, sh_vimglob_func); + strcat(command, sh_vimglob_func); } else if (shell_style == STYLE_GLOBSTAR) { - STRCAT(command, sh_globstar_opt); - STRCAT(command, sh_vimglob_func); + strcat(command, sh_globstar_opt); + strcat(command, sh_vimglob_func); } else { - STRCAT(command, "echo >"); + strcat(command, "echo >"); } } - STRCAT(command, tempname); + strcat(command, tempname); if (shell_style != STYLE_BT) { for (i = 0; i < num_pat; i++) { @@ -334,7 +334,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in } if (ampersand) { - STRCAT(command, "&"); // put the '&' after the redirection + strcat(command, "&"); // put the '&' after the redirection } // Using zsh -G: If a pattern has no matches, it is just deleted from diff --git a/src/nvim/path.c b/src/nvim/path.c index d782d1a989..aa630038a8 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -962,7 +962,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) char *file_pattern = xmalloc(len + 2); file_pattern[0] = '*'; file_pattern[1] = NUL; - STRCAT(file_pattern, pattern); + strcat(file_pattern, pattern); char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true); xfree(file_pattern); if (pat == NULL) { @@ -1065,7 +1065,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) rel_path = xmalloc(strlen(short_name) + strlen(PATHSEPSTR) + 2); STRCPY(rel_path, "."); add_pathsep(rel_path); - STRCAT(rel_path, short_name); + strcat(rel_path, short_name); xfree(fnames[i]); fnames[i] = rel_path; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index be2f41da14..ed3fd83fd5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4531,7 +4531,7 @@ static char *get_mef_name(void) name = xmalloc(strlen(p_mef) + 30); STRCPY(name, p_mef); snprintf(name + (p - p_mef), strlen(name), "%d%d", start, off); - STRCAT(name, p + 2); + strcat(name, p + 2); // Don't accept a symbolic link, it's a security risk. FileInfo file_info; bool file_or_link_found = os_fileinfo_link(name, &file_info); @@ -7237,7 +7237,7 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p // Find all "*.txt" and "*.??x" files in the "doc" directory. add_pathsep(dirname); - STRCAT(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT + strcat(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT if (gen_expand_wildcards(1, &dirname, &fcount, &fnames, EW_FILE|EW_SILENT) == OK && fcount > 0) { for (int fi = 0; fi < fcount && !got_int; fi++) { diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 2ff4dbee70..5a5ba9df07 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -11451,7 +11451,7 @@ static void nfa_set_code(int c) } if (addnl == true) { - STRCAT(code, " + NEWLINE "); + strcat(code, " + NEWLINE "); } } diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 648e574b97..c479418131 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -409,7 +409,7 @@ int do_in_path(const char *path, const char *prefix, char *name, int flags, did_one = true; } else if (buflen + 2 + strlen(prefix) + strlen(name) < MAXPATHL) { add_pathsep(buf); - STRCAT(buf, prefix); + strcat(buf, prefix); tail = buf + strlen(buf); // Loop over all patterns in "name" diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 39145d73ed..8ec28c7f61 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -2092,7 +2092,7 @@ char *parse_spelllang(win_T *wp) } else { // One entry in 'spellfile'. copy_option_part(&spf, spf_name, MAXPATHL - 5, ","); - STRCAT(spf_name, ".spl"); + strcat(spf_name, ".spl"); int c; // If it was already found above then skip it. @@ -2677,7 +2677,7 @@ void ex_spellrepall(exarg_T *eap) char *p = xmalloc((size_t)get_cursor_line_len() + (size_t)addlen + 1); memmove(p, line, (size_t)curwin->w_cursor.col); STRCPY(p + curwin->w_cursor.col, repl_to); - STRCAT(p, line + curwin->w_cursor.col + repl_from_len); + strcat(p, line + curwin->w_cursor.col + repl_from_len); ml_replace(curwin->w_cursor.lnum, p, false); inserted_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col, (int)repl_from_len, (int)repl_to_len); @@ -3444,14 +3444,14 @@ static void dump_word(slang_T *slang, char *word, char *pat, Direction *dir, int // Add flags and regions after a slash. if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap) { STRCPY(badword, p); - STRCAT(badword, "/"); + strcat(badword, "/"); if (keepcap) { - STRCAT(badword, "="); + strcat(badword, "="); } if (flags & WF_BANNED) { - STRCAT(badword, "!"); + strcat(badword, "!"); } else if (flags & WF_RARE) { - STRCAT(badword, "?"); + strcat(badword, "?"); } if (flags & WF_REGION) { for (int i = 0; i < 7; i++) { diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 9746c3df91..ddeab218e1 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -2140,11 +2140,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) + strlen(items[1]) + 3, false); if (spin->si_info != NULL) { STRCPY(p, spin->si_info); - STRCAT(p, "\n"); + strcat(p, "\n"); } - STRCAT(p, items[0]); - STRCAT(p, " "); - STRCAT(p, items[1]); + strcat(p, items[0]); + strcat(p, " "); + strcat(p, items[1]); spin->si_info = p; } else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) && midword == NULL) { midword = getroom_save(spin, items[1]); @@ -2200,7 +2200,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) // "Na" into "Na+", "1234" into "1234+". p = getroom(spin, strlen(items[1]) + 2, false); STRCPY(p, items[1]); - STRCAT(p, "+"); + strcat(p, "+"); compflags = p; } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) { // We don't use the count, but do check that it's a number and @@ -2221,9 +2221,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) p = getroom(spin, (size_t)l, false); if (compflags != NULL) { STRCPY(p, compflags); - STRCAT(p, "/"); + strcat(p, "/"); } - STRCAT(p, items[1]); + strcat(p, items[1]); compflags = p; } } else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2) @@ -2844,7 +2844,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags char *p = getroom(spin, (size_t)len, false); if (spin->si_compflags != NULL) { STRCPY(p, spin->si_compflags); - STRCAT(p, "/"); + strcat(p, "/"); } spin->si_compflags = p; uint8_t *tp = (uint8_t *)p + strlen(p); @@ -3386,7 +3386,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ MB_PTR_ADV(p); } } - STRCAT(newword, p); + strcat(newword, p); } else { // suffix: chop/add at the end of the word xstrlcpy(newword, word, MAXWLEN); @@ -3400,7 +3400,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ *p = NUL; } if (ae->ae_add != NULL) { - STRCAT(newword, ae->ae_add); + strcat(newword, ae->ae_add); } } diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index 0e674c3178..ed1ba972d5 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -643,7 +643,7 @@ void spell_suggest(int count) int c = (int)(sug.su_badptr - line); memmove(p, line, (size_t)c); STRCPY(p + c, stp->st_word); - STRCAT(p, sug.su_badptr + stp->st_orglen); + strcat(p, sug.su_badptr + stp->st_orglen); // For redo we use a change-word command. ResetRedobuff(); @@ -1638,7 +1638,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Append a space to preword when splitting. if (!try_compound && !fword_ends) { - STRCAT(preword, " "); + strcat(preword, " "); } sp->ts_prewordlen = (uint8_t)strlen(preword); sp->ts_splitoff = sp->ts_twordlen; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index c13619797a..d1af8f304c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4992,7 +4992,7 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list, } else { // Handle match of regexp with group names. *name = '^'; - STRCAT(name, "$"); + strcat(name, "$"); regmatch.regprog = vim_regcomp(name, RE_MAGIC); if (regmatch.regprog == NULL) { failed = true; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index ca3885b079..8f6342bfcc 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1060,7 +1060,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches) // Precede the tag pattern with \V to make it very // nomagic. - STRCAT(cmd, "\\V"); + strcat(cmd, "\\V"); len += 2; int cmd_len = (int)(cmd_end - cmd_start + 1); diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 79f897f020..2893c7cf9f 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -1274,9 +1274,9 @@ static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods) if (buf != NULL) { if (*multi_mods) { - STRCAT(buf, " "); + strcat(buf, " "); } - STRCAT(buf, mod_str); + strcat(buf, mod_str); } *multi_mods = true; -- cgit From 44410d063ad23544f87d1c8a553de336ae7939d8 Mon Sep 17 00:00:00 2001 From: notomo Date: Tue, 11 Jun 2024 21:11:40 +0900 Subject: fix(types): add some vim.fn type annotations Problem: Some vim.fn have no type annotations. Solution: Add type annotations. --- src/nvim/eval.lua | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index f303878897..0e7b0bf4ec 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3448,7 +3448,7 @@ M.funcs = { < ]=], name = 'getchar', - params = {}, + params = { { 'expr', '0|1' } }, returns = 'integer', signature = 'getchar([{expr}])', }, @@ -3537,7 +3537,7 @@ M.funcs = { result is converted to a string. ]=], name = 'getcharstr', - params = {}, + params = { { 'expr', '0|1' } }, returns = 'string', signature = 'getcharstr([{expr}])', }, @@ -6482,7 +6482,8 @@ M.funcs = { echo printf("Operator-pending mode bit: 0x%x", op_bit) ]], name = 'maplist', - params = {}, + params = { { 'abbr', '0|1' } }, + returns = 'table[]', signature = 'maplist([{abbr}])', }, mapnew = { @@ -9143,7 +9144,16 @@ M.funcs = { < ]=], name = 'searchpair', - params = {}, + params = { + { 'start', 'any' }, + { 'middle', 'any' }, + { 'end', 'any' }, + { 'flags', 'string' }, + { 'skip', 'any' }, + { 'stopline', 'any' }, + { 'timeout', 'integer' }, + }, + returns = 'integer', signature = 'searchpair({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])', }, searchpairpos = { @@ -9160,7 +9170,16 @@ M.funcs = { See |match-parens| for a bigger and more useful example. ]=], name = 'searchpairpos', - params = {}, + params = { + { 'start', 'any' }, + { 'middle', 'any' }, + { 'end', 'any' }, + { 'flags', 'string' }, + { 'skip', 'any' }, + { 'stopline', 'any' }, + { 'timeout', 'integer' }, + }, + returns = '[integer, integer]', signature = 'searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])', }, searchpos = { -- cgit From c37695a5d5f2e8914fff86f3581bed70b4c85d3c Mon Sep 17 00:00:00 2001 From: James <89495599+IAKOBVS@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:40:24 +0700 Subject: refactor: use S_LEN(s) instead of s, n (#29219) --- src/nvim/autocmd.c | 10 ++++---- src/nvim/buffer.c | 10 ++++---- src/nvim/channel.c | 2 +- src/nvim/cmdexpand.c | 8 +++---- src/nvim/context.c | 4 ++-- src/nvim/debugger.c | 10 ++++---- src/nvim/diff.c | 60 +++++++++++++++++++++++----------------------- src/nvim/edit.c | 2 +- src/nvim/eval.c | 14 +++++------ src/nvim/eval/funcs.c | 2 +- src/nvim/ex_cmds.c | 4 ++-- src/nvim/ex_docmd.c | 34 +++++++++++++------------- src/nvim/ex_eval.c | 4 ++-- src/nvim/ex_getln.c | 8 +++---- src/nvim/file_search.c | 8 +++---- src/nvim/fileio.c | 2 +- src/nvim/getchar.c | 4 ++-- src/nvim/help.c | 6 ++--- src/nvim/highlight_group.c | 2 +- src/nvim/indent.c | 10 ++++---- src/nvim/keycodes.c | 2 +- src/nvim/mapping.c | 28 +++++++++++----------- src/nvim/mbyte.c | 43 ++++++++++++++++++--------------- src/nvim/memline.c | 4 ++-- src/nvim/menu.c | 24 +++++++++---------- src/nvim/message.c | 4 ++-- src/nvim/option.c | 28 +++++++++++----------- src/nvim/optionstr.c | 14 +++++------ src/nvim/profile.c | 8 +++---- src/nvim/regexp.c | 4 ++-- src/nvim/runtime.c | 10 ++++---- src/nvim/search.c | 26 ++++++++++---------- src/nvim/sign.c | 46 +++++++++++++++++------------------ src/nvim/spellfile.c | 6 ++--- src/nvim/spellsuggest.c | 14 +++++------ src/nvim/statusline.c | 2 +- src/nvim/syntax.c | 12 +++++----- src/nvim/tag.c | 28 +++++++++++----------- src/nvim/terminal.c | 4 ++-- src/nvim/textformat.c | 2 +- src/nvim/usercmd.c | 6 ++--- src/nvim/window.c | 2 +- 42 files changed, 263 insertions(+), 258 deletions(-) (limited to 'src') diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index e5872fcc76..37aa946aaf 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -824,11 +824,11 @@ void do_autocmd(exarg_T *eap, char *arg_in, int forceit) continue; } - invalid_flags |= arg_autocmd_flag_get(&once, &cmd, "++once", 6); - invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "++nested", 8); + invalid_flags |= arg_autocmd_flag_get(&once, &cmd, S_LEN("++once")); + invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, S_LEN("++nested")); // Check the deprecated "nested" flag. - invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "nested", 6); + invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, S_LEN("nested")); } if (invalid_flags) { @@ -1245,7 +1245,7 @@ void ex_doautoall(exarg_T *eap) bool check_nomodeline(char **argp) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - if (strncmp(*argp, "", 12) == 0) { + if (strncmp(*argp, S_LEN("")) == 0) { *argp = skipwhite(*argp + 12); return false; } @@ -2359,7 +2359,7 @@ theend: bool aupat_is_buflocal(const char *pat, int patlen) FUNC_ATTR_PURE { - return patlen >= 8 && strncmp(pat, "'; + return patlen >= 8 && strncmp(pat, S_LEN("'; } int aupat_get_buflocal_nr(const char *pat, int patlen) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 57245ce3f5..3f4e7047f9 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3850,8 +3850,8 @@ static int chk_modeline(linenr_T lnum, int flags) int prev = -1; for (s = ml_get(lnum); *s != NUL; s++) { if (prev == -1 || ascii_isspace(prev)) { - if ((prev != -1 && strncmp(s, "ex:", 3) == 0) - || strncmp(s, "vi:", 3) == 0) { + if ((prev != -1 && strncmp(s, S_LEN("ex:")) == 0) + || strncmp(s, S_LEN("vi:")) == 0) { break; } // Accept both "vim" and "Vim". @@ -3867,7 +3867,7 @@ static int chk_modeline(linenr_T lnum, int flags) if (*e == ':' && (s[0] != 'V' - || strncmp(skipwhite(e + 1), "set", 3) == 0) + || strncmp(skipwhite(e + 1), S_LEN("set")) == 0) && (s[3] == ':' || (VIM_VERSION_100 >= vers && isdigit((uint8_t)s[3])) || (VIM_VERSION_100 < vers && s[3] == '<') @@ -3916,8 +3916,8 @@ static int chk_modeline(linenr_T lnum, int flags) // "vi:set opt opt opt: foo" -- foo not interpreted // "vi:opt opt opt: foo" -- foo interpreted // Accept "se" for compatibility with Elvis. - if (strncmp(s, "set ", 4) == 0 - || strncmp(s, "se ", 3) == 0) { + if (strncmp(s, S_LEN("set ")) == 0 + || strncmp(s, S_LEN("se ")) == 0) { if (*e != ':') { // no terminating ':'? break; } diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 5f9bfc3a73..e3df12abbe 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -639,7 +639,7 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) list_T *const l = tv_list_alloc(kListLenMayKnow); // Empty buffer should be represented by [''], encode_list_write() thinks // empty list is fine for the case. - tv_list_append_string(l, "", 0); + tv_list_append_string(l, S_LEN("")); if (len > 0) { encode_list_write(l, buf, len); } diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 0b88e2be11..d8081ddfac 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -2247,7 +2247,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) // Does command allow "++argopt" argument? if (ea.argt & EX_ARGOPT) { - while (*arg != NUL && strncmp(arg, "++", 2) == 0) { + while (*arg != NUL && strncmp(arg, S_LEN("++")) == 0) { p = arg + 2; while (*p && !ascii_isspace(*p)) { MB_PTR_ADV(p); @@ -2774,7 +2774,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM // When expanding a function name starting with s:, match the nr_ // prefix. char *tofree = NULL; - if (xp->xp_context == EXPAND_USER_FUNC && strncmp(pat, "^s:", 3) == 0) { + if (xp->xp_context == EXPAND_USER_FUNC && strncmp(pat, S_LEN("^s:")) == 0) { const size_t len = strlen(pat) + 20; tofree = xmalloc(len); @@ -3564,7 +3564,7 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (xpc.xp_context == EXPAND_USER_DEFINED) { // Must be "custom,funcname" pattern - if (strncmp(type, "custom,", 7) != 0) { + if (strncmp(type, S_LEN("custom,")) != 0) { semsg(_(e_invarg2), type); return; } @@ -3574,7 +3574,7 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (xpc.xp_context == EXPAND_USER_LIST) { // Must be "customlist,funcname" pattern - if (strncmp(type, "customlist,", 11) != 0) { + if (strncmp(type, S_LEN("customlist,")) != 0) { semsg(_(e_invarg2), type); return; } diff --git a/src/nvim/context.c b/src/nvim/context.c index 95e2618f62..b8eecfbb16 100644 --- a/src/nvim/context.c +++ b/src/nvim/context.c @@ -261,7 +261,7 @@ static inline void ctx_save_funcs(Context *ctx, bool scriptonly) HASHTAB_ITER(func_tbl_get(), hi, { const char *const name = hi->hi_key; - bool islambda = (strncmp(name, "", 8) == 0); + bool islambda = (strncmp(name, S_LEN("")) == 0); bool isscript = ((uint8_t)name[0] == K_SPECIAL); if (!islambda && (!scriptonly || isscript)) { @@ -299,7 +299,7 @@ static inline void ctx_restore_funcs(Context *ctx) static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena) { list_T *const list = tv_list_alloc(kListLenMayKnow); - tv_list_append_string(list, "", 0); + tv_list_append_string(list, S_LEN("")); if (sbuf.size > 0) { encode_list_write(list, sbuf.data, sbuf.size); } diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index b71ff23f57..ffbeee7f7a 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -521,18 +521,18 @@ static int dbg_parsearg(char *arg, garray_T *gap) struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); // Find "func" or "file". - if (strncmp(p, "func", 4) == 0) { + if (strncmp(p, S_LEN("func")) == 0) { bp->dbg_type = DBG_FUNC; - } else if (strncmp(p, "file", 4) == 0) { + } else if (strncmp(p, S_LEN("file")) == 0) { bp->dbg_type = DBG_FILE; - } else if (gap != &prof_ga && strncmp(p, "here", 4) == 0) { + } else if (gap != &prof_ga && strncmp(p, S_LEN("here")) == 0) { if (curbuf->b_ffname == NULL) { emsg(_(e_noname)); return FAIL; } bp->dbg_type = DBG_FILE; here = true; - } else if (gap != &prof_ga && strncmp(p, "expr", 4) == 0) { + } else if (gap != &prof_ga && strncmp(p, S_LEN("expr")) == 0) { bp->dbg_type = DBG_EXPR; } else { semsg(_(e_invarg2), p); @@ -559,7 +559,7 @@ static int dbg_parsearg(char *arg, garray_T *gap) } if (bp->dbg_type == DBG_FUNC) { - bp->dbg_name = xstrdup(strncmp(p, "g:", 2) == 0 ? p + 2 : p); + bp->dbg_name = xstrdup(strncmp(p, S_LEN("g:")) == 0 ? p + 2 : p); } else if (here) { bp->dbg_name = xstrdup(curbuf->b_ffname); } else if (bp->dbg_type == DBG_EXPR) { diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 54335fc93e..e24c39e60c 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1020,7 +1020,7 @@ static int check_external_diff(diffio_T *diffio) if (fd == NULL) { io_error = true; } else { - if (fwrite("line1\n", 6, 1, fd) != 1) { + if (fwrite(S_LEN("line1\n"), 1, fd) != 1) { io_error = true; } fclose(fd); @@ -1029,7 +1029,7 @@ static int check_external_diff(diffio_T *diffio) if (fd == NULL) { io_error = true; } else { - if (fwrite("line2\n", 6, 1, fd) != 1) { + if (fwrite(S_LEN("line2\n"), 1, fd) != 1) { io_error = true; } fclose(fd); @@ -1050,8 +1050,8 @@ static int check_external_diff(diffio_T *diffio) break; } - if (strncmp(linebuf, "1c1", 3) == 0 - || strncmp(linebuf, "@@ -1 +1 @@", 11) == 0) { + if (strncmp(linebuf, S_LEN("1c1")) == 0 + || strncmp(linebuf, S_LEN("@@ -1 +1 @@")) == 0) { ok = kTrue; } } @@ -1583,13 +1583,13 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle) // @@ -1,3 +1,5 @@ if (isdigit((uint8_t)(*line))) { *diffstyle = DIFF_ED; - } else if ((strncmp(line, "@@ ", 3) == 0)) { + } else if ((strncmp(line, S_LEN("@@ ")) == 0)) { *diffstyle = DIFF_UNIFIED; - } else if ((strncmp(line, "--- ", 4) == 0) + } else if ((strncmp(line, S_LEN("--- ")) == 0) && (vim_fgets(line, LBUFLEN, fd) == 0) - && (strncmp(line, "+++ ", 4) == 0) + && (strncmp(line, S_LEN("+++ ")) == 0) && (vim_fgets(line, LBUFLEN, fd) == 0) - && (strncmp(line, "@@ ", 3) == 0)) { + && (strncmp(line, S_LEN("@@ ")) == 0)) { *diffstyle = DIFF_UNIFIED; } else { // Format not recognized yet, skip over this line. Cygwin diff @@ -1607,7 +1607,7 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle) } } else { assert(*diffstyle == DIFF_UNIFIED); - if (strncmp(line, "@@ ", 3) != 0) { + if (strncmp(line, S_LEN("@@ ")) != 0) { continue; // not the start of a diff block } if (parse_diff_unified(line, hunk) == FAIL) { @@ -2473,70 +2473,70 @@ int diffopt_changed(void) char *p = p_dip; while (*p != NUL) { // Note: Keep this in sync with p_dip_values - if (strncmp(p, "filler", 6) == 0) { + if (strncmp(p, S_LEN("filler")) == 0) { p += 6; diff_flags_new |= DIFF_FILLER; - } else if ((strncmp(p, "context:", 8) == 0) && ascii_isdigit(p[8])) { + } else if ((strncmp(p, S_LEN("context:")) == 0) && ascii_isdigit(p[8])) { p += 8; diff_context_new = getdigits_int(&p, false, diff_context_new); - } else if (strncmp(p, "iblank", 6) == 0) { + } else if (strncmp(p, S_LEN("iblank")) == 0) { p += 6; diff_flags_new |= DIFF_IBLANK; - } else if (strncmp(p, "icase", 5) == 0) { + } else if (strncmp(p, S_LEN("icase")) == 0) { p += 5; diff_flags_new |= DIFF_ICASE; - } else if (strncmp(p, "iwhiteall", 9) == 0) { + } else if (strncmp(p, S_LEN("iwhiteall")) == 0) { p += 9; diff_flags_new |= DIFF_IWHITEALL; - } else if (strncmp(p, "iwhiteeol", 9) == 0) { + } else if (strncmp(p, S_LEN("iwhiteeol")) == 0) { p += 9; diff_flags_new |= DIFF_IWHITEEOL; - } else if (strncmp(p, "iwhite", 6) == 0) { + } else if (strncmp(p, S_LEN("iwhite")) == 0) { p += 6; diff_flags_new |= DIFF_IWHITE; - } else if (strncmp(p, "horizontal", 10) == 0) { + } else if (strncmp(p, S_LEN("horizontal")) == 0) { p += 10; diff_flags_new |= DIFF_HORIZONTAL; - } else if (strncmp(p, "vertical", 8) == 0) { + } else if (strncmp(p, S_LEN("vertical")) == 0) { p += 8; diff_flags_new |= DIFF_VERTICAL; - } else if ((strncmp(p, "foldcolumn:", 11) == 0) && ascii_isdigit(p[11])) { + } else if ((strncmp(p, S_LEN("foldcolumn:")) == 0) && ascii_isdigit(p[11])) { p += 11; diff_foldcolumn_new = getdigits_int(&p, false, diff_foldcolumn_new); - } else if (strncmp(p, "hiddenoff", 9) == 0) { + } else if (strncmp(p, S_LEN("hiddenoff")) == 0) { p += 9; diff_flags_new |= DIFF_HIDDEN_OFF; - } else if (strncmp(p, "closeoff", 8) == 0) { + } else if (strncmp(p, S_LEN("closeoff")) == 0) { p += 8; diff_flags_new |= DIFF_CLOSE_OFF; - } else if (strncmp(p, "followwrap", 10) == 0) { + } else if (strncmp(p, S_LEN("followwrap")) == 0) { p += 10; diff_flags_new |= DIFF_FOLLOWWRAP; - } else if (strncmp(p, "indent-heuristic", 16) == 0) { + } else if (strncmp(p, S_LEN("indent-heuristic")) == 0) { p += 16; diff_indent_heuristic = XDF_INDENT_HEURISTIC; - } else if (strncmp(p, "internal", 8) == 0) { + } else if (strncmp(p, S_LEN("internal")) == 0) { p += 8; diff_flags_new |= DIFF_INTERNAL; - } else if (strncmp(p, "algorithm:", 10) == 0) { + } else if (strncmp(p, S_LEN("algorithm:")) == 0) { // Note: Keep this in sync with p_dip_algorithm_values. p += 10; - if (strncmp(p, "myers", 5) == 0) { + if (strncmp(p, S_LEN("myers")) == 0) { p += 5; diff_algorithm_new = 0; - } else if (strncmp(p, "minimal", 7) == 0) { + } else if (strncmp(p, S_LEN("minimal")) == 0) { p += 7; diff_algorithm_new = XDF_NEED_MINIMAL; - } else if (strncmp(p, "patience", 8) == 0) { + } else if (strncmp(p, S_LEN("patience")) == 0) { p += 8; diff_algorithm_new = XDF_PATIENCE_DIFF; - } else if (strncmp(p, "histogram", 9) == 0) { + } else if (strncmp(p, S_LEN("histogram")) == 0) { p += 9; diff_algorithm_new = XDF_HISTOGRAM_DIFF; } else { return FAIL; } - } else if ((strncmp(p, "linematch:", 10) == 0) && ascii_isdigit(p[10])) { + } else if ((strncmp(p, S_LEN("linematch:")) == 0) && ascii_isdigit(p[10])) { p += 10; linematch_lines_new = getdigits_int(&p, false, linematch_lines_new); diff_flags_new |= DIFF_LINEMATCH; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index f6e2dbfa4e..889f445c3d 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3095,7 +3095,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) { p = get_cursor_line_ptr(); if (skipwhite(p) == p + curwin->w_cursor.col - 4 - && strncmp(p + curwin->w_cursor.col - 4, "else", 4) == 0) { + && strncmp(p + curwin->w_cursor.col - 4, S_LEN("else")) == 0) { return true; } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a4680b62ab..df5d336cbd 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1219,7 +1219,7 @@ int call_vim_function(const char *func, int argc, typval_T *argv, typval_T *rett int len = (int)strlen(func); partial_T *pt = NULL; - if (len >= 6 && !memcmp(func, "v:lua.", 6)) { + if (len >= 6 && !memcmp(func, S_LEN("v:lua."))) { func += 6; len = check_luafunc_name(func, false); if (len == 0) { @@ -2161,7 +2161,7 @@ void del_menutrans_vars(void) { hash_lock(&globvarht); HASHTAB_ITER(&globvarht, hi, { - if (strncmp(hi->hi_key, "menutrans_", 10) == 0) { + if (strncmp(hi->hi_key, S_LEN("menutrans_")) == 0) { delete_var(&globvarht, hi); } }); @@ -3274,7 +3274,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan check_vars(s, (size_t)len); // If evaluate is false rettv->v_type was not set, but it's needed // in handle_subscript() to parse v:lua, so set it here. - if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, "v:lua.", 6)) { + if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, S_LEN("v:lua."))) { rettv->v_type = VAR_PARTIAL; rettv->vval.v_partial = vvlua_partial; rettv->vval.v_partial->pt_refcount++; @@ -3483,7 +3483,7 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const int len; char *name = *arg; char *lua_funcname = NULL; - if (strnequal(name, "v:lua.", 6)) { + if (strnequal(name, S_LEN("v:lua."))) { lua_funcname = name + 6; *arg = (char *)skip_luafunc_name(lua_funcname); *arg = skipwhite(*arg); // to detect trailing whitespace later @@ -5618,7 +5618,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) int dict_idx = 0; int arg_idx = 0; list_T *list = NULL; - if (strncmp(s, "s:", 2) == 0 || strncmp(s, "", 5) == 0) { + if (strncmp(s, S_LEN("s:")) == 0 || strncmp(s, S_LEN("")) == 0) { // Expand s: and into nr_, so that the function can // also be called from another script. Using trans_function_name() // would also work, but some plugins depend on the name being @@ -6192,7 +6192,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co case kCallbackFuncref: name = callback->data.funcref; int len = (int)strlen(name); - if (len >= 6 && !memcmp(name, "v:lua.", 6)) { + if (len >= 6 && !memcmp(name, S_LEN("v:lua."))) { name += 6; len = check_luafunc_name(name, false); if (len == 0) { @@ -6460,7 +6460,7 @@ bool write_list(FileDescriptor *const fp, const list_T *const list, const bool b } } if (!binary || TV_LIST_ITEM_NEXT(list, li) != NULL) { - const ptrdiff_t written = file_write(fp, "\n", 1); + const ptrdiff_t written = file_write(fp, S_LEN("\n")); if (written < 0) { error = (int)written; goto write_list_error; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 666d46cdad..9a1ed7dea9 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5095,7 +5095,7 @@ static void get_matches_in_str(const char *str, regmatch_T *rmp, list_T *mlist, // return a list with the submatches for (int i = 1; i < NSUBEXP; i++) { if (rmp->endp[i] == NULL) { - tv_list_append_string(sml, "", 0); + tv_list_append_string(sml, S_LEN("")); } else { tv_list_append_string(sml, rmp->startp[i], rmp->endp[i] - rmp->startp[i]); } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 2f7673a6f4..234ab59844 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1360,11 +1360,11 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) { bool is_fish_shell = #if defined(UNIX) - strncmp(invocation_path_tail(p_sh, NULL), "fish", 4) == 0; + strncmp(invocation_path_tail(p_sh, NULL), S_LEN("fish")) == 0; #else false; #endif - bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0 + bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), S_LEN("pwsh")) == 0 || strncmp(invocation_path_tail(p_sh, NULL), "powershell", 10) == 0; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1e2c515195..a38ff6333a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4191,7 +4191,7 @@ static int getargopt(exarg_T *eap) // Note: Keep this in sync with get_argopt_name. // ":edit ++[no]bin[ary] file" - if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) { + if (strncmp(arg, S_LEN("bin")) == 0 || strncmp(arg, S_LEN("nobin")) == 0) { if (*arg == 'n') { arg += 2; eap->force_bin = FORCE_NOBIN; @@ -4206,33 +4206,33 @@ static int getargopt(exarg_T *eap) } // ":read ++edit file" - if (strncmp(arg, "edit", 4) == 0) { + if (strncmp(arg, S_LEN("edit")) == 0) { eap->read_edit = true; eap->arg = skipwhite(arg + 4); return OK; } // ":write ++p foo/bar/file - if (strncmp(arg, "p", 1) == 0) { + if (strncmp(arg, S_LEN("p")) == 0) { eap->mkdir_p = true; eap->arg = skipwhite(arg + 1); return OK; } - if (strncmp(arg, "ff", 2) == 0) { + if (strncmp(arg, S_LEN("ff")) == 0) { arg += 2; pp = &eap->force_ff; - } else if (strncmp(arg, "fileformat", 10) == 0) { + } else if (strncmp(arg, S_LEN("fileformat")) == 0) { arg += 10; pp = &eap->force_ff; - } else if (strncmp(arg, "enc", 3) == 0) { - if (strncmp(arg, "encoding", 8) == 0) { + } else if (strncmp(arg, S_LEN("enc")) == 0) { + if (strncmp(arg, S_LEN("encoding")) == 0) { arg += 8; } else { arg += 3; } pp = &eap->force_enc; - } else if (strncmp(arg, "bad", 3) == 0) { + } else if (strncmp(arg, S_LEN("bad")) == 0) { arg += 3; pp = &bad_char_idx; } @@ -4296,19 +4296,19 @@ int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int char *name_end = xp->xp_pattern - 1; if (name_end - xp->xp_line >= 2 - && strncmp(name_end - 2, "ff", 2) == 0) { + && strncmp(name_end - 2, S_LEN("ff")) == 0) { cb = get_fileformat_name; } else if (name_end - xp->xp_line >= 10 - && strncmp(name_end - 10, "fileformat", 10) == 0) { + && strncmp(name_end - 10, S_LEN("fileformat")) == 0) { cb = get_fileformat_name; } else if (name_end - xp->xp_line >= 3 - && strncmp(name_end - 3, "enc", 3) == 0) { + && strncmp(name_end - 3, S_LEN("enc")) == 0) { cb = get_encoding_name; } else if (name_end - xp->xp_line >= 8 - && strncmp(name_end - 8, "encoding", 8) == 0) { + && strncmp(name_end - 8, S_LEN("encoding")) == 0) { cb = get_encoding_name; } else if (name_end - xp->xp_line >= 3 - && strncmp(name_end - 3, "bad", 3) == 0) { + && strncmp(name_end - 3, S_LEN("bad")) == 0) { cb = get_bad_name; } @@ -7213,7 +7213,7 @@ char *expand_sfile(char *arg) char *result = xstrdup(arg); for (char *p = result; *p;) { - if (strncmp(p, "", 7) != 0) { + if (strncmp(p, S_LEN("")) != 0) { p++; } else { // replace "" with the sourced file name, and do ":" stuff @@ -7300,12 +7300,12 @@ static void ex_filetype(exarg_T *eap) // Accept "plugin" and "indent" in any order. while (true) { - if (strncmp(arg, "plugin", 6) == 0) { + if (strncmp(arg, S_LEN("plugin")) == 0) { plugin = true; arg = skipwhite(arg + 6); continue; } - if (strncmp(arg, "indent", 6) == 0) { + if (strncmp(arg, S_LEN("indent")) == 0) { indent = true; arg = skipwhite(arg + 6); continue; @@ -7384,7 +7384,7 @@ static void ex_setfiletype(exarg_T *eap) } char *arg = eap->arg; - if (strncmp(arg, "FALLBACK ", 9) == 0) { + if (strncmp(arg, S_LEN("FALLBACK ")) == 0) { arg += 9; } diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 2681beb228..0b2e1f9294 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -254,7 +254,7 @@ bool cause_errthrow(const char *mesg, bool multiline, bool severe, bool *ignore) if (plist == msg_list || severe) { // Skip the extra "Vim " prefix for message "E458". char *tmsg = elem->msg; - if (strncmp(tmsg, "Vim E", 5) == 0 + if (strncmp(tmsg, S_LEN("Vim E")) == 0 && ascii_isdigit(tmsg[5]) && ascii_isdigit(tmsg[6]) && ascii_isdigit(tmsg[7]) @@ -443,7 +443,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname) // would be treated differently from real interrupt or error exceptions // when no active try block is found, see do_cmdline(). if (type == ET_USER) { - if (strncmp(value, "Vim", 3) == 0 + if (strncmp(value, S_LEN("Vim")) == 0 && (((char *)value)[3] == NUL || ((char *)value)[3] == ':' || ((char *)value)[3] == '(')) { emsg(_("E608: Cannot :throw exceptions with 'Vim' prefix")); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index cef1868fc8..74e6e3422e 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2799,13 +2799,13 @@ int check_opt_wim(void) if (p[i] != NUL && p[i] != ',' && p[i] != ':') { return FAIL; } - if (i == 7 && strncmp(p, "longest", 7) == 0) { + if (i == 7 && strncmp(p, S_LEN("longest")) == 0) { new_wim_flags[idx] |= WIM_LONGEST; - } else if (i == 4 && strncmp(p, "full", 4) == 0) { + } else if (i == 4 && strncmp(p, S_LEN("full")) == 0) { new_wim_flags[idx] |= WIM_FULL; - } else if (i == 4 && strncmp(p, "list", 4) == 0) { + } else if (i == 4 && strncmp(p, S_LEN("list")) == 0) { new_wim_flags[idx] |= WIM_LIST; - } else if (i == 8 && strncmp(p, "lastused", 8) == 0) { + } else if (i == 8 && strncmp(p, S_LEN("lastused")) == 0) { new_wim_flags[idx] |= WIM_BUFLASTUSED; } else { return FAIL; diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 30a80773e3..ef936abab5 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -399,7 +399,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i emsg(_(e_path_too_long_for_completion)); break; } - if (strncmp(wc_part, "**", 2) == 0) { + if (strncmp(wc_part, S_LEN("**")) == 0) { ff_expand_buffer[len++] = *wc_part++; ff_expand_buffer[len++] = *wc_part++; @@ -462,7 +462,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i if (p > search_ctx->ffsc_fix_path) { // do not add '..' to the path and start upwards searching len = (int)(p - search_ctx->ffsc_fix_path) - 1; - if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path, "..", 2) == 0) + if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path, S_LEN("..")) == 0) && (len == 2 || search_ctx->ffsc_fix_path[2] == PATHSEP)) { xfree(buf); goto error_return; @@ -690,7 +690,7 @@ char *vim_findfile(void *search_ctx_arg) rest_of_wildcards = stackp->ffs_wc_path; if (*rest_of_wildcards != NUL) { len = strlen(file_path); - if (strncmp(rest_of_wildcards, "**", 2) == 0) { + if (strncmp(rest_of_wildcards, S_LEN("**")) == 0) { // pointer to the restrict byte // The restrict byte is not a character! p = rest_of_wildcards + 2; @@ -867,7 +867,7 @@ char *vim_findfile(void *search_ctx_arg) // if wildcards contains '**' we have to descent till we reach the // leaves of the directory tree. - if (strncmp(stackp->ffs_wc_path, "**", 2) == 0) { + if (strncmp(stackp->ffs_wc_path, S_LEN("**")) == 0) { for (int i = stackp->ffs_filearray_cur; i < stackp->ffs_filearray_size; i++) { if (path_fnamecmp(stackp->ffs_filearray[i], diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 3078f00fbb..4b8121b423 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1896,7 +1896,7 @@ theend: bool is_dev_fd_file(char *fname) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - return strncmp(fname, "/dev/fd/", 8) == 0 + return strncmp(fname, S_LEN("/dev/fd/")) == 0 && ascii_isdigit((uint8_t)fname[8]) && *skipdigits(fname + 9) == NUL && (fname[9] != NUL diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index ce2c85f174..6167418052 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -566,7 +566,7 @@ void AppendToRedobuffLit(const char *str, int len) // CTRL-V '0' must be inserted as CTRL-V 048. if (*s == NUL && c == '0') { - add_buff(&redobuff, "048", 3); + add_buff(&redobuff, S_LEN("048")); } else { add_char_buff(&redobuff, c); } @@ -777,7 +777,7 @@ int start_redo(int count, bool old_redo) // copy the buffer name, if present if (c == '"') { - add_buff(&readbuf2, "\"", 1); + add_buff(&readbuf2, S_LEN("\"")); c = read_redo(false, old_redo); // if a numbered buffer is used, increment the number diff --git a/src/nvim/help.c b/src/nvim/help.c index 0da846bb9f..6ba3e17e0b 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -655,7 +655,7 @@ void get_local_additions(void) // files. This uses the very first line in the help file. char *const fname = path_tail(curbuf->b_fname); if (path_fnamecmp(fname, "help.txt") == 0 - || (path_fnamencmp(fname, "help.", 5) == 0 + || (path_fnamencmp(fname, S_LEN("help.")) == 0 && ASCII_ISALPHA(fname[5]) && ASCII_ISALPHA(fname[6]) && TOLOWER_ASC(fname[7]) == 'x' @@ -1015,7 +1015,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool // Write the tags into the file. for (int i = 0; i < ga.ga_len; i++) { s = ((char **)ga.ga_data)[i]; - if (strncmp(s, "help-tags\t", 10) == 0) { + if (strncmp(s, S_LEN("help-tags\t")) == 0) { // help-tags entry was added in formatted form fputs(s, fd_tags); } else { @@ -1149,7 +1149,7 @@ void ex_helptags(exarg_T *eap) bool add_help_tags = false; // Check for ":helptags ++t {dir}". - if (strncmp(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) { + if (strncmp(eap->arg, S_LEN("++t")) == 0 && ascii_iswhite(eap->arg[3])) { add_help_tags = true; eap->arg = skipwhite(eap->arg + 3); } diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index c32e1f9657..b8381c5183 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1057,7 +1057,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) } int from_id = syn_check_group(from_start, (size_t)(from_end - from_start)); - if (strncmp(to_start, "NONE", 4) == 0) { + if (strncmp(to_start, S_LEN("NONE")) == 0) { to_id = 0; } else { to_id = syn_check_group(to_start, (size_t)(to_end - to_start)); diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 66cb443e4d..a4964db465 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -782,20 +782,20 @@ bool briopt_check(win_T *wp) char *p = wp->w_p_briopt; while (*p != NUL) { // Note: Keep this in sync with p_briopt_values - if (strncmp(p, "shift:", 6) == 0 + if (strncmp(p, S_LEN("shift:")) == 0 && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) { p += 6; bri_shift = getdigits_int(&p, true, 0); - } else if (strncmp(p, "min:", 4) == 0 && ascii_isdigit(p[4])) { + } else if (strncmp(p, S_LEN("min:")) == 0 && ascii_isdigit(p[4])) { p += 4; bri_min = getdigits_int(&p, true, 0); - } else if (strncmp(p, "sbr", 3) == 0) { + } else if (strncmp(p, S_LEN("sbr")) == 0) { p += 3; bri_sbr = true; - } else if (strncmp(p, "list:", 5) == 0) { + } else if (strncmp(p, S_LEN("list:")) == 0) { p += 5; bri_list = (int)getdigits(&p, false, 0); - } else if (strncmp(p, "column:", 7) == 0) { + } else if (strncmp(p, S_LEN("column:")) == 0) { p += 7; bri_vcol = (int)getdigits(&p, false, 0); } diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index f7215d3d12..a2dffa4602 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -904,7 +904,7 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co } // Check for special <> keycodes, like "" if (do_special && ((flags & REPTERM_DO_LT) || ((end - src) >= 3 - && strncmp(src, "", 4) != 0))) { + && strncmp(src, S_LEN("")) != 0))) { // Change Func to K_SNR _Func. This name is used // for script-local user functions. // (room: 5 * 6 = 30 bytes; needed: 3 + + 1 <= 14) diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 167111f3ae..d02c865328 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -403,43 +403,43 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa // Accept , , , ,