From da70c394053e2110aedf5a8ea72cbaba0ccf06d9 Mon Sep 17 00:00:00 2001 From: Liad Oz Date: Wed, 7 Dec 2022 19:07:56 +0200 Subject: fix(extmarks): adjust extmarks when inserting prompt prefix --- src/nvim/edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 36a8674730..b83e732cec 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1484,7 +1484,7 @@ static void init_prompt(int cmdchar_todo) } curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; coladvance(MAXCOL); - changed_bytes(curbuf->b_ml.ml_line_count, 0); + inserted_bytes(curbuf->b_ml.ml_line_count, 0, 0, (colnr_T)strlen(prompt)); } // Insert always starts after the prompt, allow editing text after it. -- cgit From c94d8e7f13bbe6aa0d195eeac115695e0d95e7f3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 07:31:32 +0800 Subject: vim-patch:9.0.1244: cursor displayed in wrong position when leaving Insert mode (#21996) Problem: Cursor briefly displayed in a wrong position when pressing Esc in Insert mode after autoindent was used. Solution: Do not adjust the cursor position for assumed deleted white space if text is following. (closes vim/vim#11877) https://github.com/vim/vim/commit/0f843ef091eceb470caece1d90fdfe08926fe076 Co-authored-by: Bram Moolenaar --- src/nvim/getchar.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 9c5364e1b1..51554fea22 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2526,10 +2526,12 @@ static int vgetorpeek(bool advance) // move cursor left, if possible if (curwin->w_cursor.col != 0) { if (curwin->w_wcol > 0) { - if (did_ai) { - // We are expecting to truncate the trailing - // white-space, so find the last non-white - // character -- webb + // After auto-indenting and no text is following, + // we are expecting to truncate the trailing + // white-space, so find the last non-white + // character -- webb + if (did_ai + && *skipwhite(get_cursor_line_ptr() + curwin->w_cursor.col) == NUL) { curwin->w_wcol = 0; ptr = (char_u *)get_cursor_line_ptr(); chartabsize_T cts; -- cgit From f15947866ce59589346a4074a1fdc10f941a16b5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 07:46:51 +0800 Subject: vim-patch:9.0.1243: :setglobal cannot use script-local function for "expr" option (#21997) Problem: :setglobal cannot use script-local function for "expr" option. Solution: Use the pointer to the option value properly. (closes vim/vim#11883) https://github.com/vim/vim/commit/01d4efe2e87632aa085897d3d64e27585908f977 --- src/nvim/optionstr.c | 33 ++++++++++------------- src/nvim/testdir/test_edit.vim | 15 +++++++++++ src/nvim/testdir/test_fold.vim | 58 +++++++++++++++++++++++++++++++++++++--- src/nvim/testdir/test_gf.vim | 25 +++++++++++++++++ src/nvim/testdir/test_normal.vim | 46 +++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index a5a708600f..162d8b691a 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -1497,12 +1497,12 @@ static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, char **errms } } -static void did_set_optexpr(win_T *win, char **p_opt, char **varp, char **gvarp) +static void did_set_optexpr(char **varp) { - char *name = get_scriptlocal_funcname(*p_opt); + char *name = get_scriptlocal_funcname(*varp); if (name != NULL) { - free_string_option(*p_opt); - *p_opt = name; + free_string_option(*varp); + *varp = name; } } @@ -1808,23 +1808,18 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char did_set_varsoftabstop(buf, varp, &errmsg); } else if (varp == &buf->b_p_vts) { // 'vartabstop' did_set_vartabstop(buf, win, varp, &errmsg); - } else if (varp == &p_dex) { // 'diffexpr' - did_set_optexpr(win, &p_dex, varp, gvarp); - } else if (varp == &win->w_p_fde) { // 'foldexpr' - did_set_optexpr(win, &win->w_p_fde, varp, gvarp); - if (foldmethodIsExpr(win)) { + } else if (varp == &p_dex // 'diffexpr' + || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr' + || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext' + || gvarp == &p_fex // 'formatexpr' + || gvarp == &p_inex // 'includeexpr' + || gvarp == &p_inde // 'indentexpr' + || varp == &p_pex // 'patchexpr' + || varp == &p_ccv) { // 'charconvert' + did_set_optexpr(varp); + if (varp == &win->w_p_fde && foldmethodIsExpr(win)) { foldUpdateAll(win); } - } else if (varp == &win->w_p_fdt) { // 'foldtext' - did_set_optexpr(win, &win->w_p_fdt, varp, gvarp); - } else if (varp == &p_pex) { // 'patchexpr' - did_set_optexpr(win, &p_pex, varp, gvarp); - } else if (gvarp == &p_fex) { // 'formatexpr' - did_set_optexpr(win, &buf->b_p_fex, varp, gvarp); - } else if (gvarp == &p_inex) { // 'includeexpr' - did_set_optexpr(win, &buf->b_p_inex, varp, gvarp); - } else if (gvarp == &p_inde) { // 'indentexpr' - did_set_optexpr(win, &buf->b_p_inde, varp, gvarp); } else if (gvarp == &p_cfu) { // 'completefunc' set_completefunc_option(&errmsg); } else if (gvarp == &p_ofu) { // 'omnifunc' diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index fd54f77ccb..89a9179e60 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -336,8 +336,23 @@ func Test_edit_11_indentexpr() endfunc set indentexpr=s:NewIndentExpr() call assert_equal(expand('') .. 'NewIndentExpr()', &indentexpr) + call assert_equal(expand('') .. 'NewIndentExpr()', &g:indentexpr) set indentexpr=NewIndentExpr() call assert_equal(expand('') .. 'NewIndentExpr()', &indentexpr) + call assert_equal(expand('') .. 'NewIndentExpr()', &g:indentexpr) + setlocal indentexpr= + setglobal indentexpr=s:NewIndentExpr() + call assert_equal(expand('') .. 'NewIndentExpr()', &g:indentexpr) + call assert_equal('', &indentexpr) + new + call assert_equal(expand('') .. 'NewIndentExpr()', &indentexpr) + bw! + setglobal indentexpr=NewIndentExpr() + call assert_equal(expand('') .. 'NewIndentExpr()', &g:indentexpr) + call assert_equal('', &indentexpr) + new + call assert_equal(expand('') .. 'NewIndentExpr()', &indentexpr) + bw! set indentexpr& bw! diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim index 19415286ad..9014948fb4 100644 --- a/src/nvim/testdir/test_fold.vim +++ b/src/nvim/testdir/test_fold.vim @@ -1305,6 +1305,7 @@ func Test_foldexpr_scriptlocal_func() set foldmethod=expr foldexpr=s:FoldFunc() redraw! call assert_equal(expand('') .. 'FoldFunc()', &foldexpr) + call assert_equal(expand('') .. 'FoldFunc()', &g:foldexpr) call assert_equal(1, g:FoldLnum) set foldmethod& foldexpr= bw! @@ -1314,8 +1315,31 @@ func Test_foldexpr_scriptlocal_func() set foldmethod=expr foldexpr=FoldFunc() redraw! call assert_equal(expand('') .. 'FoldFunc()', &foldexpr) + call assert_equal(expand('') .. 'FoldFunc()', &g:foldexpr) call assert_equal(1, g:FoldLnum) - set foldmethod& foldexpr= + bw! + call setline(1, 'abc') + setlocal foldmethod& foldexpr& + setglobal foldmethod=expr foldexpr=s:FoldFunc() + call assert_equal(expand('') .. 'FoldFunc()', &g:foldexpr) + call assert_equal('0', &foldexpr) + enew! + call setline(1, 'abc') + redraw! + call assert_equal(expand('') .. 'FoldFunc()', &foldexpr) + call assert_equal(1, g:FoldLnum) + bw! + call setline(1, 'abc') + setlocal foldmethod& foldexpr& + setglobal foldmethod=expr foldexpr=FoldFunc() + call assert_equal(expand('') .. 'FoldFunc()', &g:foldexpr) + call assert_equal('0', &foldexpr) + enew! + call setline(1, 'abc') + redraw! + call assert_equal(expand('') .. 'FoldFunc()', &foldexpr) + call assert_equal(1, g:FoldLnum) + set foldmethod& foldexpr& delfunc s:FoldFunc bw! endfunc @@ -1329,25 +1353,53 @@ func Test_foldtext_scriptlocal_func() new | only call setline(1, range(50)) let g:FoldTextArgs = [] - set foldmethod=manual set foldtext=s:FoldText() norm! 4Gzf4j redraw! call assert_equal(expand('') .. 'FoldText()', &foldtext) + call assert_equal(expand('') .. 'FoldText()', &g:foldtext) call assert_equal([4, 8], g:FoldTextArgs) set foldtext& bw! new | only call setline(1, range(50)) let g:FoldTextArgs = [] - set foldmethod=manual set foldtext=FoldText() norm! 8Gzf4j redraw! call assert_equal(expand('') .. 'FoldText()', &foldtext) + call assert_equal(expand('') .. 'FoldText()', &g:foldtext) call assert_equal([8, 12], g:FoldTextArgs) set foldtext& bw! + call setline(1, range(50)) + let g:FoldTextArgs = [] + setlocal foldtext& + setglobal foldtext=s:FoldText() + call assert_equal(expand('') .. 'FoldText()', &g:foldtext) + call assert_equal('foldtext()', &foldtext) + enew! + call setline(1, range(50)) + norm! 12Gzf4j + redraw! + call assert_equal(expand('') .. 'FoldText()', &foldtext) + call assert_equal([12, 16], g:FoldTextArgs) + set foldtext& + bw! + call setline(1, range(50)) + let g:FoldTextArgs = [] + setlocal foldtext& + setglobal foldtext=FoldText() + call assert_equal(expand('') .. 'FoldText()', &g:foldtext) + call assert_equal('foldtext()', &foldtext) + enew! + call setline(1, range(50)) + norm! 16Gzf4j + redraw! + call assert_equal(expand('') .. 'FoldText()', &foldtext) + call assert_equal([16, 20], g:FoldTextArgs) + set foldtext& + bw! delfunc s:FoldText endfunc diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim index e369645328..f09dbd72ce 100644 --- a/src/nvim/testdir/test_gf.vim +++ b/src/nvim/testdir/test_gf.vim @@ -234,6 +234,7 @@ func Test_includeexpr_scriptlocal_func() endfunc set includeexpr=s:IncludeFunc() call assert_equal(expand('') .. 'IncludeFunc()', &includeexpr) + call assert_equal(expand('') .. 'IncludeFunc()', &g:includeexpr) new | only call setline(1, 'TestFile1') let g:IncludeFname = '' @@ -242,11 +243,35 @@ func Test_includeexpr_scriptlocal_func() bw! set includeexpr=IncludeFunc() call assert_equal(expand('') .. 'IncludeFunc()', &includeexpr) + call assert_equal(expand('') .. 'IncludeFunc()', &g:includeexpr) new | only call setline(1, 'TestFile2') let g:IncludeFname = '' call assert_fails('normal! gf', 'E447:') call assert_equal('TestFile2', g:IncludeFname) + bw! + setlocal includeexpr= + setglobal includeexpr=s:IncludeFunc() + call assert_equal(expand('') .. 'IncludeFunc()', &g:includeexpr) + call assert_equal('', &includeexpr) + new + call assert_equal(expand('') .. 'IncludeFunc()', &includeexpr) + call setline(1, 'TestFile3') + let g:IncludeFname = '' + call assert_fails('normal! gf', 'E447:') + call assert_equal('TestFile3', g:IncludeFname) + bw! + setlocal includeexpr= + setglobal includeexpr=IncludeFunc() + call assert_equal(expand('') .. 'IncludeFunc()', &g:includeexpr) + call assert_equal('', &includeexpr) + new + call assert_equal(expand('') .. 'IncludeFunc()', &includeexpr) + call setline(1, 'TestFile4') + let g:IncludeFname = '' + call assert_fails('normal! gf', 'E447:') + call assert_equal('TestFile4', g:IncludeFname) + bw! set includeexpr& delfunc s:IncludeFunc bw! diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index 7c90b444e5..2aaa1ff830 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -262,6 +262,7 @@ func Test_formatexpr_scriptlocal_func() endfunc set formatexpr=s:Format() call assert_equal(expand('') .. 'Format()', &formatexpr) + call assert_equal(expand('') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] @@ -270,6 +271,7 @@ func Test_formatexpr_scriptlocal_func() bw! set formatexpr=Format() call assert_equal(expand('') .. 'Format()', &formatexpr) + call assert_equal(expand('') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] @@ -277,6 +279,7 @@ func Test_formatexpr_scriptlocal_func() call assert_equal([4, 2], g:FormatArgs) bw! let &formatexpr = 's:Format()' + call assert_equal(expand('') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] @@ -284,12 +287,55 @@ func Test_formatexpr_scriptlocal_func() call assert_equal([6, 2], g:FormatArgs) bw! let &formatexpr = 'Format()' + call assert_equal(expand('') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] normal! 8GVjgq call assert_equal([8, 2], g:FormatArgs) + bw! setlocal formatexpr= + setglobal formatexpr=s:Format() + call assert_equal(expand('') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 10GVjgq + call assert_equal([10, 2], g:FormatArgs) + bw! + setglobal formatexpr=Format() + call assert_equal(expand('') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 12GVjgq + call assert_equal([12, 2], g:FormatArgs) + bw! + let &g:formatexpr = 's:Format()' + call assert_equal(expand('') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 14GVjgq + call assert_equal([14, 2], g:FormatArgs) + bw! + let &g:formatexpr = 'Format()' + call assert_equal(expand('') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 16GVjgq + call assert_equal([16, 2], g:FormatArgs) + bw! + set formatexpr= delfunc s:Format bw! endfunc -- cgit From 88e906d165b5dd57fb13b190ec9cb2d67bc6b223 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 08:52:21 +0800 Subject: vim-patch:9.0.1245: code is indented more than necessary (#21998) Problem: Code is indented more than necessary. Solution: Use an early return where it makes sense. (Yegappan Lakshmanan, closes vim/vim#11879) https://github.com/vim/vim/commit/032713f8299abd92fcfb1e490d1ae5c1ecadde41 Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 50 +++++------ src/nvim/eval/typval.c | 80 ++++++++--------- src/nvim/tag.c | 228 +++++++++++++++++++++++++------------------------ src/nvim/testing.c | 49 +++++------ src/nvim/textformat.c | 32 +++---- 5 files changed, 226 insertions(+), 213 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 5a31288ecd..c527b62c8f 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7823,34 +7823,35 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // MSVC returns NULL for an invalid value of seconds. if (curtime_ptr == NULL) { rettv->vval.v_string = xstrdup(_("(Invalid)")); - } else { - vimconv_T conv; + return; + } - conv.vc_type = CONV_NONE; - char *enc = enc_locale(); - convert_setup(&conv, p_enc, enc); - if (conv.vc_type != CONV_NONE) { - p = string_convert(&conv, p, NULL); - } - char result_buf[256]; - if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) { - result_buf[0] = NUL; - } + vimconv_T conv; - if (conv.vc_type != CONV_NONE) { - xfree(p); - } - convert_setup(&conv, enc, p_enc); - if (conv.vc_type != CONV_NONE) { - rettv->vval.v_string = string_convert(&conv, result_buf, NULL); - } else { - rettv->vval.v_string = xstrdup(result_buf); - } + conv.vc_type = CONV_NONE; + char *enc = enc_locale(); + convert_setup(&conv, p_enc, enc); + if (conv.vc_type != CONV_NONE) { + p = string_convert(&conv, p, NULL); + } + char result_buf[256]; + if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) { + result_buf[0] = NUL; + } - // Release conversion descriptors. - convert_setup(&conv, NULL, NULL); - xfree(enc); + if (conv.vc_type != CONV_NONE) { + xfree(p); } + convert_setup(&conv, enc, p_enc); + if (conv.vc_type != CONV_NONE) { + rettv->vval.v_string = string_convert(&conv, result_buf, NULL); + } else { + rettv->vval.v_string = xstrdup(result_buf); + } + + // Release conversion descriptors. + convert_setup(&conv, NULL, NULL); + xfree(enc); } /// "strgetchar()" function @@ -8654,6 +8655,7 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, EvalFuncData fptr emsg(_(e_number_exp)); return; } + int paused = (bool)tv_get_number(&argvars[1]); timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0])); if (timer != NULL) { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 05b4737206..c298064d86 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -3208,17 +3208,19 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic /// @param[in,out] tv Value to free. void tv_clear(typval_T *const tv) { - if (tv != NULL && tv->v_type != VAR_UNKNOWN) { - // WARNING: do not translate the string here, gettext is slow and function - // is used *very* often. At the current state encode_vim_to_nothing() does - // not error out and does not use the argument anywhere. - // - // If situation changes and this argument will be used, translate it in the - // place where it is used. - const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument"); - (void)evn_ret; - assert(evn_ret == OK); + if (tv == NULL || tv->v_type == VAR_UNKNOWN) { + return; } + + // WARNING: do not translate the string here, gettext is slow and function + // is used *very* often. At the current state encode_vim_to_nothing() does + // not error out and does not use the argument anywhere. + // + // If situation changes and this argument will be used, translate it in the + // place where it is used. + const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument"); + (void)evn_ret; + assert(evn_ret == OK); } //{{{3 Free @@ -3228,35 +3230,37 @@ void tv_clear(typval_T *const tv) /// @param tv Object to free. void tv_free(typval_T *tv) { - if (tv != NULL) { - switch (tv->v_type) { - case VAR_PARTIAL: - partial_unref(tv->vval.v_partial); - break; - case VAR_FUNC: - func_unref(tv->vval.v_string); - FALLTHROUGH; - case VAR_STRING: - xfree(tv->vval.v_string); - break; - case VAR_BLOB: - tv_blob_unref(tv->vval.v_blob); - break; - case VAR_LIST: - tv_list_unref(tv->vval.v_list); - break; - case VAR_DICT: - tv_dict_unref(tv->vval.v_dict); - break; - case VAR_BOOL: - case VAR_SPECIAL: - case VAR_NUMBER: - case VAR_FLOAT: - case VAR_UNKNOWN: - break; - } - xfree(tv); + if (tv == NULL) { + return; + } + + switch (tv->v_type) { + case VAR_PARTIAL: + partial_unref(tv->vval.v_partial); + break; + case VAR_FUNC: + func_unref(tv->vval.v_string); + FALLTHROUGH; + case VAR_STRING: + xfree(tv->vval.v_string); + break; + case VAR_BLOB: + tv_blob_unref(tv->vval.v_blob); + break; + case VAR_LIST: + tv_list_unref(tv->vval.v_list); + break; + case VAR_DICT: + tv_dict_unref(tv->vval.v_dict); + break; + case VAR_BOOL: + case VAR_SPECIAL: + case VAR_NUMBER: + case VAR_FLOAT: + case VAR_UNKNOWN: + break; } + xfree(tv); } //{{{3 Copy diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 197184c181..42618e8924 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -2732,55 +2732,57 @@ static int parse_match(char *lbuf, tagptrs_T *tagp) tagp->tagline = 0; tagp->command_end = NULL; - if (retval == OK) { - // Try to find a kind field: "kind:" or just "" - p = tagp->command; - if (find_extra(&p) == OK) { - tagp->command_end = p; - if (p > tagp->command && p[-1] == '|') { - tagp->command_end = p - 1; // drop trailing bar - } - p += 2; // skip ";\"" - if (*p++ == TAB) { - // Accept ASCII alphabetic kind characters and any multi-byte - // character. - while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) { - if (strncmp(p, "kind:", 5) == 0) { - tagp->tagkind = p + 5; - } else if (strncmp(p, "user_data:", 10) == 0) { - tagp->user_data = p + 10; - } else if (strncmp(p, "line:", 5) == 0) { - tagp->tagline = atoi(p + 5); - } - if (tagp->tagkind != NULL && tagp->user_data != NULL) { - break; - } + if (retval != OK) { + return retval; + } - pc = vim_strchr(p, ':'); - pt = vim_strchr(p, '\t'); - if (pc == NULL || (pt != NULL && pc > pt)) { - tagp->tagkind = p; - } - if (pt == NULL) { - break; - } - p = pt; - MB_PTR_ADV(p); + // Try to find a kind field: "kind:" or just "" + p = tagp->command; + if (find_extra(&p) == OK) { + tagp->command_end = p; + if (p > tagp->command && p[-1] == '|') { + tagp->command_end = p - 1; // drop trailing bar + } + p += 2; // skip ";\"" + if (*p++ == TAB) { + // Accept ASCII alphabetic kind characters and any multi-byte + // character. + while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) { + if (strncmp(p, "kind:", 5) == 0) { + tagp->tagkind = p + 5; + } else if (strncmp(p, "user_data:", 10) == 0) { + tagp->user_data = p + 10; + } else if (strncmp(p, "line:", 5) == 0) { + tagp->tagline = atoi(p + 5); } + if (tagp->tagkind != NULL && tagp->user_data != NULL) { + break; + } + + pc = vim_strchr(p, ':'); + pt = vim_strchr(p, '\t'); + if (pc == NULL || (pt != NULL && pc > pt)) { + tagp->tagkind = p; + } + if (pt == NULL) { + break; + } + p = pt; + MB_PTR_ADV(p); } } - if (tagp->tagkind != NULL) { - for (p = tagp->tagkind; - *p && *p != '\t' && *p != '\r' && *p != '\n'; - MB_PTR_ADV(p)) {} - tagp->tagkind_end = p; - } - if (tagp->user_data != NULL) { - for (p = tagp->user_data; - *p && *p != '\t' && *p != '\r' && *p != '\n'; - MB_PTR_ADV(p)) {} - tagp->user_data_end = p; - } + } + if (tagp->tagkind != NULL) { + for (p = tagp->tagkind; + *p && *p != '\t' && *p != '\r' && *p != '\n'; + MB_PTR_ADV(p)) {} + tagp->tagkind_end = p; + } + if (tagp->user_data != NULL) { + for (p = tagp->user_data; + *p && *p != '\t' && *p != '\r' && *p != '\n'; + MB_PTR_ADV(p)) {} + tagp->user_data_end = p; } return retval; } @@ -3329,86 +3331,88 @@ int get_tags(list_T *list, char *pat, char *buf_fname) ret = find_tags(pat, &num_matches, &matches, TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname); - if (ret == OK && num_matches > 0) { - for (i = 0; i < num_matches; i++) { - int parse_result = parse_match(matches[i], &tp); + if (ret != OK || num_matches <= 0) { + return ret; + } - // Avoid an unused variable warning in release builds. - (void)parse_result; - assert(parse_result == OK); + for (i = 0; i < num_matches; i++) { + int parse_result = parse_match(matches[i], &tp); - is_static = test_for_static(&tp); + // Avoid an unused variable warning in release builds. + (void)parse_result; + assert(parse_result == OK); - // Skip pseudo-tag lines. - if (strncmp(tp.tagname, "!_TAG_", 6) == 0) { - xfree(matches[i]); - continue; - } + is_static = test_for_static(&tp); + + // Skip pseudo-tag lines. + if (strncmp(tp.tagname, "!_TAG_", 6) == 0) { + xfree(matches[i]); + continue; + } - dict = tv_dict_alloc(); - tv_list_append_dict(list, dict); - - full_fname = tag_full_fname(&tp); - if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL - || add_tag_field(dict, "filename", full_fname, NULL) == FAIL - || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL - || add_tag_field(dict, "kind", tp.tagkind, - tp.tagkind ? tp.tagkind_end : NULL) == FAIL - || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) { - ret = FAIL; - } - - xfree(full_fname); - - if (tp.command_end != NULL) { - for (char *p = tp.command_end + 3; - *p != NUL && *p != '\n' && *p != '\r'; - MB_PTR_ADV(p)) { - if (p == tp.tagkind - || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) { - // skip "kind:" and "" - p = tp.tagkind_end - 1; - } else if (strncmp(p, "file:", 5) == 0) { - // skip "file:" (static tag) - p += 4; - } else if (!ascii_iswhite(*p)) { - char *s, *n; - int len; - - // Add extra field as a dict entry. Fields are - // separated by Tabs. - n = p; - while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') { + dict = tv_dict_alloc(); + tv_list_append_dict(list, dict); + + full_fname = tag_full_fname(&tp); + if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL + || add_tag_field(dict, "filename", full_fname, NULL) == FAIL + || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL + || add_tag_field(dict, "kind", tp.tagkind, + tp.tagkind ? tp.tagkind_end : NULL) == FAIL + || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) { + ret = FAIL; + } + + xfree(full_fname); + + if (tp.command_end != NULL) { + for (char *p = tp.command_end + 3; + *p != NUL && *p != '\n' && *p != '\r'; + MB_PTR_ADV(p)) { + if (p == tp.tagkind + || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) { + // skip "kind:" and "" + p = tp.tagkind_end - 1; + } else if (strncmp(p, "file:", 5) == 0) { + // skip "file:" (static tag) + p += 4; + } else if (!ascii_iswhite(*p)) { + char *s, *n; + int len; + + // Add extra field as a dict entry. Fields are + // separated by Tabs. + n = p; + while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') { + p++; + } + len = (int)(p - n); + if (*p == ':' && len > 0) { + s = ++p; + while (*p != NUL && (uint8_t)(*p) >= ' ') { p++; } - len = (int)(p - n); - if (*p == ':' && len > 0) { - s = ++p; - while (*p != NUL && (uint8_t)(*p) >= ' ') { - p++; - } - n[len] = NUL; - if (add_tag_field(dict, n, s, p) == FAIL) { - ret = FAIL; - } - n[len] = ':'; - } else { - // Skip field without colon. - while (*p != NUL && (uint8_t)(*p) >= ' ') { - p++; - } + n[len] = NUL; + if (add_tag_field(dict, n, s, p) == FAIL) { + ret = FAIL; } - if (*p == NUL) { - break; + n[len] = ':'; + } else { + // Skip field without colon. + while (*p != NUL && (uint8_t)(*p) >= ' ') { + p++; } } + if (*p == NUL) { + break; + } } } - - xfree(matches[i]); } - xfree(matches); + + xfree(matches[i]); } + xfree(matches); return ret; } diff --git a/src/nvim/testing.c b/src/nvim/testing.c index edf92c78ac..b5921b3445 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -77,31 +77,32 @@ static void ga_concat_esc(garray_T *gap, const char *p, int clen) memmove(buf, p, (size_t)clen); buf[clen] = NUL; ga_concat(gap, buf); - } else { - switch (*p) { - case BS: - ga_concat(gap, "\\b"); break; - case ESC: - ga_concat(gap, "\\e"); break; - case FF: - ga_concat(gap, "\\f"); break; - case NL: - ga_concat(gap, "\\n"); break; - case TAB: - ga_concat(gap, "\\t"); break; - case CAR: - ga_concat(gap, "\\r"); break; - case '\\': - ga_concat(gap, "\\\\"); break; - default: - if ((uint8_t)(*p) < ' ' || *p == 0x7f) { - vim_snprintf(buf, NUMBUFLEN, "\\x%02x", *p); - ga_concat(gap, buf); - } else { - ga_append(gap, (uint8_t)(*p)); - } - break; + return; + } + + switch (*p) { + case BS: + ga_concat(gap, "\\b"); break; + case ESC: + ga_concat(gap, "\\e"); break; + case FF: + ga_concat(gap, "\\f"); break; + case NL: + ga_concat(gap, "\\n"); break; + case TAB: + ga_concat(gap, "\\t"); break; + case CAR: + ga_concat(gap, "\\r"); break; + case '\\': + ga_concat(gap, "\\\\"); break; + default: + if ((uint8_t)(*p) < ' ' || *p == 0x7f) { + vim_snprintf(buf, NUMBUFLEN, "\\x%02x", *p); + ga_concat(gap, buf); + } else { + ga_append(gap, (uint8_t)(*p)); } + break; } } diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index fbea1ccfb7..e30580a748 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -736,22 +736,24 @@ void check_auto_format(bool end_insert) int c = ' '; int cc; - if (did_add_space) { - cc = gchar_cursor(); - if (!WHITECHAR(cc)) { - // Somehow the space was removed already. + if (!did_add_space) { + return; + } + + cc = gchar_cursor(); + if (!WHITECHAR(cc)) { + // Somehow the space was removed already. + did_add_space = false; + } else { + if (!end_insert) { + inc_cursor(); + c = gchar_cursor(); + dec_cursor(); + } + if (c != NUL) { + // The space is no longer at the end of the line, delete it. + del_char(false); did_add_space = false; - } else { - if (!end_insert) { - inc_cursor(); - c = gchar_cursor(); - dec_cursor(); - } - if (c != NUL) { - // The space is no longer at the end of the line, delete it. - del_char(false); - did_add_space = false; - } } } } -- cgit From 116766f243b4ac647f040181334c8001e01aab75 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 09:12:33 +0800 Subject: refactor(options): don't pass negative number to illegal_char() (#21999) This only changes the error messages for an unexpected Unicode char in an option to show its first byte instead of some special keycode. The second argument of vim_strchr() usually doesn't matter, but it may be better to consistently cast to uint8_t. --- src/nvim/optionstr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 162d8b691a..5ebff9ed77 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -615,7 +615,7 @@ char *check_stl_option(char *s) continue; } if (vim_strchr(STL_ALL, (uint8_t)(*s)) == NULL) { - return illegal_char(errbuf, sizeof(errbuf), *s); + return illegal_char(errbuf, sizeof(errbuf), (uint8_t)(*s)); } if (*s == '{') { bool reevaluate = (*++s == '%'); @@ -957,7 +957,7 @@ static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, char * while (*s && *s != ':') { if (vim_strchr(COM_ALL, (uint8_t)(*s)) == NULL && !ascii_isdigit(*s) && *s != '-') { - *errmsg = illegal_char(errbuf, errbuflen, *s); + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); break; } s++; @@ -1029,7 +1029,7 @@ static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, ch for (char *s = p_shada; *s;) { // Check it's a valid character if (vim_strchr("!\"%'/:<@cfhnrs", (uint8_t)(*s)) == NULL) { - *errmsg = illegal_char(errbuf, errbuflen, *s); + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); break; } if (*s == 'n') { // name is always last one @@ -1236,7 +1236,7 @@ static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, char * break; } if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) { - *errmsg = illegal_char(errbuf, errbuflen, *s); + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); break; } if (*++s != NUL && *s != ',' && *s != ' ') { @@ -1511,8 +1511,8 @@ static void did_set_option_listflag(char **varp, char *flags, char *errbuf, size char **errmsg) { for (char *s = *varp; *s; s++) { - if (vim_strchr(flags, *s) == NULL) { - *errmsg = illegal_char(errbuf, errbuflen, *s); + if (vim_strchr(flags, (uint8_t)(*s)) == NULL) { + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); break; } } -- cgit From 5ac34cf55db2b00c044fa95f75766dd89dd36ba9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 09:30:26 +0800 Subject: refactor(intro): avoid Coverity warning (#22000) refactor(intro): avoid coverity warning Problem: Coverity warns about overwriting "mesg" leaking memory. Solution: Make it clear that "mesg" will not be overwritten. --- src/nvim/version.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/nvim/version.c b/src/nvim/version.c index 417e5116a5..11f1d6695e 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -2785,13 +2785,6 @@ void maybe_intro_message(void) /// @param colon true for ":intro" void intro_message(int colon) { - int i; - long row; - long blanklines; - int sponsor; - char *p; - char *mesg; - int mesg_size; static char *(lines[]) = { N_(NVIM_VERSION_LONG), "", @@ -2813,7 +2806,7 @@ void intro_message(int colon) size_t lines_size = ARRAY_SIZE(lines); assert(lines_size <= LONG_MAX); - blanklines = Rows - ((long)lines_size - 1L); + long blanklines = Rows - ((long)lines_size - 1L); // Don't overwrite a statusline. Depends on 'cmdheight'. if (p_ls > 1) { @@ -2826,17 +2819,17 @@ void intro_message(int colon) // Show the sponsor and register message one out of four times, the Uganda // message two out of four times. - sponsor = (int)time(NULL); + int sponsor = (int)time(NULL); sponsor = ((sponsor & 2) == 0) - ((sponsor & 4) == 0); // start displaying the message lines after half of the blank lines - row = blanklines / 2; + long row = blanklines / 2; if (((row >= 2) && (Columns >= 50)) || colon) { - for (i = 0; i < (int)ARRAY_SIZE(lines); i++) { - p = lines[i]; - mesg = NULL; - mesg_size = 0; + for (int i = 0; i < (int)ARRAY_SIZE(lines); i++) { + char *p = lines[i]; + char *mesg = NULL; + int mesg_size = 0; if (strstr(p, "news") != NULL) { p = _(p); @@ -2846,18 +2839,15 @@ void intro_message(int colon) mesg = xmallocz((size_t)mesg_size); snprintf(mesg, (size_t)mesg_size + 1, p, STR(NVIM_VERSION_MAJOR), STR(NVIM_VERSION_MINOR)); - } - - if (sponsor != 0) { + } else if (sponsor != 0) { if (strstr(p, "children") != NULL) { - mesg = sponsor < 0 - ? _("Sponsor Vim development!") - : _("Become a registered Vim user!"); - } - if (strstr(p, "iccf") != NULL) { - mesg = sponsor < 0 - ? _("type :help sponsor for information ") - : _("type :help register for information "); + p = sponsor < 0 + ? N_("Sponsor Vim development!") + : N_("Become a registered Vim user!"); + } else if (strstr(p, "iccf") != NULL) { + p = sponsor < 0 + ? N_("type :help sponsor for information ") + : N_("type :help register for information "); } } -- cgit From 6644786db078e019426f90cf85da50e3fa1b6a67 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 09:44:15 +0800 Subject: vim-patch:9.0.1227: no cmdline completion for :runtime Problem: No cmdline completion for :runtime. Solution: Add completion for :runtime. (closes vim/vim#11853, closes vim/vim#11447) Improve the resulting matches. https://github.com/vim/vim/commit/a6759381a590b2d395e05b109ca9ccfc356be5a8 --- src/nvim/cmdexpand.c | 12 +++++++ src/nvim/runtime.c | 70 ++++++++++++++++++++++++++++++++------- src/nvim/runtime.h | 1 + src/nvim/testdir/test_cmdline.vim | 9 +++++ src/nvim/usercmd.c | 1 + src/nvim/vim.h | 1 + 6 files changed, 82 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index be815151ef..3e06814d6a 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -109,6 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp) && xp->xp_context != EXPAND_OLD_SETTING && xp->xp_context != EXPAND_OWNSYNTAX && xp->xp_context != EXPAND_PACKADD + && xp->xp_context != EXPAND_RUNTIME && xp->xp_context != EXPAND_SHELLCMD && xp->xp_context != EXPAND_TAGS && xp->xp_context != EXPAND_TAGS_LISTFILES @@ -1211,6 +1212,7 @@ char *addstar(char *fname, size_t len, int context) if (context == EXPAND_HELP || context == EXPAND_CHECKHEALTH || context == EXPAND_COLORS + || context == EXPAND_RUNTIME || context == EXPAND_COMPILER || context == EXPAND_OWNSYNTAX || context == EXPAND_FILETYPE @@ -2072,6 +2074,11 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa xp->xp_pattern = (char *)arg; break; + case CMD_runtime: + xp->xp_context = EXPAND_RUNTIME; + xp->xp_pattern = (char *)arg; + break; + case CMD_compiler: xp->xp_context = EXPAND_COMPILER; xp->xp_pattern = (char *)arg; @@ -2712,6 +2719,11 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM char *directories[] = { "colors", NULL }; return ExpandRTDir(pat, DIP_START + DIP_OPT, numMatches, matches, directories); } + if (xp->xp_context == EXPAND_RUNTIME) { + char *directories[] = { "", NULL }; + return ExpandRTDir(pat, DIP_START + DIP_OPT + DIP_PRNEXT, numMatches, + matches, directories); + } if (xp->xp_context == EXPAND_COMPILER) { char *directories[] = { "compiler", NULL }; return ExpandRTDir(pat, 0, numMatches, matches, directories); diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 24500b80b9..068a43c790 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -1194,11 +1194,22 @@ int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirname // TODO(bfredl): this is bullshit, expandpath should not reinvent path logic. for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = strlen(dirnames[i]) + pat_len + 16; - char *s = xmalloc(size); - snprintf(s, size, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); - globpath(p_rtp, s, &ga, 0); - xfree(s); + size_t size = strlen(dirnames[i]) + pat_len * 2 + 26; + char *buf = xmalloc(size); + if (*dirnames[i] == NUL) { + // empty dir used for :runtime + if (path_tail(pat) == pat) { + // no path separator, match dir names and script files + snprintf(buf, size, "\\(%s*.\\(vim\\|lua\\)\\)\\|\\(%s*\\)", pat, pat); + } else { + // has path separator, match script files + snprintf(buf, size, "%s*.vim", pat); + } + } else { + snprintf(buf, size, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); + } + globpath(p_rtp, buf, &ga, 0); + xfree(buf); } if (flags & DIP_START) { @@ -1241,18 +1252,53 @@ int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirname char *match = ((char **)ga.ga_data)[i]; char *s = match; char *e = s + strlen(s); + char *res_start = s; + if ((flags & DIP_PRNEXT) != 0) { + char *p = strstr(match, pat); + if (p != NULL) { + // Drop what comes before "pat" in the match, so that for + // match "/long/path/syntax/cpp.vim" with pattern + // "syntax/cp" we only keep "syntax/cpp.vim". + res_start = p; + } + } + if (e - s > 4 && (STRNICMP(e - 4, ".vim", 4) == 0 || STRNICMP(e - 4, ".lua", 4) == 0)) { - e -= 4; - for (s = e; s > match; MB_PTR_BACK(match, s)) { - if (vim_ispathsep(*s)) { - break; + if (res_start == s) { + // Only keep the file name. + // Remove file ext only if flag DIP_PRNEXT is not present. + if ((flags & DIP_PRNEXT) == 0) { + e -= 4; + } + for (s = e; s > match; MB_PTR_BACK(match, s)) { + if (s < match) { + break; + } + if (vim_ispathsep(*s)) { + res_start = s + 1; + break; + } } } - s++; + *e = NUL; - assert((e - s) + 1 >= 0); - memmove(match, s, (size_t)(e - s) + 1); + } + + if (res_start > match) { + assert((e - res_start) + 1 >= 0); + memmove(match, res_start, (size_t)(e - res_start) + 1); + } + + // remove entries that look like backup files + if (e > s && e[-1] == '~') { + xfree(match); + char **fnames = (char **)ga.ga_data; + for (int j = i + 1; j < ga.ga_len; ++j) { + fnames[j - 1] = fnames[j]; + } + ga.ga_len--; + i--; } } diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index 97063b900c..be2663d52a 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -105,6 +105,7 @@ typedef kvec_t(char *) CharVec; #define DIP_NORTP 0x20 // do not use 'runtimepath' #define DIP_NOAFTER 0x40 // skip "after" directories #define DIP_AFTER 0x80 // only use "after" directories +#define DIP_PRNEXT 0x100 // for print also file extension #define DIP_DIRFILE 0x200 // find both files and directories #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index cf1d56ae38..8f79f0d8a0 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -542,6 +542,15 @@ func Test_getcompletion() call assert_true(index(l, '') >= 0) let l = getcompletion('not', 'mapclear') call assert_equal([], l) + + let l = getcompletion('', 'runtime') + call assert_true(index(l, 'defaults.vim') >= 0) + let l = getcompletion('synt', 'runtime') + call assert_true(index(l, 'syntax') >= 0) + let l = getcompletion('syntax/vi', 'runtime') + call assert_true(index(l, 'syntax/vim.vim') >= 0) + let l = getcompletion('notexitsts', 'runtime') + call assert_equal([], l) let l = getcompletion('.', 'shellcmd') call assert_equal(['./', '../'], filter(l, 'v:val =~ "\\./"')) diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 31cb1e8936..ef13f67e49 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -89,6 +89,7 @@ static const char *command_complete[] = { [EXPAND_SYNTIME] = "syntime", [EXPAND_SETTINGS] = "option", [EXPAND_PACKADD] = "packadd", + [EXPAND_RUNTIME] = "runtime", [EXPAND_SHELLCMD] = "shellcmd", [EXPAND_SIGN] = "sign", [EXPAND_TAGS] = "tag", diff --git a/src/nvim/vim.h b/src/nvim/vim.h index c4baa911f1..3c765f8eb2 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -156,6 +156,7 @@ enum { EXPAND_DIFF_BUFFERS, EXPAND_BREAKPOINT, EXPAND_SCRIPTNAMES, + EXPAND_RUNTIME, EXPAND_CHECKHEALTH, EXPAND_LUA, }; -- cgit From 6320c91c50e4c0ee5c366241f9a413c4edbfdad8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 09:58:27 +0800 Subject: vim-patch:9.0.1231: completion of :runtime does not handle {where} argument Problem: Completion of :runtime does not handle {where} argument. Solution: Parse the {where} argument. (closes vim/vim#11863) https://github.com/vim/vim/commit/3770f4c9cde7b5fcd10b6fa2e665cd0b69450fb2 --- src/nvim/cmdexpand.c | 17 ++-- src/nvim/eval/funcs.c | 2 +- src/nvim/path.c | 2 +- src/nvim/runtime.c | 205 +++++++++++++++++++------------------- src/nvim/runtime.h | 2 +- src/nvim/testdir/test_cmdline.vim | 9 -- src/nvim/testdir/test_packadd.vim | 64 ++++++++++++ 7 files changed, 178 insertions(+), 123 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 3e06814d6a..21ea8c1ffc 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -2075,8 +2075,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa break; case CMD_runtime: - xp->xp_context = EXPAND_RUNTIME; - xp->xp_pattern = (char *)arg; + set_context_in_runtime_cmd(xp, arg); break; case CMD_compiler: @@ -2720,9 +2719,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM return ExpandRTDir(pat, DIP_START + DIP_OPT, numMatches, matches, directories); } if (xp->xp_context == EXPAND_RUNTIME) { - char *directories[] = { "", NULL }; - return ExpandRTDir(pat, DIP_START + DIP_OPT + DIP_PRNEXT, numMatches, - matches, directories); + return expand_runtime_cmd(pat, numMatches, matches); } if (xp->xp_context == EXPAND_COMPILER) { char *directories[] = { "compiler", NULL }; @@ -3213,11 +3210,12 @@ static int ExpandUserLua(expand_T *xp, int *num_file, char ***file) /// Expand `file` for all comma-separated directories in `path`. /// Adds matches to `ga`. -void globpath(char *path, char *file, garray_T *ga, int expand_options) +/// If "dirs" is true only expand directory names. +void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dirs) { expand_T xpc; ExpandInit(&xpc); - xpc.xp_context = EXPAND_FILES; + xpc.xp_context = dirs ? EXPAND_DIRECTORIES : EXPAND_FILES; char *buf = xmalloc(MAXPATHL); @@ -3536,11 +3534,14 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) set_context_in_menu_cmd(&xpc, "menu", xpc.xp_pattern, false); xpc.xp_pattern_len = strlen(xpc.xp_pattern); } - if (xpc.xp_context == EXPAND_SIGN) { set_context_in_sign_cmd(&xpc, xpc.xp_pattern); xpc.xp_pattern_len = strlen(xpc.xp_pattern); } + if (xpc.xp_context == EXPAND_RUNTIME) { + set_context_in_runtime_cmd(&xpc, xpc.xp_pattern); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); + } theend: if (cmdline_fuzzy_completion_supported(&xpc)) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c527b62c8f..938fef9a52 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2983,7 +2983,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (file != NULL && !error) { garray_T ga; ga_init(&ga, (int)sizeof(char *), 10); - globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags); + globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags, false); if (rettv->v_type == VAR_STRING) { rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n"); diff --git a/src/nvim/path.c b/src/nvim/path.c index 513f366a27..e4c2253357 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1138,7 +1138,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl if (flags & EW_ADDSLASH) { glob_flags |= WILD_ADD_SLASH; } - globpath(paths, pattern, gap, glob_flags); + globpath(paths, pattern, gap, glob_flags, false); xfree(paths); return gap->ga_len; diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 068a43c790..129d41ed22 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -208,31 +208,65 @@ void runtime_init(void) uv_mutex_init(&runtime_search_path_mutex); } +/// Get DIP_ flags from the [what] argument of a :runtime command. +/// "*argp" is advanced to after the [what] argument. +static int get_runtime_cmd_flags(char **argp) +{ + char *arg = *argp; + char *p = skiptowhite(arg); + size_t what_len = (size_t)(p - arg); + + if (what_len == 0) { + return 0; + } + + if (strncmp(arg, "START", what_len) == 0) { + *argp = skipwhite(arg + what_len); + return DIP_START + DIP_NORTP; + } + if (strncmp(arg, "OPT", what_len) == 0) { + *argp = skipwhite(arg + what_len); + return DIP_OPT + DIP_NORTP; + } + if (strncmp(arg, "PACK", what_len) == 0) { + *argp = skipwhite(arg + what_len); + return DIP_START + DIP_OPT + DIP_NORTP; + } + if (strncmp(arg, "ALL", what_len) == 0) { + *argp = skipwhite(arg + what_len); + return DIP_START + DIP_OPT; + } + + return 0; +} + /// ":runtime [what] {name}" void ex_runtime(exarg_T *eap) { char *arg = eap->arg; - char *p = skiptowhite(arg); - size_t len = (size_t)(p - arg); int flags = eap->forceit ? DIP_ALL : 0; - if (strncmp(arg, "START", len) == 0) { - flags += DIP_START + DIP_NORTP; - arg = skipwhite(arg + len); - } else if (strncmp(arg, "OPT", len) == 0) { - flags += DIP_OPT + DIP_NORTP; - arg = skipwhite(arg + len); - } else if (strncmp(arg, "PACK", len) == 0) { - flags += DIP_START + DIP_OPT + DIP_NORTP; - arg = skipwhite(arg + len); - } else if (strncmp(arg, "ALL", len) == 0) { - flags += DIP_START + DIP_OPT; - arg = skipwhite(arg + len); - } - + flags += get_runtime_cmd_flags(&arg); source_runtime(arg, flags); } +static int runtime_expand_flags; + +/// Set the completion context for the :runtime command. +void set_context_in_runtime_cmd(expand_T *xp, const char *arg) +{ + runtime_expand_flags = DIP_KEEPEXT + get_runtime_cmd_flags((char **)&arg); + xp->xp_context = EXPAND_RUNTIME; + xp->xp_pattern = (char *)arg; +} + +/// Handle command line completion for :runtime command. +int expand_runtime_cmd(char *pat, int *numMatches, char ***matches) +{ + char *directories[] = {"", NULL}; + return ExpandRTDir(pat, runtime_expand_flags, numMatches, matches, directories); +} + static void source_callback(char *fname, void *cookie) { (void)do_source(fname, false, DOSO_NONE); @@ -1194,57 +1228,53 @@ int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirname // TODO(bfredl): this is bullshit, expandpath should not reinvent path logic. for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = strlen(dirnames[i]) + pat_len * 2 + 26; - char *buf = xmalloc(size); - if (*dirnames[i] == NUL) { - // empty dir used for :runtime - if (path_tail(pat) == pat) { - // no path separator, match dir names and script files - snprintf(buf, size, "\\(%s*.\\(vim\\|lua\\)\\)\\|\\(%s*\\)", pat, pat); - } else { - // has path separator, match script files - snprintf(buf, size, "%s*.vim", pat); - } + const size_t buf_len = strlen(dirnames[i]) + pat_len + 31; + char *const buf = xmalloc(buf_len); + char *const tail = buf + 15; + const size_t tail_buflen = buf_len - 15; + int glob_flags = 0; + bool expand_dirs = false; + + if (*dirnames[i] == NUL) { // empty dir used for :runtime + snprintf(tail, tail_buflen, "%s*.\\(vim\\|lua\\)", pat); } else { - snprintf(buf, size, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); + snprintf(tail, tail_buflen, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); } - globpath(p_rtp, buf, &ga, 0); - xfree(buf); - } - if (flags & DIP_START) { - for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = strlen(dirnames[i]) + pat_len + 31; - char *s = xmalloc(size); - snprintf(s, size, "pack/*/start/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - xfree(s); +expand: + if ((flags & DIP_NORTP) == 0) { + globpath(p_rtp, tail, &ga, glob_flags, expand_dirs); } - for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = strlen(dirnames[i]) + pat_len + 31; - char *s = xmalloc(size); - snprintf(s, size, "start/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - xfree(s); + if (flags & DIP_START) { + memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT + globpath(p_pp, tail - 15, &ga, glob_flags, expand_dirs); + memcpy(tail - 8, "start/*/", 8); // NOLINT + globpath(p_pp, tail - 8, &ga, glob_flags, expand_dirs); } - } - if (flags & DIP_OPT) { - for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = strlen(dirnames[i]) + pat_len + 29; - char *s = xmalloc(size); - snprintf(s, size, "pack/*/opt/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - xfree(s); + if (flags & DIP_OPT) { + memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT + globpath(p_pp, tail - 13, &ga, glob_flags, expand_dirs); + memcpy(tail - 6, "opt/*/", 6); // NOLINT + globpath(p_pp, tail - 6, &ga, glob_flags, expand_dirs); } - for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = strlen(dirnames[i]) + pat_len + 29; - char *s = xmalloc(size); - snprintf(s, size, "opt/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - xfree(s); + if (*dirnames[i] == NUL && !expand_dirs) { + // expand dir names in another round + snprintf(tail, tail_buflen, "%s*", pat); + glob_flags = WILD_ADD_SLASH; + expand_dirs = true; + goto expand; + } + + xfree(buf); + } + + int pat_pathsep_cnt = 0; + for (size_t i = 0; i < pat_len; i++) { + if (vim_ispathsep(pat[i])) { + pat_pathsep_cnt++; } } @@ -1252,54 +1282,23 @@ int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirname char *match = ((char **)ga.ga_data)[i]; char *s = match; char *e = s + strlen(s); - char *res_start = s; - if ((flags & DIP_PRNEXT) != 0) { - char *p = strstr(match, pat); - if (p != NULL) { - // Drop what comes before "pat" in the match, so that for - // match "/long/path/syntax/cpp.vim" with pattern - // "syntax/cp" we only keep "syntax/cpp.vim". - res_start = p; - } - } - - if (e - s > 4 && (STRNICMP(e - 4, ".vim", 4) == 0 - || STRNICMP(e - 4, ".lua", 4) == 0)) { - if (res_start == s) { - // Only keep the file name. - // Remove file ext only if flag DIP_PRNEXT is not present. - if ((flags & DIP_PRNEXT) == 0) { - e -= 4; - } - for (s = e; s > match; MB_PTR_BACK(match, s)) { - if (s < match) { - break; - } - if (vim_ispathsep(*s)) { - res_start = s + 1; - break; - } - } - } - + if (e - s > 4 && (flags & DIP_KEEPEXT) == 0 + && (STRNICMP(e - 4, ".vim", 4) == 0 + || STRNICMP(e - 4, ".lua", 4) == 0)) { + e -= 4; *e = NUL; } - if (res_start > match) { - assert((e - res_start) + 1 >= 0); - memmove(match, res_start, (size_t)(e - res_start) + 1); - } - - // remove entries that look like backup files - if (e > s && e[-1] == '~') { - xfree(match); - char **fnames = (char **)ga.ga_data; - for (int j = i + 1; j < ga.ga_len; ++j) { - fnames[j - 1] = fnames[j]; + int match_pathsep_cnt = (e > s && e[-1] == '/') ? -1 : 0; + for (s = e; s > match; MB_PTR_BACK(match, s)) { + if (vim_ispathsep(*s) && ++match_pathsep_cnt > pat_pathsep_cnt) { + break; } - ga.ga_len--; - i--; } + s++; + *e = NUL; + assert((e - s) + 1 >= 0); + memmove(match, s, (size_t)(e - s) + 1); } if (GA_EMPTY(&ga)) { @@ -1329,9 +1328,9 @@ int ExpandPackAddDir(char *pat, int *num_file, char ***file) size_t buflen = pat_len + 26; char *s = xmalloc(buflen); snprintf(s, buflen, "pack/*/opt/%s*", pat); // NOLINT - globpath(p_pp, s, &ga, 0); + globpath(p_pp, s, &ga, 0, true); snprintf(s, buflen, "opt/%s*", pat); // NOLINT - globpath(p_pp, s, &ga, 0); + globpath(p_pp, s, &ga, 0, true); xfree(s); for (int i = 0; i < ga.ga_len; i++) { diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index be2663d52a..3821fc4bbc 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -105,7 +105,7 @@ typedef kvec_t(char *) CharVec; #define DIP_NORTP 0x20 // do not use 'runtimepath' #define DIP_NOAFTER 0x40 // skip "after" directories #define DIP_AFTER 0x80 // only use "after" directories -#define DIP_PRNEXT 0x100 // for print also file extension +#define DIP_KEEPEXT 0x100 // for completion: include file extension #define DIP_DIRFILE 0x200 // find both files and directories #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 8f79f0d8a0..cf1d56ae38 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -542,15 +542,6 @@ func Test_getcompletion() call assert_true(index(l, '') >= 0) let l = getcompletion('not', 'mapclear') call assert_equal([], l) - - let l = getcompletion('', 'runtime') - call assert_true(index(l, 'defaults.vim') >= 0) - let l = getcompletion('synt', 'runtime') - call assert_true(index(l, 'syntax') >= 0) - let l = getcompletion('syntax/vi', 'runtime') - call assert_true(index(l, 'syntax/vim.vim') >= 0) - let l = getcompletion('notexitsts', 'runtime') - call assert_equal([], l) let l = getcompletion('.', 'shellcmd') call assert_equal(['./', '../'], filter(l, 'v:val =~ "\\./"')) diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim index fcb8b8033b..3f00548273 100644 --- a/src/nvim/testdir/test_packadd.vim +++ b/src/nvim/testdir/test_packadd.vim @@ -193,8 +193,10 @@ func Test_packadd_completion() call mkdir(optdir1 . '/pluginA', 'p') call mkdir(optdir1 . '/pluginC', 'p') + call writefile([], optdir1 . '/unrelated') call mkdir(optdir2 . '/pluginB', 'p') call mkdir(optdir2 . '/pluginC', 'p') + call writefile([], optdir2 . '/unrelated') let li = [] call feedkeys(":packadd \')\call add(li, '\", 't') @@ -358,4 +360,66 @@ func Test_runtime() call assert_equal('runstartopt', g:sequence) endfunc +func Test_runtime_completion() + let rundir = &packpath . '/runtime/Xextra' + let startdir = &packpath . '/pack/mine/start/foo/Xextra' + let optdir = &packpath . '/pack/mine/opt/bar/Xextra' + call mkdir(rundir . '/Xrunbaz', 'p') + call mkdir(startdir . '/Xstartbaz', 'p') + call mkdir(optdir . '/Xoptbaz', 'p') + call writefile([], rundir . '/../Xrunfoo.vim') + call writefile([], rundir . '/Xrunbar.vim') + call writefile([], rundir . '/Xunrelated') + call writefile([], rundir . '/../Xunrelated') + call writefile([], startdir . '/../Xstartfoo.vim') + call writefile([], startdir . '/Xstartbar.vim') + call writefile([], startdir . '/Xunrelated') + call writefile([], startdir . '/../Xunrelated') + call writefile([], optdir . '/../Xoptfoo.vim') + call writefile([], optdir . '/Xoptbar.vim') + call writefile([], optdir . '/Xunrelated') + call writefile([], optdir . '/../Xunrelated') + exe 'set rtp=' . &packpath . '/runtime' + + func Check_runtime_completion(arg, arg1, res) + call feedkeys(':runtime ' .. a:arg .. "\\\"\", 'xt') + call assert_equal('"runtime ' .. a:arg1 .. join(a:res), @:) + call assert_equal(a:res, getcompletion(a:arg, 'runtime')) + + call feedkeys(':runtime ' .. a:arg .. "X\\\"\", 'xt') + call assert_equal('"runtime ' .. a:arg1 .. join(a:res), @:) + call assert_equal(a:res, getcompletion(a:arg .. 'X', 'runtime')) + endfunc + + call Check_runtime_completion('', '', + \ ['Xextra/', 'Xrunfoo.vim']) + call Check_runtime_completion('Xextra/', '', + \ ['Xextra/Xrunbar.vim', 'Xextra/Xrunbaz/']) + + call Check_runtime_completion('START ', 'START ', + \ ['Xextra/', 'Xstartfoo.vim']) + call Check_runtime_completion('START Xextra/', 'START ', + \ ['Xextra/Xstartbar.vim', 'Xextra/Xstartbaz/']) + + call Check_runtime_completion('OPT ', 'OPT ', + \ ['Xextra/', 'Xoptfoo.vim']) + call Check_runtime_completion('OPT Xextra/', 'OPT ', + \ ['Xextra/Xoptbar.vim', 'Xextra/Xoptbaz/']) + + call Check_runtime_completion('PACK ', 'PACK ', + \ ['Xextra/', 'Xoptfoo.vim', 'Xstartfoo.vim']) + call Check_runtime_completion('PACK Xextra/', 'PACK ', + \ ['Xextra/Xoptbar.vim', 'Xextra/Xoptbaz/', + \ 'Xextra/Xstartbar.vim', 'Xextra/Xstartbaz/']) + + call Check_runtime_completion('ALL ', 'ALL ', + \ ['Xextra/', 'Xoptfoo.vim', 'Xrunfoo.vim', 'Xstartfoo.vim']) + call Check_runtime_completion('ALL Xextra/', 'ALL ', + \ ['Xextra/Xoptbar.vim', 'Xextra/Xoptbaz/', + \ 'Xextra/Xrunbar.vim', 'Xextra/Xrunbaz/', + \ 'Xextra/Xstartbar.vim', 'Xextra/Xstartbaz/']) + + delfunc Check_runtime_completion +endfunc + " vim: shiftwidth=2 sts=2 expandtab -- cgit From f03f6263bb3eb0b28b759292cb6ef4465a05cafe Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 10:38:53 +0800 Subject: vim-patch:9.0.1238: :runtime completion can be further improved Problem: :runtime completion can be further improved. Solution: Also complete the {where} argument values and adjust the completion for that. (closes vim/vim#11874) https://github.com/vim/vim/commit/5c8771bc5a2be123ab8e6325fa60ed524e8efb09 --- src/nvim/cmdexpand.c | 6 +- src/nvim/runtime.c | 151 +++++++++++++++++++++++--------------- src/nvim/runtime.h | 1 - src/nvim/testdir/test_packadd.vim | 92 +++++++++++++---------- 4 files changed, 148 insertions(+), 102 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 21ea8c1ffc..53d513b319 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -2718,9 +2718,6 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM char *directories[] = { "colors", NULL }; return ExpandRTDir(pat, DIP_START + DIP_OPT, numMatches, matches, directories); } - if (xp->xp_context == EXPAND_RUNTIME) { - return expand_runtime_cmd(pat, numMatches, matches); - } if (xp->xp_context == EXPAND_COMPILER) { char *directories[] = { "compiler", NULL }; return ExpandRTDir(pat, 0, numMatches, matches, directories); @@ -2742,6 +2739,9 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM if (xp->xp_context == EXPAND_PACKADD) { return ExpandPackAddDir(pat, numMatches, matches); } + if (xp->xp_context == EXPAND_RUNTIME) { + return expand_runtime_cmd(pat, numMatches, matches); + } // When expanding a function name starting with s:, match the nr_ // prefix. diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 129d41ed22..b071e10cf9 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -26,6 +26,7 @@ #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" +#include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" @@ -208,45 +209,43 @@ void runtime_init(void) uv_mutex_init(&runtime_search_path_mutex); } -/// Get DIP_ flags from the [what] argument of a :runtime command. -/// "*argp" is advanced to after the [what] argument. -static int get_runtime_cmd_flags(char **argp) +/// Get DIP_ flags from the [where] argument of a :runtime command. +/// "*argp" is advanced to after the [where] argument. +static int get_runtime_cmd_flags(char **argp, size_t where_len) { char *arg = *argp; - char *p = skiptowhite(arg); - size_t what_len = (size_t)(p - arg); - if (what_len == 0) { + if (where_len == 0) { return 0; } - if (strncmp(arg, "START", what_len) == 0) { - *argp = skipwhite(arg + what_len); + if (strncmp(arg, "START", where_len) == 0) { + *argp = skipwhite(arg + where_len); return DIP_START + DIP_NORTP; } - if (strncmp(arg, "OPT", what_len) == 0) { - *argp = skipwhite(arg + what_len); + if (strncmp(arg, "OPT", where_len) == 0) { + *argp = skipwhite(arg + where_len); return DIP_OPT + DIP_NORTP; } - if (strncmp(arg, "PACK", what_len) == 0) { - *argp = skipwhite(arg + what_len); + if (strncmp(arg, "PACK", where_len) == 0) { + *argp = skipwhite(arg + where_len); return DIP_START + DIP_OPT + DIP_NORTP; } - if (strncmp(arg, "ALL", what_len) == 0) { - *argp = skipwhite(arg + what_len); + if (strncmp(arg, "ALL", where_len) == 0) { + *argp = skipwhite(arg + where_len); return DIP_START + DIP_OPT; } return 0; } -/// ":runtime [what] {name}" +/// ":runtime [where] {name}" void ex_runtime(exarg_T *eap) { char *arg = eap->arg; int flags = eap->forceit ? DIP_ALL : 0; - - flags += get_runtime_cmd_flags(&arg); + char *p = skiptowhite(arg); + flags += get_runtime_cmd_flags(&arg, (size_t)(p - arg)); source_runtime(arg, flags); } @@ -255,18 +254,13 @@ static int runtime_expand_flags; /// Set the completion context for the :runtime command. void set_context_in_runtime_cmd(expand_T *xp, const char *arg) { - runtime_expand_flags = DIP_KEEPEXT + get_runtime_cmd_flags((char **)&arg); + char *p = skiptowhite(arg); + runtime_expand_flags + = *p != NUL ? get_runtime_cmd_flags((char **)&arg, (size_t)(p - arg)) : 0; xp->xp_context = EXPAND_RUNTIME; xp->xp_pattern = (char *)arg; } -/// Handle command line completion for :runtime command. -int expand_runtime_cmd(char *pat, int *numMatches, char ***matches) -{ - char *directories[] = {"", NULL}; - return ExpandRTDir(pat, runtime_expand_flags, numMatches, matches, directories); -} - static void source_callback(char *fname, void *cookie) { (void)do_source(fname, false, DOSO_NONE); @@ -1209,23 +1203,9 @@ void ex_packadd(exarg_T *eap) } } -/// Expand color scheme, compiler or filetype names. -/// Search from 'runtimepath': -/// 'runtimepath'/{dirnames}/{pat}.(vim|lua) -/// When "flags" has DIP_START: search also from "start" of 'packpath': -/// 'packpath'/pack/*/start/*/{dirnames}/{pat}.(vim|lua) -/// When "flags" has DIP_OPT: search also from "opt" of 'packpath': -/// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.(vim|lua) -/// "dirnames" is an array with one or more directory names. -int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[]) +static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap, + char *dirnames[]) { - *num_file = 0; - *file = NULL; - size_t pat_len = strlen(pat); - - garray_T ga; - ga_init(&ga, (int)sizeof(char *), 10); - // TODO(bfredl): this is bullshit, expandpath should not reinvent path logic. for (int i = 0; dirnames[i] != NULL; i++) { const size_t buf_len = strlen(dirnames[i]) + pat_len + 31; @@ -1243,21 +1223,21 @@ int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirname expand: if ((flags & DIP_NORTP) == 0) { - globpath(p_rtp, tail, &ga, glob_flags, expand_dirs); + globpath(p_rtp, tail, gap, glob_flags, expand_dirs); } if (flags & DIP_START) { memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT - globpath(p_pp, tail - 15, &ga, glob_flags, expand_dirs); + globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs); memcpy(tail - 8, "start/*/", 8); // NOLINT - globpath(p_pp, tail - 8, &ga, glob_flags, expand_dirs); + globpath(p_pp, tail - 8, gap, glob_flags, expand_dirs); } if (flags & DIP_OPT) { memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT - globpath(p_pp, tail - 13, &ga, glob_flags, expand_dirs); + globpath(p_pp, tail - 13, gap, glob_flags, expand_dirs); memcpy(tail - 6, "opt/*/", 6); // NOLINT - globpath(p_pp, tail - 6, &ga, glob_flags, expand_dirs); + globpath(p_pp, tail - 6, gap, glob_flags, expand_dirs); } if (*dirnames[i] == NUL && !expand_dirs) { @@ -1278,13 +1258,12 @@ expand: } } - for (int i = 0; i < ga.ga_len; i++) { - char *match = ((char **)ga.ga_data)[i]; + for (int i = 0; i < gap->ga_len; i++) { + char *match = ((char **)gap->ga_data)[i]; char *s = match; char *e = s + strlen(s); - if (e - s > 4 && (flags & DIP_KEEPEXT) == 0 - && (STRNICMP(e - 4, ".vim", 4) == 0 - || STRNICMP(e - 4, ".lua", 4) == 0)) { + if (e - s > 4 && !keep_ext && (STRNICMP(e - 4, ".vim", 4) == 0 + || STRNICMP(e - 4, ".lua", 4) == 0)) { e -= 4; *e = NUL; } @@ -1296,26 +1275,82 @@ expand: } } s++; - *e = NUL; - assert((e - s) + 1 >= 0); - memmove(match, s, (size_t)(e - s) + 1); + if (s != match) { + assert((e - s) + 1 >= 0); + memmove(match, s, (size_t)(e - s) + 1); + } } - if (GA_EMPTY(&ga)) { - return FAIL; + if (GA_EMPTY(gap)) { + return; } // Sort and remove duplicates which can happen when specifying multiple // directories in dirnames. - ga_remove_duplicate_strings(&ga); + ga_remove_duplicate_strings(gap); +} + +/// Expand color scheme, compiler or filetype names. +/// Search from 'runtimepath': +/// 'runtimepath'/{dirnames}/{pat}.(vim|lua) +/// When "flags" has DIP_START: search also from "start" of 'packpath': +/// 'packpath'/pack/*/start/*/{dirnames}/{pat}.(vim|lua) +/// When "flags" has DIP_OPT: search also from "opt" of 'packpath': +/// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.(vim|lua) +/// "dirnames" is an array with one or more directory names. +int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[]) +{ + *num_file = 0; + *file = NULL; + + garray_T ga; + ga_init(&ga, (int)sizeof(char *), 10); + + ExpandRTDir_int(pat, strlen(pat), flags, false, &ga, dirnames); + + if (GA_EMPTY(&ga)) { + return FAIL; + } *file = ga.ga_data; *num_file = ga.ga_len; return OK; } +/// Handle command line completion for :runtime command. +int expand_runtime_cmd(char *pat, int *numMatches, char ***matches) +{ + *numMatches = 0; + *matches = NULL; + + garray_T ga; + ga_init(&ga, sizeof(char *), 10); + + const size_t pat_len = strlen(pat); + char *dirnames[] = { "", NULL }; + ExpandRTDir_int(pat, pat_len, runtime_expand_flags, true, &ga, dirnames); + + // Try to complete values for [where] argument when none was found. + if (runtime_expand_flags == 0) { + char *where_values[] = { "START", "OPT", "PACK", "ALL" }; + for (size_t i = 0; i < ARRAY_SIZE(where_values); i++) { + if (strncmp(pat, where_values[i], pat_len) == 0) { + GA_APPEND(char *, &ga, xstrdup(where_values[i])); + } + } + } + + if (GA_EMPTY(&ga)) { + return FAIL; + } + + *matches = ga.ga_data; + *numMatches = ga.ga_len; + return OK; +} + /// Expand loadplugin names: -/// 'packpath'/pack/ * /opt/{pat} +/// 'packpath'/pack/*/opt/{pat} int ExpandPackAddDir(char *pat, int *num_file, char ***file) { garray_T ga; diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index 3821fc4bbc..97063b900c 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -105,7 +105,6 @@ typedef kvec_t(char *) CharVec; #define DIP_NORTP 0x20 // do not use 'runtimepath' #define DIP_NOAFTER 0x40 // skip "after" directories #define DIP_AFTER 0x80 // only use "after" directories -#define DIP_KEEPEXT 0x100 // for completion: include file extension #define DIP_DIRFILE 0x200 // find both files and directories #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim index 3f00548273..d577f32d55 100644 --- a/src/nvim/testdir/test_packadd.vim +++ b/src/nvim/testdir/test_packadd.vim @@ -361,63 +361,75 @@ func Test_runtime() endfunc func Test_runtime_completion() - let rundir = &packpath . '/runtime/Xextra' - let startdir = &packpath . '/pack/mine/start/foo/Xextra' - let optdir = &packpath . '/pack/mine/opt/bar/Xextra' - call mkdir(rundir . '/Xrunbaz', 'p') - call mkdir(startdir . '/Xstartbaz', 'p') - call mkdir(optdir . '/Xoptbaz', 'p') - call writefile([], rundir . '/../Xrunfoo.vim') - call writefile([], rundir . '/Xrunbar.vim') - call writefile([], rundir . '/Xunrelated') - call writefile([], rundir . '/../Xunrelated') - call writefile([], startdir . '/../Xstartfoo.vim') - call writefile([], startdir . '/Xstartbar.vim') - call writefile([], startdir . '/Xunrelated') - call writefile([], startdir . '/../Xunrelated') - call writefile([], optdir . '/../Xoptfoo.vim') - call writefile([], optdir . '/Xoptbar.vim') - call writefile([], optdir . '/Xunrelated') - call writefile([], optdir . '/../Xunrelated') + let rundir = &packpath . '/runtime/Aextra' + let startdir = &packpath . '/pack/mine/start/foo/Aextra' + let optdir = &packpath . '/pack/mine/opt/bar/Aextra' + call mkdir(rundir . '/Arunbaz', 'p') + call mkdir(startdir . '/Astartbaz', 'p') + call mkdir(optdir . '/Aoptbaz', 'p') + call writefile([], rundir . '/../Arunfoo.vim') + call writefile([], rundir . '/Arunbar.vim') + call writefile([], rundir . '/Aunrelated') + call writefile([], rundir . '/../Aunrelated') + call writefile([], startdir . '/../Astartfoo.vim') + call writefile([], startdir . '/Astartbar.vim') + call writefile([], startdir . '/Aunrelated') + call writefile([], startdir . '/../Aunrelated') + call writefile([], optdir . '/../Aoptfoo.vim') + call writefile([], optdir . '/Aoptbar.vim') + call writefile([], optdir . '/Aunrelated') + call writefile([], optdir . '/../Aunrelated') exe 'set rtp=' . &packpath . '/runtime' func Check_runtime_completion(arg, arg1, res) call feedkeys(':runtime ' .. a:arg .. "\\\"\", 'xt') call assert_equal('"runtime ' .. a:arg1 .. join(a:res), @:) call assert_equal(a:res, getcompletion(a:arg, 'runtime')) - - call feedkeys(':runtime ' .. a:arg .. "X\\\"\", 'xt') - call assert_equal('"runtime ' .. a:arg1 .. join(a:res), @:) - call assert_equal(a:res, getcompletion(a:arg .. 'X', 'runtime')) endfunc call Check_runtime_completion('', '', - \ ['Xextra/', 'Xrunfoo.vim']) - call Check_runtime_completion('Xextra/', '', - \ ['Xextra/Xrunbar.vim', 'Xextra/Xrunbaz/']) + \ ['Aextra/', 'Arunfoo.vim', 'START', 'OPT', 'PACK', 'ALL']) + call Check_runtime_completion('S', '', + \ ['START']) + call Check_runtime_completion('O', '', + \ ['OPT']) + call Check_runtime_completion('P', '', + \ ['PACK']) + call Check_runtime_completion('A', '', + \ ['Aextra/', 'Arunfoo.vim', 'ALL']) + call Check_runtime_completion('Aextra/', '', + \ ['Aextra/Arunbar.vim', 'Aextra/Arunbaz/']) call Check_runtime_completion('START ', 'START ', - \ ['Xextra/', 'Xstartfoo.vim']) - call Check_runtime_completion('START Xextra/', 'START ', - \ ['Xextra/Xstartbar.vim', 'Xextra/Xstartbaz/']) + \ ['Aextra/', 'Astartfoo.vim']) + call Check_runtime_completion('START A', 'START ', + \ ['Aextra/', 'Astartfoo.vim']) + call Check_runtime_completion('START Aextra/', 'START ', + \ ['Aextra/Astartbar.vim', 'Aextra/Astartbaz/']) call Check_runtime_completion('OPT ', 'OPT ', - \ ['Xextra/', 'Xoptfoo.vim']) - call Check_runtime_completion('OPT Xextra/', 'OPT ', - \ ['Xextra/Xoptbar.vim', 'Xextra/Xoptbaz/']) + \ ['Aextra/', 'Aoptfoo.vim']) + call Check_runtime_completion('OPT A', 'OPT ', + \ ['Aextra/', 'Aoptfoo.vim']) + call Check_runtime_completion('OPT Aextra/', 'OPT ', + \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/']) call Check_runtime_completion('PACK ', 'PACK ', - \ ['Xextra/', 'Xoptfoo.vim', 'Xstartfoo.vim']) - call Check_runtime_completion('PACK Xextra/', 'PACK ', - \ ['Xextra/Xoptbar.vim', 'Xextra/Xoptbaz/', - \ 'Xextra/Xstartbar.vim', 'Xextra/Xstartbaz/']) + \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('PACK A', 'PACK ', + \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('PACK Aextra/', 'PACK ', + \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/', + \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/']) call Check_runtime_completion('ALL ', 'ALL ', - \ ['Xextra/', 'Xoptfoo.vim', 'Xrunfoo.vim', 'Xstartfoo.vim']) - call Check_runtime_completion('ALL Xextra/', 'ALL ', - \ ['Xextra/Xoptbar.vim', 'Xextra/Xoptbaz/', - \ 'Xextra/Xrunbar.vim', 'Xextra/Xrunbaz/', - \ 'Xextra/Xstartbar.vim', 'Xextra/Xstartbaz/']) + \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('ALL A', 'ALL ', + \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('ALL Aextra/', 'ALL ', + \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/', + \ 'Aextra/Arunbar.vim', 'Aextra/Arunbaz/', + \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/']) delfunc Check_runtime_completion endfunc -- cgit From ebc80dcded59b3b9de147091395f7570066fb00c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 10:53:32 +0800 Subject: vim-patch:9.0.1242: code for :runtime completion is not consistent Problem: Code for :runtime completion is not consistent. Solution: Make code for cmdline expansion more consistent. (closes vim/vim#11875) https://github.com/vim/vim/commit/b0d45ec67f4976318f199a7929ad3bcf93686fd0 --- src/nvim/cmdexpand.c | 10 +++++----- src/nvim/option.c | 10 +++++----- src/nvim/testdir/test_packadd.vim | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 53d513b319..5e4b49db24 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -1212,11 +1212,11 @@ char *addstar(char *fname, size_t len, int context) if (context == EXPAND_HELP || context == EXPAND_CHECKHEALTH || context == EXPAND_COLORS - || context == EXPAND_RUNTIME || context == EXPAND_COMPILER || context == EXPAND_OWNSYNTAX || context == EXPAND_FILETYPE || context == EXPAND_PACKADD + || context == EXPAND_RUNTIME || ((context == EXPAND_TAGS_LISTFILES || context == EXPAND_TAGS) && fname[0] == '/')) { retval = xstrnsave(fname, len); @@ -2074,10 +2074,6 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa xp->xp_pattern = (char *)arg; break; - case CMD_runtime: - set_context_in_runtime_cmd(xp, arg); - break; - case CMD_compiler: xp->xp_context = EXPAND_COMPILER; xp->xp_pattern = (char *)arg; @@ -2098,6 +2094,10 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa xp->xp_pattern = (char *)arg; break; + case CMD_runtime: + set_context_in_runtime_cmd(xp, arg); + break; + #ifdef HAVE_WORKING_LIBINTL case CMD_language: return set_context_in_lang_cmd(xp, arg); diff --git a/src/nvim/option.c b/src/nvim/option.c index 01a5c7677f..ce76b99f8c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4824,12 +4824,12 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM return OK; } -void ExpandOldSetting(int *num_file, char ***file) +void ExpandOldSetting(int *numMatches, char ***matches) { char *var = NULL; - *num_file = 0; - *file = xmalloc(sizeof(char_u *)); + *numMatches = 0; + *matches = xmalloc(sizeof(char *)); // For a terminal key code expand_option_idx is < 0. if (expand_option_idx < 0) { @@ -4862,8 +4862,8 @@ void ExpandOldSetting(int *num_file, char ***file) } #endif - *file[0] = buf; - *num_file = 1; + *matches[0] = buf; + *numMatches = 1; } /// Get the value for the numeric or string option///opp in a nice format into diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim index d577f32d55..3121b3b4d1 100644 --- a/src/nvim/testdir/test_packadd.vim +++ b/src/nvim/testdir/test_packadd.vim @@ -26,7 +26,7 @@ func Test_packadd() let rtp_entries = split(rtp, ',') for entry in rtp_entries - if entry =~? '\' + if entry =~? '\' let first_after_entry = entry break endif @@ -186,7 +186,7 @@ func Test_packadd_symlink_dir2() exec "silent !rmdir" top2_dir endfunc -" Check command-line completion for 'packadd' +" Check command-line completion for :packadd func Test_packadd_completion() let optdir1 = &packpath . '/pack/mine/opt' let optdir2 = &packpath . '/pack/candidate/opt' @@ -262,9 +262,9 @@ func Test_helptags() helptags ALL - let tags1 = readfile(docdir1 . '/tags') + let tags1 = readfile(docdir1 . '/tags') call assert_match('look-here', tags1[0]) - let tags2 = readfile(docdir2 . '/tags') + let tags2 = readfile(docdir2 . '/tags') call assert_match('look-away', tags2[0]) call assert_fails('helptags abcxyz', 'E150:') -- cgit From 37b44d17727a03e6a2638da4d16ea85e80069d13 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 14:27:42 +0000 Subject: refactor(option.c): add do_set_num --- src/nvim/option.c | 121 +++++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 01a5c7677f..10773fffde 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -726,6 +726,67 @@ void ex_set(exarg_T *eap) (void)do_set(eap->arg, flags); } +static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, const set_op_T op, + const char *varp, char *errbuf, size_t errbuflen, char **errmsg) +{ + varnumber_T value; + char *arg = *argp; + + // Different ways to set a number option: + // & set to default value + // < set to global value + // accept special key codes for 'wildchar' + // c accept any non-digit for 'wildchar' + // [-]0-9 set number + // other error + arg++; + if (nextchar == '&') { + value = (long)(intptr_t)options[opt_idx].def_val; + } else if (nextchar == '<') { + // For 'undolevels' NO_LOCAL_UNDOLEVEL means to + // use the global value. + if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) { + value = NO_LOCAL_UNDOLEVEL; + } else { + value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + } + } else if (((long *)varp == &p_wc + || (long *)varp == &p_wcm) + && (*arg == '<' + || *arg == '^' + || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) + && !ascii_isdigit(*arg)))) { + value = string_to_key(arg); + if (value == 0 && (long *)varp != &p_wcm) { + *errmsg = e_invarg; + return; + } + } else if (*arg == '-' || ascii_isdigit(*arg)) { + int i; + // Allow negative, octal and hex numbers. + vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); + if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { + *errmsg = e_number_required_after_equal; + return; + } + } else { + *errmsg = e_number_required_after_equal; + return; + } + + if (op == OP_ADDING) { + value = *(long *)varp + value; + } + if (op == OP_PREPENDING) { + value = *(long *)varp * value; + } + if (op == OP_REMOVING) { + value = *(long *)varp - value; + } + *errmsg = set_num_option(opt_idx, (char_u *)varp, (long)value, + errbuf, errbuflen, opt_flags); +} + /// Part of do_set() for string options. /// @return FAIL on failure, do not process further options. static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg, @@ -1352,61 +1413,12 @@ int do_set(char *arg, int opt_flags) goto skip; } - if (flags & P_NUM) { // numeric - // Different ways to set a number option: - // & set to default value - // < set to global value - // accept special key codes for 'wildchar' - // c accept any non-digit for 'wildchar' - // [-]0-9 set number - // other error - arg++; - if (nextchar == '&') { - value = (long)(intptr_t)options[opt_idx].def_val; - } else if (nextchar == '<') { - // For 'undolevels' NO_LOCAL_UNDOLEVEL means to - // use the global value. - if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) { - value = NO_LOCAL_UNDOLEVEL; - } else { - value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); - } - } else if (((long *)varp == &p_wc - || (long *)varp == &p_wcm) - && (*arg == '<' - || *arg == '^' - || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) - && !ascii_isdigit(*arg)))) { - value = string_to_key(arg); - if (value == 0 && (long *)varp != &p_wcm) { - errmsg = e_invarg; - goto skip; - } - } else if (*arg == '-' || ascii_isdigit(*arg)) { - int i; - // Allow negative, octal and hex numbers. - vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); - if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { - errmsg = e_number_required_after_equal; - goto skip; - } - } else { - errmsg = e_number_required_after_equal; + if (flags & P_NUM) { // numeric + do_set_num(opt_idx, opt_flags, &arg, nextchar, op, varp, errbuf, sizeof(errbuf), + &errmsg); + if (errmsg != NULL) { goto skip; } - - if (op == OP_ADDING) { - value = *(long *)varp + value; - } - if (op == OP_PREPENDING) { - value = *(long *)varp * value; - } - if (op == OP_REMOVING) { - value = *(long *)varp - value; - } - errmsg = set_num_option(opt_idx, (char_u *)varp, (long)value, - errbuf, sizeof(errbuf), - opt_flags); } else if (opt_idx >= 0) { // String. if (do_set_string(opt_idx, opt_flags, &arg, nextchar, op, flags, varp, errbuf, sizeof(errbuf), @@ -2245,8 +2257,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, errmsg = e_positive; } } else if (pp == &p_ch) { - int minval = 0; - if (value < minval) { + if (value < 0) { errmsg = e_positive; } else { p_ch_was_zero = value == 0; -- cgit From ca1ad8977c9e1c79666978aef905c2a2a7f5c16e Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 14:33:23 +0000 Subject: refactor(option.c): add do_set_bool --- src/nvim/option.c | 81 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 10773fffde..c02c30c413 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -726,6 +726,49 @@ void ex_set(exarg_T *eap) (void)do_set(eap->arg, flags); } +static void do_set_bool(int opt_idx, int opt_flags, int prefix, int nextchar, int afterchar, + const char *varp, char **errmsg) +{ + if (nextchar == '=' || nextchar == ':') { + *errmsg = e_invarg; + return; + } + + varnumber_T value; + + // ":set opt!": invert + // ":set opt&": reset to default value + // ":set opt<": reset to global value + if (nextchar == '!') { + value = *(int *)(varp) ^ 1; + } else if (nextchar == '&') { + value = (int)(intptr_t)options[opt_idx].def_val; + } else if (nextchar == '<') { + // For 'autoread' -1 means to use global value. + if ((int *)varp == &curbuf->b_p_ar + && opt_flags == OPT_LOCAL) { + value = -1; + } else { + value = *(int *)get_varp_scope(&(options[opt_idx]), + OPT_GLOBAL); + } + } else { + // ":set invopt": invert + // ":set opt" or ":set noopt": set or reset + if (nextchar != NUL && !ascii_iswhite(afterchar)) { + *errmsg = e_trailing; + return; + } + if (prefix == 2) { // inv + value = *(int *)(varp) ^ 1; + } else { + value = prefix; + } + } + + *errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags); +} + static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, const set_op_T op, const char *varp, char *errbuf, size_t errbuflen, char **errmsg) { @@ -1367,45 +1410,11 @@ int do_set(char *arg, int opt_flags) } } else { int value_checked = false; - varnumber_T value; - if (flags & P_BOOL) { // boolean - if (nextchar == '=' || nextchar == ':') { - errmsg = e_invarg; + do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, &errmsg); + if (errmsg != NULL) { goto skip; } - - // ":set opt!": invert - // ":set opt&": reset to default value - // ":set opt<": reset to global value - if (nextchar == '!') { - value = *(int *)(varp) ^ 1; - } else if (nextchar == '&') { - value = (int)(intptr_t)options[opt_idx].def_val; - } else if (nextchar == '<') { - // For 'autoread' -1 means to use global value. - if ((int *)varp == &curbuf->b_p_ar - && opt_flags == OPT_LOCAL) { - value = -1; - } else { - value = *(int *)get_varp_scope(&(options[opt_idx]), - OPT_GLOBAL); - } - } else { - // ":set invopt": invert - // ":set opt" or ":set noopt": set or reset - if (nextchar != NUL && !ascii_iswhite(afterchar)) { - errmsg = e_trailing; - goto skip; - } - if (prefix == 2) { // inv - value = *(int *)(varp) ^ 1; - } else { - value = prefix; - } - } - - errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags); } else { // Numeric or string. if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL || prefix != 1) { -- cgit From 9679d058d42c22179fe3cf56e97983b2e67fb3f3 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 14:36:46 +0000 Subject: refactor(option.c): simplify do_set_string --- src/nvim/option.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index c02c30c413..84bc72e834 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -831,10 +831,9 @@ static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, co } /// Part of do_set() for string options. -/// @return FAIL on failure, do not process further options. -static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg, - uint32_t flags, char *varp_arg, char *errbuf, size_t errbuflen, - int *value_checked, char **errmsg) +static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg, + uint32_t flags, char *varp_arg, char *errbuf, size_t errbuflen, + int *value_checked, char **errmsg) { char *arg = *argp; set_op_T op = op_arg; @@ -1163,7 +1162,6 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, xfree(saved_newval); *argp = arg; - return *errmsg == NULL ? OK : FAIL; } /// Parse 'arg' for option settings. @@ -1429,13 +1427,10 @@ int do_set(char *arg, int opt_flags) goto skip; } } else if (opt_idx >= 0) { // String. - if (do_set_string(opt_idx, opt_flags, &arg, nextchar, - op, flags, varp, errbuf, sizeof(errbuf), - &value_checked, &errmsg) == FAIL) { - if (errmsg != NULL) { - goto skip; - } - break; + do_set_string(opt_idx, opt_flags, &arg, nextchar, op, flags, varp, errbuf, + sizeof(errbuf), &value_checked, &errmsg); + if (errmsg != NULL) { + goto skip; } } else { // key code option(FIXME(tarruda): Show a warning or something -- cgit From 18c37c616ec521bb79271c0b51fa198d9f664540 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 14:38:07 +0000 Subject: refactor(option.c): factor out common skip check --- src/nvim/option.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 84bc72e834..d1ecfa0dd7 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1410,9 +1410,6 @@ int do_set(char *arg, int opt_flags) int value_checked = false; if (flags & P_BOOL) { // boolean do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, &errmsg); - if (errmsg != NULL) { - goto skip; - } } else { // Numeric or string. if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL || prefix != 1) { @@ -1423,21 +1420,19 @@ int do_set(char *arg, int opt_flags) if (flags & P_NUM) { // numeric do_set_num(opt_idx, opt_flags, &arg, nextchar, op, varp, errbuf, sizeof(errbuf), &errmsg); - if (errmsg != NULL) { - goto skip; - } } else if (opt_idx >= 0) { // String. do_set_string(opt_idx, opt_flags, &arg, nextchar, op, flags, varp, errbuf, sizeof(errbuf), &value_checked, &errmsg); - if (errmsg != NULL) { - goto skip; - } } else { // key code option(FIXME(tarruda): Show a warning or something // similar) } } + if (errmsg != NULL) { + goto skip; + } + if (opt_idx >= 0) { did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); } -- cgit From e368560c80f162a67dd1ef5369ebaf57fb937de6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 14:50:29 +0000 Subject: refactor(option.c): factor out loop code from do_set() --- src/nvim/option.c | 456 +++++++++++++++++++++++++++--------------------------- 1 file changed, 230 insertions(+), 226 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index d1ecfa0dd7..5326251d2d 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1164,6 +1164,234 @@ static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, *argp = arg; } +static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, + size_t errbuflen, char **errmsg) +{ + int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name + + if (strncmp(*argp, "no", 2) == 0) { + prefix = 0; + *argp += 2; + } else if (strncmp(*argp, "inv", 3) == 0) { + prefix = 2; + *argp += 3; + } + + char *arg = *argp; + + // find end of name + int key = 0; + int len; + int opt_idx; + if (*arg == '<') { + opt_idx = -1; + // look out for ;> + if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) { + len = 5; + } else { + len = 1; + while (arg[len] != NUL && arg[len] != '>') { + len++; + } + } + if (arg[len] != '>') { + *errmsg = e_invarg; + return; + } + if (arg[1] == 't' && arg[2] == '_') { // could be term code + opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1)); + } + len++; + if (opt_idx == -1) { + key = find_key_option(arg + 1, true); + } + } else { + len = 0; + // The two characters after "t_" may not be alphanumeric. + if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { + len = 4; + } else { + while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { + len++; + } + } + opt_idx = findoption_len((const char *)arg, (size_t)len); + if (opt_idx == -1) { + key = find_key_option(arg, false); + } + } + + // remember character after option name + int afterchar = (uint8_t)arg[len]; + + // skip white space, allow ":set ai ?" + while (ascii_iswhite(arg[len])) { + len++; + } + + set_op_T op = OP_NONE; + if (arg[len] != NUL && arg[len + 1] == '=') { + if (arg[len] == '+') { + op = OP_ADDING; // "+=" + len++; + } else if (arg[len] == '^') { + op = OP_PREPENDING; // "^=" + len++; + } else if (arg[len] == '-') { + op = OP_REMOVING; // "-=" + len++; + } + } + char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name + + if (opt_idx == -1 && key == 0) { // found a mismatch: skip + *errmsg = e_unknown_option; + return; + } + + uint32_t flags; // flags for current option + char *varp = NULL; // pointer to variable for current option + + if (opt_idx >= 0) { + if (options[opt_idx].var == NULL) { // hidden option: skip + // Only give an error message when requesting the value of + // a hidden option, ignore setting it. + if (vim_strchr("=:!&<", (uint8_t)nextchar) == NULL + && (!(options[opt_idx].flags & P_BOOL) + || nextchar == '?')) { + *errmsg = e_unsupportedoption; + } + return; + } + + flags = options[opt_idx].flags; + varp = get_varp_scope(&(options[opt_idx]), opt_flags); + } else { + flags = P_STRING; + } + + // Skip all options that are not window-local (used when showing + // an already loaded buffer in a window). + if ((opt_flags & OPT_WINONLY) + && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { + return; + } + + // Skip all options that are window-local (used for :vimgrep). + if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 + && options[opt_idx].var == VAR_WIN) { + return; + } + + // Disallow changing some options from modelines. + if (opt_flags & OPT_MODELINE) { + if (flags & (P_SECURE | P_NO_ML)) { + *errmsg = e_not_allowed_in_modeline; + return; + } + if ((flags & P_MLE) && !p_mle) { + *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; + return; + } + // In diff mode some options are overruled. This avoids that + // 'foldmethod' becomes "marker" instead of "diff" and that + // "wrap" gets set. + if (curwin->w_p_diff + && opt_idx >= 0 // shut up coverity warning + && (options[opt_idx].indir == PV_FDM + || options[opt_idx].indir == PV_WRAP)) { + return; + } + } + + // Disallow changing some options in the sandbox + if (sandbox != 0 && (flags & P_SECURE)) { + *errmsg = e_sandbox; + return; + } + + if (vim_strchr("?=:!&<", (uint8_t)nextchar) != NULL) { + *argp += len; + if (nextchar == '&' && (*argp)[1] == 'v' && (*argp)[2] == 'i') { + if ((*argp)[3] == 'm') { // "opt&vim": set to Vim default + *argp += 3; + } else { // "opt&vi": set to Vi default + *argp += 2; + } + } + if (vim_strchr("?!&<", (uint8_t)nextchar) != NULL + && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) { + *errmsg = e_trailing; + return; + } + } + + // + // allow '=' and ':' as MS-DOS command.com allows only one + // '=' character per "set" command line. grrr. (jw) + // + if (nextchar == '?' + || (prefix == 1 + && vim_strchr("=:&<", (uint8_t)nextchar) == NULL + && !(flags & P_BOOL))) { + // print value + if (*did_show) { + msg_putchar('\n'); // cursor below last one + } else { + gotocmdline(true); // cursor at status line + *did_show = true; // remember that we did a line + } + if (opt_idx >= 0) { + showoneopt(&options[opt_idx], opt_flags); + if (p_verbose > 0) { + // Mention where the option was last set. + if (varp == (char *)options[opt_idx].var) { + option_last_set_msg(options[opt_idx].last_set); + } else if ((int)options[opt_idx].indir & PV_WIN) { + option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); + } else if ((int)options[opt_idx].indir & PV_BUF) { + option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); + } + } + } else { + *errmsg = e_key_code_not_set; + return; + } + if (nextchar != '?' && nextchar != NUL && !ascii_iswhite(afterchar)) { + *errmsg = e_trailing; + } + } else { + int value_checked = false; + if (flags & P_BOOL) { // boolean + do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); + } else { // Numeric or string. + if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL + || prefix != 1) { + *errmsg = e_invarg; + return; + } + + if (flags & P_NUM) { // numeric + do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); + } else if (opt_idx >= 0) { // String. + do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, + errbuflen, &value_checked, errmsg); + } else { + // key code option(FIXME(tarruda): Show a warning or something + // similar) + } + } + + if (*errmsg != NULL) { + return; + } + + if (opt_idx >= 0) { + did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); + } + } +} + /// Parse 'arg' for option settings. /// /// 'arg' may be IObuff, but only when no errors can be present and option @@ -1181,7 +1409,7 @@ static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, /// @return FAIL if an error is detected, OK otherwise int do_set(char *arg, int opt_flags) { - int did_show = false; // already showed one value + bool did_show = false; // already showed one value if (*arg == NUL) { showoptions(0, opt_flags); @@ -1213,232 +1441,8 @@ int do_set(char *arg, int opt_flags) did_show = true; } } else { - int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name - if (strncmp(arg, "no", 2) == 0) { - prefix = 0; - arg += 2; - } else if (strncmp(arg, "inv", 3) == 0) { - prefix = 2; - arg += 3; - } - - // find end of name - int key = 0; - int len; - int opt_idx; - if (*arg == '<') { - opt_idx = -1; - // look out for ;> - if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) { - len = 5; - } else { - len = 1; - while (arg[len] != NUL && arg[len] != '>') { - len++; - } - } - if (arg[len] != '>') { - errmsg = e_invarg; - goto skip; - } - if (arg[1] == 't' && arg[2] == '_') { // could be term code - opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1)); - } - len++; - if (opt_idx == -1) { - key = find_key_option(arg + 1, true); - } - } else { - len = 0; - // The two characters after "t_" may not be alphanumeric. - if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { - len = 4; - } else { - while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { - len++; - } - } - opt_idx = findoption_len((const char *)arg, (size_t)len); - if (opt_idx == -1) { - key = find_key_option(arg, false); - } - } - - // remember character after option name - int afterchar = (uint8_t)arg[len]; - - // skip white space, allow ":set ai ?" - while (ascii_iswhite(arg[len])) { - len++; - } - - set_op_T op = OP_NONE; - if (arg[len] != NUL && arg[len + 1] == '=') { - if (arg[len] == '+') { - op = OP_ADDING; // "+=" - len++; - } else if (arg[len] == '^') { - op = OP_PREPENDING; // "^=" - len++; - } else if (arg[len] == '-') { - op = OP_REMOVING; // "-=" - len++; - } - } - char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name - - if (opt_idx == -1 && key == 0) { // found a mismatch: skip - errmsg = e_unknown_option; - goto skip; - } - - uint32_t flags; // flags for current option - char *varp = NULL; // pointer to variable for current option - - if (opt_idx >= 0) { - if (options[opt_idx].var == NULL) { // hidden option: skip - // Only give an error message when requesting the value of - // a hidden option, ignore setting it. - if (vim_strchr("=:!&<", (uint8_t)nextchar) == NULL - && (!(options[opt_idx].flags & P_BOOL) - || nextchar == '?')) { - errmsg = e_unsupportedoption; - } - goto skip; - } - - flags = options[opt_idx].flags; - varp = get_varp_scope(&(options[opt_idx]), opt_flags); - } else { - flags = P_STRING; - } - - // Skip all options that are not window-local (used when showing - // an already loaded buffer in a window). - if ((opt_flags & OPT_WINONLY) - && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { - goto skip; - } - - // Skip all options that are window-local (used for :vimgrep). - if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 - && options[opt_idx].var == VAR_WIN) { - goto skip; - } - - // Disallow changing some options from modelines. - if (opt_flags & OPT_MODELINE) { - if (flags & (P_SECURE | P_NO_ML)) { - errmsg = e_not_allowed_in_modeline; - goto skip; - } - if ((flags & P_MLE) && !p_mle) { - errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; - goto skip; - } - // In diff mode some options are overruled. This avoids that - // 'foldmethod' becomes "marker" instead of "diff" and that - // "wrap" gets set. - if (curwin->w_p_diff - && opt_idx >= 0 // shut up coverity warning - && (options[opt_idx].indir == PV_FDM - || options[opt_idx].indir == PV_WRAP)) { - goto skip; - } - } - - // Disallow changing some options in the sandbox - if (sandbox != 0 && (flags & P_SECURE)) { - errmsg = e_sandbox; - goto skip; - } - - if (vim_strchr("?=:!&<", (uint8_t)nextchar) != NULL) { - arg += len; - if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { - if (arg[3] == 'm') { // "opt&vim": set to Vim default - arg += 3; - } else { // "opt&vi": set to Vi default - arg += 2; - } - } - if (vim_strchr("?!&<", (uint8_t)nextchar) != NULL - && arg[1] != NUL && !ascii_iswhite(arg[1])) { - errmsg = e_trailing; - goto skip; - } - } - - // - // allow '=' and ':' as MS-DOS command.com allows only one - // '=' character per "set" command line. grrr. (jw) - // - if (nextchar == '?' - || (prefix == 1 - && vim_strchr("=:&<", (uint8_t)nextchar) == NULL - && !(flags & P_BOOL))) { - // print value - if (did_show) { - msg_putchar('\n'); // cursor below last one - } else { - gotocmdline(true); // cursor at status line - did_show = true; // remember that we did a line - } - if (opt_idx >= 0) { - showoneopt(&options[opt_idx], opt_flags); - if (p_verbose > 0) { - // Mention where the option was last set. - if (varp == (char *)options[opt_idx].var) { - option_last_set_msg(options[opt_idx].last_set); - } else if ((int)options[opt_idx].indir & PV_WIN) { - option_last_set_msg(curwin->w_p_script_ctx[ - (int)options[opt_idx].indir & PV_MASK]); - } else if ((int)options[opt_idx].indir & PV_BUF) { - option_last_set_msg(curbuf->b_p_script_ctx[ - (int)options[opt_idx].indir & PV_MASK]); - } - } - } else { - errmsg = e_key_code_not_set; - goto skip; - } - if (nextchar != '?' - && nextchar != NUL && !ascii_iswhite(afterchar)) { - errmsg = e_trailing; - } - } else { - int value_checked = false; - if (flags & P_BOOL) { // boolean - do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, &errmsg); - } else { // Numeric or string. - if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL - || prefix != 1) { - errmsg = e_invarg; - goto skip; - } - - if (flags & P_NUM) { // numeric - do_set_num(opt_idx, opt_flags, &arg, nextchar, op, varp, errbuf, sizeof(errbuf), - &errmsg); - } else if (opt_idx >= 0) { // String. - do_set_string(opt_idx, opt_flags, &arg, nextchar, op, flags, varp, errbuf, - sizeof(errbuf), &value_checked, &errmsg); - } else { - // key code option(FIXME(tarruda): Show a warning or something - // similar) - } - } - - if (errmsg != NULL) { - goto skip; - } - - if (opt_idx >= 0) { - did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); - } - } + do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); -skip: // Advance to next argument. // - skip until a blank found, taking care of backslashes // - skip blanks -- cgit From 3ae3e47d541db6e2cbf7c42b1ccce9cf48b0e4c9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 14:53:42 +0000 Subject: refactor(option.c): reduce scope or errmsg --- src/nvim/option.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 5326251d2d..f19d1d1517 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1420,7 +1420,6 @@ int do_set(char *arg, int opt_flags) char errbuf[80]; while (*arg != NUL) { // loop to process all options - char *errmsg = NULL; char *startarg = arg; // remember for error message if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) @@ -1441,6 +1440,7 @@ int do_set(char *arg, int opt_flags) did_show = true; } } else { + char *errmsg = NULL; do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); // Advance to next argument. @@ -1458,26 +1458,26 @@ int do_set(char *arg, int opt_flags) break; } } - } - if (errmsg != NULL) { - xstrlcpy(IObuff, _(errmsg), IOSIZE); - int i = (int)strlen(IObuff) + 2; - if (i + (arg - startarg) < IOSIZE) { - // append the argument with the error - STRCAT(IObuff, ": "); - assert(arg >= startarg); - memmove(IObuff + i, startarg, (size_t)(arg - startarg)); - IObuff[i + (arg - startarg)] = NUL; - } - // make sure all characters are printable - trans_characters(IObuff, IOSIZE); + if (errmsg != NULL) { + xstrlcpy(IObuff, _(errmsg), IOSIZE); + int i = (int)strlen(IObuff) + 2; + if (i + (arg - startarg) < IOSIZE) { + // append the argument with the error + STRCAT(IObuff, ": "); + assert(arg >= startarg); + memmove(IObuff + i, startarg, (size_t)(arg - startarg)); + IObuff[i + (arg - startarg)] = NUL; + } + // make sure all characters are printable + trans_characters(IObuff, IOSIZE); - no_wait_return++; // wait_return() done later - emsg(IObuff); // show error highlighted - no_wait_return--; + no_wait_return++; // wait_return() done later + emsg(IObuff); // show error highlighted + no_wait_return--; - return FAIL; + return FAIL; + } } arg = skipwhite(arg); -- cgit From b93bec68bcd681e06df4f977f4fef3b4ecff2555 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 15:06:32 +0000 Subject: refactor(option.c): reduce scope or errbuf --- src/nvim/option.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index f19d1d1517..535e162e91 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1417,8 +1417,6 @@ int do_set(char *arg, int opt_flags) goto theend; } - char errbuf[80]; - while (*arg != NUL) { // loop to process all options char *startarg = arg; // remember for error message @@ -1441,6 +1439,8 @@ int do_set(char *arg, int opt_flags) } } else { char *errmsg = NULL; + char errbuf[80]; + do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); // Advance to next argument. -- cgit From bb1efa85aa245b9d21f85fc541530be9f8d6dda4 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 15:12:33 +0000 Subject: refactor(option.c): reduce scope or startarg --- src/nvim/option.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 535e162e91..490ce07c44 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1418,8 +1418,6 @@ int do_set(char *arg, int opt_flags) } while (*arg != NUL) { // loop to process all options - char *startarg = arg; // remember for error message - if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) && !(opt_flags & OPT_MODELINE)) { // ":set all" show all options. @@ -1438,6 +1436,7 @@ int do_set(char *arg, int opt_flags) did_show = true; } } else { + char *startarg = arg; // remember for error message char *errmsg = NULL; char errbuf[80]; -- cgit From a13e97ece52a4b6dccda08ec88c035306fd6d24a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 15:19:11 +0000 Subject: refactor(option.c): int -> bool --- src/nvim/option.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 490ce07c44..8df3063fec 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1412,7 +1412,7 @@ int do_set(char *arg, int opt_flags) bool did_show = false; // already showed one value if (*arg == NUL) { - showoptions(0, opt_flags); + showoptions(false, opt_flags); did_show = true; goto theend; } @@ -1432,7 +1432,7 @@ int do_set(char *arg, int opt_flags) ui_refresh_options(); redraw_all_later(UPD_CLEAR); } else { - showoptions(1, opt_flags); + showoptions(true, opt_flags); did_show = true; } } else { @@ -3124,11 +3124,11 @@ static int find_key_option(const char *arg, bool has_lt) return find_key_option_len(arg, strlen(arg), has_lt); } -/// if 'all' == 0: show changed options -/// if 'all' == 1: show all normal options +/// if 'all' == false: show changed options +/// if 'all' == true: show all normal options /// /// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL -static void showoptions(int all, int opt_flags) +static void showoptions(bool all, int opt_flags) { #define INC 20 #define GAP 3 -- cgit From ef85238fde4560ae931dc98ac052a2b5564327fd Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 15:22:31 +0000 Subject: refactor(option.c): remove goto --- src/nvim/option.c | 116 +++++++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 8df3063fec..ecec421e90 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1414,75 +1414,73 @@ int do_set(char *arg, int opt_flags) if (*arg == NUL) { showoptions(false, opt_flags); did_show = true; - goto theend; - } - - while (*arg != NUL) { // loop to process all options - if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) - && !(opt_flags & OPT_MODELINE)) { - // ":set all" show all options. - // ":set all&" set all options to their default value. - arg += 3; - if (*arg == '&') { - arg++; - // Only for :set command set global value of local options. - set_options_default(OPT_FREE | opt_flags); - didset_options(); - didset_options2(); - ui_refresh_options(); - redraw_all_later(UPD_CLEAR); + } else { + while (*arg != NUL) { // loop to process all options + if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) + && !(opt_flags & OPT_MODELINE)) { + // ":set all" show all options. + // ":set all&" set all options to their default value. + arg += 3; + if (*arg == '&') { + arg++; + // Only for :set command set global value of local options. + set_options_default(OPT_FREE | opt_flags); + didset_options(); + didset_options2(); + ui_refresh_options(); + redraw_all_later(UPD_CLEAR); + } else { + showoptions(true, opt_flags); + did_show = true; + } } else { - showoptions(true, opt_flags); - did_show = true; - } - } else { - char *startarg = arg; // remember for error message - char *errmsg = NULL; - char errbuf[80]; - - do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); - - // Advance to next argument. - // - skip until a blank found, taking care of backslashes - // - skip blanks - // - skip one "=val" argument (for hidden options ":set gfn =xx") - for (int i = 0; i < 2; i++) { - while (*arg != NUL && !ascii_iswhite(*arg)) { - if (*arg++ == '\\' && *arg != NUL) { - arg++; + char *startarg = arg; // remember for error message + char *errmsg = NULL; + char errbuf[80]; + + do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); + + // Advance to next argument. + // - skip until a blank found, taking care of backslashes + // - skip blanks + // - skip one "=val" argument (for hidden options ":set gfn =xx") + for (int i = 0; i < 2; i++) { + while (*arg != NUL && !ascii_iswhite(*arg)) { + if (*arg++ == '\\' && *arg != NUL) { + arg++; + } + } + arg = skipwhite(arg); + if (*arg != '=') { + break; } } - arg = skipwhite(arg); - if (*arg != '=') { - break; - } - } - if (errmsg != NULL) { - xstrlcpy(IObuff, _(errmsg), IOSIZE); - int i = (int)strlen(IObuff) + 2; - if (i + (arg - startarg) < IOSIZE) { - // append the argument with the error - STRCAT(IObuff, ": "); - assert(arg >= startarg); - memmove(IObuff + i, startarg, (size_t)(arg - startarg)); - IObuff[i + (arg - startarg)] = NUL; - } - // make sure all characters are printable - trans_characters(IObuff, IOSIZE); + if (errmsg != NULL) { + xstrlcpy(IObuff, _(errmsg), IOSIZE); + int i = (int)strlen(IObuff) + 2; + if (i + (arg - startarg) < IOSIZE) { + // append the argument with the error + STRCAT(IObuff, ": "); + assert(arg >= startarg); + memmove(IObuff + i, startarg, (size_t)(arg - startarg)); + IObuff[i + (arg - startarg)] = NUL; + } + // make sure all characters are printable + trans_characters(IObuff, IOSIZE); - no_wait_return++; // wait_return() done later - emsg(IObuff); // show error highlighted - no_wait_return--; + no_wait_return++; // wait_return() done later + emsg(IObuff); // show error highlighted + no_wait_return--; - return FAIL; + return FAIL; + } } - } - arg = skipwhite(arg); + arg = skipwhite(arg); + } } -theend: if (silent_mode && did_show) { // After displaying option values in silent mode. silent_mode = false; -- cgit From 334f5382677b3bcf91e74bb8502d38c7d2bd4281 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 15:41:55 +0000 Subject: refactor(option.c): change nextchar to uint8_t --- src/nvim/option.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index ecec421e90..ac889f2451 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1242,7 +1242,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb len++; } } - char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name + uint8_t nextchar = (uint8_t)arg[len]; // next non-white char after option name if (opt_idx == -1 && key == 0) { // found a mismatch: skip *errmsg = e_unknown_option; @@ -1256,7 +1256,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb if (options[opt_idx].var == NULL) { // hidden option: skip // Only give an error message when requesting the value of // a hidden option, ignore setting it. - if (vim_strchr("=:!&<", (uint8_t)nextchar) == NULL + if (vim_strchr("=:!&<", nextchar) == NULL && (!(options[opt_idx].flags & P_BOOL) || nextchar == '?')) { *errmsg = e_unsupportedoption; @@ -1310,7 +1310,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb return; } - if (vim_strchr("?=:!&<", (uint8_t)nextchar) != NULL) { + if (vim_strchr("?=:!&<", nextchar) != NULL) { *argp += len; if (nextchar == '&' && (*argp)[1] == 'v' && (*argp)[2] == 'i') { if ((*argp)[3] == 'm') { // "opt&vim": set to Vim default @@ -1319,7 +1319,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb *argp += 2; } } - if (vim_strchr("?!&<", (uint8_t)nextchar) != NULL + if (vim_strchr("?!&<", nextchar) != NULL && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) { *errmsg = e_trailing; return; @@ -1332,7 +1332,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb // if (nextchar == '?' || (prefix == 1 - && vim_strchr("=:&<", (uint8_t)nextchar) == NULL + && vim_strchr("=:&<", nextchar) == NULL && !(flags & P_BOOL))) { // print value if (*did_show) { @@ -1365,8 +1365,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb if (flags & P_BOOL) { // boolean do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); } else { // Numeric or string. - if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL - || prefix != 1) { + if (vim_strchr("=:&<", nextchar) == NULL || prefix != 1) { *errmsg = e_invarg; return; } -- cgit From 25310af06085c243c2b72a6a0f21cc45ce86a283 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 17:03:15 +0000 Subject: refactor(option.c): use skiptowhite_esc --- src/nvim/option.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index ac889f2451..a4e48f9c02 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1444,11 +1444,7 @@ int do_set(char *arg, int opt_flags) // - skip blanks // - skip one "=val" argument (for hidden options ":set gfn =xx") for (int i = 0; i < 2; i++) { - while (*arg != NUL && !ascii_iswhite(*arg)) { - if (*arg++ == '\\' && *arg != NUL) { - arg++; - } - } + arg = skiptowhite_esc(arg); arg = skipwhite(arg); if (*arg != '=') { break; -- cgit From 0f3fa5a30a6433ab32cfb3aaed946f858f7113a1 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 17:12:21 +0000 Subject: refactor(option.c): factor out set op parsing --- src/nvim/option.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index a4e48f9c02..c511a8e622 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1164,6 +1164,21 @@ static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, *argp = arg; } +static set_op_T get_op(const char *arg) +{ + set_op_T op = OP_NONE; + if (*arg != NUL && *(arg + 1) == '=') { + if (*arg == '+') { + op = OP_ADDING; // "+=" + } else if (*arg == '^') { + op = OP_PREPENDING; // "^=" + } else if (*arg == '-') { + op = OP_REMOVING; // "-=" + } + } + return op; +} + static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, size_t errbuflen, char **errmsg) { @@ -1229,19 +1244,11 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb len++; } - set_op_T op = OP_NONE; - if (arg[len] != NUL && arg[len + 1] == '=') { - if (arg[len] == '+') { - op = OP_ADDING; // "+=" - len++; - } else if (arg[len] == '^') { - op = OP_PREPENDING; // "^=" - len++; - } else if (arg[len] == '-') { - op = OP_REMOVING; // "-=" - len++; - } + set_op_T op = get_op(arg + len); + if (op != OP_NONE) { + len++; } + uint8_t nextchar = (uint8_t)arg[len]; // next non-white char after option name if (opt_idx == -1 && key == 0) { // found a mismatch: skip -- cgit From 9a9129c60b76cdfae5752071ec4c998c2f873c7c Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 17:28:21 +0000 Subject: refactor(option.c): factor out option prefix parsing --- src/nvim/option.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index c511a8e622..a54dd4d877 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1179,19 +1179,25 @@ static set_op_T get_op(const char *arg) return op; } -static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, - size_t errbuflen, char **errmsg) +static int get_option_prefix(char **argp) { - int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name - if (strncmp(*argp, "no", 2) == 0) { - prefix = 0; *argp += 2; + return 0; } else if (strncmp(*argp, "inv", 3) == 0) { - prefix = 2; *argp += 3; + return 2; } + return 1; +} + +static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, + size_t errbuflen, char **errmsg) +{ + // 1: nothing, 0: "no", 2: "inv" in front of name + int prefix = get_option_prefix(argp); + char *arg = *argp; // find end of name @@ -1221,11 +1227,11 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb key = find_key_option(arg + 1, true); } } else { - len = 0; // The two characters after "t_" may not be alphanumeric. if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { len = 4; } else { + len = 0; while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { len++; } -- cgit From 2c601787ab2fead995fdecce08d0bd21d23eb284 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 25 Jan 2023 17:33:09 +0000 Subject: refactor(option.c): factor out option name parsing --- src/nvim/option.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index a54dd4d877..babbe7e1b3 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1192,18 +1192,18 @@ static int get_option_prefix(char **argp) return 1; } -static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, - size_t errbuflen, char **errmsg) +/// @param[in] arg Pointer to start option name +/// @param[out] opt_idxp Option index in options[] table. +/// @param[out] keyp +/// @param[out] len Length of option name +/// @return FAIL if an error is detected, OK otherwise +static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp) { - // 1: nothing, 0: "no", 2: "inv" in front of name - int prefix = get_option_prefix(argp); - - char *arg = *argp; - // find end of name int key = 0; int len; int opt_idx; + if (*arg == '<') { opt_idx = -1; // look out for ;> @@ -1216,8 +1216,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb } } if (arg[len] != '>') { - *errmsg = e_invarg; - return; + return FAIL; } if (arg[1] == 't' && arg[2] == '_') { // could be term code opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1)); @@ -1242,6 +1241,30 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb } } + *keyp = key; + *lenp = len; + *opt_idxp = opt_idx; + + return OK; +} + +static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, + size_t errbuflen, char **errmsg) +{ + // 1: nothing, 0: "no", 2: "inv" in front of name + int prefix = get_option_prefix(argp); + + char *arg = *argp; + + // find end of name + int key = 0; + int len; + int opt_idx; + if (parse_option_name(arg, &key, &len, &opt_idx) == FAIL) { + *errmsg = e_invarg; + return; + } + // remember character after option name int afterchar = (uint8_t)arg[len]; -- cgit From e49ae04caf52ac848d090940a36393e4255726c8 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 09:43:11 +0000 Subject: refactor(option.c): factor out opt_idx validation --- src/nvim/option.c | 83 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index babbe7e1b3..4c83eb2a1a 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1248,6 +1248,51 @@ static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp) return OK; } +static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t flags, char **errmsg) +{ + // Skip all options that are not window-local (used when showing + // an already loaded buffer in a window). + if ((opt_flags & OPT_WINONLY) + && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { + return FAIL; + } + + // Skip all options that are window-local (used for :vimgrep). + if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 + && options[opt_idx].var == VAR_WIN) { + return FAIL; + } + + // Disallow changing some options from modelines. + if (opt_flags & OPT_MODELINE) { + if (flags & (P_SECURE | P_NO_ML)) { + *errmsg = e_not_allowed_in_modeline; + return FAIL; + } + if ((flags & P_MLE) && !p_mle) { + *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; + return FAIL; + } + // In diff mode some options are overruled. This avoids that + // 'foldmethod' becomes "marker" instead of "diff" and that + // "wrap" gets set. + if (win->w_p_diff + && opt_idx >= 0 // shut up coverity warning + && (options[opt_idx].indir == PV_FDM + || options[opt_idx].indir == PV_WRAP)) { + return FAIL; + } + } + + // Disallow changing some options in the sandbox + if (sandbox != 0 && (flags & P_SECURE)) { + *errmsg = e_sandbox; + return FAIL; + } + + return OK; +} + static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, size_t errbuflen, char **errmsg) { @@ -1306,43 +1351,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb flags = P_STRING; } - // Skip all options that are not window-local (used when showing - // an already loaded buffer in a window). - if ((opt_flags & OPT_WINONLY) - && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { - return; - } - - // Skip all options that are window-local (used for :vimgrep). - if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 - && options[opt_idx].var == VAR_WIN) { - return; - } - - // Disallow changing some options from modelines. - if (opt_flags & OPT_MODELINE) { - if (flags & (P_SECURE | P_NO_ML)) { - *errmsg = e_not_allowed_in_modeline; - return; - } - if ((flags & P_MLE) && !p_mle) { - *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; - return; - } - // In diff mode some options are overruled. This avoids that - // 'foldmethod' becomes "marker" instead of "diff" and that - // "wrap" gets set. - if (curwin->w_p_diff - && opt_idx >= 0 // shut up coverity warning - && (options[opt_idx].indir == PV_FDM - || options[opt_idx].indir == PV_WRAP)) { - return; - } - } - - // Disallow changing some options in the sandbox - if (sandbox != 0 && (flags & P_SECURE)) { - *errmsg = e_sandbox; + if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, errmsg) == FAIL) { return; } -- cgit From c6907ea895694ea675ba8c912c3d8e9f67f5c7d4 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 09:47:50 +0000 Subject: refactor(option.c): de-nest code in do_set_option --- src/nvim/option.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 4c83eb2a1a..1d5ceb70e6 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1405,35 +1405,36 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb if (nextchar != '?' && nextchar != NUL && !ascii_iswhite(afterchar)) { *errmsg = e_trailing; } - } else { - int value_checked = false; - if (flags & P_BOOL) { // boolean - do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); - } else { // Numeric or string. - if (vim_strchr("=:&<", nextchar) == NULL || prefix != 1) { - *errmsg = e_invarg; - return; - } - - if (flags & P_NUM) { // numeric - do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); - } else if (opt_idx >= 0) { // String. - do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, - errbuflen, &value_checked, errmsg); - } else { - // key code option(FIXME(tarruda): Show a warning or something - // similar) - } - } + return; + } - if (*errmsg != NULL) { + int value_checked = false; + if (flags & P_BOOL) { // boolean + do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); + } else { // Numeric or string. + if (vim_strchr("=:&<", nextchar) == NULL || prefix != 1) { + *errmsg = e_invarg; return; } - if (opt_idx >= 0) { - did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); + if (flags & P_NUM) { // numeric + do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); + } else if (opt_idx >= 0) { // String. + do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, + errbuflen, &value_checked, errmsg); + } else { + // key code option(FIXME(tarruda): Show a warning or something + // similar) } } + + if (*errmsg != NULL) { + return; + } + + if (opt_idx >= 0) { + did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); + } } /// Parse 'arg' for option settings. -- cgit From 0170219e92ce211d935b78895825000f074c4cff Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 09:59:37 +0000 Subject: refactor(option.c): move bool prefix check --- src/nvim/option.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 1d5ceb70e6..50ccf9d302 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1248,8 +1248,15 @@ static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp) return OK; } -static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t flags, char **errmsg) +static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t flags, int prefix, + char **errmsg) { + // Only bools can have a prefix of 'inv' or 'no' + if (!(flags & P_BOOL) && prefix != 1) { + *errmsg = e_invarg; + return FAIL; + } + // Skip all options that are not window-local (used when showing // an already loaded buffer in a window). if ((opt_flags & OPT_WINONLY) @@ -1351,7 +1358,7 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb flags = P_STRING; } - if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, errmsg) == FAIL) { + if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, prefix, errmsg) == FAIL) { return; } @@ -1408,24 +1415,22 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb return; } + if (!(flags & P_BOOL) && vim_strchr("=:&<", nextchar) == NULL) { + *errmsg = e_invarg; + return; + } + int value_checked = false; - if (flags & P_BOOL) { // boolean + if (flags & P_BOOL) { // boolean do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); - } else { // Numeric or string. - if (vim_strchr("=:&<", nextchar) == NULL || prefix != 1) { - *errmsg = e_invarg; - return; - } - - if (flags & P_NUM) { // numeric - do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); - } else if (opt_idx >= 0) { // String. - do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, - errbuflen, &value_checked, errmsg); - } else { - // key code option(FIXME(tarruda): Show a warning or something - // similar) - } + } else if (flags & P_NUM) { // numeric + do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); + } else if (opt_idx >= 0) { // string. + do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, + errbuflen, &value_checked, errmsg); + } else { + // key code option(FIXME(tarruda): Show a warning or something + // similar) } if (*errmsg != NULL) { -- cgit From 8f2d3537b49846f6e0d27ae5957b57a7ea57e232 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 10:37:05 +0000 Subject: refactor(option.c): add do_set_option_value --- src/nvim/option.c | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 50ccf9d302..641f07d70b 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1300,6 +1300,32 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla return OK; } +static void do_set_option_value(int opt_idx, int opt_flags, char **argp, int prefix, int nextchar, + int afterchar, set_op_T op, uint32_t flags, char *varp, + char *errbuf, size_t errbuflen, char **errmsg) +{ + int value_checked = false; + if (flags & P_BOOL) { // boolean + do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); + } else if (flags & P_NUM) { // numeric + do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); + } else if (opt_idx >= 0) { // string. + do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, + errbuflen, &value_checked, errmsg); + } else { + // key code option(FIXME(tarruda): Show a warning or something + // similar) + } + + if (*errmsg != NULL) { + return; + } + + if (opt_idx >= 0) { + did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); + } +} + static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, size_t errbuflen, char **errmsg) { @@ -1420,26 +1446,8 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb return; } - int value_checked = false; - if (flags & P_BOOL) { // boolean - do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); - } else if (flags & P_NUM) { // numeric - do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); - } else if (opt_idx >= 0) { // string. - do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, - errbuflen, &value_checked, errmsg); - } else { - // key code option(FIXME(tarruda): Show a warning or something - // similar) - } - - if (*errmsg != NULL) { - return; - } - - if (opt_idx >= 0) { - did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); - } + do_set_option_value(opt_idx, opt_flags, argp, prefix, nextchar, afterchar, op, flags, varp, + errbuf, errbuflen, errmsg); } /// Parse 'arg' for option settings. -- cgit From 41aa5ce3eb49705d26137ac2b34f5ad7cd43f2cf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 21:05:34 +0800 Subject: vim-patch:9.0.1246: code is indented more than necessary (#22006) Problem: Code is indented more than necessary. Solution: Use an early return where it makes sense. (Yegappan Lakshmanan, closes vim/vim#11887) https://github.com/vim/vim/commit/142ed77898facf8f423fee2717efee1749c55f9a Omit function_using_block_scopes(): only affects Vim9 script. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/userfunc.c | 9 ++++----- src/nvim/undo.c | 8 +++++--- src/nvim/window.c | 30 +++++++++++++++++------------- 3 files changed, 26 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 22c5b1954d..6c6dc3fa43 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -760,13 +760,12 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) static bool func_remove(ufunc_T *fp) { hashitem_T *hi = hash_find(&func_hashtab, (char *)UF2HIKEY(fp)); - - if (!HASHITEM_EMPTY(hi)) { - hash_remove(&func_hashtab, hi); - return true; + if (HASHITEM_EMPTY(hi)) { + return false; } - return false; + hash_remove(&func_hashtab, hi); + return true; } static void func_clear_items(ufunc_T *fp) diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 2b0bb1d243..0f12c00f15 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2985,10 +2985,12 @@ void u_saveline(linenr_T lnum) /// (this is used externally for crossing a line while in insert mode) void u_clearline(void) { - if (curbuf->b_u_line_ptr != NULL) { - XFREE_CLEAR(curbuf->b_u_line_ptr); - curbuf->b_u_line_lnum = 0; + if (curbuf->b_u_line_ptr == NULL) { + return; } + + XFREE_CLEAR(curbuf->b_u_line_ptr); + curbuf->b_u_line_lnum = 0; } /// Implementation of the "U" command. diff --git a/src/nvim/window.c b/src/nvim/window.c index 05f84b5a91..6b40ccdb84 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2599,6 +2599,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev if (!ONE_WINDOW) { return false; } + buf_T *old_curbuf = curbuf; Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL; @@ -4144,12 +4145,13 @@ int may_open_tabpage(void) { int n = (cmdmod.cmod_tab == 0) ? postponed_split_tab : cmdmod.cmod_tab; - if (n != 0) { - cmdmod.cmod_tab = 0; // reset it to avoid doing it twice - postponed_split_tab = 0; - return win_new_tabpage(n, NULL); + if (n == 0) { + return FAIL; } - return FAIL; + + cmdmod.cmod_tab = 0; // reset it to avoid doing it twice + postponed_split_tab = 0; + return win_new_tabpage(n, NULL); } // Create up to "maxcount" tabpages with empty windows. @@ -4494,11 +4496,12 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le /// @return true if the tab page is valid, false otherwise. bool goto_tabpage_lastused(void) { - if (valid_tabpage(lastused_tabpage)) { - goto_tabpage_tp(lastused_tabpage, true, true); - return true; + if (!valid_tabpage(lastused_tabpage)) { + return false; } - return false; + + goto_tabpage_tp(lastused_tabpage, true, true); + return true; } // Enter window "wp" in tab page "tp". @@ -7250,11 +7253,12 @@ static void clear_snapshot(tabpage_T *tp, int idx) static void clear_snapshot_rec(frame_T *fr) { - if (fr != NULL) { - clear_snapshot_rec(fr->fr_next); - clear_snapshot_rec(fr->fr_child); - xfree(fr); + if (fr == NULL) { + return; } + clear_snapshot_rec(fr->fr_next); + clear_snapshot_rec(fr->fr_child); + xfree(fr); } /// Traverse a snapshot to find the previous curwin. -- cgit From 3c2bb1b2bec993cbcd6d65572c531aafbefa25a1 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 15:17:23 +0000 Subject: refactor(fileio.c): reduce scope of locals --- src/nvim/fileio.c | 184 +++++++++++++++++++----------------------------------- 1 file changed, 63 insertions(+), 121 deletions(-) (limited to 'src') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 9da9d6199e..6b3e7dddb5 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -968,13 +968,11 @@ retry: if (read_buf_lnum > from) { size = 0; } else { - int n, ni; - long tlen; - - tlen = 0; + int ni; + long tlen = 0; for (;;) { p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; - n = (int)strlen((char *)p); + int n = (int)strlen((char *)p); if ((int)tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done @@ -2126,7 +2124,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bool errmsg_allocated = false; char *buffer; char smallbuf[SMBUFSIZE]; - char *backup_ext; int bufsize; long perm; // file permissions int retval = OK; @@ -2555,8 +2552,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if ((bkc & BKC_YES) || append) { // "yes" backup_copy = true; } else if ((bkc & BKC_AUTO)) { // "auto" - int i; - // Don't rename the file when: // - it's a hard link // - it's a symbolic link @@ -2571,7 +2566,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // First find a file name that doesn't exist yet (use some // arbitrary numbers). STRCPY(IObuff, fname); - for (i = 4913;; i += 123) { + for (int i = 4913;; i += 123) { char *tail = path_tail(IObuff); size_t size = (size_t)(tail - IObuff); snprintf(tail, IOSIZE - size, "%d", i); @@ -2624,18 +2619,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } // make sure we have a valid backup extension to use - if (*p_bex == NUL) { - backup_ext = ".bak"; - } else { - backup_ext = p_bex; - } + char *backup_ext = *p_bex == NUL ? ".bak" : p_bex; if (backup_copy) { - char *wp; int some_error = false; - char *dirp; - char *rootname; - char *p; // Try to make the backup in each directory in the 'bdir' option. // @@ -2647,11 +2634,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // // For these reasons, the existing writable file must be truncated // and reused. Creation of a backup COPY will be attempted. - dirp = p_bdir; + char *dirp = p_bdir; while (*dirp) { // Isolate one directory name, using an entry in 'bdir'. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - p = IObuff + dir_len; + char *p = IObuff + dir_len; bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; @@ -2674,7 +2661,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } } - rootname = get_file_in_dir(fname, IObuff); + char *rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { some_error = true; // out of memory goto nobackup; @@ -2710,7 +2697,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // delete an existing one, and try to use another name instead. // Change one character, just before the extension. // - wp = backup + strlen(backup) - 1 - strlen(backup_ext); + char *wp = backup + strlen(backup) - 1 - strlen(backup_ext); if (wp < backup) { // empty file name ??? wp = backup; } @@ -2781,10 +2768,6 @@ nobackup: } SET_ERRMSG(NULL); } else { - char *dirp; - char *p; - char *rootname; - // Make a backup by renaming the original file. // If 'cpoptions' includes the "W" flag, we don't want to @@ -2798,11 +2781,11 @@ nobackup: // Form the backup file name - change path/fo.o.h to // path/fo.o.h.bak Try all directories in 'backupdir', first one // that works is used. - dirp = p_bdir; + char *dirp = p_bdir; while (*dirp) { // Isolate one directory name and make the backup file name. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - p = IObuff + dir_len; + char *p = IObuff + dir_len; bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; @@ -2826,7 +2809,7 @@ nobackup: } if (backup == NULL) { - rootname = get_file_in_dir(fname, IObuff); + char *rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { backup = NULL; } else { @@ -3690,9 +3673,7 @@ static bool msg_add_fileformat(int eol_type) /// Append line and character count to IObuff. void msg_add_lines(int insert_space, long lnum, off_T nchars) { - char *p; - - p = IObuff + strlen(IObuff); + char *p = IObuff + strlen(IObuff); if (insert_space) { *p++ = ' '; @@ -3758,46 +3739,35 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F /// @return FAIL for failure, OK otherwise. static int buf_write_bytes(struct bw_info *ip) { - int wlen; - char *buf = ip->bw_buf; // data to write - int len = ip->bw_len; // length of data + char *buf = ip->bw_buf; // data to write + int len = ip->bw_len; // length of data #ifdef HAS_BW_FLAGS - int flags = ip->bw_flags; // extra flags + int flags = ip->bw_flags; // extra flags #endif // Skip conversion when writing the BOM. if (!(flags & FIO_NOCONVERT)) { - char *p; - unsigned c; - int n; - if (flags & FIO_UTF8) { // Convert latin1 in the buffer to UTF-8 in the file. - p = ip->bw_conv_buf; // translate to buffer - for (wlen = 0; wlen < len; wlen++) { + char *p = ip->bw_conv_buf; // translate to buffer + for (int wlen = 0; wlen < len; wlen++) { p += utf_char2bytes((uint8_t)buf[wlen], p); } buf = ip->bw_conv_buf; len = (int)(p - ip->bw_conv_buf); } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { + unsigned c; + int n = 0; // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or // Latin1 chars in the file. - if (flags & FIO_LATIN1) { - p = buf; // translate in-place (can only get shorter) - } else { - p = ip->bw_conv_buf; // translate to buffer - } - for (wlen = 0; wlen < len; wlen += n) { + // translate in-place (can only get shorter) or to buffer + char *p = flags & FIO_LATIN1 ? buf : ip->bw_conv_buf; + for (int wlen = 0; wlen < len; wlen += n) { if (wlen == 0 && ip->bw_restlen != 0) { - int l; - // Use remainder of previous call. Append the start of // buf[] to get a full sequence. Might still be too // short! - l = CONV_RESTLEN - ip->bw_restlen; - if (l > len) { - l = len; - } + int l = MIN(len, CONV_RESTLEN - ip->bw_restlen); memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); n = utf_ptr2len_len((char *)ip->bw_rest, ip->bw_restlen + l); if (n > ip->bw_restlen + len) { @@ -3864,18 +3834,15 @@ static int buf_write_bytes(struct bw_info *ip) if (ip->bw_iconv_fd != (iconv_t)-1) { const char *from; size_t fromlen; - char *to; size_t tolen; // Convert with iconv(). if (ip->bw_restlen > 0) { - char *fp; - // Need to concatenate the remainder of the previous call and // the bytes of the current call. Use the end of the // conversion buffer for this. fromlen = (size_t)len + (size_t)ip->bw_restlen; - fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; + char *fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); memmove(fp + ip->bw_restlen, buf, (size_t)len); from = fp; @@ -3885,7 +3852,7 @@ static int buf_write_bytes(struct bw_info *ip) fromlen = (size_t)len; tolen = ip->bw_conv_buflen; } - to = ip->bw_conv_buf; + char *to = ip->bw_conv_buf; if (ip->bw_first) { size_t save_len = tolen; @@ -3925,7 +3892,7 @@ static int buf_write_bytes(struct bw_info *ip) // Only checking conversion, which is OK if we get here. return OK; } - wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len); + int wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len); return (wlen < len) ? FAIL : OK; } @@ -3940,7 +3907,6 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL { char_u *p = (char_u *)(*pp); bool error = false; - int cc; if (flags & FIO_UCS4) { if (flags & FIO_ENDIAN_L) { @@ -3963,7 +3929,7 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL if (c >= 0x100000) { error = true; } - cc = (int)(((c >> 10) & 0x3ff) + 0xd800); + int cc = (int)(((c >> 10) & 0x3ff) + 0xd800); if (flags & FIO_ENDIAN_L) { *p++ = (uint8_t)cc; *p++ = (uint8_t)(cc >> 8); @@ -4006,7 +3972,6 @@ static bool need_conversion(const char *fenc) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { int same_encoding; - int enc_flags; int fenc_flags; if (*fenc == NUL || strcmp(p_enc, fenc) == 0) { @@ -4015,7 +3980,7 @@ static bool need_conversion(const char *fenc) } else { // Ignore difference between "ansi" and "latin1", "ucs-4" and // "ucs-4be", etc. - enc_flags = get_fio_flags(p_enc); + int enc_flags = get_fio_flags(p_enc); fenc_flags = get_fio_flags(fenc); same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); } @@ -4036,12 +4001,10 @@ static bool need_conversion(const char *fenc) /// @param name string to check for encoding static int get_fio_flags(const char *name) { - int prop; - if (*name == NUL) { name = p_enc; } - prop = enc_canon_props(name); + int prop = enc_canon_props(name); if (prop & ENC_UNICODE) { if (prop & ENC_2BYTE) { if (prop & ENC_ENDIAN_L) { @@ -4121,10 +4084,7 @@ static char *check_for_bom(const char *p_in, long size, int *lenp, int flags) /// @return the length of the BOM (zero when no BOM). static int make_bom(char_u *buf, char *name) { - int flags; - char *p; - - flags = get_fio_flags(name); + int flags = get_fio_flags(name); // Can't put a BOM in a non-Unicode file. if (flags == FIO_LATIN1 || flags == 0) { @@ -4137,7 +4097,7 @@ static int make_bom(char_u *buf, char *name) buf[2] = 0xbf; return 3; } - p = (char *)buf; + char *p = (char *)buf; (void)ucs2bytes(0xfeff, &p, flags); return (int)((char_u *)p - buf); } @@ -4153,8 +4113,6 @@ static int make_bom(char_u *buf, char *name) /// name. void shorten_buf_fname(buf_T *buf, char *dirname, int force) { - char *p; - if (buf->b_fname != NULL && !bt_nofilename(buf) && !path_with_url(buf->b_fname) @@ -4164,7 +4122,7 @@ void shorten_buf_fname(buf_T *buf, char *dirname, int force) if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } - p = path_shorten_fname(buf->b_ffname, dirname); + char *p = path_shorten_fname(buf->b_ffname, dirname); if (p != NULL) { buf->b_sfname = xstrdup(p); buf->b_fname = buf->b_sfname; @@ -4461,10 +4419,7 @@ int vim_rename(const char *from, const char *to) { int fd_in; int fd_out; - int n; char *errmsg = NULL; - char *buffer; - long perm; #ifdef HAVE_ACL vim_acl_T acl; // ACL from original file #endif @@ -4506,7 +4461,7 @@ int vim_rename(const char *from, const char *to) return -1; } STRCPY(tempname, from); - for (n = 123; n < 99999; n++) { + for (int n = 123; n < 99999; n++) { char *tail = path_tail(tempname); snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n); @@ -4540,7 +4495,7 @@ int vim_rename(const char *from, const char *to) } // Rename() failed, try copying the file. - perm = os_getperm(from); + long perm = os_getperm(from); #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. acl = os_get_acl(from); @@ -4566,7 +4521,7 @@ int vim_rename(const char *from, const char *to) // Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim // is `preserve_exit()`ing. - buffer = try_malloc(BUFSIZE); + char *buffer = try_malloc(BUFSIZE); if (buffer == NULL) { close(fd_out); close(fd_in); @@ -4576,6 +4531,7 @@ int vim_rename(const char *from, const char *to) return -1; } + int n; while ((n = (int)read_eintr(fd_in, buffer, BUFSIZE)) > 0) { if (write_eintr(fd_out, buffer, (size_t)n) != n) { errmsg = _("E208: Error writing to \"%s\""); @@ -4619,8 +4575,6 @@ static int already_warned = false; /// @return true if some message was written (screen should be redrawn and cursor positioned). int check_timestamps(int focus) { - int didit = 0; - // Don't check timestamps while system() or another low-level function may // cause us to lose and gain focus. if (no_check_timestamps > 0) { @@ -4635,6 +4589,8 @@ int check_timestamps(int focus) return false; } + int didit = 0; + if (!stuff_empty() || global_busy || !typebuf_typed() || autocmd_busy || curbuf->b_ro_locked > 0 || allbuf_lock > 0) { @@ -4678,13 +4634,11 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) { buf_T *tbuf = curbuf; int retval = OK; - linenr_T lnum; - char *p; // Copy the lines in "frombuf" to "tobuf". curbuf = tobuf; - for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { - p = xstrdup(ml_get_buf(frombuf, lnum, false)); + for (linenr_T lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { + char *p = xstrdup(ml_get_buf(frombuf, lnum, false)); if (ml_append(lnum - 1, p, 0, false) == FAIL) { xfree(p); retval = FAIL; @@ -4696,7 +4650,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) // Delete all the lines in "frombuf". if (retval != FAIL) { curbuf = frombuf; - for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { + for (linenr_T lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { if (ml_delete(lnum, false) == FAIL) { // Oops! We could try putting back the saved lines, but that // might fail again... @@ -4720,7 +4674,6 @@ int buf_check_timestamp(buf_T *buf) FUNC_ATTR_NONNULL_ALL { int retval = 0; - char *path; char *mesg = NULL; char *mesg2 = ""; bool helpmesg = false; @@ -4735,8 +4688,6 @@ int buf_check_timestamp(buf_T *buf) uint64_t orig_size = buf->b_orig_size; int orig_mode = buf->b_orig_mode; static bool busy = false; - char *s; - char *reason; bufref_T bufref; set_bufref(&bufref, buf); @@ -4784,6 +4735,7 @@ int buf_check_timestamp(buf_T *buf) // was set, the global option value otherwise. reload = RELOAD_NORMAL; } else { + char *reason; if (!file_info_ok) { reason = "deleted"; } else if (bufIsChanged(buf)) { @@ -4810,7 +4762,7 @@ int buf_check_timestamp(buf_T *buf) if (!bufref_valid(&bufref)) { emsg(_("E246: FileChangedShell autocommand deleted buffer")); } - s = get_vim_var_str(VV_FCS_CHOICE); + char *s = get_vim_var_str(VV_FCS_CHOICE); if (strcmp(s, "reload") == 0 && *reason != 'd') { reload = RELOAD_NORMAL; } else if (strcmp(s, "edit") == 0) { @@ -4863,7 +4815,7 @@ int buf_check_timestamp(buf_T *buf) } if (mesg != NULL) { - path = home_replace_save(buf, buf->b_fname); + char *path = home_replace_save(buf, buf->b_fname); if (!helpmesg) { mesg2 = ""; } @@ -4946,8 +4898,6 @@ int buf_check_timestamp(buf_T *buf) void buf_reload(buf_T *buf, int orig_mode, bool reload_options) { exarg_T ea; - pos_T old_cursor; - linenr_T old_topline; int old_ro = buf->b_p_ro; buf_T *savebuf; bufref_T bufref; @@ -4967,8 +4917,8 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) prep_exarg(&ea, buf); } - old_cursor = curwin->w_cursor; - old_topline = curwin->w_topline; + pos_T old_cursor = curwin->w_cursor; + linenr_T old_topline = curwin->w_topline; if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) { // Save all the text, so that the reload can be undone. @@ -5454,24 +5404,19 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, bool match_file_list(char *list, char *sfname, char *ffname) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) { - char buf[100]; - char *tail; - char *regpat; - char allow_dirs; - bool match; - char *p; - - tail = path_tail(sfname); + char *tail = path_tail(sfname); // try all patterns in 'wildignore' - p = list; + char *p = list; while (*p) { + char buf[100]; copy_option_part(&p, buf, ARRAY_SIZE(buf), ","); - regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); + char allow_dirs; + char *regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); if (regpat == NULL) { break; } - match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs); + bool match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs); xfree(regpat); if (match) { return true; @@ -5494,15 +5439,6 @@ bool match_file_list(char *list, char *sfname, char *ffname) char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash) FUNC_ATTR_NONNULL_ARG(1) { - const char *endp; - char *reg_pat; - const char *p; - int nested = 0; - bool add_dollar = true; - - if (allow_dirs != NULL) { - *allow_dirs = false; - } if (pat_end == NULL) { pat_end = pat + strlen(pat); } @@ -5511,9 +5447,13 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs return xstrdup("^$"); } + if (allow_dirs != NULL) { + *allow_dirs = false; + } + size_t size = 2; // '^' at start, '$' at end. - for (p = pat; p < pat_end; p++) { + for (const char *p = pat; p < pat_end; p++) { switch (*p) { case '*': case '.': @@ -5534,7 +5474,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs break; } } - reg_pat = xmalloc(size + 1); + char *reg_pat = xmalloc(size + 1); size_t i = 0; @@ -5545,14 +5485,16 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs } else { reg_pat[i++] = '^'; } - endp = pat_end - 1; + const char *endp = pat_end - 1; + bool add_dollar = true; if (endp >= pat && *endp == '*') { while (endp - pat > 0 && *endp == '*') { endp--; } add_dollar = false; } - for (p = pat; *p && nested >= 0 && p <= endp; p++) { + int nested = 0; + for (const char *p = pat; *p && nested >= 0 && p <= endp; p++) { switch (*p) { case '*': reg_pat[i++] = '.'; -- cgit From 843c9025ae8b44b14d0908674c8874a51dc13a38 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Thu, 26 Jan 2023 21:35:06 +0100 Subject: build: check if libvterm version meets requirement (#22010) The vterm.h file only specifies major and minor version, but not patch, meaning that requiring a specific patch number isn't currently possible. --- src/nvim/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 2361210e59..faeef65261 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -30,9 +30,8 @@ find_package(LibTermkey 0.22 REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBTERMKEY_INCLUDE_DIRS}) target_link_libraries(main_lib INTERFACE ${LIBTERMKEY_LIBRARIES}) -find_package(LIBVTERM 0.3 REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBVTERM_INCLUDE_DIRS}) -target_link_libraries(main_lib INTERFACE ${LIBVTERM_LIBRARIES}) +find_package(libvterm 0.3 REQUIRED) +target_link_libraries(main_lib INTERFACE libvterm) find_package(Iconv REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${Iconv_INCLUDE_DIRS}) -- cgit From 9b43dcdbff4fd9418a66a4b356e3cb8a11762971 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 27 Jan 2023 09:48:00 +0000 Subject: fix(test): unset XDG_CONFIG_HOME when running oldtest - also fix test_taglist.vim for users running with a tags file created in runtime/doc --- src/nvim/testdir/runnvim.sh | 3 +++ src/nvim/testdir/test_taglist.vim | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh index 322265737a..3a0a94b6bf 100755 --- a/src/nvim/testdir/runnvim.sh +++ b/src/nvim/testdir/runnvim.sh @@ -30,6 +30,9 @@ main() {( . "$CI_DIR/common/suite.sh" . "$CI_DIR/common/test.sh" + # Redirect XDG_CONFIG_HOME so users local config doesn't interfere + export XDG_CONFIG_HOME="$root" + export VIMRUNTIME="$root/runtime" if ! "$nvim_prg" \ -u NONE -i NONE \ diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim index 0387ef2bd8..75d28c3ec4 100644 --- a/src/nvim/testdir/test_taglist.vim +++ b/src/nvim/testdir/test_taglist.vim @@ -105,8 +105,8 @@ func Test_tagfiles() help let tf = tagfiles() " Nvim: expectation(s) based on tags in build dir (added to &rtp). - " Filter out the (non-existing) '../../../runtime/doc/tags'. - call filter(tf, 'filereadable(v:val)') + " Filter out the '../../../runtime/doc/tags'. + call filter(tf, 'v:val != "../../../runtime/doc/tags"') call assert_equal(1, len(tf)) call assert_equal(fnamemodify(expand('$BUILD_DIR/runtime/doc/tags'), ':p:gs?\\?/?'), \ fnamemodify(tf[0], ':p:gs?\\?/?')) -- cgit From 068151f5c69c9ba5e7d80101ccc62b4aea138a04 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 11:02:00 +0000 Subject: refactor(option.c): factor out some nextchar checks --- src/nvim/option.c | 53 ++++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 641f07d70b..64128333a9 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -726,14 +726,9 @@ void ex_set(exarg_T *eap) (void)do_set(eap->arg, flags); } -static void do_set_bool(int opt_idx, int opt_flags, int prefix, int nextchar, int afterchar, - const char *varp, char **errmsg) +static void do_set_bool(int opt_idx, int opt_flags, int prefix, int nextchar, const char *varp, + char **errmsg) { - if (nextchar == '=' || nextchar == ':') { - *errmsg = e_invarg; - return; - } - varnumber_T value; // ":set opt!": invert @@ -745,24 +740,16 @@ static void do_set_bool(int opt_idx, int opt_flags, int prefix, int nextchar, in value = (int)(intptr_t)options[opt_idx].def_val; } else if (nextchar == '<') { // For 'autoread' -1 means to use global value. - if ((int *)varp == &curbuf->b_p_ar - && opt_flags == OPT_LOCAL) { + if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL) { value = -1; } else { - value = *(int *)get_varp_scope(&(options[opt_idx]), - OPT_GLOBAL); + value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); } } else { - // ":set invopt": invert - // ":set opt" or ":set noopt": set or reset - if (nextchar != NUL && !ascii_iswhite(afterchar)) { - *errmsg = e_trailing; - return; - } - if (prefix == 2) { // inv - value = *(int *)(varp) ^ 1; + if (prefix == 2) { + value = *(int *)varp ^ 1; // ":set invopt": invert } else { - value = prefix; + value = prefix; // ":set opt" or ":set noopt": set or reset } } @@ -1301,12 +1288,12 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla } static void do_set_option_value(int opt_idx, int opt_flags, char **argp, int prefix, int nextchar, - int afterchar, set_op_T op, uint32_t flags, char *varp, - char *errbuf, size_t errbuflen, char **errmsg) + set_op_T op, uint32_t flags, char *varp, char *errbuf, + size_t errbuflen, char **errmsg) { int value_checked = false; if (flags & P_BOOL) { // boolean - do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg); + do_set_bool(opt_idx, opt_flags, prefix, nextchar, varp, errmsg); } else if (flags & P_NUM) { // numeric do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); } else if (opt_idx >= 0) { // string. @@ -1441,12 +1428,24 @@ static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errb return; } - if (!(flags & P_BOOL) && vim_strchr("=:&<", nextchar) == NULL) { - *errmsg = e_invarg; - return; + if (flags & P_BOOL) { + if (vim_strchr("=:", nextchar) != NULL) { + *errmsg = e_invarg; + return; + } + + if (vim_strchr("!&<", nextchar) == NULL && nextchar != NUL && !ascii_iswhite(afterchar)) { + *errmsg = e_trailing; + return; + } + } else { + if (vim_strchr("=:&<", nextchar) == NULL) { + *errmsg = e_invarg; + return; + } } - do_set_option_value(opt_idx, opt_flags, argp, prefix, nextchar, afterchar, op, flags, varp, + do_set_option_value(opt_idx, opt_flags, argp, prefix, nextchar, op, flags, varp, errbuf, errbuflen, errmsg); } -- cgit From 77a0ce1d9b7c6c223fedec043cdd7379d0047bf8 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 11:17:36 +0000 Subject: refactor(option.c): factor out string option special case handling --- src/nvim/option.c | 138 +++++++++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 64128333a9..b8e234981a 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -817,6 +817,78 @@ static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, co errbuf, errbuflen, opt_flags); } +// Handle some special cases with string option values +static void munge_string_opt_val(char **varp, char **oldval, char **const origval, + char_u **const origval_l, char_u **const origval_g, + char **const argp, char *const whichwrap, size_t whichwraplen, + char **const save_argp) +{ + // Set 'keywordprg' to ":help" if an empty + // value was passed to :set by the user. + if (varp == &p_kp && (**argp == NUL || **argp == ' ')) { + *save_argp = *argp; + *argp = ":help"; + } else if (varp == &p_bs && ascii_isdigit(**(char_u **)varp)) { + // Convert 'backspace' number to string, for + // adding, prepending and removing string. + const int i = getdigits_int(varp, true, 0); + switch (i) { + case 0: + *varp = empty_option; + break; + case 1: + *varp = xstrdup("indent,eol"); + break; + case 2: + *varp = xstrdup("indent,eol,start"); + break; + case 3: + *varp = xstrdup("indent,eol,nostop"); + break; + } + xfree(*oldval); + if (*origval == *oldval) { + *origval = *varp; + } + if (*origval_l == (char_u *)(*oldval)) { + *origval_l = *(char_u **)varp; + } + if (*origval_g == (char_u *)(*oldval)) { + *origval_g = *(char_u **)varp; + } + *oldval = *varp; + } else if (varp == &p_ww && ascii_isdigit(**argp)) { + // Convert 'whichwrap' number to string, for backwards compatibility + // with Vim 3.0. + *whichwrap = NUL; + int i = getdigits_int(argp, true, 0); + if (i & 1) { + xstrlcat(whichwrap, "b,", whichwraplen); + } + if (i & 2) { + xstrlcat(whichwrap, "s,", whichwraplen); + } + if (i & 4) { + xstrlcat(whichwrap, "h,l,", whichwraplen); + } + if (i & 8) { + xstrlcat(whichwrap, "<,>,", whichwraplen); + } + if (i & 16) { + xstrlcat(whichwrap, "[,],", whichwraplen); + } + if (*whichwrap != NUL) { // remove trailing , + whichwrap[strlen(whichwrap) - 1] = NUL; + } + *save_argp = *argp; + *argp = whichwrap; + } else if (**argp == '>' && (varp == &p_dir || varp == &p_bdir)) { + // Remove '>' before 'dir' and 'bdir', for backwards compatibility with + // version 3.0 + (*argp)++; + } +} + /// Part of do_set() for string options. static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg, uint32_t flags, char *varp_arg, char *errbuf, size_t errbuflen, @@ -884,70 +956,8 @@ static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, } else { arg++; // jump to after the '=' or ':' - // Set 'keywordprg' to ":help" if an empty - // value was passed to :set by the user. - if (varp == (char *)&p_kp && (*arg == NUL || *arg == ' ')) { - save_arg = arg; - arg = ":help"; - } else if (varp == (char *)&p_bs && ascii_isdigit(**(char_u **)varp)) { - // Convert 'backspace' number to string, for - // adding, prepending and removing string. - int i = getdigits_int((char **)varp, true, 0); - switch (i) { - case 0: - *(char **)varp = empty_option; - break; - case 1: - *(char_u **)varp = (char_u *)xstrdup("indent,eol"); - break; - case 2: - *(char_u **)varp = (char_u *)xstrdup("indent,eol,start"); - break; - case 3: - *(char_u **)varp = (char_u *)xstrdup("indent,eol,nostop"); - break; - } - xfree(oldval); - if (origval == oldval) { - origval = *(char **)varp; - } - if (origval_l == (char_u *)oldval) { - origval_l = *(char_u **)varp; - } - if (origval_g == (char_u *)oldval) { - origval_g = *(char_u **)varp; - } - oldval = *(char **)varp; - } else if (varp == (char *)&p_ww && ascii_isdigit(*arg)) { - // Convert 'whichwrap' number to string, for backwards compatibility - // with Vim 3.0. - *whichwrap = NUL; - int i = getdigits_int(&arg, true, 0); - if (i & 1) { - xstrlcat(whichwrap, "b,", sizeof(whichwrap)); - } - if (i & 2) { - xstrlcat(whichwrap, "s,", sizeof(whichwrap)); - } - if (i & 4) { - xstrlcat(whichwrap, "h,l,", sizeof(whichwrap)); - } - if (i & 8) { - xstrlcat(whichwrap, "<,>,", sizeof(whichwrap)); - } - if (i & 16) { - xstrlcat(whichwrap, "[,],", sizeof(whichwrap)); - } - if (*whichwrap != NUL) { // remove trailing , - whichwrap[strlen(whichwrap) - 1] = NUL; - } - save_arg = arg; - arg = whichwrap; - } else if (*arg == '>' && (varp == (char *)&p_dir || varp == (char *)&p_bdir)) { - // Remove '>' before 'dir' and 'bdir', for backwards compatibility with - // version 3.0 - arg++; - } + munge_string_opt_val((char **)varp, &oldval, &origval, &origval_l, &origval_g, &arg, + whichwrap, sizeof(whichwrap), &save_arg); // Copy the new string into allocated memory. // Can't use set_string_option_direct(), because we need to remove the -- cgit From d85ed00a8cc2274eff4409e2b18ba34178ae567a Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Fri, 27 Jan 2023 11:53:32 +0100 Subject: build: find unibilium without relying on libfindmacros (#22015) This will remove the warning about the find module not providing a version. --- src/nvim/CMakeLists.txt | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index faeef65261..77ed0490d8 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -22,9 +22,8 @@ find_package(TreeSitter REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${TreeSitter_INCLUDE_DIRS}) target_link_libraries(main_lib INTERFACE ${TreeSitter_LIBRARIES}) -find_package(UNIBILIUM 2.0 REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${UNIBILIUM_INCLUDE_DIRS}) -target_link_libraries(main_lib INTERFACE ${UNIBILIUM_LIBRARIES}) +find_package(unibilium 2.0 REQUIRED) +target_link_libraries(main_lib INTERFACE unibilium) find_package(LibTermkey 0.22 REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBTERMKEY_INCLUDE_DIRS}) @@ -174,24 +173,6 @@ if(CI_BUILD) endif() endif() -list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}") -list(APPEND CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}") -check_c_source_compiles(" -#include - -int -main(void) -{ - unibi_str_from_var(unibi_var_from_str(\"\")); - return unibi_num_from_var(unibi_var_from_num(0)); -} -" UNIBI_HAS_VAR_FROM) -list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}") -list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}") -if(UNIBI_HAS_VAR_FROM) - target_compile_definitions(main_lib INTERFACE NVIM_UNIBI_HAS_VAR_FROM) -endif() - list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}") check_c_source_compiles(" #include -- cgit From aec4b476c5689f032103ab3e0ca068fc2af8bbba Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 27 Jan 2023 11:24:20 +0000 Subject: docs(api): tweak data arg for nvim_create_autocmd (#22008) Fixes #21964 --- src/nvim/api/autocmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 931363e199..a2cb297b15 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -404,7 +404,7 @@ cleanup: /// - match: (string) expanded value of || /// - buf: (number) expanded value of || /// - file: (string) expanded value of || -/// - data: (any) arbitrary data passed to |nvim_exec_autocmds()| +/// - data: (any) arbitrary data passed from |nvim_exec_autocmds()| /// - command (string) optional: Vim command to execute on event. Cannot be used with /// {callback} /// - once (boolean) optional: defaults to false. Run the autocommand -- cgit From 881d4adb5942301a26ccd45315e146eccb114519 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 28 Jan 2023 00:42:13 +0100 Subject: build: enable ccache by default if available (#22020) Initial benchmarks show that this gives a nice 50% compile time reduction for neovim. This shouldn't affect users or CI, but it's a nice speedup for local development. The C_COMPILER_LAUNCHER target property is only supported by Makefiles and Ninja generators only, so this won't give a speedup when using the Xcode and Visual Studio generators even if ccache is available. --- src/nvim/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 77ed0490d8..d1bf08f3fb 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -688,6 +688,13 @@ set_target_properties(nvim EXPORT_COMPILE_COMMANDS ON ENABLE_EXPORTS TRUE) +find_program(CCACHE_PRG ccache) +if(CCACHE_PRG) + set_target_properties(nvim + PROPERTIES + C_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;CCACHE_SLOPPINESS=pch_defines,time_macros;${CCACHE_PRG}") +endif() + if(${CMAKE_VERSION} VERSION_LESS 3.20) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) endif() -- cgit From b4c4c232ba6fe3df5c6f12faff4405a16e4d40df Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 28 Jan 2023 13:06:45 +0800 Subject: fix(fileio.c): don't use uninitialized memory (#22031) --- src/nvim/fileio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 6b3e7dddb5..fbb5c4f1fa 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -5439,6 +5439,10 @@ bool match_file_list(char *list, char *sfname, char *ffname) char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash) FUNC_ATTR_NONNULL_ARG(1) { + if (allow_dirs != NULL) { + *allow_dirs = false; + } + if (pat_end == NULL) { pat_end = pat + strlen(pat); } @@ -5447,10 +5451,6 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs return xstrdup("^$"); } - if (allow_dirs != NULL) { - *allow_dirs = false; - } - size_t size = 2; // '^' at start, '$' at end. for (const char *p = pat; p < pat_end; p++) { -- cgit From 4c90a84c61d19e5131579b2c38960de3ec8e4a5e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 29 Jan 2023 07:42:22 +0800 Subject: vim-patch:9.0.1255: changing 'virtualedit' does not have immediate effect (#22039) Problem: Changing 'virtualedit' does not have immediate effect. Solution: Correct how is checked for a changed value. (closes vim/vim#11878) https://github.com/vim/vim/commit/8fe5b9c8c1223861cec0484ccc031858ae08d107 Co-authored-by: Bram Moolenaar --- src/nvim/optionstr.c | 3 ++- src/nvim/testdir/test_virtualedit.vim | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 5ebff9ed77..30afb0db37 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -1404,10 +1404,11 @@ static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, char ** } else { if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { *errmsg = e_invarg; - } else if (strcmp(p_ve, oldval) != 0) { + } else if (strcmp(ve, oldval) != 0) { // Recompute cursor position in case the new 've' setting // changes something. validate_virtcol_win(win); + // XXX: this only works when win == curwin coladvance(win->w_virtcol); } } diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim index 2bf8c3fc77..20a5f87517 100644 --- a/src/nvim/testdir/test_virtualedit.vim +++ b/src/nvim/testdir/test_virtualedit.vim @@ -537,6 +537,19 @@ func Test_global_local_virtualedit() set virtualedit& endfunc +func Test_virtualedit_setlocal() + enew + setglobal virtualedit=all + setlocal virtualedit=all + normal! l + redraw + setlocal virtualedit=none + call assert_equal(1, wincol()) + + setlocal virtualedit& + set virtualedit& +endfunc + func Test_virtualedit_mouse() let save_mouse = &mouse set mouse=a -- cgit From 8144deb0989ea5c61fe9a1a5802d230eba33dfdd Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 29 Jan 2023 10:39:20 +0100 Subject: vim-patch:9.0.1256: NetworkManager connection files are not recognized (#22038) Problem: NetworkManager connection files are not recognized. Solution: Add a pattern for NetworkManager connection files. (closes vim/vim#11893) https://github.com/vim/vim/commit/04e4f1d98556e67d7337224b67b71c828410ee0f Co-authored-by: ObserverOfTime --- src/nvim/testdir/test_filetype.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index cddb1349f5..a4fbe48249 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -123,7 +123,7 @@ let s:filename_checks = { \ 'conaryrecipe': ['file.recipe'], \ 'conf': ['auto.master'], \ 'config': ['configure.in', 'configure.ac', '/etc/hostname.file', 'any/etc/hostname.file'], - \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials'], + \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials', 'file.nmconnection'], \ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi', 'file.mkxl', 'file.mklx'], \ 'cook': ['file.cook'], \ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'], -- cgit From 930125647fd99de78b6845f9a4db637ae4517b84 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 29 Jan 2023 17:02:34 +0100 Subject: build: enable ccache project-wide (#22045) Currently, only the nvim target uses ccache but not libnvim or unittests. It is generally a good idea to operate on targets rather than globally, but this is an exception as there isn't a target where we don't want to use ccache on. --- src/nvim/CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index d1bf08f3fb..77ed0490d8 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -688,13 +688,6 @@ set_target_properties(nvim EXPORT_COMPILE_COMMANDS ON ENABLE_EXPORTS TRUE) -find_program(CCACHE_PRG ccache) -if(CCACHE_PRG) - set_target_properties(nvim - PROPERTIES - C_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;CCACHE_SLOPPINESS=pch_defines,time_macros;${CCACHE_PRG}") -endif() - if(${CMAKE_VERSION} VERSION_LESS 3.20) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) endif() -- cgit From c9ac4e487706658852f0e6c2e71cf669dafba90b Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Sun, 29 Jan 2023 14:19:07 -0500 Subject: vim-patch:9.0.1261: Elsa files are not recognized (#22047) Problem: Elsa files are not recognized. Solution: Add the name of Elsa files. (Amaan Qureshi) https://github.com/vim/vim/commit/2a99fe6c41efcd5d1eb47823e7e73cf391e230ba --- src/nvim/testdir/test_filetype.vim | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index a4fbe48249..128ecfb408 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -181,6 +181,7 @@ let s:filename_checks = { \ 'elixir': ['file.ex', 'file.exs', 'mix.lock'], \ 'elm': ['file.elm'], \ 'elmfilt': ['filter-rules'], + \ 'elsa': ['file.lc'], \ 'elvish': ['file.elv'], \ 'epuppet': ['file.epp'], \ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'], -- cgit From 27b81af19c498892f4b0444ad29b7be842f8e7b8 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 30 Jan 2023 19:06:32 +0100 Subject: refactor!: remove has("debug") (#22060) This value can not be relied on as it doesn't work for multi-configuration generators. I don't think this undocumented option is used much, if at all, so I think we should remove it. --- src/nvim/eval/funcs.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 938fef9a52..48f3cd4293 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3064,9 +3064,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) "conceal", "cursorbind", "cursorshape", -#ifdef DEBUG - "debug", -#endif "dialog_con", "diff", "digraphs", -- cgit From 860fea1a3f880c2da0ac351a9523156bcfc67361 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 31 Jan 2023 07:08:23 +0800 Subject: fix(highlight): properly deal with underline mask when listing (#22057) --- src/nvim/highlight.c | 10 +++++----- src/nvim/highlight_defs.h | 4 ++-- src/nvim/highlight_group.c | 9 +++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 9dab91cc2b..c20eac3c28 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -842,14 +842,14 @@ void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb) PUT_C(hl, "underline", BOOLEAN_OBJ(true)); break; - case HL_UNDERDOUBLE: - PUT_C(hl, "underdouble", BOOLEAN_OBJ(true)); - break; - case HL_UNDERCURL: PUT_C(hl, "undercurl", BOOLEAN_OBJ(true)); break; + case HL_UNDERDOUBLE: + PUT_C(hl, "underdouble", BOOLEAN_OBJ(true)); + break; + case HL_UNDERDOTTED: PUT_C(hl, "underdotted", BOOLEAN_OBJ(true)); break; @@ -930,8 +930,8 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e CHECK_FLAG(dict, mask, bold, , HL_BOLD); CHECK_FLAG(dict, mask, italic, , HL_ITALIC); CHECK_FLAG(dict, mask, underline, , HL_UNDERLINE); - CHECK_FLAG(dict, mask, underdouble, , HL_UNDERDOUBLE); CHECK_FLAG(dict, mask, undercurl, , HL_UNDERCURL); + CHECK_FLAG(dict, mask, underdouble, , HL_UNDERDOUBLE); CHECK_FLAG(dict, mask, underdotted, , HL_UNDERDOTTED); CHECK_FLAG(dict, mask, underdashed, , HL_UNDERDASHED); CHECK_FLAG(dict, mask, standout, , HL_STANDOUT); diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index a4dcf6eb60..95c81ac9db 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -18,8 +18,8 @@ typedef enum { // The next three bits are all underline styles HL_UNDERLINE_MASK = 0x38, HL_UNDERLINE = 0x08, - HL_UNDERDOUBLE = 0x10, - HL_UNDERCURL = 0x18, + HL_UNDERCURL = 0x10, + HL_UNDERDOUBLE = 0x18, HL_UNDERDOTTED = 0x20, HL_UNDERDASHED = 0x28, // 0x30 and 0x38 spare for underline styles diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 5b1ea9967d..3d91335f55 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1553,12 +1553,17 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg } else { // type == LIST_ATTR buf[0] = NUL; for (int i = 0; hl_attr_table[i] != 0; i++) { - if (iarg & hl_attr_table[i]) { + if (((hl_attr_table[i] & HL_UNDERLINE_MASK) + && ((iarg & HL_UNDERLINE_MASK) == hl_attr_table[i])) + || (!(hl_attr_table[i] & HL_UNDERLINE_MASK) + && (iarg & hl_attr_table[i]))) { if (buf[0] != NUL) { xstrlcat(buf, ",", 100); } xstrlcat(buf, hl_name_table[i], 100); - iarg &= ~hl_attr_table[i]; // don't want "inverse" + if (!(hl_attr_table[i] & HL_UNDERLINE_MASK)) { + iarg &= ~hl_attr_table[i]; // don't want "inverse" + } } } } -- cgit From b649a96fc09fa7f18a988b0b0be5dadb54ad49de Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 31 Jan 2023 08:12:10 +0100 Subject: vim-patch:9.0.1263: KDL files are not recognized (#22058) Problem: KDL files are not recognized. Solution: Add a pattern for KDL files. (Amaan Qureshi, closes vim/vim#11898) https://github.com/vim/vim/commit/907349a74331fc1bc48cf43c1e7d54cb9e0e4fc9 Co-authored-by: Amaan Qureshi --- src/nvim/testdir/test_filetype.vim | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 128ecfb408..e366fd23ad 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -302,6 +302,7 @@ let s:filename_checks = { \ 'jsp': ['file.jsp'], \ 'julia': ['file.jl'], \ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'], + \ 'kdl': ['file.kdl'], \ 'kivy': ['file.kv'], \ 'kix': ['file.kix'], \ 'kotlin': ['file.kt', 'file.ktm', 'file.kts'], -- cgit From d6d6ab3f8e77d54c8030c0c18f17d3c72ac4445c Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 26 Feb 2022 15:19:10 +0100 Subject: feat(lua): low-level interpreter mode (nvim -ll) --- src/nvim/lua/executor.c | 67 ++++++++++++++++++++++++++++++++++++------------- src/nvim/main.c | 16 ++++++++++-- 2 files changed, 63 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 5ffd90fddd..d144a5ae23 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -64,6 +64,7 @@ #include "nvim/window.h" static int in_fast_callback = 0; +static bool in_script = false; // Initialized in nlua_init(). static lua_State *global_lstate = NULL; @@ -133,8 +134,13 @@ static void nlua_error(lua_State *const lstate, const char *const msg) str = lua_tolstring(lstate, -1, &len); } - msg_ext_set_kind("lua_error"); - semsg_multiline(msg, (int)len, str); + if (in_script) { + os_errmsg(str); + os_errmsg("\n"); + } else { + msg_ext_set_kind("lua_error"); + semsg_multiline(msg, (int)len, str); + } lua_pop(lstate, 1); } @@ -534,7 +540,7 @@ int nlua_get_global_ref_count(void) return nlua_global_refs->ref_count; } -static void nlua_common_vim_init(lua_State *lstate, bool is_thread) +static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_standalone) FUNC_ATTR_NONNULL_ARG(1) { nlua_ref_state_t *ref_state = nlua_new_ref_state(lstate, is_thread); @@ -567,7 +573,9 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread) lua_setfield(lstate, -2, "_empty_dict_mt"); // vim.loop - if (is_thread) { + if (is_standalone) { + // do nothing, use libluv like in a standalone interpreter + } else if (is_thread) { luv_set_callback(lstate, nlua_luv_thread_cb_cfpcall); luv_set_thread(lstate, nlua_luv_thread_cfpcall); luv_set_cthread(lstate, nlua_luv_thread_cfcpcall); @@ -606,7 +614,7 @@ static int nlua_module_preloader(lua_State *lstate) return 1; } -static bool nlua_init_packages(lua_State *lstate) +static bool nlua_init_packages(lua_State *lstate, bool is_standalone) FUNC_ATTR_NONNULL_ALL { // put builtin packages in preload @@ -618,7 +626,7 @@ static bool nlua_init_packages(lua_State *lstate) lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure] lua_setfield(lstate, -2, def.name); // [package, preload] - if (nlua_disable_preload && strequal(def.name, "vim.inspect")) { + if ((nlua_disable_preload && !is_standalone) && strequal(def.name, "vim.inspect")) { break; } } @@ -769,7 +777,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, &nlua_ui_detach); lua_setfield(lstate, -2, "ui_detach"); - nlua_common_vim_init(lstate, false); + nlua_common_vim_init(lstate, false, false); // patch require() (only for --startuptime) if (time_fd != NULL) { @@ -788,7 +796,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_setglobal(lstate, "vim"); - if (!nlua_init_packages(lstate)) { + if (!nlua_init_packages(lstate, false)) { return false; } @@ -823,10 +831,29 @@ void nlua_init(char **argv, int argc, int lua_arg0) } static lua_State *nlua_thread_acquire_vm(void) +{ + return nlua_init_state(true); +} + +void nlua_run_script(char **argv, int argc, int lua_arg0) + FUNC_ATTR_NORETURN +{ + in_script = true; + global_lstate = nlua_init_state(false); + luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem); + nlua_init_argv(global_lstate, argv, argc, lua_arg0); + bool lua_ok = nlua_exec_file(argv[lua_arg0 - 1]); +#ifdef EXITFREE + nlua_free_all_mem(); +#endif + exit(lua_ok ? 0 : 1); +} + +lua_State *nlua_init_state(bool thread) { // If it is called from the main thread, it will attempt to rebuild the cache. const uv_thread_t self = uv_thread_self(); - if (uv_thread_equal(&main_thread, &self)) { + if (!in_script && uv_thread_equal(&main_thread, &self)) { runtime_search_path_validate(); } @@ -835,9 +862,11 @@ static lua_State *nlua_thread_acquire_vm(void) // Add in the lua standard libraries luaL_openlibs(lstate); - // print - lua_pushcfunction(lstate, &nlua_print); - lua_setglobal(lstate, "print"); + if (!in_script) { + // print + lua_pushcfunction(lstate, &nlua_print); + lua_setglobal(lstate, "print"); + } lua_pushinteger(lstate, 0); lua_setfield(lstate, LUA_REGISTRYINDEX, "nlua.refcount"); @@ -845,18 +874,20 @@ static lua_State *nlua_thread_acquire_vm(void) // vim lua_newtable(lstate); - nlua_common_vim_init(lstate, true); + nlua_common_vim_init(lstate, thread, in_script); nlua_state_add_stdlib(lstate, true); - lua_createtable(lstate, 0, 0); - lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime); - lua_setfield(lstate, -2, "nvim__get_runtime"); - lua_setfield(lstate, -2, "api"); + if (!in_script) { + lua_createtable(lstate, 0, 0); + lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime); + lua_setfield(lstate, -2, "nvim__get_runtime"); + lua_setfield(lstate, -2, "api"); + } lua_setglobal(lstate, "vim"); - nlua_init_packages(lstate); + nlua_init_packages(lstate, in_script); lua_getglobal(lstate, "package"); lua_getfield(lstate, -1, "loaded"); diff --git a/src/nvim/main.c b/src/nvim/main.c index bbe877356d..8df82c710a 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -239,6 +239,14 @@ int main(int argc, char **argv) argv0 = argv[0]; + if (argc > 1 && STRICMP(argv[1], "-ll") == 0) { + if (argc == 2) { + print_mainerr(err_arg_missing, argv[1]); + exit(1); + } + nlua_run_script(argv, argc, 3); + } + char *fname = NULL; // file name from command line mparm_T params; // various parameters passed between // main() and other functions. @@ -2110,6 +2118,12 @@ static int execute_env(char *env) /// @param str string to append to the primary error message, or NULL static void mainerr(const char *errstr, const char *str) FUNC_ATTR_NORETURN +{ + print_mainerr(errstr, str); + os_exit(1); +} + +static void print_mainerr(const char *errstr, const char *str) { char *prgname = path_tail(argv0); @@ -2126,8 +2140,6 @@ static void mainerr(const char *errstr, const char *str) os_errmsg(_("\nMore info with \"")); os_errmsg(prgname); os_errmsg(" -h\"\n"); - - os_exit(1); } /// Prints version information for "nvim -v" or "nvim --version". -- cgit From 42999a8d645ccf880222f0192671b8ce01bde361 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 30 Jan 2023 14:46:28 +0100 Subject: fix(test): fix issues detected by running unittests in ASAN/UBSAN --- src/nvim/lua/executor.c | 3 +++ src/nvim/marktree.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d144a5ae23..1415ceeaed 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -821,6 +821,9 @@ void nlua_init(char **argv, int argc, int lua_arg0) luaL_openlibs(lstate); if (!nlua_state_init(lstate)) { os_errmsg(_("E970: Failed to initialize builtin lua modules\n")); +#ifdef EXITFREE + nlua_common_free_all_mem(lstate); +#endif os_exit(1); } diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 2036ddd21d..77ba6e6fa4 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -1182,7 +1182,7 @@ static size_t check_node(MarkTree *b, mtnode_t *x, mtpos_t *last, bool *last_rig assert(x->ptr[i] != x->ptr[j]); } } - } else { + } else if (x->n > 0) { *last = x->key[x->n - 1].pos; } return n_keys; -- cgit From 13aa23b62af4df3e7f10687b76fe8c04efa2a598 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 30 Jan 2023 20:36:49 +0100 Subject: refactor(tests): run unittests using main nvim binary in interpreter mode This allows us to get rid of the separate "nvim-test" target --- src/nvim/CMakeLists.txt | 31 +++++++++---------------------- src/nvim/tui/input.c | 16 +--------------- src/nvim/tui/input.h | 8 ++------ 3 files changed, 12 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 77ed0490d8..7b56af59da 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -52,7 +52,7 @@ if(PREFER_LUA) find_package(Lua 5.1 EXACT REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUA_INCLUDE_DIR}) target_link_libraries(main_lib INTERFACE ${LUA_LIBRARIES}) - # Passive (not REQUIRED): if LUAJIT_FOUND is not set, nvim-test is skipped. + # Passive (not REQUIRED): if LUAJIT_FOUND is not set, fixtures for unittests is skipped. find_package(LuaJit) else() find_package(LuaJit REQUIRED) @@ -679,6 +679,14 @@ if(UNIX) endif() endif() +if(NOT LUAJIT_FOUND) + message(STATUS "luajit not found, skipping unit tests") +elseif(CMAKE_BUILD_TYPE MATCHES Debug) + glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) + list(APPEND NVIM_SOURCES ${UNIT_TEST_FIXTURES}) + target_compile_definitions(main_lib INTERFACE UNIT_TESTING) +endif() + target_sources(nvim PRIVATE ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS} ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}) @@ -837,27 +845,6 @@ set_target_properties( target_compile_definitions(libnvim PRIVATE MAKE_LIB) target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv_lib) -if(NOT LUAJIT_FOUND) - message(STATUS "luajit not found, skipping nvim-test (unit tests) target") -else() - glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) - add_library( - nvim-test - MODULE - EXCLUDE_FROM_ALL - ${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES} - ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} - ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS} - ${UNIT_TEST_FIXTURES} - ) - target_link_libraries(nvim-test PRIVATE ${LUAJIT_LIBRARIES} main_lib PUBLIC libuv_lib) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_link_libraries(nvim-test PRIVATE "-framework CoreServices") - endif() - target_include_directories(nvim-test PRIVATE ${LUAJIT_INCLUDE_DIRS}) - target_compile_definitions(nvim-test PRIVATE UNIT_TESTING) -endif() - if(CLANG_ASAN_UBSAN) message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.") if(CI_BUILD) diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 2cb39ab26b..733aa25f03 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -117,14 +117,6 @@ static const struct kitty_key_map_entry { static Map(KittyKey, cstr_t) kitty_key_map = MAP_INIT; -#ifndef UNIT_TESTING -typedef enum { - kIncomplete = -1, - kNotApplicable = 0, - kComplete = 1, -} HandleState; -#endif - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tui/input.c.generated.h" #endif @@ -584,7 +576,7 @@ static void set_bg(char *bgvalue) // ignored in the calculations. // // [1] https://en.wikipedia.org/wiki/Luma_%28video%29 -static HandleState handle_background_color(TermInput *input) +HandleState handle_background_color(TermInput *input) { if (input->waiting_for_bg_response <= 0) { return kNotApplicable; @@ -669,12 +661,6 @@ static HandleState handle_background_color(TermInput *input) } return kComplete; } -#ifdef UNIT_TESTING -HandleState ut_handle_background_color(TermInput *input) -{ - return handle_background_color(input); -} -#endif static void handle_raw_buffer(TermInput *input, bool force) { diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 5df108b107..d33cea6383 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -40,18 +40,14 @@ typedef struct term_input { TUIData *tui_data; } TermInput; -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "tui/input.h.generated.h" -#endif - -#ifdef UNIT_TESTING typedef enum { kIncomplete = -1, kNotApplicable = 0, kComplete = 1, } HandleState; -HandleState ut_handle_background_color(TermInput *input); +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/input.h.generated.h" #endif #endif // NVIM_TUI_INPUT_H -- cgit From 249b9de4056d0e0a57c59bc533a0cf2b96c42436 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 1 Feb 2023 08:17:18 +0800 Subject: refactor(optionstr.c): align comments (#22070) Align comments in did_set_string_option_for() at column 57. --- src/nvim/optionstr.c | 276 ++++++++++++++++++++++++++------------------------- 1 file changed, 143 insertions(+), 133 deletions(-) (limited to 'src') diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 30afb0db37..ca50c3ab00 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -638,13 +638,11 @@ char *check_stl_option(char *s) return NULL; } -static int shada_idx = -1; - +/// Check for a "normal" directory or file name in some options. Disallow a +/// path separator (slash and/or backslash), wildcards and characters that are +/// often illegal in a file name. Be more permissive if "secure" is off. static bool check_illegal_path_names(char *val, uint32_t flags) { - // Disallow a path separator (slash and/or backslash), wildcards and - // characters that are often illegal in a file name. Be more permissive - // if "secure" is off. return (((flags & P_NFNAME) && strpbrk(val, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) || ((flags & P_NDNAME) @@ -701,8 +699,8 @@ static void did_set_breakindentopt(win_T *win, char **errmsg) static void did_set_isopt(buf_T *buf, bool *did_chartab, char **errmsg) { // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] - // If the new option is invalid, use old value. 'lisp' option: refill - // g_chartab[] for '-' char + // If the new option is invalid, use old value. + // 'lisp' option: refill g_chartab[] for '-' char if (buf_init_chartab(buf, true) == FAIL) { *did_chartab = true; // need to restore it below *errmsg = e_invarg; // error in value @@ -1013,6 +1011,8 @@ static void did_set_verbosefile(char **errmsg) } } +static int shada_idx = -1; + static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf, size_t errbuflen, char **errmsg) { @@ -1272,6 +1272,16 @@ static void did_set_completeopt(char **errmsg) } } +#ifdef BACKSLASH_IN_FILENAME +static void did_set_completeslash(buf_T *buf, char **errmsg) +{ + if (check_opt_strings(p_csl, p_csl_values, false) != OK + || check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) { + *errmsg = e_invarg; + } +} +#endif + static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, char **errmsg) { if (check_signcolumn(*varp) != OK) { @@ -1561,7 +1571,7 @@ static void do_filetype_autocmd(buf_T *buf, char **varp, int opt_flags, bool val } } -static void did_set_spelllang_source(win_T *win) +static void do_spelllang_source(win_T *win) { char fname[200]; char *q = win->w_s->b_p_spl; @@ -1614,238 +1624,238 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char char **gvarp = (char **)get_varp_scope(opt, OPT_GLOBAL); // Disallow changing some options from secure mode - if ((secure || sandbox != 0) - && (opt->flags & P_SECURE)) { + if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) { errmsg = e_secure; - } else if (check_illegal_path_names(*varp, opt->flags)) { // Check for a "normal" directory or file name in some options. + } else if (check_illegal_path_names(*varp, opt->flags)) { errmsg = e_invarg; - } else if (gvarp == &p_bkc) { // 'backupcopy' + } else if (gvarp == &p_bkc) { // 'backupcopy' did_set_backupcopy(buf, oldval, opt_flags, &errmsg); - } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode' + } else if (varp == &p_bex // 'backupext' + || varp == &p_pm) { // 'patchmode' did_set_backupext_or_patchmode(&errmsg); - } else if (varp == &win->w_p_briopt) { // 'breakindentopt' + } else if (varp == &win->w_p_briopt) { // 'breakindentopt' did_set_breakindentopt(win, &errmsg); - } else if (varp == &p_isi - || varp == &buf->b_p_isk - || varp == &p_isp - || varp == &p_isf) { - // 'isident', 'iskeyword', 'isprint or 'isfname' option + } else if (varp == &p_isi // 'isident' + || varp == &buf->b_p_isk // 'iskeyword' + || varp == &p_isp // 'isprint' + || varp == &p_isf) { // 'isfname' did_set_isopt(buf, &did_chartab, &errmsg); - } else if (varp == &p_hf) { // 'helpfile' + } else if (varp == &p_hf) { // 'helpfile' did_set_helpfile(); - } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath' + } else if (varp == &p_rtp // 'runtimepath' + || varp == &p_pp) { // 'packpath' runtime_search_path_invalidate(); - } else if (varp == &win->w_p_culopt - || gvarp == &win->w_allbuf_opt.wo_culopt) { // 'cursorlineopt' + } else if (gvarp == &win->w_allbuf_opt.wo_culopt) { // 'cursorlineopt' did_set_cursorlineopt(win, varp, &errmsg); - } else if (varp == &win->w_p_cc) { // 'colorcolumn' + } else if (varp == &win->w_p_cc) { // 'colorcolumn' errmsg = check_colorcolumn(win); - } else if (varp == &p_hlg) { // 'helplang' + } else if (varp == &p_hlg) { // 'helplang' did_set_helplang(&errmsg); - } else if (varp == &p_hl) { // 'highlight' + } else if (varp == &p_hl) { // 'highlight' did_set_highlight(varp, &errmsg); - } else if (varp == &p_jop) { // 'jumpoptions' + } else if (varp == &p_jop) { // 'jumpoptions' did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true, &errmsg); - } else if (gvarp == &p_nf) { // 'nrformats' + } else if (gvarp == &p_nf) { // 'nrformats' did_set_opt_strings(*varp, p_nf_values, true, &errmsg); - } else if (varp == &p_ssop) { // 'sessionoptions' + } else if (varp == &p_ssop) { // 'sessionoptions' did_set_sessionoptions(oldval, &errmsg); - } else if (varp == &p_vop) { // 'viewoptions' + } else if (varp == &p_vop) { // 'viewoptions' did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true, &errmsg); - } else if (varp == &p_rdb) { // 'redrawdebug' + } else if (varp == &p_rdb) { // 'redrawdebug' did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true, &errmsg); - } else if (varp == &p_sbo) { // 'scrollopt' + } else if (varp == &p_sbo) { // 'scrollopt' did_set_opt_strings(p_sbo, p_scbopt_values, true, &errmsg); - } else if (varp == &p_ambw || (int *)varp == &p_emoji) { // 'ambiwidth' + } else if (varp == &p_ambw // 'ambiwidth' + || (int *)varp == &p_emoji) { // 'emoji' did_set_ambiwidth(&errmsg); - } else if (varp == &p_bg) { // 'background' + } else if (varp == &p_bg) { // 'background' did_set_background(&errmsg); - } else if (varp == &p_wim) { // 'wildmode' + } else if (varp == &p_wim) { // 'wildmode' did_set_wildmode(&errmsg); - } else if (varp == &p_wop) { // 'wildoptions' + } else if (varp == &p_wop) { // 'wildoptions' did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true, &errmsg); - } else if (varp == &p_wak) { // 'winaltkeys' + } else if (varp == &p_wak) { // 'winaltkeys' did_set_winaltkeys(&errmsg); - } else if (varp == &p_ei) { // 'eventignore' + } else if (varp == &p_ei) { // 'eventignore' did_set_eventignore(&errmsg); - } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) { - // 'encoding', 'fileencoding' and 'makeencoding' + } else if (varp == &p_enc // 'encoding' + || gvarp == &p_fenc // 'fileencoding' + || gvarp == &p_menc) { // 'makeencoding' did_set_encoding(buf, varp, gvarp, opt_flags, &errmsg); - } else if (varp == &buf->b_p_keymap) { + } else if (varp == &buf->b_p_keymap) { // 'keymap' did_set_keymap(buf, varp, opt_flags, value_checked, &errmsg); - } else if (gvarp == &p_ff) { // 'fileformat' + } else if (gvarp == &p_ff) { // 'fileformat' did_set_fileformat(buf, varp, oldval, opt_flags, &errmsg); - } else if (varp == &p_ffs) { // 'fileformats' + } else if (varp == &p_ffs) { // 'fileformats' did_set_opt_strings(p_ffs, p_ff_values, true, &errmsg); - } else if (gvarp == &p_mps) { // 'matchpairs' + } else if (gvarp == &p_mps) { // 'matchpairs' did_set_matchpairs(varp, &errmsg); - } else if (gvarp == &p_com) { // 'comments' + } else if (gvarp == &p_com) { // 'comments' did_set_comments(varp, errbuf, errbuflen, &errmsg); - } else if (varp == &p_lcs || varp == &p_fcs) { // global 'listchars' or 'fillchars' + } else if (varp == &p_lcs // global 'listchars' + || varp == &p_fcs) { // global 'fillchars' did_set_global_listfillchars(win, varp, opt_flags, &errmsg); - } else if (varp == &win->w_p_lcs) { // local 'listchars' + } else if (varp == &win->w_p_lcs) { // local 'listchars' errmsg = set_chars_option(win, varp, true); - } else if (varp == &win->w_p_fcs) { // local 'fillchars' + } else if (varp == &win->w_p_fcs) { // local 'fillchars' errmsg = set_chars_option(win, varp, true); - } else if (varp == &p_cedit) { // 'cedit' + } else if (varp == &p_cedit) { // 'cedit' errmsg = check_cedit(); - } else if (varp == &p_vfile) { // 'verbosefile' + } else if (varp == &p_vfile) { // 'verbosefile' did_set_verbosefile(&errmsg); - } else if (varp == &p_shada) { // 'shada' + } else if (varp == &p_shada) { // 'shada' did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen, &errmsg); - } else if (gvarp == &p_sbr) { // 'showbreak' + } else if (gvarp == &p_sbr) { // 'showbreak' did_set_showbreak(varp, &errmsg); - } else if (varp == &p_guicursor) { // 'guicursor' + } else if (varp == &p_guicursor) { // 'guicursor' errmsg = parse_shape_opt(SHAPE_CURSOR); - } else if (varp == &p_langmap) { // 'langmap' + } else if (varp == &p_langmap) { // 'langmap' langmap_set(); - } else if (varp == &p_breakat) { // 'breakat' + } else if (varp == &p_breakat) { // 'breakat' fill_breakat_flags(); - } else if (varp == &p_titlestring || varp == &p_iconstring) { - // 'titlestring' and 'iconstring' + } else if (varp == &p_titlestring // 'titlestring' + || varp == &p_iconstring) { // 'iconstring' did_set_titleiconstring(varp); - } else if (varp == &p_sel) { // 'selection' + } else if (varp == &p_sel) { // 'selection' did_set_selection(&errmsg); - } else if (varp == &p_slm) { // 'selectmode' + } else if (varp == &p_slm) { // 'selectmode' did_set_opt_strings(p_slm, p_slm_values, true, &errmsg); - } else if (varp == &p_km) { // 'keymodel' + } else if (varp == &p_km) { // 'keymodel' did_set_keymodel(&errmsg); - } else if (varp == &p_mousem) { // 'mousemodel' + } else if (varp == &p_mousem) { // 'mousemodel' did_set_opt_strings(p_mousem, p_mousem_values, false, &errmsg); - } else if (varp == &p_mousescroll) { // 'mousescroll' + } else if (varp == &p_mousescroll) { // 'mousescroll' errmsg = check_mousescroll(p_mousescroll); - } else if (varp == &p_swb) { // 'switchbuf' + } else if (varp == &p_swb) { // 'switchbuf' did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true, &errmsg); - } else if (varp == &p_spk) { // 'splitkeep' + } else if (varp == &p_spk) { // 'splitkeep' did_set_opt_strings(p_spk, p_spk_values, false, &errmsg); - } else if (varp == &p_debug) { // 'debug' + } else if (varp == &p_debug) { // 'debug' did_set_opt_strings(p_debug, p_debug_values, true, &errmsg); - } else if (varp == &p_dy) { // 'display' + } else if (varp == &p_dy) { // 'display' did_set_display(&errmsg); - } else if (varp == &p_ead) { // 'eadirection' + } else if (varp == &p_ead) { // 'eadirection' did_set_opt_strings(p_ead, p_ead_values, false, &errmsg); - } else if (varp == &p_cb) { // 'clipboard' + } else if (varp == &p_cb) { // 'clipboard' did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true, &errmsg); - } else if (varp == &win->w_s->b_p_spf) { + } else if (varp == &win->w_s->b_p_spf) { // 'spellfile' did_set_spellfile(varp, &errmsg); - } else if (varp == &win->w_s->b_p_spl) { // 'spell' + } else if (varp == &win->w_s->b_p_spl) { // 'spell' did_set_spell(varp, &errmsg); - } else if (varp == &win->w_s->b_p_spc) { + } else if (varp == &win->w_s->b_p_spc) { // 'spellcapcheck' did_set_spellcapcheck(win, &errmsg); - } else if (varp == &win->w_s->b_p_spo) { // 'spelloptions' + } else if (varp == &win->w_s->b_p_spo) { // 'spelloptions' did_set_spelloptions(win, &errmsg); - } else if (varp == &p_sps) { // 'spellsuggest' + } else if (varp == &p_sps) { // 'spellsuggest' did_set_spellsuggest(&errmsg); - } else if (varp == &p_msm) { // 'mkspellmem' + } else if (varp == &p_msm) { // 'mkspellmem' did_set_mkspellmem(&errmsg); - } else if (gvarp == &p_bh) { + } else if (gvarp == &p_bh) { // 'bufhidden' did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false, &errmsg); - } else if (gvarp == &p_bt) { // 'buftype' + } else if (gvarp == &p_bt) { // 'buftype' did_set_buftype(buf, win, &errmsg); - } else if (gvarp == &p_stl || gvarp == &p_wbr || varp == &p_tal - || varp == &p_ruf || varp == &win->w_p_stc) { - // 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' + } else if (gvarp == &p_stl // 'statusline' + || gvarp == &p_wbr // 'winbar' + || varp == &p_tal // 'tabline' + || varp == &p_ruf // 'rulerformat' + || varp == &win->w_p_stc) { // 'statuscolumn' did_set_statusline(win, varp, gvarp, &errmsg); - } else if (gvarp == &p_cpt) { // 'complete' + } else if (gvarp == &p_cpt) { // 'complete' did_set_complete(varp, errbuf, errbuflen, &errmsg); - } else if (varp == &p_cot) { // 'completeopt' + } else if (varp == &p_cot) { // 'completeopt' did_set_completeopt(&errmsg); #ifdef BACKSLASH_IN_FILENAME - } else if (gvarp == &p_csl) { // 'completeslash' - if (check_opt_strings(p_csl, p_csl_values, false) != OK - || check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) { - errmsg = e_invarg; - } + } else if (gvarp == &p_csl) { // 'completeslash' + did_set_completeslash(buf, &errmsg); #endif - } else if (varp == &win->w_p_scl) { // 'signcolumn' + } else if (varp == &win->w_p_scl) { // 'signcolumn' did_set_signcolumn(win, varp, oldval, &errmsg); - } else if (varp == &p_sloc) { // 'showcmdloc' + } else if (varp == &p_sloc) { // 'showcmdloc' did_set_opt_strings(*varp, p_sloc_values, false, &errmsg); - } else if (varp == &win->w_p_fdc - || varp == &win->w_allbuf_opt.wo_fdc) { - // 'foldcolumn' + } else if (gvarp == &win->w_allbuf_opt.wo_fdc) { // 'foldcolumn' did_set_foldcolumn(varp, &errmsg); - } else if (varp == &p_pt) { // 'pastetoggle' + } else if (varp == &p_pt) { // 'pastetoggle' did_set_pastetoggle(); - } else if (varp == &p_bs) { // 'backspace' + } else if (varp == &p_bs) { // 'backspace' did_set_backspace(&errmsg); } else if (varp == &p_bo) { did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true, &errmsg); - } else if (gvarp == &p_tc) { // 'tagcase' + } else if (gvarp == &p_tc) { // 'tagcase' did_set_tagcase(buf, opt_flags, &errmsg); - } else if (varp == &p_cmp) { // 'casemap' + } else if (varp == &p_cmp) { // 'casemap' did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true, &errmsg); - } else if (varp == &p_dip) { // 'diffopt' + } else if (varp == &p_dip) { // 'diffopt' did_set_diffopt(&errmsg); - } else if (gvarp == &win->w_allbuf_opt.wo_fdm) { // 'foldmethod' + } else if (gvarp == &win->w_allbuf_opt.wo_fdm) { // 'foldmethod' did_set_foldmethod(win, varp, &errmsg); - } else if (gvarp == &win->w_allbuf_opt.wo_fmr) { // 'foldmarker' + } else if (gvarp == &win->w_allbuf_opt.wo_fmr) { // 'foldmarker' did_set_foldmarker(win, varp, &errmsg); - } else if (gvarp == &p_cms) { // 'commentstring' + } else if (gvarp == &p_cms) { // 'commentstring' did_set_commentstring(varp, &errmsg); - } else if (varp == &p_fdo) { // 'foldopen' + } else if (varp == &p_fdo) { // 'foldopen' did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true, &errmsg); - } else if (varp == &p_fcl) { // 'foldclose' + } else if (varp == &p_fcl) { // 'foldclose' did_set_opt_strings(*varp, p_fcl_values, true, &errmsg); - } else if (gvarp == &win->w_allbuf_opt.wo_fdi) { // 'foldignore' + } else if (gvarp == &win->w_allbuf_opt.wo_fdi) { // 'foldignore' did_set_foldignore(win); - } else if (gvarp == &p_ve) { // 'virtualedit' + } else if (gvarp == &p_ve) { // 'virtualedit' did_set_virtualedit(win, opt_flags, oldval, &errmsg); - } else if (gvarp == &p_cino) { // 'cinoptions' + } else if (gvarp == &p_cino) { // 'cinoptions' // TODO(vim): recognize errors parse_cino(buf); - } else if (gvarp == &p_lop) { // 'lispoptions' + } else if (gvarp == &p_lop) { // 'lispoptions' did_set_lispoptions(varp, &errmsg); - } else if (varp == &p_icm) { // 'inccommand' + } else if (varp == &p_icm) { // 'inccommand' did_set_opt_strings(*varp, p_icm_values, false, &errmsg); - } else if (gvarp == &p_ft || gvarp == &p_syn) { + } else if (gvarp == &p_ft // 'filetype' + || gvarp == &p_syn) { // 'syntax' did_set_filetype_or_syntax(varp, oldval, value_checked, &value_changed, &errmsg); - } else if (varp == &win->w_p_winhl) { + } else if (varp == &win->w_p_winhl) { // 'winhighlight' did_set_winhl(win, &errmsg); } else if (varp == &p_tpf) { did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true, &errmsg); - } else if (varp == &buf->b_p_vsts) { // 'varsofttabstop' + } else if (varp == &buf->b_p_vsts) { // 'varsofttabstop' did_set_varsoftabstop(buf, varp, &errmsg); - } else if (varp == &buf->b_p_vts) { // 'vartabstop' + } else if (varp == &buf->b_p_vts) { // 'vartabstop' did_set_vartabstop(buf, win, varp, &errmsg); - } else if (varp == &p_dex // 'diffexpr' - || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr' - || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext' - || gvarp == &p_fex // 'formatexpr' - || gvarp == &p_inex // 'includeexpr' - || gvarp == &p_inde // 'indentexpr' - || varp == &p_pex // 'patchexpr' - || varp == &p_ccv) { // 'charconvert' + } else if (varp == &p_dex // 'diffexpr' + || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr' + || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext' + || gvarp == &p_fex // 'formatexpr' + || gvarp == &p_inex // 'includeexpr' + || gvarp == &p_inde // 'indentexpr' + || varp == &p_pex // 'patchexpr' + || varp == &p_ccv) { // 'charconvert' did_set_optexpr(varp); if (varp == &win->w_p_fde && foldmethodIsExpr(win)) { foldUpdateAll(win); } - } else if (gvarp == &p_cfu) { // 'completefunc' + } else if (gvarp == &p_cfu) { // 'completefunc' set_completefunc_option(&errmsg); - } else if (gvarp == &p_ofu) { // 'omnifunc' + } else if (gvarp == &p_ofu) { // 'omnifunc' set_omnifunc_option(buf, &errmsg); - } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc' + } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc' set_thesaurusfunc_option(&errmsg); - } else if (varp == &p_opfunc) { // 'operatorfunc' + } else if (varp == &p_opfunc) { // 'operatorfunc' set_operatorfunc_option(&errmsg); - } else if (varp == &p_qftf) { // 'quickfixtextfunc' + } else if (varp == &p_qftf) { // 'quickfixtextfunc' qf_process_qftf_option(&errmsg); - } else if (gvarp == &p_tfu) { // 'tagfunc' + } else if (gvarp == &p_tfu) { // 'tagfunc' set_tagfunc_option(&errmsg); - } else if (varp == &p_ww) { // 'whichwrap' + } else if (varp == &p_ww) { // 'whichwrap' did_set_option_listflag(varp, WW_ALL, errbuf, errbuflen, &errmsg); - } else if (varp == &p_shm) { // 'shortmess' + } else if (varp == &p_shm) { // 'shortmess' did_set_option_listflag(varp, SHM_ALL, errbuf, errbuflen, &errmsg); - } else if (varp == &p_cpo) { // 'cpoptions' + } else if (varp == &p_cpo) { // 'cpoptions' did_set_option_listflag(varp, CPO_VI, errbuf, errbuflen, &errmsg); - } else if (varp == &buf->b_p_fo) { // 'formatoptions' + } else if (varp == &buf->b_p_fo) { // 'formatoptions' did_set_option_listflag(varp, FO_ALL, errbuf, errbuflen, &errmsg); - } else if (varp == &win->w_p_cocu) { // 'concealcursor' + } else if (varp == &win->w_p_cocu) { // 'concealcursor' did_set_option_listflag(varp, COCU_ALL, errbuf, errbuflen, &errmsg); - } else if (varp == &p_mouse) { // 'mouse' + } else if (varp == &p_mouse) { // 'mouse' did_set_option_listflag(varp, MOUSE_ALL, errbuf, errbuflen, &errmsg); - } else if (gvarp == &p_flp) { + } else if (gvarp == &p_flp) { // 'formatlistpat' if (win->w_briopt_list) { // Changing Formatlistpattern when briopt includes the list setting: // redraw @@ -1853,7 +1863,7 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char } } - // If error detected, restore the previous value. + // If an error is detected, restore the previous value. if (errmsg != NULL) { free_string_option(*varp); *varp = oldval; @@ -1890,7 +1900,7 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char } else if (varp == &buf->b_p_ft) { do_filetype_autocmd(buf, varp, opt_flags, value_changed); } else if (varp == &win->w_s->b_p_spl) { - did_set_spelllang_source(win); + do_spelllang_source(win); } } -- cgit From 7880eeb2ee9d4a0d3eeeec58c8af9a144c8d5e77 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 1 Feb 2023 08:21:32 +0800 Subject: vim-patch:9.0.1270: crash when using search stat in narrow screen (#22078) Problem: Crash when using search stat in narrow screen. Solution: Check length of message. (closes vim/vim#11921) https://github.com/vim/vim/commit/a7d36b732070944aab614944075ec0b409311482 --- src/nvim/search.c | 7 ++++++- src/nvim/testdir/test_search_stat.vim | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/search.c b/src/nvim/search.c index b24b6ad27c..eb5cc2e07f 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -2644,7 +2644,12 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh len += 2; } - memmove(msgbuf + strlen(msgbuf) - len, t, len); + size_t msgbuf_len = strlen(msgbuf); + if (len > msgbuf_len) { + len = msgbuf_len; + } + memmove(msgbuf + msgbuf_len - len, t, len); + if (dirc == '?' && stat.cur == maxcount + 1) { stat.cur = -1; } diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim index 77bd50ada2..1b2d854829 100644 --- a/src/nvim/testdir/test_search_stat.vim +++ b/src/nvim/testdir/test_search_stat.vim @@ -270,6 +270,29 @@ func Test_searchcount_fails() call assert_fails('echo searchcount({"pos" : [1, 2, []]})', 'E745:') endfunc +func Test_search_stat_narrow_screen() + " This used to crash Vim + let save_columns = &columns + try + let after =<< trim [CODE] + set laststatus=2 + set columns=16 + set shortmess-=S showcmd + call setline(1, 'abc') + call feedkeys("/abc\:quit!\") + autocmd VimLeavePre * call writefile(["done"], "Xdone") + [CODE] + + if !RunVim([], after, '--clean') + return + endif + call assert_equal("done", readfile("Xdone")[0]) + call delete('Xdone') + finally + let &columns = save_columns + endtry +endfunc + func Test_searchcount_in_statusline() CheckScreendump -- cgit From d63ad600e0571ccf07eed1e841e8519da7d4af9f Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 1 Feb 2023 10:08:50 +0100 Subject: vim-patch:9.0.1268: .clangd and .stylelintrc files don't get a filetype (#22079) Problem: .clangd and .stylelintrc files don't get a filetype. Solution: Use yaml for .clangd and json for .stylelintrc files. (Mark Skelton, closes vim/vim#11916) https://github.com/vim/vim/commit/9c51798a1f3b79ace5ae0551a8bb122025ac94ed Co-authored-by: Mark Skelton --- src/nvim/testdir/test_filetype.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index e366fd23ad..88c25ab115 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -295,7 +295,7 @@ let s:filename_checks = { \ 'jq': ['file.jq'], \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'], - \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.prettierrc', '.firebaserc', 'file.slnf'], + \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.prettierrc', '.firebaserc', '.stylelintrc', 'file.slnf'], \ 'json5': ['file.json5'], \ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json'], \ 'jsonnet': ['file.jsonnet', 'file.libsonnet'], @@ -657,7 +657,7 @@ let s:filename_checks = { \ 'xsd': ['file.xsd'], \ 'xslt': ['file.xsl', 'file.xslt'], \ 'yacc': ['file.yy', 'file.yxx', 'file.y++'], - \ 'yaml': ['file.yaml', 'file.yml', '.clang-format', '.clang-tidy'], + \ 'yaml': ['file.yaml', 'file.yml', '.clangd', '.clang-format', '.clang-tidy'], \ 'yang': ['file.yang'], \ 'z8a': ['file.z8a'], \ 'zig': ['file.zig'], -- cgit From 01d3a64e284749ac1ae40b0caf7165155063fc4f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 1 Feb 2023 18:07:09 +0800 Subject: vim-patch:8.1.1827: allocating more memory than needed for extended structs (#22081) Problem: Allocating more memory than needed for extended structs. Solution: Use offsetof() instead of sizeof(). (Dominique Pelle, closes vim/vim#4786) https://github.com/vim/vim/commit/47ed553fd5bebfc36eb8aa81686eeaa5a84eccac --- src/nvim/getchar.c | 2 +- src/nvim/regexp_bt.c | 2 +- src/nvim/sign.c | 2 +- src/nvim/sign_defs.h | 6 +++--- src/nvim/syntax.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 51554fea22..8ed9381bca 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -252,7 +252,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } else { len = (size_t)slen; } - buffblock_T *p = xmalloc(sizeof(buffblock_T) + len); + buffblock_T *p = xmalloc(offsetof(buffblock_T, b_str) + len + 1); buf->bh_space = len - (size_t)slen; xstrlcpy(p->b_str, s, (size_t)slen + 1); diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c index 1b32447d77..af3d93f7c4 100644 --- a/src/nvim/regexp_bt.c +++ b/src/nvim/regexp_bt.c @@ -2862,7 +2862,7 @@ static regprog_T *bt_regcomp(uint8_t *expr, int re_flags) } // Allocate space. - bt_regprog_T *r = xmalloc(sizeof(bt_regprog_T) + (size_t)regsize); + bt_regprog_T *r = xmalloc(offsetof(bt_regprog_T, program) + (size_t)regsize); r->re_in_use = false; // Second pass: emit code. diff --git a/src/nvim/sign.c b/src/nvim/sign.c index d0c093d93a..00e282b76e 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -103,7 +103,7 @@ static signgroup_T *sign_group_ref(const char *groupname) hi = hash_lookup(&sg_table, (char *)groupname, strlen(groupname), hash); if (HASHITEM_EMPTY(hi)) { // new group - group = xmalloc(sizeof(signgroup_T) + strlen(groupname)); + group = xmalloc(offsetof(signgroup_T, sg_name) + strlen(groupname) + 1); STRCPY(group->sg_name, groupname); group->sg_refcount = 1; diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h index 16e783aab7..7aa06ce48a 100644 --- a/src/nvim/sign_defs.h +++ b/src/nvim/sign_defs.h @@ -10,9 +10,9 @@ // Sign group typedef struct signgroup_S { - uint16_t sg_refcount; // number of signs in this group - int sg_next_sign_id; // next sign id for this group - char sg_name[1]; // sign group name + int sg_next_sign_id; ///< next sign id for this group + uint16_t sg_refcount; ///< number of signs in this group + char sg_name[1]; ///< sign group name, actually longer } signgroup_T; // Macros to get the sign group structure from the group name diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 05c570e52f..49b63ad324 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -3736,7 +3736,7 @@ static void add_keyword(char *const name, const int id, const int flags, sizeof(name_folded)) : name; - keyentry_T *const kp = xmalloc(sizeof(keyentry_T) + strlen(name_ic)); + keyentry_T *const kp = xmalloc(offsetof(keyentry_T, keyword) + strlen(name_ic) + 1); STRCPY(kp->keyword, name_ic); kp->k_syn.id = (int16_t)id; kp->k_syn.inc_tag = current_syn_inc_tag; -- cgit From 4cc0d6b854b44c0b8466e0a84bbc9e350cda8c4f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 1 Feb 2023 21:53:32 +0800 Subject: vim-patch:9.0.1271: using sizeof() and subtract array size is tricky (#22087) Problem: Using sizeof() and subtract array size is tricky. Solution: Use offsetof() instead. (closes vim/vim#11926) https://github.com/vim/vim/commit/1b438a8228a415720efb5ca1c0503f5467292e8e --- src/nvim/eval/vars.c | 2 +- src/nvim/file_search.c | 2 +- src/nvim/memline.c | 5 +++-- src/nvim/message.c | 2 +- src/nvim/regexp_nfa.c | 2 +- src/nvim/spell.c | 2 +- src/nvim/spellfile.c | 2 +- src/nvim/spellsuggest.c | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 3e593151fc..9ed245d6c4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -1347,7 +1347,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, // Make sure dict is valid assert(dict != NULL); - v = xmalloc(sizeof(dictitem_T) + strlen(varname)); + v = xmalloc(offsetof(dictitem_T, di_key) + strlen(varname) + 1); STRCPY(v->di_key, varname); if (hash_add(ht, (char *)v->di_key) == FAIL) { xfree(v); diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index e236f23895..a0435afd65 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1092,7 +1092,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p } // New file/dir. Add it to the list of visited files/dirs. - vp = xmalloc(sizeof(ff_visited_T) + strlen(ff_expand_buffer)); + vp = xmalloc(offsetof(ff_visited_T, ffv_fname) + strlen(ff_expand_buffer) + 1); if (!url) { vp->file_id_valid = true; diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 10a8195e7a..b3fc64a68c 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -149,7 +149,7 @@ struct data_block { #define DB_INDEX_MASK (~DB_MARKED) #define INDEX_SIZE (sizeof(unsigned)) // size of one db_index entry -#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) // size of data block header +#define HEADER_SIZE (offsetof(DATA_BL, db_index)) // size of data block header enum { B0_FNAME_SIZE_ORG = 900, // what it was in older versions @@ -2720,7 +2720,8 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp) PTR_BL *pp = hp->bh_data; pp->pb_id = PTR_ID; pp->pb_count = 0; - pp->pb_count_max = (uint16_t)((mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1); + pp->pb_count_max + = (uint16_t)((mfp->mf_page_size - offsetof(PTR_BL, pb_pointer)) / sizeof(PTR_EN)); return hp; } diff --git a/src/nvim/message.c b/src/nvim/message.c index 7f29b19031..3b3dfcd5b6 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2514,7 +2514,7 @@ static void store_sb_text(char **sb_str, char *s, int attr, int *sb_col, int fin } if (s > *sb_str) { - mp = xmalloc((sizeof(msgchunk_T) + (size_t)(s - *sb_str))); + mp = xmalloc(offsetof(msgchunk_T, sb_text) + (size_t)(s - *sb_str) + 1); mp->sb_eol = (char)finish; mp->sb_msg_col = *sb_col; mp->sb_attr = attr; diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 93b03f0632..ea59e7d464 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -7511,7 +7511,7 @@ static regprog_T *nfa_regcomp(uint8_t *expr, int re_flags) post2nfa(postfix, post_ptr, true); // allocate the regprog with space for the compiled regexp - size_t prog_size = sizeof(nfa_regprog_T) + sizeof(nfa_state_T) * (size_t)(nstate - 1); + size_t prog_size = offsetof(nfa_regprog_T, state) + sizeof(nfa_state_T) * (size_t)nstate; prog = xmalloc(prog_size); state_ptr = prog->state; prog->re_in_use = false; diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 8e18be5bd1..2204cda169 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1745,7 +1745,7 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count) const size_t p_len = strlen(p); hashitem_T *hi = hash_lookup(&lp->sl_wordcount, (const char *)p, p_len, hash); if (HASHITEM_EMPTY(hi)) { - wc = xmalloc(sizeof(wordcount_T) + p_len); + 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, (char *)wc->wc_word, hash); diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 44414ca1a5..7b124ae6b6 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -3855,7 +3855,7 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align) if (bl == NULL || (size_t)bl->sb_used + len > SBLOCKSIZE) { // Allocate a block of memory. It is not freed until much later. - bl = xcalloc(1, (sizeof(sblock_T) + SBLOCKSIZE)); + bl = xcalloc(1, offsetof(sblock_T, sb_data) + SBLOCKSIZE + 1); bl->sb_next = spin->si_blocks; spin->si_blocks = bl; bl->sb_used = 0; diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index 22add418a0..54b6f552b5 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -2828,7 +2828,7 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T hi = hash_lookup(&slang->sl_sounddone, (const char *)goodword, goodword_len, hash); if (HASHITEM_EMPTY(hi)) { - sft = xmalloc(sizeof(sftword_T) + goodword_len); + sft = xmalloc(offsetof(sftword_T, sft_word) + goodword_len + 1); sft->sft_score = (int16_t)score; memcpy(sft->sft_word, goodword, goodword_len + 1); hash_add_item(&slang->sl_sounddone, hi, (char *)sft->sft_word, hash); -- cgit From fa35d3c33a74123a3a3374566652161d3ad6ee5c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 2 Feb 2023 08:05:15 +0800 Subject: vim-patch:9.0.1273: "1v" may select block with wrong size (#22092) Problem: "1v" may select block with wrong size. (Evgeni Chasnovski) Solution: Compute "curswant" in the right line. (closes vim/vim#11925) https://github.com/vim/vim/commit/8f531662e28c37560bf5ac20a059bf00d01ee5a4 Co-authored-by: Bram Moolenaar --- src/nvim/normal.c | 4 ++++ src/nvim/testdir/test_visual.vim | 11 +++++++++++ 2 files changed, 15 insertions(+) (limited to 'src') diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 58a18ca5a8..b88cfb8926 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -5072,9 +5072,13 @@ static void nv_visual(cmdarg_T *cap) curwin->w_curswant = MAXCOL; coladvance(MAXCOL); } else if (VIsual_mode == Ctrl_V) { + // Update curswant on the original line, that is where "col" is valid. + linenr_T lnum = curwin->w_cursor.lnum; + curwin->w_cursor.lnum = VIsual.lnum; update_curswant_force(); assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX); curwin->w_curswant += resel_VIsual_vcol * (int)cap->count0 - 1; + curwin->w_cursor.lnum = lnum; coladvance(curwin->w_curswant); } else { curwin->w_set_curswant = true; diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index 14d62089cf..1e9629c2c4 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1319,6 +1319,17 @@ func Test_visual_block_with_substitute() endfunc func Test_visual_reselect_with_count() + enew + call setline(1, ['aaaaaa', '✗ bbbb', '✗ bbbb']) + exe "normal! 2Gw\jed" + exe "normal! gg0lP" + call assert_equal(['abbbbaaaaa', '✗bbbb ', '✗ '], getline(1, '$')) + + exe "normal! 1vr." + call assert_equal(['a....aaaaa', '✗.... ', '✗ '], getline(1, '$')) + + bwipe! + " this was causing an illegal memory access let lines =<< trim END -- cgit From ecc1595c7b81987ca9d6265d1e08ef37a05c95bf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Feb 2023 08:07:11 +0800 Subject: version.c: update [skip ci] (#21306) Co-authored-by: marvim N/A patches: vim-patch:9.0.1272: typo in pattern for filetype detection --- src/nvim/version.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/version.c b/src/nvim/version.c index 11f1d6695e..3324ac2a94 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -795,7 +795,7 @@ static const int included_patches[] = { 1702, 1701, // 1700, - // 1699, + 1699, 1698, 1697, 1696, @@ -1361,7 +1361,7 @@ static const int included_patches[] = { // 1136, 1135, 1134, - // 1133, + 1133, 1132, 1131, 1130, @@ -1674,7 +1674,7 @@ static const int included_patches[] = { 823, 822, 821, - // 820, + 820, 819, 818, 817, -- cgit From 2c5906b55bb6092121f4d3b032d5449da7675c2b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 2 Feb 2023 10:05:03 +0800 Subject: fix(exit): skip unnecessary steps in TUI preserve_exit() (#21897) This prevents the TUI from doing unexpected things when receiving a deadly signal or running out of memory. --- src/nvim/main.c | 5 +++++ src/nvim/tui/tui.c | 3 +++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index 8df82c710a..e26922bf8e 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -811,6 +811,11 @@ void preserve_exit(void) really_exiting = true; // Ignore SIGHUP while we are already exiting. #9274 signal_reject_deadly(); + + if (ui_client_channel_id) { + os_exit(1); + } + os_errmsg(IObuff); os_errmsg("\n"); ui_flush(); diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index a50e44f7a3..ceda3b2076 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -458,6 +458,9 @@ static void tui_terminal_stop(TUIData *tui) void tui_stop(TUIData *tui) { + if (tui->stopped) { + return; + } tui_terminal_stop(tui); stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) tinput_destroy(&tui->input); -- cgit From 64fa75a86a9e2e301e884e21911d71688fc8f122 Mon Sep 17 00:00:00 2001 From: luukvbaal <31730729+luukvbaal@users.noreply.github.com> Date: Thu, 2 Feb 2023 10:35:51 +0100 Subject: fix(column): estimate 'statuscolumn' width appropriately Problem: The 'statuscolumn' width is being estimated without the proper context. In particular, this resulted in the fact that a custom fold column could be included in the estimated `number_width()`, and doubly added when actually drawing the statuscolumn due to `win_col_off()` also adding the `'foldcolumn'` width. Resulting in a status column that is `'foldcolumn'` cells wider than necessary. Solution: Estimate 'statuscolumn' width in `get_statuscol_str()` when a buffer's line count has changed. --- src/nvim/buffer_defs.h | 1 + src/nvim/drawline.c | 13 ++++++++++++- src/nvim/screen.c | 11 +++-------- 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index f01edd1ad2..4c99191170 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1392,6 +1392,7 @@ struct window_S { int w_prev_fraction_row; linenr_T w_nrwidth_line_count; // line count when ml_nrwidth_width was computed. + linenr_T w_statuscol_line_count; // line count when 'statuscolumn' width was computed. int w_nrwidth_width; // nr of chars to print line count. qf_info_T *w_llist; // Location list for this window diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index e24d86b353..01ff207c2b 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -412,7 +412,6 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, i bool use_cul = use_cursor_line_sign(wp, lnum); int virtnum = row - startrow - filler_lines; - set_vim_var_nr(VV_VIRTNUM, virtnum); // When called the first time for line "lnum" set num_attr if (stcp->num_attr == 0) { stcp->num_attr = sign_num_attr ? sign_num_attr @@ -437,6 +436,18 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, i } stcp->sign_text[i] = NULL; + // When a buffer's line count has changed, make a best estimate for the full + // width of the status column by building with "w_nrwidth_line_count". Add + // potentially truncated width and rebuild before drawing anything. + if (wp->w_statuscol_line_count != wp->w_nrwidth_line_count) { + wp->w_statuscol_line_count = wp->w_nrwidth_line_count; + set_vim_var_nr(VV_VIRTNUM, 0); + build_statuscol_str(wp, wp->w_nrwidth_line_count, 0, stcp->width, + ' ', stcp->text, &stcp->hlrec, stcp); + stcp->width += stcp->truncate; + } + set_vim_var_nr(VV_VIRTNUM, virtnum); + int width = build_statuscol_str(wp, lnum, relnum, stcp->width, ' ', stcp->text, &stcp->hlrec, stcp); // Force a redraw in case of error or when truncated diff --git a/src/nvim/screen.c b/src/nvim/screen.c index ebff52cd69..05da6e0ef1 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -768,7 +768,6 @@ void comp_col(void) /// Otherwise it depends on 'numberwidth' and the line count. int number_width(win_T *wp) { - int n; linenr_T lnum; if (wp->w_p_rnu && !wp->w_p_nu) { @@ -784,17 +783,13 @@ int number_width(win_T *wp) } wp->w_nrwidth_line_count = lnum; - // make best estimate for 'statuscolumn' + // reset for 'statuscolumn' if (*wp->w_p_stc != NUL) { - char buf[MAXPATHL]; - wp->w_nrwidth_width = 0; - n = build_statuscol_str(wp, lnum, 0, 0, NUL, buf, NULL, NULL); - n = MAX(n, (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw); - wp->w_nrwidth_width = MIN(n, MAX_NUMBERWIDTH); + wp->w_nrwidth_width = (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw; return wp->w_nrwidth_width; } - n = 0; + int n = 0; do { lnum /= 10; n++; -- cgit From b02eeb6a7281df0561a021d7ae595c84be9a01be Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 2 Feb 2023 13:21:44 +0000 Subject: fix(lua): mark some eval functions that can run in API-fast --- src/nvim/eval.lua | 68 +++++++++++++++++++++++++++---------------------------- src/nvim/os/fs.c | 6 +---- 2 files changed, 35 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index c17a44b990..9a5ab51c71 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -26,7 +26,7 @@ return { acos={args=1, base=1, float_func="acos"}, -- WJMc add={args=2, base=1}, ['and']={args=2, base=1}, - api_info={}, + api_info={fast=true}, append={args=2, base=2}, appendbufline={args=3, base=3}, argc={args={0, 1}}, @@ -64,14 +64,14 @@ return { bufwinid={args=1, base=1}, bufwinnr={args=1, base=1}, byte2line={args=1, base=1}, - byteidx={args=2, base=1}, - byteidxcomp={args=2, base=1}, + byteidx={args=2, base=1, fast=true}, + byteidxcomp={args=2, base=1, fast=true}, call={args={2, 3}, base=1}, ceil={args=1, base=1, float_func="ceil"}, changenr={}, chanclose={args={1, 2}}, chansend={args=2}, - char2nr={args={1, 2}, base=1}, + char2nr={args={1, 2}, base=1, fast=true}, charclass={args=1, base=1}, charcol={args={1, 2}, base=1}, charidx={args={2, 3}, base=1}, @@ -100,7 +100,7 @@ return { deletebufline={args={2,3}, base=1}, dictwatcheradd={args=3}, dictwatcherdel={args=3}, - did_filetype={}, + did_filetype={fast=true}, diff_filler={args=1, base=1}, diff_hlID={args=2, base=1}, digraph_get={args=1, base=1}, @@ -108,11 +108,11 @@ return { digraph_set={args=2, base=1}, digraph_setlist={args=1, base=1}, empty={args=1, base=1}, - environ={}, - escape={args=2, base=1}, + environ={fast=true}, + escape={args=2, base=1, fast=true}, eval={args=1, base=1}, eventhandler={}, - executable={args=1, base=1}, + executable={args=1, base=1, fast=true}, execute={args={1, 2}, base=1}, exepath={args=1, base=1}, exists={args=1, base=1}, @@ -122,8 +122,8 @@ return { extend={args={2, 3}, base=1}, feedkeys={args={1, 2}, base=1}, file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete - filereadable={args=1, base=1}, - filewritable={args=1, base=1}, + filereadable={args=1, base=1, fast=true}, + filewritable={args=1, base=1, fast=true}, filter={args=2, base=1}, finddir={args={1, 3}, base=1}, findfile={args={1, 3}, base=1}, @@ -131,8 +131,8 @@ return { float2nr={args=1, base=1}, floor={args=1, base=1, float_func="floor"}, fmod={args=2, base=1}, - fnameescape={args=1, base=1}, - fnamemodify={args=2, base=1}, + fnameescape={args=1, base=1, fast=true}, + fnamemodify={args=2, base=1, fast=true}, foldclosed={args=1, base=1}, foldclosedend={args=1, base=1}, foldlevel={args=1, base=1}, @@ -167,17 +167,17 @@ return { getcwd={args={0, 2}, base=1}, getenv={args=1, base=1}, getfontname={args={0, 1}}, - getfperm={args=1, base=1}, - getfsize={args=1, base=1}, - getftime={args=1, base=1}, - getftype={args=1, base=1}, + getfperm={args=1, base=1, fast=true}, + getfsize={args=1, base=1, fast=true}, + getftime={args=1, base=1, fast=true}, + getftype={args=1, base=1, fast=true}, getjumplist={args={0, 2}, base=1}, getline={args={1, 2}, base=1}, getloclist={args={1, 2}}, getmarklist={args={0, 1}, base=1}, getmatches={args={0, 1}}, getmousepos={}, - getpid={}, + getpid={fast=true}, getpos={args=1, base=1}, getqflist={args={0, 1}}, getreg={args={0, 3}, base=1}, @@ -208,7 +208,7 @@ return { histnr={args=1, base=1}, hlID={args=1, base=1}, hlexists={args=1, base=1}, - hostname={}, + hostname={fast=true}, iconv={args=3, base=1, fast=true}, indent={args=1, base=1}, index={args={2, 4}, base=1}, @@ -221,7 +221,7 @@ return { insert={args={2, 3}, base=1}, interrupt={args=0}, invert={args=1, base=1}, - isdirectory={args=1, base=1}, + isdirectory={args=1, base=1, fast=true}, isinf={args=1, base=1}, islocked={args=1, base=1}, isnan={args=1, base=1}, @@ -300,13 +300,13 @@ return { reg_executing={}, reg_recording={}, reg_recorded={}, - reltime={args={0, 2}, base=1}, - reltimefloat={args=1, base=1}, - reltimestr={args=1, base=1}, + reltime={args={0, 2}, base=1, fast=true}, + reltimefloat={args=1, base=1, fast=true}, + reltimestr={args=1, base=1, fast=true}, remove={args={2, 3}, base=1}, rename={args=2, base=1}, - ['repeat']={args=2, base=1}, - resolve={args=1, base=1}, + ['repeat']={args=2, base=1, fast=true}, + resolve={args=1, base=1, fast=true}, reverse={args=1, base=1}, round={args=1, base=1, float_func="round"}, rpcnotify={args=varargs(2)}, @@ -374,24 +374,24 @@ return { split={args={1, 3}, base=1}, sqrt={args=1, base=1, float_func="sqrt"}, srand={args={0, 1}, base=1}, - stdpath={args=1}, + stdpath={args=1, fast=true}, str2float={args=1, base=1}, str2list={args={1, 2}, base=1}, str2nr={args={1, 3}, base=1}, strcharlen={args=1, base=1}, - strcharpart={args={2, 3}, base=1}, + strcharpart={args={2, 3}, base=1, fast=true}, strchars={args={1, 2}, base=1}, strdisplaywidth={args={1, 2}, base=1}, strftime={args={1, 2}, base=1}, strgetchar={args=2, base=1}, - stridx={args={2, 3}, base=1}, + stridx={args={2, 3}, base=1, fast=true}, string={args=1, base=1}, strlen={args=1, base=1}, - strpart={args={2, 4}, base=1}, + strpart={args={2, 4}, base=1, fast=true}, strptime={args=2, base=1}, strridx={args={2, 3}, base=1}, - strtrans={args=1, base=1}, - strwidth={args=1, base=1}, + strtrans={args=1, base=1, fast=true}, + strwidth={args=1, base=1, fast=true}, submatch={args={1, 2}, base=1}, substitute={args=4, base=1}, swapinfo={args=1, base=1}, @@ -419,12 +419,12 @@ return { timer_start={args={2, 3}, base=1}, timer_stop={args=1, base=1}, timer_stopall={args=0}, - tolower={args=1, base=1}, - toupper={args=1, base=1}, + tolower={args=1, base=1, fast=true}, + toupper={args=1, base=1, fast=true}, tr={args=3, base=1}, trim={args={1, 3}, base=1}, trunc={args=1, base=1, float_func="trunc"}, - type={args=1, base=1}, + type={args=1, base=1, fast=true}, undofile={args=1, base=1}, undotree={}, uniq={args={1, 3}, base=1}, @@ -447,7 +447,7 @@ return { win_splitmove={args={2, 3}, base=1}, winbufnr={args=1, base=1}, wincol={}, - windowsversion={}, + windowsversion={fast=true}, winheight={args=1, base=1}, winlayout={args={0, 1}, base=1}, winline={}, diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 302faa8140..6157341ec9 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -146,11 +146,7 @@ bool os_isdir(const char *name) return false; } - if (!S_ISDIR(mode)) { - return false; - } - - return true; + return S_ISDIR(mode); } /// Check what `name` is: -- cgit From d3355ad01c3b9d1dbc62210c29d8e51245f081aa Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 2 Feb 2023 22:42:15 +0800 Subject: fix(tui): detach/attach on suspend/resume (#22040) Problem: When a TUI client is suspended it still receives UI events from the server, and has to process these accumulated events when it is resumed. With mulitple TUI clients this is a bigger problem, considering the following steps: 1. A TUI client is attached. 2. CTRL-Z is pressed and the first client is suspended. 3. Another TUI client is attached. 4. CTRL-Z is pressed and a "suspend" event is sent to both clients. The second client is suspended, while the first client isn't able to process the event because it has already been suspended. 5. The first client is resumed. It processes the accumulated "suspend" event and suspends immediately. Solution: Make a TUI client detach on suspend and re-attach on resume. --- src/nvim/tui/tui.c | 2 ++ src/nvim/ui_client.c | 29 +++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index ceda3b2076..f760e99262 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1347,6 +1347,7 @@ static void show_verbose_terminfo(TUIData *tui) static void suspend_event(void **argv) { TUIData *tui = argv[0]; + ui_client_detach(); bool enable_mouse = tui->mouse_enabled; tui_terminal_stop(tui); stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) @@ -1359,6 +1360,7 @@ static void suspend_event(void **argv) tui_mouse_on(tui); } stream_set_blocking(tui->input.in_fd, false); // libuv expects this + ui_client_attach(tui->width, tui->height, tui->term); } #endif diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index 378c0e4831..b5c8dff412 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -23,6 +23,7 @@ #include "nvim/ui_client.h" static TUIData *tui = NULL; +static bool ui_client_is_remote = false; // uncrustify:off #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -66,13 +67,8 @@ uint64_t ui_client_start_server(int argc, char **argv) return channel->id; } -void ui_client_run(bool remote_ui) - FUNC_ATTR_NORETURN +void ui_client_attach(int width, int height, char *term) { - int width, height; - char *term; - tui = tui_start(&width, &height, &term); - MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, INTEGER_OBJ(width)); ADD_C(args, INTEGER_OBJ(height)); @@ -82,14 +78,14 @@ void ui_client_run(bool remote_ui) PUT_C(opts, "ext_linegrid", BOOLEAN_OBJ(true)); PUT_C(opts, "ext_termcolors", BOOLEAN_OBJ(true)); if (term) { - PUT(opts, "term_name", STRING_OBJ(cstr_to_string(term))); + PUT_C(opts, "term_name", STRING_OBJ(cstr_as_string(term))); } if (ui_client_bg_response != kNone) { bool is_dark = (ui_client_bg_response == kTrue); PUT_C(opts, "term_background", STRING_OBJ(cstr_as_string(is_dark ? "dark" : "light"))); } PUT_C(opts, "term_colors", INTEGER_OBJ(t_colors)); - if (!remote_ui) { + if (!ui_client_is_remote) { PUT_C(opts, "stdin_tty", BOOLEAN_OBJ(stdin_isatty)); PUT_C(opts, "stdout_tty", BOOLEAN_OBJ(stdout_isatty)); if (ui_client_forward_stdin) { @@ -100,6 +96,23 @@ void ui_client_run(bool remote_ui) rpc_send_event(ui_client_channel_id, "nvim_ui_attach", args); ui_client_attached = true; +} + +void ui_client_detach(void) +{ + rpc_send_event(ui_client_channel_id, "nvim_ui_detach", (Array)ARRAY_DICT_INIT); + ui_client_attached = false; +} + +void ui_client_run(bool remote_ui) + FUNC_ATTR_NORETURN +{ + ui_client_is_remote = remote_ui; + int width, height; + char *term; + tui = tui_start(&width, &height, &term); + + ui_client_attach(width, height, term); // os_exit() will be invoked when the client channel detaches while (true) { -- cgit From c05b3c3bbdef4018ce70f0c822c4a55654a9c186 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 2 Feb 2023 17:26:22 +0100 Subject: vim-patch:9.0.1274: FIRRTL files are not recognized (#22102) Problem: FIRRTL files are not recognized. Solution: Add a pattern for FIRRTL files. (Amaan Qureshi, closes vim/vim#11931) https://github.com/vim/vim/commit/685bf83b73d0fe6fd36bb2949bebd6aae66a139e Co-authored-by: Amaan Qureshi --- src/nvim/testdir/test_filetype.vim | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 88c25ab115..7b5ec22dd4 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -199,6 +199,7 @@ let s:filename_checks = { \ 'fennel': ['file.fnl'], \ 'fetchmail': ['.fetchmailrc'], \ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'], + \ 'firrtl': ['file.fir'], \ 'fish': ['file.fish'], \ 'focexec': ['file.fex', 'file.focexec'], \ 'form': ['file.frm'], -- cgit From 0bd07bea095a8000cffa4f379c1fa53e009c1143 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Thu, 2 Feb 2023 18:52:52 +0000 Subject: feat(TextPutPost): add TextPutPost autocommand Adds a new autocommand, TextPutPost. This autocommand fires when the user puts text with p or P. The motivating feature for this change was to implement a plugin that "carries" Java imports between files. I.e. yanking from one java file and pasting into another would automatically add the imports required. --- src/nvim/auevents.lua | 1 + src/nvim/ops.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) (limited to 'src') diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index a75ee3bbd5..fb0062e524 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -110,6 +110,7 @@ return { 'TextChangedP', -- text was modified in Insert mode(popup) 'TextChangedT', -- text was modified in Terminal mode 'TextYankPost', -- after a yank or delete was done (y, d, c) + 'TextPutPost', -- after a put was done (p, P) 'UIEnter', -- after UI attaches 'UILeave', -- after UI detaches 'User', -- user defined autocommand diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 435ca106ab..cb56cb7027 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -2910,6 +2910,56 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) recursive = false; } +/// Execute autocommands for TextPutPost. +/// +/// @param oap Operator arguments. +/// @param reg The yank register used. +static void do_autocmd_textputpost(int regname, yankreg_T *reg) + FUNC_ATTR_NONNULL_ALL +{ + static bool recursive = false; + int len; + + if (recursive || !has_event(EVENT_TEXTPUTPOST)) { + // No autocommand was defined, or we yanked from this autocommand. + return; + } + + recursive = true; + + save_v_event_T save_v_event; + // Set the v:event dictionary with information about the yank. + dict_T *dict = get_v_event(&save_v_event); + + // The yanked text contents. + list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size); + for (size_t i = 0; i < reg->y_size; i++) { + tv_list_append_string(list, (const char *)reg->y_array[i], -1); + } + tv_list_set_lock(list, VAR_FIXED); + (void)tv_dict_add_list(dict, S_LEN("regcontents"), list); + + // Register type. + char buf[NUMBUFLEN + 6]; + format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf)); + (void)tv_dict_add_str(dict, S_LEN("regtype"), buf); + + // Name of requested register, or empty string for unnamed operation. + len = (*utf_char2len)(regname); + buf[len] = 0; + utf_char2bytes(regname, buf); + recursive = true; + (void)tv_dict_add_str(dict, S_LEN("regname"), buf); + + tv_dict_set_keys_readonly(dict); + textlock++; + apply_autocmds(EVENT_TEXTPUTPOST, NULL, NULL, false, curbuf); + textlock--; + restore_v_event(dict, &save_v_event); + + recursive = false; +} + /// Put contents of register "regname" into the text. /// Caller must check "regname" to be valid! /// @@ -3693,6 +3743,8 @@ error: curwin->w_set_curswant = true; end: + do_autocmd_textputpost(regname, reg); + if (cmdmod.cmod_flags & CMOD_LOCKMARKS) { curbuf->b_op_start = orig_start; curbuf->b_op_end = orig_end; -- cgit