From effed9315c6c5a35fc2824b90da4af753c7a02dc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 14 Aug 2018 13:38:17 +0200 Subject: [PATCH 01/35] patch 8.1.0281: parsing command modifiers is not separated Problem: Parsing command modifiers is not separated. Solution: Move command modifier parsing to a separate function. --- src/ex_cmds.h | 6 + src/ex_docmd.c | 505 +++++++++++++++++++++-------------------- src/feature.h | 4 + src/globals.h | 3 +- src/proto/ex_docmd.pro | 1 + src/version.c | 2 + 6 files changed, 276 insertions(+), 245 deletions(-) diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 045bfcb203..187efea232 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1791,6 +1791,12 @@ struct exarg void *cookie; /* argument for getline() */ #ifdef FEAT_EVAL struct condstack *cstack; /* condition stack for ":if" etc. */ +#endif + long verbose_save; // saved value of p_verbose + int save_msg_silent; // saved value of msg_silent + int did_esilent; // how many times emsg_silent was incremented +#ifdef HAVE_SANDBOX + int did_sandbox; // when TRUE did ++sandbox #endif }; diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 51aa068885..9491e235d9 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -1709,13 +1709,7 @@ do_one_cmd( char_u *errormsg = NULL; /* error message */ char_u *after_modifier = NULL; exarg_T ea; /* Ex command arguments */ - long verbose_save = -1; int save_msg_scroll = msg_scroll; - int save_msg_silent = -1; - int did_esilent = 0; -#ifdef HAVE_SANDBOX - int did_sandbox = FALSE; -#endif cmdmod_T save_cmdmod; int ni; /* set when Not Implemented */ char_u *cmd; @@ -1742,7 +1736,6 @@ do_one_cmd( * recursive calls. */ save_cmdmod = cmdmod; - vim_memset(&cmdmod, 0, sizeof(cmdmod)); /* "#!anything" is handled like a comment. */ if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') @@ -1750,228 +1743,18 @@ do_one_cmd( /* * Repeat until no more command modifiers are found. + * The "ea" structure holds the arguments that can be used. */ ea.cmd = *cmdlinep; - for (;;) - { -/* - * 1. Skip comment lines and leading white space and colons. - */ - while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':') - ++ea.cmd; - - /* in ex mode, an empty line works like :+ */ - if (*ea.cmd == NUL && exmode_active - && (getline_equal(fgetline, cookie, getexmodeline) - || getline_equal(fgetline, cookie, getexline)) - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - { - ea.cmd = (char_u *)"+"; - ex_pressedreturn = TRUE; - } - - /* ignore comment and empty lines */ - if (*ea.cmd == '"') - goto doend; - if (*ea.cmd == NUL) - { - ex_pressedreturn = TRUE; - goto doend; - } - -/* - * 2. Handle command modifiers. - */ - p = skip_range(ea.cmd, NULL); - switch (*p) - { - /* When adding an entry, also modify cmd_exists(). */ - case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3)) - break; - cmdmod.split |= WSP_ABOVE; - continue; - - case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) - { - cmdmod.split |= WSP_BELOW; - continue; - } - if (checkforcmd(&ea.cmd, "browse", 3)) - { -#ifdef FEAT_BROWSE_CMD - cmdmod.browse = TRUE; + ea.cmdlinep = cmdlinep; + ea.getline = fgetline; + ea.cookie = cookie; +#ifdef FEAT_EVAL + ea.cstack = cstack; #endif - continue; - } - if (!checkforcmd(&ea.cmd, "botright", 2)) - break; - cmdmod.split |= WSP_BOT; - continue; + if (parse_command_modifiers(&ea, &errormsg) == FAIL) + goto doend; - case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4)) - break; -#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) - cmdmod.confirm = TRUE; -#endif - continue; - - case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) - { - cmdmod.keepmarks = TRUE; - continue; - } - if (checkforcmd(&ea.cmd, "keepalt", 5)) - { - cmdmod.keepalt = TRUE; - continue; - } - if (checkforcmd(&ea.cmd, "keeppatterns", 5)) - { - cmdmod.keeppatterns = TRUE; - continue; - } - if (!checkforcmd(&ea.cmd, "keepjumps", 5)) - break; - cmdmod.keepjumps = TRUE; - continue; - - case 'f': /* only accept ":filter {pat} cmd" */ - { - char_u *reg_pat; - - if (!checkforcmd(&p, "filter", 4) - || *p == NUL || ends_excmd(*p)) - break; - if (*p == '!') - { - cmdmod.filter_force = TRUE; - p = skipwhite(p + 1); - if (*p == NUL || ends_excmd(*p)) - break; - } - p = skip_vimgrep_pat(p, ®_pat, NULL); - if (p == NULL || *p == NUL) - break; - cmdmod.filter_regmatch.regprog = - vim_regcomp(reg_pat, RE_MAGIC); - if (cmdmod.filter_regmatch.regprog == NULL) - break; - ea.cmd = p; - continue; - } - - /* ":hide" and ":hide | cmd" are not modifiers */ - case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3) - || *p == NUL || ends_excmd(*p)) - break; - ea.cmd = p; - cmdmod.hide = TRUE; - continue; - - case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) - { - cmdmod.lockmarks = TRUE; - continue; - } - - if (!checkforcmd(&ea.cmd, "leftabove", 5)) - break; - cmdmod.split |= WSP_ABOVE; - continue; - - case 'n': if (checkforcmd(&ea.cmd, "noautocmd", 3)) - { - if (cmdmod.save_ei == NULL) - { - /* Set 'eventignore' to "all". Restore the - * existing option value later. */ - cmdmod.save_ei = vim_strsave(p_ei); - set_string_option_direct((char_u *)"ei", -1, - (char_u *)"all", OPT_FREE, SID_NONE); - } - continue; - } - if (!checkforcmd(&ea.cmd, "noswapfile", 3)) - break; - cmdmod.noswapfile = TRUE; - continue; - - case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6)) - break; - cmdmod.split |= WSP_BELOW; - continue; - - case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) - { -#ifdef HAVE_SANDBOX - if (!did_sandbox) - ++sandbox; - did_sandbox = TRUE; -#endif - continue; - } - if (!checkforcmd(&ea.cmd, "silent", 3)) - break; - if (save_msg_silent == -1) - save_msg_silent = msg_silent; - ++msg_silent; - if (*ea.cmd == '!' && !VIM_ISWHITE(ea.cmd[-1])) - { - /* ":silent!", but not "silent !cmd" */ - ea.cmd = skipwhite(ea.cmd + 1); - ++emsg_silent; - ++did_esilent; - } - continue; - - case 't': if (checkforcmd(&p, "tab", 3)) - { - long tabnr = get_address(&ea, &ea.cmd, ADDR_TABS, - ea.skip, FALSE, 1); - if (tabnr == MAXLNUM) - cmdmod.tab = tabpage_index(curtab) + 1; - else - { - if (tabnr < 0 || tabnr > LAST_TAB_NR) - { - errormsg = (char_u *)_(e_invrange); - goto doend; - } - cmdmod.tab = tabnr + 1; - } - ea.cmd = p; - continue; - } - if (!checkforcmd(&ea.cmd, "topleft", 2)) - break; - cmdmod.split |= WSP_TOP; - continue; - - case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3)) - break; - if (save_msg_silent == -1) - save_msg_silent = msg_silent; - msg_silent = 0; - continue; - - case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) - { - cmdmod.split |= WSP_VERT; - continue; - } - if (!checkforcmd(&p, "verbose", 4)) - break; - if (verbose_save < 0) - verbose_save = p_verbose; - if (vim_isdigit(*ea.cmd)) - p_verbose = atoi((char *)ea.cmd); - else - p_verbose = 1; - ea.cmd = p; - continue; - } - break; - } after_modifier = ea.cmd; #ifdef FEAT_EVAL @@ -2688,25 +2471,17 @@ do_one_cmd( /* The :try command saves the emsg_silent flag, reset it here when * ":silent! try" was used, it should only apply to :try itself. */ - if (ea.cmdidx == CMD_try && did_esilent > 0) + if (ea.cmdidx == CMD_try && ea.did_esilent > 0) { - emsg_silent -= did_esilent; + emsg_silent -= ea.did_esilent; if (emsg_silent < 0) emsg_silent = 0; - did_esilent = 0; + ea.did_esilent = 0; } /* * 7. Execute the command. - * - * The "ea" structure holds the arguments that can be used. */ - ea.cmdlinep = cmdlinep; - ea.getline = fgetline; - ea.cookie = cookie; -#ifdef FEAT_EVAL - ea.cstack = cstack; -#endif #ifdef FEAT_USR_CMDS if (IS_USER_CMDIDX(ea.cmdidx)) @@ -2775,8 +2550,8 @@ doend: ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); #endif - if (verbose_save >= 0) - p_verbose = verbose_save; + if (ea.verbose_save >= 0) + p_verbose = ea.verbose_save; if (cmdmod.save_ei != NULL) { @@ -2791,13 +2566,13 @@ doend: cmdmod = save_cmdmod; - if (save_msg_silent != -1) + if (ea.save_msg_silent != -1) { /* messages could be enabled for a serious error, need to check if the * counters don't become negative */ - if (!did_emsg || msg_silent > save_msg_silent) - msg_silent = save_msg_silent; - emsg_silent -= did_esilent; + if (!did_emsg || msg_silent > ea.save_msg_silent) + msg_silent = ea.save_msg_silent; + emsg_silent -= ea.did_esilent; if (emsg_silent < 0) emsg_silent = 0; /* Restore msg_scroll, it's set by file I/O commands, even when no @@ -2811,7 +2586,7 @@ doend: } #ifdef HAVE_SANDBOX - if (did_sandbox) + if (ea.did_sandbox) --sandbox; #endif @@ -2828,6 +2603,250 @@ doend: #pragma optimize( "", on ) #endif +/* + * Parse and skip over command modifiers: + * - update eap->cmd + * - store flags in "cmdmod". + * - Set ex_pressedreturn for an empty command line. + * - set msg_silent for ":silent" + * - set p_verbose for ":verbose" + * - Increment "sandbox" for ":sandbox" + * Return FAIL when the command is not to be executed. + * May set "errormsg" to an error message. + */ + int +parse_command_modifiers(exarg_T *eap, char_u **errormsg) +{ + char_u *p; + + vim_memset(&cmdmod, 0, sizeof(cmdmod)); + eap->verbose_save = -1; + eap->save_msg_silent = -1; + + for (;;) + { +/* + * 1. Skip comment lines and leading white space and colons. + */ + while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':') + ++eap->cmd; + + /* in ex mode, an empty line works like :+ */ + if (*eap->cmd == NUL && exmode_active + && (getline_equal(eap->getline, eap->cookie, getexmodeline) + || getline_equal(eap->getline, eap->cookie, getexline)) + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) + { + eap->cmd = (char_u *)"+"; + ex_pressedreturn = TRUE; + } + + /* ignore comment and empty lines */ + if (*eap->cmd == '"') + return FAIL; + if (*eap->cmd == NUL) + { + ex_pressedreturn = TRUE; + return FAIL; + } + +/* + * 2. Handle command modifiers. + */ + p = skip_range(eap->cmd, NULL); + switch (*p) + { + /* When adding an entry, also modify cmd_exists(). */ + case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3)) + break; + cmdmod.split |= WSP_ABOVE; + continue; + + case 'b': if (checkforcmd(&eap->cmd, "belowright", 3)) + { + cmdmod.split |= WSP_BELOW; + continue; + } + if (checkforcmd(&eap->cmd, "browse", 3)) + { +#ifdef FEAT_BROWSE_CMD + cmdmod.browse = TRUE; +#endif + continue; + } + if (!checkforcmd(&eap->cmd, "botright", 2)) + break; + cmdmod.split |= WSP_BOT; + continue; + + case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4)) + break; +#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) + cmdmod.confirm = TRUE; +#endif + continue; + + case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3)) + { + cmdmod.keepmarks = TRUE; + continue; + } + if (checkforcmd(&eap->cmd, "keepalt", 5)) + { + cmdmod.keepalt = TRUE; + continue; + } + if (checkforcmd(&eap->cmd, "keeppatterns", 5)) + { + cmdmod.keeppatterns = TRUE; + continue; + } + if (!checkforcmd(&eap->cmd, "keepjumps", 5)) + break; + cmdmod.keepjumps = TRUE; + continue; + + case 'f': /* only accept ":filter {pat} cmd" */ + { + char_u *reg_pat; + + if (!checkforcmd(&p, "filter", 4) + || *p == NUL || ends_excmd(*p)) + break; + if (*p == '!') + { + cmdmod.filter_force = TRUE; + p = skipwhite(p + 1); + if (*p == NUL || ends_excmd(*p)) + break; + } + p = skip_vimgrep_pat(p, ®_pat, NULL); + if (p == NULL || *p == NUL) + break; + cmdmod.filter_regmatch.regprog = + vim_regcomp(reg_pat, RE_MAGIC); + if (cmdmod.filter_regmatch.regprog == NULL) + break; + eap->cmd = p; + continue; + } + + /* ":hide" and ":hide | cmd" are not modifiers */ + case 'h': if (p != eap->cmd || !checkforcmd(&p, "hide", 3) + || *p == NUL || ends_excmd(*p)) + break; + eap->cmd = p; + cmdmod.hide = TRUE; + continue; + + case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3)) + { + cmdmod.lockmarks = TRUE; + continue; + } + + if (!checkforcmd(&eap->cmd, "leftabove", 5)) + break; + cmdmod.split |= WSP_ABOVE; + continue; + + case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3)) + { + if (cmdmod.save_ei == NULL) + { + /* Set 'eventignore' to "all". Restore the + * existing option value later. */ + cmdmod.save_ei = vim_strsave(p_ei); + set_string_option_direct((char_u *)"ei", -1, + (char_u *)"all", OPT_FREE, SID_NONE); + } + continue; + } + if (!checkforcmd(&eap->cmd, "noswapfile", 3)) + break; + cmdmod.noswapfile = TRUE; + continue; + + case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6)) + break; + cmdmod.split |= WSP_BELOW; + continue; + + case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) + { +#ifdef HAVE_SANDBOX + if (!eap->did_sandbox) + ++sandbox; + eap->did_sandbox = TRUE; +#endif + continue; + } + if (!checkforcmd(&eap->cmd, "silent", 3)) + break; + if (eap->save_msg_silent == -1) + eap->save_msg_silent = msg_silent; + ++msg_silent; + if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1])) + { + /* ":silent!", but not "silent !cmd" */ + eap->cmd = skipwhite(eap->cmd + 1); + ++emsg_silent; + ++eap->did_esilent; + } + continue; + + case 't': if (checkforcmd(&p, "tab", 3)) + { + long tabnr = get_address(eap, &eap->cmd, ADDR_TABS, + eap->skip, FALSE, 1); + if (tabnr == MAXLNUM) + cmdmod.tab = tabpage_index(curtab) + 1; + else + { + if (tabnr < 0 || tabnr > LAST_TAB_NR) + { + *errormsg = (char_u *)_(e_invrange); + return FAIL; + } + cmdmod.tab = tabnr + 1; + } + eap->cmd = p; + continue; + } + if (!checkforcmd(&eap->cmd, "topleft", 2)) + break; + cmdmod.split |= WSP_TOP; + continue; + + case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3)) + break; + if (eap->save_msg_silent == -1) + eap->save_msg_silent = msg_silent; + msg_silent = 0; + continue; + + case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) + { + cmdmod.split |= WSP_VERT; + continue; + } + if (!checkforcmd(&p, "verbose", 4)) + break; + if (eap->verbose_save < 0) + eap->verbose_save = p_verbose; + if (vim_isdigit(*eap->cmd)) + p_verbose = atoi((char *)eap->cmd); + else + p_verbose = 1; + eap->cmd = p; + continue; + } + break; + } + + return OK; +} + /* * Parse the address range, if any, in "eap". * Return FAIL and set "errormsg" or return OK. diff --git a/src/feature.h b/src/feature.h index efe349d54f..6ae3ac23fa 100644 --- a/src/feature.h +++ b/src/feature.h @@ -355,6 +355,10 @@ # endif #endif +#ifdef FEAT_EVAL +# define HAVE_SANDBOX +#endif + /* * +profile Profiling for functions and scripts. */ diff --git a/src/globals.h b/src/globals.h index 58763295a7..09820cfdf2 100644 --- a/src/globals.h +++ b/src/globals.h @@ -678,8 +678,7 @@ EXTERN int allbuf_lock INIT(= 0); * changed, no buffer can be deleted and * current directory can't be changed. * Used for SwapExists et al. */ -#ifdef FEAT_EVAL -# define HAVE_SANDBOX +#ifdef HAVE_SANDBOX EXTERN int sandbox INIT(= 0); /* Non-zero when evaluating an expression in a * "sandbox". Several things are not allowed diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 00800e1ef5..50a2c0c2ad 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -4,6 +4,7 @@ int do_cmdline_cmd(char_u *cmd); int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int), void *cookie, int flags); int getline_equal(char_u *(*fgetline)(int, void *, int), void *cookie, char_u *(*func)(int, void *, int)); void *getline_cookie(char_u *(*fgetline)(int, void *, int), void *cookie); +int parse_command_modifiers(exarg_T *eap, char_u **errormsg); int parse_cmd_address(exarg_T *eap, char_u **errormsg); int checkforcmd(char_u **pp, char *cmd, int len); int modifier_len(char_u *cmd); diff --git a/src/version.c b/src/version.c index 1450992209..8afd943b93 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 281, /**/ 280, /**/ From 33c4dbb74bdf41aadd193a704f597d4df20f0e47 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 14 Aug 2018 16:06:16 +0200 Subject: [PATCH 02/35] patch 8.1.0282: 'incsearch' does not work with command modifiers Problem: 'incsearch' does not work with command modifiers. Solution: Skip command modifiers. --- src/ex_docmd.c | 126 ++++++++++++++++++++++-------------- src/ex_getln.c | 28 ++++---- src/proto/ex_docmd.pro | 2 +- src/testdir/test_search.vim | 6 ++ src/version.c | 2 + 5 files changed, 105 insertions(+), 59 deletions(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 9491e235d9..169cb7a64e 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -68,6 +68,7 @@ static char_u *do_one_cmd(char_u **, int, struct condstack *, char_u *(*fgetline static char_u *do_one_cmd(char_u **, int, char_u *(*fgetline)(int, void *, int), void *cookie); static int if_level = 0; /* depth in :if */ #endif +static void free_cmdmod(void); static void append_command(char_u *cmd); static char_u *find_command(exarg_T *eap, int *full); @@ -1741,10 +1742,11 @@ do_one_cmd( if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') goto doend; - /* - * Repeat until no more command modifiers are found. - * The "ea" structure holds the arguments that can be used. - */ +/* + * 1. Skip comment lines and leading white space and colons. + * 2. Handle command modifiers. + */ + // The "ea" structure holds the arguments that can be used. ea.cmd = *cmdlinep; ea.cmdlinep = cmdlinep; ea.getline = fgetline; @@ -1752,7 +1754,7 @@ do_one_cmd( #ifdef FEAT_EVAL ea.cstack = cstack; #endif - if (parse_command_modifiers(&ea, &errormsg) == FAIL) + if (parse_command_modifiers(&ea, &errormsg, FALSE) == FAIL) goto doend; after_modifier = ea.cmd; @@ -2553,17 +2555,7 @@ doend: if (ea.verbose_save >= 0) p_verbose = ea.verbose_save; - if (cmdmod.save_ei != NULL) - { - /* Restore 'eventignore' to the value before ":noautocmd". */ - set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei, - OPT_FREE, SID_NONE); - free_string_option(cmdmod.save_ei); - } - - if (cmdmod.filter_regmatch.regprog != NULL) - vim_regfree(cmdmod.filter_regmatch.regprog); - + free_cmdmod(); cmdmod = save_cmdmod; if (ea.save_msg_silent != -1) @@ -2609,13 +2601,16 @@ doend: * - store flags in "cmdmod". * - Set ex_pressedreturn for an empty command line. * - set msg_silent for ":silent" + * - set 'eventignore' to "all" for ":noautocmd" * - set p_verbose for ":verbose" * - Increment "sandbox" for ":sandbox" + * When "skip_only" is TRUE the global variables are not changed, except for + * "cmdmod". * Return FAIL when the command is not to be executed. * May set "errormsg" to an error message. */ int -parse_command_modifiers(exarg_T *eap, char_u **errormsg) +parse_command_modifiers(exarg_T *eap, char_u **errormsg, int skip_only) { char_u *p; @@ -2623,11 +2618,9 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) eap->verbose_save = -1; eap->save_msg_silent = -1; + // Repeat until no more command modifiers are found. for (;;) { -/* - * 1. Skip comment lines and leading white space and colons. - */ while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':') ++eap->cmd; @@ -2638,7 +2631,8 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { eap->cmd = (char_u *)"+"; - ex_pressedreturn = TRUE; + if (!skip_only) + ex_pressedreturn = TRUE; } /* ignore comment and empty lines */ @@ -2646,13 +2640,11 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) return FAIL; if (*eap->cmd == NUL) { - ex_pressedreturn = TRUE; + if (!skip_only) + ex_pressedreturn = TRUE; return FAIL; } -/* - * 2. Handle command modifiers. - */ p = skip_range(eap->cmd, NULL); switch (*p) { @@ -2720,13 +2712,20 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) if (*p == NUL || ends_excmd(*p)) break; } - p = skip_vimgrep_pat(p, ®_pat, NULL); + if (skip_only) + p = skip_vimgrep_pat(p, NULL, NULL); + else + // NOTE: This puts a NUL after the pattern. + p = skip_vimgrep_pat(p, ®_pat, NULL); if (p == NULL || *p == NUL) break; - cmdmod.filter_regmatch.regprog = + if (!skip_only) + { + cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC); - if (cmdmod.filter_regmatch.regprog == NULL) - break; + if (cmdmod.filter_regmatch.regprog == NULL) + break; + } eap->cmd = p; continue; } @@ -2752,7 +2751,7 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3)) { - if (cmdmod.save_ei == NULL) + if (cmdmod.save_ei == NULL && !skip_only) { /* Set 'eventignore' to "all". Restore the * existing option value later. */ @@ -2775,23 +2774,32 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) { #ifdef HAVE_SANDBOX - if (!eap->did_sandbox) - ++sandbox; - eap->did_sandbox = TRUE; + if (!skip_only) + { + if (!eap->did_sandbox) + ++sandbox; + eap->did_sandbox = TRUE; + } #endif continue; } if (!checkforcmd(&eap->cmd, "silent", 3)) break; - if (eap->save_msg_silent == -1) - eap->save_msg_silent = msg_silent; - ++msg_silent; + if (!skip_only) + { + if (eap->save_msg_silent == -1) + eap->save_msg_silent = msg_silent; + ++msg_silent; + } if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1])) { /* ":silent!", but not "silent !cmd" */ eap->cmd = skipwhite(eap->cmd + 1); - ++emsg_silent; - ++eap->did_esilent; + if (!skip_only) + { + ++emsg_silent; + ++eap->did_esilent; + } } continue; @@ -2820,9 +2828,12 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3)) break; - if (eap->save_msg_silent == -1) - eap->save_msg_silent = msg_silent; - msg_silent = 0; + if (!skip_only) + { + if (eap->save_msg_silent == -1) + eap->save_msg_silent = msg_silent; + msg_silent = 0; + } continue; case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) @@ -2832,12 +2843,15 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) } if (!checkforcmd(&p, "verbose", 4)) break; - if (eap->verbose_save < 0) - eap->verbose_save = p_verbose; - if (vim_isdigit(*eap->cmd)) - p_verbose = atoi((char *)eap->cmd); - else - p_verbose = 1; + if (!skip_only) + { + if (eap->verbose_save < 0) + eap->verbose_save = p_verbose; + if (vim_isdigit(*eap->cmd)) + p_verbose = atoi((char *)eap->cmd); + else + p_verbose = 1; + } eap->cmd = p; continue; } @@ -2847,6 +2861,24 @@ parse_command_modifiers(exarg_T *eap, char_u **errormsg) return OK; } +/* + * Free contents of "cmdmod". + */ + static void +free_cmdmod(void) +{ + if (cmdmod.save_ei != NULL) + { + /* Restore 'eventignore' to the value before ":noautocmd". */ + set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei, + OPT_FREE, SID_NONE); + free_string_option(cmdmod.save_ei); + } + + if (cmdmod.filter_regmatch.regprog != NULL) + vim_regfree(cmdmod.filter_regmatch.regprog); +} + /* * Parse the address range, if any, in "eap". * Return FAIL and set "errormsg" or return OK. diff --git a/src/ex_getln.c b/src/ex_getln.c index fb16743f0c..a8c5cfb001 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -283,11 +283,24 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, return TRUE; if (firstc == ':') { - char_u *cmd = skip_range(ccline.cmdbuff, NULL); - char_u *p; - int delim; - char_u *end; + char_u *cmd; + cmdmod_T save_cmdmod = cmdmod; + char_u *p; + int delim; + char_u *end; + char_u *dummy; + exarg_T ea; + vim_memset(&ea, 0, sizeof(ea)); + ea.line1 = 1; + ea.line2 = 1; + ea.cmd = ccline.cmdbuff; + ea.addr_type = ADDR_LINES; + + parse_command_modifiers(&ea, &dummy, TRUE); + cmdmod = save_cmdmod; + + cmd = skip_range(ea.cmd, NULL); if (*cmd == 's' || *cmd == 'g' || *cmd == 'v') { // Skip over "substitute" to find the pattern separator. @@ -310,8 +323,6 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, end = skip_regexp(p, delim, p_magic, NULL); if (end > p || *end == delim) { - char_u *dummy; - exarg_T ea; pos_T save_cursor = curwin->w_cursor; // found a non-empty pattern @@ -319,11 +330,6 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, *patlen = (int)(end - p); // parse the address range - vim_memset(&ea, 0, sizeof(ea)); - ea.line1 = 1; - ea.line2 = 1; - ea.cmd = ccline.cmdbuff; - ea.addr_type = ADDR_LINES; curwin->w_cursor = is_state->search_start; parse_cmd_address(&ea, &dummy); if (ea.addr_count > 0) diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 50a2c0c2ad..bfd4f056d8 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -4,7 +4,7 @@ int do_cmdline_cmd(char_u *cmd); int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int), void *cookie, int flags); int getline_equal(char_u *(*fgetline)(int, void *, int), void *cookie, char_u *(*func)(int, void *, int)); void *getline_cookie(char_u *(*fgetline)(int, void *, int), void *cookie); -int parse_command_modifiers(exarg_T *eap, char_u **errormsg); +int parse_command_modifiers(exarg_T *eap, char_u **errormsg, int skip_only); int parse_cmd_address(exarg_T *eap, char_u **errormsg); int checkforcmd(char_u **pp, char *cmd, int len); int modifier_len(char_u *cmd); diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index 8d4b7cc604..851811b199 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -884,6 +884,12 @@ func Test_incsearch_substitute_dump() call VerifyScreenDump(buf, 'Test_incsearch_substitute_05', {}) call term_sendkeys(buf, "\") + " Command modifiers are skipped + call term_sendkeys(buf, ':above below browse botr confirm keepmar keepalt keeppat keepjum filter xxx hide lockm leftabove noau noswap rightbel sandbox silent silent! $tab top unsil vert verbose 4,5s/fo.') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {}) + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) call delete('Xis_subst_script') endfunc diff --git a/src/version.c b/src/version.c index 8afd943b93..d96c6a5d2f 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 282, /**/ 281, /**/ From 80d83c094d52b9983ef316b1a08c314060ca8313 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 14 Aug 2018 17:28:56 +0200 Subject: [PATCH 03/35] patch 8.1.0283: missing test dump Problem: Missing test dump. Solution: Add the dump file --- src/testdir/dumps/Test_incsearch_substitute_06.dump | 9 +++++++++ src/version.c | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 src/testdir/dumps/Test_incsearch_substitute_06.dump diff --git a/src/testdir/dumps/Test_incsearch_substitute_06.dump b/src/testdir/dumps/Test_incsearch_substitute_06.dump new file mode 100644 index 0000000000..8a666208a0 --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_substitute_06.dump @@ -0,0 +1,9 @@ +|f+0&#ffffff0|o@1| |3| @64 +|f+1&&|o@1| +0&&|4| @64 +|f+0&#ffff4012|o@1| +0&#ffffff0|5| @64 +|f|o@1| |6| @64 +|f|o@1| |7| @64 +|f|o@1| |8| @64 +|:|a|b|o|v|e| |b|e|l|o|w| |b|r|o|w|s|e| |b|o|t|r| |c|o|n|f|i|r|m| |k|e@1|p|m|a|r| |k|e@1|p|a|l|t| |k|e@1|p@1|a|t| |k|e@1|p|j|u|m| |f|i|l|t|e +|r| |x@2| |h|i|d|e| |l|o|c|k|m| |l|e|f|t|a|b|o|v|e| |n|o|a|u| |n|o|s|w|a|p| |r|i|g|h|t|b|e|l| |s|a|n|d|b|o|x| |s|i|l|e|n|t| |s|i|l|e|n|t|! +| |$|t|a|b| |t|o|p| |u|n|s|i|l| |v|e|r|t| |v|e|r|b|o|s|e| |4|,|5|s|/|f|o|.> @32 diff --git a/src/version.c b/src/version.c index d96c6a5d2f..005cce6b47 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 283, /**/ 282, /**/ From 2f6a346a4cd2d5bdd6dc9b3209ebce7b6340221d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 14 Aug 2018 18:16:52 +0200 Subject: [PATCH 04/35] patch 8.1.0284: 'cursorline' highlighting wrong with 'incsearch' Problem: 'cursorline' highlighting wrong with 'incsearch'. Solution: Move the cursor back if the match is outside the range. --- src/ex_getln.c | 3 +++ .../dumps/Test_incsearch_substitute_07.dump | 9 +++++++++ .../dumps/Test_incsearch_substitute_08.dump | 9 +++++++++ src/testdir/test_search.vim | 15 +++++++++++++++ src/version.c | 2 ++ 5 files changed, 38 insertions(+) create mode 100644 src/testdir/dumps/Test_incsearch_substitute_07.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_08.dump diff --git a/src/ex_getln.c b/src/ex_getln.c index a8c5cfb001..ba6fe729c7 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -480,8 +480,11 @@ may_do_incsearch_highlighting( if (curwin->w_cursor.lnum < search_first_line || curwin->w_cursor.lnum > search_last_line) + { // match outside of address range i = 0; + curwin->w_cursor = is_state->search_start; + } // if interrupted while searching, behave like it failed if (got_int) diff --git a/src/testdir/dumps/Test_incsearch_substitute_07.dump b/src/testdir/dumps/Test_incsearch_substitute_07.dump new file mode 100644 index 0000000000..7b4dc6e14a --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_substitute_07.dump @@ -0,0 +1,9 @@ +|f+0&#ffffff0|o@1| |4| @64 +|f|o@1| |5| @64 +|f|o@1| |6| @64 +|f|o@1| |7| @64 +|f|o@1| |8| @64 +|f|o@1| |9| @64 +|f|o@1| |1|0| @63 +|b+9&&|a|r| +8&&|1@1| @63 +|:+0&&|9|,|1@1|s|/|b|a|r> @59 diff --git a/src/testdir/dumps/Test_incsearch_substitute_08.dump b/src/testdir/dumps/Test_incsearch_substitute_08.dump new file mode 100644 index 0000000000..d87e507b2e --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_substitute_08.dump @@ -0,0 +1,9 @@ +|f+0&#ffffff0|o@1| |4| @64 +|f|o@1| |5| @64 +|f|o@1| |6| @64 +|f|o@1| |7| @64 +|f|o@1| |8| @64 +|f+8&&|o@1| |9| @64 +|f+0&&|o@1| |1|0| @63 +|b|a|r| |1@1| @63 +|:|9|,|1|0|s|/|b|a|r> @59 diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index 851811b199..a36b4fbcd7 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -839,6 +839,7 @@ func Test_incsearch_substitute_dump() \ 'for n in range(1, 10)', \ ' call setline(n, "foo " . n)', \ 'endfor', + \ 'call setline(11, "bar 11")', \ '3', \ ], 'Xis_subst_script') let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70}) @@ -890,6 +891,20 @@ func Test_incsearch_substitute_dump() call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {}) call term_sendkeys(buf, "\") + " Cursorline highlighting at match + call term_sendkeys(buf, ":set cursorline\") + call term_sendkeys(buf, 'G9G') + call term_sendkeys(buf, ':9,11s/bar') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_substitute_07', {}) + call term_sendkeys(buf, "\") + + " Cursorline highlighting at cursor when no match + call term_sendkeys(buf, ':9,10s/bar') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_substitute_08', {}) + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) call delete('Xis_subst_script') endfunc diff --git a/src/version.c b/src/version.c index 005cce6b47..18051faa37 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 284, /**/ 283, /**/ From d7cc16357083c4fc4271e25fb36c4fbaee99e0f1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 14 Aug 2018 20:18:26 +0200 Subject: [PATCH 05/35] patch 8.1.0285: compiler warning for conversion Problem: Compiler warning for conversion. Solution: Add a type cast. (Mike Williams) --- src/ex_getln.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ex_getln.c b/src/ex_getln.c index ba6fe729c7..d200eab78a 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -580,7 +580,7 @@ may_adjust_incsearch_highlighting( { pat = last_search_pattern(); skiplen = 0; - patlen = STRLEN(pat); + patlen = (int)STRLEN(pat); } else pat = ccline.cmdbuff + skiplen; diff --git a/src/version.c b/src/version.c index 18051faa37..876fcf3358 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 285, /**/ 284, /**/ From 167ae42685dcd430800c51ac7339f7f0938a3e70 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 14 Aug 2018 21:32:21 +0200 Subject: [PATCH 06/35] patch 8.1.0286: 'incsearch' does not apply to :smagic and :snomagic Problem: 'incsearch' does not apply to :smagic and :snomagic. Solution: Add support. (Hirohito Higashi) --- src/ex_getln.c | 10 ++++++++++ src/testdir/test_search.vim | 8 ++++++++ src/version.c | 2 ++ 3 files changed, 20 insertions(+) diff --git a/src/ex_getln.c b/src/ex_getln.c index d200eab78a..4af3904409 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -231,6 +231,7 @@ typedef struct { pos_T match_end; int did_incsearch; int incsearch_postponed; + int magic_save; } incsearch_state_T; static void @@ -239,6 +240,7 @@ init_incsearch_state(incsearch_state_T *is_state) is_state->match_start = curwin->w_cursor; is_state->did_incsearch = FALSE; is_state->incsearch_postponed = FALSE; + is_state->magic_save = p_magic; CLEAR_POS(&is_state->match_end); is_state->save_cursor = curwin->w_cursor; // may be restored later is_state->search_start = curwin->w_cursor; @@ -308,9 +310,16 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, ; if (*skipwhite(p) != NUL && (STRNCMP(cmd, "substitute", p - cmd) == 0 + || STRNCMP(cmd, "smagic", p - cmd) == 0 + || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0 || STRNCMP(cmd, "global", p - cmd) == 0 || STRNCMP(cmd, "vglobal", p - cmd) == 0)) { + if (*cmd == 's' && cmd[1] == 'm') + p_magic = TRUE; + else if (*cmd == 's' && cmd[1] == 'n') + p_magic = FALSE; + // Check for "global!/". if (*cmd == 'g' && *p == '!') { @@ -392,6 +401,7 @@ finish_incsearch_highlighting( update_screen(SOME_VALID); else redraw_all_later(SOME_VALID); + p_magic = is_state->magic_save; } } diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index a36b4fbcd7..90a0a0e3b5 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -384,6 +384,14 @@ func Test_search_cmdline3s() undo call feedkeys(":%substitute/the\/xxx\", 'tx') call assert_equal(' 2 xxxe', getline('.')) + undo + call feedkeys(":%smagic/the.e/xxx\", 'tx') + call assert_equal(' 2 xxx', getline('.')) + undo + call assert_fails(":%snomagic/the.e/xxx\", 'E486') + " + call feedkeys(":%snomagic/the\\.e/xxx\", 'tx') + call assert_equal(' 2 xxx', getline('.')) call Incsearch_cleanup() endfunc diff --git a/src/version.c b/src/version.c index 876fcf3358..23bcbf83e1 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 286, /**/ 285, /**/ From 37b15568c26e669c333903a70422eacc09488f79 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 14 Aug 2018 22:08:25 +0200 Subject: [PATCH 07/35] patch 8.1.0287: MAX is not defined everywhere Problem: MAX is not defined everywhere. Solution: Define MAX where needed. --- src/ex_getln.c | 4 ++++ src/version.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/ex_getln.c b/src/ex_getln.c index 4af3904409..d38fa4b023 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -13,6 +13,10 @@ #include "vim.h" +#ifndef MAX +# define MAX(x,y) ((x) > (y) ? (x) : (y)) +#endif + /* * Variables shared between getcmdline(), redrawcmdline() and others. * These need to be saved when using CTRL-R |, that's why they are in a diff --git a/src/version.c b/src/version.c index 23bcbf83e1..efc214caba 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 287, /**/ 286, /**/ From 396659592fe039decc8c088694912067fe32a681 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 15 Aug 2018 20:59:48 +0200 Subject: [PATCH 08/35] patch 8.1.0288: quickfix code uses cmdidx too often Problem: Quickfix code uses cmdidx too often. Solution: Add is_loclist_cmd(). (Yegappan Lakshmanan) --- src/ex_docmd.c | 14 +++++ src/proto/ex_docmd.pro | 1 + src/quickfix.c | 113 ++++++++++++++++++++--------------------- src/version.c | 2 + 4 files changed, 71 insertions(+), 59 deletions(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 169cb7a64e..14ec213239 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -12529,6 +12529,20 @@ ex_folddo(exarg_T *eap) } #endif +#ifdef FEAT_QUICKFIX +/* + * Returns TRUE if the supplied Ex cmdidx is for a location list command + * instead of a quickfix command. + */ + int +is_loclist_cmd(int cmdidx) +{ + if (cmdidx < 0 || cmdidx > CMD_SIZE) + return FALSE; + return cmdnames[cmdidx].cmd_name[0] == 'l'; +} +#endif + # if defined(FEAT_TIMERS) || defined(PROTO) int get_pressedreturn(void) diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index bfd4f056d8..04bc0c3abd 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -70,6 +70,7 @@ char_u *get_behave_arg(expand_T *xp, int idx); char_u *get_messages_arg(expand_T *xp, int idx); char_u *get_mapclear_arg(expand_T *xp, int idx); void set_no_hlsearch(int flag); +int is_loclist_cmd(int cmdidx); int get_pressedreturn(void); void set_pressedreturn(int val); /* vim: set ft=c : */ diff --git a/src/quickfix.c b/src/quickfix.c index ac40b24dd3..8cfec6c704 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -3330,7 +3330,7 @@ qf_list(exarg_T *eap) recognised errors */ qf_info_T *qi = &ql_info; - if (eap->cmdidx == CMD_llist) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -3478,7 +3478,7 @@ qf_age(exarg_T *eap) qf_info_T *qi = &ql_info; int count; - if (eap->cmdidx == CMD_lolder || eap->cmdidx == CMD_lnewer) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -3526,7 +3526,7 @@ qf_history(exarg_T *eap) qf_info_T *qi = &ql_info; int i; - if (eap->cmdidx == CMD_lhistory) + if (is_loclist_cmd(eap->cmdidx)) qi = GET_LOC_LIST(curwin); if (qi == NULL || (qi->qf_listcount == 0 && qf_list_empty(qi, qi->qf_curlist))) @@ -3745,7 +3745,7 @@ ex_cwindow(exarg_T *eap) qf_info_T *qi = &ql_info; win_T *win; - if (eap->cmdidx == CMD_lwindow) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -3781,7 +3781,7 @@ ex_cclose(exarg_T *eap) win_T *win = NULL; qf_info_T *qi = &ql_info; - if (eap->cmdidx == CMD_lclose || eap->cmdidx == CMD_lwindow) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -3808,7 +3808,7 @@ ex_copen(exarg_T *eap) buf_T *qf_buf; win_T *oldwin = curwin; - if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -3953,12 +3953,12 @@ qf_win_goto(win_T *win, linenr_T lnum) * :cbottom/:lbottom commands. */ void -ex_cbottom(exarg_T *eap UNUSED) +ex_cbottom(exarg_T *eap) { qf_info_T *qi = &ql_info; win_T *win; - if (eap->cmdidx == CMD_lbottom) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -4430,8 +4430,7 @@ ex_make(exarg_T *eap) enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc; #endif - if (eap->cmdidx == CMD_lmake || eap->cmdidx == CMD_lgrep - || eap->cmdidx == CMD_lgrepadd) + if (is_loclist_cmd(eap->cmdidx)) wp = curwin; autowrite_all(); @@ -4570,7 +4569,7 @@ qf_get_size(exarg_T *eap) int i, sz = 0; int prev_fnum = 0; - if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) + if (is_loclist_cmd(eap->cmdidx)) { /* Location list */ qi = GET_LOC_LIST(curwin); @@ -4607,7 +4606,7 @@ qf_get_cur_idx(exarg_T *eap) { qf_info_T *qi = &ql_info; - if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) + if (is_loclist_cmd(eap->cmdidx)) { /* Location list */ qi = GET_LOC_LIST(curwin); @@ -4631,7 +4630,7 @@ qf_get_cur_valid_idx(exarg_T *eap) int i, eidx = 0; int prev_fnum = 0; - if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) + if (is_loclist_cmd(eap->cmdidx)) { /* Location list */ qi = GET_LOC_LIST(curwin); @@ -4724,12 +4723,7 @@ ex_cc(exarg_T *eap) qf_info_T *qi = &ql_info; int errornr; - if (eap->cmdidx == CMD_ll - || eap->cmdidx == CMD_lrewind - || eap->cmdidx == CMD_lfirst - || eap->cmdidx == CMD_llast - || eap->cmdidx == CMD_ldo - || eap->cmdidx == CMD_lfdo) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -4743,13 +4737,18 @@ ex_cc(exarg_T *eap) errornr = (int)eap->line2; else { - if (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) - errornr = 0; - else if (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind - || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) - errornr = 1; - else - errornr = 32767; + switch (eap->cmdidx) + { + case CMD_cc: case CMD_ll: + errornr = 0; + break; + case CMD_crewind: case CMD_lrewind: case CMD_cfirst: + case CMD_lfirst: + errornr = 1; + break; + default: + errornr = 32767; + } } /* For cdo and ldo commands, jump to the nth valid error. @@ -4774,15 +4773,9 @@ ex_cnext(exarg_T *eap) { qf_info_T *qi = &ql_info; int errornr; + int dir; - if (eap->cmdidx == CMD_lnext - || eap->cmdidx == CMD_lNext - || eap->cmdidx == CMD_lprevious - || eap->cmdidx == CMD_lnfile - || eap->cmdidx == CMD_lNfile - || eap->cmdidx == CMD_lpfile - || eap->cmdidx == CMD_ldo - || eap->cmdidx == CMD_lfdo) + if (is_loclist_cmd(eap->cmdidx)) { qi = GET_LOC_LIST(curwin); if (qi == NULL) @@ -4799,17 +4792,28 @@ ex_cnext(exarg_T *eap) else errornr = 1; - qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext - || eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo) - ? FORWARD - : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile - || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) - ? FORWARD_FILE - : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile - || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile) - ? BACKWARD_FILE - : BACKWARD, - errornr, eap->forceit); + // Depending on the command jump to either next or previous entry/file. + switch (eap->cmdidx) + { + case CMD_cnext: case CMD_lnext: case CMD_cdo: case CMD_ldo: + dir = FORWARD; + break; + case CMD_cprevious: case CMD_lprevious: case CMD_cNext: + case CMD_lNext: + dir = BACKWARD; + break; + case CMD_cnfile: case CMD_lnfile: case CMD_cfdo: case CMD_lfdo: + dir = FORWARD_FILE; + break; + case CMD_cpfile: case CMD_lpfile: case CMD_cNfile: case CMD_lNfile: + dir = BACKWARD_FILE; + break; + default: + dir = FORWARD; + break; + } + + qf_jump(qi, dir, errornr, eap->forceit); } /* @@ -4857,9 +4861,7 @@ ex_cfile(exarg_T *eap) if (*eap->arg != NUL) set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE, 0); - if (eap->cmdidx == CMD_lfile - || eap->cmdidx == CMD_lgetfile - || eap->cmdidx == CMD_laddfile) + if (is_loclist_cmd(eap->cmdidx)) wp = curwin; /* @@ -5178,10 +5180,7 @@ ex_vimgrep(exarg_T *eap) #endif } - if (eap->cmdidx == CMD_lgrep - || eap->cmdidx == CMD_lvimgrep - || eap->cmdidx == CMD_lgrepadd - || eap->cmdidx == CMD_lvimgrepadd) + if (is_loclist_cmd(eap->cmdidx)) { qi = ll_get_or_alloc_list(curwin); if (qi == NULL) @@ -6525,9 +6524,7 @@ ex_cbuffer(exarg_T *eap) } /* Must come after autocommands. */ - if (eap->cmdidx == CMD_lbuffer - || eap->cmdidx == CMD_lgetbuffer - || eap->cmdidx == CMD_laddbuffer) + if (is_loclist_cmd(eap->cmdidx)) { qi = ll_get_or_alloc_list(curwin); if (qi == NULL) @@ -6631,9 +6628,7 @@ ex_cexpr(exarg_T *eap) #endif } - if (eap->cmdidx == CMD_lexpr - || eap->cmdidx == CMD_lgetexpr - || eap->cmdidx == CMD_laddexpr) + if (is_loclist_cmd(eap->cmdidx)) { qi = ll_get_or_alloc_list(curwin); if (qi == NULL) @@ -6922,7 +6917,7 @@ ex_helpgrep(exarg_T *eap) save_cpo = p_cpo; p_cpo = empty_option; - if (eap->cmdidx == CMD_lhelpgrep) + if (is_loclist_cmd(eap->cmdidx)) { qi = hgr_get_ll(&new_qi); if (qi == NULL) diff --git a/src/version.c b/src/version.c index efc214caba..82b7022069 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 288, /**/ 287, /**/ From 2dfcef4c08a3371e2126504bea00b274f937a840 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 15 Aug 2018 22:29:51 +0200 Subject: [PATCH 09/35] patch 8.1.0289: cursor moves to wrong column after quickfix jump Problem: Cursor moves to wrong column after quickfix jump. Solution: Set the curswant flag. (Andy Massimino, closes #3331) --- src/quickfix.c | 1 + src/testdir/test_quickfix.vim | 9 +++++++++ src/version.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/quickfix.c b/src/quickfix.c index 8cfec6c704..78df7081f8 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -3010,6 +3010,7 @@ qf_jump_goto_line( ++screen_col; } } + curwin->w_set_curswant = TRUE; check_cursor(); } else diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index ce19e74d3f..8a175a185d 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -3546,3 +3546,12 @@ func Test_view_result_split() call Xview_result_split_tests('c') call Xview_result_split_tests('l') endfunc + +" Test that :cc sets curswant +func Test_curswant() + helpgrep quickfix + normal! llll + 1cc + call assert_equal(getcurpos()[4], virtcol('.')) + cclose | helpclose +endfunc diff --git a/src/version.c b/src/version.c index 82b7022069..66e79d88c1 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 289, /**/ 288, /**/ From b476cb7d8d1a8c02409f110dea8b166aa9334e18 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 16 Aug 2018 21:37:50 +0200 Subject: [PATCH 10/35] patch 8.1.0290: "cit" on an empty HTML tag changes the whole tag Problem: "cit" on an empty HTML tag changes the whole tag. Solution: Only adjust the area in Visual mode. (Andy Massimino, closes #3332) --- src/search.c | 7 ++++--- src/testdir/test_textobjects.vim | 17 +++++++++++++++++ src/version.c | 2 ++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/search.c b/src/search.c index 66ae647185..a12a1d33c5 100644 --- a/src/search.c +++ b/src/search.c @@ -4106,9 +4106,10 @@ again: } curwin->w_cursor = end_pos; - /* If we now have the same text as before reset "do_include" and try - * again. */ - if (EQUAL_POS(start_pos, old_start) && EQUAL_POS(end_pos, old_end)) + // If we are in Visual mode and now have the same text as before set + // "do_include" and try again. + if (VIsual_active && EQUAL_POS(start_pos, old_start) + && EQUAL_POS(end_pos, old_end)) { do_include = TRUE; curwin->w_cursor = old_start; diff --git a/src/testdir/test_textobjects.vim b/src/testdir/test_textobjects.vim index f02619fc09..6a2f5044cc 100644 --- a/src/testdir/test_textobjects.vim +++ b/src/testdir/test_textobjects.vim @@ -121,6 +121,23 @@ func Test_string_html_objects() enew! endfunc +func Test_empty_html_tag() + new + call setline(1, '
') + normal 0citxxx + call assert_equal('
xxx
', getline(1)) + + call setline(1, '
') + normal 0fyyy', getline(1)) + + call setline(1, '
') + normal 0f Date: Sat, 18 Aug 2018 16:19:42 +0200 Subject: [PATCH 11/35] patch 8.1.0291: 'incsearch' highlighting not used for :sort Problem: 'incsearch' highlighting not used for :sort. Solution: Handle pattern in :sort command. --- src/ex_getln.c | 13 ++++++++- src/testdir/dumps/Test_incsearch_sort_01.dump | 9 +++++++ src/testdir/test_search.vim | 27 +++++++++++++++++++ src/version.c | 2 ++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/testdir/dumps/Test_incsearch_sort_01.dump diff --git a/src/ex_getln.c b/src/ex_getln.c index d38fa4b023..7928af7bff 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -316,6 +316,7 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, && (STRNCMP(cmd, "substitute", p - cmd) == 0 || STRNCMP(cmd, "smagic", p - cmd) == 0 || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0 + || STRNCMP(cmd, "sort", p - cmd) == 0 || STRNCMP(cmd, "global", p - cmd) == 0 || STRNCMP(cmd, "vglobal", p - cmd) == 0)) { @@ -331,6 +332,16 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, if (*skipwhite(p) == NUL) return FALSE; } + + // For ":sort" skip over flags. + if (cmd[0] == 's' && cmd[1] == 'o') + { + while (ASCII_ISALPHA(*(p = skipwhite(p)))) + ++p; + if (*p == NUL) + return FALSE; + } + p = skipwhite(p); delim = *p++; end = skip_regexp(p, delim, p_magic, NULL); @@ -359,7 +370,7 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, search_last_line = ea.line2; } } - else if (*cmd == 's') + else if (cmd[0] == 's' && cmd[1] != 'o') { // :s defaults to the current line search_first_line = curwin->w_cursor.lnum; diff --git a/src/testdir/dumps/Test_incsearch_sort_01.dump b/src/testdir/dumps/Test_incsearch_sort_01.dump new file mode 100644 index 0000000000..6c003af419 --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_sort_01.dump @@ -0,0 +1,9 @@ +|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56 +|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59 +|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60 +|~+0#4040ff13&| @68 +|~| @68 +|~| @68 +|~| @68 +|~| @68 +|:+0#0000000&|s|o|r|t| |n|i| |u| |/|o|n> @55 diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index 90a0a0e3b5..da388cd2e6 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -917,6 +917,33 @@ func Test_incsearch_substitute_dump() call delete('Xis_subst_script') endfunc +" Similar to Test_incsearch_substitute_dump() for :sort +func Test_incsearch_ssort_dump() + if !exists('+incsearch') + return + endif + if !CanRunVimInTerminal() + return + endif + call writefile([ + \ 'set incsearch hlsearch scrolloff=0', + \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])', + \ ], 'Xis_sort_script') + let buf = RunVimInTerminal('-S Xis_sort_script', {'rows': 9, 'cols': 70}) + " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by + " the 'ambiwidth' check. + sleep 100m + + " Need to send one key at a time to force a redraw. + call term_sendkeys(buf, ':sort ni u /on') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {}) + call term_sendkeys(buf, "\") + + call StopVimInTerminal(buf) + call delete('Xis_sort_script') +endfunc + func Test_search_undefined_behaviour() if !has("terminal") return diff --git a/src/version.c b/src/version.c index 279908e043..56ab4182d7 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 291, /**/ 290, /**/ From 9bc1eac2c75d8440c68f305302bc5bdef515f489 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 18 Aug 2018 19:04:37 +0200 Subject: [PATCH 12/35] patch 8.1.0292: MS-Windows: the text "self-installing" confuses some users Problem: MS-Windows: the text "self-installing" confuses some users. Solution: Remove the text from the uninstall entry. (closes #3337) --- src/dosinst.c | 7 +------ src/version.c | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/dosinst.c b/src/dosinst.c index 64edbbdae4..182546e885 100644 --- a/src/dosinst.c +++ b/src/dosinst.c @@ -1575,18 +1575,13 @@ install_registry(void) } printf("Creating an uninstall entry\n"); + sprintf(display_name, "Vim " VIM_VERSION_SHORT); /* For the NSIS installer use the generated uninstaller. */ if (interactive) - { - sprintf(display_name, "Vim " VIM_VERSION_SHORT); sprintf(uninstall_string, "%s\\uninstal.exe", installdir); - } else - { - sprintf(display_name, "Vim " VIM_VERSION_SHORT " (self-installing)"); sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir); - } lRet = register_uninstall( HKEY_LOCAL_MACHINE, diff --git a/src/version.c b/src/version.c index 56ab4182d7..f91dd9b8a9 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 292, /**/ 291, /**/ From 4d77c65a9e57e1d1a459c44411930c7a892835fd Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 18 Aug 2018 19:59:54 +0200 Subject: [PATCH 13/35] patch 8.1.0293: checks for type of stack is cryptic Problem: Checks for type of stack is cryptic. Solution: Define IS_QF_STACK() and IS_LL_STACK(). (Yegappan Lakshmanan) --- src/quickfix.c | 23 ++++++++++++++--------- src/version.c | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index 78df7081f8..1f193453f1 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -159,6 +159,11 @@ static qf_info_T *ll_get_or_alloc_list(win_T *); #define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL) /* Location list window check helper macro */ #define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) + +// Quickfix and location list stack check helper macros +#define IS_QF_STACK(qi) (qi == &ql_info) +#define IS_LL_STACK(qi) (qi != &ql_info) + /* * Return location list for window 'wp' * For location list window, return the referenced location list @@ -1940,7 +1945,7 @@ qf_add_entry( qfp->qf_fnum = bufnum; if (buf != NULL) buf->b_has_qf_entry |= - (qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; + IS_QF_STACK(qi) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; } else qfp->qf_fnum = qf_get_fnum(qi, qf_idx, dir, fname); @@ -2224,7 +2229,7 @@ qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *directory, char_u *fname) return 0; buf->b_has_qf_entry = - (qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; + IS_QF_STACK(qi) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; return buf->b_fnum; } @@ -2631,7 +2636,7 @@ jump_to_help_window(qf_info_T *qi, int *opened_window) if (cmdmod.split == 0 && curwin->w_width != Columns && curwin->w_width < 80) flags |= WSP_TOP; - if (qi != &ql_info) + if (IS_LL_STACK(qi)) flags |= WSP_NEWLOC; /* don't copy the location list */ if (win_split(0, flags) == FAIL) @@ -2642,7 +2647,7 @@ jump_to_help_window(qf_info_T *qi, int *opened_window) if (curwin->w_height < p_hh) win_setheight((int)p_hh); - if (qi != &ql_info) /* not a quickfix list */ + if (IS_LL_STACK(qi)) // not a quickfix list { /* The new window should use the supplied location list */ curwin->w_llist = qi; @@ -2918,7 +2923,7 @@ qf_jump_edit_buffer( retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); - if (qi != &ql_info) + if (IS_LL_STACK(qi)) { /* * Location list. Check whether the associated window is still @@ -2939,7 +2944,7 @@ qf_jump_edit_buffer( else if (old_qf_curlist != qi->qf_curlist || !is_qf_entry_present(qi, qf_ptr)) { - if (qi == &ql_info) + if (IS_QF_STACK(qi)) EMSG(_("E925: Current quickfix was changed")); else EMSG(_(e_loc_list_changed)); @@ -4040,8 +4045,8 @@ is_qf_win(win_T *win, qf_info_T *qi) * pointing to the location list. */ if (bt_quickfix(win->w_buffer)) - if ((qi == &ql_info && win->w_llist_ref == NULL) - || (qi != &ql_info && win->w_llist_ref == qi)) + if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL) + || (IS_LL_STACK(qi) && win->w_llist_ref == qi)) return TRUE; return FALSE; @@ -6955,7 +6960,7 @@ ex_helpgrep(exarg_T *eap) { apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, TRUE, curbuf); - if (!new_qi && qi != &ql_info && qf_find_buf(qi) == NULL) + if (!new_qi && IS_LL_STACK(qi) && qf_find_buf(qi) == NULL) /* autocommands made "qi" invalid */ return; } diff --git a/src/version.c b/src/version.c index f91dd9b8a9..c5975e8b32 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 293, /**/ 292, /**/ From 3b9fcfcffab8f927a01877804fa6ac5bbca34c7a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 18 Aug 2018 20:20:27 +0200 Subject: [PATCH 14/35] patch 8.1.0294: MS-Windows: sometimes uses short directory name Problem: MS-Windows: sometimes uses short directory name. Solution: Expand to long file name with correct caps. (Nobuhiro Takasaki, closes #3334) --- src/os_win32.c | 19 +++++++++++++++++-- src/version.c | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/os_win32.c b/src/os_win32.c index 85c8a57d11..8065ee858b 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -3108,6 +3108,8 @@ mch_dirname( char_u *buf, int len) { + char_u abuf[_MAX_PATH + 1]; + /* * Originally this was: * return (getcwd(buf, len) != NULL ? OK : FAIL); @@ -3121,7 +3123,13 @@ mch_dirname( if (GetCurrentDirectoryW(_MAX_PATH, wbuf) != 0) { - char_u *p = utf16_to_enc(wbuf, NULL); + WCHAR wcbuf[_MAX_PATH + 1]; + char_u *p; + + if (GetLongPathNameW(wbuf, wcbuf, _MAX_PATH) != 0) + p = utf16_to_enc(wcbuf, NULL); + else + p = utf16_to_enc(wbuf, NULL); if (p != NULL) { @@ -3133,7 +3141,14 @@ mch_dirname( return FAIL; } #endif - return (GetCurrentDirectory(len, (LPSTR)buf) != 0 ? OK : FAIL); + if (GetCurrentDirectory(len, (LPSTR)buf) == 0) + return FAIL; + if (GetLongPathNameA((LPSTR)buf, (LPSTR)abuf, _MAX_PATH) == 0) + // return the short path name + return OK; + + vim_strncpy(abuf, buf, len - 1); + return OK; } /* diff --git a/src/version.c b/src/version.c index c5975e8b32..8cf1ad45f4 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 294, /**/ 293, /**/ From 264cf5cfaf40e704aea2578e70c15ed9a9d0161e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 18 Aug 2018 21:05:31 +0200 Subject: [PATCH 15/35] patch 8.1.0295: no 'incsearch' highlighting for :vimgrep and similar Problem: No 'incsearch' highlighting for :vimgrep and similar commands. Solution: Parse the :vimgrep command and similar ones to locate the search pattern. (Hirohito Higashi, closes #3344) --- src/ex_getln.c | 86 ++++++++++++------- .../dumps/Test_incsearch_vimgrep_01.dump | 9 ++ .../dumps/Test_incsearch_vimgrep_02.dump | 9 ++ .../dumps/Test_incsearch_vimgrep_03.dump | 9 ++ .../dumps/Test_incsearch_vimgrep_04.dump | 9 ++ .../dumps/Test_incsearch_vimgrep_05.dump | 9 ++ src/testdir/test_search.vim | 47 ++++++++++ src/version.c | 2 + 8 files changed, 149 insertions(+), 31 deletions(-) create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_02.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_03.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_04.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_05.dump diff --git a/src/ex_getln.c b/src/ex_getln.c index 7928af7bff..bce4aac790 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -307,49 +307,73 @@ do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, cmdmod = save_cmdmod; cmd = skip_range(ea.cmd, NULL); - if (*cmd == 's' || *cmd == 'g' || *cmd == 'v') + if (*cmd == 's' || *cmd == 'g' || *cmd == 'v' || *cmd == 'l') { // Skip over "substitute" to find the pattern separator. for (p = cmd; ASCII_ISALPHA(*p); ++p) ; - if (*skipwhite(p) != NUL - && (STRNCMP(cmd, "substitute", p - cmd) == 0 - || STRNCMP(cmd, "smagic", p - cmd) == 0 - || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0 - || STRNCMP(cmd, "sort", p - cmd) == 0 - || STRNCMP(cmd, "global", p - cmd) == 0 - || STRNCMP(cmd, "vglobal", p - cmd) == 0)) + if (*skipwhite(p) != NUL) { - if (*cmd == 's' && cmd[1] == 'm') - p_magic = TRUE; - else if (*cmd == 's' && cmd[1] == 'n') - p_magic = FALSE; - - // Check for "global!/". - if (*cmd == 'g' && *p == '!') + if (STRNCMP(cmd, "substitute", p - cmd) == 0 + || STRNCMP(cmd, "smagic", p - cmd) == 0 + || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0 + || STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0 + || STRNCMP(cmd, "global", p - cmd) == 0 + || STRNCMP(cmd, "vglobal", p - cmd) == 0) { - p++; - if (*skipwhite(p) == NUL) - return FALSE; + if (*cmd == 's' && cmd[1] == 'm') + p_magic = TRUE; + else if (*cmd == 's' && cmd[1] == 'n') + p_magic = FALSE; + + // Check for "global!/". + if (*cmd == 'g' && *p == '!') + { + p++; + if (*skipwhite(p) == NUL) + return FALSE; + } + + // For ":sort" skip over flags. + if (cmd[0] == 's' && cmd[1] == 'o') + { + while (ASCII_ISALPHA(*(p = skipwhite(p)))) + ++p; + if (*p == NUL) + return FALSE; + } + + p = skipwhite(p); + delim = *p++; + end = skip_regexp(p, delim, p_magic, NULL); + } + else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0 + || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0 + || STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0 + || STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0) + { + // Check for "!/". + if (*p == '!') + { + p++; + if (*skipwhite(p) == NUL) + return FALSE; + } + p = skipwhite(p); + delim = (vim_isIDc(*p)) ? ' ' : *p++; + end = skip_regexp(p, delim, p_magic, NULL); + } + else + { + end = p; + delim = -1; } - // For ":sort" skip over flags. - if (cmd[0] == 's' && cmd[1] == 'o') - { - while (ASCII_ISALPHA(*(p = skipwhite(p)))) - ++p; - if (*p == NUL) - return FALSE; - } - - p = skipwhite(p); - delim = *p++; - end = skip_regexp(p, delim, p_magic, NULL); if (end > p || *end == delim) { pos_T save_cursor = curwin->w_cursor; - // found a non-empty pattern + // found a non-empty pattern or // *skiplen = (int)(p - ccline.cmdbuff); *patlen = (int)(end - p); diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_01.dump b/src/testdir/dumps/Test_incsearch_vimgrep_01.dump new file mode 100644 index 0000000000..955d030583 --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_vimgrep_01.dump @@ -0,0 +1,9 @@ +|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56 +|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59 +|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60 +|~+0#4040ff13&| @68 +|~| @68 +|~| @68 +|~| @68 +|~| @68 +|:+0#0000000&|v|i|m|g|r|e|p| |o|n> @58 diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_02.dump b/src/testdir/dumps/Test_incsearch_vimgrep_02.dump new file mode 100644 index 0000000000..a5d94eac55 --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_vimgrep_02.dump @@ -0,0 +1,9 @@ +|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56 +|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59 +|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60 +|~+0#4040ff13&| @68 +|~| @68 +|~| @68 +|~| @68 +|~| @68 +|:+0#0000000&|v|i|m|g| |/|o|n|/| |*|.|t|x|t> @53 diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_03.dump b/src/testdir/dumps/Test_incsearch_vimgrep_03.dump new file mode 100644 index 0000000000..038ceb9d95 --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_vimgrep_03.dump @@ -0,0 +1,9 @@ +|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56 +|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59 +|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60 +|~+0#4040ff13&| @68 +|~| @68 +|~| @68 +|~| @68 +|~| @68 +|:+0#0000000&|v|i|m|g|r|e|p|a|d@1| |"|\|<|o|n> @52 diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_04.dump b/src/testdir/dumps/Test_incsearch_vimgrep_04.dump new file mode 100644 index 0000000000..92dd78dd87 --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_vimgrep_04.dump @@ -0,0 +1,9 @@ +|a+0&#ffffff0|n|o|t|h|e|r| |o|n|e| |2| @56 +|t+1&&|h|a|t+0&&| |o|n|e| |3| @59 +|t|h|e| |o|n|e| |1| @60 +|~+0#4040ff13&| @68 +|~| @68 +|~| @68 +|~| @68 +|~| @68 +|:+0#0000000&|l|v| |"|t|h|a> @61 diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_05.dump b/src/testdir/dumps/Test_incsearch_vimgrep_05.dump new file mode 100644 index 0000000000..e11ff574c1 --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_vimgrep_05.dump @@ -0,0 +1,9 @@ +|a+0&#ffffff0|n|o|t+1&&|h|e|r+0&&| |o|n|e| |2| @56 +|t|h|a|t| |o|n|e| |3| @59 +|t+0&#ffff4012|h|e| +0&#ffffff0|o|n|e| |1| @60 +|~+0#4040ff13&| @68 +|~| @68 +|~| @68 +|~| @68 +|~| @68 +|:+0#0000000&|l|v|i|m|g|r|e|p|a| |"|t|h|e|"| |*@1|/|*|.|t|x|t> @44 diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index da388cd2e6..9ede26dd3e 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -944,6 +944,53 @@ func Test_incsearch_ssort_dump() call delete('Xis_sort_script') endfunc +" Similar to Test_incsearch_substitute_dump() for :vimgrep famiry +func Test_incsearch_vimgrep_dump() + if !exists('+incsearch') + return + endif + if !CanRunVimInTerminal() + return + endif + call writefile([ + \ 'set incsearch hlsearch scrolloff=0', + \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])', + \ ], 'Xis_vimgrep_script') + let buf = RunVimInTerminal('-S Xis_vimgrep_script', {'rows': 9, 'cols': 70}) + " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by + " the 'ambiwidth' check. + sleep 100m + + " Need to send one key at a time to force a redraw. + call term_sendkeys(buf, ':vimgrep on') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_01', {}) + call term_sendkeys(buf, "\") + + call term_sendkeys(buf, ':vimg /on/ *.txt') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_02', {}) + call term_sendkeys(buf, "\") + + call term_sendkeys(buf, ':vimgrepadd "\") + + call term_sendkeys(buf, ':lv "tha') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_04', {}) + call term_sendkeys(buf, "\") + + call term_sendkeys(buf, ':lvimgrepa "the" **/*.txt') + sleep 100m + call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_05', {}) + call term_sendkeys(buf, "\") + + call StopVimInTerminal(buf) + call delete('Xis_vimgrep_script') +endfunc + func Test_search_undefined_behaviour() if !has("terminal") return diff --git a/src/version.c b/src/version.c index 8cf1ad45f4..a084de0488 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 295, /**/ 294, /**/ From 111bbd61e96d1d3ee4bc07ae435fd97b88413aba Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 18 Aug 2018 21:23:05 +0200 Subject: [PATCH 16/35] patch 8.1.0296: command parsing for 'incsearch' is a bit ugly Problem: Command parsing for 'incsearch' is a bit ugly. Solution: Return when there is no pattern. Put common checks together. --- src/ex_getln.c | 229 +++++++++++++++++++++++-------------------------- src/version.c | 2 + 2 files changed, 109 insertions(+), 122 deletions(-) diff --git a/src/ex_getln.c b/src/ex_getln.c index bce4aac790..b0da5d80eb 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -276,140 +276,125 @@ set_search_match(pos_T *t) do_incsearch_highlighting(int firstc, incsearch_state_T *is_state, int *skiplen, int *patlen) { + char_u *cmd; + cmdmod_T save_cmdmod = cmdmod; + char_u *p; + int delim_optional = FALSE; + int delim; + char_u *end; + char_u *dummy; + exarg_T ea; + pos_T save_cursor; + *skiplen = 0; *patlen = ccline.cmdlen; - if (p_is && !cmd_silent) + if (!p_is || cmd_silent) + return FALSE; + + // by default search all lines + search_first_line = 0; + search_last_line = MAXLNUM; + + if (firstc == '/' || firstc == '?') + return TRUE; + if (firstc != ':') + return FALSE; + + vim_memset(&ea, 0, sizeof(ea)); + ea.line1 = 1; + ea.line2 = 1; + ea.cmd = ccline.cmdbuff; + ea.addr_type = ADDR_LINES; + + parse_command_modifiers(&ea, &dummy, TRUE); + cmdmod = save_cmdmod; + + cmd = skip_range(ea.cmd, NULL); + if (vim_strchr((char_u *)"sgvl", *cmd) == NULL) + return FALSE; + + // Skip over "substitute" to find the pattern separator. + for (p = cmd; ASCII_ISALPHA(*p); ++p) + ; + if (*skipwhite(p) == NUL) + return FALSE; + + if (STRNCMP(cmd, "substitute", p - cmd) == 0 + || STRNCMP(cmd, "smagic", p - cmd) == 0 + || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0 + || STRNCMP(cmd, "vglobal", p - cmd) == 0) { - // by default search all lines - search_first_line = 0; - search_last_line = MAXLNUM; - - if (firstc == '/' || firstc == '?') - return TRUE; - if (firstc == ':') + if (*cmd == 's' && cmd[1] == 'm') + p_magic = TRUE; + else if (*cmd == 's' && cmd[1] == 'n') + p_magic = FALSE; + } + else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0) + { + // skip over flags + while (ASCII_ISALPHA(*(p = skipwhite(p)))) + ++p; + if (*p == NUL) + return FALSE; + } + else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0 + || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0 + || STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0 + || STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0 + || STRNCMP(cmd, "global", p - cmd) == 0) + { + // skip over "!" + if (*p == '!') { - char_u *cmd; - cmdmod_T save_cmdmod = cmdmod; - char_u *p; - int delim; - char_u *end; - char_u *dummy; - exarg_T ea; + p++; + if (*skipwhite(p) == NUL) + return FALSE; + } + if (*cmd != 'g') + delim_optional = TRUE; + } + else + return FALSE; - vim_memset(&ea, 0, sizeof(ea)); - ea.line1 = 1; - ea.line2 = 1; - ea.cmd = ccline.cmdbuff; - ea.addr_type = ADDR_LINES; + p = skipwhite(p); + delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++; + end = skip_regexp(p, delim, p_magic, NULL); - parse_command_modifiers(&ea, &dummy, TRUE); - cmdmod = save_cmdmod; + if (end == p && *end != delim) + return FALSE; + // found a non-empty pattern or // - cmd = skip_range(ea.cmd, NULL); - if (*cmd == 's' || *cmd == 'g' || *cmd == 'v' || *cmd == 'l') - { - // Skip over "substitute" to find the pattern separator. - for (p = cmd; ASCII_ISALPHA(*p); ++p) - ; - if (*skipwhite(p) != NUL) - { - if (STRNCMP(cmd, "substitute", p - cmd) == 0 - || STRNCMP(cmd, "smagic", p - cmd) == 0 - || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0 - || STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0 - || STRNCMP(cmd, "global", p - cmd) == 0 - || STRNCMP(cmd, "vglobal", p - cmd) == 0) - { - if (*cmd == 's' && cmd[1] == 'm') - p_magic = TRUE; - else if (*cmd == 's' && cmd[1] == 'n') - p_magic = FALSE; + *skiplen = (int)(p - ccline.cmdbuff); + *patlen = (int)(end - p); - // Check for "global!/". - if (*cmd == 'g' && *p == '!') - { - p++; - if (*skipwhite(p) == NUL) - return FALSE; - } - - // For ":sort" skip over flags. - if (cmd[0] == 's' && cmd[1] == 'o') - { - while (ASCII_ISALPHA(*(p = skipwhite(p)))) - ++p; - if (*p == NUL) - return FALSE; - } - - p = skipwhite(p); - delim = *p++; - end = skip_regexp(p, delim, p_magic, NULL); - } - else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0 - || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0 - || STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0 - || STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0) - { - // Check for "!/". - if (*p == '!') - { - p++; - if (*skipwhite(p) == NUL) - return FALSE; - } - p = skipwhite(p); - delim = (vim_isIDc(*p)) ? ' ' : *p++; - end = skip_regexp(p, delim, p_magic, NULL); - } - else - { - end = p; - delim = -1; - } - - if (end > p || *end == delim) - { - pos_T save_cursor = curwin->w_cursor; - - // found a non-empty pattern or // - *skiplen = (int)(p - ccline.cmdbuff); - *patlen = (int)(end - p); - - // parse the address range - curwin->w_cursor = is_state->search_start; - parse_cmd_address(&ea, &dummy); - if (ea.addr_count > 0) - { - // Allow for reverse match. - if (ea.line2 < ea.line1) - { - search_first_line = ea.line2; - search_last_line = ea.line1; - } - else - { - search_first_line = ea.line1; - search_last_line = ea.line2; - } - } - else if (cmd[0] == 's' && cmd[1] != 'o') - { - // :s defaults to the current line - search_first_line = curwin->w_cursor.lnum; - search_last_line = curwin->w_cursor.lnum; - } - - curwin->w_cursor = save_cursor; - return TRUE; - } - } - } + // parse the address range + save_cursor = curwin->w_cursor; + curwin->w_cursor = is_state->search_start; + parse_cmd_address(&ea, &dummy); + if (ea.addr_count > 0) + { + // Allow for reverse match. + if (ea.line2 < ea.line1) + { + search_first_line = ea.line2; + search_last_line = ea.line1; + } + else + { + search_first_line = ea.line1; + search_last_line = ea.line2; } } + else if (cmd[0] == 's' && cmd[1] != 'o') + { + // :s defaults to the current line + search_first_line = curwin->w_cursor.lnum; + search_last_line = curwin->w_cursor.lnum; + } - return FALSE; + curwin->w_cursor = save_cursor; + return TRUE; } static void diff --git a/src/version.c b/src/version.c index a084de0488..194ee4cda7 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 296, /**/ 295, /**/ From cea1f9ec5256755ad119526fea2ef6811f7b53cd Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 19 Aug 2018 14:38:42 +0200 Subject: [PATCH 17/35] patch 8.1.0297: MS-Windows: tests fail, Vim crashes Problem: MS-Windows: tests fail, Vim crashes. Solution: Fix long file name handling. --- src/os_win32.c | 21 ++++++++++++++++----- src/version.c | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/os_win32.c b/src/os_win32.c index 8065ee858b..dc98d6acd2 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -3109,6 +3109,7 @@ mch_dirname( int len) { char_u abuf[_MAX_PATH + 1]; + DWORD lfnlen; /* * Originally this was: @@ -3124,11 +3125,19 @@ mch_dirname( if (GetCurrentDirectoryW(_MAX_PATH, wbuf) != 0) { WCHAR wcbuf[_MAX_PATH + 1]; - char_u *p; + char_u *p = NULL; if (GetLongPathNameW(wbuf, wcbuf, _MAX_PATH) != 0) + { p = utf16_to_enc(wcbuf, NULL); - else + if (STRLEN(p) >= (size_t)len) + { + // long path name is too long, fall back to short one + vim_free(p); + p = NULL; + } + } + if (p == NULL) p = utf16_to_enc(wbuf, NULL); if (p != NULL) @@ -3143,11 +3152,13 @@ mch_dirname( #endif if (GetCurrentDirectory(len, (LPSTR)buf) == 0) return FAIL; - if (GetLongPathNameA((LPSTR)buf, (LPSTR)abuf, _MAX_PATH) == 0) - // return the short path name + lfnlen = GetLongPathNameA((LPCSTR)buf, (LPSTR)abuf, _MAX_PATH); + if (lfnlen == 0 || lfnlen >= (DWORD)len) + // Failed to get long path name or it's too long: fall back to the + // short path name. return OK; - vim_strncpy(abuf, buf, len - 1); + STRCPY(buf, abuf); return OK; } diff --git a/src/version.c b/src/version.c index 194ee4cda7..99f86e70c8 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 297, /**/ 296, /**/ From 46fad2ef0bd5124f1be22c807214c243fb5611d8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 19 Aug 2018 16:09:27 +0200 Subject: [PATCH 18/35] patch 8.1.0298: window resize test sometimes fails on Mac Problem: Window resize test sometimes fails on Mac. Solution: Add Test_popup_and_window_resize() to flaky tests. --- src/testdir/runtest.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index 4f508a4875..fa621f4978 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -272,6 +272,7 @@ let s:flaky = [ \ 'Test_paused()', \ 'Test_pipe_through_sort_all()', \ 'Test_pipe_through_sort_some()', + \ 'Test_popup_and_window_resize()', " sometimes fails on Mac \ 'Test_quoteplus()', \ 'Test_quotestar()', \ 'Test_reltime()', diff --git a/src/version.c b/src/version.c index 99f86e70c8..ac39425536 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 298, /**/ 297, /**/ From 142ae736d984f4575c1c6ec1a4f679ae4ddf9413 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 19 Aug 2018 17:04:01 +0200 Subject: [PATCH 19/35] patch 8.1.0299: misplaced comment Problem: misplaced comment Solution: Remove comment --- src/testdir/runtest.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index fa621f4978..c3414914f8 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -272,7 +272,7 @@ let s:flaky = [ \ 'Test_paused()', \ 'Test_pipe_through_sort_all()', \ 'Test_pipe_through_sort_some()', - \ 'Test_popup_and_window_resize()', " sometimes fails on Mac + \ 'Test_popup_and_window_resize()', \ 'Test_quoteplus()', \ 'Test_quotestar()', \ 'Test_reltime()', diff --git a/src/version.c b/src/version.c index ac39425536..7278799b78 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 299, /**/ 298, /**/ From d8f0cef2bdbdc15d7906f991725e09e67c97cf7e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 19 Aug 2018 22:20:16 +0200 Subject: [PATCH 20/35] patch 8.1.0300: the old window title might be freed twice Problem: The old window title might be freed twice. (Dominique Pelle) Solution: Do not free "oldtitle" in a signal handler but set a flag to have it freed later. --- src/os_unix.c | 11 +++++++++-- src/version.c | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index 148d8a499c..b044df27f7 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -161,6 +161,7 @@ static int get_x11_title(int); static int get_x11_icon(int); static char_u *oldtitle = NULL; +static volatile int oldtitle_outdated = FALSE; static int did_set_title = FALSE; static char_u *oldicon = NULL; static int did_set_icon = FALSE; @@ -1231,8 +1232,9 @@ deathtrap SIGDEFARG(sigarg) after_sigcont(void) { # ifdef FEAT_TITLE - // Set oldtitle to NULL, so the current title is obtained again. - VIM_CLEAR(oldtitle); + // Don't change "oldtitle" in a signal handler, set a flag to obtain it + // again later. + oldtitle_outdated = TRUE; # endif settmode(TMODE_RAW); need_check_timestamps = TRUE; @@ -2281,6 +2283,11 @@ mch_settitle(char_u *title, char_u *icon) */ if ((type || *T_TS != NUL) && title != NULL) { + if (oldtitle_outdated) + { + oldtitle_outdated = FALSE; + VIM_CLEAR(oldtitle); + } if (oldtitle == NULL #ifdef FEAT_GUI && !gui.in_use diff --git a/src/version.c b/src/version.c index 7278799b78..e7ea55f9d5 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 300, /**/ 299, /**/ From 3f6a16f022c437eccaeb683640b25a972cb1b376 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 19 Aug 2018 22:58:45 +0200 Subject: [PATCH 21/35] patch 8.1.0301: GTK: input method popup displayed on wrong screen. Problem: GTK: Input method popup displayed on wrong screen. Solution: Add the screen position offset. (Ken Takata, closes #3268) --- src/gui_beval.c | 16 ++++++++++------ src/gui_gtk_x11.c | 26 ++++++++++++++++++-------- src/mbyte.c | 16 +++++++++------- src/proto/gui_gtk_x11.pro | 2 +- src/version.c | 2 ++ 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/gui_beval.c b/src/gui_beval.c index 49694cfdda..03216008e6 100644 --- a/src/gui_beval.c +++ b/src/gui_beval.c @@ -944,6 +944,8 @@ drawBalloon(BalloonEval *beval) GtkRequisition requisition; int screen_w; int screen_h; + int screen_x; + int screen_y; int x; int y; int x_offset = EVAL_OFFSET_X; @@ -956,8 +958,8 @@ drawBalloon(BalloonEval *beval) screen = gtk_widget_get_screen(beval->target); gtk_window_set_screen(GTK_WINDOW(beval->balloonShell), screen); # endif - gui_gtk_get_screen_size_of_win(beval->balloonShell, - &screen_w, &screen_h); + gui_gtk_get_screen_geom_of_win(beval->balloonShell, + &screen_x, &screen_y, &screen_w, &screen_h); # if !GTK_CHECK_VERSION(3,0,0) gtk_widget_ensure_style(beval->balloonShell); gtk_widget_ensure_style(beval->balloonLabel); @@ -998,14 +1000,16 @@ drawBalloon(BalloonEval *beval) y += beval->y; /* Get out of the way of the mouse pointer */ - if (x + x_offset + requisition.width > screen_w) + if (x + x_offset + requisition.width > screen_x + screen_w) y_offset += 15; - if (y + y_offset + requisition.height > screen_h) + if (y + y_offset + requisition.height > screen_y + screen_h) y_offset = -requisition.height - EVAL_OFFSET_Y; /* Sanitize values */ - x = CLAMP(x + x_offset, 0, MAX(0, screen_w - requisition.width)); - y = CLAMP(y + y_offset, 0, MAX(0, screen_h - requisition.height)); + x = CLAMP(x + x_offset, 0, + MAX(0, screen_x + screen_w - requisition.width)); + y = CLAMP(y + y_offset, 0, + MAX(0, screen_y + screen_h - requisition.height)); /* Show the balloon */ # if GTK_CHECK_VERSION(3,0,0) diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 7541d79072..196c9dc7be 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -5008,27 +5008,35 @@ gui_mch_set_shellsize(int width, int height, } void -gui_gtk_get_screen_size_of_win(GtkWidget *wid, int *width, int *height) +gui_gtk_get_screen_geom_of_win( + GtkWidget *wid, + int *screen_x, + int *screen_y, + int *width, + int *height) { + GdkRectangle geometry; + GdkWindow *win = gtk_widget_get_window(wid); #if GTK_CHECK_VERSION(3,22,0) GdkDisplay *dpy = gtk_widget_get_display(wid); - GdkWindow *win = gtk_widget_get_window(wid); GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); - GdkRectangle geometry; gdk_monitor_get_geometry(monitor, &geometry); - *width = geometry.width; - *height = geometry.height; #else GdkScreen* screen; + int monitor; if (wid != NULL && gtk_widget_has_screen(wid)) screen = gtk_widget_get_screen(wid); else screen = gdk_screen_get_default(); - *width = gdk_screen_get_width(screen); - *height = gdk_screen_get_height(screen); + monitor = gdk_screen_get_monitor_at_window(screen, win); + gdk_screen_get_monitor_geometry(screen, monitor, &geometry); #endif + *screen_x = geometry.x; + *screen_y = geometry.y; + *width = geometry.width; + *height = geometry.height; } /* @@ -5039,7 +5047,9 @@ gui_gtk_get_screen_size_of_win(GtkWidget *wid, int *width, int *height) void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) { - gui_gtk_get_screen_size_of_win(gui.mainwin, screen_w, screen_h); + int x, y; + + gui_gtk_get_screen_geom_of_win(gui.mainwin, &x, &y, screen_w, screen_h); /* Subtract 'guiheadroom' from the height to allow some room for the * window manager (task list and window title bar). */ diff --git a/src/mbyte.c b/src/mbyte.c index 96b39b4114..ee1d572ee0 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4951,24 +4951,26 @@ im_add_to_input(char_u *str, int len) static void im_preedit_window_set_position(void) { - int x, y, w, h, sw, sh; + int x, y, width, height; + int screen_x, screen_y, screen_width, screen_height; if (preedit_window == NULL) return; - gui_gtk_get_screen_size_of_win(preedit_window, &sw, &sh); + gui_gtk_get_screen_geom_of_win(gui.drawarea, + &screen_x, &screen_y, &screen_width, &screen_height); #if GTK_CHECK_VERSION(3,0,0) gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), &x, &y); #else gdk_window_get_origin(gui.drawarea->window, &x, &y); #endif - gtk_window_get_size(GTK_WINDOW(preedit_window), &w, &h); + gtk_window_get_size(GTK_WINDOW(preedit_window), &width, &height); x = x + FILL_X(gui.col); y = y + FILL_Y(gui.row); - if (x + w > sw) - x = sw - w; - if (y + h > sh) - y = sh - h; + if (x + width > screen_x + screen_width) + x = screen_x + screen_width - width; + if (y + height > screen_y + screen_height) + y = screen_y + screen_height - height; gtk_window_move(GTK_WINDOW(preedit_window), x, y); } diff --git a/src/proto/gui_gtk_x11.pro b/src/proto/gui_gtk_x11.pro index aea8d0b68e..111cac7c99 100644 --- a/src/proto/gui_gtk_x11.pro +++ b/src/proto/gui_gtk_x11.pro @@ -25,7 +25,7 @@ int gui_mch_maximized(void); void gui_mch_unmaximize(void); void gui_mch_newfont(void); void gui_mch_set_shellsize(int width, int height, int min_width, int min_height, int base_width, int base_height, int direction); -void gui_gtk_get_screen_size_of_win(GtkWidget *wid, int *width, int *height); +void gui_gtk_get_screen_geom_of_win(GtkWidget *wid, int *screen_x, int *screen_y, int *width, int *height); void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h); void gui_mch_settitle(char_u *title, char_u *icon); void gui_mch_enable_menu(int showit); diff --git a/src/version.c b/src/version.c index e7ea55f9d5..4cb2f34195 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 301, /**/ 300, /**/ From f1883479be91550bc31dd88f593b3012863a2629 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Aug 2018 21:58:57 +0200 Subject: [PATCH 22/35] patch 8.1.0302: crash when using :suspend and "fg" Problem: Crash when using :suspend and "fg". Solution: Undo patch 8.1.244. --- src/os_unix.c | 69 +++++++++------------------------------------- src/proto/term.pro | 1 - src/term.c | 15 +++------- src/version.c | 2 ++ 4 files changed, 19 insertions(+), 68 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index b044df27f7..39ace2e295 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1228,24 +1228,7 @@ deathtrap SIGDEFARG(sigarg) SIGRETURN; } - static void -after_sigcont(void) -{ -# ifdef FEAT_TITLE - // Don't change "oldtitle" in a signal handler, set a flag to obtain it - // again later. - oldtitle_outdated = TRUE; -# endif - settmode(TMODE_RAW); - need_check_timestamps = TRUE; - did_check_timestamps = FALSE; -} - -#if defined(SIGCONT) -static RETSIGTYPE sigcont_handler SIGPROTOARG; -static int in_mch_suspend = FALSE; - -# if defined(_REENTRANT) && defined(SIGCONT) +#if defined(_REENTRANT) && defined(SIGCONT) /* * On Solaris with multi-threading, suspending might not work immediately. * Catch the SIGCONT signal, which will be used as an indication whether the @@ -1257,7 +1240,7 @@ static int in_mch_suspend = FALSE; * volatile because it is used in signal handler sigcont_handler(). */ static volatile int sigcont_received; -# endif +static RETSIGTYPE sigcont_handler SIGPROTOARG; /* * signal handler for SIGCONT @@ -1265,38 +1248,7 @@ static volatile int sigcont_received; static RETSIGTYPE sigcont_handler SIGDEFARG(sigarg) { - if (in_mch_suspend) - { -# if defined(_REENTRANT) && defined(SIGCONT) - sigcont_received = TRUE; -# endif - } - else - { - // We didn't suspend ourselves, assume we were stopped by a SIGSTOP - // signal (which can't be intercepted) and get a SIGCONT. Need to get - // back to a sane mode and redraw. - after_sigcont(); - - update_screen(CLEAR); - if (State & CMDLINE) - redrawcmdline(); - else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE - || State == EXTERNCMD || State == CONFIRM || exmode_active) - repeat_message(); - else if (redrawing()) - setcursor(); -#if defined(FEAT_INS_EXPAND) - if (pum_visible()) - { - redraw_later(NOT_VALID); - ins_compl_show_pum(); - } -#endif - cursor_on_force(); - out_flush(); - } - + sigcont_received = TRUE; SIGRETURN; } #endif @@ -1379,8 +1331,6 @@ mch_suspend(void) { /* BeOS does have SIGTSTP, but it doesn't work. */ #if defined(SIGTSTP) && !defined(__BEOS__) - in_mch_suspend = TRUE; - out_flush(); /* needed to make cursor visible on some systems */ settmode(TMODE_COOK); out_flush(); /* needed to disable mouse on some systems */ @@ -1412,9 +1362,16 @@ mch_suspend(void) mch_delay(wait_time, FALSE); } # endif - in_mch_suspend = FALSE; - after_sigcont(); +# ifdef FEAT_TITLE + /* + * Set oldtitle to NULL, so the current title is obtained again. + */ + VIM_CLEAR(oldtitle); +# endif + settmode(TMODE_RAW); + need_check_timestamps = TRUE; + did_check_timestamps = FALSE; #else suspend_shell(); #endif @@ -1454,7 +1411,7 @@ set_signals(void) #ifdef SIGTSTP signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL); #endif -#if defined(SIGCONT) +#if defined(_REENTRANT) && defined(SIGCONT) signal(SIGCONT, sigcont_handler); #endif diff --git a/src/proto/term.pro b/src/proto/term.pro index 1b8ab5f0dd..c68d7ab033 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -52,7 +52,6 @@ void setmouse(void); int mouse_has(int c); int mouse_model_popup(void); void scroll_start(void); -void cursor_on_force(void); void cursor_on(void); void cursor_off(void); void term_cursor_mode(int forced); diff --git a/src/term.c b/src/term.c index 66f03ee108..97ddf8bc4a 100644 --- a/src/term.c +++ b/src/term.c @@ -3833,16 +3833,6 @@ scroll_start(void) static int cursor_is_off = FALSE; -/* - * Enable the cursor without checking if it's already enabled. - */ - void -cursor_on_force(void) -{ - out_str(T_VE); - cursor_is_off = FALSE; -} - /* * Enable the cursor. */ @@ -3850,7 +3840,10 @@ cursor_on_force(void) cursor_on(void) { if (cursor_is_off) - cursor_on_force(); + { + out_str(T_VE); + cursor_is_off = FALSE; + } } /* diff --git a/src/version.c b/src/version.c index 4cb2f34195..42a81ccfa8 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 302, /**/ 301, /**/ From c26f7c60532a37a2bf0a5e69aa81081b440dfc38 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Aug 2018 22:53:04 +0200 Subject: [PATCH 23/35] patch 8.1.0303: line2byte() is wrong for last line with 'noeol' Problem: line2byte() is wrong for last line with 'noeol' and 'nofixeol'. Solution: Fix off-by-one error. (Shane Harper, closes #3351) --- src/memline.c | 2 +- src/testdir/test_functions.vim | 12 +++++++++++- src/version.c | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/memline.c b/src/memline.c index a2f0b4f626..fb262acef5 100644 --- a/src/memline.c +++ b/src/memline.c @@ -5267,7 +5267,7 @@ ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp) /* Don't count the last line break if 'noeol' and ('bin' or * 'nofixeol'). */ if ((!buf->b_p_fixeol || buf->b_p_bin) && !buf->b_p_eol - && buf->b_ml.ml_line_count == lnum) + && lnum > buf->b_ml.ml_line_count) size -= ffdos + 1; } diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 13db0041e7..848e7986c3 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -682,6 +682,7 @@ endfunc func Test_byte2line_line2byte() new + set endofline call setline(1, ['a', 'bc', 'd']) set fileformat=unix @@ -702,7 +703,16 @@ func Test_byte2line_line2byte() call assert_equal([-1, -1, 1, 4, 8, 11, -1], \ map(range(-1, 5), 'line2byte(v:val)')) - set fileformat& + bw! + set noendofline nofixendofline + normal a- + for ff in ["unix", "mac", "dos"] + let &fileformat = ff + call assert_equal(1, line2byte(1)) + call assert_equal(2, line2byte(2)) " line2byte(line("$") + 1) is the buffer size plus one (as per :help line2byte). + endfor + + set endofline& fixendofline& fileformat& bw! endfunc diff --git a/src/version.c b/src/version.c index 42a81ccfa8..d382ff316d 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 303, /**/ 302, /**/ From 2e31048c304fb94d6255667783edfe9f4d5894c2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 13:09:10 +0200 Subject: [PATCH 24/35] patch 8.1.0304: no redraw when using a STOP signal on Vim and then CONT Problem: No redraw when using a STOP signal on Vim and then a CONT signal. Solution: Catch the CONT signal and set the terminal to raw mode. This is like 8.1.0244 but without the screen redraw and a fix for multi-threading suggested by Dominique Pelle. --- src/os_unix.c | 88 +++++++++++++++++++++++++++++++--------------- src/proto/term.pro | 1 + src/term.c | 17 ++++++--- src/version.c | 2 ++ 4 files changed, 74 insertions(+), 34 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index 39ace2e295..80c61755b1 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1228,14 +1228,35 @@ deathtrap SIGDEFARG(sigarg) SIGRETURN; } -#if defined(_REENTRANT) && defined(SIGCONT) /* - * On Solaris with multi-threading, suspending might not work immediately. - * Catch the SIGCONT signal, which will be used as an indication whether the - * suspending has been done or not. + * Invoked after receiving SIGCONT. We don't know what happened while + * sleeping, deal with part of that. + */ + static void +after_sigcont(void) +{ +# ifdef FEAT_TITLE + // Don't change "oldtitle" in a signal handler, set a flag to obtain it + // again later. + oldtitle_outdated = TRUE; +# endif + settmode(TMODE_RAW); + need_check_timestamps = TRUE; + did_check_timestamps = FALSE; +} + +#if defined(SIGCONT) +static RETSIGTYPE sigcont_handler SIGPROTOARG; +static volatile int in_mch_suspend = FALSE; + +/* + * With multi-threading, suspending might not work immediately. Catch the + * SIGCONT signal, which will be used as an indication whether the suspending + * has been done or not. * * On Linux, signal is not always handled immediately either. * See https://bugs.launchpad.net/bugs/291373 + * Probably because the signal is handled in another thread. * * volatile because it is used in signal handler sigcont_handler(). */ @@ -1248,7 +1269,22 @@ static RETSIGTYPE sigcont_handler SIGPROTOARG; static RETSIGTYPE sigcont_handler SIGDEFARG(sigarg) { - sigcont_received = TRUE; + if (in_mch_suspend) + { + sigcont_received = TRUE; + } + else + { + // We didn't suspend ourselves, assume we were stopped by a SIGSTOP + // signal (which can't be intercepted) and get a SIGCONT. Need to get + // back to a sane mode. We should redraw, but we can't really do that + // in a signal handler, do a redraw later. + after_sigcont(); + redraw_later(CLEAR); + cursor_on_force(); + out_flush(); + } + SIGRETURN; } #endif @@ -1331,6 +1367,8 @@ mch_suspend(void) { /* BeOS does have SIGTSTP, but it doesn't work. */ #if defined(SIGTSTP) && !defined(__BEOS__) + in_mch_suspend = TRUE; + out_flush(); /* needed to make cursor visible on some systems */ settmode(TMODE_COOK); out_flush(); /* needed to disable mouse on some systems */ @@ -1338,40 +1376,32 @@ mch_suspend(void) # if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) loose_clipboard(); # endif - -# if defined(_REENTRANT) && defined(SIGCONT) +# if defined(SIGCONT) sigcont_received = FALSE; # endif + kill(0, SIGTSTP); /* send ourselves a STOP signal */ -# if defined(_REENTRANT) && defined(SIGCONT) + +# if defined(SIGCONT) /* * Wait for the SIGCONT signal to be handled. It generally happens - * immediately, but somehow not all the time. Do not call pause() - * because there would be race condition which would hang Vim if - * signal happened in between the test of sigcont_received and the - * call to pause(). If signal is not yet received, call sleep(0) - * to just yield CPU. Signal should then be received. If somehow - * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting - * further if signal is not received after 1+2+3+4 ms (not expected - * to happen). + * immediately, but somehow not all the time, probably because it's handled + * in another thread. Do not call pause() because there would be race + * condition which would hang Vim if signal happened in between the test of + * sigcont_received and the call to pause(). If signal is not yet received, + * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not + * received after 1+2+3 ms (not expected to happen). */ { long wait_time; + for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++) - /* Loop is not entered most of the time */ mch_delay(wait_time, FALSE); } # endif + in_mch_suspend = FALSE; -# ifdef FEAT_TITLE - /* - * Set oldtitle to NULL, so the current title is obtained again. - */ - VIM_CLEAR(oldtitle); -# endif - settmode(TMODE_RAW); - need_check_timestamps = TRUE; - did_check_timestamps = FALSE; + after_sigcont(); #else suspend_shell(); #endif @@ -1411,7 +1441,7 @@ set_signals(void) #ifdef SIGTSTP signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL); #endif -#if defined(_REENTRANT) && defined(SIGCONT) +#if defined(SIGCONT) signal(SIGCONT, sigcont_handler); #endif @@ -1470,7 +1500,7 @@ catch_int_signal(void) reset_signals(void) { catch_signals(SIG_DFL, SIG_DFL); -#if defined(_REENTRANT) && defined(SIGCONT) +#if defined(SIGCONT) /* SIGCONT isn't in the list, because its default action is ignore */ signal(SIGCONT, SIG_DFL); #endif @@ -1533,7 +1563,7 @@ block_signals(sigset_t *set) for (i = 0; signal_info[i].sig != -1; i++) sigaddset(&newset, signal_info[i].sig); -# if defined(_REENTRANT) && defined(SIGCONT) +# if defined(SIGCONT) /* SIGCONT isn't in the list, because its default action is ignore */ sigaddset(&newset, SIGCONT); # endif diff --git a/src/proto/term.pro b/src/proto/term.pro index c68d7ab033..1b8ab5f0dd 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -52,6 +52,7 @@ void setmouse(void); int mouse_has(int c); int mouse_model_popup(void); void scroll_start(void); +void cursor_on_force(void); void cursor_on(void); void cursor_off(void); void term_cursor_mode(int forced); diff --git a/src/term.c b/src/term.c index 97ddf8bc4a..cede4b8949 100644 --- a/src/term.c +++ b/src/term.c @@ -3834,16 +3834,23 @@ scroll_start(void) static int cursor_is_off = FALSE; /* - * Enable the cursor. + * Enable the cursor without checking if it's already enabled. + */ + void +cursor_on_force(void) +{ + out_str(T_VE); + cursor_is_off = FALSE; +} + +/* + * Enable the cursor if it's currently off. */ void cursor_on(void) { if (cursor_is_off) - { - out_str(T_VE); - cursor_is_off = FALSE; - } + cursor_on_force(); } /* diff --git a/src/version.c b/src/version.c index d382ff316d..8fa17ec790 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 304, /**/ 303, /**/ From 830e3583da682eee41ed6b027c9912547d4022c0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 14:23:35 +0200 Subject: [PATCH 25/35] patch 8.1.0305: missing support for Lua 5.4 32 bits on Unix Problem: Missing support for Lua 5.4 32 bits on Unix. Solution: Define lua_newuserdatauv. (Kazunobu Kuriyama) --- src/if_lua.c | 14 +++++++++++++- src/version.c | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/if_lua.c b/src/if_lua.c index 7602c80de4..6e33734643 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -164,7 +164,11 @@ static luaV_Funcref *luaV_pushfuncref(lua_State *L, typval_T *tv); #define lua_rawget dll_lua_rawget #define lua_rawgeti dll_lua_rawgeti #define lua_createtable dll_lua_createtable -#define lua_newuserdata dll_lua_newuserdata +#if LUA_VERSION_NUM >= 504 + #define lua_newuserdatauv dll_lua_newuserdatauv +#else + #define lua_newuserdata dll_lua_newuserdata +#endif #define lua_getmetatable dll_lua_getmetatable #define lua_setfield dll_lua_setfield #define lua_rawset dll_lua_rawset @@ -261,7 +265,11 @@ int (*dll_lua_rawget) (lua_State *L, int idx); int (*dll_lua_rawgeti) (lua_State *L, int idx, lua_Integer n); #endif void (*dll_lua_createtable) (lua_State *L, int narr, int nrec); +#if LUA_VERSION_NUM >= 504 +void *(*dll_lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); +#else void *(*dll_lua_newuserdata) (lua_State *L, size_t sz); +#endif int (*dll_lua_getmetatable) (lua_State *L, int objindex); void (*dll_lua_setfield) (lua_State *L, int idx, const char *k); void (*dll_lua_rawset) (lua_State *L, int idx); @@ -362,7 +370,11 @@ static const luaV_Reg luaV_dll[] = { {"lua_rawget", (luaV_function) &dll_lua_rawget}, {"lua_rawgeti", (luaV_function) &dll_lua_rawgeti}, {"lua_createtable", (luaV_function) &dll_lua_createtable}, +#if LUA_VERSION_NUM >= 504 + {"lua_newuserdatauv", (luaV_function) &dll_lua_newuserdatauv}, +#else {"lua_newuserdata", (luaV_function) &dll_lua_newuserdata}, +#endif {"lua_getmetatable", (luaV_function) &dll_lua_getmetatable}, {"lua_setfield", (luaV_function) &dll_lua_setfield}, {"lua_rawset", (luaV_function) &dll_lua_rawset}, diff --git a/src/version.c b/src/version.c index 8fa17ec790..9cb104134c 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 305, /**/ 304, /**/ From da6e8919e75fa8f961d1b805e877c8a92e76dafb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 15:12:14 +0200 Subject: [PATCH 26/35] patch 8.1.0306: plural messages are not translated properly Problem: Plural messages are not translated properly. Solution: Add more usage of NGETTEXT(). (Sergey Alyoshin) --- src/buffer.c | 37 +++++++------------------ src/ex_cmds.c | 40 ++++++++++++++------------- src/ex_docmd.c | 16 ++++------- src/fileio.c | 13 +++------ src/misc1.c | 22 ++++----------- src/ops.c | 73 +++++++++++++++++++------------------------------- src/version.c | 2 ++ src/vim.h | 4 +++ 8 files changed, 79 insertions(+), 128 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index 6405372546..6bcd28b36c 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1174,26 +1174,14 @@ do_bufdel( else if (deleted >= p_report) { if (command == DOBUF_UNLOAD) - { - if (deleted == 1) - MSG(_("1 buffer unloaded")); - else - smsg((char_u *)_("%d buffers unloaded"), deleted); - } + smsg((char_u *)NGETTEXT("%d buffer unloaded", + "%d buffers unloaded", deleted), deleted); else if (command == DOBUF_DEL) - { - if (deleted == 1) - MSG(_("1 buffer deleted")); - else - smsg((char_u *)_("%d buffers deleted"), deleted); - } + smsg((char_u *)NGETTEXT("%d buffer deleted", + "%d buffers deleted", deleted), deleted); else - { - if (deleted == 1) - MSG(_("1 buffer wiped out")); - else - smsg((char_u *)_("%d buffers wiped out"), deleted); - } + smsg((char_u *)NGETTEXT("%d buffer wiped out", + "%d buffers wiped out", deleted), deleted); } } @@ -3485,19 +3473,14 @@ fileinfo( n = (int)(((long)curwin->w_cursor.lnum * 100L) / (long)curbuf->b_ml.ml_line_count); if (curbuf->b_ml.ml_flags & ML_EMPTY) - { vim_snprintf_add((char *)buffer, IOSIZE, "%s", _(no_lines_msg)); - } #ifdef FEAT_CMDL_INFO else if (p_ru) - { /* Current line and column are already on the screen -- webb */ - if (curbuf->b_ml.ml_line_count == 1) - vim_snprintf_add((char *)buffer, IOSIZE, _("1 line --%d%%--"), n); - else - vim_snprintf_add((char *)buffer, IOSIZE, _("%ld lines --%d%%--"), - (long)curbuf->b_ml.ml_line_count, n); - } + vim_snprintf_add((char *)buffer, IOSIZE, + NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--", + curbuf->b_ml.ml_line_count), + (long)curbuf->b_ml.ml_line_count, n); #endif else { diff --git a/src/ex_cmds.c b/src/ex_cmds.c index bee50c5955..6e713c49a3 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -985,12 +985,8 @@ do_move(linenr_T line1, linenr_T line2, linenr_T dest) ml_delete(line1 + extra, TRUE); if (!global_busy && num_lines > p_report) - { - if (num_lines == 1) - MSG(_("1 line moved")); - else - smsg((char_u *)_("%ld lines moved"), num_lines); - } + smsg((char_u *)NGETTEXT("%ld line moved", "%ld lines moved", num_lines), + (long)num_lines); /* * Leave the cursor on the last of the moved lines. @@ -5940,23 +5936,29 @@ do_sub_msg( || count_only) && messaging()) { + char *msg_single; + char *msg_plural; + if (got_int) STRCPY(msg_buf, _("(Interrupted) ")); else *msg_buf = NUL; - if (sub_nsubs == 1) - vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), - "%s", count_only ? _("1 match") : _("1 substitution")); - else - vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), - count_only ? _("%ld matches") : _("%ld substitutions"), - sub_nsubs); - if (sub_nlines == 1) - vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), - "%s", _(" on 1 line")); - else - vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), - _(" on %ld lines"), (long)sub_nlines); + + msg_single = count_only + ? NGETTEXT("%ld match on %ld line", + "%ld matches on %ld line", sub_nsubs) + : NGETTEXT("%ld substitution on %ld line", + "%ld substitutions on %ld line", sub_nsubs); + msg_plural = count_only + ? NGETTEXT("%ld match on %ld lines", + "%ld matches on %ld lines", sub_nsubs) + : NGETTEXT("%ld substitution on %ld lines", + "%ld substitutions on %ld lines", sub_nsubs); + + vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), + NGETTEXT(msg_single, msg_plural, sub_nlines), + sub_nsubs, (long)sub_nlines); + if (msg(msg_buf)) /* save message to display it after redraw */ set_keep_msg(msg_buf, 0); diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 14ec213239..ccd96b1d32 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -5749,22 +5749,16 @@ check_more( { char_u buff[DIALOG_MSG_SIZE]; - if (n == 1) - vim_strncpy(buff, - (char_u *)_("1 more file to edit. Quit anyway?"), - DIALOG_MSG_SIZE - 1); - else - vim_snprintf((char *)buff, DIALOG_MSG_SIZE, - _("%d more files to edit. Quit anyway?"), n); + vim_snprintf((char *)buff, DIALOG_MSG_SIZE, + NGETTEXT("%d more file to edit. Quit anyway?", + "%d more files to edit. Quit anyway?", n), n); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) return OK; return FAIL; } #endif - if (n == 1) - EMSG(_("E173: 1 more file to edit")); - else - EMSGN(_("E173: %ld more files to edit"), n); + EMSGN(NGETTEXT("E173: %ld more file to edit", + "E173: %ld more files to edit", n), n); quitmore = 2; /* next try to quit is allowed */ } return FAIL; diff --git a/src/fileio.c b/src/fileio.c index 7bceb75fd7..d00dc5e47b 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5349,16 +5349,11 @@ msg_add_lines( "%ldL, %lldC", lnum, (long long)nchars); else { - if (lnum == 1) - STRCPY(p, _("1 line, ")); - else - sprintf((char *)p, _("%ld lines, "), lnum); + sprintf((char *)p, NGETTEXT("%ld line, ", "%ld lines, ", lnum), lnum); p += STRLEN(p); - if (nchars == 1) - STRCPY(p, _("1 character")); - else - vim_snprintf((char *)p, IOSIZE - (p - IObuff), - _("%lld characters"), (long long)nchars); + vim_snprintf((char *)p, IOSIZE - (p - IObuff), + NGETTEXT("%lld character", "%lld characters", nchars), + (long long)nchars); } } diff --git a/src/misc1.c b/src/misc1.c index 1647aa9524..f2aa96b372 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -3802,24 +3802,12 @@ msgmore(long n) if (pn > p_report) { - if (pn == 1) - { - if (n > 0) - vim_strncpy(msg_buf, (char_u *)_("1 more line"), - MSG_BUF_LEN - 1); - else - vim_strncpy(msg_buf, (char_u *)_("1 line less"), - MSG_BUF_LEN - 1); - } + if (n > 0) + vim_snprintf((char *)msg_buf, MSG_BUF_LEN, + NGETTEXT("%ld more line", "%ld more lines", pn), pn); else - { - if (n > 0) - vim_snprintf((char *)msg_buf, MSG_BUF_LEN, - _("%ld more lines"), pn); - else - vim_snprintf((char *)msg_buf, MSG_BUF_LEN, - _("%ld fewer lines"), pn); - } + vim_snprintf((char *)msg_buf, MSG_BUF_LEN, + NGETTEXT("%ld line less", "%ld fewer lines", pn), pn); if (got_int) vim_strcat(msg_buf, (char_u *)_(" (Interrupted)"), MSG_BUF_LEN); if (msg(msg_buf)) diff --git a/src/ops.c b/src/ops.c index 50ebf44495..3384556f90 100644 --- a/src/ops.c +++ b/src/ops.c @@ -244,7 +244,6 @@ op_shift(oparg_T *oap, int curs_top, int amount) { long i; int first_char; - char_u *s; int block_col = 0; if (u_save((linenr_T)(oap->start.lnum - 1), @@ -297,26 +296,21 @@ op_shift(oparg_T *oap, int curs_top, int amount) if (oap->line_count > p_report) { + char *op; + char *msg_line_single; + char *msg_line_plural; + if (oap->op_type == OP_RSHIFT) - s = (char_u *)">"; + op = ">"; else - s = (char_u *)"<"; - if (oap->line_count == 1) - { - if (amount == 1) - sprintf((char *)IObuff, _("1 line %sed 1 time"), s); - else - sprintf((char *)IObuff, _("1 line %sed %d times"), s, amount); - } - else - { - if (amount == 1) - sprintf((char *)IObuff, _("%ld lines %sed 1 time"), - oap->line_count, s); - else - sprintf((char *)IObuff, _("%ld lines %sed %d times"), - oap->line_count, s, amount); - } + op = "<"; + msg_line_single = NGETTEXT("%ld line %sed %d time", + "%ld line %sed %d times", amount); + msg_line_plural = NGETTEXT("%ld lines %sed %d time", + "%ld lines %sed %d times", amount); + vim_snprintf((char *)IObuff, IOSIZE, + NGETTEXT(msg_line_single, msg_line_plural, oap->line_count), + oap->line_count, op, amount); msg(IObuff); } @@ -789,10 +783,8 @@ op_reindent(oparg_T *oap, int (*how)(void)) if (oap->line_count > p_report) { i = oap->line_count - (i + 1); - if (i == 1) - MSG(_("1 line indented ")); - else - smsg((char_u *)_("%ld lines indented "), i); + smsg((char_u *)NGETTEXT("%ld line indented ", + "%ld lines indented ", i), i); } /* set '[ and '] marks */ curbuf->b_op_start = oap->start; @@ -2529,12 +2521,8 @@ op_tilde(oparg_T *oap) curbuf->b_op_end = oap->end; if (oap->line_count > p_report) - { - if (oap->line_count == 1) - MSG(_("1 line changed")); - else - smsg((char_u *)_("%ld lines changed"), oap->line_count); - } + smsg((char_u *)NGETTEXT("%ld line changed", "%ld lines changed", + oap->line_count), oap->line_count); } /* @@ -3348,19 +3336,18 @@ op_yank(oparg_T *oap, int deleting, int mess) /* redisplay now, so message is not deleted */ update_topline_redraw(); - if (yanklines == 1) + if (oap->block_mode) { - if (oap->block_mode) - smsg((char_u *)_("block of 1 line yanked%s"), namebuf); - else - smsg((char_u *)_("1 line yanked%s"), namebuf); + smsg((char_u *)NGETTEXT("block of %ld line yanked%s", + "block of %ld lines yanked%s", yanklines), + yanklines, namebuf); } - else if (oap->block_mode) - smsg((char_u *)_("block of %ld lines yanked%s"), - yanklines, namebuf); else - smsg((char_u *)_("%ld lines yanked%s"), yanklines, - namebuf); + { + smsg((char_u *)NGETTEXT("%ld line yanked%s", + "%ld lines yanked%s", yanklines), + yanklines, namebuf); + } } } @@ -5653,12 +5640,8 @@ op_addsub( curbuf->b_op_start = startpos; if (change_cnt > p_report) - { - if (change_cnt == 1) - MSG(_("1 line changed")); - else - smsg((char_u *)_("%ld lines changed"), change_cnt); - } + smsg((char_u *)NGETTEXT("%ld line changed", "%ld lines changed", + change_cnt), change_cnt); } } diff --git a/src/version.c b/src/version.c index 9cb104134c..5f03975c94 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 306, /**/ 305, /**/ diff --git a/src/vim.h b/src/vim.h index 794d2cd773..ece5414fea 100644 --- a/src/vim.h +++ b/src/vim.h @@ -553,6 +553,10 @@ extern int (*dyn_libintl_putenv)(const char *envstring); /* * The _() stuff is for using gettext(). It is a no-op when libintl.h is not * found or the +multilang feature is disabled. + * Use NGETTEXT(single, multi, number) to get plural behavior: + * - single - message for singular form + * - multi - message for plural form + * - number - the count */ #ifdef FEAT_GETTEXT # ifdef DYNAMIC_GETTEXT From 0f6b4f06dece71487a6d8546c50de775d9c8c287 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 16:56:34 +0200 Subject: [PATCH 27/35] patch 8.1.0307: there is no good way to get the window layout Problem: There is no good way to get the window layout. Solution: Add the winlayout() function. (Yegappan Lakshmanan) --- runtime/doc/eval.txt | 30 +++++++++++++++++++++ src/evalfunc.c | 25 +++++++++++++++++ src/proto/window.pro | 1 + src/testdir/test_window_id.vim | 20 ++++++++++++++ src/version.c | 2 ++ src/window.c | 49 ++++++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 53ee2094e3..821cbbca9b 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2497,6 +2497,7 @@ win_screenpos({nr}) List get screen position of window {nr} winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor winheight({nr}) Number height of window {nr} +winlayout([{tabnr}]) List layout of windows in tab {tabnr} winline() Number window line of the cursor winnr([{expr}]) Number number of current window winrestcmd() String returns command to restore window sizes @@ -9087,6 +9088,35 @@ winheight({nr}) *winheight()* This excludes any window toolbar line. Examples: > :echo "The current window has " . winheight(0) . " lines." +< +winlayout([{tabnr}]) *winlayout()* + The result is a nested List containing the layout of windows + in a tabpage. + + Without {tabnr} use the current tabpage, otherwise the tabpage + with number {tabnr}. If the tabpage {tabnr} is not found, + returns an empty list. + + For a leaf window, it returns: + ['leaf', {winid}] + For horizontally split windows, which form a column, it + returns: + ['col', [{nested list of windows}]] + For vertically split windows, which form a row, it returns: + ['row', [{nested list of windows}]] + + Example: > + " Only one window in the tab page + :echo winlayout() + ['leaf', 1000] + " Two horizontally split windows + :echo winlayout() + ['col', [['leaf', 1000], ['leaf', 1001]]] + " Three horizontally split windows, with two + " vertically split windows in the middle window + :echo winlayout(2) + ['col', [['leaf', 1002], ['row', ['leaf', 1003], + ['leaf', 1001]]], ['leaf', 1000]] < *winline()* winline() The result is a Number, which is the screen line of the cursor diff --git a/src/evalfunc.c b/src/evalfunc.c index 2bebdd1c62..5e7c013979 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -463,6 +463,7 @@ static void f_win_screenpos(typval_T *argvars, typval_T *rettv); static void f_winbufnr(typval_T *argvars, typval_T *rettv); static void f_wincol(typval_T *argvars, typval_T *rettv); static void f_winheight(typval_T *argvars, typval_T *rettv); +static void f_winlayout(typval_T *argvars, typval_T *rettv); static void f_winline(typval_T *argvars, typval_T *rettv); static void f_winnr(typval_T *argvars, typval_T *rettv); static void f_winrestcmd(typval_T *argvars, typval_T *rettv); @@ -952,6 +953,7 @@ static struct fst {"winbufnr", 1, 1, f_winbufnr}, {"wincol", 0, 0, f_wincol}, {"winheight", 1, 1, f_winheight}, + {"winlayout", 0, 1, f_winlayout}, {"winline", 0, 0, f_winline}, {"winnr", 0, 1, f_winnr}, {"winrestcmd", 0, 0, f_winrestcmd}, @@ -13742,6 +13744,29 @@ f_winheight(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = wp->w_height; } +/* + * "winlayout()" function + */ + static void +f_winlayout(typval_T *argvars, typval_T *rettv) +{ + tabpage_T *tp; + + if (rettv_list_alloc(rettv) != OK) + return; + + if (argvars[0].v_type == VAR_UNKNOWN) + tp = curtab; + else + { + tp = find_tabpage((int)get_tv_number(&argvars[0])); + if (tp == NULL) + return; + } + + get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE); +} + /* * "winline()" function */ diff --git a/src/proto/window.pro b/src/proto/window.pro index 7ed8042f7b..c31e59969b 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -94,4 +94,5 @@ void win_id2tabwin(typval_T *argvars, list_T *list); win_T *win_id2wp(typval_T *argvars); int win_id2win(typval_T *argvars); void win_findbuf(typval_T *argvars, list_T *list); +void get_framelayout(frame_T *fr, list_T *l, int topframe); /* vim: set ft=c : */ diff --git a/src/testdir/test_window_id.vim b/src/testdir/test_window_id.vim index b3b506d04d..d10d831650 100644 --- a/src/testdir/test_window_id.vim +++ b/src/testdir/test_window_id.vim @@ -101,3 +101,23 @@ func Test_win_getid_curtab() call assert_equal(win_getid(1), win_getid(1, 1)) tabclose! endfunc + +func Test_winlayout() + let w1 = win_getid() + call assert_equal(['leaf', w1], winlayout()) + + split + let w2 = win_getid() + call assert_equal(['col', [['leaf', w2], ['leaf', w1]]], winlayout()) + + split + let w3 = win_getid() + call assert_equal(['col', [['leaf', w3], ['leaf', w2], ['leaf', w1]]], winlayout()) + + 2wincmd w + vsplit + let w4 = win_getid() + call assert_equal(['col', [['leaf', w3], ['row', [['leaf', w4], ['leaf', w2]]], ['leaf', w1]]], winlayout()) + + only! +endfunc diff --git a/src/version.c b/src/version.c index 5f03975c94..bad2b33242 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 307, /**/ 306, /**/ diff --git a/src/window.c b/src/window.c index e1781d3f46..5671cf900e 100644 --- a/src/window.c +++ b/src/window.c @@ -7236,4 +7236,53 @@ win_findbuf(typval_T *argvars, list_T *list) list_append_number(list, wp->w_id); } +/* + * Get the layout of the given tab page for winlayout(). + */ + void +get_framelayout(frame_T *fr, list_T *l, int outer) +{ + frame_T *child; + list_T *fr_list; + list_T *win_list; + + if (fr == NULL) + return; + + if (outer) + // outermost call from f_winlayout() + fr_list = l; + else + { + fr_list = list_alloc(); + if (fr_list == NULL) + return; + list_append_list(l, fr_list); + } + + if (fr->fr_layout == FR_LEAF) + { + if (fr->fr_win != NULL) + { + list_append_string(fr_list, (char_u *)"leaf", -1); + list_append_number(fr_list, fr->fr_win->w_id); + } + } + else + { + list_append_string(fr_list, + fr->fr_layout == FR_ROW ? (char_u *)"row" : (char_u *)"col", -1); + + win_list = list_alloc(); + if (win_list == NULL) + return; + list_append_list(fr_list, win_list); + child = fr->fr_child; + while (child != NULL) + { + get_framelayout(child, win_list, FALSE); + child = child->fr_next; + } + } +} #endif From fd6100b2aa6178b88cfadcdbc494966bf79a5488 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 17:07:45 +0200 Subject: [PATCH 28/35] patch 8.1.0308: a quick undo shows "1 seconds ago" Problem: A quick undo shows "1 seconds ago". (Tony Mechelynck) Solution: Add singular/plural message. --- src/undo.c | 9 +++++++-- src/version.c | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/undo.c b/src/undo.c index 040ec54809..ebf18da499 100644 --- a/src/undo.c +++ b/src/undo.c @@ -3124,8 +3124,13 @@ u_add_time(char_u *buf, size_t buflen, time_t tt) } else #endif - vim_snprintf((char *)buf, buflen, _("%ld seconds ago"), - (long)(vim_time() - tt)); + { + long seconds = (long)(vim_time() - tt); + + vim_snprintf((char *)buf, buflen, + NGETTEXT("%ld second ago", "%ld seconds ago", seconds), + seconds); + } } /* diff --git a/src/version.c b/src/version.c index bad2b33242..51ead8f5d8 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 308, /**/ 307, /**/ From 7feb35e7782907b44659a2748ff5d7489deeed74 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 17:49:54 +0200 Subject: [PATCH 29/35] patch 8.1.0309: profiling does not show a count for condition lines Problem: Profiling does not show a count for condition lines. (Daniel Hahler) Solution: Count lines when not skipping. (Ozaki Kiichi, closes #2499) --- src/ex_docmd.c | 67 +++++++---- src/testdir/test_profile.vim | 225 ++++++++++++++++++++++++++++++++++- src/version.c | 2 + 3 files changed, 270 insertions(+), 24 deletions(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index ccd96b1d32..fc2b20ea7d 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -1766,28 +1766,6 @@ do_one_cmd( ea.skip = (if_level > 0); #endif -#ifdef FEAT_EVAL -# ifdef FEAT_PROFILE - /* Count this line for profiling if ea.skip is FALSE. */ - if (do_profiling == PROF_YES && !ea.skip) - { - if (getline_equal(fgetline, cookie, get_func_line)) - func_line_exec(getline_cookie(fgetline, cookie)); - else if (getline_equal(fgetline, cookie, getsourceline)) - script_line_exec(); - } -#endif - - /* May go to debug mode. If this happens and the ">quit" debug command is - * used, throw an interrupt exception and skip the next command. */ - dbg_check_breakpoint(&ea); - if (!ea.skip && got_int) - { - ea.skip = TRUE; - (void)do_intthrow(cstack); - } -#endif - /* * 3. Skip over the range to find the command. Let "p" point to after it. * @@ -1799,6 +1777,51 @@ do_one_cmd( ea.cmd = skipwhite(ea.cmd + 1); p = find_command(&ea, NULL); +#ifdef FEAT_EVAL +# ifdef FEAT_PROFILE + // Count this line for profiling if skip is TRUE. + if (do_profiling == PROF_YES + && (!ea.skip || cstack->cs_idx == 0 || (cstack->cs_idx > 0 + && (cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))) + { + int skip = did_emsg || got_int || did_throw; + + if (ea.cmdidx == CMD_catch) + skip = !skip && !(cstack->cs_idx >= 0 + && (cstack->cs_flags[cstack->cs_idx] & CSF_THROWN) + && !(cstack->cs_flags[cstack->cs_idx] & CSF_CAUGHT)); + else if (ea.cmdidx == CMD_else || ea.cmdidx == CMD_elseif) + skip = skip || !(cstack->cs_idx >= 0 + && !(cstack->cs_flags[cstack->cs_idx] + & (CSF_ACTIVE | CSF_TRUE))); + else if (ea.cmdidx == CMD_finally) + skip = FALSE; + else if (ea.cmdidx != CMD_endif + && ea.cmdidx != CMD_endfor + && ea.cmdidx != CMD_endtry + && ea.cmdidx != CMD_endwhile) + skip = ea.skip; + + if (!skip) + { + if (getline_equal(fgetline, cookie, get_func_line)) + func_line_exec(getline_cookie(fgetline, cookie)); + else if (getline_equal(fgetline, cookie, getsourceline)) + script_line_exec(); + } + } +# endif + + /* May go to debug mode. If this happens and the ">quit" debug command is + * used, throw an interrupt exception and skip the next command. */ + dbg_check_breakpoint(&ea); + if (!ea.skip && got_int) + { + ea.skip = TRUE; + (void)do_intthrow(cstack); + } +#endif + /* * 4. parse a range specifier of the form: addr [,addr] [;addr] .. * diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim index 6c24d31100..cf9f3465cf 100644 --- a/src/testdir/test_profile.vim +++ b/src/testdir/test_profile.vim @@ -67,7 +67,7 @@ func Test_profile_func() call assert_match('^\s*1\s\+.*\slet l:count = 100$', lines[13]) call assert_match('^\s*101\s\+.*\swhile l:count > 0$', lines[14]) call assert_match('^\s*100\s\+.*\s let l:count = l:count - 1$', lines[15]) - call assert_match('^\s*100\s\+.*\sendwhile$', lines[16]) + call assert_match('^\s*101\s\+.*\sendwhile$', lines[16]) call assert_equal('', lines[17]) call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[18]) call assert_equal('count total (s) self (s) function', lines[19]) @@ -84,6 +84,227 @@ func Test_profile_func() call delete('Xprofile_func.log') endfunc +func Test_profile_func_with_ifelse() + let lines = [ + \ "func! Foo1()", + \ " if 1", + \ " let x = 0", + \ " elseif 1", + \ " let x = 1", + \ " else", + \ " let x = 2", + \ " endif", + \ "endfunc", + \ "func! Foo2()", + \ " if 0", + \ " let x = 0", + \ " elseif 1", + \ " let x = 1", + \ " else", + \ " let x = 2", + \ " endif", + \ "endfunc", + \ "func! Foo3()", + \ " if 0", + \ " let x = 0", + \ " elseif 0", + \ " let x = 1", + \ " else", + \ " let x = 2", + \ " endif", + \ "endfunc", + \ "call Foo1()", + \ "call Foo2()", + \ "call Foo3()", + \ ] + + call writefile(lines, 'Xprofile_func.vim') + call system(v:progpath + \ . ' -es -u NONE -U NONE -i NONE --noplugin' + \ . ' -c "profile start Xprofile_func.log"' + \ . ' -c "profile func Foo*"' + \ . ' -c "so Xprofile_func.vim"' + \ . ' -c "qall!"') + call assert_equal(0, v:shell_error) + + let lines = readfile('Xprofile_func.log') + + " - Foo1() should pass 'if' block. + " - Foo2() should pass 'elseif' block. + " - Foo3() should pass 'else' block. + call assert_equal(54, len(lines)) + + call assert_equal('FUNCTION Foo1()', lines[0]) + call assert_equal('Called 1 time', lines[1]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3]) + call assert_equal('', lines[4]) + call assert_equal('count total (s) self (s)', lines[5]) + call assert_match('^\s*1\s\+.*\sif 1$', lines[6]) + call assert_match('^\s*1\s\+.*\s let x = 0$', lines[7]) + call assert_match( '^\s\+elseif 1$', lines[8]) + call assert_match( '^\s\+let x = 1$', lines[9]) + call assert_match( '^\s\+else$', lines[10]) + call assert_match( '^\s\+let x = 2$', lines[11]) + call assert_match('^\s*1\s\+.*\sendif$', lines[12]) + call assert_equal('', lines[13]) + call assert_equal('FUNCTION Foo2()', lines[14]) + call assert_equal('Called 1 time', lines[15]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[16]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[17]) + call assert_equal('', lines[18]) + call assert_equal('count total (s) self (s)', lines[19]) + call assert_match('^\s*1\s\+.*\sif 0$', lines[20]) + call assert_match( '^\s\+let x = 0$', lines[21]) + call assert_match('^\s*1\s\+.*\selseif 1$', lines[22]) + call assert_match('^\s*1\s\+.*\s let x = 1$', lines[23]) + call assert_match( '^\s\+else$', lines[24]) + call assert_match( '^\s\+let x = 2$', lines[25]) + call assert_match('^\s*1\s\+.*\sendif$', lines[26]) + call assert_equal('', lines[27]) + call assert_equal('FUNCTION Foo3()', lines[28]) + call assert_equal('Called 1 time', lines[29]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[30]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[31]) + call assert_equal('', lines[32]) + call assert_equal('count total (s) self (s)', lines[33]) + call assert_match('^\s*1\s\+.*\sif 0$', lines[34]) + call assert_match( '^\s\+let x = 0$', lines[35]) + call assert_match('^\s*1\s\+.*\selseif 0$', lines[36]) + call assert_match( '^\s\+let x = 1$', lines[37]) + call assert_match('^\s*1\s\+.*\selse$', lines[38]) + call assert_match('^\s*1\s\+.*\s let x = 2$', lines[39]) + call assert_match('^\s*1\s\+.*\sendif$', lines[40]) + call assert_equal('', lines[41]) + call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[42]) + call assert_equal('count total (s) self (s) function', lines[43]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[44]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[45]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[46]) + call assert_equal('', lines[47]) + call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[48]) + call assert_equal('count total (s) self (s) function', lines[49]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[50]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[51]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[52]) + call assert_equal('', lines[53]) + + call delete('Xprofile_func.vim') + call delete('Xprofile_func.log') +endfunc + +func Test_profile_func_with_trycatch() + let lines = [ + \ "func! Foo1()", + \ " try", + \ " let x = 0", + \ " catch", + \ " let x = 1", + \ " finally", + \ " let x = 2", + \ " endtry", + \ "endfunc", + \ "func! Foo2()", + \ " try", + \ " throw 0", + \ " catch", + \ " let x = 1", + \ " finally", + \ " let x = 2", + \ " endtry", + \ "endfunc", + \ "func! Foo3()", + \ " try", + \ " throw 0", + \ " catch", + \ " throw 1", + \ " finally", + \ " let x = 2", + \ " endtry", + \ "endfunc", + \ "call Foo1()", + \ "call Foo2()", + \ "try", + \ " call Foo3()", + \ "catch", + \ "endtry", + \ ] + + call writefile(lines, 'Xprofile_func.vim') + call system(v:progpath + \ . ' -es -u NONE -U NONE -i NONE --noplugin' + \ . ' -c "profile start Xprofile_func.log"' + \ . ' -c "profile func Foo*"' + \ . ' -c "so Xprofile_func.vim"' + \ . ' -c "qall!"') + call assert_equal(0, v:shell_error) + + let lines = readfile('Xprofile_func.log') + + " - Foo1() should pass 'try' 'finally' blocks. + " - Foo2() should pass 'catch' 'finally' blocks. + " - Foo3() should not pass 'endtry'. + call assert_equal(54, len(lines)) + + call assert_equal('FUNCTION Foo1()', lines[0]) + call assert_equal('Called 1 time', lines[1]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3]) + call assert_equal('', lines[4]) + call assert_equal('count total (s) self (s)', lines[5]) + call assert_match('^\s*1\s\+.*\stry$', lines[6]) + call assert_match('^\s*1\s\+.*\s let x = 0$', lines[7]) + call assert_match( '^\s\+catch$', lines[8]) + call assert_match( '^\s\+let x = 1$', lines[9]) + call assert_match('^\s*1\s\+.*\sfinally$', lines[10]) + call assert_match('^\s*1\s\+.*\s let x = 2$', lines[11]) + call assert_match('^\s*1\s\+.*\sendtry$', lines[12]) + call assert_equal('', lines[13]) + call assert_equal('FUNCTION Foo2()', lines[14]) + call assert_equal('Called 1 time', lines[15]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[16]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[17]) + call assert_equal('', lines[18]) + call assert_equal('count total (s) self (s)', lines[19]) + call assert_match('^\s*1\s\+.*\stry$', lines[20]) + call assert_match('^\s*1\s\+.*\s throw 0$', lines[21]) + call assert_match('^\s*1\s\+.*\scatch$', lines[22]) + call assert_match('^\s*1\s\+.*\s let x = 1$', lines[23]) + call assert_match('^\s*1\s\+.*\sfinally$', lines[24]) + call assert_match('^\s*1\s\+.*\s let x = 2$', lines[25]) + call assert_match('^\s*1\s\+.*\sendtry$', lines[26]) + call assert_equal('', lines[27]) + call assert_equal('FUNCTION Foo3()', lines[28]) + call assert_equal('Called 1 time', lines[29]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[30]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[31]) + call assert_equal('', lines[32]) + call assert_equal('count total (s) self (s)', lines[33]) + call assert_match('^\s*1\s\+.*\stry$', lines[34]) + call assert_match('^\s*1\s\+.*\s throw 0$', lines[35]) + call assert_match('^\s*1\s\+.*\scatch$', lines[36]) + call assert_match('^\s*1\s\+.*\s throw 1$', lines[37]) + call assert_match('^\s*1\s\+.*\sfinally$', lines[38]) + call assert_match('^\s*1\s\+.*\s let x = 2$', lines[39]) + call assert_match( '^\s\+endtry$', lines[40]) + call assert_equal('', lines[41]) + call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[42]) + call assert_equal('count total (s) self (s) function', lines[43]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[44]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[45]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[46]) + call assert_equal('', lines[47]) + call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[48]) + call assert_equal('count total (s) self (s) function', lines[49]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[50]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[51]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[52]) + call assert_equal('', lines[53]) + + call delete('Xprofile_func.vim') + call delete('Xprofile_func.log') +endfunc + func Test_profile_file() let lines = [ \ 'func! Foo()', @@ -123,7 +344,7 @@ func Test_profile_file() call assert_equal(' " a comment', lines[9]) " if self and total are equal we only get one number call assert_match('^\s*20\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[10]) - call assert_match('^\s*20\s\+\d\+\.\d\+\s\+endfor$', lines[11]) + call assert_match('^\s*22\s\+\d\+\.\d\+\s\+endfor$', lines[11]) " if self and total are equal we only get one number call assert_match('^\s*2\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[12]) call assert_equal('', lines[13]) diff --git a/src/version.c b/src/version.c index 51ead8f5d8..8107b44c6e 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 309, /**/ 308, /**/ From 2f0f871159b2cba862fcd41edab65b17da75c422 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 18:50:18 +0200 Subject: [PATCH 30/35] patch 8.1.0310: file info msg not always suppressed with 'F' in 'shortmess' Problem: File info message not always suppressed with 'F' in 'shortmess'. (Asheq Imran) Solution: Save and restore msg_silent. (Christian Brabandt, closes #3221) --- src/buffer.c | 7 +++++++ src/memline.c | 5 ++++- src/testdir/test_options.vim | 21 +++++++++++++++++++++ src/version.c | 2 ++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/buffer.c b/src/buffer.c index 6bcd28b36c..2ca131d23e 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1035,7 +1035,14 @@ handle_swap_exists(bufref_T *old_curbuf) buf = old_curbuf->br_buf; if (buf != NULL) { + int old_msg_silent = msg_silent; + + if (shortmess(SHM_FILEINFO)) + msg_silent = 1; // prevent fileinfo message enter_buffer(buf); + // restore msg_silent, so that the command line will be shown + msg_silent = old_msg_silent; + # ifdef FEAT_SYN_HL if (old_tw != curbuf->b_p_tw) check_colorcolumn(curwin); diff --git a/src/memline.c b/src/memline.c index fb262acef5..fbdd8a372c 100644 --- a/src/memline.c +++ b/src/memline.c @@ -828,10 +828,13 @@ ml_open_file(buf_T *buf) */ void check_need_swap( - int newfile) /* reading file into new buffer */ + int newfile) // reading file into new buffer { + int old_msg_silent = msg_silent; // might be reset by an E325 message + if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile)) ml_open_file(curbuf); + msg_silent = old_msg_silent; } /* diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index d8f033e03f..2d4a97aa18 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -414,3 +414,24 @@ func Test_shortmess_F() set shortmess& bwipe endfunc + +func Test_shortmess_F2() + e file1 + e file2 + call assert_match('file1', execute('bn', '')) + call assert_match('file2', execute('bn', '')) + set shortmess+=F + call assert_true(empty(execute('bn', ''))) + call assert_true(empty(execute('bn', ''))) + set hidden + call assert_true(empty(execute('bn', ''))) + call assert_true(empty(execute('bn', ''))) + set nohidden + call assert_true(empty(execute('bn', ''))) + call assert_true(empty(execute('bn', ''))) + set shortmess& + call assert_match('file1', execute('bn', '')) + call assert_match('file2', execute('bn', '')) + bwipe + bwipe +endfunc diff --git a/src/version.c b/src/version.c index 8107b44c6e..cc62660160 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 310, /**/ 309, /**/ From 8c5e0093c9badced73e382915fb024a5c3ea463b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 19:22:23 +0200 Subject: [PATCH 31/35] patch 8.1.0311: filtering entries in a quickfix list is not easy Problem: Filtering entries in a quickfix list is not easy. Solution: Add the cfilter plugin. (Yegappan Lakshmanan) --- runtime/doc/quickfix.txt | 16 +++++++ .../pack/dist/opt/cfilter/plugin/cfilter.vim | 43 +++++++++++++++++++ src/version.c | 2 + 3 files changed, 61 insertions(+) create mode 100644 runtime/pack/dist/opt/cfilter/plugin/cfilter.vim diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index 1399d8bed4..211fe96117 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1551,6 +1551,22 @@ The backslashes before the pipe character are required to avoid it to be recognized as a command separator. The backslash before each space is required for the set command. + *cfilter-plugin* +If you have too many matching messages, you can use the cfilter plugin to +reduce the number of entries. Load the plugin with: > + packadd cfilter + +Then you can use these command: > + :Cfilter[!] {pat} + :Lfilter[!] {pat} + +:Cfilter creates a new quickfix list from entries matching {pat} in the +current quickfix list. Both the file name and the text of the entries are +matched against {pat}. If ! is supplied, then entries not matching {pat} are +used. + +:Lfilter does the same as :Cfilter but operates on the current location list. + ============================================================================= 8. The directory stack *quickfix-directory-stack* diff --git a/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim b/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim new file mode 100644 index 0000000000..7a6464fc98 --- /dev/null +++ b/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim @@ -0,0 +1,43 @@ +" cfilter.vim: Plugin to filter entries from a quickfix/location list +" Last Change: May 12, 2018 +" Maintainer: Yegappan Lakshmanan (yegappan AT yahoo DOT com) +" Version: 1.0 +" +" Commands to filter the quickfix list: +" :Cfilter[!] {pat} +" Create a new quickfix list from entries matching {pat} in the current +" quickfix list. Both the file name and the text of the entries are +" matched against {pat}. If ! is supplied, then entries not matching +" {pat} are used. +" :Lfilter[!] {pat} +" Same as :Cfilter but operates on the current location list. +" +if exists("loaded_cfilter") + finish +endif +let loaded_cfilter = 1 + +func s:Qf_filter(qf, pat, bang) + if a:qf + let Xgetlist = function('getqflist') + let Xsetlist = function('setqflist') + let cmd = ':Cfilter' . a:bang + else + let Xgetlist = function('getloclist', [0]) + let Xsetlist = function('setloclist', [0]) + let cmd = ':Lfilter' . a:bang + endif + + if a:bang == '!' + let cond = 'v:val.text !~# a:pat && bufname(v:val.bufnr) !~# a:pat' + else + let cond = 'v:val.text =~# a:pat || bufname(v:val.bufnr) =~# a:pat' + endif + + let items = filter(Xgetlist(), cond) + let title = cmd . ' ' . a:pat + call Xsetlist([], ' ', {'title' : title, 'items' : items}) +endfunc + +com! -nargs=+ -bang Cfilter call s:Qf_filter(1, , ) +com! -nargs=+ -bang Lfilter call s:Qf_filter(0, , ) diff --git a/src/version.c b/src/version.c index cc62660160..f37cdfcf6f 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 311, /**/ 310, /**/ From 8e82c057ffb86cec3210ad8a22ad3f21d52e0953 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 19:47:48 +0200 Subject: [PATCH 32/35] patch 8.1.0312: wrong type for flags used in signal handlers Problem: Wrong type for flags used in signal handlers. Solution: Use sig_atomic_t. (Dominique Pelle, closes #3356) --- src/globals.h | 10 +++++----- src/os_unix.c | 14 +++++++------- src/os_win32.h | 1 + src/version.c | 2 ++ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/globals.h b/src/globals.h index 09820cfdf2..fa5b493e8a 100644 --- a/src/globals.h +++ b/src/globals.h @@ -518,7 +518,7 @@ EXTERN char *foreground_argument INIT(= NULL); * * volatile because it is used in signal handler sig_sysmouse(). */ -EXTERN volatile int hold_gui_events INIT(= 0); +EXTERN volatile sig_atomic_t hold_gui_events INIT(= 0); /* * When resizing the shell is postponed, remember the new size, and call @@ -655,7 +655,7 @@ EXTERN int entered_free_all_mem INIT(= FALSE); /* TRUE when in or after free_all_mem() */ #endif /* volatile because it is used in signal handler deathtrap(). */ -EXTERN volatile int full_screen INIT(= FALSE); +EXTERN volatile sig_atomic_t full_screen INIT(= FALSE); /* TRUE when doing full-screen output * otherwise only writing some messages */ @@ -800,11 +800,11 @@ EXTERN JMP_BUF x_jump_env; EXTERN JMP_BUF lc_jump_env; /* argument to SETJMP() */ # ifdef SIGHASARG /* volatile because it is used in signal handlers. */ -EXTERN volatile int lc_signal; /* caught signal number, 0 when no was signal +EXTERN volatile sig_atomic_t lc_signal; /* caught signal number, 0 when no was signal caught; used for mch_libcall() */ # endif /* volatile because it is used in signal handler deathtrap(). */ -EXTERN volatile int lc_active INIT(= FALSE); /* TRUE when lc_jump_env is valid. */ +EXTERN volatile sig_atomic_t lc_active INIT(= FALSE); /* TRUE when lc_jump_env is valid. */ #endif #if defined(FEAT_MBYTE) || defined(FEAT_POSTSCRIPT) @@ -1037,7 +1037,7 @@ EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */ EXTERN int read_cmd_fd INIT(= 0); /* fd to read commands from */ /* volatile because it is used in signal handler catch_sigint(). */ -EXTERN volatile int got_int INIT(= FALSE); /* set to TRUE when interrupt +EXTERN volatile sig_atomic_t got_int INIT(= FALSE); /* set to TRUE when interrupt signal occurred */ #ifdef USE_TERM_CONSOLE EXTERN int term_console INIT(= FALSE); /* set to TRUE when console used */ diff --git a/src/os_unix.c b/src/os_unix.c index 80c61755b1..080f03c7ba 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -161,7 +161,7 @@ static int get_x11_title(int); static int get_x11_icon(int); static char_u *oldtitle = NULL; -static volatile int oldtitle_outdated = FALSE; +static volatile sig_atomic_t oldtitle_outdated = FALSE; static int did_set_title = FALSE; static char_u *oldicon = NULL; static int did_set_icon = FALSE; @@ -205,7 +205,7 @@ static RETSIGTYPE catch_sigpwr SIGPROTOARG; # define SET_SIG_ALARM static RETSIGTYPE sig_alarm SIGPROTOARG; /* volatile because it is used in signal handler sig_alarm(). */ -static volatile int sig_alarm_called; +static volatile sig_atomic_t sig_alarm_called; #endif static RETSIGTYPE deathtrap SIGPROTOARG; @@ -231,13 +231,13 @@ static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***fil #endif /* volatile because it is used in signal handler sig_winch(). */ -static volatile int do_resize = FALSE; +static volatile sig_atomic_t do_resize = FALSE; static char_u *extra_shell_arg = NULL; static int show_shell_mess = TRUE; /* volatile because it is used in signal handler deathtrap(). */ -static volatile int deadly_signal = 0; /* The signal we caught */ +static volatile sig_atomic_t deadly_signal = 0; /* The signal we caught */ /* volatile because it is used in signal handler deathtrap(). */ -static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */ +static volatile sig_atomic_t in_mch_delay = FALSE; /* sleeping in mch_delay() */ #if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM) static int dont_check_job_ended = 0; @@ -1247,7 +1247,7 @@ after_sigcont(void) #if defined(SIGCONT) static RETSIGTYPE sigcont_handler SIGPROTOARG; -static volatile int in_mch_suspend = FALSE; +static volatile sig_atomic_t in_mch_suspend = FALSE; /* * With multi-threading, suspending might not work immediately. Catch the @@ -1260,7 +1260,7 @@ static volatile int in_mch_suspend = FALSE; * * volatile because it is used in signal handler sigcont_handler(). */ -static volatile int sigcont_received; +static volatile sig_atomic_t sigcont_received; static RETSIGTYPE sigcont_handler SIGPROTOARG; /* diff --git a/src/os_win32.h b/src/os_win32.h index 5017f532ef..4b1fc39bbf 100644 --- a/src/os_win32.h +++ b/src/os_win32.h @@ -89,6 +89,7 @@ #define FNAME_ILLEGAL "\"*?><|" /* illegal characters in a file name */ +#include #include #include #include diff --git a/src/version.c b/src/version.c index f37cdfcf6f..d752d04ff4 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 312, /**/ 311, /**/ From 00f123a56585363cd13f062fd3bb123efcfaa664 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 20:28:54 +0200 Subject: [PATCH 33/35] patch 8.1.0313: information about a swap file is unavailable Problem: Information about a swap file is unavailable. Solution: Add swapinfo(). (Enzo Ferber) --- runtime/doc/eval.txt | 17 ++++++++++++++++ src/evalfunc.c | 12 +++++++++++ src/memline.c | 43 +++++++++++++++++++++++++++++++++++++++ src/proto/memline.pro | 3 ++- src/testdir/test_swap.vim | 34 +++++++++++++++++++++++++++++++ src/version.c | 2 ++ 6 files changed, 110 insertions(+), 1 deletion(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 821cbbca9b..a9d0dc0151 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2409,6 +2409,7 @@ submatch({nr} [, {list}]) String or List specific match in ":s" or substitute() substitute({expr}, {pat}, {sub}, {flags}) String all {pat} in {expr} replaced with {sub} +swapinfo({fname}) Dict information about swap file {fname} synID({lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col} synIDattr({synID}, {what} [, {mode}]) String attribute {what} of syntax ID {synID} @@ -8001,6 +8002,22 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()* |submatch()| returns. Example: > :echo substitute(s, '%\(\x\x\)', {m -> '0x' . m[1]}, 'g') +swapinfo({fname}) swapinfo() + The result is a dictionary, which holds information about the + swapfile {fname}. The available fields are: + version VIM version + user user name + host host name + fname original file name + pid PID of the VIM process that created the swap + file + mtime last modification time in seconds + inode Optional: INODE number of the file + In case of failure an "error" item is added with the reason: + Cannot open file: file not found or in accessible + Cannot read file: cannot read first block + magic number mismatch: info in first block is invalid + synID({lnum}, {col}, {trans}) *synID()* The result is a Number, which is the syntax ID at the position {lnum} and {col} in the current window. diff --git a/src/evalfunc.c b/src/evalfunc.c index 5e7c013979..3c64212061 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -398,6 +398,7 @@ static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); static void f_strwidth(typval_T *argvars, typval_T *rettv); static void f_submatch(typval_T *argvars, typval_T *rettv); static void f_substitute(typval_T *argvars, typval_T *rettv); +static void f_swapinfo(typval_T *argvars, typval_T *rettv); static void f_synID(typval_T *argvars, typval_T *rettv); static void f_synIDattr(typval_T *argvars, typval_T *rettv); static void f_synIDtrans(typval_T *argvars, typval_T *rettv); @@ -859,6 +860,7 @@ static struct fst {"strwidth", 1, 1, f_strwidth}, {"submatch", 1, 2, f_submatch}, {"substitute", 4, 4, f_substitute}, + {"swapinfo", 1, 1, f_swapinfo}, {"synID", 3, 3, f_synID}, {"synIDattr", 2, 3, f_synIDattr}, {"synIDtrans", 1, 1, f_synIDtrans}, @@ -12313,6 +12315,16 @@ f_substitute(typval_T *argvars, typval_T *rettv) rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg); } +/* + * "swapinfo(swap_filename)" function + */ + static void +f_swapinfo(typval_T *argvars, typval_T *rettv) +{ + if (rettv_dict_alloc(rettv) == OK) + get_b0_dict(get_tv_string(argvars), rettv->vval.v_dict); +} + /* * "synID(lnum, col, trans)" function */ diff --git a/src/memline.c b/src/memline.c index fbdd8a372c..660e89c111 100644 --- a/src/memline.c +++ b/src/memline.c @@ -2041,6 +2041,49 @@ make_percent_swname(char_u *dir, char_u *name) static int process_still_running; #endif +/* + * Return information found in swapfile "fname" in dictionary "d". + * This is used by the swapinfo() function. + */ + void +get_b0_dict(char_u *fname, dict_T *d) +{ + int fd; + struct block0 b0; + + if ((fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0) + { + if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) + { + if (b0_magic_wrong(&b0)) + { + dict_add_string(d, "error", + vim_strsave((char_u *)"magic number mismatch")); + } + else + { + /* we have swap information */ + dict_add_string(d, "version", vim_strsave(b0.b0_version)); + dict_add_string(d, "user", vim_strsave(b0.b0_uname)); + dict_add_string(d, "host", vim_strsave(b0.b0_hname)); + dict_add_string(d, "fname", vim_strsave(b0.b0_fname)); + + dict_add_number(d, "pid", char_to_long(b0.b0_pid)); + dict_add_number(d, "mtime", char_to_long(b0.b0_mtime)); +#ifdef CHECK_INODE + dict_add_number(d, "inode", char_to_long(b0.b0_ino)); +#endif + } + } + else + dict_add_string(d, "error", + vim_strsave((char_u *)"Cannot read file")); + close(fd); + } + else + dict_add_string(d, "error", vim_strsave((char_u *)"Cannot open file")); +} + /* * Give information about an existing swap file. * Returns timestamp (0 when unknown). diff --git a/src/proto/memline.pro b/src/proto/memline.pro index 727b24cc30..d18ede37b6 100644 --- a/src/proto/memline.pro +++ b/src/proto/memline.pro @@ -11,6 +11,8 @@ void ml_close_notmod(void); void ml_timestamp(buf_T *buf); void ml_recover(void); int recover_names(char_u *fname, int list, int nr, char_u **fname_out); +char_u *make_percent_swname(char_u *dir, char_u *name); +void get_b0_dict(char_u *fname, dict_T *d); void ml_sync_all(int check_file, int check_char); void ml_preserve(buf_T *buf, int message); char_u *ml_get(linenr_T lnum); @@ -34,5 +36,4 @@ char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned siz void ml_decrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned size); long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp); void goto_byte(long cnt); -char_u *make_percent_swname (char_u *dir, char_u *name); /* vim: set ft=c : */ diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index da5da2dbbd..b0e2ec9aa5 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -97,3 +97,37 @@ func Test_missing_dir() set directory& call delete('Xswapdir', 'rf') endfunc + +func Test_swapinfo() + new Xswapinfo + call setline(1, ['one', 'two', 'three']) + w + let fname = trim(execute('swapname')) + call assert_match('Xswapinfo', fname) + let info = swapinfo(fname) + call assert_match('8\.', info.version) + call assert_match('\w', info.user) + call assert_equal(hostname(), info.host) + call assert_match('Xswapinfo', info.fname) + call assert_equal(getpid(), info.pid) + call assert_match('^\d*$', info.mtime) + if has_key(info, 'inode') + call assert_match('\d', info.inode) + endif + bwipe! + call delete(fname) + call delete('Xswapinfo') + + let info = swapinfo('doesnotexist') + call assert_equal('Cannot open file', info.error) + + call writefile(['burp'], 'Xnotaswapfile') + let info = swapinfo('Xnotaswapfile') + call assert_equal('Cannot read file', info.error) + call delete('Xnotaswapfile') + + call writefile([repeat('x', 10000)], 'Xnotaswapfile') + let info = swapinfo('Xnotaswapfile') + call assert_equal('magic number mismatch', info.error) + call delete('Xnotaswapfile') +endfunc diff --git a/src/version.c b/src/version.c index d752d04ff4..d0052fa331 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 313, /**/ 312, /**/ From 47ad5656e1e4285a74e7e8e5d0f1f71cd554e25c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 21:09:07 +0200 Subject: [PATCH 34/35] patch 8.1.0314: build failure without the +eval feature Problem: Build failure without the +eval feature. (Brenton Horne) Solution: Add #ifdef. Also add the "dirty" item. --- runtime/doc/eval.txt | 4 +++- src/memline.c | 16 ++++++++++------ src/testdir/test_swap.vim | 3 ++- src/version.c | 2 ++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index a9d0dc0151..2e5bf7f3d1 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -8013,10 +8013,12 @@ swapinfo({fname}) swapinfo() file mtime last modification time in seconds inode Optional: INODE number of the file + dirty 1 if file was modified, 0 if not In case of failure an "error" item is added with the reason: Cannot open file: file not found or in accessible Cannot read file: cannot read first block - magic number mismatch: info in first block is invalid + Not a swap file: does not contain correct block ID + Magic number mismatch: Info in first block is invalid synID({lnum}, {col}, {trans}) *synID()* The result is a Number, which is the syntax ID at the position diff --git a/src/memline.c b/src/memline.c index 660e89c111..3d82af0813 100644 --- a/src/memline.c +++ b/src/memline.c @@ -2041,6 +2041,7 @@ make_percent_swname(char_u *dir, char_u *name) static int process_still_running; #endif +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return information found in swapfile "fname" in dictionary "d". * This is used by the swapinfo() function. @@ -2055,11 +2056,12 @@ get_b0_dict(char_u *fname, dict_T *d) { if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) { - if (b0_magic_wrong(&b0)) - { + if (ml_check_b0_id(&b0) == FAIL) dict_add_string(d, "error", - vim_strsave((char_u *)"magic number mismatch")); - } + vim_strsave((char_u *)"Not a swap file")); + else if (b0_magic_wrong(&b0)) + dict_add_string(d, "error", + vim_strsave((char_u *)"Magic number mismatch")); else { /* we have swap information */ @@ -2070,9 +2072,10 @@ get_b0_dict(char_u *fname, dict_T *d) dict_add_number(d, "pid", char_to_long(b0.b0_pid)); dict_add_number(d, "mtime", char_to_long(b0.b0_mtime)); -#ifdef CHECK_INODE + dict_add_number(d, "dirty", b0.b0_dirty ? 1 : 0); +# ifdef CHECK_INODE dict_add_number(d, "inode", char_to_long(b0.b0_ino)); -#endif +# endif } } else @@ -2083,6 +2086,7 @@ get_b0_dict(char_u *fname, dict_T *d) else dict_add_string(d, "error", vim_strsave((char_u *)"Cannot open file")); } +#endif /* * Give information about an existing swap file. diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index b0e2ec9aa5..c12693c81c 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -109,6 +109,7 @@ func Test_swapinfo() call assert_match('\w', info.user) call assert_equal(hostname(), info.host) call assert_match('Xswapinfo', info.fname) + call assert_match(0, info.dirty) call assert_equal(getpid(), info.pid) call assert_match('^\d*$', info.mtime) if has_key(info, 'inode') @@ -128,6 +129,6 @@ func Test_swapinfo() call writefile([repeat('x', 10000)], 'Xnotaswapfile') let info = swapinfo('Xnotaswapfile') - call assert_equal('magic number mismatch', info.error) + call assert_equal('Not a swap file', info.error) call delete('Xnotaswapfile') endfunc diff --git a/src/version.c b/src/version.c index d0052fa331..55d3ce33e6 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 314, /**/ 313, /**/ From c631f2df624954184509df49479d52ad7fe5233b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Aug 2018 21:58:13 +0200 Subject: [PATCH 35/35] patch 8.1.0315: helpgrep with language doesn't work properly Problem: Helpgrep with language doesn't work properly. (Takuya Fujiwara) Solution: Check for the language earlier. (Hirohito Higashi) --- src/quickfix.c | 30 ++++++++++++++---------------- src/testdir/test_quickfix.vim | 14 ++++++++++++++ src/version.c | 2 ++ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index 1f193453f1..6248c21e64 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -5385,7 +5385,7 @@ ex_vimgrep(exarg_T *eap) if (qf_restore_list(qi, save_qfid) == FAIL) goto theend; - /* Jump to first match. */ + // Jump to first match. if (!qf_list_empty(qi, qi->qf_curlist)) { if ((flags & VGR_NOJUMP) == 0) @@ -6844,16 +6844,13 @@ hgr_search_files_in_dir( /* * Search for a pattern in all the help files in the 'runtimepath' * and add the matches to a quickfix list. - * 'arg' is the language specifier. If supplied, then only matches in the + * 'lang' is the language specifier. If supplied, then only matches in the * specified language are found. */ static void -hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch, char_u *arg) +hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch, char_u *lang) { char_u *p; -#ifdef FEAT_MULTI_LANG - char_u *lang; -#endif #ifdef FEAT_MBYTE vimconv_T vc; @@ -6865,10 +6862,6 @@ hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch, char_u *arg) convert_setup(&vc, (char_u *)"utf-8", p_enc); #endif -#ifdef FEAT_MULTI_LANG - /* Check for a specified language */ - lang = check_help_lang(arg); -#endif /* Go through all the directories in 'runtimepath' */ p = p_rtp; @@ -6903,6 +6896,7 @@ ex_helpgrep(exarg_T *eap) qf_info_T *qi = &ql_info; int new_qi = FALSE; char_u *au_name = NULL; + char_u *lang = NULL; switch (eap->cmdidx) { @@ -6919,7 +6913,7 @@ ex_helpgrep(exarg_T *eap) #endif } - /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ + // Make 'cpoptions' empty, the 'l' flag should not be used here. save_cpo = p_cpo; p_cpo = empty_option; @@ -6930,14 +6924,18 @@ ex_helpgrep(exarg_T *eap) return; } +#ifdef FEAT_MULTI_LANG + // Check for a specified language + lang = check_help_lang(eap->arg); +#endif regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); regmatch.rm_ic = FALSE; if (regmatch.regprog != NULL) { - /* create a new quickfix list */ + // create a new quickfix list qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep)); - hgr_search_in_rtp(qi, ®match, eap->arg); + hgr_search_in_rtp(qi, ®match, lang); vim_regfree(regmatch.regprog); @@ -6950,7 +6948,7 @@ ex_helpgrep(exarg_T *eap) if (p_cpo == empty_option) p_cpo = save_cpo; else - /* Darn, some plugin changed the value. */ + // Darn, some plugin changed the value. free_string_option(save_cpo); qf_list_changed(qi, qi->qf_curlist); @@ -6973,8 +6971,8 @@ ex_helpgrep(exarg_T *eap) if (eap->cmdidx == CMD_lhelpgrep) { - /* If the help window is not opened or if it already points to the - * correct location list, then free the new location list. */ + // If the help window is not opened or if it already points to the + // correct location list, then free the new location list. if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi) { if (new_qi) diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 8a175a185d..6063fd63cd 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -3091,6 +3091,20 @@ func Test_qf_tick() call Xqftick_tests('l') endfunc +" Test helpgrep with lang specifier +func Xtest_helpgrep_with_lang_specifier(cchar) + call s:setup_commands(a:cchar) + Xhelpgrep Vim@en + call assert_equal('help', &filetype) + call assert_notequal(0, g:Xgetlist({'nr' : '$'}).nr) + new | only +endfunc + +func Test_helpgrep_with_lang_specifier() + call Xtest_helpgrep_with_lang_specifier('c') + call Xtest_helpgrep_with_lang_specifier('l') +endfunc + " The following test used to crash Vim. " Open the location list window and close the regular window associated with " the location list. When the garbage collection runs now, it incorrectly diff --git a/src/version.c b/src/version.c index 55d3ce33e6..6b79b6e542 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 315, /**/ 314, /**/