From b54abeeafb074248597878a874fed9a66b114c06 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 2 Jun 2021 11:49:23 +0200 Subject: [PATCH 01/41] patch 8.2.2921: E704 for script local variable is not backwards compatible Problem: E704 for script local variable is not backwards compatible. (Yasuhiro Matsumoto) Solution: Only give the error in Vim9 script. Also check for function-local variable. --- src/dict.c | 5 +++-- src/testdir/test_functions.vim | 10 ++++++++-- src/version.c | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dict.c b/src/dict.c index 876eeea492..f0f045b272 100644 --- a/src/dict.c +++ b/src/dict.c @@ -352,8 +352,9 @@ dict_copy(dict_T *orig, int deep, int copyID) dict_wrong_func_name(dict_T *d, typval_T *tv, char_u *name) { return (d == get_globvar_dict() - || (SCRIPT_ID_VALID(current_sctx.sc_sid) - && d == &SCRIPT_ITEM(current_sctx.sc_sid)->sn_vars->sv_dict)) + || (in_vim9script() && SCRIPT_ID_VALID(current_sctx.sc_sid) + && d == &SCRIPT_ITEM(current_sctx.sc_sid)->sn_vars->sv_dict) + || &d->dv_hashtab == get_funccal_local_ht()) && (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) && var_wrong_func_name(name, TRUE); } diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index f945e9064e..bc96491726 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -4,6 +4,7 @@ source shared.vim source check.vim source term_util.vim source screendump.vim +source vim9.vim " Must be done first, since the alternate buffer must be unset. func Test_00_bufexists() @@ -2684,8 +2685,13 @@ endfunc func Test_builtin_check() call assert_fails('let g:["trim"] = {x -> " " .. x}', 'E704:') call assert_fails('let g:.trim = {x -> " " .. x}', 'E704:') - call assert_fails('let s:["trim"] = {x -> " " .. x}', 'E704:') - call assert_fails('let s:.trim = {x -> " " .. x}', 'E704:') + call assert_fails('let l:["trim"] = {x -> " " .. x}', 'E704:') + call assert_fails('let l:.trim = {x -> " " .. x}', 'E704:') + let lines =<< trim END + vim9script + var s:trim = (x) => " " .. x + END + call CheckScriptFailure(lines, 'E704:') call assert_fails('call extend(g:, #{foo: { -> "foo" }})', 'E704:') let g:bar = 123 diff --git a/src/version.c b/src/version.c index 1c01adb222..321047f56b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2921, /**/ 2920, /**/ From eeec2548785b2dd245a31ab25d7bde0f88ea1a6d Mon Sep 17 00:00:00 2001 From: "K.Takata" Date: Wed, 2 Jun 2021 13:28:16 +0200 Subject: [PATCH 02/41] patch 8.2.2922: computing array length is done in various ways Problem: Computing array length is done in various ways. Solution: Use ARRAY_LENGTH everywhere. (Ken Takata, closes #8305) --- src/arabic.c | 4 +--- src/blowfish.c | 2 -- src/cindent.c | 2 +- src/cmdexpand.c | 2 +- src/cmdhist.c | 2 +- src/dosinst.c | 5 ++--- src/eval.c | 2 +- src/evalfunc.c | 4 ++-- src/ex_docmd.c | 6 +++--- src/fileio.c | 2 +- src/gui_athena.c | 2 +- src/gui_gtk_x11.c | 6 +++--- src/gui_haiku.cc | 2 +- src/gui_photon.c | 1 - src/gui_w32.c | 4 ++-- src/gui_xmebw.c | 2 +- src/hardcopy.c | 26 ++++++++++++-------------- src/help.c | 2 +- src/highlight.c | 4 ++-- src/if_mzsch.c | 2 +- src/macros.h | 3 +++ src/main.c | 6 +++--- src/map.c | 5 ++--- src/mbyte.c | 6 +++--- src/memline.c | 2 +- src/menu.c | 2 +- src/misc2.c | 3 +-- src/normal.c | 2 +- src/ops.c | 2 +- src/option.c | 5 ++--- src/optiondefs.h | 2 +- src/os_win32.c | 11 +++++------ src/popupwin.c | 6 ++---- src/quickfix.c | 2 +- src/regexp.c | 2 +- src/screen.c | 4 ++-- src/search.c | 2 +- src/syntax.c | 2 +- src/term.c | 2 +- src/terminal.c | 2 +- src/time.c | 3 +-- src/usercmd.c | 4 ++-- src/version.c | 10 ++++++---- 43 files changed, 80 insertions(+), 90 deletions(-) diff --git a/src/arabic.c b/src/arabic.c index efc6aa66db..f64dab2499 100644 --- a/src/arabic.c +++ b/src/arabic.c @@ -163,8 +163,6 @@ static struct achar { #define a_BYTE_ORDER_MARK 0xfeff -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - /* * Find the struct achar pointer to the given Arabic char. * Returns NULL if not found. @@ -175,7 +173,7 @@ find_achar(int c) int h, m, l; // using binary search to find c - h = ARRAY_SIZE(achars); + h = ARRAY_LENGTH(achars); l = 0; while (l < h) { diff --git a/src/blowfish.c b/src/blowfish.c index 74d8e5416f..342bcc406e 100644 --- a/src/blowfish.c +++ b/src/blowfish.c @@ -23,8 +23,6 @@ #if defined(FEAT_CRYPT) || defined(PROTO) -#define ARRAY_LENGTH(A) (sizeof(A)/sizeof(A[0])) - #define BF_BLOCK 8 #define BF_BLOCK_MASK 7 #define BF_MAX_CFB_LEN (8 * BF_BLOCK) diff --git a/src/cindent.c b/src/cindent.c index b2fac1a9fb..ce02402c22 100644 --- a/src/cindent.c +++ b/src/cindent.c @@ -718,7 +718,7 @@ cin_isinit(void) { int i, l; - for (i = 0; i < (int)(sizeof(skip) / sizeof(char *)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(skip); ++i) { l = (int)strlen(skip[i]); if (cin_starts_with(s, skip[i])) diff --git a/src/cmdexpand.c b/src/cmdexpand.c index 280b9e415c..c5b8f70585 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -2155,7 +2155,7 @@ ExpandFromContext( // Find a context in the table and call the ExpandGeneric() with the // right function to do the expansion. ret = FAIL; - for (i = 0; i < (int)(sizeof(tab) / sizeof(struct expgen)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(tab); ++i) if (xp->xp_context == tab[i].context) { if (tab[i].ic) diff --git a/src/cmdhist.c b/src/cmdhist.c index 1e7ae34034..8bb3cb61c7 100644 --- a/src/cmdhist.c +++ b/src/cmdhist.c @@ -98,7 +98,7 @@ get_history_arg(expand_T *xp UNUSED, int idx) static char_u compl[2] = { NUL, NUL }; char *short_names = ":=@>?/"; int short_names_count = (int)STRLEN(short_names); - int history_name_count = sizeof(history_names) / sizeof(char *) - 1; + int history_name_count = ARRAY_LENGTH(history_names) - 1; if (idx < short_names_count) { diff --git a/src/dosinst.c b/src/dosinst.c index 7f3a0695e7..2d2b95c10a 100644 --- a/src/dosinst.c +++ b/src/dosinst.c @@ -59,7 +59,7 @@ struct choice struct choice choices[30]; // choices the user can make int choice_count = 0; // number of choices available -#define TABLE_SIZE(s) (int)(sizeof(s) / sizeof(*s)) +#define TABLE_SIZE(s) (int)ARRAYSIZE(s) enum { @@ -1527,8 +1527,7 @@ register_openwith( "*\\OpenWithList\\gvim.exe", }; - for (i = 0; ERROR_SUCCESS == lRet - && i < sizeof(openwith) / sizeof(openwith[0]); i++) + for (i = 0; ERROR_SUCCESS == lRet && i < ARRAYSIZE(openwith); i++) lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag); } diff --git a/src/eval.c b/src/eval.c index 7a05d359ba..1ee4a3dbcd 100644 --- a/src/eval.c +++ b/src/eval.c @@ -125,7 +125,7 @@ compare_func_name(const void *s1, const void *s2) static void sortFunctions(void) { - int funcCnt = (int)(sizeof(functions) / sizeof(struct fst)) - 1; + int funcCnt = (int)ARRAY_LENGTH(functions) - 1; qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name); } diff --git a/src/evalfunc.c b/src/evalfunc.c index 16447aba25..fcb64f67ac 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1877,7 +1877,7 @@ get_function_name(expand_T *xp, int idx) return name; } } - if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T))) + if (++intidx < (int)ARRAY_LENGTH(global_functions)) { STRCPY(IObuff, global_functions[intidx].f_name); STRCAT(IObuff, "("); @@ -1923,7 +1923,7 @@ find_internal_func_opt(char_u *name, int implemented) int cmp; int x; - last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1; + last = (int)ARRAY_LENGTH(global_functions) - 1; // Find the function name in the table. Binary search. while (first <= last) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 9c8eba558a..fbf2c7d0dd 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -3735,7 +3735,7 @@ modifier_len(char_u *cmd) if (VIM_ISDIGIT(*cmd)) p = skipwhite(skipdigits(cmd + 1)); - for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(cmdmods); ++i) { for (j = 0; p[j] != NUL; ++j) if (p[j] != cmdmods[i].name[j]) @@ -3762,7 +3762,7 @@ cmd_exists(char_u *name) char_u *p; // Check command modifiers. - for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(cmdmods); ++i) { for (j = 0; name[j] != NUL; ++j) if (name[j] != cmdmods[i].name[j]) @@ -8732,7 +8732,7 @@ find_cmdline_var(char_u *src, int *usedlen) #endif }; - for (i = 0; i < (int)(sizeof(spec_str) / sizeof(char *)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(spec_str); ++i) { len = (int)STRLEN(spec_str[i]); if (STRNCMP(src, spec_str[i], len) == 0) diff --git a/src/fileio.c b/src/fileio.c index b59c01d267..91c02bfcd0 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5073,7 +5073,7 @@ vim_tempname( /* * Try the entries in TEMPDIRNAMES to create the temp directory. */ - for (i = 0; i < (int)(sizeof(tempdirs) / sizeof(char *)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(tempdirs); ++i) { # ifndef HAVE_MKDTEMP size_t itmplen; diff --git a/src/gui_athena.c b/src/gui_athena.c index 43847404a3..f4aafcd94e 100644 --- a/src/gui_athena.c +++ b/src/gui_athena.c @@ -469,7 +469,7 @@ get_toolbar_pixmap(vimmenu_T *menu, Pixmap *sen) if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL) { if (menu->iconidx >= 0 && menu->iconidx - < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0]))) + < (int)ARRAY_LENGTH(built_in_pixmaps)) xpm = built_in_pixmaps[menu->iconidx]; else xpm = tb_blank_xpm; diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 249b20877a..1a3eadad72 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -134,7 +134,7 @@ static const GtkTargetEntry selection_targets[] = {"TEXT", 0, TARGET_TEXT}, {"STRING", 0, TARGET_STRING} }; -#define N_SELECTION_TARGETS (sizeof(selection_targets) / sizeof(selection_targets[0])) +#define N_SELECTION_TARGETS ARRAY_LENGTH(selection_targets) #ifdef FEAT_DND /* @@ -149,7 +149,7 @@ static const GtkTargetEntry dnd_targets[] = {"STRING", 0, TARGET_STRING}, {"text/plain", 0, TARGET_TEXT_PLAIN} }; -# define N_DND_TARGETS (sizeof(dnd_targets) / sizeof(dnd_targets[0])) +# define N_DND_TARGETS ARRAY_LENGTH(dnd_targets) #endif @@ -6853,7 +6853,7 @@ mch_set_mouse_shape(int shape) else id &= ~1; // they are always even (why?) } - else if (shape < (int)(sizeof(mshape_ids) / sizeof(int))) + else if (shape < (int)ARRAY_LENGTH(mshape_ids)) id = mshape_ids[shape]; else return; diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc index a1c7e3eb1b..644c2db665 100644 --- a/src/gui_haiku.cc +++ b/src/gui_haiku.cc @@ -638,7 +638,7 @@ static struct specialkey {0, 0, 0} }; -#define NUM_SPECIAL_KEYS (sizeof(special_keys)/sizeof(special_keys[0])) +#define NUM_SPECIAL_KEYS ARRAY_LENGTH(special_keys) // ---------------- VimApp ---------------- diff --git a/src/gui_photon.c b/src/gui_photon.c index 12b0a3cdee..c89d781056 100644 --- a/src/gui_photon.c +++ b/src/gui_photon.c @@ -34,7 +34,6 @@ # define PhImage_t int #endif -#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a[0])) #define RGB(r, g, b) PgRGB(r, g, b) #define EVENT_BUFFER_SIZE sizeof(PhEvent_t) + 1000 diff --git a/src/gui_w32.c b/src/gui_w32.c index 80a70e25ce..c1f823e27a 100644 --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -1627,7 +1627,7 @@ gui_mch_get_color(char_u *name) /* * Try to look up a system colour. */ - for (i = 0; i < sizeof(sys_table) / sizeof(sys_table[0]); i++) + for (i = 0; i < ARRAY_LENGTH(sys_table); i++) if (STRICMP(name, sys_table[i].name) == 0) return GetSysColor(sys_table[i].color); @@ -5077,7 +5077,7 @@ error: /* * Parse the GUI related command-line arguments. Any arguments used are * deleted from argv, and *argc is decremented accordingly. This is called - * when vim is started, whether or not the GUI has been started. + * when Vim is started, whether or not the GUI has been started. */ void gui_mch_prepare(int *argc, char **argv) diff --git a/src/gui_xmebw.c b/src/gui_xmebw.c index 2c66db121b..3387fbe0b4 100644 --- a/src/gui_xmebw.c +++ b/src/gui_xmebw.c @@ -455,7 +455,7 @@ set_pixmap(XmEnhancedButtonWidget eb) attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColorKey; attr.closeness = 65535; // accuracy isn't crucial attr.colorsymbols = color; - attr.numsymbols = sizeof(color) / sizeof(color[0]); + attr.numsymbols = ARRAY_LENGTH(color); attr.color_key = XPM_MONO; status = XpmCreatePixmapFromData(dpy, root, data, &pix, &mask, &attr); diff --git a/src/hardcopy.c b/src/hardcopy.c index a6df816316..069fa43ddd 100644 --- a/src/hardcopy.c +++ b/src/hardcopy.c @@ -972,8 +972,6 @@ hardcopy_line( * http://www.adobe.com */ -#define NUM_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0])) - #define PRT_PS_DEFAULT_DPI (72) // Default user space resolution #define PRT_PS_DEFAULT_FONTSIZE (10) #define PRT_PS_DEFAULT_BUFFER_SIZE (80) @@ -985,7 +983,7 @@ struct prt_mediasize_S float height; }; -#define PRT_MEDIASIZE_LEN (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S)) +#define PRT_MEDIASIZE_LEN ARRAY_LENGTH(prt_mediasize) static struct prt_mediasize_S prt_mediasize[] = { @@ -1210,33 +1208,33 @@ struct prt_ps_mbfont_S static struct prt_ps_mbfont_S prt_ps_mbfonts[] = { { - NUM_ELEMENTS(j_encodings), + ARRAY_LENGTH(j_encodings), j_encodings, - NUM_ELEMENTS(j_charsets), + ARRAY_LENGTH(j_charsets), j_charsets, "jis_roman", "JIS_X_1983" }, { - NUM_ELEMENTS(sc_encodings), + ARRAY_LENGTH(sc_encodings), sc_encodings, - NUM_ELEMENTS(sc_charsets), + ARRAY_LENGTH(sc_charsets), sc_charsets, "gb_roman", "GB_2312-80" }, { - NUM_ELEMENTS(tc_encodings), + ARRAY_LENGTH(tc_encodings), tc_encodings, - NUM_ELEMENTS(tc_charsets), + ARRAY_LENGTH(tc_charsets), tc_charsets, "cns_roman", "BIG5" }, { - NUM_ELEMENTS(k_encodings), + ARRAY_LENGTH(k_encodings), k_encodings, - NUM_ELEMENTS(k_charsets), + ARRAY_LENGTH(k_charsets), k_charsets, "ks_roman", "KS_X_1992" @@ -1793,12 +1791,12 @@ prt_next_dsc(struct prt_dsc_line_S *p_dsc_line) return FALSE; // Find type of DSC comment - for (comment = 0; comment < (int)NUM_ELEMENTS(prt_dsc_table); comment++) + for (comment = 0; comment < (int)ARRAY_LENGTH(prt_dsc_table); comment++) if (prt_resfile_strncmp(0, prt_dsc_table[comment].string, prt_dsc_table[comment].len) == 0) break; - if (comment != NUM_ELEMENTS(prt_dsc_table)) + if (comment != ARRAY_LENGTH(prt_dsc_table)) { // Return type of comment p_dsc_line->type = prt_dsc_table[comment].type; @@ -2385,7 +2383,7 @@ mch_print_init( int cmap_first = 0; p_mbenc_first = NULL; - for (cmap = 0; cmap < (int)NUM_ELEMENTS(prt_ps_mbfonts); cmap++) + for (cmap = 0; cmap < (int)ARRAY_LENGTH(prt_ps_mbfonts); cmap++) if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap], &p_mbenc)) { diff --git a/src/help.c b/src/help.c index ee6ff18512..28d914c823 100644 --- a/src/help.c +++ b/src/help.c @@ -381,7 +381,7 @@ find_help_tags( // When the string starting with "expr-" and containing '?' and matches // the table, it is taken literally (but ~ is escaped). Otherwise '?' // is recognized as a wildcard. - for (i = (int)(sizeof(expr_table) / sizeof(char *)); --i >= 0; ) + for (i = (int)ARRAY_LENGTH(expr_table); --i >= 0; ) if (STRCMP(arg + 5, expr_table[i]) == 0) { int si = 0, di = 0; diff --git a/src/highlight.c b/src/highlight.c index 56b1988835..defbe55176 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -998,7 +998,7 @@ do_highlight( off = 0; while (arg[off] != NUL) { - for (i = sizeof(hl_attr_table) / sizeof(int); --i >= 0; ) + for (i = ARRAY_LENGTH(hl_attr_table); --i >= 0; ) { len = (int)STRLEN(hl_name_table[i]); if (STRNICMP(arg + off, hl_name_table[i], len) == 0) @@ -1168,7 +1168,7 @@ do_highlight( // reduce calls to STRICMP a bit, it can be slow off = TOUPPER_ASC(*arg); - for (i = (sizeof(color_names) / sizeof(char *)); --i >= 0; ) + for (i = ARRAY_LENGTH(color_names); --i >= 0; ) if (off == color_names[i][0] && STRICMP(arg + 1, color_names[i] + 1) == 0) break; diff --git a/src/if_mzsch.c b/src/if_mzsch.c index 58b169231b..0c1c765db5 100644 --- a/src/if_mzsch.c +++ b/src/if_mzsch.c @@ -3799,7 +3799,7 @@ make_modules(void) mod = scheme_primitive_module(vimext_symbol, environment); MZ_GC_CHECK(); // all prims made closed so they can access their own names - for (i = 0; i < (int)(sizeof(prims)/sizeof(prims[0])); i++) + for (i = 0; i < (int)ARRAY_LENGTH(prims); i++) { Vim_Prim *prim = prims + i; closed_prim = scheme_make_closed_prim_w_arity(prim->prim, prim, prim->name, diff --git a/src/macros.h b/src/macros.h index c11ee660c9..4ca24c0f5d 100644 --- a/src/macros.h +++ b/src/macros.h @@ -396,3 +396,6 @@ #ifndef MAX # define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif + +// Length of the array. +#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) diff --git a/src/main.c b/src/main.c index db8202ea7d..de94a1576b 100644 --- a/src/main.c +++ b/src/main.c @@ -645,7 +645,7 @@ vim_main2(void) #endif /* - * When done something that is not allowed or error message call + * When done something that is not allowed or given an error message call * wait_return. This must be done before starttermcap(), because it may * switch to another screen. It must be done after settmode(TMODE_RAW), * because we want to react on a single key stroke. @@ -1662,7 +1662,7 @@ getout(int exitval) { // give the user a chance to read the (error) message no_wait_return = FALSE; - wait_return(FALSE); +// wait_return(FALSE); } // Position the cursor again, the autocommands may have moved it @@ -3435,7 +3435,7 @@ usage(void) { mch_msg(_(" vim [arguments] ")); mch_msg(_(use[i])); - if (i == (sizeof(use) / sizeof(char_u *)) - 1) + if (i == ARRAY_LENGTH(use) - 1) break; mch_msg(_("\n or:")); } diff --git a/src/map.c b/src/map.c index 2e792feaa0..9923522b14 100644 --- a/src/map.c +++ b/src/map.c @@ -2478,13 +2478,12 @@ init_mappings(void) if (!gui.starting) # endif { - for (i = 0; - i < (int)(sizeof(cinitmappings) / sizeof(struct initmap)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(cinitmappings); ++i) add_map(cinitmappings[i].arg, cinitmappings[i].mode); } # endif # if defined(FEAT_GUI_MSWIN) || defined(MACOS_X) - for (i = 0; i < (int)(sizeof(initmappings) / sizeof(struct initmap)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(initmappings); ++i) add_map(initmappings[i].arg, initmappings[i].mode); # endif #endif diff --git a/src/mbyte.c b/src/mbyte.c index 697e58520f..6df3a15dee 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -2850,7 +2850,7 @@ utf_class_buf(int c, buf_T *buf) }; int bot = 0; - int top = sizeof(classes) / sizeof(struct clinterval) - 1; + int top = ARRAY_LENGTH(classes) - 1; int mid; // First quick check for Latin1 characters, use 'iskeyword'. @@ -3948,7 +3948,7 @@ utf_allow_break_before(int cc) }; int first = 0; - int last = sizeof(BOL_prohibition_punct)/sizeof(int) - 1; + int last = ARRAY_LENGTH(BOL_prohibition_punct) - 1; int mid = 0; while (first < last) @@ -3998,7 +3998,7 @@ utf_allow_break_after(int cc) }; int first = 0; - int last = sizeof(EOL_prohibition_punct)/sizeof(int) - 1; + int last = ARRAY_LENGTH(EOL_prohibition_punct) - 1; int mid = 0; while (first < last) diff --git a/src/memline.c b/src/memline.c index 5356369c16..a0b642908d 100644 --- a/src/memline.c +++ b/src/memline.c @@ -1312,7 +1312,7 @@ ml_recover(int checkext) } #ifdef FEAT_CRYPT - for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(id1_codes); ++i) if (id1_codes[i] == b0p->b0_id[1]) b0_cm = i; if (b0_cm > 0) diff --git a/src/menu.c b/src/menu.c index 4f5e26b3d6..fb4be218b5 100644 --- a/src/menu.c +++ b/src/menu.c @@ -73,7 +73,7 @@ static const char *toolbar_names[] = /* 25 */ "Make", "TagJump", "RunCtags", "WinVSplit", "WinMaxWidth", /* 30 */ "WinMinWidth", "Exit" }; -# define TOOLBAR_NAME_COUNT (sizeof(toolbar_names) / sizeof(char *)) +# define TOOLBAR_NAME_COUNT ARRAY_LENGTH(toolbar_names) #endif /* diff --git a/src/misc2.c b/src/misc2.c index 08e6ed9368..0553c2ce14 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1050,7 +1050,6 @@ free_all_mem(void) if (entered_free_all_mem) return; entered_free_all_mem = TRUE; - // Don't want to trigger autocommands from here on. block_autocmds(); @@ -2542,7 +2541,7 @@ static struct key_name_entry // NOTE: When adding a long name update MAX_KEY_NAME_LEN. }; -#define KEY_NAMES_TABLE_LEN (sizeof(key_names_table) / sizeof(struct key_name_entry)) +#define KEY_NAMES_TABLE_LEN ARRAY_LENGTH(key_names_table) /* * Return the modifier mask bit (MOD_MASK_*) which corresponds to the given diff --git a/src/normal.c b/src/normal.c index 39643bae88..cb496dd1f0 100644 --- a/src/normal.c +++ b/src/normal.c @@ -379,7 +379,7 @@ static const struct nv_cmd }; // Number of commands in nv_cmds[]. -#define NV_CMDS_SIZE (sizeof(nv_cmds) / sizeof(struct nv_cmd)) +#define NV_CMDS_SIZE ARRAY_LENGTH(nv_cmds) // Sorted index of commands in nv_cmds[]. static short nv_cmd_idx[NV_CMDS_SIZE]; diff --git a/src/ops.c b/src/ops.c index 87fb2a05b4..48d629df27 100644 --- a/src/ops.c +++ b/src/ops.c @@ -82,7 +82,7 @@ get_op_type(int char1, int char2) { if (opchars[i][0] == char1 && opchars[i][1] == char2) break; - if (i == (int)(sizeof(opchars) / sizeof(char [3]) - 1)) + if (i == (int)ARRAY_LENGTH(opchars) - 1) { internal_error("get_op_type()"); break; diff --git a/src/option.c b/src/option.c index 6ca424e12e..33d29a1fc4 100644 --- a/src/option.c +++ b/src/option.c @@ -145,7 +145,7 @@ set_init_1(int clean_arg) opt_idx = findoption((char_u *)"backupskip"); ga_init2(&ga, 1, 100); - for (n = 0; n < (long)(sizeof(names) / sizeof(char *)); ++n) + for (n = 0; n < (long)ARRAY_LENGTH(names); ++n) { mustfree = FALSE; # ifdef UNIX @@ -6317,8 +6317,7 @@ ExpandSettings( regmatch->rm_ic = ic; if (xp->xp_context != EXPAND_BOOL_SETTINGS) { - for (match = 0; match < (int)(sizeof(names) / sizeof(char *)); - ++match) + for (match = 0; match < (int)ARRAY_LENGTH(names); ++match) if (vim_regexec(regmatch, (char_u *)names[match], (colnr_T)0)) { if (loop == 0) diff --git a/src/optiondefs.h b/src/optiondefs.h index 42f355c287..782e4ef44a 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -3033,7 +3033,7 @@ static struct vimoption options[] = {NULL, NULL, 0, NULL, PV_NONE, {NULL, NULL} SCTX_INIT} }; -#define OPTION_COUNT (sizeof(options) / sizeof(struct vimoption)) +#define OPTION_COUNT ARRAY_LENGTH(options) // The following is needed to make the gen_opt_test.vim script work. // {" diff --git a/src/os_win32.c b/src/os_win32.c index c5bbc2bf2b..874a2c69d8 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -1105,7 +1105,7 @@ decode_key_event( return TRUE; } - for (i = sizeof(VirtKeyMap) / sizeof(VirtKeyMap[0]); --i >= 0; ) + for (i = ARRAY_LENGTH(VirtKeyMap); --i >= 0; ) { if (VirtKeyMap[i].wVirtKey == pker->wVirtualKeyCode) { @@ -3045,7 +3045,7 @@ mch_get_user_name( int len) { WCHAR wszUserName[256 + 1]; // UNLEN is 256 - DWORD wcch = sizeof(wszUserName) / sizeof(WCHAR); + DWORD wcch = ARRAY_LENGTH(wszUserName); if (GetUserNameW(wszUserName, &wcch)) { @@ -3072,7 +3072,7 @@ mch_get_host_name( int len) { WCHAR wszHostName[256 + 1]; - DWORD wcch = sizeof(wszHostName) / sizeof(WCHAR); + DWORD wcch = ARRAY_LENGTH(wszHostName); if (GetComputerNameW(wszHostName, &wcch)) { @@ -4757,8 +4757,7 @@ mch_call_shell( WCHAR szShellTitle[512]; // Change the title to reflect that we are in a subshell. - if (GetConsoleTitleW(szShellTitle, - sizeof(szShellTitle)/sizeof(WCHAR) - 4) > 0) + if (GetConsoleTitleW(szShellTitle, ARRAY_LENGTH(szShellTitle) - 4) > 0) { if (cmd == NULL) wcscat(szShellTitle, L" :sh"); @@ -4770,7 +4769,7 @@ mch_call_shell( { wcscat(szShellTitle, L" - !"); if ((wcslen(szShellTitle) + wcslen(wn) < - sizeof(szShellTitle)/sizeof(WCHAR))) + ARRAY_LENGTH(szShellTitle))) wcscat(szShellTitle, wn); SetConsoleTitleW(szShellTitle); vim_free(wn); diff --git a/src/popupwin.c b/src/popupwin.c index 35c4b0af5e..cd343f819d 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -402,8 +402,7 @@ get_pos_entry(dict_T *d, int give_error) if (str == NULL) return POPPOS_NONE; - for (nr = 0; nr < (int)(sizeof(poppos_entries) / sizeof(poppos_entry_T)); - ++nr) + for (nr = 0; nr < (int)ARRAY_LENGTH(poppos_entries); ++nr) if (STRCMP(str, poppos_entries[nr].pp_name) == 0) return poppos_entries[nr].pp_val; @@ -3042,8 +3041,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv) if (wp->w_close_cb.cb_name != NULL) dict_add_callback(dict, "callback", &wp->w_close_cb); - for (i = 0; i < (int)(sizeof(poppos_entries) / sizeof(poppos_entry_T)); - ++i) + for (i = 0; i < (int)ARRAY_LENGTH(poppos_entries); ++i) if (wp->w_popup_pos == poppos_entries[i].pp_val) { dict_add_string(dict, "pos", diff --git a/src/quickfix.c b/src/quickfix.c index 665641c0ff..ad07a5b4ee 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -5971,7 +5971,7 @@ vgr_match_buflines( char_u *str = ml_get_buf(buf, lnum, FALSE); int score; int_u matches[MAX_FUZZY_MATCHES]; - int_u sz = sizeof(matches) / sizeof(matches[0]); + int_u sz = ARRAY_LENGTH(matches); // Fuzzy string match while (fuzzy_match(str + col, spat, FALSE, &score, matches, sz) > 0) diff --git a/src/regexp.c b/src/regexp.c index 8c1431d3c2..805056e3e6 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -202,7 +202,7 @@ get_char_class(char_u **pp) if ((*pp)[1] == ':') { - for (i = 0; i < (int)(sizeof(class_names) / sizeof(*class_names)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(class_names); ++i) if (STRNCMP(*pp + 2, class_names[i], STRLEN(class_names[i])) == 0) { *pp += STRLEN(class_names[i]) + 2; diff --git a/src/screen.c b/src/screen.c index 9d5d4df98c..7c27e2ca42 100644 --- a/src/screen.c +++ b/src/screen.c @@ -4817,14 +4817,14 @@ set_chars_option(win_T *wp, char_u **varp) { tab = lcstab; CLEAR_FIELD(lcs_chars); - entries = sizeof(lcstab) / sizeof(struct charstab); + entries = ARRAY_LENGTH(lcstab); if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) varp = &p_lcs; } else { tab = filltab; - entries = sizeof(filltab) / sizeof(struct charstab); + entries = ARRAY_LENGTH(filltab); } // first round: check for valid value, second round: assign values diff --git a/src/search.c b/src/search.c index 24dcd5a584..bbf67d5ce0 100644 --- a/src/search.c +++ b/src/search.c @@ -4444,7 +4444,7 @@ fuzzy_match_recursive( if (fuzzy_match_recursive(fuzpat, next_char, strIdx + 1, &recursiveScore, strBegin, strLen, matches, recursiveMatches, - sizeof(recursiveMatches)/sizeof(recursiveMatches[0]), + ARRAY_LENGTH(recursiveMatches), nextMatch, recursionCount)) { // Pick best recursive score diff --git a/src/syntax.c b/src/syntax.c index c3572d8435..60c35bdce8 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -4573,7 +4573,7 @@ get_syn_options( if (strchr(first_letters, *arg) == NULL) break; - for (fidx = sizeof(flagtab) / sizeof(struct flag); --fidx >= 0; ) + for (fidx = ARRAY_LENGTH(flagtab); --fidx >= 0; ) { p = flagtab[fidx].name; for (i = 0, len = 0; p[i] != NUL; i += 2, ++len) diff --git a/src/term.c b/src/term.c index a91d2c73ea..99b33d4399 100644 --- a/src/term.c +++ b/src/term.c @@ -6725,7 +6725,7 @@ gui_get_color_cmn(char_u *name) } // Check if the name is one of the colors we know - for (i = 0; i < (int)(sizeof(rgb_table) / sizeof(rgb_table[0])); i++) + for (i = 0; i < (int)ARRAY_LENGTH(rgb_table); i++) if (STRICMP(name, rgb_table[i].color_name) == 0) return gui_adjust_rgb(rgb_table[i].color); diff --git a/src/terminal.c b/src/terminal.c index 2189d01842..e3945d03ac 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -5691,7 +5691,7 @@ f_term_getattr(typval_T *argvars, typval_T *rettv) if (attr > HL_ALL) attr = syn_attr2attr(attr); - for (i = 0; i < sizeof(attrs)/sizeof(attrs[0]); ++i) + for (i = 0; i < ARRAY_LENGTH(attrs); ++i) if (STRCMP(name, attrs[i].name) == 0) { rettv->vval.v_number = (attr & attrs[i].attr) != 0 ? 1 : 0; diff --git a/src/time.c b/src/time.c index a28708f9f8..6d4ad5d51e 100644 --- a/src/time.c +++ b/src/time.c @@ -276,8 +276,7 @@ f_strftime(typval_T *argvars, typval_T *rettv) wp = enc_to_utf16(p, NULL); if (wp != NULL) - (void)wcsftime(result_buf, sizeof(result_buf) / sizeof(WCHAR), - wp, curtime); + (void)wcsftime(result_buf, ARRAY_LENGTH(result_buf), wp, curtime); else result_buf[0] = NUL; rettv->vval.v_string = utf16_to_enc(result_buf, NULL); diff --git a/src/usercmd.c b/src/usercmd.c index 03e7b245d3..a4bbfd77cf 100644 --- a/src/usercmd.c +++ b/src/usercmd.c @@ -339,7 +339,7 @@ get_user_cmd_flags(expand_T *xp UNUSED, int idx) "count", "nargs", "range", "register" }; - if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))) + if (idx >= (int)ARRAY_LENGTH(user_cmd_flags)) return NULL; return (char_u *)user_cmd_flags[idx]; } @@ -352,7 +352,7 @@ get_user_cmd_nargs(expand_T *xp UNUSED, int idx) { static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; - if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))) + if (idx >= (int)ARRAY_LENGTH(user_cmd_nargs)) return NULL; return (char_u *)user_cmd_nargs[idx]; } diff --git a/src/version.c b/src/version.c index 321047f56b..812731417a 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2922, /**/ 2921, /**/ @@ -6627,7 +6629,7 @@ has_patch(int n) // Perform a binary search. l = 0; - h = (int)(sizeof(included_patches) / sizeof(included_patches[0])) - 1; + h = (int)ARRAY_LENGTH(included_patches) - 1; while (l < h) { m = (l + h) / 2; @@ -6854,7 +6856,7 @@ list_version(void) { msg_puts(_("\nIncluded patches: ")); first = -1; - i = (int)(sizeof(included_patches) / sizeof(included_patches[0])) - 1; + i = (int)ARRAY_LENGTH(included_patches) - 1; while (--i >= 0) { if (first < 0) @@ -7145,7 +7147,7 @@ intro_message( #endif // blanklines = screen height - # message lines - blanklines = (int)Rows - ((sizeof(lines) / sizeof(char *)) - 1); + blanklines = (int)Rows - (ARRAY_LENGTH(lines) - 1); if (!p_cp) blanklines += 4; // add 4 for not showing "Vi compatible" message @@ -7164,7 +7166,7 @@ intro_message( row = blanklines / 2; if ((row >= 2 && Columns >= 50) || colon) { - for (i = 0; i < (int)(sizeof(lines) / sizeof(char *)); ++i) + for (i = 0; i < (int)ARRAY_LENGTH(lines); ++i) { p = lines[i]; #ifdef FEAT_GUI From eecf2b35a146d7d5512f2525ad631d796e19edac Mon Sep 17 00:00:00 2001 From: "K.Takata" Date: Wed, 2 Jun 2021 14:56:39 +0200 Subject: [PATCH 03/41] patch 8.2.2923: EBCDIC build is broken Problem: EBCDIC build is broken. Solution: Move sortFunctions() to evalfunc.c. (Ken Takata, closes #8306) --- src/eval.c | 27 --------------------------- src/evalfunc.c | 27 +++++++++++++++++++++++++++ src/proto/evalfunc.pro | 2 +- src/version.c | 2 ++ 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/eval.c b/src/eval.c index 1ee4a3dbcd..e39c604ad2 100644 --- a/src/eval.c +++ b/src/eval.c @@ -104,33 +104,6 @@ num_modulus(varnumber_T n1, varnumber_T n2, int *failed) return (n2 == 0) ? 0 : (n1 % n2); } -#if defined(EBCDIC) || defined(PROTO) -/* - * Compare struct fst by function name. - */ - static int -compare_func_name(const void *s1, const void *s2) -{ - struct fst *p1 = (struct fst *)s1; - struct fst *p2 = (struct fst *)s2; - - return STRCMP(p1->f_name, p2->f_name); -} - -/* - * Sort the function table by function name. - * The sorting of the table above is ASCII dependent. - * On machines using EBCDIC we have to sort it. - */ - static void -sortFunctions(void) -{ - int funcCnt = (int)ARRAY_LENGTH(functions) - 1; - - qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name); -} -#endif - /* * Initialize the global and v: variables. */ diff --git a/src/evalfunc.c b/src/evalfunc.c index fcb64f67ac..8ea48f9bd5 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1855,6 +1855,33 @@ static funcentry_T global_functions[] = ret_number, f_xor}, }; +#if defined(EBCDIC) || defined(PROTO) +/* + * Compare funcentry_T by function name. + */ + static int +compare_func_name(const void *s1, const void *s2) +{ + funcentry_T *p1 = (funcentry_T *)s1; + funcentry_T *p2 = (funcentry_T *)s2; + + return STRCMP(p1->f_name, p2->f_name); +} + +/* + * Sort the function table by function name. + * The sorting of the table above is ASCII dependent. + * On machines using EBCDIC we have to sort it. + */ + void +sortFunctions(void) +{ + size_t funcCnt = ARRAY_LENGTH(global_functions); + + qsort(global_functions, funcCnt, sizeof(funcentry_T), compare_func_name); +} +#endif + /* * Function given to ExpandGeneric() to obtain the list of internal * or user defined function names. diff --git a/src/proto/evalfunc.pro b/src/proto/evalfunc.pro index 2b194486f6..c1ac55f5b9 100644 --- a/src/proto/evalfunc.pro +++ b/src/proto/evalfunc.pro @@ -1,4 +1,5 @@ /* evalfunc.c */ +void sortFunctions(void); char_u *get_function_name(expand_T *xp, int idx); char_u *get_expr_name(expand_T *xp, int idx); int find_internal_func(char_u *name); @@ -23,5 +24,4 @@ void range_list_materialize(list_T *list); float_T vim_round(float_T f); long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit); void f_string(typval_T *argvars, typval_T *rettv); -void f_fullcommand(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c index 812731417a..ee1dfa7191 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2923, /**/ 2922, /**/ From a2e468fcac7523ae6a0ab65db5196684801fa2d1 Mon Sep 17 00:00:00 2001 From: "K.Takata" Date: Wed, 2 Jun 2021 15:08:50 +0200 Subject: [PATCH 04/41] patch 8.2.2924: superfluous extern declaration Problem: Superfluous extern declaration. Solution: Delete the declaration. (Ken Takata, closes #8307) --- src/main.c | 2 -- src/version.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index de94a1576b..d418c13801 100644 --- a/src/main.c +++ b/src/main.c @@ -260,8 +260,6 @@ main #ifdef MSWIN { - extern void set_alist_count(void); - // Remember the number of entries in the argument list. If it changes // we don't react on setting 'encoding'. set_alist_count(); diff --git a/src/version.c b/src/version.c index ee1dfa7191..aaf27c1423 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2924, /**/ 2923, /**/ From 0f37e3561db95b0ef0b636588bbd30297e377384 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 2 Jun 2021 15:28:15 +0200 Subject: [PATCH 05/41] patch 8.2.2925: Vim9: line continuation comment uses legacy syntax Problem: Vim9: line continuation comment uses legacy syntax. Solution: Check for #\ instead of "\. (closes #8295) --- src/scriptfile.c | 3 ++- src/testdir/test_vim9_script.vim | 18 ++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/scriptfile.c b/src/scriptfile.c index 203cad09fd..15338be632 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1842,7 +1842,8 @@ getsourceline( ga_concat(&ga, p); } } - else if (!(p[0] == '"' && p[1] == '\\' && p[2] == ' ') + else if (!(p[0] == (in_vim9script() ? '#' : '"') + && p[1] == '\\' && p[2] == ' ') && !(do_vim9_all && (*p == NUL || vim9_comment_start(p)))) break; /* drop a # comment or "\ comment line */ diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index cdda613218..ee324950fe 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -3074,6 +3074,24 @@ def Test_vim9_comment() 'func Test() # comment', 'endfunc', ], 'E488:') + + var lines =<< trim END + vim9script + syn region Text + \ start='foo' + #\ comment + \ end='bar' + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + syn region Text + \ start='foo' + "\ comment + \ end='bar' + END + CheckScriptFailure(lines, 'E399:') enddef def Test_vim9_comment_gui() diff --git a/src/version.c b/src/version.c index aaf27c1423..188bb1a880 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2925, /**/ 2924, /**/ From c3cb1c92a335be818971acd89f631e82aa30ad3f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 2 Jun 2021 16:47:53 +0200 Subject: [PATCH 06/41] patch 8.2.2926: Vim9: no good error for using :legacy in a :def function Problem: Vim9: no good error for using :legacy in a :def function. Solution: Give an explicit error where :legacy is not working. (closes #8309) --- src/errors.h | 2 ++ src/testdir/test_vim9_func.vim | 9 +++++++++ src/version.c | 2 ++ src/vim9compile.c | 21 +++++++++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/src/errors.h b/src/errors.h index 00d395baea..00e2d565d0 100644 --- a/src/errors.h +++ b/src/errors.h @@ -417,3 +417,5 @@ EXTERN char e_failed_to_source_defaults[] INIT(= N_("E1187: Failed to source defaults.vim")); EXTERN char e_cannot_open_terminal_from_command_line_window[] INIT(= N_("E1188: Cannot open a terminal from the command line window")); +EXTERN char e_cannot_use_legacy_with_command_str[] + INIT(= N_("E1189: Cannot use :legacy with this command: %s")); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 3626cca47a..9f0cd3f895 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2207,6 +2207,15 @@ def Test_legacy_lambda() CheckScriptSuccess(lines) enddef +def Test_legacy_errors() + for cmd in ['if', 'elseif', 'else', 'endif', + 'for', 'endfor', 'continue', 'break', + 'while', 'endwhile', + 'try', 'catch', 'finally', 'endtry'] + CheckDefFailure(['legacy ' .. cmd .. ' expr'], 'E1189:') + endfor +enddef + def DoFilterThis(a: string): list # closure nested inside another closure using argument var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0) diff --git a/src/version.c b/src/version.c index 188bb1a880..6761b72d8e 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2926, /**/ 2925, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 2ea487de78..5152b61a5f 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -9222,6 +9222,27 @@ compile_def_function( { char_u *start = ea.cmd; + switch (ea.cmdidx) + { + case CMD_if: + case CMD_elseif: + case CMD_else: + case CMD_endif: + case CMD_for: + case CMD_endfor: + case CMD_continue: + case CMD_break: + case CMD_while: + case CMD_endwhile: + case CMD_try: + case CMD_catch: + case CMD_finally: + case CMD_endtry: + semsg(_(e_cannot_use_legacy_with_command_str), ea.cmd); + goto erret; + default: break; + } + // ":legacy return expr" needs to be handled differently. if (checkforcmd(&start, "return", 4)) ea.cmdidx = CMD_return; From a83d06026d0e0dad873de296bff97707ad2faff3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 2 Jun 2021 16:49:32 +0200 Subject: [PATCH 07/41] patch 8.2.2927: test commented out because it fails with ASAN Problem: Test commented out because it fails with ASAN. Solution: Only skip the test when running with ASAN. --- src/testdir/test_startup.vim | 26 ++++++++++++++------------ src/version.c | 2 ++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/testdir/test_startup.vim b/src/testdir/test_startup.vim index 4e034ef85d..3cb5a2deb6 100644 --- a/src/testdir/test_startup.vim +++ b/src/testdir/test_startup.vim @@ -277,18 +277,20 @@ func Test_V_arg() endfunc " Test that an error is shown when the defaults.vim file could not be read -" TODO: disabled - this causes ASAN errors for unknown reasons -"func Test_defaults_error() -" " Can't catch the output of gvim. -" CheckNotGui -" CheckNotMSWindows -" -" let out = system('VIMRUNTIME=/tmp ' .. GetVimCommand() .. ' --clean -cq') -" call assert_match("E1187: Failed to source defaults.vim", out) -" -" let out = system('VIMRUNTIME=/tmp ' .. GetVimCommand() .. ' -u DEFAULTS -cq') -" call assert_match("E1187: Failed to source defaults.vim", out) -"endfunc +func Test_defaults_error() + " Can't catch the output of gvim. + CheckNotGui + CheckNotMSWindows + " For unknown reasons freeing all memory does not work here, even though + " EXITFREE is defined. + CheckNotAsan + + let out = system('VIMRUNTIME=/tmp ' .. GetVimCommand() .. ' --clean -cq') + call assert_match("E1187: Failed to source defaults.vim", out) + + let out = system('VIMRUNTIME=/tmp ' .. GetVimCommand() .. ' -u DEFAULTS -cq') + call assert_match("E1187: Failed to source defaults.vim", out) +endfunc " Test the '-q [errorfile]' argument. func Test_q_arg() diff --git a/src/version.c b/src/version.c index 6761b72d8e..63b3a3ff25 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2927, /**/ 2926, /**/ From 01c798c31a94a50ad0c4a022fc21c1a31553be21 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Wed, 2 Jun 2021 17:07:18 +0200 Subject: [PATCH 08/41] patch 8.2.2928: the evalfunc.c file is too big Problem: The evalfunc.c file is too big. Solution: Move float related functionality to a separate file. (Yegappan Lakshmanan, closes #8287) --- Filelist | 2 + src/Make_ami.mak | 1 + src/Make_cyg_ming.mak | 1 + src/Make_mvc.mak | 4 + src/Make_vms.mms | 5 + src/Makefile | 29 ++- src/README.md | 1 + src/eval.c | 37 ---- src/evalfunc.c | 502 ------------------------------------------ src/float.c | 477 +++++++++++++++++++++++++++++++++++++++ src/proto.h | 1 + src/proto/eval.pro | 1 - src/proto/float.pro | 28 +++ src/version.c | 2 + 14 files changed, 544 insertions(+), 547 deletions(-) create mode 100644 src/float.c create mode 100644 src/proto/float.pro diff --git a/Filelist b/Filelist index 66fe467a9c..579344bddc 100644 --- a/Filelist +++ b/Filelist @@ -68,6 +68,7 @@ SRC_ALL = \ src/fileio.c \ src/filepath.c \ src/findfile.c \ + src/float.c \ src/fold.c \ src/getchar.c \ src/globals.h \ @@ -246,6 +247,7 @@ SRC_ALL = \ src/proto/fileio.pro \ src/proto/filepath.pro \ src/proto/findfile.pro \ + src/proto/float.pro \ src/proto/fold.pro \ src/proto/getchar.pro \ src/proto/gui.pro \ diff --git a/src/Make_ami.mak b/src/Make_ami.mak index 88b3986508..91246d9bce 100644 --- a/src/Make_ami.mak +++ b/src/Make_ami.mak @@ -117,6 +117,7 @@ SRC += \ fileio.c \ filepath.c \ findfile.c \ + float.c \ fold.c \ getchar.c \ hardcopy.c \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 0be3abbaa1..c33200b33e 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -749,6 +749,7 @@ OBJ = \ $(OUTDIR)/fileio.o \ $(OUTDIR)/filepath.o \ $(OUTDIR)/findfile.o \ + $(OUTDIR)/float.o \ $(OUTDIR)/fold.o \ $(OUTDIR)/getchar.o \ $(OUTDIR)/gui_xim.o \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index 30f8175e25..42b6f8ddf6 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -743,6 +743,7 @@ OBJ = \ $(OUTDIR)\fileio.obj \ $(OUTDIR)\filepath.obj \ $(OUTDIR)\findfile.obj \ + $(OUTDIR)\float.obj \ $(OUTDIR)\fold.obj \ $(OUTDIR)\getchar.obj \ $(OUTDIR)\gui_xim.obj \ @@ -1599,6 +1600,8 @@ $(OUTDIR)/filepath.obj: $(OUTDIR) filepath.c $(INCL) $(OUTDIR)/findfile.obj: $(OUTDIR) findfile.c $(INCL) +$(OUTDIR)/float.obj: $(OUTDIR) float.c $(INCL) + $(OUTDIR)/fold.obj: $(OUTDIR) fold.c $(INCL) $(OUTDIR)/getchar.obj: $(OUTDIR) getchar.c $(INCL) @@ -1935,6 +1938,7 @@ proto.h: \ proto/fileio.pro \ proto/filepath.pro \ proto/findfile.pro \ + proto/float.pro \ proto/getchar.pro \ proto/gui_xim.pro \ proto/hardcopy.pro \ diff --git a/src/Make_vms.mms b/src/Make_vms.mms index 3631236360..4928b0be86 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -343,6 +343,7 @@ SRC = \ fileio.c \ filepath.c, \ findfile.c \ + float.c \ fold.c \ getchar.c \ gui_xim.c \ @@ -460,6 +461,7 @@ OBJ = \ fileio.obj \ filepath.obj \ findfile.obj \ + float.obj \ fold.obj \ getchar.obj \ gui_xim.obj \ @@ -860,6 +862,9 @@ findfile.obj : findfile.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h \ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ errors.h globals.h +float.obj : float.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h fold.obj : fold.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h diff --git a/src/Makefile b/src/Makefile index 4e32814ffd..202daec91a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -386,7 +386,8 @@ CClink = $(CC) # Select the architecture supported. Default is to build for the current # platform. Use "both" for a universal binary. That probably doesn't work # when including Perl, Python, etc. -#CONF_OPT_DARWIN = --with-mac-arch=i386 +# NOTE: ppc probably doesn't work anymore, +#CONF_OPT_DARWIN = --with-mac-arch=intel #CONF_OPT_DARWIN = --with-mac-arch=ppc #CONF_OPT_DARWIN = --with-mac-arch=both @@ -436,6 +437,8 @@ CClink = $(CC) # PYTHON # Uncomment lines here when you want to include the Python interface. # This requires at least "normal" features, "tiny" and "small" don't work. +# Python 3 is preferred, Python 2 (often referred to as "Python") has been +# deprecated for a long time. # NOTE: This may cause threading to be enabled, which has side effects (such # as using different libraries and debugging becomes more difficult). # For Python3 support make a symbolic link in /usr/local/bin: @@ -463,7 +466,7 @@ CClink = $(CC) # TCL # Uncomment this when you want to include the Tcl interface. # First one is for static linking, second one for dynamic loading. -#CONF_OPT_TCL = --enable-tclinterp +CONF_OPT_TCL = --enable-tclinterp #CONF_OPT_TCL = --enable-tclinterp=dynamic #CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4 @@ -690,16 +693,18 @@ LINT_OPTIONS = -beprxzF # PROFILE_CFLAGS=-g -O0 --coverage -DWE_ARE_PROFILING -DUSE_GCOV_FLUSH -# Uncomment one of the next two lines to compile Vim with the -# address sanitizer (asan) or with the undefined sanitizer. Works with gcc. +# Uncomment the next lines to compile Vim with the address sanitizer (asan) and +# with the undefined sanitizer. Works with gcc. +# You should also use -DEXITFREE to avoid false reports. # May make Vim twice as slow. Errors are reported on stderr. # More at: https://code.google.com/p/address-sanitizer/ # Useful environment variables: # $ export ASAN_OPTIONS="print_stacktrace=1 log_path=asan" # $ export LSAN_OPTIONS="suppressions=`pwd`/testdir/lsan-suppress.txt" # When running tests output can be found in testdir/asan.* -#SANITIZER_CFLAGS = -g -O0 -fsanitize=address -fno-omit-frame-pointer -#SANITIZER_CFLAGS = -g -O0 -fsanitize=undefined -fno-omit-frame-pointer +#SANITIZER_CFLAGS = -g -O0 -fsanitize-recover=all \ +# -fsanitize=address -fsanitize=undefined \ +# -fno-omit-frame-pointer # Similarly when compiling with clang and using ubsan. # $ export UBSAN_OPTIONS="print_stacktrace=1 log_path=ubsan" @@ -979,7 +984,7 @@ SANITIZER_LIBS = $(SANITIZER_CFLAGS) # The value of QUOTESED comes from auto/config.mk. # Uncomment the next line to use the default value. -# QUOTESED = sed -e 's/[\\"]/\\&/g' -e 's/\\"/"/' -e 's/\\";$$/";/' +# QUOTESED = sed -e 's/[\\"]/\\&/g' -e 's/\\"/"/' -e 's/\\";$$/";/' -e 's/ */ /g' ##################### end of system specific lines ################### }}} @@ -1621,6 +1626,7 @@ BASIC_SRC = \ fileio.c \ filepath.c \ findfile.c \ + float.c \ fold.c \ getchar.c \ gui_xim.c \ @@ -1775,6 +1781,7 @@ OBJ_COMMON = \ objects/fileio.o \ objects/filepath.o \ objects/findfile.o \ + objects/float.o \ objects/fold.o \ objects/getchar.o \ objects/gui_xim.o \ @@ -1945,6 +1952,7 @@ PRO_AUTO = \ fileio.pro \ filepath.pro \ findfile.pro \ + float.pro \ fold.pro \ getchar.pro \ gui_xim.pro \ @@ -3247,6 +3255,9 @@ objects/filepath.o: filepath.c objects/findfile.o: findfile.c $(CCC) -o $@ findfile.c +objects/float.o: float.c + $(CCC) -o $@ float.c + objects/fold.o: fold.c $(CCC) -o $@ fold.c @@ -3838,6 +3849,10 @@ objects/findfile.o: findfile.c vim.h protodef.h auto/config.h feature.h os_unix. auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ proto.h errors.h globals.h +objects/float.o: float.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h objects/fold.o: fold.c vim.h protodef.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ diff --git a/src/README.md b/src/README.md index b4d9bdd89a..81ca37d0d6 100644 --- a/src/README.md +++ b/src/README.md @@ -56,6 +56,7 @@ locale.c | locale/language handling map.c | mapping and abbreviations mark.c | marks match.c | highlight matching +float.c | floating point functions mbyte.c | multi-byte character handling memfile.c | storing lines for buffers in a swapfile memline.c | storing lines for buffers in memory diff --git a/src/eval.c b/src/eval.c index e39c604ad2..77578f3650 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5155,43 +5155,6 @@ string_quote(char_u *str, int function) return s; } -#if defined(FEAT_FLOAT) || defined(PROTO) -/* - * Convert the string "text" to a floating point number. - * This uses strtod(). setlocale(LC_NUMERIC, "C") has been used to make sure - * this always uses a decimal point. - * Returns the length of the text that was consumed. - */ - int -string2float( - char_u *text, - float_T *value) // result stored here -{ - char *s = (char *)text; - float_T f; - - // MS-Windows does not deal with "inf" and "nan" properly. - if (STRNICMP(text, "inf", 3) == 0) - { - *value = INFINITY; - return 3; - } - if (STRNICMP(text, "-inf", 3) == 0) - { - *value = -INFINITY; - return 4; - } - if (STRNICMP(text, "nan", 3) == 0) - { - *value = NAN; - return 3; - } - f = strtod(s, &s); - *value = f; - return (int)((char_u *)s - text); -} -#endif - /* * Convert the specified byte index of line 'lnum' in buffer 'buf' to a * character index. Works only for loaded buffers. Returns -1 on failure. diff --git a/src/evalfunc.c b/src/evalfunc.c index 8ea48f9bd5..1962ccd15a 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -20,16 +20,7 @@ # include #endif -#ifdef FEAT_FLOAT -static void f_abs(typval_T *argvars, typval_T *rettv); -static void f_acos(typval_T *argvars, typval_T *rettv); -#endif static void f_and(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_asin(typval_T *argvars, typval_T *rettv); -static void f_atan(typval_T *argvars, typval_T *rettv); -static void f_atan2(typval_T *argvars, typval_T *rettv); -#endif #ifdef FEAT_BEVAL static void f_balloon_gettext(typval_T *argvars, typval_T *rettv); static void f_balloon_show(typval_T *argvars, typval_T *rettv); @@ -42,9 +33,6 @@ static void byteidx(typval_T *argvars, typval_T *rettv, int comp); static void f_byteidx(typval_T *argvars, typval_T *rettv); static void f_byteidxcomp(typval_T *argvars, typval_T *rettv); static void f_call(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_ceil(typval_T *argvars, typval_T *rettv); -#endif static void f_changenr(typval_T *argvars, typval_T *rettv); static void f_char2nr(typval_T *argvars, typval_T *rettv); static void f_charcol(typval_T *argvars, typval_T *rettv); @@ -52,10 +40,6 @@ static void f_charidx(typval_T *argvars, typval_T *rettv); static void f_col(typval_T *argvars, typval_T *rettv); static void f_confirm(typval_T *argvars, typval_T *rettv); static void f_copy(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_cos(typval_T *argvars, typval_T *rettv); -static void f_cosh(typval_T *argvars, typval_T *rettv); -#endif static void f_cursor(typval_T *argsvars, typval_T *rettv); #ifdef MSWIN static void f_debugbreak(typval_T *argvars, typval_T *rettv); @@ -70,17 +54,9 @@ static void f_eval(typval_T *argvars, typval_T *rettv); static void f_eventhandler(typval_T *argvars, typval_T *rettv); static void f_execute(typval_T *argvars, typval_T *rettv); static void f_exists(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_exp(typval_T *argvars, typval_T *rettv); -#endif static void f_expand(typval_T *argvars, typval_T *rettv); static void f_expandcmd(typval_T *argvars, typval_T *rettv); static void f_feedkeys(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_float2nr(typval_T *argvars, typval_T *rettv); -static void f_floor(typval_T *argvars, typval_T *rettv); -static void f_fmod(typval_T *argvars, typval_T *rettv); -#endif static void f_fnameescape(typval_T *argvars, typval_T *rettv); static void f_foreground(typval_T *argvars, typval_T *rettv); static void f_funcref(typval_T *argvars, typval_T *rettv); @@ -118,20 +94,12 @@ static void f_inputsecret(typval_T *argvars, typval_T *rettv); static void f_interrupt(typval_T *argvars, typval_T *rettv); static void f_invert(typval_T *argvars, typval_T *rettv); static void f_islocked(typval_T *argvars, typval_T *rettv); -#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) -static void f_isinf(typval_T *argvars, typval_T *rettv); -static void f_isnan(typval_T *argvars, typval_T *rettv); -#endif static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); static void f_len(typval_T *argvars, typval_T *rettv); static void f_libcall(typval_T *argvars, typval_T *rettv); static void f_libcallnr(typval_T *argvars, typval_T *rettv); static void f_line(typval_T *argvars, typval_T *rettv); static void f_line2byte(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_log(typval_T *argvars, typval_T *rettv); -static void f_log10(typval_T *argvars, typval_T *rettv); -#endif #ifdef FEAT_LUA static void f_luaeval(typval_T *argvars, typval_T *rettv); #endif @@ -153,9 +121,6 @@ static void f_or(typval_T *argvars, typval_T *rettv); #ifdef FEAT_PERL static void f_perleval(typval_T *argvars, typval_T *rettv); #endif -#ifdef FEAT_FLOAT -static void f_pow(typval_T *argvars, typval_T *rettv); -#endif static void f_prevnonblank(typval_T *argvars, typval_T *rettv); static void f_printf(typval_T *argvars, typval_T *rettv); static void f_pum_getpos(typval_T *argvars, typval_T *rettv); @@ -176,9 +141,6 @@ static void f_reg_executing(typval_T *argvars, typval_T *rettv); static void f_reg_recording(typval_T *argvars, typval_T *rettv); static void f_rename(typval_T *argvars, typval_T *rettv); static void f_repeat(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_round(typval_T *argvars, typval_T *rettv); -#endif #ifdef FEAT_RUBY static void f_rubyeval(typval_T *argvars, typval_T *rettv); #endif @@ -206,21 +168,11 @@ static void f_sha256(typval_T *argvars, typval_T *rettv); #endif static void f_shellescape(typval_T *argvars, typval_T *rettv); static void f_shiftwidth(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_sin(typval_T *argvars, typval_T *rettv); -static void f_sinh(typval_T *argvars, typval_T *rettv); -#endif static void f_soundfold(typval_T *argvars, typval_T *rettv); static void f_spellbadword(typval_T *argvars, typval_T *rettv); static void f_spellsuggest(typval_T *argvars, typval_T *rettv); static void f_split(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_sqrt(typval_T *argvars, typval_T *rettv); -#endif static void f_srand(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_str2float(typval_T *argvars, typval_T *rettv); -#endif static void f_str2list(typval_T *argvars, typval_T *rettv); static void f_str2nr(typval_T *argvars, typval_T *rettv); static void f_strcharlen(typval_T *argvars, typval_T *rettv); @@ -246,17 +198,10 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv); static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv); static void f_taglist(typval_T *argvars, typval_T *rettv); static void f_tagfiles(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_tan(typval_T *argvars, typval_T *rettv); -static void f_tanh(typval_T *argvars, typval_T *rettv); -#endif static void f_tolower(typval_T *argvars, typval_T *rettv); static void f_toupper(typval_T *argvars, typval_T *rettv); static void f_tr(typval_T *argvars, typval_T *rettv); static void f_trim(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_trunc(typval_T *argvars, typval_T *rettv); -#endif static void f_type(typval_T *argvars, typval_T *rettv); static void f_virtcol(typval_T *argvars, typval_T *rettv); static void f_visualmode(typval_T *argvars, typval_T *rettv); @@ -2194,70 +2139,6 @@ non_zero_arg(typval_T *argvars) && *argvars[0].vval.v_string != NUL)); } -#ifdef FEAT_FLOAT -/* - * Get the float value of "argvars[0]" into "f". - * Returns FAIL when the argument is not a Number or Float. - */ - static int -get_float_arg(typval_T *argvars, float_T *f) -{ - if (argvars[0].v_type == VAR_FLOAT) - { - *f = argvars[0].vval.v_float; - return OK; - } - if (argvars[0].v_type == VAR_NUMBER) - { - *f = (float_T)argvars[0].vval.v_number; - return OK; - } - emsg(_("E808: Number or Float required")); - return FAIL; -} - -/* - * "abs(expr)" function - */ - static void -f_abs(typval_T *argvars, typval_T *rettv) -{ - if (argvars[0].v_type == VAR_FLOAT) - { - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = fabs(argvars[0].vval.v_float); - } - else - { - varnumber_T n; - int error = FALSE; - - n = tv_get_number_chk(&argvars[0], &error); - if (error) - rettv->vval.v_number = -1; - else if (n > 0) - rettv->vval.v_number = n; - else - rettv->vval.v_number = -n; - } -} - -/* - * "acos()" function - */ - static void -f_acos(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = acos(f); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "and(expr, expr)" function */ @@ -2268,54 +2149,6 @@ f_and(typval_T *argvars, typval_T *rettv) & tv_get_number_chk(&argvars[1], NULL); } -#ifdef FEAT_FLOAT -/* - * "asin()" function - */ - static void -f_asin(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = asin(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "atan()" function - */ - static void -f_atan(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = atan(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "atan2()" function - */ - static void -f_atan2(typval_T *argvars, typval_T *rettv) -{ - float_T fx = 0.0, fy = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &fx) == OK - && get_float_arg(&argvars[1], &fy) == OK) - rettv->vval.v_float = atan2(fx, fy); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "balloon_show()" function */ @@ -2518,23 +2351,6 @@ f_call(typval_T *argvars, typval_T *rettv) (void)func_call(func, &argvars[1], partial, selfdict, rettv); } -#ifdef FEAT_FLOAT -/* - * "ceil({float})" function - */ - static void -f_ceil(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = ceil(f); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "changenr()" function */ @@ -2772,38 +2588,6 @@ f_copy(typval_T *argvars, typval_T *rettv) item_copy(&argvars[0], rettv, FALSE, 0); } -#ifdef FEAT_FLOAT -/* - * "cos()" function - */ - static void -f_cos(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = cos(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "cosh()" function - */ - static void -f_cosh(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = cosh(f); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * Set the cursor position. * If 'charcol' is TRUE, then use the column number as a character offset. @@ -3351,23 +3135,6 @@ f_exists(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = n; } -#ifdef FEAT_FLOAT -/* - * "exp()" function - */ - static void -f_exp(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = exp(f); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "expand()" function */ @@ -3578,58 +3345,6 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) } } -#ifdef FEAT_FLOAT -/* - * "float2nr({float})" function - */ - static void -f_float2nr(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - if (get_float_arg(argvars, &f) == OK) - { - if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON) - rettv->vval.v_number = -VARNUM_MAX; - else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON) - rettv->vval.v_number = VARNUM_MAX; - else - rettv->vval.v_number = (varnumber_T)f; - } -} - -/* - * "floor({float})" function - */ - static void -f_floor(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = floor(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "fmod()" function - */ - static void -f_fmod(typval_T *argvars, typval_T *rettv) -{ - float_T fx = 0.0, fy = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &fx) == OK - && get_float_arg(&argvars[1], &fy) == OK) - rettv->vval.v_float = fmod(fx, fy); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "fnameescape({string})" function */ @@ -6262,28 +5977,6 @@ f_islocked(typval_T *argvars, typval_T *rettv) clear_lval(&lv); } -#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) -/* - * "isinf()" function - */ - static void -f_isinf(typval_T *argvars, typval_T *rettv) -{ - if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float)) - rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1; -} - -/* - * "isnan()" function - */ - static void -f_isnan(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT - && isnan(argvars[0].vval.v_float); -} -#endif - /* * "last_buffer_nr()" function. */ @@ -6456,38 +6149,6 @@ f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) #endif } -#ifdef FEAT_FLOAT -/* - * "log()" function - */ - static void -f_log(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = log(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "log10()" function - */ - static void -f_log10(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = log10(f); - else - rettv->vval.v_float = 0.0; -} -#endif - #ifdef FEAT_LUA /* * "luaeval()" function @@ -7008,24 +6669,6 @@ f_perleval(typval_T *argvars, typval_T *rettv) } #endif -#ifdef FEAT_FLOAT -/* - * "pow()" function - */ - static void -f_pow(typval_T *argvars, typval_T *rettv) -{ - float_T fx = 0.0, fy = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &fx) == OK - && get_float_arg(&argvars[1], &fy) == OK) - rettv->vval.v_float = pow(fx, fy); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "prevnonblank()" function */ @@ -7780,33 +7423,6 @@ theend: return retval; } -#ifdef FEAT_FLOAT - -/* - * round() is not in C90, use ceil() or floor() instead. - */ - float_T -vim_round(float_T f) -{ - return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); -} - -/* - * "round({float})" function - */ - static void -f_round(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = vim_round(f); - else - rettv->vval.v_float = 0.0; -} -#endif - #ifdef FEAT_RUBY /* * "rubyeval()" function @@ -8790,38 +8406,6 @@ f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv) rettv->vval.v_number = get_sw_value(curbuf); } -#ifdef FEAT_FLOAT -/* - * "sin()" function - */ - static void -f_sin(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = sin(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "sinh()" function - */ - static void -f_sinh(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = sinh(f); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "soundfold({word})" function */ @@ -9072,42 +8656,6 @@ theend: p_cpo = save_cpo; } -#ifdef FEAT_FLOAT -/* - * "sqrt()" function - */ - static void -f_sqrt(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = sqrt(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -#ifdef FEAT_FLOAT -/* - * "str2float()" function - */ - static void -f_str2float(typval_T *argvars, typval_T *rettv) -{ - char_u *p = skipwhite(tv_get_string(&argvars[0])); - int isneg = (*p == '-'); - - if (*p == '+' || *p == '-') - p = skipwhite(p + 1); - (void)string2float(p, &rettv->vval.v_float); - if (isneg) - rettv->vval.v_float *= -1; - rettv->v_type = VAR_FLOAT; -} -#endif - /* * "str2list()" function */ @@ -9949,38 +9497,6 @@ f_taglist(typval_T *argvars, typval_T *rettv) (void)get_tags(rettv->vval.v_list, tag_pattern, fname); } -#ifdef FEAT_FLOAT -/* - * "tan()" function - */ - static void -f_tan(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = tan(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "tanh()" function - */ - static void -f_tanh(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = tanh(f); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "tolower(string)" function */ @@ -10205,24 +9721,6 @@ f_trim(typval_T *argvars, typval_T *rettv) rettv->vval.v_string = vim_strnsave(head, tail - head); } -#ifdef FEAT_FLOAT -/* - * "trunc({float})" function - */ - static void -f_trunc(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - // trunc() is not in C90, use floor() or ceil() instead. - rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); - else - rettv->vval.v_float = 0.0; -} -#endif - /* * "type(expr)" function */ diff --git a/src/float.c b/src/float.c new file mode 100644 index 0000000000..1361a36d50 --- /dev/null +++ b/src/float.c @@ -0,0 +1,477 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * float.c: Floating point functions + */ +#define USING_FLOAT_STUFF + +#include "vim.h" + +#if (defined(FEAT_EVAL) && defined(FEAT_FLOAT)) || defined(PROTO) + +#ifdef VMS +# include +#endif + +/* + * Convert the string "text" to a floating point number. + * This uses strtod(). setlocale(LC_NUMERIC, "C") has been used to make sure + * this always uses a decimal point. + * Returns the length of the text that was consumed. + */ + int +string2float( + char_u *text, + float_T *value) // result stored here +{ + char *s = (char *)text; + float_T f; + + // MS-Windows does not deal with "inf" and "nan" properly. + if (STRNICMP(text, "inf", 3) == 0) + { + *value = INFINITY; + return 3; + } + if (STRNICMP(text, "-inf", 3) == 0) + { + *value = -INFINITY; + return 4; + } + if (STRNICMP(text, "nan", 3) == 0) + { + *value = NAN; + return 3; + } + f = strtod(s, &s); + *value = f; + return (int)((char_u *)s - text); +} + +/* + * Get the float value of "argvars[0]" into "f". + * Returns FAIL when the argument is not a Number or Float. + */ + static int +get_float_arg(typval_T *argvars, float_T *f) +{ + if (argvars[0].v_type == VAR_FLOAT) + { + *f = argvars[0].vval.v_float; + return OK; + } + if (argvars[0].v_type == VAR_NUMBER) + { + *f = (float_T)argvars[0].vval.v_number; + return OK; + } + emsg(_("E808: Number or Float required")); + return FAIL; +} + +/* + * "abs(expr)" function + */ + void +f_abs(typval_T *argvars, typval_T *rettv) +{ + if (argvars[0].v_type == VAR_FLOAT) + { + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = fabs(argvars[0].vval.v_float); + } + else + { + varnumber_T n; + int error = FALSE; + + n = tv_get_number_chk(&argvars[0], &error); + if (error) + rettv->vval.v_number = -1; + else if (n > 0) + rettv->vval.v_number = n; + else + rettv->vval.v_number = -n; + } +} + +/* + * "acos()" function + */ + void +f_acos(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = acos(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "asin()" function + */ + void +f_asin(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = asin(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "atan()" function + */ + void +f_atan(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = atan(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "atan2()" function + */ + void +f_atan2(typval_T *argvars, typval_T *rettv) +{ + float_T fx = 0.0, fy = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &fx) == OK + && get_float_arg(&argvars[1], &fy) == OK) + rettv->vval.v_float = atan2(fx, fy); + else + rettv->vval.v_float = 0.0; +} + +/* + * "ceil({float})" function + */ + void +f_ceil(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = ceil(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "cos()" function + */ + void +f_cos(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = cos(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "cosh()" function + */ + void +f_cosh(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = cosh(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "exp()" function + */ + void +f_exp(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = exp(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "float2nr({float})" function + */ + void +f_float2nr(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + if (get_float_arg(argvars, &f) == OK) + { + if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON) + rettv->vval.v_number = -VARNUM_MAX; + else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON) + rettv->vval.v_number = VARNUM_MAX; + else + rettv->vval.v_number = (varnumber_T)f; + } +} + +/* + * "floor({float})" function + */ + void +f_floor(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = floor(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "fmod()" function + */ + void +f_fmod(typval_T *argvars, typval_T *rettv) +{ + float_T fx = 0.0, fy = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &fx) == OK + && get_float_arg(&argvars[1], &fy) == OK) + rettv->vval.v_float = fmod(fx, fy); + else + rettv->vval.v_float = 0.0; +} + +# if defined(HAVE_MATH_H) || defined(PROTO) +/* + * "isinf()" function + */ + void +f_isinf(typval_T *argvars, typval_T *rettv) +{ + if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float)) + rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1; +} + +/* + * "isnan()" function + */ + void +f_isnan(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT + && isnan(argvars[0].vval.v_float); +} +# endif + +/* + * "log()" function + */ + void +f_log(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = log(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "log10()" function + */ + void +f_log10(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = log10(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "pow()" function + */ + void +f_pow(typval_T *argvars, typval_T *rettv) +{ + float_T fx = 0.0, fy = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &fx) == OK + && get_float_arg(&argvars[1], &fy) == OK) + rettv->vval.v_float = pow(fx, fy); + else + rettv->vval.v_float = 0.0; +} + + +/* + * round() is not in C90, use ceil() or floor() instead. + */ + float_T +vim_round(float_T f) +{ + return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); +} + +/* + * "round({float})" function + */ + void +f_round(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = vim_round(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "sin()" function + */ + void +f_sin(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = sin(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "sinh()" function + */ + void +f_sinh(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = sinh(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "sqrt()" function + */ + void +f_sqrt(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = sqrt(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "str2float()" function + */ + void +f_str2float(typval_T *argvars, typval_T *rettv) +{ + char_u *p = skipwhite(tv_get_string(&argvars[0])); + int isneg = (*p == '-'); + + if (*p == '+' || *p == '-') + p = skipwhite(p + 1); + (void)string2float(p, &rettv->vval.v_float); + if (isneg) + rettv->vval.v_float *= -1; + rettv->v_type = VAR_FLOAT; +} + +/* + * "tan()" function + */ + void +f_tan(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = tan(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "tanh()" function + */ + void +f_tanh(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = tanh(f); + else + rettv->vval.v_float = 0.0; +} + +/* + * "trunc({float})" function + */ + void +f_trunc(typval_T *argvars, typval_T *rettv) +{ + float_T f = 0.0; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + // trunc() is not in C90, use floor() or ceil() instead. + rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); + else + rettv->vval.v_float = 0.0; +} + +#endif diff --git a/src/proto.h b/src/proto.h index 686a3d63ad..78f814ca57 100644 --- a/src/proto.h +++ b/src/proto.h @@ -90,6 +90,7 @@ extern int _stricoll(char *a, char *b); # include "fileio.pro" # include "filepath.pro" # include "findfile.pro" +# include "float.pro" # include "fold.pro" # include "getchar.pro" # include "gui_xim.pro" diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 03630c4b03..d31ed1c722 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -56,7 +56,6 @@ int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_ char_u *echo_string_core(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID, int echo_style, int restore_copyID, int composite_val); char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); char_u *string_quote(char_u *str, int function); -int string2float(char_u *text, float_T *value); int buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx); int buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx); pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum, int charcol); diff --git a/src/proto/float.pro b/src/proto/float.pro new file mode 100644 index 0000000000..e14ce24735 --- /dev/null +++ b/src/proto/float.pro @@ -0,0 +1,28 @@ +/* math.c */ +int string2float(char_u *text, float_T *value); +void f_abs(typval_T *argvars, typval_T *rettv); +void f_acos(typval_T *argvars, typval_T *rettv); +void f_asin(typval_T *argvars, typval_T *rettv); +void f_atan(typval_T *argvars, typval_T *rettv); +void f_atan2(typval_T *argvars, typval_T *rettv); +void f_ceil(typval_T *argvars, typval_T *rettv); +void f_cos(typval_T *argvars, typval_T *rettv); +void f_cosh(typval_T *argvars, typval_T *rettv); +void f_exp(typval_T *argvars, typval_T *rettv); +void f_float2nr(typval_T *argvars, typval_T *rettv); +void f_floor(typval_T *argvars, typval_T *rettv); +void f_fmod(typval_T *argvars, typval_T *rettv); +void f_isinf(typval_T *argvars, typval_T *rettv); +void f_isnan(typval_T *argvars, typval_T *rettv); +void f_log(typval_T *argvars, typval_T *rettv); +void f_log10(typval_T *argvars, typval_T *rettv); +void f_pow(typval_T *argvars, typval_T *rettv); +void f_round(typval_T *argvars, typval_T *rettv); +void f_sin(typval_T *argvars, typval_T *rettv); +void f_sinh(typval_T *argvars, typval_T *rettv); +void f_sqrt(typval_T *argvars, typval_T *rettv); +void f_str2float(typval_T *argvars, typval_T *rettv); +void f_tan(typval_T *argvars, typval_T *rettv); +void f_tanh(typval_T *argvars, typval_T *rettv); +void f_trunc(typval_T *argvars, typval_T *rettv); +/* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c index 63b3a3ff25..ea752d9e1e 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2928, /**/ 2927, /**/ From 0a808598e4edb3f1a167ac8c5c1f9084af625c4d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 2 Jun 2021 19:22:45 +0200 Subject: [PATCH 09/41] patch 8.2.2929: accidentally enable tcl by default Problem: Accidentally enable tcl by default. Solution: Revert change to Makefile --- src/Makefile | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 202daec91a..0efee51958 100644 --- a/src/Makefile +++ b/src/Makefile @@ -466,7 +466,7 @@ CClink = $(CC) # TCL # Uncomment this when you want to include the Tcl interface. # First one is for static linking, second one for dynamic loading. -CONF_OPT_TCL = --enable-tclinterp +#CONF_OPT_TCL = --enable-tclinterp #CONF_OPT_TCL = --enable-tclinterp=dynamic #CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4 diff --git a/src/version.c b/src/version.c index ea752d9e1e..28907ee647 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2929, /**/ 2928, /**/ From 85eee5b969485142b54337cadadd65a38e7d7396 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 3 Jun 2021 20:34:57 +0200 Subject: [PATCH 10/41] patch 8.2.2930: when a popup is visible a mouse move my restart Visual mode Problem: When a popup is visible a mouse move my restart Visual mode. Solution: Reset held_button when ending Visual mode. (closes #8318) --- src/mouse.c | 9 ++++++++- src/normal.c | 1 + src/proto/mouse.pro | 1 + src/version.c | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/mouse.c b/src/mouse.c index 4bff48e768..f1c1aabbc8 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -2098,6 +2098,14 @@ nv_mouse(cmdarg_T *cap) (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0); } +static int held_button = MOUSE_RELEASE; + + void +reset_held_button() +{ + held_button = MOUSE_RELEASE; +} + /* * Check if typebuf 'tp' contains a terminal mouse code and returns the * modifiers found in typebuf in 'modifiers'. @@ -2123,7 +2131,6 @@ check_termcode_mouse( int is_release, release_is_ambiguous; int wheel_code = 0; int current_button; - static int held_button = MOUSE_RELEASE; static int orig_num_clicks = 1; static int orig_mouse_code = 0x0; # ifdef CHECK_DOUBLE_CLICK diff --git a/src/normal.c b/src/normal.c index cb496dd1f0..f8ec8e9ce3 100644 --- a/src/normal.c +++ b/src/normal.c @@ -1380,6 +1380,7 @@ end_visual_mode(void) #endif VIsual_active = FALSE; + reset_held_button(); setmouse(); mouse_dragging = 0; diff --git a/src/proto/mouse.pro b/src/proto/mouse.pro index f2a8c3829c..37a2f07cb6 100644 --- a/src/proto/mouse.pro +++ b/src/proto/mouse.pro @@ -13,6 +13,7 @@ int mouse_model_popup(void); int jump_to_mouse(int flags, int *inclusive, int which_button); void nv_mousescroll(cmdarg_T *cap); void nv_mouse(cmdarg_T *cap); +void reset_held_button(void); int check_termcode_mouse(char_u *tp, int *slen, char_u *key_name, char_u *modifiers_start, int idx, int *modifiers); int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump, int *plines_cache); win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup); diff --git a/src/version.c b/src/version.c index 28907ee647..f89a1490f1 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2930, /**/ 2929, /**/ From 5072b47a223fb044041b8e7db59a17b3b1d8a625 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 3 Jun 2021 21:56:10 +0200 Subject: [PATCH 11/41] patch 8.2.2931: Vim9: line continuation comment uses legacy syntax Problem: Vim9: line continuation comment still uses legacy syntax in one place. Solution: Check for #\ instead of "\ earlier. (closes #8316) --- src/scriptfile.c | 7 +++++-- src/testdir/test_vim9_script.vim | 3 +++ src/version.c | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/scriptfile.c b/src/scriptfile.c index 15338be632..bbc415664e 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1788,6 +1788,8 @@ getsourceline( if (line != NULL && options != GETLINE_NONE && vim_strchr(p_cpo, CPO_CONCAT) == NULL) { + int comment_char = in_vim9script() ? '#' : '"'; + // compensate for the one line read-ahead --sp->sourcing_lnum; @@ -1800,7 +1802,8 @@ getsourceline( sp->nextline = get_one_sourceline(sp); if (sp->nextline != NULL && (*(p = skipwhite(sp->nextline)) == '\\' - || (p[0] == '"' && p[1] == '\\' && p[2] == ' ') + || (p[0] == comment_char + && p[1] == '\\' && p[2] == ' ') || (do_vim9_all && (*p == NUL || vim9_comment_start(p))) || (do_bar_cont && p[0] == '|' && p[1] != '|'))) @@ -1842,7 +1845,7 @@ getsourceline( ga_concat(&ga, p); } } - else if (!(p[0] == (in_vim9script() ? '#' : '"') + else if (!(p[0] == (comment_char) && p[1] == '\\' && p[2] == ' ') && !(do_vim9_all && (*p == NUL || vim9_comment_start(p)))) break; diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index ee324950fe..d5951c647a 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -3081,6 +3081,9 @@ def Test_vim9_comment() \ start='foo' #\ comment \ end='bar' + syn region Text start='foo' + #\ comment + \ end='bar' END CheckScriptSuccess(lines) diff --git a/src/version.c b/src/version.c index f89a1490f1..57a4dcd263 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2931, /**/ 2930, /**/ From 4f3c57f7980592b25f483e5953799c010a8ae196 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 3 Jun 2021 22:11:08 +0200 Subject: [PATCH 12/41] patch 8.2.2932: select mode test fails Problem: Select mode test fails. Solution: Do not always reset the held mouse button. --- src/mouse.c | 10 +++++----- src/normal.c | 14 ++++++++++---- src/proto/normal.pro | 1 + src/version.c | 2 ++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/mouse.c b/src/mouse.c index f1c1aabbc8..c17e26a3d6 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -477,7 +477,7 @@ do_mouse( if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) { // double click opens new page - end_visual_mode(); + end_visual_mode_keep_button(); tabpage_new(); tabpage_move(c1 == 0 ? 9999 : c1 - 1); } @@ -489,7 +489,7 @@ do_mouse( // It's like clicking on the status line of a window. if (curwin != old_curwin) - end_visual_mode(); + end_visual_mode_keep_button(); } } else @@ -1568,7 +1568,7 @@ retnomove: #endif if (flags & MOUSE_MAY_STOP_VIS) { - end_visual_mode(); + end_visual_mode_keep_button(); redraw_curbuf_later(INVERTED); // delete the inversion } #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD) @@ -1717,7 +1717,7 @@ retnomove: #endif && (flags & MOUSE_MAY_STOP_VIS)))) { - end_visual_mode(); + end_visual_mode_keep_button(); redraw_curbuf_later(INVERTED); // delete the inversion } #ifdef FEAT_CMDWIN @@ -1821,7 +1821,7 @@ retnomove: // before moving the cursor for a left click, stop Visual mode if (flags & MOUSE_MAY_STOP_VIS) { - end_visual_mode(); + end_visual_mode_keep_button(); redraw_curbuf_later(INVERTED); // delete the inversion } diff --git a/src/normal.c b/src/normal.c index f8ec8e9ce3..c4c167935e 100644 --- a/src/normal.c +++ b/src/normal.c @@ -1350,11 +1350,18 @@ call_yank_do_autocmd(int regname) /* * End Visual mode. - * This function should ALWAYS be called to end Visual mode, except from - * do_pending_operator(). + * This function or the next should ALWAYS be called to end Visual mode, except + * from do_pending_operator(). */ void -end_visual_mode(void) +end_visual_mode() +{ + end_visual_mode_keep_button(); + reset_held_button(); +} + + void +end_visual_mode_keep_button() { #ifdef FEAT_CLIPBOARD /* @@ -1380,7 +1387,6 @@ end_visual_mode(void) #endif VIsual_active = FALSE; - reset_held_button(); setmouse(); mouse_dragging = 0; diff --git a/src/proto/normal.pro b/src/proto/normal.pro index a1e31b341d..30f360b935 100644 --- a/src/proto/normal.pro +++ b/src/proto/normal.pro @@ -3,6 +3,7 @@ void init_normal_cmds(void); void normal_cmd(oparg_T *oap, int toplevel); void check_visual_highlight(void); void end_visual_mode(void); +void end_visual_mode_keep_button(void); void reset_VIsual_and_resel(void); void reset_VIsual(void); void restore_visual_mode(void); diff --git a/src/version.c b/src/version.c index 57a4dcd263..5ebcfcb07d 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2932, /**/ 2931, /**/ From 6e0b553fa12fc5ad5d8ee3d8457e7cb16f38b56f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 4 Jun 2021 17:11:47 +0200 Subject: [PATCH 13/41] patch 8.2.2933: when 'clipboard' is "unnamed" zp does not work correctly Problem: When 'clipboard' is "unnamed" zp and zP do not work correctly. Solution: Pass -1 to str_to_reg() and fix computing the character width instead of using the byte length. (Christian Brabandt, closes #8301, closes #8317) --- src/clipboard.c | 2 +- src/mbyte.c | 2 -- src/register.c | 13 +++++++++---- src/version.c | 2 ++ 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/clipboard.c b/src/clipboard.c index c26349291e..b1da99bcbe 100644 --- a/src/clipboard.c +++ b/src/clipboard.c @@ -2090,7 +2090,7 @@ clip_yank_selection( clip_free_selection(cbd); - str_to_reg(y_ptr, type, str, len, 0L, FALSE); + str_to_reg(y_ptr, type, str, len, -1, FALSE); } /* diff --git a/src/mbyte.c b/src/mbyte.c index 6df3a15dee..4b78eee0e5 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4308,7 +4308,6 @@ mb_charlen(char_u *str) return count; } -#if (defined(FEAT_SPELL) || defined(FEAT_EVAL)) || defined(PROTO) /* * Like mb_charlen() but for a string with specified length. */ @@ -4323,7 +4322,6 @@ mb_charlen_len(char_u *str, int len) return count; } -#endif /* * Try to un-escape a multi-byte character. diff --git a/src/register.c b/src/register.c index f4d934393b..8680c6bf32 100644 --- a/src/register.c +++ b/src/register.c @@ -2836,6 +2836,7 @@ str_to_reg( char_u **ss; char_u **pp; long maxlen; + int charlen; if (y_ptr->y_array == NULL) // NULL means empty register y_ptr->y_size = 0; @@ -2894,22 +2895,26 @@ str_to_reg( { for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum) { + charlen = MB_CHARLEN(*ss); i = (long)STRLEN(*ss); pp[lnum] = vim_strnsave(*ss, i); - if (i > maxlen) - maxlen = i; + if (charlen > maxlen) + maxlen = charlen; } } else { for (start = 0; start < len + extraline; start += i + 1) { + charlen = 0; for (i = start; i < len; ++i) // find the end of the line if (str[i] == '\n') break; i -= start; // i is now length of line - if (i > maxlen) - maxlen = i; + if (start < len) + charlen = mb_charlen_len(str + start, i); + if (charlen > maxlen) + maxlen = charlen; if (append) { --lnum; diff --git a/src/version.c b/src/version.c index 5ebcfcb07d..ab4ffeb39b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2933, /**/ 2932, /**/ From 24951a67c24e75ec4ff7506f8e2e789ccd786e89 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 4 Jun 2021 18:33:49 +0200 Subject: [PATCH 14/41] patch 8.2.2934: ASAN error when using text from the clipboard Problem: ASAN error when using text from the clipboard. Solution: Get width of each character. --- src/register.c | 7 ++++--- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/register.c b/src/register.c index 8680c6bf32..8c951b7eab 100644 --- a/src/register.c +++ b/src/register.c @@ -2908,11 +2908,12 @@ str_to_reg( { charlen = 0; for (i = start; i < len; ++i) // find the end of the line + { if (str[i] == '\n') break; + charlen += mb_ptr2cells_len(str + i, len - i); + } i -= start; // i is now length of line - if (start < len) - charlen = mb_charlen_len(str + start, i); if (charlen > maxlen) maxlen = charlen; if (append) @@ -2929,7 +2930,7 @@ str_to_reg( mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra); if (append) vim_free(y_ptr->y_array[lnum]); - if (i) + if (i > 0) mch_memmove(s + extra, str + start, (size_t)i); extra += i; s[extra] = NUL; diff --git a/src/version.c b/src/version.c index ab4ffeb39b..eab59f42ef 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2934, /**/ 2933, /**/ From 6c4c404c580fadd69e39297a6cb4b214f2fcb6d6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 4 Jun 2021 19:17:07 +0200 Subject: [PATCH 15/41] patch 8.2.2935: calculating register width is not always needed Problem: Calculating register width is not always needed. (Christian Brabandt) Solution: Only calculate the width when the type is MBLOCK. --- src/register.c | 20 ++++++++++++-------- src/version.c | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/register.c b/src/register.c index 8c951b7eab..5dc8f2896a 100644 --- a/src/register.c +++ b/src/register.c @@ -2836,7 +2836,6 @@ str_to_reg( char_u **ss; char_u **pp; long maxlen; - int charlen; if (y_ptr->y_array == NULL) // NULL means empty register y_ptr->y_size = 0; @@ -2895,23 +2894,28 @@ str_to_reg( { for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum) { - charlen = MB_CHARLEN(*ss); - i = (long)STRLEN(*ss); - pp[lnum] = vim_strnsave(*ss, i); - if (charlen > maxlen) - maxlen = charlen; + pp[lnum] = vim_strsave(*ss); + if (type == MBLOCK) + { + int charlen = mb_string2cells(*ss, -1); + + if (charlen > maxlen) + maxlen = charlen; + } } } else { for (start = 0; start < len + extraline; start += i + 1) { - charlen = 0; + int charlen = 0; + for (i = start; i < len; ++i) // find the end of the line { if (str[i] == '\n') break; - charlen += mb_ptr2cells_len(str + i, len - i); + if (type == MBLOCK) + charlen += mb_ptr2cells_len(str + i, len - i); } i -= start; // i is now length of line if (charlen > maxlen) diff --git a/src/version.c b/src/version.c index eab59f42ef..d55bb30ce3 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2935, /**/ 2934, /**/ From 5fa9b24440d677c1aa00084d0cf84638b1e1a0d5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 4 Jun 2021 21:00:32 +0200 Subject: [PATCH 16/41] patch 8.2.2936: Vim9: converting number to bool uses wrong stack offset Problem: Vim9: converting number to bool uses wrong stack offset. (Salman Halim) Solution: Include the offset in the 2BOOL command. --- src/testdir/test_vim9_disassemble.vim | 4 +-- src/testdir/test_vim9_expr.vim | 19 ++++++++++ src/version.c | 2 ++ src/vim9.h | 18 ++++++++-- src/vim9compile.c | 43 ++++++++++++++-------- src/vim9execute.c | 52 +++++++++++++++++++-------- 6 files changed, 104 insertions(+), 34 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index c4482a5d9c..f266cbe7c8 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -1650,11 +1650,11 @@ def Test_disassemble_invert_bool() '\d STORE $0\_s*' .. 'var invert = !flag\_s*' .. '\d LOAD $0\_s*' .. - '\d INVERT (!val)\_s*' .. + '\d INVERT -1 (!val)\_s*' .. '\d STORE $1\_s*' .. 'var res = !!flag\_s*' .. '\d LOAD $0\_s*' .. - '\d 2BOOL (!!val)\_s*' .. + '\d 2BOOL -1 (!!val)\_s*' .. '\d STORE $2\_s*', instr) assert_equal(true, InvertBool()) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 22186808e4..dc6858fc78 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2480,6 +2480,25 @@ def Test_expr7_dict_vim9script() endif enddef +def Test_expr7_call_2bool() + var lines =<< trim END + vim9script + + def BrokenCall(nr: number, mode: bool, use: string): void + assert_equal(3, nr) + assert_equal(false, mode) + assert_equal('ab', use) + enddef + + def TestBrokenCall(): void + BrokenCall(3, 0, 'ab') + enddef + + TestBrokenCall() + END + CheckScriptSuccess(lines) +enddef + let g:oneString = 'one' def Test_expr_member() diff --git a/src/version.c b/src/version.c index d55bb30ce3..a230c4eb0b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2936, /**/ 2935, /**/ diff --git a/src/vim9.h b/src/vim9.h index b260bdf1f3..6bc277d9bf 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -148,9 +148,9 @@ typedef enum { ISN_GETITEM, // push list item, isn_arg.number is the index ISN_MEMBER, // dict[member] ISN_STRINGMEMBER, // dict.member using isn_arg.string - ISN_2BOOL, // falsy/truthy to bool, invert if isn_arg.number != 0 + ISN_2BOOL, // falsy/truthy to bool, uses isn_arg.tobool ISN_COND2BOOL, // convert value to bool - ISN_2STRING, // convert value to string at isn_arg.number on stack + ISN_2STRING, // convert value to string at isn_arg.tostring on stack ISN_2STRING_ANY, // like ISN_2STRING but check type ISN_NEGATENR, // apply "-" to number @@ -369,6 +369,18 @@ typedef struct { cexprref_T *cexpr_ref; } cexpr_T; +// arguments to ISN_2STRING and ISN_2STRING_ANY +typedef struct { + int offset; + int tolerant; +} tostring_T; + +// arguments to ISN_2BOOL +typedef struct { + int offset; + int invert; +} tobool_T; + /* * Instruction */ @@ -414,6 +426,8 @@ struct isn_S { subs_T subs; cexpr_T cexpr; isn_T *instr; + tostring_T tostring; + tobool_T tobool; } isn_arg; }; diff --git a/src/vim9compile.c b/src/vim9compile.c index 5152b61a5f..573fa4365b 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -577,9 +577,10 @@ generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type) /* * If type at "offset" isn't already VAR_STRING then generate ISN_2STRING. * But only for simple types. + * When "tolerant" is TRUE convert most types to string, e.g. a List. */ static int -may_generate_2STRING(int offset, cctx_T *cctx) +may_generate_2STRING(int offset, int tolerant, cctx_T *cctx) { isn_T *isn; isntype_T isntype = ISN_2STRING; @@ -606,12 +607,20 @@ may_generate_2STRING(int offset, cctx_T *cctx) isntype = ISN_2STRING_ANY; break; + // conversion possible when tolerant + case VAR_LIST: + if (tolerant) + { + isntype = ISN_2STRING_ANY; + break; + } + // FALLTHROUGH + // conversion not possible case VAR_VOID: case VAR_BLOB: case VAR_FUNC: case VAR_PARTIAL: - case VAR_LIST: case VAR_DICT: case VAR_JOB: case VAR_CHANNEL: @@ -623,7 +632,8 @@ may_generate_2STRING(int offset, cctx_T *cctx) *type = &t_string; if ((isn = generate_instr(cctx, isntype)) == NULL) return FAIL; - isn->isn_arg.number = offset; + isn->isn_arg.tostring.offset = offset; + isn->isn_arg.tostring.tolerant = tolerant; return OK; } @@ -886,9 +896,10 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic) /* * Generate an ISN_2BOOL instruction. + * "offset" is the offset in the type stack. */ static int -generate_2BOOL(cctx_T *cctx, int invert) +generate_2BOOL(cctx_T *cctx, int invert, int offset) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; @@ -896,10 +907,11 @@ generate_2BOOL(cctx_T *cctx, int invert) RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL) return FAIL; - isn->isn_arg.number = invert; + isn->isn_arg.tobool.invert = invert; + isn->isn_arg.tobool.offset = offset; // type becomes bool - ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool; + ((type_T **)stack->ga_data)[stack->ga_len + offset] = &t_bool; return OK; } @@ -1008,7 +1020,7 @@ need_type( { // Using "0", "1" or the result of an expression with "&&" or "||" as a // boolean is OK but requires a conversion. - generate_2BOOL(cctx, FALSE); + generate_2BOOL(cctx, FALSE, offset); return OK; } @@ -2782,7 +2794,7 @@ compile_member(int is_slice, cctx_T *cctx) return FAIL; *typep = &t_any; } - if (may_generate_2STRING(-1, cctx) == FAIL) + if (may_generate_2STRING(-1, FALSE, cctx) == FAIL) return FAIL; if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL) return FAIL; @@ -3625,7 +3637,7 @@ compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) } if (isn->isn_type == ISN_PUSHS) key = isn->isn_arg.string; - else if (may_generate_2STRING(-1, cctx) == FAIL) + else if (may_generate_2STRING(-1, FALSE, cctx) == FAIL) return FAIL; *arg = skipwhite(*arg); if (**arg != ']') @@ -4026,7 +4038,7 @@ compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end) invert = !invert; --p; } - if (generate_2BOOL(cctx, invert) == FAIL) + if (generate_2BOOL(cctx, invert, -1) == FAIL) return FAIL; } } @@ -4849,8 +4861,8 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) ppconst->pp_is_const = FALSE; if (*op == '.') { - if (may_generate_2STRING(-2, cctx) == FAIL - || may_generate_2STRING(-1, cctx) == FAIL) + if (may_generate_2STRING(-2, FALSE, cctx) == FAIL + || may_generate_2STRING(-1, FALSE, cctx) == FAIL) return FAIL; generate_instr_drop(cctx, ISN_CONCAT, 1); } @@ -6420,7 +6432,8 @@ compile_assign_unlet( emsg(e_cannot_use_range_with_dictionary); return FAIL; } - if (dest_type == VAR_DICT && may_generate_2STRING(-1, cctx) == FAIL) + if (dest_type == VAR_DICT + && may_generate_2STRING(-1, FALSE, cctx) == FAIL) return FAIL; if (dest_type == VAR_LIST || dest_type == VAR_BLOB) { @@ -8383,7 +8396,7 @@ compile_throw(char_u *arg, cctx_T *cctx UNUSED) return NULL; if (cctx->ctx_skip == SKIP_YES) return p; - if (may_generate_2STRING(-1, cctx) == FAIL) + if (may_generate_2STRING(-1, FALSE, cctx) == FAIL) return NULL; if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL) return NULL; @@ -8618,7 +8631,7 @@ compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx) p += 2; if (compile_expr0(&p, cctx) == FAIL) return NULL; - may_generate_2STRING(-1, cctx); + may_generate_2STRING(-1, TRUE, cctx); ++count; p = skipwhite(p); if (*p != '`') diff --git a/src/vim9execute.c b/src/vim9execute.c index 35a106f26f..b23879d3ef 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -980,7 +980,7 @@ store_var(char_u *name, typval_T *tv) * Return FAIL if not allowed. */ static int -do_2string(typval_T *tv, int is_2string_any) +do_2string(typval_T *tv, int is_2string_any, int tolerant) { if (tv->v_type != VAR_STRING) { @@ -995,6 +995,22 @@ do_2string(typval_T *tv, int is_2string_any) case VAR_NUMBER: case VAR_FLOAT: case VAR_BLOB: break; + + case VAR_LIST: + if (tolerant) + { + char_u *p; + + str = typval2string(tv, TRUE); + clear_tv(tv); + tv->v_type = VAR_STRING; + tv->vval.v_string = str; + // TODO: escaping + while ((p = vim_strchr(str, '\n')) != NULL) + *p = ' '; + return OK; + } + // FALLTHROUGH default: to_string_error(tv->v_type); return FAIL; } @@ -2055,7 +2071,7 @@ exec_instructions(ectx_T *ectx) { dest_type = tv_dest->v_type; if (dest_type == VAR_DICT) - status = do_2string(tv_idx, TRUE); + status = do_2string(tv_idx, TRUE, FALSE); else if (dest_type == VAR_LIST && tv_idx->v_type != VAR_NUMBER) { @@ -3770,15 +3786,16 @@ exec_instructions(ectx_T *ectx) int n; int error = FALSE; - tv = STACK_TV_BOT(-1); if (iptr->isn_type == ISN_2BOOL) { + tv = STACK_TV_BOT(iptr->isn_arg.tobool.offset); n = tv2bool(tv); - if (iptr->isn_arg.number) // invert + if (iptr->isn_arg.tobool.invert) n = !n; } else { + tv = STACK_TV_BOT(-1); SOURCING_LNUM = iptr->isn_lnum; n = tv_get_bool_chk(tv, &error); if (error) @@ -3793,8 +3810,9 @@ exec_instructions(ectx_T *ectx) case ISN_2STRING: case ISN_2STRING_ANY: SOURCING_LNUM = iptr->isn_lnum; - if (do_2string(STACK_TV_BOT(iptr->isn_arg.number), - iptr->isn_type == ISN_2STRING_ANY) == FAIL) + if (do_2string(STACK_TV_BOT(iptr->isn_arg.tostring.offset), + iptr->isn_type == ISN_2STRING_ANY, + iptr->isn_arg.tostring.tolerant) == FAIL) goto on_error; break; @@ -5122,26 +5140,30 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) break; } case ISN_COND2BOOL: smsg("%s%4d COND2BOOL", pfx, current); break; - case ISN_2BOOL: if (iptr->isn_arg.number) - smsg("%s%4d INVERT (!val)", pfx, current); + case ISN_2BOOL: if (iptr->isn_arg.tobool.invert) + smsg("%s%4d INVERT %d (!val)", pfx, current, + iptr->isn_arg.tobool.offset); else - smsg("%s%4d 2BOOL (!!val)", pfx, current); + smsg("%s%4d 2BOOL %d (!!val)", pfx, current, + iptr->isn_arg.tobool.offset); break; case ISN_2STRING: smsg("%s%4d 2STRING stack[%lld]", pfx, current, - (varnumber_T)(iptr->isn_arg.number)); + (varnumber_T)(iptr->isn_arg.tostring.offset)); break; - case ISN_2STRING_ANY: smsg("%s%4d 2STRING_ANY stack[%lld]", pfx, current, - (varnumber_T)(iptr->isn_arg.number)); + case ISN_2STRING_ANY: smsg("%s%4d 2STRING_ANY stack[%lld]", + pfx, current, + (varnumber_T)(iptr->isn_arg.tostring.offset)); break; - case ISN_RANGE: smsg("%s%4d RANGE %s", pfx, current, iptr->isn_arg.string); + case ISN_RANGE: smsg("%s%4d RANGE %s", pfx, current, + iptr->isn_arg.string); break; case ISN_PUT: if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE) smsg("%s%4d PUT %c above range", - pfx, current, iptr->isn_arg.put.put_regname); + pfx, current, iptr->isn_arg.put.put_regname); else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE) smsg("%s%4d PUT %c range", - pfx, current, iptr->isn_arg.put.put_regname); + pfx, current, iptr->isn_arg.put.put_regname); else smsg("%s%4d PUT %c %ld", pfx, current, iptr->isn_arg.put.put_regname, From 56cddb38790ba535919524d9d2f32dbec9f3f07a Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Fri, 4 Jun 2021 21:09:55 +0200 Subject: [PATCH 17/41] patch 8.2.2937: popup test fails if rightleft feature not enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Popup test fails if rightleft feature not enabled. Solution: Check that the rightleft feature is available. (Dominique PellĂ©, closes #8321) --- src/testdir/test_popup.vim | 14 +++++++++----- src/version.c | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index 88aeafda7e..1d0a77c17c 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -1147,7 +1147,9 @@ endfunc " Test for the popup menu with the 'rightleft' option set func Test_pum_rightleft() + CheckFeature rightleft CheckScreendump + let lines =<< trim END abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz vim @@ -1204,11 +1206,13 @@ func Test_pum_scrollbar() call term_sendkeys(buf, "\\dd") call term_wait(buf) - call term_sendkeys(buf, ":set rightleft\") - call term_wait(buf) - call term_sendkeys(buf, "Go\\\") - call term_wait(buf) - call VerifyScreenDump(buf, 'Test_pum_scrollbar_02', {'rows': 7}) + if has('rightleft') + call term_sendkeys(buf, ":set rightleft\") + call term_wait(buf) + call term_sendkeys(buf, "Go\\\") + call term_wait(buf) + call VerifyScreenDump(buf, 'Test_pum_scrollbar_02', {'rows': 7}) + endif call StopVimInTerminal(buf) call delete('Xtest1') diff --git a/src/version.c b/src/version.c index a230c4eb0b..d59df5c3c7 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2937, /**/ 2936, /**/ From 21492743e80c6740bac65a91311c28bede8ef2f8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 4 Jun 2021 21:57:57 +0200 Subject: [PATCH 18/41] patch 8.2.2938: after using motion force from feedkeys() it sticks Problem: After using motion force from feedkeys() it may not be reset. Solution: Clear motion_force in clearop(). (closes #8323) --- src/normal.c | 1 + src/testdir/test_visual.vim | 9 +++++++++ src/version.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/normal.c b/src/normal.c index c4c167935e..fe47e2b74d 100644 --- a/src/normal.c +++ b/src/normal.c @@ -1750,6 +1750,7 @@ clearop(oparg_T *oap) oap->regname = 0; oap->motion_force = NUL; oap->use_reg_one = FALSE; + motion_force = NUL; } void diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 1b3661c228..b368c32b1f 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -913,6 +913,15 @@ func Test_visual_block_mode() set tabstop& shiftwidth& endfunc +func Test_visual_force_motion_feedkeys() + onoremap i- execute('let g:mode = mode(1)')->slice(0, 0) + call feedkeys('dvi-', 'x') + call assert_equal('nov', g:mode) + call feedkeys('di-', 'x') + call assert_equal('no', g:mode) + ounmap i- +endfunc + " Test block-insert using cursor keys for movement func Test_visual_block_insert_cursor_keys() new diff --git a/src/version.c b/src/version.c index d59df5c3c7..3ac26ab405 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2938, /**/ 2937, /**/ From 84e9ade826e7a6a03e0ff5cd9a35b48c4d88367e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 5 Jun 2021 16:07:37 +0200 Subject: [PATCH 19/41] patch 8.2.2939: GTK: righthand scrollbar does not show with split window Problem: GTK: righthand scrollbar does not show with split window. Solution: Adjust padding when two scrollbars are used. (Matt Wozniski, closes #8324) --- src/gui_gtk.c | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/gui_gtk.c b/src/gui_gtk.c index 77076fcbeb..79a1ac3d8e 100644 --- a/src/gui_gtk.c +++ b/src/gui_gtk.c @@ -1050,6 +1050,9 @@ gui_mch_get_scrollbar_xpadding(void) xpad = gui.formwin->allocation.width - gui.drawarea->allocation.width - gui.scrollbar_width; #endif + if (gui.which_scrollbars[SBAR_LEFT] && gui.which_scrollbars[SBAR_RIGHT]) + xpad -= gui.scrollbar_width; + return (xpad < 0) ? 0 : xpad; } diff --git a/src/version.c b/src/version.c index 3ac26ab405..b3de4a3398 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2939, /**/ 2938, /**/ From 4f2417ffeedbb687a59a36547e8143724a86bb31 Mon Sep 17 00:00:00 2001 From: "K.Takata" Date: Sat, 5 Jun 2021 16:25:32 +0200 Subject: [PATCH 20/41] patch 8.2.2940: MS-Windows: cannot see the size when resizing Problem: MS-Windows: cannot see the size of the text area when resizing the gvim window. Solution: Show a tooltip with the text size. (Ken Takata, closes #8326) --- src/gui_w32.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++----- src/version.c | 2 ++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/gui_w32.c b/src/gui_w32.c index c1f823e27a..b879aa3c88 100644 --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -2942,7 +2942,9 @@ gui_mswin_get_valid_dimensions( int w, int h, int *valid_w, - int *valid_h) + int *valid_h, + int *cols, + int *rows) { int base_width, base_height; @@ -2957,10 +2959,10 @@ gui_mswin_get_valid_dimensions( + gui_mswin_get_menu_height(FALSE) #endif ; - *valid_w = base_width + - ((w - base_width) / gui.char_width) * gui.char_width; - *valid_h = base_height + - ((h - base_height) / gui.char_height) * gui.char_height; + *cols = (w - base_width) / gui.char_width; + *rows = (h - base_height) / gui.char_height; + *valid_w = base_width + *cols * gui.char_width; + *valid_h = base_height + *rows * gui.char_height; } void @@ -4480,6 +4482,46 @@ _OnWindowPosChanged( } #endif + +static HWND hwndTip = NULL; + + static void +show_sizing_tip(int cols, int rows) +{ + TOOLINFOA ti = {sizeof(ti)}; + char buf[32]; + + ti.hwnd = s_hwnd; + ti.uId = (UINT_PTR)s_hwnd; + ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; + ti.lpszText = buf; + sprintf(buf, "%dx%d", cols, rows); + if (hwndTip == NULL) + { + hwndTip = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, + WS_POPUP | TTS_ALWAYSTIP | TTS_NOPREFIX, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + s_hwnd, NULL, GetModuleHandle(NULL), NULL); + SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&ti); + SendMessage(hwndTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti); + } + else + { + SendMessage(hwndTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); + } + SendMessage(hwndTip, TTM_POPUP, 0, 0); +} + + static void +destroy_sizing_tip(void) +{ + if (hwndTip != NULL) + { + DestroyWindow(hwndTip); + hwndTip = NULL; + } +} + static int _DuringSizing( UINT fwSide, @@ -4488,10 +4530,11 @@ _DuringSizing( int w, h; int valid_w, valid_h; int w_offset, h_offset; + int cols, rows; w = lprc->right - lprc->left; h = lprc->bottom - lprc->top; - gui_mswin_get_valid_dimensions(w, h, &valid_w, &valid_h); + gui_mswin_get_valid_dimensions(w, h, &valid_w, &valid_h, &cols, &rows); w_offset = w - valid_w; h_offset = h - valid_h; @@ -4508,6 +4551,8 @@ _DuringSizing( else if (fwSide == WMSZ_BOTTOM || fwSide == WMSZ_BOTTOMLEFT || fwSide == WMSZ_BOTTOMRIGHT) lprc->bottom -= h_offset; + + show_sizing_tip(cols, rows); return TRUE; } @@ -4648,6 +4693,10 @@ _WndProc( return 0L; #endif + case WM_EXITSIZEMOVE: + destroy_sizing_tip(); + break; + case WM_SIZING: // HANDLE_MSG doesn't seem to handle this one return _DuringSizing((UINT)wParam, (LPRECT)lParam); diff --git a/src/version.c b/src/version.c index b3de4a3398..e244d4b957 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2940, /**/ 2939, /**/ From b288ba9f1dd29ba34f236e3099f779d5ab130227 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 5 Jun 2021 17:10:55 +0200 Subject: [PATCH 21/41] patch 8.2.2941: Vim9: using does not handle a list of strings Problem: Vim9: using does not handle a list of strings. Solution: Convert a list to a string and escape each item. (closes #8310) --- src/testdir/test_vim9_cmd.vim | 4 ++++ src/version.c | 2 ++ src/vim9execute.c | 29 ++++++++++++++++++++++++----- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 87832ce2eb..6b31a62222 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -34,6 +34,10 @@ def Test_edit_wildcards() CheckDefFailure(['edit `=xxx`'], 'E1001:') CheckDefFailure(['edit `="foo"'], 'E1083:') + + var files = ['file 1', 'file%2', 'file# 3'] + args `=files` + assert_equal(files, argv()) enddef def Test_expand_alternate_file() diff --git a/src/version.c b/src/version.c index e244d4b957..0f539ca2ee 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2941, /**/ 2940, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index b23879d3ef..9826678293 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -999,15 +999,34 @@ do_2string(typval_T *tv, int is_2string_any, int tolerant) case VAR_LIST: if (tolerant) { - char_u *p; + char_u *s, *e, *p; + garray_T ga; + ga_init2(&ga, sizeof(char_u *), 1); + + // Convert to NL separated items, then + // escape the items and replace the NL with + // a space. str = typval2string(tv, TRUE); + if (str == NULL) + return FAIL; + s = str; + while ((e = vim_strchr(s, '\n')) != NULL) + { + *e = NUL; + p = vim_strsave_fnameescape(s, FALSE); + if (p != NULL) + { + ga_concat(&ga, p); + ga_concat(&ga, (char_u *)" "); + vim_free(p); + } + s = e + 1; + } + vim_free(str); clear_tv(tv); tv->v_type = VAR_STRING; - tv->vval.v_string = str; - // TODO: escaping - while ((p = vim_strchr(str, '\n')) != NULL) - *p = ' '; + tv->vval.v_string = ga.ga_data; return OK; } // FALLTHROUGH From 8da6d6db340069b3307e6bce3cdd40441197efce Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 5 Jun 2021 18:15:09 +0200 Subject: [PATCH 22/41] patch 8.2.2942: Vim9: error when calling function with too few arguments Problem: Vim9: internal error when calling function with too few arguments Solution: Check for argument count to be too few. (closes #8325) --- src/errors.h | 4 ++++ src/testdir/test_vim9_builtin.vim | 9 +++++++++ src/version.c | 2 ++ src/vim9execute.c | 8 ++++++++ 4 files changed, 23 insertions(+) diff --git a/src/errors.h b/src/errors.h index 00e2d565d0..94a752ae68 100644 --- a/src/errors.h +++ b/src/errors.h @@ -419,3 +419,7 @@ EXTERN char e_cannot_open_terminal_from_command_line_window[] INIT(= N_("E1188: Cannot open a terminal from the command line window")); EXTERN char e_cannot_use_legacy_with_command_str[] INIT(= N_("E1189: Cannot use :legacy with this command: %s")); +EXTERN char e_one_argument_too_few[] + INIT(= N_("E1190: One argument too few")); +EXTERN char e_nr_arguments_too_few[] + INIT(= N_("E1190: %d arguments too few")); diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 3fa5eb3065..9cae4a34e1 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -810,6 +810,15 @@ def Test_map_function_arg() assert_equal(['0:a', '1:b', '2:c'], l) END CheckDefAndScriptSuccess(lines) + + lines =<< trim END + range(3)->map((a, b, c) => a + b + c) + END + CheckDefExecAndScriptFailure(lines, 'E1190: One argument too few') + lines =<< trim END + range(3)->map((a, b, c, d) => a + b + c + d) + END + CheckDefExecAndScriptFailure(lines, 'E1190: 2 arguments too few') enddef def Test_map_item_type() diff --git a/src/version.c b/src/version.c index 0f539ca2ee..ce8273f483 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2942, /**/ 2941, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 9826678293..c2a7de50d6 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -4234,6 +4234,14 @@ call_def_function( semsg(_(e_nr_arguments_too_many), idx); goto failed_early; } + else if (idx < 0) + { + if (idx == -1) + emsg(_(e_one_argument_too_few)); + else + semsg(_(e_nr_arguments_too_few), -idx); + goto failed_early; + } // Put arguments on the stack, but no more than what the function expects. // A lambda can be called with more arguments than it uses. From c6d71532dda0b3a244907bb5d1826f9340f7571d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 5 Jun 2021 18:49:38 +0200 Subject: [PATCH 23/41] patch 8.2.2943: Vim9: check for argument count ignores default values Problem: Vim9: check for argument count ignores default values. Solution: Take default argument values into account. --- src/version.c | 2 ++ src/vim9execute.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/version.c b/src/version.c index ce8273f483..87bc2a09ed 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2943, /**/ 2942, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index c2a7de50d6..455a205070 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -4234,7 +4234,8 @@ call_def_function( semsg(_(e_nr_arguments_too_many), idx); goto failed_early; } - else if (idx < 0) + idx = argc - ufunc->uf_args.ga_len + ufunc->uf_def_args.ga_len; + if (idx < 0) { if (idx == -1) emsg(_(e_one_argument_too_few)); From 1328bde9d406aa1292e92673fa8a026889424e79 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 5 Jun 2021 20:51:38 +0200 Subject: [PATCH 24/41] patch 8.2.2944: Vim9: no error when using job or channel as a string Problem: Vim9: no error when using job or channel as a string. Solution: Be more strict about conversion to string. (closes #8312) --- src/channel.c | 18 ++++++++++++++ src/eval.c | 3 ++- src/job.c | 30 +++++++++++++++++++++++ src/proto/channel.pro | 1 + src/proto/job.pro | 1 + src/testdir/test_vim9_builtin.vim | 12 +++++++++- src/typval.c | 40 +++++++------------------------ src/version.c | 2 ++ src/vim9execute.c | 3 ++- 9 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/channel.c b/src/channel.c index fa329bdba3..2a93e2578c 100644 --- a/src/channel.c +++ b/src/channel.c @@ -5015,4 +5015,22 @@ f_ch_status(typval_T *argvars, typval_T *rettv) rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part)); } +/* + * Get a string with information about the channel in "varp" in "buf". + * "buf" must be at least NUMBUFLEN long. + */ + char_u * +channel_to_string_buf(typval_T *varp, char_u *buf) +{ + channel_T *channel = varp->vval.v_channel; + char *status = channel_status(channel, -1); + + if (channel == NULL) + vim_snprintf((char *)buf, NUMBUFLEN, "channel %s", status); + else + vim_snprintf((char *)buf, NUMBUFLEN, + "channel %d %s", channel->ch_id, status); + return buf; +} + #endif // FEAT_JOB_CHANNEL diff --git a/src/eval.c b/src/eval.c index 77578f3650..1fb1f5e70b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5060,7 +5060,8 @@ echo_string_core( case VAR_JOB: case VAR_CHANNEL: *tofree = NULL; - r = tv_get_string_buf(tv, numbuf); + r = tv->v_type == VAR_JOB ? job_to_string_buf(tv, numbuf) + : channel_to_string_buf(tv, numbuf); if (composite_val) { *tofree = string_quote(r, FALSE); diff --git a/src/job.c b/src/job.c index aeb2af7b53..189c06eb6e 100644 --- a/src/job.c +++ b/src/job.c @@ -1927,4 +1927,34 @@ f_job_stop(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = job_stop(job, argvars, NULL); } +/* + * Get a string with information about the job in "varp" in "buf". + * "buf" must be at least NUMBUFLEN long. + */ + char_u * +job_to_string_buf(typval_T *varp, char_u *buf) +{ + job_T *job = varp->vval.v_job; + char *status; + + if (job == NULL) + return (char_u *)"no process"; + status = job->jv_status == JOB_FAILED ? "fail" + : job->jv_status >= JOB_ENDED ? "dead" + : "run"; +# ifdef UNIX + vim_snprintf((char *)buf, NUMBUFLEN, + "process %ld %s", (long)job->jv_pid, status); +# elif defined(MSWIN) + vim_snprintf((char *)buf, NUMBUFLEN, + "process %ld %s", + (long)job->jv_proc_info.dwProcessId, + status); +# else + // fall-back + vim_snprintf((char *)buf, NUMBUFLEN, "process ? %s", status); +# endif + return buf; +} + #endif // FEAT_JOB_CHANNEL diff --git a/src/proto/channel.pro b/src/proto/channel.pro index bbe5288a38..32e68d8942 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -58,4 +58,5 @@ void f_ch_evalraw(typval_T *argvars, typval_T *rettv); void f_ch_sendraw(typval_T *argvars, typval_T *rettv); void f_ch_setoptions(typval_T *argvars, typval_T *rettv); void f_ch_status(typval_T *argvars, typval_T *rettv); +char_u *channel_to_string_buf(typval_T *varp, char_u *buf); /* vim: set ft=c : */ diff --git a/src/proto/job.pro b/src/proto/job.pro index bf97577e12..3927e7f48e 100644 --- a/src/proto/job.pro +++ b/src/proto/job.pro @@ -34,4 +34,5 @@ void f_job_setoptions(typval_T *argvars, typval_T *rettv); void f_job_start(typval_T *argvars, typval_T *rettv); void f_job_status(typval_T *argvars, typval_T *rettv); void f_job_stop(typval_T *argvars, typval_T *rettv); +char_u *job_to_string_buf(typval_T *varp, char_u *buf); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 9cae4a34e1..b98c840ce0 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1104,7 +1104,7 @@ def Test_set_get_bufline() assert_equal([], getbufline(b, 2, 1)) if has('job') - setbufline(b, 2, [function('eval'), {key: 123}, test_null_job()]) + setbufline(b, 2, [function('eval'), {key: 123}, string(test_null_job())]) assert_equal(["function('eval')", "{'key': 123}", "no process"], @@ -1250,6 +1250,16 @@ def Test_submatch() actual->assert_equal(expected) enddef +def Test_substitute() + var res = substitute('A1234', '\d', 'X', '') + assert_equal('AX234', res) + + if has('job') + assert_fails('"text"->substitute(".*", () => job_start(":"), "")', 'E908: using an invalid value as a String: job') + assert_fails('"text"->substitute(".*", () => job_start(":")->job_getchannel(), "")', 'E908: using an invalid value as a String: channel') + endif +enddef + def Test_synID() new setline(1, "text") diff --git a/src/typval.c b/src/typval.c index 3d1bd7f53f..f08d1aa421 100644 --- a/src/typval.c +++ b/src/typval.c @@ -414,7 +414,7 @@ tv_get_string_strict(typval_T *varp) char_u * tv_get_string_buf(typval_T *varp, char_u *buf) { - char_u *res = tv_get_string_buf_chk(varp, buf); + char_u *res = tv_get_string_buf_chk(varp, buf); return res != NULL ? res : (char_u *)""; } @@ -478,44 +478,22 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict) break; case VAR_JOB: #ifdef FEAT_JOB_CHANNEL + if (in_vim9script()) { - job_T *job = varp->vval.v_job; - char *status; - - if (job == NULL) - return (char_u *)"no process"; - status = job->jv_status == JOB_FAILED ? "fail" - : job->jv_status >= JOB_ENDED ? "dead" - : "run"; -# ifdef UNIX - vim_snprintf((char *)buf, NUMBUFLEN, - "process %ld %s", (long)job->jv_pid, status); -# elif defined(MSWIN) - vim_snprintf((char *)buf, NUMBUFLEN, - "process %ld %s", - (long)job->jv_proc_info.dwProcessId, - status); -# else - // fall-back - vim_snprintf((char *)buf, NUMBUFLEN, "process ? %s", status); -# endif - return buf; + semsg(_(e_using_invalid_value_as_string_str), "job"); + break; } + return job_to_string_buf(varp, buf); #endif break; case VAR_CHANNEL: #ifdef FEAT_JOB_CHANNEL + if (in_vim9script()) { - channel_T *channel = varp->vval.v_channel; - char *status = channel_status(channel, -1); - - if (channel == NULL) - vim_snprintf((char *)buf, NUMBUFLEN, "channel %s", status); - else - vim_snprintf((char *)buf, NUMBUFLEN, - "channel %d %s", channel->ch_id, status); - return buf; + semsg(_(e_using_invalid_value_as_string_str), "channel"); + break; } + return channel_to_string_buf(varp, buf); #endif break; case VAR_UNKNOWN: diff --git a/src/version.c b/src/version.c index 87bc2a09ed..b729c99f5e 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2944, /**/ 2943, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 455a205070..a13b0ab986 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -4831,10 +4831,11 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) { typval_T tv; char_u *name; + char_u buf[NUMBUFLEN]; tv.v_type = VAR_JOB; tv.vval.v_job = iptr->isn_arg.job; - name = tv_get_string(&tv); + name = job_to_string_buf(&tv, buf); smsg("%s%4d PUSHJOB \"%s\"", pfx, current, name); } #endif From 59b262362f26b3aaea1eeb0078adc33eed59863e Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sat, 5 Jun 2021 20:59:22 +0200 Subject: [PATCH 25/41] patch 8.2.2945: some buffer related code is not tested Problem: Some buffer related code is not tested. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #8320) --- src/termlib.c | 2 +- src/testdir/test_excmd.vim | 8 +++ src/testdir/test_recover.vim | 127 +++++++++++++++++++++++++++++++++++ src/testdir/test_swap.vim | 75 +++++++++++++++++++++ src/testdir/test_visual.vim | 4 ++ src/version.c | 2 + 6 files changed, 217 insertions(+), 1 deletion(-) diff --git a/src/termlib.c b/src/termlib.c index e05daae5d4..7c845c5c36 100644 --- a/src/termlib.c +++ b/src/termlib.c @@ -591,7 +591,7 @@ _match(char *s1, char *s2) static char * _find(char *s, char *set) { - for(; *s; s++) + for (; *s; s++) { char *ptr = set; diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim index 2e137f0e61..60753a6e82 100644 --- a/src/testdir/test_excmd.vim +++ b/src/testdir/test_excmd.vim @@ -69,6 +69,14 @@ func Test_file_cmd() call assert_fails('3file', 'E474:') call assert_fails('0,0file', 'E474:') call assert_fails('0file abc', 'E474:') + if !has('win32') + " Change the name of the buffer to the same name + new Xfile1 + file Xfile1 + call assert_equal('Xfile1', @%) + call assert_equal('Xfile1', @#) + bw! + endif endfunc " Test for the :drop command diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim index a1ff7d92af..654a0f855a 100644 --- a/src/testdir/test_recover.vim +++ b/src/testdir/test_recover.vim @@ -133,4 +133,131 @@ func Test_nocatch_process_still_running() call delete(swname) endfunc +" Test for :recover with multiple swap files +func Test_recover_multiple_swap_files() + CheckUnix + new Xfile1 + call setline(1, ['a', 'b', 'c']) + preserve + let b = readblob('.Xfile1.swp') + call writefile(b, '.Xfile1.swm') + call writefile(b, '.Xfile1.swn') + call writefile(b, '.Xfile1.swo') + %bw! + call feedkeys(":recover Xfile1\3\q", 'xt') + call assert_equal(['a', 'b', 'c'], getline(1, '$')) + + call delete('.Xfile1.swm') + call delete('.Xfile1.swn') + call delete('.Xfile1.swo') +endfunc + +" Test for :recover using an empty swap file +func Test_recover_empty_swap_file() + CheckUnix + call writefile([], '.Xfile1.swp') + let msg = execute('recover Xfile1') + call assert_match('Unable to read block 0 from .Xfile1.swp', msg) + call assert_equal('Xfile1', @%) + bw! + " :recover from an empty buffer + call assert_fails('recover', 'E305:') + call delete('.Xfile1.swp') +endfunc + +" Test for :recover using a corrupted swap file +func Test_recover_corrupted_swap_file() + CheckUnix + " recover using a partial swap file + call writefile(0z1234, '.Xfile1.swp') + call assert_fails('recover Xfile1', 'E295:') + bw! + + " recover using invalid content in the swap file + call writefile([repeat('1', 2*1024)], '.Xfile1.swp') + call assert_fails('recover Xfile1', 'E307:') + call delete('.Xfile1.swp') + + " :recover using a swap file with a corrupted header + edit Xfile1 + preserve + let sn = swapname('') + let b = readblob(sn) + bw! + " clear the B0_MAGIC_LONG field + let b[1008:1011] = 0z00000000 + call writefile(b, sn) + let msg = execute('recover Xfile1') + call assert_match('the file has been damaged', msg) + bw! + call delete(sn) +endfunc + +" Test for :recover using an encrypted swap file +func Test_recover_encrypted_swap_file() + CheckUnix + + " Recover an encrypted file from the swap file without the original file + new Xfile1 + call feedkeys(":X\vim\vim\", 'xt') + call setline(1, ['aaa', 'bbb', 'ccc']) + preserve + let b = readblob('.Xfile1.swp') + call writefile(b, '.Xfile1.swm') + bw! + call feedkeys(":recover Xfile1\vim\\", 'xt') + call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$')) + bw! + call delete('.Xfile1.swm') + + " Recover an encrypted file from the swap file with the original file + new Xfile1 + call feedkeys(":X\vim\vim\", 'xt') + call setline(1, ['aaa', 'bbb', 'ccc']) + update + call setline(1, ['111', '222', '333']) + preserve + let b = readblob('.Xfile1.swp') + call writefile(b, '.Xfile1.swm') + bw! + call feedkeys(":recover Xfile1\vim\\", 'xt') + call assert_equal(['111', '222', '333'], getline(1, '$')) + call assert_true(&modified) + bw! + call delete('.Xfile1.swm') + call delete('Xfile1') +endfunc + +" Test for :recover using a unreadable swap file +func Test_recover_unreadble_swap_file() + CheckUnix + CheckNotRoot + new Xfile1 + let b = readblob('.Xfile1.swp') + call writefile(b, '.Xfile1.swm') + bw! + call setfperm('.Xfile1.swm', '-w-------') + call assert_fails('recover Xfile1', 'E306:') + call delete('.Xfile1.swm') +endfunc + +" Test for using :recover when the original file and the swap file have the +" same contents. +func Test_recover_unmodified_file() + CheckUnix + call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1') + edit Xfile1 + preserve + let b = readblob('.Xfile1.swp') + %bw! + call writefile(b, '.Xfile1.swz') + let msg = execute('recover Xfile1') + call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$')) + call assert_false(&modified) + call assert_match('Buffer contents equals file contents', msg) + bw! + call delete('Xfile1') + call delete('.Xfile1.swz') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index 5f3f24da6a..52eb62e729 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -483,4 +483,79 @@ func Test_swap_auto_delete() augroup! test_swap_recover_ext endfunc +" Test for renaming a buffer when the swap file is deleted out-of-band +func Test_missing_swap_file() + CheckUnix + new Xfile1 + call delete('.Xfile1.swp') + call assert_fails('file Xfile2', 'E301:') + call assert_equal('Xfile2', bufname()) + call assert_true(bufexists('Xfile1')) + call assert_true(bufexists('Xfile2')) + %bw! +endfunc + +" Test for :preserve command +func Test_preserve() + new Xfile1 + setlocal noswapfile + call assert_fails('preserve', 'E313:') + bw! +endfunc + +" Test for the v:swapchoice variable +func Test_swapchoice() + call writefile(['aaa', 'bbb'], 'Xfile1') + edit Xfile1 + preserve + let swapfname = swapname('') + let b = readblob(swapfname) + bw! + call writefile(b, swapfname) + + autocmd! SwapExists + + " Test for v:swapchoice = 'o' (readonly) + augroup test_swapchoice + autocmd! + autocmd SwapExists * let v:swapchoice = 'o' + augroup END + edit Xfile1 + call assert_true(&readonly) + call assert_equal(['aaa', 'bbb'], getline(1, '$')) + %bw! + call assert_true(filereadable(swapfname)) + + " Test for v:swapchoice = 'a' (abort) + augroup test_swapchoice + autocmd! + autocmd SwapExists * let v:swapchoice = 'a' + augroup END + try + edit Xfile1 + catch /^Vim:Interrupt$/ + endtry + call assert_equal('', @%) + call assert_true(bufexists('Xfile1')) + %bw! + call assert_true(filereadable(swapfname)) + + " Test for v:swapchoice = 'd' (delete) + augroup test_swapchoice + autocmd! + autocmd SwapExists * let v:swapchoice = 'd' + augroup END + edit Xfile1 + call assert_equal('Xfile1', @%) + %bw! + call assert_false(filereadable(swapfname)) + + call delete('Xfile1') + call delete(swapfname) + augroup test_swapchoice + autocmd! + augroup END + augroup! test_swapchoice +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index b368c32b1f..51ef5ae812 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -811,6 +811,10 @@ func Test_visual_block_mode() " reproducible if this operation is performed manually. "call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$')) call assert_equal(['aaxa', 'bbba', 'ccca'], getline(1, '$')) + " Repeat the previous test but use 'l' to move the cursor instead of '$' + call setline(1, ['aaa', 'bbb', 'ccc']) + exe "normal! gg2l\2jA\x" + call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$')) " Change a characterwise motion to a blockwise motion using CTRL-V %d _ diff --git a/src/version.c b/src/version.c index b729c99f5e..ec20c946e4 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2945, /**/ 2944, /**/ From 2752360646545a9ae4853d2d5ca91cdb07c14eea Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 5 Jun 2021 21:36:19 +0200 Subject: [PATCH 26/41] patch 8.2.2946: Vim9: substitute expression cannot be a List Problem: Vim9: substitute expression cannot be a List in a :def function. Solution: Use typval2string(). (closes #8330) --- src/testdir/test_vim9_cmd.vim | 7 +++++++ src/version.c | 2 ++ src/vim9execute.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 6b31a62222..8481ecc595 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -1236,6 +1236,13 @@ def Test_substitute_expr() END CheckScriptSuccess(lines) unlet g:cond + + # List results in multiple lines + new + setline(1, 'some text here') + s/text/\=['aaa', 'bbb', 'ccc']/ + assert_equal(['some aaa', 'bbb', 'ccc', ' here'], getline(1, '$')) + bwipe! enddef def Test_redir_to_var() diff --git a/src/version.c b/src/version.c index ec20c946e4..efb1b42518 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2946, /**/ 2945, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index a13b0ab986..e870a279c0 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -4130,7 +4130,7 @@ exe_substitute_instr(void) { typval_T *tv = STACK_TV_BOT(-1); - res = vim_strsave(tv_get_string(tv)); + res = typval2string(tv, TRUE); --ectx->ec_stack.ga_len; clear_tv(tv); } From f5bfa8faa7bbe025c10148d37e8b47217a430a3b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 6 Jun 2021 12:07:54 +0200 Subject: [PATCH 27/41] patch 8.2.2947: build failure without the channel feature Problem: Build failure without the channel feature. Solution: Add back #ifdef. (John Marriott) --- src/eval.c | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/eval.c b/src/eval.c index 1fb1f5e70b..d0007bbd3e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5059,6 +5059,7 @@ echo_string_core( case VAR_JOB: case VAR_CHANNEL: +#ifdef FEAT_JOB_CHANNEL *tofree = NULL; r = tv->v_type == VAR_JOB ? job_to_string_buf(tv, numbuf) : channel_to_string_buf(tv, numbuf); @@ -5067,6 +5068,7 @@ echo_string_core( *tofree = string_quote(r, FALSE); r = *tofree; } +#endif break; case VAR_INSTR: diff --git a/src/version.c b/src/version.c index efb1b42518..7bc2afcec8 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2947, /**/ 2946, /**/ From 7a2217bedd223df4c8bbebe731bf0b5fe8532533 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 6 Jun 2021 12:33:49 +0200 Subject: [PATCH 28/41] patch 8.2.2948: substitute() accepts a number but not a float expression Problem: Substitute() accepts a number but not a float expression. Solution: Also accept a float. (closes #8331) --- src/testdir/test_substitute.vim | 8 ++++++++ src/typval.c | 9 +++++++-- src/version.c | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim index 4c99f81870..0c367485b8 100644 --- a/src/testdir/test_substitute.vim +++ b/src/testdir/test_substitute.vim @@ -1,6 +1,7 @@ " Tests for multi-line regexps with ":s". source shared.vim +source check.vim func Test_multiline_subst() enew! @@ -453,6 +454,13 @@ func Test_substitute_partial() call assert_fails("call substitute('123', '2', Replacer, 'g')", 'E118:') endfunc +func Test_substitute_float() + CheckFeature float + + call assert_equal('number 1.23', substitute('number ', '$', { -> 1.23 }, '')) + vim9 assert_equal('number 1.23', substitute('number ', '$', () => 1.23, '')) +endfunc + " Tests for *sub-replace-special* and *sub-replace-expression* on :substitute. " Execute a list of :substitute command tests diff --git a/src/typval.c b/src/typval.c index f08d1aa421..a17dbef7ef 100644 --- a/src/typval.c +++ b/src/typval.c @@ -462,8 +462,13 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict) break; case VAR_FLOAT: #ifdef FEAT_FLOAT - emsg(_(e_float_as_string)); - break; + if (strict) + { + emsg(_(e_float_as_string)); + break; + } + vim_snprintf((char *)buf, NUMBUFLEN, "%g", varp->vval.v_float); + return buf; #endif case VAR_STRING: if (varp->vval.v_string != NULL) diff --git a/src/version.c b/src/version.c index 7bc2afcec8..b9df688016 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2948, /**/ 2947, /**/ From 3cfa5b16b06bcc034f6de77070fa779d698ab5e9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 6 Jun 2021 14:14:39 +0200 Subject: [PATCH 29/41] patch 8.2.2949: tests failing because no error for float to string conversion Problem: Tests failing because there is no error for float to string conversion. Solution: Change the check for failure to check for correct result. Make some conversions strict in Vim9 script. --- src/evalfunc.c | 5 +++-- src/filepath.c | 4 +++- src/findfile.c | 2 +- src/float.c | 2 +- src/json.c | 11 ++++++++++- src/testdir/test_eval_stuff.vim | 2 +- src/testdir/test_execute_func.vim | 6 ++++-- src/testdir/test_float_func.vim | 5 ++++- src/testdir/test_functions.vim | 15 ++++++++++----- src/testdir/test_glob2regpat.vim | 5 ++++- src/testdir/test_listdict.vim | 6 +++--- src/version.c | 2 ++ 12 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 1962ccd15a..07f158d6d7 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -3000,7 +3000,8 @@ execute_common(typval_T *argvars, typval_T *rettv, int arg_off) if (argvars[arg_off + 1].v_type != VAR_UNKNOWN) { char_u buf[NUMBUFLEN]; - char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf); + char_u *s = tv_get_string_buf_chk_strict(&argvars[arg_off + 1], buf, + in_vim9script()); if (s == NULL) return; @@ -8897,7 +8898,7 @@ f_strdisplaywidth(typval_T *argvars, typval_T *rettv) static void f_strwidth(typval_T *argvars, typval_T *rettv) { - char_u *s = tv_get_string(&argvars[0]); + char_u *s = tv_get_string_strict(&argvars[0]); rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1)); } diff --git a/src/filepath.c b/src/filepath.c index e81eeb1200..69bc8b5f49 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -1301,7 +1301,9 @@ f_glob(typval_T *argvars, typval_T *rettv) void f_glob2regpat(typval_T *argvars, typval_T *rettv) { - char_u *pat = tv_get_string_chk(&argvars[0]); + char_u buf[NUMBUFLEN]; + char_u *pat = tv_get_string_buf_chk_strict(&argvars[0], buf, + in_vim9script()); rettv->v_type = VAR_STRING; rettv->vval.v_string = (pat == NULL) diff --git a/src/findfile.c b/src/findfile.c index 4f69c47caa..a72fe45ad9 100644 --- a/src/findfile.c +++ b/src/findfile.c @@ -2848,7 +2848,7 @@ f_simplify(typval_T *argvars, typval_T *rettv) { char_u *p; - p = tv_get_string(&argvars[0]); + p = tv_get_string_strict(&argvars[0]); rettv->vval.v_string = vim_strsave(p); simplify_filename(rettv->vval.v_string); // simplify in place rettv->v_type = VAR_STRING; diff --git a/src/float.c b/src/float.c index 1361a36d50..7c020448aa 100644 --- a/src/float.c +++ b/src/float.c @@ -417,7 +417,7 @@ f_sqrt(typval_T *argvars, typval_T *rettv) void f_str2float(typval_T *argvars, typval_T *rettv) { - char_u *p = skipwhite(tv_get_string(&argvars[0])); + char_u *p = skipwhite(tv_get_string_strict(&argvars[0])); int isneg = (*p == '-'); if (*p == '+' || *p == '-') diff --git a/src/json.c b/src/json.c index db25b70cc4..d0a087a927 100644 --- a/src/json.c +++ b/src/json.c @@ -607,7 +607,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) cur_item = res; init_tv(&item); if (res != NULL) - init_tv(res); + init_tv(res); fill_numbuflen(reader); p = reader->js_buf + reader->js_used; @@ -920,6 +920,15 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY && cur_item != NULL) { +#ifdef FEAT_FLOAT + if (cur_item->v_type == VAR_FLOAT) + { + // cannot use a float as a key + emsg(_(e_float_as_string)); + retval = FAIL; + goto theend; + } +#endif top_item->jd_key = tv_get_string_buf_chk(cur_item, key_buf); if (top_item->jd_key == NULL) { diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim index 4549f48608..0c1e75df59 100644 --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -144,7 +144,7 @@ func Test_string_concatenation() if has('float') let a = 'A' let b = 1.234 - call assert_fails('echo a .. b', 'E806:') + call assert_equal('A1.234', a .. b) endif endfunc diff --git a/src/testdir/test_execute_func.vim b/src/testdir/test_execute_func.vim index 036371715c..c08b2390f2 100644 --- a/src/testdir/test_execute_func.vim +++ b/src/testdir/test_execute_func.vim @@ -2,6 +2,7 @@ source view_util.vim source check.vim +source vim9.vim func NestedEval() let nested = execute('echo "nested\nlines"') @@ -37,8 +38,9 @@ func Test_execute_string() call assert_equal("\nsomething", execute('echo "something"', 'silent!')) call assert_equal("", execute('burp', 'silent!')) if has('float') - call assert_fails('call execute(3.4)', 'E806:') - call assert_fails('call execute("echo \"x\"", 3.4)', 'E806:') + call assert_fails('call execute(3.4)', 'E492:') + call assert_equal("\nx", execute("echo \"x\"", 3.4)) + call CheckDefExecAndScriptFailure(['execute("echo \"x\"", 3.4)'], 'E806:') endif endfunc diff --git a/src/testdir/test_float_func.vim b/src/testdir/test_float_func.vim index 17b5cdac96..b10bffd728 100644 --- a/src/testdir/test_float_func.vim +++ b/src/testdir/test_float_func.vim @@ -2,6 +2,7 @@ source check.vim CheckFeature float +source vim9.vim func Test_abs() call assert_equal('1.23', string(abs(1.23))) @@ -238,7 +239,9 @@ func Test_str2float() call assert_equal('nan', string(str2float('NaN'))) call assert_equal('nan', string(str2float(' nan '))) - call assert_fails("call str2float(1.2)", 'E806:') + call assert_equal(1.2, str2float(1.2)) + call CheckDefExecFailure(['str2float(1.2)'], 'E1013:') + call CheckScriptFailure(['vim9script', 'str2float(1.2)'], 'E806:') call assert_fails("call str2float([])", 'E730:') call assert_fails("call str2float({})", 'E731:') call assert_fails("call str2float(function('string'))", 'E729:') diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index bc96491726..023da66ba1 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -165,11 +165,13 @@ func Test_strwidth() call assert_fails('call strwidth({->0})', 'E729:') call assert_fails('call strwidth([])', 'E730:') call assert_fails('call strwidth({})', 'E731:') - if has('float') - call assert_fails('call strwidth(1.2)', 'E806:') - endif endfor + if has('float') + call assert_equal(3, strwidth(1.2)) + call CheckDefExecAndScriptFailure(['echo strwidth(1.2)'], 'E806:') + endif + set ambiwidth& endfunc @@ -233,7 +235,9 @@ func Test_str2nr() call assert_fails('call str2nr([])', 'E730:') call assert_fails('call str2nr({->2})', 'E729:') if has('float') - call assert_fails('call str2nr(1.2)', 'E806:') + call assert_equal(1, str2nr(1.2)) + call CheckDefExecFailure(['echo str2nr(1.2)'], 'E1013:') + call CheckScriptFailure(['vim9script', 'echo str2nr(1.2)'], 'E806:') endif call assert_fails('call str2nr(10, [])', 'E745:') endfunc @@ -494,7 +498,8 @@ func Test_simplify() call assert_fails('call simplify([])', 'E730:') call assert_fails('call simplify({})', 'E731:') if has('float') - call assert_fails('call simplify(1.2)', 'E806:') + call assert_equal('1.2', simplify(1.2)) + call CheckDefExecAndScriptFailure(['echo simplify(1.2)'], 'E806:') endif endfunc diff --git a/src/testdir/test_glob2regpat.vim b/src/testdir/test_glob2regpat.vim index 2907b286db..ab459bba33 100644 --- a/src/testdir/test_glob2regpat.vim +++ b/src/testdir/test_glob2regpat.vim @@ -1,8 +1,11 @@ " Test glob2regpat() +source vim9.vim + func Test_glob2regpat_invalid() if has('float') - call assert_fails('call glob2regpat(1.33)', 'E806:') + call assert_equal('^1\.33$', glob2regpat(1.33)) + call CheckDefExecAndScriptFailure(['echo glob2regpat(1.33)'], 'E806:') endif call assert_fails('call glob2regpat("}")', 'E219:') call assert_fails('call glob2regpat("{")', 'E220:') diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 46b030b86e..8351acb410 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -859,7 +859,7 @@ func Test_listdict_extend() call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 'error')", 'E737:') call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 'xxx')", 'E475:') if has('float') - call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 1.2)", 'E806:') + call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 1.2)", 'E475:') endif call assert_equal({'a': 'A', 'b': 'B'}, d) @@ -1022,9 +1022,9 @@ func Test_listdict_index() call assert_fails("let l = insert([1,2,3], 4, [])", 'E745:') let l = [1, 2, 3] call assert_fails("let l[i] = 3", 'E121:') - call assert_fails("let l[1.1] = 4", 'E806:') + call assert_fails("let l[1.1] = 4", 'E805:') call assert_fails("let l[:i] = [4, 5]", 'E121:') - call assert_fails("let l[:3.2] = [4, 5]", 'E806:') + call assert_fails("let l[:3.2] = [4, 5]", 'E805:') let t = test_unknown() call assert_fails("echo t[0]", 'E685:') endfunc diff --git a/src/version.c b/src/version.c index b9df688016..94a4cfb23b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2949, /**/ 2948, /**/ From c64ed2b714e605930e7c4102d4e80a2b1d9ff9bf Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Sun, 6 Jun 2021 15:07:09 +0200 Subject: [PATCH 30/41] patch 8.2.2950: sound code not fully tested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Sound code not fully tested. Solution: Add more sound tests. (Dominique PellĂ©, closes #8332) --- src/testdir/test_sound.vim | 39 +++++++++++++++++++++++++++++++++++--- src/version.c | 2 ++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_sound.vim b/src/testdir/test_sound.vim index c8f6305efb..cc01bf6a74 100644 --- a/src/testdir/test_sound.vim +++ b/src/testdir/test_sound.vim @@ -1,12 +1,12 @@ " Tests for the sound feature +source check.vim source shared.vim -if !has('sound') - throw 'Skipped: sound feature not available' -endif +CheckFeature sound func PlayCallback(id, result) + let g:playcallback_count += 1 let g:id = a:id let g:result = a:result endfunc @@ -15,20 +15,24 @@ func Test_play_event() if has('win32') throw 'Skipped: Playing event with callback is not supported on Windows' endif + let g:playcallback_count = 0 let g:id = 0 let id = 'bell'->sound_playevent('PlayCallback') if id == 0 throw 'Skipped: bell event not available' endif + " Stop it quickly, avoid annoying the user. sleep 20m eval id->sound_stop() call WaitForAssert({-> assert_equal(id, g:id)}) call assert_equal(1, g:result) " sound was aborted + call assert_equal(1, g:playcallback_count) endfunc func Test_play_silent() let fname = fnamemodify('silent.wav', '%p') + let g:playcallback_count = 0 " play without callback let id1 = sound_playfile(fname) @@ -41,6 +45,7 @@ func Test_play_silent() call assert_true(id2 > 0) call WaitForAssert({-> assert_equal(id2, g:id)}) call assert_equal(0, g:result) + call assert_equal(1, g:playcallback_count) let id2 = sound_playfile(fname, 'PlayCallback') call assert_true(id2 > 0) @@ -48,6 +53,13 @@ func Test_play_silent() call sound_clear() call WaitForAssert({-> assert_equal(id2, g:id)}) call assert_equal(1, g:result) " sound was aborted + call assert_equal(2, g:playcallback_count) + + " Play 2 sounds almost at the same time to exercise + " code with multiple callbacks in the callback list. + call sound_playfile(fname, 'PlayCallback') + call sound_playfile(fname, 'PlayCallback') + call WaitForAssert({-> assert_equal(4, g:playcallback_count)}) " recursive use was causing a crash func PlayAgain(id, fname) @@ -62,4 +74,25 @@ func Test_play_silent() call WaitForAssert({-> assert_true(g:id > 0)}) endfunc +func Test_play_event_error() + " Do not run test on Windows as: + " - playing event with callback is not supported on Windows. + " - FIXME: even without callback, sound_playevent('') does not return 0 on Windows. Bug? + CheckNotMSWindows + + call assert_equal(0, sound_playevent('')) + call assert_equal(0, sound_playevent(test_null_string())) + call assert_equal(0, sound_playevent('doesnotexist')) + call assert_equal(0, sound_playevent('doesnotexist', 'doesnotexist')) + call assert_equal(0, sound_playevent(test_null_string(), test_null_string())) + call assert_equal(0, sound_playevent(test_null_string(), test_null_function())) + + call assert_equal(0, sound_playfile('')) + call assert_equal(0, sound_playfile(test_null_string())) + call assert_equal(0, sound_playfile('doesnotexist')) + call assert_equal(0, sound_playfile('doesnotexist', 'doesnotexist')) + call assert_equal(0, sound_playfile(test_null_string(), test_null_string())) + call assert_equal(0, sound_playfile(test_null_string(), test_null_function())) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 94a4cfb23b..06340e31af 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2950, /**/ 2949, /**/ From 2067733b5c76e996238af938af36b8196366b7ce Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 6 Jun 2021 17:02:53 +0200 Subject: [PATCH 31/41] patch 8.2.2951: Vim9: cannot use heredoc for :python, :lua, etc. Problem: Vim9: cannot use heredoc in :def function for :python, :lua, etc. Solution: Concatenate the heredoc lines and pass them in the ISN_EXEC_SPLIT instruction. --- src/testdir/test_vim9_disassemble.vim | 17 ++++++++ src/testdir/test_vim9_func.vim | 28 ++++++++++++++ src/userfunc.c | 41 ++++++++++++++++++-- src/version.c | 2 + src/vim9.h | 1 + src/vim9compile.c | 56 +++++++++++++++++++++------ src/vim9execute.c | 52 +++++++++++++++++++++++++ 7 files changed, 182 insertions(+), 15 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index f266cbe7c8..965399bca1 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -121,6 +121,23 @@ def Test_disassemble_exec_expr() res) enddef +if has('python3') + def s:PyHeredoc() + python3 << EOF + print('hello') +EOF + enddef + + def Test_disassemble_python_heredoc() + var res = execute('disass s:PyHeredoc') + assert_match('\d*_PyHeredoc.*' .. + " python3 << EOF^@ print('hello')^@EOF\\_s*" .. + '\d EXEC_SPLIT python3 << EOF^@ print(''hello'')^@EOF\_s*' .. + '\d RETURN 0', + res) + enddef +endif + def s:Substitute() var expr = "abc" :%s/a/\=expr/&g#c diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 9f0cd3f895..7e21b37883 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2758,5 +2758,33 @@ def Test_closing_brace_at_start_of_line() call CheckDefAndScriptSuccess(lines) enddef +if has('python3') + def Test_python3_heredoc() + py3 << trim EOF + import vim + vim.vars['didit'] = 'yes' + EOF + assert_equal('yes', g:didit) + + python3 << trim EOF + import vim + vim.vars['didit'] = 'again' + EOF + assert_equal('again', g:didit) + enddef +endif + +" This messes up syntax highlight, keep near the end. +if has('lua') + def Test_lua_heredoc() + g:d = {} + lua << trim EOF + x = vim.eval('g:d') + x['key'] = 'val' + EOF + assert_equal('val', g:d.key) + enddef +endif + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/userfunc.c b/src/userfunc.c index f5d9063028..64e815d042 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -631,8 +631,12 @@ get_function_body( char_u *skip_until = NULL; int ret = FAIL; int is_heredoc = FALSE; + int heredoc_concat_len = 0; + garray_T heredoc_ga; char_u *heredoc_trimmed = NULL; + ga_init2(&heredoc_ga, 1, 500); + // Detect having skipped over comment lines to find the return // type. Add NULL lines to keep the line count correct. sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie); @@ -733,6 +737,20 @@ get_function_body( getline_options = vim9_function ? GETLINE_CONCAT_CONTBAR : GETLINE_CONCAT_CONT; is_heredoc = FALSE; + + if (heredoc_concat_len > 0) + { + // Replace the starting line with all the concatenated + // lines. + ga_concat(&heredoc_ga, theline); + vim_free(((char_u **)(newlines->ga_data))[ + heredoc_concat_len - 1]); + ((char_u **)(newlines->ga_data))[ + heredoc_concat_len - 1] = heredoc_ga.ga_data; + ga_init(&heredoc_ga); + heredoc_concat_len = 0; + theline += STRLEN(theline); // skip the "EOF" + } } } } @@ -886,6 +904,8 @@ get_function_body( skip_until = vim_strnsave(p, skiptowhite(p) - p); getline_options = GETLINE_NONE; is_heredoc = TRUE; + if (eap->cmdidx == CMD_def) + heredoc_concat_len = newlines->ga_len + 1; } // Check for ":cmd v =<< [trim] EOF" @@ -928,10 +948,21 @@ get_function_body( if (ga_grow(newlines, 1 + sourcing_lnum_off) == FAIL) goto theend; - // Copy the line to newly allocated memory. get_one_sourceline() - // allocates 250 bytes per line, this saves 80% on average. The cost - // is an extra alloc/free. - p = vim_strsave(theline); + if (heredoc_concat_len > 0) + { + // For a :def function "python << EOF" concatenats all the lines, + // to be used for the instruction later. + ga_concat(&heredoc_ga, theline); + ga_concat(&heredoc_ga, (char_u *)"\n"); + p = vim_strsave((char_u *)""); + } + else + { + // Copy the line to newly allocated memory. get_one_sourceline() + // allocates 250 bytes per line, this saves 80% on average. The + // cost is an extra alloc/free. + p = vim_strsave(theline); + } if (p == NULL) goto theend; ((char_u **)(newlines->ga_data))[newlines->ga_len++] = p; @@ -953,6 +984,7 @@ get_function_body( theend: vim_free(skip_until); vim_free(heredoc_trimmed); + vim_free(heredoc_ga.ga_data); need_wait_return |= saved_wait_return; return ret; } @@ -1436,6 +1468,7 @@ deref_func_name( cc = name[*lenp]; name[*lenp] = NUL; + v = find_var(name, &ht, no_autoload); name[*lenp] = cc; if (v != NULL) diff --git a/src/version.c b/src/version.c index 06340e31af..f995518798 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2951, /**/ 2950, /**/ diff --git a/src/vim9.h b/src/vim9.h index 6bc277d9bf..d4d3b7d6c1 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -14,6 +14,7 @@ typedef enum { ISN_EXEC, // execute Ex command line isn_arg.string ISN_EXECCONCAT, // execute Ex command from isn_arg.number items on stack + ISN_EXEC_SPLIT, // execute Ex command from isn_arg.string split at NL ISN_LEGACY_EVAL, // evaluate expression isn_arg.string with legacy syntax. ISN_ECHO, // echo isn_arg.echo.echo_count items on top of stack ISN_EXECUTE, // execute Ex commands isn_arg.number items on top of stack diff --git a/src/vim9compile.c b/src/vim9compile.c index 573fa4365b..0c73433d5f 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -8668,6 +8668,29 @@ theend: return nextcmd; } +/* + * A script command with heredoc, e.g. + * ruby << EOF + * command + * EOF + * Has been turned into one long line with NL characters by + * get_function_body(): + * ruby << EOF commandEOF + */ + static char_u * +compile_script(char_u *line, cctx_T *cctx) +{ + if (cctx->ctx_skip != SKIP_YES) + { + isn_T *isn; + + if ((isn = generate_instr(cctx, ISN_EXEC_SPLIT)) == NULL) + return NULL; + isn->isn_arg.string = vim_strsave(line); + } + return (char_u *)""; +} + /* * :s/pat/repl/ @@ -9480,18 +9503,28 @@ compile_def_function( line = (char_u *)""; break; - default: - if (cctx.ctx_skip == SKIP_YES) - { - // We don't check for a next command here. - line = (char_u *)""; - } - else - { - // Not recognized, execute with do_cmdline_cmd(). - ea.arg = p; + case CMD_lua: + case CMD_mzscheme: + case CMD_perl: + case CMD_py3: + case CMD_python3: + case CMD_python: + case CMD_pythonx: + case CMD_ruby: + case CMD_tcl: + ea.arg = p; + if (vim_strchr(line, '\n') == NULL) line = compile_exec(line, &ea, &cctx); - } + else + // heredoc lines have been concatenated with NL + // characters in get_function_body() + line = compile_script(line, &cctx); + break; + + default: + // Not recognized, execute with do_cmdline_cmd(). + ea.arg = p; + line = compile_exec(line, &ea, &cctx); break; } nextline: @@ -9674,6 +9707,7 @@ delete_instr(isn_T *isn) { case ISN_DEF: case ISN_EXEC: + case ISN_EXEC_SPLIT: case ISN_LEGACY_EVAL: case ISN_LOADAUTO: case ISN_LOADB: diff --git a/src/vim9execute.c b/src/vim9execute.c index e870a279c0..1f2f7357e8 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1213,6 +1213,37 @@ get_script_svar(scriptref_T *sref, ectx_T *ectx) return sv; } +/* + * Function passed to do_cmdline() for splitting a script joined by NL + * characters. + */ + static char_u * +get_split_sourceline( + int c UNUSED, + void *cookie, + int indent UNUSED, + getline_opt_T options UNUSED) +{ + source_cookie_T *sp = (source_cookie_T *)cookie; + char_u *p; + char_u *line; + + if (*sp->nextline == NUL) + return NULL; + p = vim_strchr(sp->nextline, '\n'); + if (p == NULL) + { + line = vim_strsave(sp->nextline); + sp->nextline += STRLEN(sp->nextline); + } + else + { + line = vim_strnsave(sp->nextline, p - sp->nextline); + sp->nextline = p + 1; + } + return line; +} + /* * Execute a function by "name". * This can be a builtin function, user function or a funcref. @@ -1425,6 +1456,24 @@ exec_instructions(ectx_T *ectx) } break; + // execute Ex command line split at NL characters. + case ISN_EXEC_SPLIT: + { + source_cookie_T cookie; + + SOURCING_LNUM = iptr->isn_lnum; + CLEAR_FIELD(cookie); + cookie.sourcing_lnum = iptr->isn_lnum - 1; + cookie.nextline = iptr->isn_arg.string; + if (do_cmdline(get_split_sourceline(0, &cookie, 0, 0), + get_split_sourceline, &cookie, + DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED) + == FAIL + || did_emsg) + goto on_error; + } + break; + // Evaluate an expression with legacy syntax, push it onto the // stack. case ISN_LEGACY_EVAL: @@ -4536,6 +4585,9 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) case ISN_EXEC: smsg("%s%4d EXEC %s", pfx, current, iptr->isn_arg.string); break; + case ISN_EXEC_SPLIT: + smsg("%s%4d EXEC_SPLIT %s", pfx, current, iptr->isn_arg.string); + break; case ISN_LEGACY_EVAL: smsg("%s%4d EVAL legacy %s", pfx, current, iptr->isn_arg.string); From 99285550a9957e2c8669f183557944c6513c4875 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sun, 6 Jun 2021 17:12:46 +0200 Subject: [PATCH 32/41] patch 8.2.2952: recover test fails on big endian systems Problem: Recover test fails on big endian systems. Solution: Disable the failing test on big endian systems. (Yegappan Lakshmanan, closes #8335) --- src/testdir/test_recover.vim | 42 ++++++++++++++++++++++++++++++------ src/testdir/test_swap.vim | 2 +- src/version.c | 2 ++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim index 654a0f855a..7e96622d1a 100644 --- a/src/testdir/test_recover.vim +++ b/src/testdir/test_recover.vim @@ -139,7 +139,7 @@ func Test_recover_multiple_swap_files() new Xfile1 call setline(1, ['a', 'b', 'c']) preserve - let b = readblob('.Xfile1.swp') + let b = readblob(swapname('')) call writefile(b, '.Xfile1.swm') call writefile(b, '.Xfile1.swn') call writefile(b, '.Xfile1.swo') @@ -168,6 +168,7 @@ endfunc " Test for :recover using a corrupted swap file func Test_recover_corrupted_swap_file() CheckUnix + " recover using a partial swap file call writefile(0z1234, '.Xfile1.swp') call assert_fails('recover Xfile1', 'E295:') @@ -183,12 +184,41 @@ func Test_recover_corrupted_swap_file() preserve let sn = swapname('') let b = readblob(sn) + let save_b = copy(b) bw! - " clear the B0_MAGIC_LONG field - let b[1008:1011] = 0z00000000 - call writefile(b, sn) - let msg = execute('recover Xfile1') - call assert_match('the file has been damaged', msg) + " Run these tests only on little-endian systems. These tests fail on a + " big-endian system (IBM S390x system). + if b[1008:1011] == 0z33323130 + \ && b[4096:4097] == 0z7470 + \ && b[8192:8193] == 0z6164 + + " clear the B0_MAGIC_LONG field + let b[1008:1011] = 0z00000000 + call writefile(b, sn) + let msg = execute('recover Xfile1') + call assert_match('the file has been damaged', msg) + bw! + + " clear the pointer ID + let b = copy(save_b) + let b[4096:4097] = 0z0000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E310:') + bw! + + " clear the data block ID + let b = copy(save_b) + let b[8192:8193] = 0z0000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + bw! + + " remove the data block + let b = copy(save_b) + call writefile(b[:8191], sn) + call assert_fails('recover Xfile1', 'E312:') + endif + bw! call delete(sn) endfunc diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index 52eb62e729..90afb4d6f0 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -487,7 +487,7 @@ endfunc func Test_missing_swap_file() CheckUnix new Xfile1 - call delete('.Xfile1.swp') + call delete(swapname('')) call assert_fails('file Xfile2', 'E301:') call assert_equal('Xfile2', bufname()) call assert_true(bufexists('Xfile1')) diff --git a/src/version.c b/src/version.c index f995518798..59cd0ce949 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2952, /**/ 2951, /**/ From 518df27ebe23033a25304d3826187c27bfa53c01 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 6 Jun 2021 17:34:13 +0200 Subject: [PATCH 33/41] patch 8.2.2953: Vim9: leaking memory when using heredoc script Problem: Vim9: leaking memory when using heredoc script. Solution: Free the first line. --- src/version.c | 2 ++ src/vim9execute.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/version.c b/src/version.c index 59cd0ce949..1e9a787e9b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2953, /**/ 2952, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 1f2f7357e8..5a8a112a6a 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1460,17 +1460,23 @@ exec_instructions(ectx_T *ectx) case ISN_EXEC_SPLIT: { source_cookie_T cookie; + char_u *line; SOURCING_LNUM = iptr->isn_lnum; CLEAR_FIELD(cookie); cookie.sourcing_lnum = iptr->isn_lnum - 1; cookie.nextline = iptr->isn_arg.string; - if (do_cmdline(get_split_sourceline(0, &cookie, 0, 0), + line = get_split_sourceline(0, &cookie, 0, 0); + if (do_cmdline(line, get_split_sourceline, &cookie, DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED) == FAIL || did_emsg) + { + vim_free(line); goto on_error; + } + vim_free(line); } break; From 6db7b6375a3ea3afef5295b1366896902012e640 Mon Sep 17 00:00:00 2001 From: Brennon M Date: Sun, 6 Jun 2021 20:15:53 +0200 Subject: [PATCH 34/41] patch 8.2.2954: short file name extension for Scala not recognized Problem: Short file name extension for Scala not recognized. Solution: Recognize *.sc. (closes #8337) --- runtime/filetype.vim | 2 +- src/testdir/test_filetype.vim | 2 +- src/version.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index b1eb2ecbea..8ca6f6a77b 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1496,7 +1496,7 @@ au BufNewFile,BufRead *.sass setf sass au BufNewFile,BufRead *.sa setf sather " Scala -au BufNewFile,BufRead *.scala setf scala +au BufNewFile,BufRead *.scala,*.sc setf scala " SBT - Scala Build Tool au BufNewFile,BufRead *.sbt setf sbt diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 1b07b0e616..ac227fee17 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -423,7 +423,7 @@ let s:filename_checks = { \ 'sass': ['file.sass'], \ 'sather': ['file.sa'], \ 'sbt': ['file.sbt'], - \ 'scala': ['file.scala'], + \ 'scala': ['file.scala', 'file.sc'], \ 'scheme': ['file.scm', 'file.ss', 'file.rkt'], \ 'scilab': ['file.sci', 'file.sce'], \ 'screen': ['.screenrc', 'screenrc'], diff --git a/src/version.c b/src/version.c index 1e9a787e9b..f9529abc1d 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2954, /**/ 2953, /**/ From e729ce294f9756165020ad86e3b98b4112e1a6ab Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 6 Jun 2021 21:38:09 +0200 Subject: [PATCH 35/41] patch 8.2.2955: Vim9: using filter in compiled command does not work Problem: Vim9: using filter in compiled command does not work. Solution: Generate EXEC including the command modifier. --- src/ex_cmds.c | 24 ++++++++++++++++++++++++ src/ex_docmd.c | 10 ++++++++-- src/proto/ex_cmds.pro | 1 + src/testdir/test_vim9_cmd.vim | 8 ++++++++ src/version.c | 2 ++ src/vim9compile.c | 23 ++++++++++++++++++++--- 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index e1497a5a4a..614d41d69f 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -5277,6 +5277,16 @@ ex_drop(exarg_T *eap) */ char_u * skip_vimgrep_pat(char_u *p, char_u **s, int *flags) +{ + return skip_vimgrep_pat_ext(p, s, flags, NULL, NULL); +} + +/* + * As skip_vimgrep_pat() and store the character overwritten by NUL in "cp" + * and the pointer to it in "nulp". + */ + char_u * +skip_vimgrep_pat_ext(char_u *p, char_u **s, int *flags, char_u **nulp, int *cp) { int c; @@ -5287,7 +5297,14 @@ skip_vimgrep_pat(char_u *p, char_u **s, int *flags) *s = p; p = skiptowhite(p); if (s != NULL && *p != NUL) + { + if (nulp != NULL) + { + *nulp = p; + *cp = *p; + } *p++ = NUL; + } } else { @@ -5301,7 +5318,14 @@ skip_vimgrep_pat(char_u *p, char_u **s, int *flags) // Truncate the pattern. if (s != NULL) + { + if (nulp != NULL) + { + *nulp = p; + *cp = *p; + } *p = NUL; + } ++p; // Find the flags diff --git a/src/ex_docmd.c b/src/ex_docmd.c index fbf2c7d0dd..4aaccb593f 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2881,7 +2881,9 @@ parse_command_modifiers( case 'f': // only accept ":filter {pat} cmd" { - char_u *reg_pat; + char_u *reg_pat; + char_u *nulp = NULL; + int c = 0; if (!checkforcmd_noparen(&p, "filter", 4) || *p == NUL || ends_excmd(*p)) @@ -2902,7 +2904,8 @@ parse_command_modifiers( p = skip_vimgrep_pat(p, NULL, NULL); else // NOTE: This puts a NUL after the pattern. - p = skip_vimgrep_pat(p, ®_pat, NULL); + p = skip_vimgrep_pat_ext(p, ®_pat, NULL, + &nulp, &c); if (p == NULL || *p == NUL) break; if (!skip_only) @@ -2911,6 +2914,9 @@ parse_command_modifiers( vim_regcomp(reg_pat, RE_MAGIC); if (cmod->cmod_filter_regmatch.regprog == NULL) break; + // restore the character overwritten by NUL + if (nulp != NULL) + *nulp = c; } eap->cmd = p; continue; diff --git a/src/proto/ex_cmds.pro b/src/proto/ex_cmds.pro index 1711af4537..c083cec5cc 100644 --- a/src/proto/ex_cmds.pro +++ b/src/proto/ex_cmds.pro @@ -39,5 +39,6 @@ int prepare_tagpreview(int undo_sync, int use_previewpopup, use_popup_T use_popu void ex_smile(exarg_T *eap); void ex_drop(exarg_T *eap); char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags); +char_u *skip_vimgrep_pat_ext(char_u *p, char_u **s, int *flags, char_u **nulp, int *cp); void ex_oldfiles(exarg_T *eap); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 8481ecc595..23c5cfacf6 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -534,6 +534,14 @@ def Test_command_modifier_filter() assert_equal(execute('filter /piyo/ registers abc'), expected) END CheckDefAndScriptSuccess(lines) + + # also do this compiled + lines =<< trim END + @a = 'very specific z3d37dh234 string' + filter z3d37dh234 registers + assert_match('very specific z3d37dh234 string', Screenline(&lines)) + END + CheckDefAndScriptSuccess(lines) enddef def Test_win_command_modifiers() diff --git a/src/version.c b/src/version.c index f9529abc1d..4dc6bd523b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2955, /**/ 2954, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 0c73433d5f..1256bfaac4 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -8536,13 +8536,30 @@ compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx) static char_u * compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx) { - char_u *p; - int has_expr = FALSE; - char_u *nextcmd = (char_u *)""; + char_u *p; + int has_expr = FALSE; + char_u *nextcmd = (char_u *)""; if (cctx->ctx_skip == SKIP_YES) goto theend; + // If there was a prececing command modifier, drop it and include it in the + // EXEC command. + if (cctx->ctx_has_cmdmod) + { + garray_T *instr = &cctx->ctx_instr; + isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; + + if (isn->isn_type == ISN_CMDMOD) + { + vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod + ->cmod_filter_regmatch.regprog); + vim_free(isn->isn_arg.cmdmod.cf_cmdmod); + --instr->ga_len; + cctx->ctx_has_cmdmod = FALSE; + } + } + if (eap->cmdidx >= 0 && eap->cmdidx < CMD_SIZE) { long argt = eap->argt; From f05d2fc539c389c3b8142d9fb06fb0443de14902 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 6 Jun 2021 22:02:16 +0200 Subject: [PATCH 36/41] patch 8.2.2956: Vim9: need to plan for future additions Problem: Vim9: need to plan for future additions. Solution: Reserve commands for future use: :type, :class, :enum. --- src/ex_cmdidxs.h | 54 ++++++++++++++++++++++++------------------------ src/ex_cmds.h | 15 ++++++++++++++ src/version.c | 2 ++ 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h index 2696128af7..76b6dff052 100644 --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -8,29 +8,29 @@ static const unsigned short cmdidxs1[26] = /* a */ 0, /* b */ 19, /* c */ 43, - /* d */ 109, - /* e */ 134, - /* f */ 158, - /* g */ 175, - /* h */ 181, - /* i */ 190, - /* j */ 209, - /* k */ 211, - /* l */ 216, - /* m */ 279, - /* n */ 297, - /* o */ 317, - /* p */ 329, - /* q */ 368, - /* r */ 371, - /* s */ 391, - /* t */ 460, - /* u */ 505, - /* v */ 516, - /* w */ 537, - /* x */ 551, - /* y */ 561, - /* z */ 562 + /* d */ 110, + /* e */ 135, + /* f */ 162, + /* g */ 179, + /* h */ 185, + /* i */ 194, + /* j */ 213, + /* k */ 215, + /* l */ 220, + /* m */ 283, + /* n */ 301, + /* o */ 321, + /* p */ 333, + /* q */ 372, + /* r */ 375, + /* s */ 395, + /* t */ 464, + /* u */ 510, + /* v */ 521, + /* w */ 542, + /* x */ 556, + /* y */ 566, + /* z */ 567 }; /* @@ -43,9 +43,9 @@ static const unsigned char cmdidxs2[26][26] = { /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 }, /* b */ { 2, 0, 0, 5, 6, 8, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 23, 0, 0, 0 }, - /* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 56, 58, 59, 60, 0, 62, 0, 65, 0, 0, 0 }, + /* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 38, 41, 47, 57, 59, 60, 61, 0, 63, 0, 66, 0, 0, 0 }, /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 8, 18, 0, 19, 0, 0, 20, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0 }, - /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 11, 0, 0, 0, 0, 0, 0, 0, 18, 0, 19, 0, 0 }, + /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 11, 0, 0, 0, 0, 0, 0, 0, 21, 0, 22, 0, 0 }, /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0 }, /* g */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 4, 5, 0, 0, 0, 0 }, /* h */ { 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -60,7 +60,7 @@ static const unsigned char cmdidxs2[26][26] = /* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 }, /* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 50, 0, 51, 0, 63, 64, 0, 65, 0 }, - /* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 28, 0, 29, 33, 36, 38, 39, 0, 40, 42, 0, 43, 0, 0, 0, 0, 0 }, + /* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 28, 0, 29, 33, 36, 38, 39, 0, 40, 42, 0, 43, 0, 0, 0, 45, 0 }, /* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* v */ { 1, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 12, 15, 0, 0, 0, 0, 18, 0, 19, 0, 0, 0, 0, 0 }, /* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 12, 13, 0, 0, 0, 0 }, @@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] = /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const int command_count = 579; +static const int command_count = 584; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index aee2e6f72e..8a1ed5ed68 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -344,6 +344,9 @@ EXCMD(CMD_clist, "clist", qf_list, EXCMD(CMD_clast, "clast", ex_cc, EX_RANGE|EX_COUNT|EX_TRLBAR|EX_BANG, ADDR_UNSIGNED), +EXCMD(CMD_class, "class", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_close, "close", ex_close, EX_BANG|EX_RANGE|EX_COUNT|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_WINDOWS), @@ -548,9 +551,15 @@ EXCMD(CMD_emenu, "emenu", ex_emenu, EXCMD(CMD_endif, "endif", ex_endif, EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), +EXCMD(CMD_endclass, "endclass", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_enddef, "enddef", ex_endfunction, EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), +EXCMD(CMD_endenum, "endenum", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_endfunction, "endfunction", ex_endfunction, EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), @@ -566,6 +575,9 @@ EXCMD(CMD_endwhile, "endwhile", ex_endwhile, EXCMD(CMD_enew, "enew", ex_edit, EX_BANG|EX_TRLBAR, ADDR_NONE), +EXCMD(CMD_enum, "enum", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_eval, "eval", ex_eval, EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), @@ -1625,6 +1637,9 @@ EXCMD(CMD_tunmenu, "tunmenu", ex_menu, EXCMD(CMD_tunmap, "tunmap", ex_unmap, EX_EXTRA|EX_TRLBAR|EX_NOTRLCOM|EX_CTRLV|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), +EXCMD(CMD_type, "type", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_undo, "undo", ex_undo, EX_RANGE|EX_COUNT|EX_ZEROR|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_OTHER), diff --git a/src/version.c b/src/version.c index 4dc6bd523b..b64839e5cd 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2956, /**/ 2955, /**/ From 3a7503c34c65ed15cc08deb5b54aaf2ea51525b4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 7 Jun 2021 18:29:17 +0200 Subject: [PATCH 37/41] patch 8.2.2957: using getchar() in Vim9 script is problematic Problem: Using getchar() in Vim9 script is problematic. Solution: Add getcharstr(). (closes #8343) --- runtime/doc/eval.txt | 19 ++++++++++++++- src/evalfunc.c | 4 +++- src/getchar.c | 42 +++++++++++++++++++++++++++++++--- src/proto/getchar.pro | 1 + src/testdir/test_functions.vim | 7 ++++++ src/version.c | 2 ++ 6 files changed, 70 insertions(+), 5 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 890943810d..97585ad6c5 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2594,10 +2594,12 @@ getbufline({expr}, {lnum} [, {end}]) getbufvar({expr}, {varname} [, {def}]) any variable {varname} in buffer {expr} getchangelist([{expr}]) List list of change list items -getchar([expr]) Number get one character from the user +getchar([expr]) Number or String + get one character from the user getcharmod() Number modifiers for the last typed character getcharpos({expr}) List position of cursor, mark, etc. getcharsearch() Dict last character search +getcharstr([expr]) String get one character from the user getcmdline() String return the current command-line getcmdpos() Number return cursor position in command-line getcmdtype() String return current command-line type @@ -5232,6 +5234,7 @@ getchar([expr]) *getchar()* Return zero otherwise. If [expr] is 1, only check if a character is available, it is not consumed. Return zero if no character available. + If you prefer always getting a string use |getcharstr()|. Without [expr] and when [expr] is 0 a whole character or special key is returned. If it is a single character, the @@ -5357,6 +5360,20 @@ getcharsearch() *getcharsearch()* :nnoremap , getcharsearch().forward ? ',' : ';' < Also see |setcharsearch()|. + +getcharstr([expr]) *getcharstr()* + Get a single character from the user or input stream as a + string. + If [expr] is omitted, wait until a character is available. + If [expr] is 0 or false, only get a character when one is + available. Return an empty string otherwise. + If [expr] is 1 or true, only check if a character is + available, it is not consumed. Return an empty string + if no character is available. + Otherwise this works like |getchar()|, except that a number + result is converted to a string. + + getcmdline() *getcmdline()* Return the current command-line. Only works when the command line is being edited, thus requires use of |c_CTRL-\_e| or diff --git a/src/evalfunc.c b/src/evalfunc.c index 07f158d6d7..d08cf43d82 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -945,13 +945,15 @@ static funcentry_T global_functions[] = {"getchangelist", 0, 1, FEARG_1, NULL, ret_list_any, f_getchangelist}, {"getchar", 0, 1, 0, NULL, - ret_number, f_getchar}, + ret_any, f_getchar}, {"getcharmod", 0, 0, 0, NULL, ret_number, f_getcharmod}, {"getcharpos", 1, 1, FEARG_1, NULL, ret_list_number, f_getcharpos}, {"getcharsearch", 0, 0, 0, NULL, ret_dict_any, f_getcharsearch}, + {"getcharstr", 0, 1, 0, NULL, + ret_string, f_getcharstr}, {"getcmdline", 0, 0, 0, NULL, ret_string, f_getcmdline}, {"getcmdpos", 0, 0, 0, NULL, diff --git a/src/getchar.c b/src/getchar.c index 185b73bdb0..3b069c4386 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -2016,10 +2016,10 @@ char_avail(void) #if defined(FEAT_EVAL) || defined(PROTO) /* - * "getchar()" function + * "getchar()" and "getcharstr()" functions */ - void -f_getchar(typval_T *argvars, typval_T *rettv) + static void +getchar_common(typval_T *argvars, typval_T *rettv) { varnumber_T n; int error = FALSE; @@ -2126,6 +2126,42 @@ f_getchar(typval_T *argvars, typval_T *rettv) } } +/* + * "getchar()" function + */ + void +f_getchar(typval_T *argvars, typval_T *rettv) +{ + getchar_common(argvars, rettv); +} + +/* + * "getcharstr()" function + */ + void +f_getcharstr(typval_T *argvars, typval_T *rettv) +{ + getchar_common(argvars, rettv); + + if (rettv->v_type == VAR_NUMBER) + { + char_u temp[7]; // mbyte-char: 6, NUL: 1 + varnumber_T n = rettv->vval.v_number; + int i = 0; + + if (n != 0) + { + if (has_mbyte) + i += (*mb_char2bytes)(n, temp + i); + else + temp[i++] = n; + } + temp[i++] = NUL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strsave(temp); + } +} + /* * "getcharmod()" function */ diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro index cb8b7507e1..25aef1c01a 100644 --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -46,6 +46,7 @@ int vpeekc_nomap(void); int vpeekc_any(void); int char_avail(void); void f_getchar(typval_T *argvars, typval_T *rettv); +void f_getcharstr(typval_T *argvars, typval_T *rettv); void f_getcharmod(typval_T *argvars, typval_T *rettv); void parse_queued_messages(void); void vungetc(int c); diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 023da66ba1..1309554395 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -1729,6 +1729,13 @@ endfunc func Test_getchar() call feedkeys('a', '') call assert_equal(char2nr('a'), getchar()) + call assert_equal(0, getchar(0)) + call assert_equal(0, getchar(1)) + + call feedkeys('a', '') + call assert_equal('a', getcharstr()) + call assert_equal('', getcharstr(0)) + call assert_equal('', getcharstr(1)) call setline(1, 'xxxx') call test_setmouse(1, 3) diff --git a/src/version.c b/src/version.c index b64839e5cd..a1b2c23600 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2957, /**/ 2956, /**/ From f7a023e580c695e86f68228adcf5c9e6ea00a4d5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 7 Jun 2021 18:50:01 +0200 Subject: [PATCH 38/41] patch 8.2.2958: function list test fails Problem: Function list test fails. Solution: Add newly added function to the list. Fix typo. --- runtime/doc/usr_41.txt | 1 + src/testdir/test_function_lists.vim | 2 +- src/version.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index f34891a905..0d66d2bb67 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -952,6 +952,7 @@ Interactive: *interactive-functions* browsedir() put up a directory requester confirm() let the user make a choice getchar() get a character from the user + getcharstr() get a character from the user as a string getcharmod() get modifiers for the last typed character getmousepos() get last known mouse position echoraw() output characters as-is diff --git a/src/testdir/test_function_lists.vim b/src/testdir/test_function_lists.vim index 7bf8d4d2fc..59180e3294 100644 --- a/src/testdir/test_function_lists.vim +++ b/src/testdir/test_function_lists.vim @@ -96,7 +96,7 @@ func Test_function_lists() sort u w! ++ff=unix Xfunction-list let l:unequal = assert_equalfile("Xsorted_current_global_functions", "Xfunction-list", - \ "\":help functions-list\" incomplete") + \ "\":help function-list\" incomplete") if l:unequal && executable("diff") call system("diff -u Xsorted_current_global_functions Xfunction-list > Xfunction-list.diff") endif diff --git a/src/version.c b/src/version.c index a1b2c23600..e39ee98fc6 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2958, /**/ 2957, /**/ From 2f9c209ba089d81fd727122bbe0ae1da00585d80 Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Mon, 7 Jun 2021 20:28:45 +0200 Subject: [PATCH 39/41] patch 8.2.2959: sound_playfile() is not tested on MS-Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: sound_playfile() is not tested on MS-Windows. Solution: Make it work and enable the test. (Dominique PellĂ©, closes #8338) --- src/sound.c | 5 ++--- src/testdir/test_sound.vim | 20 +++++++++----------- src/version.c | 2 ++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sound.c b/src/sound.c index 9d91f6c086..702fd257a7 100644 --- a/src/sound.c +++ b/src/sound.c @@ -355,10 +355,9 @@ f_sound_playevent(typval_T *argvars, typval_T *rettv) if (wp == NULL) return; - PlaySoundW(wp, NULL, SND_ASYNC | SND_ALIAS); + if (PlaySoundW(wp, NULL, SND_ASYNC | SND_ALIAS)) + rettv->vval.v_number = ++sound_id; free(wp); - - rettv->vval.v_number = ++sound_id; } void diff --git a/src/testdir/test_sound.vim b/src/testdir/test_sound.vim index cc01bf6a74..ff58262bff 100644 --- a/src/testdir/test_sound.vim +++ b/src/testdir/test_sound.vim @@ -75,17 +75,15 @@ func Test_play_silent() endfunc func Test_play_event_error() - " Do not run test on Windows as: - " - playing event with callback is not supported on Windows. - " - FIXME: even without callback, sound_playevent('') does not return 0 on Windows. Bug? - CheckNotMSWindows - - call assert_equal(0, sound_playevent('')) - call assert_equal(0, sound_playevent(test_null_string())) - call assert_equal(0, sound_playevent('doesnotexist')) - call assert_equal(0, sound_playevent('doesnotexist', 'doesnotexist')) - call assert_equal(0, sound_playevent(test_null_string(), test_null_string())) - call assert_equal(0, sound_playevent(test_null_string(), test_null_function())) + " FIXME: sound_playevent() doesn't return 0 in case of error on Windows. + if !has('win32') + call assert_equal(0, sound_playevent('')) + call assert_equal(0, sound_playevent(test_null_string())) + call assert_equal(0, sound_playevent('doesnotexist')) + call assert_equal(0, sound_playevent('doesnotexist', 'doesnotexist')) + call assert_equal(0, sound_playevent(test_null_string(), test_null_string())) + call assert_equal(0, sound_playevent(test_null_string(), test_null_function())) + endif call assert_equal(0, sound_playfile('')) call assert_equal(0, sound_playfile(test_null_string())) diff --git a/src/version.c b/src/version.c index e39ee98fc6..13a5200470 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2959, /**/ 2958, /**/ From 8cf02e5cf8fb14a5009f12e7af0a47617a0ce88d Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Mon, 7 Jun 2021 20:41:22 +0200 Subject: [PATCH 40/41] patch 8.2.2960: swap file recovery not sufficiently tested Problem: Swap file recovery not sufficiently tested. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #8339) --- src/testdir/test_recover.vim | 100 +++++++++++++++++++++++++++++++++++ src/version.c | 2 + 2 files changed, 102 insertions(+) diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim index 7e96622d1a..63225f31d9 100644 --- a/src/testdir/test_recover.vim +++ b/src/testdir/test_recover.vim @@ -146,6 +146,16 @@ func Test_recover_multiple_swap_files() %bw! call feedkeys(":recover Xfile1\3\q", 'xt') call assert_equal(['a', 'b', 'c'], getline(1, '$')) + " try using out-of-range number to select a swap file + bw! + call feedkeys(":recover Xfile1\4\q", 'xt') + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) + bw! + call feedkeys(":recover Xfile1\0\q", 'xt') + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) + bw! call delete('.Xfile1.swm') call delete('.Xfile1.swn') @@ -166,6 +176,8 @@ func Test_recover_empty_swap_file() endfunc " Test for :recover using a corrupted swap file +" Refer to the comments in the memline.c file for the swap file headers +" definition. func Test_recover_corrupted_swap_file() CheckUnix @@ -197,6 +209,18 @@ func Test_recover_corrupted_swap_file() call writefile(b, sn) let msg = execute('recover Xfile1') call assert_match('the file has been damaged', msg) + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) + bw! + + " reduce the page size + let b = copy(save_b) + let b[12:15] = 0z00010000 + call writefile(b, sn) + let msg = execute('recover Xfile1') + call assert_match('page size is smaller than minimum value', msg) + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) bw! " clear the pointer ID @@ -204,6 +228,26 @@ func Test_recover_corrupted_swap_file() let b[4096:4097] = 0z0000 call writefile(b, sn) call assert_fails('recover Xfile1', 'E310:') + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) + bw! + + " set the number of pointers in a pointer block to zero + let b = copy(save_b) + let b[4098:4099] = 0z0000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???EMPTY BLOCK'], getline(1, '$')) + bw! + + " set the block number in a pointer entry to a negative number + let b = copy(save_b) + let b[4104:4111] = 0z00000000.00000080 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???LINES MISSING'], getline(1, '$')) bw! " clear the data block ID @@ -211,12 +255,45 @@ func Test_recover_corrupted_swap_file() let b[8192:8193] = 0z0000 call writefile(b, sn) call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???BLOCK MISSING'], getline(1, '$')) + bw! + + " set the number of lines in the data block to zero + let b = copy(save_b) + let b[8208:8211] = 0z00000000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['??? from here until ???END lines may have been inserted/deleted', + \ '???END'], getline(1, '$')) + bw! + + " use an invalid text start for the lines in a data block + let b = copy(save_b) + let b[8216:8219] = 0z00000000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???'], getline(1, '$')) + bw! + + " use an incorrect text end (db_txt_end) for the data block + let b = copy(save_b) + let b[8204:8207] = 0z80000000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['??? from here until ???END lines may be messed up', '', + \ '???END'], getline(1, '$')) bw! " remove the data block let b = copy(save_b) call writefile(b[:8191], sn) call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???MANY LINES MISSING'], getline(1, '$')) endif bw! @@ -290,4 +367,27 @@ func Test_recover_unmodified_file() call delete('.Xfile1.swz') endfunc +" Test for recovering a file when editing a symbolically linked file +func Test_recover_symbolic_link() + CheckUnix + call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1') + silent !ln -s Xfile1 Xfile2 + edit Xfile2 + call assert_equal('.Xfile1.swp', fnamemodify(swapname(''), ':t')) + preserve + let b = readblob('.Xfile1.swp') + %bw! + call writefile([], 'Xfile1') + call writefile(b, '.Xfile1.swp') + silent! recover Xfile2 + call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$')) + call assert_true(&modified) + update + %bw! + call assert_equal(['aaa', 'bbb', 'ccc'], readfile('Xfile1')) + call delete('Xfile1') + call delete('Xfile2') + call delete('.Xfile1.swp') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 13a5200470..e7aa583508 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2960, /**/ 2959, /**/ From c41badb748bbaa78cbadfcda9ca965e8a283fb9b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 7 Jun 2021 22:04:52 +0200 Subject: [PATCH 41/41] patch 8.2.2961: keys typed during a :normal command are discarded Problem: Keys typed during a :normal command are discarded. Solution: Concatenate saved typeahead and typed kesy. (closes #8340) --- src/debugger.c | 2 +- src/evalfunc.c | 2 +- src/ex_docmd.c | 2 +- src/getchar.c | 5 +++-- src/proto/getchar.pro | 2 +- src/proto/ui.pro | 2 +- src/ui.c | 16 +++++++++++++--- src/version.c | 2 ++ 8 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/debugger.c b/src/debugger.c index 6f52e984d1..9c3c4a178c 100644 --- a/src/debugger.c +++ b/src/debugger.c @@ -140,7 +140,7 @@ do_debug(char_u *cmd) if (typeahead_saved) { - restore_typeahead(&typeaheadbuf); + restore_typeahead(&typeaheadbuf, TRUE); ignore_script = save_ignore_script; } ex_normal_busy = save_ex_normal_busy; diff --git a/src/evalfunc.c b/src/evalfunc.c index d08cf43d82..97f7b61070 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5873,7 +5873,7 @@ f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv) { --ga_userinput.ga_len; restore_typeahead((tasave_T *)(ga_userinput.ga_data) - + ga_userinput.ga_len); + + ga_userinput.ga_len, TRUE); // default return is zero == OK } else if (p_verbose > 1) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 4aaccb593f..25ec9c3fdb 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -8249,7 +8249,7 @@ save_current_state(save_state_T *sst) restore_current_state(save_state_T *sst) { // Restore the previous typeahead. - restore_typeahead(&sst->tabuf); + restore_typeahead(&sst->tabuf, FALSE); msg_scroll = sst->save_msg_scroll; restart_edit = sst->save_restart_edit; diff --git a/src/getchar.c b/src/getchar.c index 3b069c4386..149bf55a0a 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -1414,9 +1414,10 @@ save_typeahead(tasave_T *tp) /* * Restore the typeahead to what it was before calling save_typeahead(). * The allocated memory is freed, can only be called once! + * When "overwrite" is FALSE input typed later is kept. */ void -restore_typeahead(tasave_T *tp) +restore_typeahead(tasave_T *tp, int overwrite UNUSED) { if (tp->typebuf_valid) { @@ -1432,7 +1433,7 @@ restore_typeahead(tasave_T *tp) free_buff(&readbuf2); readbuf2 = tp->save_readbuf2; # ifdef USE_INPUT_BUF - set_input_buf(tp->save_inputbuf); + set_input_buf(tp->save_inputbuf, overwrite); # endif } diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro index 25aef1c01a..5f07ad6c2a 100644 --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -32,7 +32,7 @@ int typebuf_maplen(void); void del_typebuf(int len, int offset); int save_typebuf(void); void save_typeahead(tasave_T *tp); -void restore_typeahead(tasave_T *tp); +void restore_typeahead(tasave_T *tp, int overwrite); void openscript(char_u *name, int directly); void close_all_scripts(void); int using_script(void); diff --git a/src/proto/ui.pro b/src/proto/ui.pro index e75be32b97..f44bad1d65 100644 --- a/src/proto/ui.pro +++ b/src/proto/ui.pro @@ -19,7 +19,7 @@ int vim_is_input_buf_empty(void); int vim_free_in_input_buf(void); int vim_used_in_input_buf(void); char_u *get_input_buf(void); -void set_input_buf(char_u *p); +void set_input_buf(char_u *p, int overwrite); void add_to_input_buf(char_u *s, int len); void add_to_input_buf_csi(char_u *str, int len); void trash_input_buf(void); diff --git a/src/ui.c b/src/ui.c index a42393732f..65ac626d2f 100644 --- a/src/ui.c +++ b/src/ui.c @@ -810,9 +810,10 @@ get_input_buf(void) /* * Restore the input buffer with a pointer returned from get_input_buf(). * The allocated memory is freed, this only works once! + * When "overwrite" is FALSE input typed later is kept. */ void -set_input_buf(char_u *p) +set_input_buf(char_u *p, int overwrite) { garray_T *gap = (garray_T *)p; @@ -820,8 +821,17 @@ set_input_buf(char_u *p) { if (gap->ga_data != NULL) { - mch_memmove(inbuf, gap->ga_data, gap->ga_len); - inbufcount = gap->ga_len; + if (overwrite || inbufcount + gap->ga_len >= INBUFLEN) + { + mch_memmove(inbuf, gap->ga_data, gap->ga_len); + inbufcount = gap->ga_len; + } + else + { + mch_memmove(inbuf + gap->ga_len, inbuf, inbufcount); + mch_memmove(inbuf, gap->ga_data, gap->ga_len); + inbufcount += gap->ga_len; + } vim_free(gap->ga_data); } vim_free(gap); diff --git a/src/version.c b/src/version.c index e7aa583508..bbf13dddf5 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2961, /**/ 2960, /**/