From 3ea45a2caf23ac1c335d04c0a3b2b2aa254d3d96 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Jul 2022 16:56:11 +0800 Subject: vim-patch:8.2.1469: Vim9: cannot assign string to string option Problem: Vim9: cannot assign string to string option. Solution: Change checks for option value. (closes vim/vim#6720) https://github.com/vim/vim/commit/0aae4809fd52b445531766411a9c963dc6274a04 --- src/nvim/eval/vars.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index e56ccef02b..edc112109a 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -619,24 +619,32 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo && vim_strchr(endchars, *skipwhite(p)) == NULL)) { emsg(_(e_letunexp)); } else { + varnumber_T n = 0; int opt_type; long numval; char *stringval = NULL; const char *s = NULL; + bool failed = false; const char c1 = *p; *p = NUL; - varnumber_T n = tv_get_number(tv); + opt_type = get_option_value(arg, &numval, &stringval, opt_flags); + if (opt_type == 1 || opt_type == -1) { + // number, possibly hidden + n = (long)tv_get_number(tv); + } + + // Avoid setting a string option to the text "v:false" or similar. if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) { - s = tv_get_string_chk(tv); // != NULL if number or string. + s = tv_get_string_chk(tv); } - if (s != NULL && op != NULL && *op != '=') { - opt_type = get_option_value(arg, &numval, &stringval, opt_flags); + + if (op != NULL && *op != '=') { if ((opt_type == 1 && *op == '.') || (opt_type == 0 && *op != '.')) { semsg(_(e_letwrong), op); - s = NULL; // don't set the value + failed = true; // don't set the value } else { if (opt_type == 1) { // number switch (*op) { @@ -651,7 +659,8 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo case '%': n = num_modulus(numval, n); break; } - } else if (opt_type == 0 && stringval != NULL) { // string + } else if (opt_type == 0 && stringval != NULL && s != NULL) { + // string char *const oldstringval = stringval; stringval = (char *)concat_str((const char_u *)stringval, (const char_u *)s); @@ -660,10 +669,14 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo } } } - if (s != NULL || tv->v_type == VAR_BOOL - || tv->v_type == VAR_SPECIAL) { - set_option_value((const char *)arg, n, s, opt_flags); - arg_end = p; + + if (!failed) { + if (opt_type != 0 || s != NULL) { + set_option_value(arg, n, s, opt_flags); + arg_end = p; + } else { + emsg(_(e_stringreq)); + } } *p = c1; xfree(stringval); -- cgit From 2241fd3211012e5eba3479d64e190f206c12087e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Jul 2022 17:37:06 +0800 Subject: vim-patch:8.2.2254: Vim9: bool option type is number Problem: Vim9: bool option type is number. Solution: Have get_option_value() return a different value for bool and number options. (closes vim/vim#7583) https://github.com/vim/vim/commit/dd1f426bd617ac6a775f2e7795ff0b159e3fa315 --- src/nvim/api/options.c | 20 ++++++++++---------- src/nvim/eval.c | 14 ++++++++------ src/nvim/eval/vars.c | 18 +++++++++++------- src/nvim/option.c | 45 ++++++++++++++++++++++----------------------- src/nvim/option.h | 11 +++++++++++ src/nvim/spell.c | 2 +- 6 files changed, 63 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 4ed676e613..5c9eba163b 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -104,20 +104,20 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) long numval = 0; char *stringval = NULL; - int result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type, from, - true, err); + getoption_T result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type, + from, true, err); if (ERROR_SET(err)) { return rv; } switch (result) { - case 0: + case gov_string: rv = STRING_OBJ(cstr_as_string(stringval)); break; - case 1: + case gov_number: rv = INTEGER_OBJ(numval); break; - case 2: + case gov_bool: switch (numval) { case 0: case 1: @@ -483,8 +483,8 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object }); } -static int access_option_value(char *key, long *numval, char **stringval, int opt_flags, bool get, - Error *err) +static getoption_T access_option_value(char *key, long *numval, char **stringval, int opt_flags, + bool get, Error *err) { if (get) { return get_option_value(key, numval, stringval, opt_flags); @@ -501,13 +501,13 @@ static int access_option_value(char *key, long *numval, char **stringval, int op } } -static int access_option_value_for(char *key, long *numval, char **stringval, int opt_flags, - int opt_type, void *from, bool get, Error *err) +static getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags, + int opt_type, void *from, bool get, Error *err) { bool need_switch = false; switchwin_T switchwin; aco_save_T aco; - int result = 0; + getoption_T result = 0; try_start(); switch (opt_type) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7b2a20e6fb..9c27ec16f3 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3774,7 +3774,7 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval { long numval; char *stringval; - int opt_type; + getoption_T opt_type; bool working = (**arg == '+'); // has("+option") int ret = OK; int opt_flags; @@ -3798,26 +3798,28 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval opt_type = get_option_value(*arg, &numval, rettv == NULL ? NULL : &stringval, opt_flags); - if (opt_type == -3) { // invalid name + if (opt_type == gov_unknown) { if (rettv != NULL) { semsg(_("E113: Unknown option: %s"), *arg); } ret = FAIL; } else if (rettv != NULL) { - if (opt_type == -2) { // hidden string option + if (opt_type == gov_hidden_string) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - } else if (opt_type == -1) { // hidden number option + } else if (opt_type == gov_hidden_bool || opt_type == gov_hidden_number) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; - } else if (opt_type == 1 || opt_type == 2) { // number or boolean option + } else if (opt_type == gov_bool || opt_type == gov_number) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = numval; } else { // string option rettv->v_type = VAR_STRING; rettv->vval.v_string = stringval; } - } else if (working && (opt_type == -2 || opt_type == -1)) { + } else if (working && (opt_type == gov_hidden_bool + || opt_type == gov_hidden_number + || opt_type == gov_hidden_string)) { ret = FAIL; } diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index edc112109a..091e3f87c4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -620,7 +620,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo emsg(_(e_letunexp)); } else { varnumber_T n = 0; - int opt_type; + getoption_T opt_type; long numval; char *stringval = NULL; const char *s = NULL; @@ -630,7 +630,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo *p = NUL; opt_type = get_option_value(arg, &numval, &stringval, opt_flags); - if (opt_type == 1 || opt_type == -1) { + if (opt_type == gov_bool + || opt_type == gov_number + || opt_type == gov_hidden_bool + || opt_type == gov_hidden_number) { // number, possibly hidden n = (long)tv_get_number(tv); } @@ -641,12 +644,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo } if (op != NULL && *op != '=') { - if ((opt_type == 1 && *op == '.') - || (opt_type == 0 && *op != '.')) { + if (((opt_type == gov_bool || opt_type == gov_number) && *op == '.') + || (opt_type == gov_string && *op != '.')) { semsg(_(e_letwrong), op); failed = true; // don't set the value } else { - if (opt_type == 1) { // number + // number or bool + if (opt_type == gov_number || opt_type == gov_bool) { switch (*op) { case '+': n = numval + n; break; @@ -659,7 +663,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo case '%': n = num_modulus(numval, n); break; } - } else if (opt_type == 0 && stringval != NULL && s != NULL) { + } else if (opt_type == gov_string && stringval != NULL && s != NULL) { // string char *const oldstringval = stringval; stringval = (char *)concat_str((const char_u *)stringval, @@ -671,7 +675,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo } if (!failed) { - if (opt_type != 0 || s != NULL) { + if (opt_type != gov_string || s != NULL) { set_option_value(arg, n, s, opt_flags); arg_end = p; } else { diff --git a/src/nvim/option.c b/src/nvim/option.c index bb3881b809..ea4c7080b7 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5046,28 +5046,29 @@ static int findoption(const char *const arg) /// @param stringval NULL when only checking existence /// /// @returns: -/// Toggle option: 2, *numval gets value. -/// Number option: 1, *numval gets value. -/// String option: 0, *stringval gets allocated string. -/// Hidden Number or Toggle option: -1. -/// hidden String option: -2. -/// unknown option: -3. -int get_option_value(const char *name, long *numval, char **stringval, int opt_flags) +/// Number option: gov_number, *numval gets value. +/// Tottle option: gov_bool, *numval gets value. +/// String option: gov_string, *stringval gets allocated string. +/// Hidden Number option: gov_hidden_number. +/// Hidden Toggle option: gov_hidden_bool. +/// Hidden String option: gov_hidden_string. +/// Unknown option: gov_unknown. +getoption_T get_option_value(const char *name, long *numval, char **stringval, int opt_flags) { if (get_tty_option(name, stringval)) { - return 0; + return gov_string; } int opt_idx = findoption(name); - if (opt_idx < 0) { // Unknown option. - return -3; + if (opt_idx < 0) { // option not in the table + return gov_unknown; } char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags); if (options[opt_idx].flags & P_STRING) { if (varp == NULL) { // hidden option - return -2; + return gov_hidden_string; } if (stringval != NULL) { if ((char_u **)varp == &p_pt) { // 'pastetoggle' @@ -5076,26 +5077,24 @@ int get_option_value(const char *name, long *numval, char **stringval, int opt_f *stringval = xstrdup(*(char **)(varp)); } } - return 0; + return gov_string; } if (varp == NULL) { // hidden option - return -1; + return (options[opt_idx].flags & P_NUM) ? gov_hidden_number : gov_hidden_bool; } if (options[opt_idx].flags & P_NUM) { *numval = *(long *)varp; - return 1; - } - - // Special case: 'modified' is b_changed, but we also want to consider - // it set when 'ff' or 'fenc' changed. - if ((int *)varp == &curbuf->b_changed) { - *numval = curbufIsChanged(); } else { - *numval = (long)*(int *)varp; // NOLINT(whitespace/cast) + // Special case: 'modified' is b_changed, but we also want to consider + // it set when 'ff' or 'fenc' changed. + if ((int *)varp == &curbuf->b_changed) { + *numval = curbufIsChanged(); + } else { + *numval = (long)(*(int *)varp); + } } - - return 2; + return (options[opt_idx].flags & P_NUM) ? gov_number : gov_bool; } // Returns the option attributes and its value. Unlike the above function it diff --git a/src/nvim/option.h b/src/nvim/option.h index 9321dd5454..a5a57cc66d 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -3,6 +3,17 @@ #include "nvim/ex_cmds_defs.h" // for exarg_T +/// Returned by get_option_value(). +typedef enum { + gov_unknown, + gov_bool, + gov_number, + gov_string, + gov_hidden_bool, + gov_hidden_number, + gov_hidden_string, +} getoption_T; + // flags for buf_copy_options() #define BCO_ENTER 1 // going to enter the buffer #define BCO_ALWAYS 2 // always copy the options diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 8bc9cda247..948e935907 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -6880,7 +6880,7 @@ void ex_spelldump(exarg_T *eap) if (no_spell_checking(curwin)) { return; } - get_option_value("spl", &dummy, &spl, OPT_LOCAL); + (void)get_option_value("spl", &dummy, &spl, OPT_LOCAL); // Create a new empty buffer in a new window. do_cmdline_cmd("new"); -- cgit From 8921035fc762d39f42f1b644a19a78d36fbda87a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Jul 2022 17:17:20 +0800 Subject: vim-patch:8.2.2284: Vim9: cannot set an option to a boolean value Problem: Vim9: cannot set an option to a boolean value. Solution: Check for VAR_BOOL. (closes vim/vim#7603) https://github.com/vim/vim/commit/31a201a04aa95708af5d62070d2d397a201cc1a5 --- src/nvim/eval/vars.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 091e3f87c4..40a3707060 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -1564,10 +1564,17 @@ static void getwinvar(typval_T *argvars, typval_T *rettv, int off) /// Set option "varname" to the value of "varp" for the current buffer/window. static void set_option_from_tv(const char *varname, typval_T *varp) { + long numval = 0; + const char *strval; bool error = false; char nbuf[NUMBUFLEN]; - const long numval = (long)tv_get_number_chk(varp, &error); - const char *const strval = tv_get_string_buf_chk(varp, nbuf); + + if (varp->v_type == VAR_BOOL) { + numval = (long)varp->vval.v_number; + } else { + numval = (long)tv_get_number_chk(varp, &error); + } + strval = tv_get_string_buf_chk(varp, nbuf); if (!error && strval != NULL) { set_option_value(varname, numval, strval, OPT_LOCAL); } -- cgit From 963ea726daf3e19279f8e24b48116f11f1921c7d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Jul 2022 17:20:23 +0800 Subject: vim-patch:8.2.2285: Vim9: cannot set an option to a false Problem: Vim9: cannot set an option to a false. Solution: For VAR_BOOL use string "0". (closes vim/vim#7603) https://github.com/vim/vim/commit/b0d8182fa39f2c9403f5f9a0663589fcab43a6c8 --- src/nvim/eval/vars.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 40a3707060..a0141402bc 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -1571,10 +1571,11 @@ static void set_option_from_tv(const char *varname, typval_T *varp) if (varp->v_type == VAR_BOOL) { numval = (long)varp->vval.v_number; + strval = "0"; // avoid using "false" } else { numval = (long)tv_get_number_chk(varp, &error); + strval = tv_get_string_buf_chk(varp, nbuf); } - strval = tv_get_string_buf_chk(varp, nbuf); if (!error && strval != NULL) { set_option_value(varname, numval, strval, OPT_LOCAL); } -- cgit From d8df9afad62a9a4beb4ec607f8e10d674de66dbe Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Jul 2022 18:11:37 +0800 Subject: vim-patch:8.2.2969: subtracting from number option fails when result is zero Problem: Subtracting from number option fails when result is zero. (Ingo Karkat) Solution: Reset the string value when using the numeric value. (closes vim/vim#8351) https://github.com/vim/vim/commit/a42e6e0082a6d564dbfa55317d4a698ac12ae898 Cherry-pick Test_compound_assignment_operators() changes from patch 8.2.1593 --- src/nvim/eval/vars.c | 1 + src/nvim/testdir/test_vimscript.vim | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index a0141402bc..152d1c3e00 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -663,6 +663,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo case '%': n = num_modulus(numval, n); break; } + s = NULL; } else if (opt_type == gov_string && stringval != NULL && s != NULL) { // string char *const oldstringval = stringval; diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 1323288676..de4629451b 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1661,16 +1661,25 @@ func Test_compound_assignment_operators() call assert_equal(6, &scrolljump) let &scrolljump %= 5 call assert_equal(1, &scrolljump) - call assert_fails('let &scrolljump .= "j"', 'E734') + call assert_fails('let &scrolljump .= "j"', 'E734:') set scrolljump&vim + let &foldlevelstart = 2 + let &foldlevelstart -= 1 + call assert_equal(1, &foldlevelstart) + let &foldlevelstart -= 1 + call assert_equal(0, &foldlevelstart) + let &foldlevelstart = 2 + let &foldlevelstart -= 2 + call assert_equal(0, &foldlevelstart) + " Test for register let @/ = 1 - call assert_fails('let @/ += 1', 'E734') - call assert_fails('let @/ -= 1', 'E734') - call assert_fails('let @/ *= 1', 'E734') - call assert_fails('let @/ /= 1', 'E734') - call assert_fails('let @/ %= 1', 'E734') + call assert_fails('let @/ += 1', 'E734:') + call assert_fails('let @/ -= 1', 'E734:') + call assert_fails('let @/ *= 1', 'E734:') + call assert_fails('let @/ /= 1', 'E734:') + call assert_fails('let @/ %= 1', 'E734:') let @/ .= 's' call assert_equal('1s', @/) let @/ = '' -- cgit From aba3147cb62339714633b53f9ba114b08c5d6761 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Jul 2022 17:21:55 +0800 Subject: vim-patch:8.2.4228: no tests for clicking in the GUI tabline Problem: No tests for clicking in the GUI tabline. Solution: Add test functions to generate the events. Add tests using the functions. (Yegappan Lakshmanan, closes vim/vim#9638) https://github.com/vim/vim/commit/b0ad2d92fd19e673ddbbc66742bae3f71778efde --- src/nvim/normal.c | 3 ++- src/nvim/testdir/test_diffmode.vim | 46 ++++++++++++++++++++++++++++++++++++++ src/nvim/testdir/test_normal.vim | 3 ++- 3 files changed, 50 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/normal.c b/src/nvim/normal.c index a842bb20a9..64bc868cb5 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3485,7 +3485,8 @@ void scroll_redraw(int up, long count) redraw_later(curwin, VALID); } -/// Get the count specified after a 'z' command. +/// Get the count specified after a 'z' command. Only the 'z', 'zl', 'zh', +/// 'z', and 'z' commands accept a count after 'z'. /// @return true to process the 'z' command and false to skip it. static bool nv_z_get_count(cmdarg_T *cap, int *nchar_arg) { diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 8c20c647f1..007b7e0f14 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -1332,4 +1332,50 @@ func Test_diff_binary() set diffopt&vim endfunc +" Test for using the 'zi' command to invert 'foldenable' in diff windows (test +" for the issue fixed by patch 6.2.317) +func Test_diff_foldinvert() + %bw! + edit Xfile1 + new Xfile2 + new Xfile3 + windo diffthis + " open a non-diff window + botright new + 1wincmd w + call assert_true(getwinvar(1, '&foldenable')) + call assert_true(getwinvar(2, '&foldenable')) + call assert_true(getwinvar(3, '&foldenable')) + normal zi + call assert_false(getwinvar(1, '&foldenable')) + call assert_false(getwinvar(2, '&foldenable')) + call assert_false(getwinvar(3, '&foldenable')) + normal zi + call assert_true(getwinvar(1, '&foldenable')) + call assert_true(getwinvar(2, '&foldenable')) + call assert_true(getwinvar(3, '&foldenable')) + + " If the current window has 'noscrollbind', then 'zi' should not change + " 'foldenable' in other windows. + 1wincmd w + set noscrollbind + normal zi + call assert_false(getwinvar(1, '&foldenable')) + call assert_true(getwinvar(2, '&foldenable')) + call assert_true(getwinvar(3, '&foldenable')) + + " 'zi' should not change the 'foldenable' for windows with 'noscrollbind' + 1wincmd w + set scrollbind + normal zi + call setwinvar(2, '&scrollbind', v:false) + normal zi + call assert_false(getwinvar(1, '&foldenable')) + call assert_true(getwinvar(2, '&foldenable')) + call assert_false(getwinvar(3, '&foldenable')) + + %bw! + set scrollbind& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index ffa0cd1807..f18ddb274c 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -580,6 +580,7 @@ endfunc func Test_normal_z_error() call assert_beeps('normal! z2p') call assert_beeps('normal! zq') + call assert_beeps('normal! cz1') endfunc func Test_normal15_z_scroll_vert() @@ -619,7 +620,7 @@ func Test_normal15_z_scroll_vert() call assert_equal(10, winheight(0)) exe "norm! z12\" call assert_equal(12, winheight(0)) - exe "norm! z10\" + exe "norm! z15\0\" call assert_equal(10, winheight(0)) " Test for z. -- cgit