mirror of
https://github.com/neovim/neovim.git
synced 2025-09-22 19:18:34 +00:00
Merge pull request #12721 from aufarg/vim-8.1.0265
[RDY] vim-patch:8.1.{265,271,273,274,275,277,278,279,280,281,282,284,286,291,295,296,320,321,339,351,392,399,552}
This commit is contained in:
@@ -169,6 +169,10 @@ struct exarg {
|
|||||||
LineGetter getline; ///< Function used to get the next line
|
LineGetter getline; ///< Function used to get the next line
|
||||||
void *cookie; ///< argument for getline()
|
void *cookie; ///< argument for getline()
|
||||||
cstack_T *cstack; ///< condition stack for ":if" etc.
|
cstack_T *cstack; ///< condition stack for ":if" etc.
|
||||||
|
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
|
||||||
|
bool did_sandbox; ///< when true did sandbox++
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FORCE_BIN 1 // ":edit ++bin file"
|
#define FORCE_BIN 1 // ":edit ++bin file"
|
||||||
|
@@ -137,32 +137,6 @@ struct dbg_stuff {
|
|||||||
except_T *current_exception;
|
except_T *current_exception;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// parsed results
|
|
||||||
exarg_T *eap;
|
|
||||||
char_u *parsed_upto; // local we've parsed up to so far
|
|
||||||
char_u *cmd; // start of command
|
|
||||||
char_u *after_modifier;
|
|
||||||
|
|
||||||
// errors
|
|
||||||
char_u *errormsg;
|
|
||||||
|
|
||||||
// globals that need to be updated
|
|
||||||
cmdmod_T cmdmod;
|
|
||||||
int sandbox;
|
|
||||||
int msg_silent;
|
|
||||||
int emsg_silent;
|
|
||||||
bool ex_pressedreturn;
|
|
||||||
long p_verbose;
|
|
||||||
|
|
||||||
// other side-effects
|
|
||||||
bool set_eventignore;
|
|
||||||
long verbose_save;
|
|
||||||
int save_msg_silent;
|
|
||||||
int did_esilent;
|
|
||||||
bool did_sandbox;
|
|
||||||
} parse_state_T;
|
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "ex_docmd.c.generated.h"
|
# include "ex_docmd.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -1235,292 +1209,6 @@ static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite)
|
|||||||
return (char_u *)p;
|
return (char_u *)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_state_to_global(const parse_state_T *parse_state)
|
|
||||||
{
|
|
||||||
cmdmod = parse_state->cmdmod;
|
|
||||||
sandbox = parse_state->sandbox;
|
|
||||||
msg_silent = parse_state->msg_silent;
|
|
||||||
emsg_silent = parse_state->emsg_silent;
|
|
||||||
ex_pressedreturn = parse_state->ex_pressedreturn;
|
|
||||||
p_verbose = parse_state->p_verbose;
|
|
||||||
|
|
||||||
if (parse_state->set_eventignore) {
|
|
||||||
set_string_option_direct(
|
|
||||||
(char_u *)"ei", -1, (char_u *)"all", OPT_FREE, SID_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_state_from_global(parse_state_T *parse_state)
|
|
||||||
{
|
|
||||||
memset(parse_state, 0, sizeof(*parse_state));
|
|
||||||
parse_state->cmdmod = cmdmod;
|
|
||||||
parse_state->sandbox = sandbox;
|
|
||||||
parse_state->msg_silent = msg_silent;
|
|
||||||
parse_state->emsg_silent = emsg_silent;
|
|
||||||
parse_state->ex_pressedreturn = ex_pressedreturn;
|
|
||||||
parse_state->p_verbose = p_verbose;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Parse one Ex command.
|
|
||||||
//
|
|
||||||
// This has no side-effects, except for modifying parameters
|
|
||||||
// passed in by pointer.
|
|
||||||
//
|
|
||||||
// The `out` should be zeroed, and its `ea` member initialised,
|
|
||||||
// before calling this function.
|
|
||||||
//
|
|
||||||
static bool parse_one_cmd(
|
|
||||||
char_u **cmdlinep,
|
|
||||||
parse_state_T *const out,
|
|
||||||
LineGetter fgetline,
|
|
||||||
void *fgetline_cookie)
|
|
||||||
{
|
|
||||||
exarg_T ea = {
|
|
||||||
.line1 = 1,
|
|
||||||
.line2 = 1,
|
|
||||||
};
|
|
||||||
*out->eap = ea;
|
|
||||||
|
|
||||||
// "#!anything" is handled like a comment.
|
|
||||||
if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Repeat until no more command modifiers are found.
|
|
||||||
*/
|
|
||||||
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, fgetline_cookie, getexmodeline)
|
|
||||||
|| getline_equal(fgetline, fgetline_cookie, getexline))
|
|
||||||
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
|
|
||||||
ea.cmd = (char_u *)"+";
|
|
||||||
out->ex_pressedreturn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore comment and empty lines
|
|
||||||
if (*ea.cmd == '"') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (*ea.cmd == NUL) {
|
|
||||||
out->ex_pressedreturn = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 2. Handle command modifiers.
|
|
||||||
*/
|
|
||||||
char_u *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;
|
|
||||||
out->cmdmod.split |= WSP_ABOVE;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) {
|
|
||||||
out->cmdmod.split |= WSP_BELOW;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (checkforcmd(&ea.cmd, "browse", 3)) {
|
|
||||||
out->cmdmod.browse = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!checkforcmd(&ea.cmd, "botright", 2)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out->cmdmod.split |= WSP_BOT;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4))
|
|
||||||
break;
|
|
||||||
out->cmdmod.confirm = true;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) {
|
|
||||||
out->cmdmod.keepmarks = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (checkforcmd(&ea.cmd, "keepalt", 5)) {
|
|
||||||
out->cmdmod.keepalt = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (checkforcmd(&ea.cmd, "keeppatterns", 5)) {
|
|
||||||
out->cmdmod.keeppatterns = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!checkforcmd(&ea.cmd, "keepjumps", 5)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out->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 == '!') {
|
|
||||||
out->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;
|
|
||||||
}
|
|
||||||
out->cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC);
|
|
||||||
if (out->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;
|
|
||||||
out->cmdmod.hide = true;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) {
|
|
||||||
out->cmdmod.lockmarks = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!checkforcmd(&ea.cmd, "leftabove", 5)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out->cmdmod.split |= WSP_ABOVE;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
if (checkforcmd(&ea.cmd, "noautocmd", 3)) {
|
|
||||||
if (out->cmdmod.save_ei == NULL) {
|
|
||||||
// Set 'eventignore' to "all". Restore the
|
|
||||||
// existing option value later.
|
|
||||||
out->cmdmod.save_ei = vim_strsave(p_ei);
|
|
||||||
out->set_eventignore = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!checkforcmd(&ea.cmd, "noswapfile", 3)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out->cmdmod.noswapfile = true;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6))
|
|
||||||
break;
|
|
||||||
out->cmdmod.split |= WSP_BELOW;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) {
|
|
||||||
if (!out->did_sandbox) {
|
|
||||||
out->sandbox++;
|
|
||||||
}
|
|
||||||
out->did_sandbox = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!checkforcmd(&ea.cmd, "silent", 3)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (out->save_msg_silent == -1) {
|
|
||||||
out->save_msg_silent = out->msg_silent;
|
|
||||||
}
|
|
||||||
out->msg_silent++;
|
|
||||||
if (*ea.cmd == '!' && !ascii_iswhite(ea.cmd[-1])) {
|
|
||||||
// ":silent!", but not "silent !cmd"
|
|
||||||
ea.cmd = skipwhite(ea.cmd + 1);
|
|
||||||
out->emsg_silent++;
|
|
||||||
out->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) {
|
|
||||||
out->cmdmod.tab = tabpage_index(curtab) + 1;
|
|
||||||
} else {
|
|
||||||
if (tabnr < 0 || tabnr > LAST_TAB_NR) {
|
|
||||||
out->errormsg = (char_u *)_(e_invrange);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
out->cmdmod.tab = tabnr + 1;
|
|
||||||
}
|
|
||||||
ea.cmd = p;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!checkforcmd(&ea.cmd, "topleft", 2)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out->cmdmod.split |= WSP_TOP;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3))
|
|
||||||
break;
|
|
||||||
if (out->save_msg_silent == -1) {
|
|
||||||
out->save_msg_silent = out->msg_silent;
|
|
||||||
}
|
|
||||||
out->msg_silent = 0;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) {
|
|
||||||
out->cmdmod.split |= WSP_VERT;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!checkforcmd(&p, "verbose", 4))
|
|
||||||
break;
|
|
||||||
if (out->verbose_save < 0) {
|
|
||||||
out->verbose_save = out->p_verbose;
|
|
||||||
}
|
|
||||||
if (ascii_isdigit(*ea.cmd)) {
|
|
||||||
out->p_verbose = atoi((char *)ea.cmd);
|
|
||||||
} else {
|
|
||||||
out->p_verbose = 1;
|
|
||||||
}
|
|
||||||
ea.cmd = p;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out->after_modifier = ea.cmd;
|
|
||||||
|
|
||||||
// 3. Skip over the range to find the command. Let "p" point to after it.
|
|
||||||
//
|
|
||||||
// We need the command to know what kind of range it uses.
|
|
||||||
|
|
||||||
out->cmd = ea.cmd;
|
|
||||||
ea.cmd = skip_range(ea.cmd, NULL);
|
|
||||||
if (*ea.cmd == '*') {
|
|
||||||
ea.cmd = skipwhite(ea.cmd + 1);
|
|
||||||
}
|
|
||||||
out->parsed_upto = find_command(&ea, NULL);
|
|
||||||
|
|
||||||
*out->eap = ea;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute one Ex command.
|
* Execute one Ex command.
|
||||||
*
|
*
|
||||||
@@ -1549,12 +1237,16 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
|||||||
linenr_T lnum;
|
linenr_T lnum;
|
||||||
long n;
|
long n;
|
||||||
char_u *errormsg = NULL; // error message
|
char_u *errormsg = NULL; // error message
|
||||||
|
char_u *after_modifier = NULL;
|
||||||
exarg_T ea;
|
exarg_T ea;
|
||||||
int save_msg_scroll = msg_scroll;
|
int save_msg_scroll = msg_scroll;
|
||||||
parse_state_T parsed;
|
|
||||||
cmdmod_T save_cmdmod;
|
cmdmod_T save_cmdmod;
|
||||||
const int save_reg_executing = reg_executing;
|
const int save_reg_executing = reg_executing;
|
||||||
|
char_u *cmd;
|
||||||
|
|
||||||
|
memset(&ea, 0, sizeof(ea));
|
||||||
|
ea.line1 = 1;
|
||||||
|
ea.line2 = 1;
|
||||||
ex_nesting_level++;
|
ex_nesting_level++;
|
||||||
|
|
||||||
/* When the last file has not been edited :q has to be typed twice. */
|
/* When the last file has not been edited :q has to be typed twice. */
|
||||||
@@ -1571,31 +1263,44 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
|||||||
* recursive calls.
|
* recursive calls.
|
||||||
*/
|
*/
|
||||||
save_cmdmod = cmdmod;
|
save_cmdmod = cmdmod;
|
||||||
memset(&cmdmod, 0, sizeof(cmdmod));
|
|
||||||
|
|
||||||
parse_state_from_global(&parsed);
|
// "#!anything" is handled like a comment.
|
||||||
parsed.eap = &ea;
|
if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') {
|
||||||
parsed.verbose_save = -1;
|
|
||||||
parsed.save_msg_silent = -1;
|
|
||||||
parsed.did_esilent = 0;
|
|
||||||
parsed.did_sandbox = false;
|
|
||||||
bool parse_success = parse_one_cmd(cmdlinep, &parsed, fgetline, cookie);
|
|
||||||
parse_state_to_global(&parsed);
|
|
||||||
|
|
||||||
// Update locals from parse_one_cmd()
|
|
||||||
errormsg = parsed.errormsg;
|
|
||||||
p = parsed.parsed_upto;
|
|
||||||
|
|
||||||
if (!parse_success) {
|
|
||||||
goto doend;
|
goto doend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
ea.cookie = cookie;
|
||||||
|
ea.cstack = cstack;
|
||||||
|
|
||||||
|
if (parse_command_modifiers(&ea, &errormsg, false) == FAIL) {
|
||||||
|
goto doend;
|
||||||
|
}
|
||||||
|
|
||||||
|
after_modifier = ea.cmd;
|
||||||
|
|
||||||
ea.skip = (did_emsg
|
ea.skip = (did_emsg
|
||||||
|| got_int
|
|| got_int
|
||||||
|| current_exception
|
|| current_exception
|
||||||
|| (cstack->cs_idx >= 0
|
|| (cstack->cs_idx >= 0
|
||||||
&& !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)));
|
&& !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)));
|
||||||
|
|
||||||
|
// 3. Skip over the range to find the command. Let "p" point to after it.
|
||||||
|
//
|
||||||
|
// We need the command to know what kind of range it uses.
|
||||||
|
cmd = ea.cmd;
|
||||||
|
ea.cmd = skip_range(ea.cmd, NULL);
|
||||||
|
if (*ea.cmd == '*') {
|
||||||
|
ea.cmd = skipwhite(ea.cmd + 1);
|
||||||
|
}
|
||||||
|
p = find_command(&ea, NULL);
|
||||||
|
|
||||||
// Count this line for profiling if skip is TRUE.
|
// Count this line for profiling if skip is TRUE.
|
||||||
if (do_profiling == PROF_YES
|
if (do_profiling == PROF_YES
|
||||||
&& (!ea.skip || cstack->cs_idx == 0
|
&& (!ea.skip || cstack->cs_idx == 0
|
||||||
@@ -1665,8 +1370,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ea.cmd = parsed.cmd;
|
ea.cmd = cmd;
|
||||||
if (parse_cmd_address(&ea, &errormsg) == FAIL) {
|
if (parse_cmd_address(&ea, &errormsg, false) == FAIL) {
|
||||||
goto doend;
|
goto doend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,8 +1451,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
|||||||
if (!(flags & DOCMD_VERBOSE)) {
|
if (!(flags & DOCMD_VERBOSE)) {
|
||||||
// If the modifier was parsed OK the error must be in the following
|
// If the modifier was parsed OK the error must be in the following
|
||||||
// command
|
// command
|
||||||
if (parsed.after_modifier != NULL) {
|
if (after_modifier != NULL) {
|
||||||
append_command(parsed.after_modifier);
|
append_command(after_modifier);
|
||||||
} else {
|
} else {
|
||||||
append_command(*cmdlinep);
|
append_command(*cmdlinep);
|
||||||
}
|
}
|
||||||
@@ -2222,22 +1927,15 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
|||||||
|
|
||||||
// The :try command saves the emsg_silent flag, reset it here when
|
// The :try command saves the emsg_silent flag, reset it here when
|
||||||
// ":silent! try" was used, it should only apply to :try itself.
|
// ":silent! try" was used, it should only apply to :try itself.
|
||||||
if (ea.cmdidx == CMD_try && parsed.did_esilent > 0) {
|
if (ea.cmdidx == CMD_try && ea.did_esilent > 0) {
|
||||||
emsg_silent -= parsed.did_esilent;
|
emsg_silent -= ea.did_esilent;
|
||||||
if (emsg_silent < 0) {
|
if (emsg_silent < 0) {
|
||||||
emsg_silent = 0;
|
emsg_silent = 0;
|
||||||
}
|
}
|
||||||
parsed.did_esilent = 0;
|
ea.did_esilent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Execute the command.
|
// 7. Execute the command.
|
||||||
//
|
|
||||||
// The "ea" structure holds the arguments that can be used.
|
|
||||||
ea.cmdlinep = cmdlinep;
|
|
||||||
ea.getline = fgetline;
|
|
||||||
ea.cookie = cookie;
|
|
||||||
ea.cstack = cstack;
|
|
||||||
|
|
||||||
if (IS_USER_CMDIDX(ea.cmdidx)) {
|
if (IS_USER_CMDIDX(ea.cmdidx)) {
|
||||||
/*
|
/*
|
||||||
* Execute a user-defined command.
|
* Execute a user-defined command.
|
||||||
@@ -2293,30 +1991,21 @@ doend:
|
|||||||
? cmdnames[(int)ea.cmdidx].cmd_name
|
? cmdnames[(int)ea.cmdidx].cmd_name
|
||||||
: (char_u *)NULL);
|
: (char_u *)NULL);
|
||||||
|
|
||||||
if (parsed.verbose_save >= 0) {
|
if (ea.verbose_save >= 0) {
|
||||||
p_verbose = parsed.verbose_save;
|
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;
|
cmdmod = save_cmdmod;
|
||||||
reg_executing = save_reg_executing;
|
reg_executing = save_reg_executing;
|
||||||
|
|
||||||
if (parsed.save_msg_silent != -1) {
|
if (ea.save_msg_silent != -1) {
|
||||||
// messages could be enabled for a serious error, need to check if the
|
// messages could be enabled for a serious error, need to check if the
|
||||||
// counters don't become negative
|
// counters don't become negative
|
||||||
if (!did_emsg || msg_silent > parsed.save_msg_silent) {
|
if (!did_emsg || msg_silent > ea.save_msg_silent) {
|
||||||
msg_silent = parsed.save_msg_silent;
|
msg_silent = ea.save_msg_silent;
|
||||||
}
|
}
|
||||||
emsg_silent -= parsed.did_esilent;
|
emsg_silent -= ea.did_esilent;
|
||||||
if (emsg_silent < 0) {
|
if (emsg_silent < 0) {
|
||||||
emsg_silent = 0;
|
emsg_silent = 0;
|
||||||
}
|
}
|
||||||
@@ -2330,7 +2019,7 @@ doend:
|
|||||||
msg_col = 0;
|
msg_col = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.did_sandbox) {
|
if (ea.did_sandbox) {
|
||||||
sandbox--;
|
sandbox--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2342,9 +2031,279 @@ doend:
|
|||||||
return ea.nextcmd;
|
return ea.nextcmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 '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, bool skip_only)
|
||||||
|
{
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
memset(&cmdmod, 0, sizeof(cmdmod));
|
||||||
|
eap->verbose_save = -1;
|
||||||
|
eap->save_msg_silent = -1;
|
||||||
|
|
||||||
|
// Repeat until no more command modifiers are found.
|
||||||
|
for (;; ) {
|
||||||
|
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 *)"+";
|
||||||
|
if (!skip_only) {
|
||||||
|
ex_pressedreturn = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore comment and empty lines
|
||||||
|
if (*eap->cmd == '"') {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (*eap->cmd == NUL) {
|
||||||
|
if (!skip_only) {
|
||||||
|
ex_pressedreturn = true;
|
||||||
|
}
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
cmdmod.browse = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!checkforcmd(&eap->cmd, "botright", 2)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmdmod.split |= WSP_BOT;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4))
|
||||||
|
break;
|
||||||
|
cmdmod.confirm = true;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (!skip_only) {
|
||||||
|
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 && !skip_only) {
|
||||||
|
// 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)) {
|
||||||
|
if (!skip_only) {
|
||||||
|
if (!eap->did_sandbox) {
|
||||||
|
sandbox++;
|
||||||
|
}
|
||||||
|
eap->did_sandbox = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!checkforcmd(&eap->cmd, "silent", 3)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!skip_only) {
|
||||||
|
if (eap->save_msg_silent == -1) {
|
||||||
|
eap->save_msg_silent = msg_silent;
|
||||||
|
}
|
||||||
|
msg_silent++;
|
||||||
|
}
|
||||||
|
if (*eap->cmd == '!' && !ascii_iswhite(eap->cmd[-1])) {
|
||||||
|
// ":silent!", but not "silent !cmd"
|
||||||
|
eap->cmd = skipwhite(eap->cmd + 1);
|
||||||
|
if (!skip_only) {
|
||||||
|
emsg_silent++;
|
||||||
|
eap->did_esilent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 't': if (checkforcmd(&p, "tab", 3)) {
|
||||||
|
long tabnr = get_address(
|
||||||
|
eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, 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 false;
|
||||||
|
}
|
||||||
|
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 (!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)) {
|
||||||
|
cmdmod.split |= WSP_VERT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!checkforcmd(&p, "verbose", 4))
|
||||||
|
break;
|
||||||
|
if (!skip_only) {
|
||||||
|
if (eap->verbose_save < 0) {
|
||||||
|
eap->verbose_save = p_verbose;
|
||||||
|
}
|
||||||
|
if (ascii_isdigit(*eap->cmd)) {
|
||||||
|
p_verbose = atoi((char *)eap->cmd);
|
||||||
|
} else {
|
||||||
|
p_verbose = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eap->cmd = p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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".
|
// Parse the address range, if any, in "eap".
|
||||||
|
// May set the last search pattern, unless "silent" is true.
|
||||||
// Return FAIL and set "errormsg" or return OK.
|
// Return FAIL and set "errormsg" or return OK.
|
||||||
int parse_cmd_address(exarg_T *eap, char_u **errormsg)
|
int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
int address_count = 1;
|
int address_count = 1;
|
||||||
@@ -2382,7 +2341,7 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
eap->cmd = skipwhite(eap->cmd);
|
eap->cmd = skipwhite(eap->cmd);
|
||||||
lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip,
|
lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent,
|
||||||
eap->addr_count == 0, address_count++);
|
eap->addr_count == 0, address_count++);
|
||||||
if (eap->cmd == NULL) { // error detected
|
if (eap->cmd == NULL) { // error detected
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -3725,18 +3684,18 @@ char_u *skip_range(
|
|||||||
return (char_u *)cmd;
|
return (char_u *)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Get a single EX address
|
||||||
* get a single EX address
|
//
|
||||||
*
|
// Set ptr to the next character after the part that was interpreted.
|
||||||
* Set ptr to the next character after the part that was interpreted.
|
// Set ptr to NULL when an error is encountered.
|
||||||
* Set ptr to NULL when an error is encountered.
|
// This may set the last used search pattern.
|
||||||
*
|
//
|
||||||
* Return MAXLNUM when no Ex address was found.
|
// Return MAXLNUM when no Ex address was found.
|
||||||
*/
|
|
||||||
static linenr_T get_address(exarg_T *eap,
|
static linenr_T get_address(exarg_T *eap,
|
||||||
char_u **ptr,
|
char_u **ptr,
|
||||||
int addr_type, // flag: one of ADDR_LINES, ...
|
int addr_type, // flag: one of ADDR_LINES, ...
|
||||||
int skip, // only skip the address, don't use it
|
int skip, // only skip the address, don't use it
|
||||||
|
bool silent, // no errors or side effects
|
||||||
int to_other_file, // flag: may jump to other file
|
int to_other_file, // flag: may jump to other file
|
||||||
int address_count) // 1 for first, >1 after comma
|
int address_count) // 1 for first, >1 after comma
|
||||||
{
|
{
|
||||||
@@ -3868,13 +3827,15 @@ static linenr_T get_address(exarg_T *eap,
|
|||||||
if (*cmd == c)
|
if (*cmd == c)
|
||||||
++cmd;
|
++cmd;
|
||||||
} else {
|
} else {
|
||||||
pos = curwin->w_cursor; /* save curwin->w_cursor */
|
int flags;
|
||||||
/*
|
|
||||||
* When '/' or '?' follows another address, start
|
pos = curwin->w_cursor; // save curwin->w_cursor
|
||||||
* from there.
|
|
||||||
*/
|
// When '/' or '?' follows another address, start from
|
||||||
if (lnum != MAXLNUM)
|
// there.
|
||||||
|
if (lnum != MAXLNUM) {
|
||||||
curwin->w_cursor.lnum = lnum;
|
curwin->w_cursor.lnum = lnum;
|
||||||
|
}
|
||||||
|
|
||||||
// Start a forward search at the end of the line (unless
|
// Start a forward search at the end of the line (unless
|
||||||
// before the first line).
|
// before the first line).
|
||||||
@@ -3888,7 +3849,8 @@ static linenr_T get_address(exarg_T *eap,
|
|||||||
curwin->w_cursor.col = 0;
|
curwin->w_cursor.col = 0;
|
||||||
}
|
}
|
||||||
searchcmdlen = 0;
|
searchcmdlen = 0;
|
||||||
if (!do_search(NULL, c, cmd, 1L, SEARCH_HIS | SEARCH_MSG, NULL)) {
|
flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG;
|
||||||
|
if (!do_search(NULL, c, cmd, 1L, flags, NULL)) {
|
||||||
curwin->w_cursor = pos;
|
curwin->w_cursor = pos;
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
goto error;
|
goto error;
|
||||||
@@ -7793,7 +7755,7 @@ static void ex_put(exarg_T *eap)
|
|||||||
*/
|
*/
|
||||||
static void ex_copymove(exarg_T *eap)
|
static void ex_copymove(exarg_T *eap)
|
||||||
{
|
{
|
||||||
long n = get_address(eap, &eap->arg, eap->addr_type, false, false, 1);
|
long n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1);
|
||||||
if (eap->arg == NULL) { // error detected
|
if (eap->arg == NULL) { // error detected
|
||||||
eap->nextcmd = NULL;
|
eap->nextcmd = NULL;
|
||||||
return;
|
return;
|
||||||
|
@@ -137,6 +137,7 @@ struct cmdline_info {
|
|||||||
/// Last value of prompt_id, incremented when doing new prompt
|
/// Last value of prompt_id, incremented when doing new prompt
|
||||||
static unsigned last_prompt_id = 0;
|
static unsigned last_prompt_id = 0;
|
||||||
|
|
||||||
|
// Struct to store the viewstate during 'incsearch' highlighting.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
colnr_T vs_curswant;
|
colnr_T vs_curswant;
|
||||||
colnr_T vs_leftcol;
|
colnr_T vs_leftcol;
|
||||||
@@ -146,6 +147,19 @@ typedef struct {
|
|||||||
int vs_empty_rows;
|
int vs_empty_rows;
|
||||||
} viewstate_T;
|
} viewstate_T;
|
||||||
|
|
||||||
|
// Struct to store the state of 'incsearch' highlighting.
|
||||||
|
typedef struct {
|
||||||
|
pos_T search_start; // where 'incsearch' starts searching
|
||||||
|
pos_T save_cursor;
|
||||||
|
viewstate_T init_viewstate;
|
||||||
|
viewstate_T old_viewstate;
|
||||||
|
pos_T match_start;
|
||||||
|
pos_T match_end;
|
||||||
|
bool did_incsearch;
|
||||||
|
bool incsearch_postponed;
|
||||||
|
int magic_save;
|
||||||
|
} incsearch_state_T;
|
||||||
|
|
||||||
typedef struct command_line_state {
|
typedef struct command_line_state {
|
||||||
VimState state;
|
VimState state;
|
||||||
int firstc;
|
int firstc;
|
||||||
@@ -159,14 +173,7 @@ typedef struct command_line_state {
|
|||||||
int save_hiscnt; // history line before attempting
|
int save_hiscnt; // history line before attempting
|
||||||
// to jump to next match
|
// to jump to next match
|
||||||
int histype; // history type to be used
|
int histype; // history type to be used
|
||||||
pos_T search_start; // where 'incsearch' starts searching
|
incsearch_state_T is_state;
|
||||||
pos_T save_cursor;
|
|
||||||
viewstate_T init_viewstate;
|
|
||||||
viewstate_T old_viewstate;
|
|
||||||
pos_T match_start;
|
|
||||||
pos_T match_end;
|
|
||||||
int did_incsearch;
|
|
||||||
int incsearch_postponed;
|
|
||||||
int did_wild_list; // did wild_list() recently
|
int did_wild_list; // did wild_list() recently
|
||||||
int wim_index; // index in wim_flags[]
|
int wim_index; // index in wim_flags[]
|
||||||
int res;
|
int res;
|
||||||
@@ -252,6 +259,382 @@ static void restore_viewstate(viewstate_T *vs)
|
|||||||
curwin->w_empty_rows = vs->vs_empty_rows;
|
curwin->w_empty_rows = vs->vs_empty_rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void init_incsearch_state(incsearch_state_T *s)
|
||||||
|
{
|
||||||
|
s->match_start = curwin->w_cursor;
|
||||||
|
s->did_incsearch = false;
|
||||||
|
s->incsearch_postponed = false;
|
||||||
|
s->magic_save = p_magic;
|
||||||
|
clearpos(&s->match_end);
|
||||||
|
s->save_cursor = curwin->w_cursor; // may be restored later
|
||||||
|
s->search_start = curwin->w_cursor;
|
||||||
|
save_viewstate(&s->init_viewstate);
|
||||||
|
save_viewstate(&s->old_viewstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true when 'incsearch' highlighting is to be done.
|
||||||
|
// Sets search_first_line and search_last_line to the address range.
|
||||||
|
static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
|
||||||
|
int *skiplen, int *patlen)
|
||||||
|
{
|
||||||
|
char_u *cmd;
|
||||||
|
cmdmod_T save_cmdmod = cmdmod;
|
||||||
|
char_u *p;
|
||||||
|
bool delim_optional = false;
|
||||||
|
int delim;
|
||||||
|
char_u *end;
|
||||||
|
char_u *dummy;
|
||||||
|
exarg_T ea;
|
||||||
|
pos_T save_cursor;
|
||||||
|
bool use_last_pat;
|
||||||
|
|
||||||
|
*skiplen = 0;
|
||||||
|
*patlen = ccline.cmdlen;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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 == '!') {
|
||||||
|
p++;
|
||||||
|
if (*skipwhite(p) == NUL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*cmd != 'g') {
|
||||||
|
delim_optional = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = skipwhite(p);
|
||||||
|
delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
|
||||||
|
end = skip_regexp(p, delim, p_magic, NULL);
|
||||||
|
|
||||||
|
use_last_pat = end == p && *end == delim;
|
||||||
|
if (end == p && !use_last_pat) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't do 'hlsearch' highlighting if the pattern matches everything.
|
||||||
|
if (!use_last_pat) {
|
||||||
|
char_u c = *end;
|
||||||
|
int empty;
|
||||||
|
|
||||||
|
*end = NUL;
|
||||||
|
empty = empty_pattern(p);
|
||||||
|
*end = c;
|
||||||
|
if (empty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// found a non-empty pattern or //
|
||||||
|
*skiplen = (int)(p - ccline.cmdbuff);
|
||||||
|
*patlen = (int)(end - p);
|
||||||
|
|
||||||
|
// parse the address range
|
||||||
|
save_cursor = curwin->w_cursor;
|
||||||
|
curwin->w_cursor = s->search_start;
|
||||||
|
parse_cmd_address(&ea, &dummy, true);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// May do 'incsearch' highlighting if desired.
|
||||||
|
static void may_do_incsearch_highlighting(int firstc, long count,
|
||||||
|
incsearch_state_T *s)
|
||||||
|
{
|
||||||
|
pos_T end_pos;
|
||||||
|
proftime_T tm;
|
||||||
|
searchit_arg_T sia;
|
||||||
|
int skiplen, patlen;
|
||||||
|
char_u next_char;
|
||||||
|
char_u use_last_pat;
|
||||||
|
|
||||||
|
// Parsing range may already set the last search pattern.
|
||||||
|
// NOTE: must call restore_last_search_pattern() before returning!
|
||||||
|
save_last_search_pattern();
|
||||||
|
|
||||||
|
if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) {
|
||||||
|
restore_last_search_pattern();
|
||||||
|
finish_incsearch_highlighting(false, s, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a character waiting, search and redraw later
|
||||||
|
if (char_avail()) {
|
||||||
|
restore_last_search_pattern();
|
||||||
|
s->incsearch_postponed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->incsearch_postponed = false;
|
||||||
|
|
||||||
|
if (search_first_line == 0) {
|
||||||
|
// start at the original cursor position
|
||||||
|
curwin->w_cursor = s->search_start;
|
||||||
|
} else {
|
||||||
|
// start at the first line in the range
|
||||||
|
curwin->w_cursor.lnum = search_first_line;
|
||||||
|
curwin->w_cursor.col = 0;
|
||||||
|
}
|
||||||
|
int found; // do_search() result
|
||||||
|
|
||||||
|
// Use the previous pattern for ":s//".
|
||||||
|
next_char = ccline.cmdbuff[skiplen + patlen];
|
||||||
|
use_last_pat = patlen == 0 && skiplen > 0
|
||||||
|
&& ccline.cmdbuff[skiplen - 1] == next_char;
|
||||||
|
|
||||||
|
// If there is no pattern, don't do anything.
|
||||||
|
if (patlen == 0 && !use_last_pat) {
|
||||||
|
found = 0;
|
||||||
|
set_no_hlsearch(true); // turn off previous highlight
|
||||||
|
redraw_all_later(SOME_VALID);
|
||||||
|
} else {
|
||||||
|
int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
|
||||||
|
ui_busy_start();
|
||||||
|
ui_flush();
|
||||||
|
emsg_off++; // So it doesn't beep if bad expr
|
||||||
|
// Set the time limit to half a second.
|
||||||
|
tm = profile_setlimit(500L);
|
||||||
|
if (!p_hls) {
|
||||||
|
search_flags += SEARCH_KEEP;
|
||||||
|
}
|
||||||
|
if (search_first_line != 0) {
|
||||||
|
search_flags += SEARCH_START;
|
||||||
|
}
|
||||||
|
ccline.cmdbuff[skiplen + patlen] = NUL;
|
||||||
|
memset(&sia, 0, sizeof(sia));
|
||||||
|
sia.sa_tm = &tm;
|
||||||
|
found = do_search(NULL, firstc == ':' ? '/' : firstc,
|
||||||
|
ccline.cmdbuff + skiplen, count,
|
||||||
|
search_flags, &sia);
|
||||||
|
ccline.cmdbuff[skiplen + patlen] = next_char;
|
||||||
|
emsg_off--;
|
||||||
|
if (curwin->w_cursor.lnum < search_first_line
|
||||||
|
|| curwin->w_cursor.lnum > search_last_line) {
|
||||||
|
// match outside of address range
|
||||||
|
found = 0;
|
||||||
|
curwin->w_cursor = s->search_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if interrupted while searching, behave like it failed
|
||||||
|
if (got_int) {
|
||||||
|
(void)vpeekc(); // remove <C-C> from input stream
|
||||||
|
got_int = false; // don't abandon the command line
|
||||||
|
found = 0;
|
||||||
|
} else if (char_avail()) {
|
||||||
|
// cancelled searching because a char was typed
|
||||||
|
s->incsearch_postponed = true;
|
||||||
|
}
|
||||||
|
ui_busy_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != 0) {
|
||||||
|
highlight_match = true; // highlight position
|
||||||
|
} else {
|
||||||
|
highlight_match = false; // remove highlight
|
||||||
|
}
|
||||||
|
|
||||||
|
// first restore the old curwin values, so the screen is
|
||||||
|
// positioned in the same way as the actual search command
|
||||||
|
restore_viewstate(&s->old_viewstate);
|
||||||
|
changed_cline_bef_curs();
|
||||||
|
update_topline();
|
||||||
|
|
||||||
|
if (found != 0) {
|
||||||
|
pos_T save_pos = curwin->w_cursor;
|
||||||
|
|
||||||
|
s->match_start = curwin->w_cursor;
|
||||||
|
set_search_match(&curwin->w_cursor);
|
||||||
|
validate_cursor();
|
||||||
|
end_pos = curwin->w_cursor;
|
||||||
|
s->match_end = end_pos;
|
||||||
|
curwin->w_cursor = save_pos;
|
||||||
|
} else {
|
||||||
|
end_pos = curwin->w_cursor; // shutup gcc 4
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Disable 'hlsearch' highlighting if the pattern matches
|
||||||
|
// everything. Avoids a flash when typing "foo\|".
|
||||||
|
if (!use_last_pat) {
|
||||||
|
next_char = ccline.cmdbuff[skiplen + patlen];
|
||||||
|
ccline.cmdbuff[skiplen + patlen] = NUL;
|
||||||
|
if (empty_pattern(ccline.cmdbuff) && !no_hlsearch) {
|
||||||
|
redraw_all_later(SOME_VALID);
|
||||||
|
set_no_hlsearch(true);
|
||||||
|
}
|
||||||
|
ccline.cmdbuff[skiplen + patlen] = next_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_cursor();
|
||||||
|
// May redraw the status line to show the cursor position.
|
||||||
|
if (p_ru && curwin->w_status_height > 0) {
|
||||||
|
curwin->w_redr_status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_screen(SOME_VALID);
|
||||||
|
restore_last_search_pattern();
|
||||||
|
|
||||||
|
// Leave it at the end to make CTRL-R CTRL-W work. But not when beyond the
|
||||||
|
// end of the pattern, e.g. for ":s/pat/".
|
||||||
|
if (ccline.cmdbuff[skiplen + patlen] != NUL) {
|
||||||
|
curwin->w_cursor = s->search_start;
|
||||||
|
} else if (found != 0) {
|
||||||
|
curwin->w_cursor = end_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_starthere();
|
||||||
|
redrawcmdline();
|
||||||
|
s->did_incsearch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When CTRL-L typed: add character from the match to the pattern.
|
||||||
|
// May set "*c" to the added character.
|
||||||
|
// Return OK when calling command_line_not_changed.
|
||||||
|
static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
|
||||||
|
{
|
||||||
|
int skiplen, patlen;
|
||||||
|
|
||||||
|
// Parsing range may already set the last search pattern.
|
||||||
|
// NOTE: must call restore_last_search_pattern() before returning!
|
||||||
|
save_last_search_pattern();
|
||||||
|
|
||||||
|
// Add a character from under the cursor for 'incsearch'
|
||||||
|
if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) {
|
||||||
|
restore_last_search_pattern();
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
restore_last_search_pattern();
|
||||||
|
|
||||||
|
if (s->did_incsearch) {
|
||||||
|
curwin->w_cursor = s->match_end;
|
||||||
|
if (!equalpos(curwin->w_cursor, s->search_start)) {
|
||||||
|
*c = gchar_cursor();
|
||||||
|
// If 'ignorecase' and 'smartcase' are set and the
|
||||||
|
// command line has no uppercase characters, convert
|
||||||
|
// the character to lowercase
|
||||||
|
if (p_ic && p_scs
|
||||||
|
&& !pat_has_uppercase(ccline.cmdbuff + skiplen)) {
|
||||||
|
*c = mb_tolower(*c);
|
||||||
|
}
|
||||||
|
if (*c != NUL) {
|
||||||
|
if (*c == firstc
|
||||||
|
|| vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), *c)
|
||||||
|
!= NULL) {
|
||||||
|
// put a backslash before special characters
|
||||||
|
stuffcharReadbuff(*c);
|
||||||
|
*c = '\\';
|
||||||
|
}
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s,
|
||||||
|
bool call_update_screen)
|
||||||
|
{
|
||||||
|
if (s->did_incsearch) {
|
||||||
|
s->did_incsearch = false;
|
||||||
|
if (gotesc) {
|
||||||
|
curwin->w_cursor = s->save_cursor;
|
||||||
|
} else {
|
||||||
|
if (!equalpos(s->save_cursor, s->search_start)) {
|
||||||
|
// put the '" mark at the original position
|
||||||
|
curwin->w_cursor = s->save_cursor;
|
||||||
|
setpcmark();
|
||||||
|
}
|
||||||
|
curwin->w_cursor = s->search_start; // -V519
|
||||||
|
}
|
||||||
|
restore_viewstate(&s->old_viewstate);
|
||||||
|
highlight_match = false;
|
||||||
|
|
||||||
|
// by default search all lines
|
||||||
|
search_first_line = 0;
|
||||||
|
search_last_line = MAXLNUM;
|
||||||
|
|
||||||
|
p_magic = s->magic_save;
|
||||||
|
|
||||||
|
validate_cursor(); // needed for TAB
|
||||||
|
redraw_all_later(SOME_VALID);
|
||||||
|
if (call_update_screen) {
|
||||||
|
update_screen(SOME_VALID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Internal entry point for cmdline mode.
|
/// Internal entry point for cmdline mode.
|
||||||
///
|
///
|
||||||
/// caller must use save_cmdline and restore_cmdline. Best is to use
|
/// caller must use save_cmdline and restore_cmdline. Best is to use
|
||||||
@@ -269,11 +652,10 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
.save_msg_scroll = msg_scroll,
|
.save_msg_scroll = msg_scroll,
|
||||||
.save_State = State,
|
.save_State = State,
|
||||||
.ignore_drag_release = true,
|
.ignore_drag_release = true,
|
||||||
.match_start = curwin->w_cursor,
|
|
||||||
};
|
};
|
||||||
CommandLineState *s = &state;
|
CommandLineState *s = &state;
|
||||||
s->save_p_icm = vim_strsave(p_icm);
|
s->save_p_icm = vim_strsave(p_icm);
|
||||||
save_viewstate(&state.init_viewstate);
|
init_incsearch_state(&s->is_state);
|
||||||
|
|
||||||
if (s->firstc == -1) {
|
if (s->firstc == -1) {
|
||||||
s->firstc = NUL;
|
s->firstc = NUL;
|
||||||
@@ -288,10 +670,6 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
ccline.prompt_id = last_prompt_id++;
|
ccline.prompt_id = last_prompt_id++;
|
||||||
ccline.level = cmdline_level;
|
ccline.level = cmdline_level;
|
||||||
ccline.overstrike = false; // always start in insert mode
|
ccline.overstrike = false; // always start in insert mode
|
||||||
clearpos(&s->match_end);
|
|
||||||
s->save_cursor = curwin->w_cursor; // may be restored later
|
|
||||||
s->search_start = curwin->w_cursor;
|
|
||||||
save_viewstate(&state.old_viewstate);
|
|
||||||
|
|
||||||
assert(indent >= 0);
|
assert(indent >= 0);
|
||||||
|
|
||||||
@@ -455,22 +833,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
close_preview_windows();
|
close_preview_windows();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->did_incsearch) {
|
finish_incsearch_highlighting(s->gotesc, &s->is_state, false);
|
||||||
if (s->gotesc) {
|
|
||||||
curwin->w_cursor = s->save_cursor;
|
|
||||||
} else {
|
|
||||||
if (!equalpos(s->save_cursor, s->search_start)) {
|
|
||||||
// put the '" mark at the original position
|
|
||||||
curwin->w_cursor = s->save_cursor;
|
|
||||||
setpcmark();
|
|
||||||
}
|
|
||||||
curwin->w_cursor = s->search_start; // -V519
|
|
||||||
}
|
|
||||||
restore_viewstate(&s->old_viewstate);
|
|
||||||
highlight_match = false;
|
|
||||||
validate_cursor(); // needed for TAB
|
|
||||||
redraw_all_later(SOME_VALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ccline.cmdbuff != NULL) {
|
if (ccline.cmdbuff != NULL) {
|
||||||
// Put line in history buffer (":" and "=" only when it was typed).
|
// Put line in history buffer (":" and "=" only when it was typed).
|
||||||
@@ -1075,24 +1438,45 @@ static int command_line_execute(VimState *state, int key)
|
|||||||
return command_line_handle_key(s);
|
return command_line_handle_key(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_line_next_incsearch(CommandLineState *s, bool next_match)
|
// May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next
|
||||||
|
// or previous match.
|
||||||
|
// Returns FAIL when calling command_line_not_changed.
|
||||||
|
static int may_do_command_line_next_incsearch(int firstc, long count,
|
||||||
|
incsearch_state_T *s,
|
||||||
|
bool next_match)
|
||||||
{
|
{
|
||||||
|
int skiplen, patlen;
|
||||||
|
|
||||||
|
// Parsing range may already set the last search pattern.
|
||||||
|
// NOTE: must call restore_last_search_pattern() before returning!
|
||||||
|
save_last_search_pattern();
|
||||||
|
|
||||||
|
if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) {
|
||||||
|
restore_last_search_pattern();
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (patlen == 0 && ccline.cmdbuff[skiplen] == NUL) {
|
||||||
|
restore_last_search_pattern();
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
ui_busy_start();
|
ui_busy_start();
|
||||||
ui_flush();
|
ui_flush();
|
||||||
|
|
||||||
pos_T t;
|
pos_T t;
|
||||||
char_u *pat;
|
char_u *pat;
|
||||||
int search_flags = SEARCH_NOOF;
|
int search_flags = SEARCH_NOOF;
|
||||||
|
char_u save;
|
||||||
|
|
||||||
|
|
||||||
if (s->firstc == ccline.cmdbuff[0]) {
|
if (firstc == ccline.cmdbuff[skiplen]) {
|
||||||
pat = last_search_pattern();
|
pat = last_search_pattern();
|
||||||
|
skiplen = 0;
|
||||||
|
patlen = (int)STRLEN(pat);
|
||||||
} else {
|
} else {
|
||||||
pat = ccline.cmdbuff;
|
pat = ccline.cmdbuff + skiplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
save_last_search_pattern();
|
|
||||||
|
|
||||||
if (next_match) {
|
if (next_match) {
|
||||||
t = s->match_end;
|
t = s->match_end;
|
||||||
if (lt(s->match_start, s->match_end)) {
|
if (lt(s->match_start, s->match_end)) {
|
||||||
@@ -1108,23 +1492,26 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
|
|||||||
search_flags += SEARCH_KEEP;
|
search_flags += SEARCH_KEEP;
|
||||||
}
|
}
|
||||||
emsg_off++;
|
emsg_off++;
|
||||||
|
save = pat[patlen];
|
||||||
|
pat[patlen] = NUL;
|
||||||
int found = searchit(curwin, curbuf, &t, NULL,
|
int found = searchit(curwin, curbuf, &t, NULL,
|
||||||
next_match ? FORWARD : BACKWARD,
|
next_match ? FORWARD : BACKWARD,
|
||||||
pat, s->count, search_flags,
|
pat, count, search_flags,
|
||||||
RE_SEARCH, NULL);
|
RE_SEARCH, NULL);
|
||||||
emsg_off--;
|
emsg_off--;
|
||||||
|
pat[patlen] = save;
|
||||||
ui_busy_stop();
|
ui_busy_stop();
|
||||||
if (found) {
|
if (found) {
|
||||||
s->search_start = s->match_start;
|
s->search_start = s->match_start;
|
||||||
s->match_end = t;
|
s->match_end = t;
|
||||||
s->match_start = t;
|
s->match_start = t;
|
||||||
if (!next_match && s->firstc == '/') {
|
if (!next_match && firstc != '?') {
|
||||||
// move just before the current match, so that
|
// move just before the current match, so that
|
||||||
// when nv_search finishes the cursor will be
|
// when nv_search finishes the cursor will be
|
||||||
// put back on the match
|
// put back on the match
|
||||||
s->search_start = t;
|
s->search_start = t;
|
||||||
(void)decl(&s->search_start);
|
(void)decl(&s->search_start);
|
||||||
} else if (next_match && s->firstc == '?') {
|
} else if (next_match && firstc == '?') {
|
||||||
// move just after the current match, so that
|
// move just after the current match, so that
|
||||||
// when nv_search finishes the cursor will be
|
// when nv_search finishes the cursor will be
|
||||||
// put back on the match
|
// put back on the match
|
||||||
@@ -1134,7 +1521,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
|
|||||||
if (lt(t, s->search_start) && next_match) {
|
if (lt(t, s->search_start) && next_match) {
|
||||||
// wrap around
|
// wrap around
|
||||||
s->search_start = t;
|
s->search_start = t;
|
||||||
if (s->firstc == '?') {
|
if (firstc == '?') {
|
||||||
(void)incl(&s->search_start);
|
(void)incl(&s->search_start);
|
||||||
} else {
|
} else {
|
||||||
(void)decl(&s->search_start);
|
(void)decl(&s->search_start);
|
||||||
@@ -1154,7 +1541,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
|
|||||||
vim_beep(BO_ERROR);
|
vim_beep(BO_ERROR);
|
||||||
}
|
}
|
||||||
restore_last_search_pattern();
|
restore_last_search_pattern();
|
||||||
return;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_line_next_histidx(CommandLineState *s, bool next_match)
|
static void command_line_next_histidx(CommandLineState *s, bool next_match)
|
||||||
@@ -1265,10 +1652,10 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
// Truncate at the end, required for multi-byte chars.
|
// Truncate at the end, required for multi-byte chars.
|
||||||
ccline.cmdbuff[ccline.cmdlen] = NUL;
|
ccline.cmdbuff[ccline.cmdlen] = NUL;
|
||||||
if (ccline.cmdlen == 0) {
|
if (ccline.cmdlen == 0) {
|
||||||
s->search_start = s->save_cursor;
|
s->is_state.search_start = s->is_state.save_cursor;
|
||||||
// save view settings, so that the screen won't be restored at the
|
// save view settings, so that the screen won't be restored at the
|
||||||
// wrong position
|
// wrong position
|
||||||
s->old_viewstate = s->init_viewstate;
|
s->is_state.old_viewstate = s->is_state.init_viewstate;
|
||||||
}
|
}
|
||||||
redrawcmd();
|
redrawcmd();
|
||||||
} else if (ccline.cmdlen == 0 && s->c != Ctrl_W
|
} else if (ccline.cmdlen == 0 && s->c != Ctrl_W
|
||||||
@@ -1287,7 +1674,7 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
}
|
}
|
||||||
msg_putchar(' '); // delete ':'
|
msg_putchar(' '); // delete ':'
|
||||||
}
|
}
|
||||||
s->search_start = s->save_cursor;
|
s->is_state.search_start = s->is_state.save_cursor;
|
||||||
redraw_cmdline = true;
|
redraw_cmdline = true;
|
||||||
return 0; // back to cmd mode
|
return 0; // back to cmd mode
|
||||||
}
|
}
|
||||||
@@ -1337,7 +1724,7 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
// Truncate at the end, required for multi-byte chars.
|
// Truncate at the end, required for multi-byte chars.
|
||||||
ccline.cmdbuff[ccline.cmdlen] = NUL;
|
ccline.cmdbuff[ccline.cmdlen] = NUL;
|
||||||
if (ccline.cmdlen == 0) {
|
if (ccline.cmdlen == 0) {
|
||||||
s->search_start = s->save_cursor;
|
s->is_state.search_start = s->is_state.save_cursor;
|
||||||
}
|
}
|
||||||
redrawcmd();
|
redrawcmd();
|
||||||
return command_line_changed(s);
|
return command_line_changed(s);
|
||||||
@@ -1565,31 +1952,7 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
return command_line_changed(s);
|
return command_line_changed(s);
|
||||||
|
|
||||||
case Ctrl_L:
|
case Ctrl_L:
|
||||||
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
|
if (may_add_char_to_search(s->firstc, &s->c, &s->is_state) == OK) {
|
||||||
// Add a character from under the cursor for 'incsearch'
|
|
||||||
if (s->did_incsearch) {
|
|
||||||
curwin->w_cursor = s->match_end;
|
|
||||||
if (!equalpos(curwin->w_cursor, s->search_start)) {
|
|
||||||
s->c = gchar_cursor();
|
|
||||||
// If 'ignorecase' and 'smartcase' are set and the
|
|
||||||
// command line has no uppercase characters, convert
|
|
||||||
// the character to lowercase
|
|
||||||
if (p_ic && p_scs
|
|
||||||
&& !pat_has_uppercase(ccline.cmdbuff)) {
|
|
||||||
s->c = mb_tolower(s->c);
|
|
||||||
}
|
|
||||||
if (s->c != NUL) {
|
|
||||||
if (s->c == s->firstc
|
|
||||||
|| vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), s->c)
|
|
||||||
!= NULL) {
|
|
||||||
// put a backslash before special characters
|
|
||||||
stuffcharReadbuff(s->c);
|
|
||||||
s->c = '\\';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return command_line_not_changed(s);
|
return command_line_not_changed(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1703,10 +2066,8 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
|
|
||||||
case Ctrl_G: // next match
|
case Ctrl_G: // next match
|
||||||
case Ctrl_T: // previous match
|
case Ctrl_T: // previous match
|
||||||
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
|
if (may_do_command_line_next_incsearch(s->firstc, s->count, &s->is_state,
|
||||||
if (ccline.cmdlen != 0) {
|
s->c == Ctrl_G) == FAIL) {
|
||||||
command_line_next_incsearch(s, s->c == Ctrl_G);
|
|
||||||
}
|
|
||||||
return command_line_not_changed(s);
|
return command_line_not_changed(s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1791,7 +2152,7 @@ static int command_line_not_changed(CommandLineState *s)
|
|||||||
// command line did not change. Then we only search and redraw if something
|
// command line did not change. Then we only search and redraw if something
|
||||||
// changed in the past.
|
// changed in the past.
|
||||||
// Enter command_line_changed() when the command line did change.
|
// Enter command_line_changed() when the command line did change.
|
||||||
if (!s->incsearch_postponed) {
|
if (!s->is_state.incsearch_postponed) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return command_line_changed(s);
|
return command_line_changed(s);
|
||||||
@@ -1843,108 +2204,13 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 'incsearch' highlighting.
|
// 'incsearch' highlighting.
|
||||||
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
|
if (s->firstc == ':'
|
||||||
pos_T end_pos;
|
&& current_sctx.sc_sid == 0 // only if interactive
|
||||||
proftime_T tm;
|
&& *p_icm != NUL // 'inccommand' is set
|
||||||
searchit_arg_T sia;
|
&& curbuf->b_p_ma // buffer is modifiable
|
||||||
|
&& cmdline_star == 0 // not typing a password
|
||||||
// if there is a character waiting, search and redraw later
|
&& cmd_can_preview(ccline.cmdbuff)
|
||||||
if (char_avail()) {
|
&& !vpeekc_any()) {
|
||||||
s->incsearch_postponed = true;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
s->incsearch_postponed = false;
|
|
||||||
curwin->w_cursor = s->search_start; // start at old position
|
|
||||||
save_last_search_pattern();
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// If there is no command line, don't do anything
|
|
||||||
if (ccline.cmdlen == 0) {
|
|
||||||
i = 0;
|
|
||||||
set_no_hlsearch(true); // turn off previous highlight
|
|
||||||
redraw_all_later(SOME_VALID);
|
|
||||||
} else {
|
|
||||||
int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
|
|
||||||
ui_busy_start();
|
|
||||||
ui_flush();
|
|
||||||
++emsg_off; // So it doesn't beep if bad expr
|
|
||||||
// Set the time limit to half a second.
|
|
||||||
tm = profile_setlimit(500L);
|
|
||||||
if (!p_hls) {
|
|
||||||
search_flags += SEARCH_KEEP;
|
|
||||||
}
|
|
||||||
memset(&sia, 0, sizeof(sia));
|
|
||||||
sia.sa_tm = &tm;
|
|
||||||
i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
|
|
||||||
search_flags, &sia);
|
|
||||||
emsg_off--;
|
|
||||||
// if interrupted while searching, behave like it failed
|
|
||||||
if (got_int) {
|
|
||||||
(void)vpeekc(); // remove <C-C> from input stream
|
|
||||||
got_int = false; // don't abandon the command line
|
|
||||||
i = 0;
|
|
||||||
} else if (char_avail()) {
|
|
||||||
// cancelled searching because a char was typed
|
|
||||||
s->incsearch_postponed = true;
|
|
||||||
}
|
|
||||||
ui_busy_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i != 0) {
|
|
||||||
highlight_match = true; // highlight position
|
|
||||||
} else {
|
|
||||||
highlight_match = false; // remove highlight
|
|
||||||
}
|
|
||||||
|
|
||||||
// first restore the old curwin values, so the screen is
|
|
||||||
// positioned in the same way as the actual search command
|
|
||||||
restore_viewstate(&s->old_viewstate);
|
|
||||||
changed_cline_bef_curs();
|
|
||||||
update_topline();
|
|
||||||
|
|
||||||
if (i != 0) {
|
|
||||||
pos_T save_pos = curwin->w_cursor;
|
|
||||||
|
|
||||||
s->match_start = curwin->w_cursor;
|
|
||||||
set_search_match(&curwin->w_cursor);
|
|
||||||
validate_cursor();
|
|
||||||
end_pos = curwin->w_cursor;
|
|
||||||
s->match_end = end_pos;
|
|
||||||
curwin->w_cursor = save_pos;
|
|
||||||
} else {
|
|
||||||
end_pos = curwin->w_cursor; // shutup gcc 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable 'hlsearch' highlighting if the pattern matches
|
|
||||||
// everything. Avoids a flash when typing "foo\|".
|
|
||||||
if (empty_pattern(ccline.cmdbuff)) {
|
|
||||||
set_no_hlsearch(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_cursor();
|
|
||||||
// May redraw the status line to show the cursor position.
|
|
||||||
if (p_ru && curwin->w_status_height > 0) {
|
|
||||||
curwin->w_redr_status = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_screen(SOME_VALID);
|
|
||||||
restore_last_search_pattern();
|
|
||||||
|
|
||||||
// Leave it at the end to make CTRL-R CTRL-W work.
|
|
||||||
if (i != 0) {
|
|
||||||
curwin->w_cursor = end_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_starthere();
|
|
||||||
redrawcmdline();
|
|
||||||
s->did_incsearch = true;
|
|
||||||
} else if (s->firstc == ':'
|
|
||||||
&& current_sctx.sc_sid == 0 // only if interactive
|
|
||||||
&& *p_icm != NUL // 'inccommand' is set
|
|
||||||
&& curbuf->b_p_ma // buffer is modifiable
|
|
||||||
&& cmdline_star == 0 // not typing a password
|
|
||||||
&& cmd_can_preview(ccline.cmdbuff)
|
|
||||||
&& !vpeekc_any()) {
|
|
||||||
// Show 'inccommand' preview. It works like this:
|
// Show 'inccommand' preview. It works like this:
|
||||||
// 1. Do the command.
|
// 1. Do the command.
|
||||||
// 2. Command implementation detects CMDPREVIEW state, then:
|
// 2. Command implementation detects CMDPREVIEW state, then:
|
||||||
@@ -1958,8 +2224,8 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
emsg_silent--; // Unblock error reporting
|
emsg_silent--; // Unblock error reporting
|
||||||
|
|
||||||
// Restore the window "view".
|
// Restore the window "view".
|
||||||
curwin->w_cursor = s->save_cursor;
|
curwin->w_cursor = s->is_state.save_cursor;
|
||||||
restore_viewstate(&s->old_viewstate);
|
restore_viewstate(&s->is_state.old_viewstate);
|
||||||
update_topline();
|
update_topline();
|
||||||
|
|
||||||
redrawcmdline();
|
redrawcmdline();
|
||||||
@@ -1968,6 +2234,8 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
State = (State & ~CMDPREVIEW);
|
State = (State & ~CMDPREVIEW);
|
||||||
close_preview_windows();
|
close_preview_windows();
|
||||||
update_screen(SOME_VALID); // Clear 'inccommand' preview.
|
update_screen(SOME_VALID); // Clear 'inccommand' preview.
|
||||||
|
} else {
|
||||||
|
may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdmsg_rl || (p_arshape && !p_tbidi && enc_utf8)) {
|
if (cmdmsg_rl || (p_arshape && !p_tbidi && enc_utf8)) {
|
||||||
|
@@ -353,9 +353,11 @@ EXTERN int t_colors INIT(= 256); // int value of T_CCO
|
|||||||
// position. Search_match_lines is the number of lines after the match (0 for
|
// position. Search_match_lines is the number of lines after the match (0 for
|
||||||
// a match within one line), search_match_endcol the column number of the
|
// a match within one line), search_match_endcol the column number of the
|
||||||
// character just after the match in the last line.
|
// character just after the match in the last line.
|
||||||
EXTERN int highlight_match INIT(= false); // show search match pos
|
EXTERN bool highlight_match INIT(= false); // show search match pos
|
||||||
EXTERN linenr_T search_match_lines; // lines of of matched string
|
EXTERN linenr_T search_match_lines; // lines of of matched string
|
||||||
EXTERN colnr_T search_match_endcol; // col nr of match end
|
EXTERN colnr_T search_match_endcol; // col nr of match end
|
||||||
|
EXTERN linenr_T search_first_line INIT(= 0); // for :{FIRST},{last}s/pat
|
||||||
|
EXTERN linenr_T search_last_line INIT(= MAXLNUM); // for :{first},{LAST}s/pat
|
||||||
|
|
||||||
EXTERN int no_smartcase INIT(= false); // don't use 'smartcase' once
|
EXTERN int no_smartcase INIT(= false); // don't use 'smartcase' once
|
||||||
|
|
||||||
|
@@ -5918,6 +5918,12 @@ next_search_hl (
|
|||||||
long nmatched = 0;
|
long nmatched = 0;
|
||||||
int save_called_emsg = called_emsg;
|
int save_called_emsg = called_emsg;
|
||||||
|
|
||||||
|
// for :{range}s/pat only highlight inside the range
|
||||||
|
if (lnum < search_first_line || lnum > search_last_line) {
|
||||||
|
shl->lnum = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (shl->lnum != 0) {
|
if (shl->lnum != 0) {
|
||||||
// Check for three situations:
|
// Check for three situations:
|
||||||
// 1. If the "lnum" is below a previous match, start a new search.
|
// 1. If the "lnum" is below a previous match, start a new search.
|
||||||
|
@@ -99,6 +99,7 @@ static struct spat saved_spats[2];
|
|||||||
// copy of spats[RE_SEARCH], for keeping the search patterns while incremental
|
// copy of spats[RE_SEARCH], for keeping the search patterns while incremental
|
||||||
// searching
|
// searching
|
||||||
static struct spat saved_last_search_spat;
|
static struct spat saved_last_search_spat;
|
||||||
|
static int did_save_last_search_spat = 0;
|
||||||
static int saved_last_idx = 0;
|
static int saved_last_idx = 0;
|
||||||
static bool saved_no_hlsearch = false;
|
static bool saved_no_hlsearch = false;
|
||||||
|
|
||||||
@@ -316,6 +317,12 @@ void free_search_patterns(void)
|
|||||||
/// cancelling incremental searching even if it's called inside user functions.
|
/// cancelling incremental searching even if it's called inside user functions.
|
||||||
void save_last_search_pattern(void)
|
void save_last_search_pattern(void)
|
||||||
{
|
{
|
||||||
|
if (did_save_last_search_spat != 0) {
|
||||||
|
IEMSG("did_save_last_search_spat is not zero");
|
||||||
|
} else {
|
||||||
|
did_save_last_search_spat++;
|
||||||
|
}
|
||||||
|
|
||||||
saved_last_search_spat = spats[RE_SEARCH];
|
saved_last_search_spat = spats[RE_SEARCH];
|
||||||
if (spats[RE_SEARCH].pat != NULL) {
|
if (spats[RE_SEARCH].pat != NULL) {
|
||||||
saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat);
|
saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat);
|
||||||
@@ -326,8 +333,15 @@ void save_last_search_pattern(void)
|
|||||||
|
|
||||||
void restore_last_search_pattern(void)
|
void restore_last_search_pattern(void)
|
||||||
{
|
{
|
||||||
|
if (did_save_last_search_spat != 1) {
|
||||||
|
IEMSG("did_save_last_search_spat is not one");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
did_save_last_search_spat--;
|
||||||
|
|
||||||
xfree(spats[RE_SEARCH].pat);
|
xfree(spats[RE_SEARCH].pat);
|
||||||
spats[RE_SEARCH] = saved_last_search_spat;
|
spats[RE_SEARCH] = saved_last_search_spat;
|
||||||
|
saved_last_search_spat.pat = NULL;
|
||||||
set_vv_searchforward();
|
set_vv_searchforward();
|
||||||
last_idx = saved_last_idx;
|
last_idx = saved_last_idx;
|
||||||
set_no_hlsearch(saved_no_hlsearch);
|
set_no_hlsearch(saved_no_hlsearch);
|
||||||
|
@@ -346,25 +346,104 @@ func Test_searchc()
|
|||||||
bw!
|
bw!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_search_cmdline3()
|
func Cmdline3_prep()
|
||||||
throw 'skipped: Nvim does not support test_override()'
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
if !exists('+incsearch')
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
" need to disable char_avail,
|
" need to disable char_avail,
|
||||||
" so that expansion of commandline works
|
" so that expansion of commandline works
|
||||||
call test_override("char_avail", 1)
|
call test_override("char_avail", 1)
|
||||||
new
|
new
|
||||||
call setline(1, [' 1', ' 2 the~e', ' 3 the theother'])
|
call setline(1, [' 1', ' 2 the~e', ' 3 the theother'])
|
||||||
set incsearch
|
set incsearch
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Incsearch_cleanup()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
set noincsearch
|
||||||
|
call test_override("char_avail", 0)
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_search_cmdline3()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call Cmdline3_prep()
|
||||||
1
|
1
|
||||||
" first match
|
" first match
|
||||||
call feedkeys("/the\<c-l>\<cr>", 'tx')
|
call feedkeys("/the\<c-l>\<cr>", 'tx')
|
||||||
call assert_equal(' 2 the~e', getline('.'))
|
call assert_equal(' 2 the~e', getline('.'))
|
||||||
" clean up
|
|
||||||
set noincsearch
|
call Incsearch_cleanup()
|
||||||
call test_override("char_avail", 0)
|
endfunc
|
||||||
bw!
|
|
||||||
|
func Test_search_cmdline3s()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call Cmdline3_prep()
|
||||||
|
1
|
||||||
|
call feedkeys(":%s/the\<c-l>/xxx\<cr>", 'tx')
|
||||||
|
call assert_equal(' 2 xxxe', getline('.'))
|
||||||
|
undo
|
||||||
|
call feedkeys(":%subs/the\<c-l>/xxx\<cr>", 'tx')
|
||||||
|
call assert_equal(' 2 xxxe', getline('.'))
|
||||||
|
undo
|
||||||
|
call feedkeys(":%substitute/the\<c-l>/xxx\<cr>", 'tx')
|
||||||
|
call assert_equal(' 2 xxxe', getline('.'))
|
||||||
|
undo
|
||||||
|
call feedkeys(":%smagic/the.e/xxx\<cr>", 'tx')
|
||||||
|
call assert_equal(' 2 xxx', getline('.'))
|
||||||
|
undo
|
||||||
|
call assert_fails(":%snomagic/the.e/xxx\<cr>", 'E486')
|
||||||
|
"
|
||||||
|
call feedkeys(":%snomagic/the\\.e/xxx\<cr>", 'tx')
|
||||||
|
call assert_equal(' 2 xxx', getline('.'))
|
||||||
|
|
||||||
|
call Incsearch_cleanup()
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_search_cmdline3g()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call Cmdline3_prep()
|
||||||
|
1
|
||||||
|
call feedkeys(":g/the\<c-l>/d\<cr>", 'tx')
|
||||||
|
call assert_equal(' 3 the theother', getline(2))
|
||||||
|
undo
|
||||||
|
call feedkeys(":global/the\<c-l>/d\<cr>", 'tx')
|
||||||
|
call assert_equal(' 3 the theother', getline(2))
|
||||||
|
undo
|
||||||
|
call feedkeys(":g!/the\<c-l>/d\<cr>", 'tx')
|
||||||
|
call assert_equal(1, line('$'))
|
||||||
|
call assert_equal(' 2 the~e', getline(1))
|
||||||
|
undo
|
||||||
|
call feedkeys(":global!/the\<c-l>/d\<cr>", 'tx')
|
||||||
|
call assert_equal(1, line('$'))
|
||||||
|
call assert_equal(' 2 the~e', getline(1))
|
||||||
|
|
||||||
|
call Incsearch_cleanup()
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_search_cmdline3v()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call Cmdline3_prep()
|
||||||
|
1
|
||||||
|
call feedkeys(":v/the\<c-l>/d\<cr>", 'tx')
|
||||||
|
call assert_equal(1, line('$'))
|
||||||
|
call assert_equal(' 2 the~e', getline(1))
|
||||||
|
undo
|
||||||
|
call feedkeys(":vglobal/the\<c-l>/d\<cr>", 'tx')
|
||||||
|
call assert_equal(1, line('$'))
|
||||||
|
call assert_equal(' 2 the~e', getline(1))
|
||||||
|
|
||||||
|
call Incsearch_cleanup()
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_search_cmdline4()
|
func Test_search_cmdline4()
|
||||||
@@ -423,6 +502,45 @@ func Test_search_cmdline5()
|
|||||||
bw!
|
bw!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_search_cmdline7()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
" Test that an pressing <c-g> in an empty command line
|
||||||
|
" does not move the cursor
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
" need to disable char_avail,
|
||||||
|
" so that expansion of commandline works
|
||||||
|
call test_override("char_avail", 1)
|
||||||
|
new
|
||||||
|
let @/ = 'b'
|
||||||
|
call setline(1, [' bbvimb', ''])
|
||||||
|
set incsearch
|
||||||
|
" first match
|
||||||
|
norm! gg0
|
||||||
|
" moves to next match of previous search pattern, just like /<cr>
|
||||||
|
call feedkeys("/\<c-g>\<cr>", 'tx')
|
||||||
|
call assert_equal([0,1,2,0], getpos('.'))
|
||||||
|
" moves to next match of previous search pattern, just like /<cr>
|
||||||
|
call feedkeys("/\<cr>", 'tx')
|
||||||
|
call assert_equal([0,1,3,0], getpos('.'))
|
||||||
|
" moves to next match of previous search pattern, just like /<cr>
|
||||||
|
call feedkeys("/\<c-t>\<cr>", 'tx')
|
||||||
|
call assert_equal([0,1,7,0], getpos('.'))
|
||||||
|
|
||||||
|
" using an offset uses the last search pattern
|
||||||
|
call cursor(1, 1)
|
||||||
|
call setline(1, ['1 bbvimb', ' 2 bbvimb'])
|
||||||
|
let @/ = 'b'
|
||||||
|
call feedkeys("//e\<c-g>\<cr>", 'tx')
|
||||||
|
call assert_equal('1 bbvimb', getline('.'))
|
||||||
|
call assert_equal(4, col('.'))
|
||||||
|
|
||||||
|
set noincsearch
|
||||||
|
call test_override("char_avail", 0)
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Tests for regexp with various magic settings
|
" Tests for regexp with various magic settings
|
||||||
func Test_search_regexp()
|
func Test_search_regexp()
|
||||||
enew!
|
enew!
|
||||||
@@ -504,6 +622,7 @@ func Test_incsearch_substitute_dump()
|
|||||||
\ 'for n in range(1, 10)',
|
\ 'for n in range(1, 10)',
|
||||||
\ ' call setline(n, "foo " . n)',
|
\ ' call setline(n, "foo " . n)',
|
||||||
\ 'endfor',
|
\ 'endfor',
|
||||||
|
\ 'call setline(11, "bar 11")',
|
||||||
\ '3',
|
\ '3',
|
||||||
\ ], 'Xis_subst_script')
|
\ ], 'Xis_subst_script')
|
||||||
let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70})
|
let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70})
|
||||||
@@ -512,6 +631,7 @@ func Test_incsearch_substitute_dump()
|
|||||||
sleep 100m
|
sleep 100m
|
||||||
|
|
||||||
" Need to send one key at a time to force a redraw.
|
" Need to send one key at a time to force a redraw.
|
||||||
|
" Select three lines at the cursor with typed pattern.
|
||||||
call term_sendkeys(buf, ':.,.+2s/')
|
call term_sendkeys(buf, ':.,.+2s/')
|
||||||
sleep 100m
|
sleep 100m
|
||||||
call term_sendkeys(buf, 'f')
|
call term_sendkeys(buf, 'f')
|
||||||
@@ -520,12 +640,203 @@ func Test_incsearch_substitute_dump()
|
|||||||
sleep 100m
|
sleep 100m
|
||||||
call term_sendkeys(buf, 'o')
|
call term_sendkeys(buf, 'o')
|
||||||
call VerifyScreenDump(buf, 'Test_incsearch_substitute_01', {})
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_01', {})
|
||||||
|
|
||||||
call term_sendkeys(buf, "\<Esc>")
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" Select three lines at the cursor using previous pattern.
|
||||||
|
call term_sendkeys(buf, "/foo\<CR>")
|
||||||
|
sleep 100m
|
||||||
|
call term_sendkeys(buf, ':.,.+2s//')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_02', {})
|
||||||
|
|
||||||
|
" Deleting last slash should remove the match.
|
||||||
|
call term_sendkeys(buf, "\<BS>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_03', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" Reverse range is accepted
|
||||||
|
call term_sendkeys(buf, ':5,2s/foo')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_04', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" White space after the command is skipped
|
||||||
|
call term_sendkeys(buf, ':2,3sub /fo')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_05', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" 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.')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" Cursorline highlighting at match
|
||||||
|
call term_sendkeys(buf, ":set cursorline\<CR>")
|
||||||
|
call term_sendkeys(buf, 'G9G')
|
||||||
|
call term_sendkeys(buf, ':9,11s/bar')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_07', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" Cursorline highlighting at cursor when no match
|
||||||
|
call term_sendkeys(buf, ':9,10s/bar')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_08', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" Only \v handled as empty pattern, does not move cursor
|
||||||
|
call term_sendkeys(buf, '3G4G')
|
||||||
|
call term_sendkeys(buf, ":nohlsearch\<CR>")
|
||||||
|
call term_sendkeys(buf, ':6,7s/\v')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_09', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ":set nocursorline\<CR>")
|
||||||
|
|
||||||
|
" All matches are highlighted for 'hlsearch' after the incsearch canceled
|
||||||
|
call term_sendkeys(buf, "1G*")
|
||||||
|
call term_sendkeys(buf, ":2,5s/foo")
|
||||||
|
sleep 100m
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_10', {})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ":split\<CR>")
|
||||||
|
call term_sendkeys(buf, ":let @/ = 'xyz'\<CR>")
|
||||||
|
call term_sendkeys(buf, ":%s/.")
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_11', {})
|
||||||
|
call term_sendkeys(buf, "\<BS>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_12', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_substitute_13', {})
|
||||||
|
|
||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
call delete('Xis_subst_script')
|
call delete('Xis_subst_script')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Similar to Test_incsearch_substitute_dump() for :sort
|
||||||
|
func Test_incsearch_sort_dump()
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
if !CanRunVimInTerminal()
|
||||||
|
throw 'Skipped: cannot make screendumps'
|
||||||
|
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')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call StopVimInTerminal(buf)
|
||||||
|
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()
|
||||||
|
throw 'Skipped: cannot make screendumps'
|
||||||
|
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')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_01', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ':vimg /on/ *.txt')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_02', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ':vimgrepadd "\<on')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_03', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ':lv "tha')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_04', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ':lvimgrepa "the" **/*.txt')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_05', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call StopVimInTerminal(buf)
|
||||||
|
call delete('Xis_vimgrep_script')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_keep_last_search_pattern()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
new
|
||||||
|
call setline(1, ['foo', 'foo', 'foo'])
|
||||||
|
set incsearch
|
||||||
|
call test_override("char_avail", 1)
|
||||||
|
let @/ = 'bar'
|
||||||
|
call feedkeys(":/foo/s//\<Esc>", 'ntx')
|
||||||
|
call assert_equal('bar', @/)
|
||||||
|
|
||||||
|
" no error message if pattern not found
|
||||||
|
call feedkeys(":/xyz/s//\<Esc>", 'ntx')
|
||||||
|
call assert_equal('bar', @/)
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
call test_override("ALL", 0)
|
||||||
|
set noincsearch
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_word_under_cursor_after_match()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
new
|
||||||
|
call setline(1, 'foo bar')
|
||||||
|
set incsearch
|
||||||
|
call test_override("char_avail", 1)
|
||||||
|
try
|
||||||
|
call feedkeys("/foo\<C-R>\<C-W>\<CR>", 'ntx')
|
||||||
|
catch /E486:/
|
||||||
|
endtry
|
||||||
|
call assert_equal('foobar', @/)
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
call test_override("ALL", 0)
|
||||||
|
set noincsearch
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_subst_word_under_cursor()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
new
|
||||||
|
call setline(1, ['int SomeLongName;', 'for (xxx = 1; xxx < len; ++xxx)'])
|
||||||
|
set incsearch
|
||||||
|
call test_override("char_avail", 1)
|
||||||
|
call feedkeys("/LongName\<CR>", 'ntx')
|
||||||
|
call feedkeys(":%s/xxx/\<C-R>\<C-W>/g\<CR>", 'ntx')
|
||||||
|
call assert_equal('for (SomeLongName = 1; SomeLongName < len; ++SomeLongName)', getline(2))
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
call test_override("ALL", 0)
|
||||||
|
set noincsearch
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_incsearch_with_change()
|
func Test_incsearch_with_change()
|
||||||
if !has('timers') || !exists('+incsearch') || !CanRunVimInTerminal()
|
if !has('timers') || !exists('+incsearch') || !CanRunVimInTerminal()
|
||||||
throw 'Skipped: cannot make screendumps and/or timers feature and/or incsearch option missing'
|
throw 'Skipped: cannot make screendumps and/or timers feature and/or incsearch option missing'
|
||||||
@@ -580,6 +891,61 @@ func Test_incsearch_scrolling()
|
|||||||
call delete('Xscript')
|
call delete('Xscript')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_incsearch_search_dump()
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
if !CanRunVimInTerminal()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call writefile([
|
||||||
|
\ 'set incsearch hlsearch scrolloff=0',
|
||||||
|
\ 'for n in range(1, 8)',
|
||||||
|
\ ' call setline(n, "foo " . n)',
|
||||||
|
\ 'endfor',
|
||||||
|
\ '3',
|
||||||
|
\ ], 'Xis_search_script')
|
||||||
|
let buf = RunVimInTerminal('-S Xis_search_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, '/fo')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_search_01', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
sleep 100m
|
||||||
|
|
||||||
|
call term_sendkeys(buf, '/\v')
|
||||||
|
call VerifyScreenDump(buf, 'Test_incsearch_search_02', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call StopVimInTerminal(buf)
|
||||||
|
call delete('Xis_search_script')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_incsearch_substitute()
|
||||||
|
throw 'skipped: Nvim does not support test_override()'
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call test_override("char_avail", 1)
|
||||||
|
new
|
||||||
|
set incsearch
|
||||||
|
for n in range(1, 10)
|
||||||
|
call setline(n, 'foo ' . n)
|
||||||
|
endfor
|
||||||
|
4
|
||||||
|
call feedkeys(":.,.+2s/foo\<BS>o\<BS>o/xxx\<cr>", 'tx')
|
||||||
|
call assert_equal('foo 3', getline(3))
|
||||||
|
call assert_equal('xxx 4', getline(4))
|
||||||
|
call assert_equal('xxx 5', getline(5))
|
||||||
|
call assert_equal('xxx 6', getline(6))
|
||||||
|
call assert_equal('foo 7', getline(7))
|
||||||
|
|
||||||
|
call Incsearch_cleanup()
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_search_undefined_behaviour()
|
func Test_search_undefined_behaviour()
|
||||||
if !has("terminal")
|
if !has("terminal")
|
||||||
return
|
return
|
||||||
|
@@ -21,6 +21,7 @@ describe('search cmdline', function()
|
|||||||
err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
|
err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
|
||||||
more = { bold = true, foreground = Screen.colors.SeaGreen4 },
|
more = { bold = true, foreground = Screen.colors.SeaGreen4 },
|
||||||
tilde = { bold = true, foreground = Screen.colors.Blue1 },
|
tilde = { bold = true, foreground = Screen.colors.Blue1 },
|
||||||
|
hl = { background = Screen.colors.Yellow },
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -570,4 +571,72 @@ describe('search cmdline', function()
|
|||||||
?the |
|
?the |
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('incsearch works with :sort', function()
|
||||||
|
-- oldtest: Test_incsearch_sort_dump().
|
||||||
|
screen:try_resize(20, 4)
|
||||||
|
command('set incsearch hlsearch scrolloff=0')
|
||||||
|
funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
|
||||||
|
|
||||||
|
feed(':sort ni u /on')
|
||||||
|
screen:expect([[
|
||||||
|
another {inc:on}e 2 |
|
||||||
|
that {hl:on}e 3 |
|
||||||
|
the {hl:on}e 1 |
|
||||||
|
:sort ni u /on^ |
|
||||||
|
]])
|
||||||
|
feed('<esc>')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('incsearch works with :vimgrep family', function()
|
||||||
|
-- oldtest: Test_incsearch_vimgrep_dump().
|
||||||
|
screen:try_resize(30, 4)
|
||||||
|
command('set incsearch hlsearch scrolloff=0')
|
||||||
|
funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
|
||||||
|
|
||||||
|
feed(':vimgrep on')
|
||||||
|
screen:expect([[
|
||||||
|
another {inc:on}e 2 |
|
||||||
|
that {hl:on}e 3 |
|
||||||
|
the {hl:on}e 1 |
|
||||||
|
:vimgrep on^ |
|
||||||
|
]])
|
||||||
|
feed('<esc>')
|
||||||
|
|
||||||
|
feed(':vimg /on/ *.txt')
|
||||||
|
screen:expect([[
|
||||||
|
another {inc:on}e 2 |
|
||||||
|
that {hl:on}e 3 |
|
||||||
|
the {hl:on}e 1 |
|
||||||
|
:vimg /on/ *.txt^ |
|
||||||
|
]])
|
||||||
|
feed('<esc>')
|
||||||
|
|
||||||
|
feed(':vimgrepadd "\\<LT>on')
|
||||||
|
screen:expect([[
|
||||||
|
another {inc:on}e 2 |
|
||||||
|
that {hl:on}e 3 |
|
||||||
|
the {hl:on}e 1 |
|
||||||
|
:vimgrepadd "\<on^ |
|
||||||
|
]])
|
||||||
|
feed('<esc>')
|
||||||
|
|
||||||
|
feed(':lv "tha')
|
||||||
|
screen:expect([[
|
||||||
|
another one 2 |
|
||||||
|
{inc:tha}t one 3 |
|
||||||
|
the one 1 |
|
||||||
|
:lv "tha^ |
|
||||||
|
]])
|
||||||
|
feed('<esc>')
|
||||||
|
|
||||||
|
feed(':lvimgrepa "the" **/*.txt')
|
||||||
|
screen:expect([[
|
||||||
|
ano{inc:the}r one 2 |
|
||||||
|
that one 3 |
|
||||||
|
{hl:the} one 1 |
|
||||||
|
:lvimgrepa "the" **/*.txt^ |
|
||||||
|
]])
|
||||||
|
feed('<esc>')
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
@@ -162,7 +162,7 @@ describe(":substitute, 'inccommand' preserves", function()
|
|||||||
insert(default_text)
|
insert(default_text)
|
||||||
feed_command("set inccommand=" .. case)
|
feed_command("set inccommand=" .. case)
|
||||||
|
|
||||||
local delims = { '/', '#', ';', '%', ',', '@', '!', ''}
|
local delims = { '/', '#', ';', '%', ',', '@', '!' }
|
||||||
for _,delim in pairs(delims) do
|
for _,delim in pairs(delims) do
|
||||||
feed_command("%s"..delim.."lines"..delim.."LINES"..delim.."g")
|
feed_command("%s"..delim.."lines"..delim.."LINES"..delim.."g")
|
||||||
expect([[
|
expect([[
|
||||||
|
Reference in New Issue
Block a user