aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/starting.txt27
-rw-r--r--src/nvim/buffer.c13
-rw-r--r--src/nvim/eval.c46
-rw-r--r--src/nvim/ex_cmds.c105
-rw-r--r--src/nvim/ex_cmds.lua6
-rw-r--r--src/nvim/ex_cmds_defs.h27
-rw-r--r--src/nvim/ex_docmd.c101
-rw-r--r--src/nvim/getchar.c6
-rw-r--r--src/nvim/message.c19
-rw-r--r--src/nvim/quickfix.c46
-rw-r--r--src/nvim/testdir/runtest.vim1
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim76
-rw-r--r--src/nvim/version.c12
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua47
15 files changed, 379 insertions, 154 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index f7c47125f1..edb0770313 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -518,7 +518,8 @@ accordingly. Vim proceeds in this order:
The |v:vim_did_enter| variable is set to 1.
The |VimEnter| autocommands are executed.
-Some hints on using initializations:
+
+Some hints on using initializations ~
Standard setup:
Create a vimrc file to set the default settings and mappings for all your edit
@@ -540,17 +541,23 @@ the ":version" command. NOTE: System vimrc file needs specific compilation
options (one needs to define SYS_VIMRC_FILE macros). If :version command does
not show anything like this, consider contacting the nvim package maintainer.
-Saving the current state of Vim to a file:
+
+Saving the current state of Vim to a file ~
+
Whenever you have changed values of options or when you have created a
mapping, then you may want to save them in a vimrc file for later use. See
|save-settings| about saving the current state of settings to a file.
-Avoiding setup problems for Vi users:
+
+Avoiding setup problems for Vi users ~
+
Vi uses the variable EXINIT and the file "~/.exrc". So if you do not want to
interfere with Vi, then use the variable VIMINIT and the file init.vim
instead.
-MS-DOS line separators:
+
+MS-DOS line separators: ~
+
On Windows systems Vim assumes that all the vimrc files have <CR> <NL> pairs
as line separators. This will give problems if you have a file with only
<NL>s and have a line like ":map xx yy^M". The trailing ^M will be ignored.
@@ -558,8 +565,10 @@ as line separators. This will give problems if you have a file with only
The $MYVIMRC or $MYGVIMRC file will be set to the first found vimrc and/or
gvimrc file.
-Avoiding trojan horses: *trojan-horse*
-While reading the vimrc or the exrc file in the current directory, some
+
+Avoiding trojan horses ~
+ *trojan-horse*
+While reading the "vimrc" or the "exrc" file in the current directory, some
commands can be disabled for security reasons by setting the 'secure' option.
This is always done when executing the command from a tags file. Otherwise it
would be possible that you accidentally use a vimrc or tags file that somebody
@@ -581,6 +590,8 @@ Be careful!
part of the line in the tags file) is always done in secure mode. This works
just like executing a command from a vimrc/exrc in the current directory.
+
+If Vim startup is slow ~
*slow-start*
If Vim takes a long time to start up, use the |--startuptime| argument to find
out what happens.
@@ -590,6 +601,8 @@ while. You can find out if this is the problem by disabling ShaDa for a
moment (use the Vim argument "-i NONE", |-i|). Try reducing the number of
lines stored in a register with ":set shada='20,<50,s10". |shada-file|.
+
+Intro message ~
*:intro*
When Vim starts without a file name, an introductory message is displayed (for
those who don't know what Vim is). It is removed as soon as the display is
@@ -1182,7 +1195,7 @@ running) you have additional options:
*:o* *:ol* *:oldfiles*
:o[ldfiles] List the files that have marks stored in the ShaDa
file. This list is read on startup and only changes
- afterwards with ":rshada!". Also see |v:oldfiles|.
+ afterwards with `:rshada!`. Also see |v:oldfiles|.
The number can be used with |c_#<|.
The output can be filtered with |:filter|, e.g.: >
filter /\.vim/ oldfiles
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 7477118d6f..7def8c1684 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -2365,12 +2365,17 @@ void buflist_list(exarg_T *eap)
&& (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum))) {
continue;
}
- msg_putchar('\n');
- if (buf_spname(buf) != NULL)
+ if (buf_spname(buf) != NULL) {
STRLCPY(NameBuff, buf_spname(buf), MAXPATHL);
- else
- home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
+ } else {
+ home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, true);
+ }
+ if (message_filtered(NameBuff)) {
+ continue;
+ }
+
+ msg_putchar('\n');
len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
buf->b_fnum,
buf->b_p_bl ? ' ' : 'u',
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index b0f47d8e45..1bf85ccd8b 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -21779,52 +21779,6 @@ void last_set_msg(scid_T scriptID)
}
}
-/*
- * List v:oldfiles in a nice way.
- */
-void ex_oldfiles(exarg_T *eap)
-{
- list_T *l = get_vim_var_list(VV_OLDFILES);
- listitem_T *li;
- long nr = 0;
-
- if (l == NULL)
- msg((char_u *)_("No old files"));
- else {
- msg_start();
- msg_scroll = TRUE;
- for (li = l->lv_first; li != NULL && !got_int; li = li->li_next) {
- msg_outnum(++nr);
- MSG_PUTS(": ");
- msg_outtrans((char_u *)tv_get_string(&li->li_tv));
- msg_clr_eos();
- msg_putchar('\n');
- ui_flush(); /* output one line at a time */
- os_breakcheck();
- }
- /* Assume "got_int" was set to truncate the listing. */
- got_int = FALSE;
-
- // File selection prompt on ":browse oldfiles"
- if (cmdmod.browse) {
- quit_more = false;
- nr = prompt_for_number(false);
- msg_starthere();
- if (nr > 0 && nr <= l->lv_len) {
- const char *const p = tv_list_find_str(l, nr - 1);
- if (p == NULL) {
- return;
- }
- char *const s = (char *)expand_env_save((char_u *)p);
- eap->arg = (char_u *)s;
- eap->cmdidx = CMD_edit;
- do_exedit(eap, NULL);
- xfree(s);
- }
- }
- }
-}
-
// reset v:option_new, v:option_old and v:option_type
void reset_v_option_vars(void)
{
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 7726e0fc6d..f73d4c16b6 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1490,6 +1490,11 @@ void print_line(linenr_T lnum, int use_number, int list)
{
int save_silent = silent_mode;
+ // apply :filter /pat/
+ if (message_filtered(ml_get(lnum))) {
+ return;
+ }
+
msg_start();
silent_mode = FALSE;
info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
@@ -6158,3 +6163,103 @@ void ex_substitute(exarg_T *eap)
ga_clear(&save_view);
unblock_autocmds();
}
+
+/// Skip over the pattern argument of ":vimgrep /pat/[g][j]".
+/// Put the start of the pattern in "*s", unless "s" is NULL.
+/// If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP.
+/// If "s" is not NULL terminate the pattern with a NUL.
+/// Return a pointer to the char just past the pattern plus flags.
+char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
+{
+ int c;
+
+ if (vim_isIDc(*p)) {
+ // ":vimgrep pattern fname"
+ if (s != NULL) {
+ *s = p;
+ }
+ p = skiptowhite(p);
+ if (s != NULL && *p != NUL) {
+ *p++ = NUL;
+ }
+ } else {
+ // ":vimgrep /pattern/[g][j] fname"
+ if (s != NULL) {
+ *s = p + 1;
+ }
+ c = *p;
+ p = skip_regexp(p + 1, c, true, NULL);
+ if (*p != c) {
+ return NULL;
+ }
+
+ // Truncate the pattern.
+ if (s != NULL) {
+ *p = NUL;
+ }
+ p++;
+
+ // Find the flags
+ while (*p == 'g' || *p == 'j') {
+ if (flags != NULL) {
+ if (*p == 'g') {
+ *flags |= VGR_GLOBAL;
+ } else {
+ *flags |= VGR_NOJUMP;
+ }
+ }
+ p++;
+ }
+ }
+ return p;
+}
+
+/// List v:oldfiles in a nice way.
+void ex_oldfiles(exarg_T *eap)
+{
+ list_T *l = get_vim_var_list(VV_OLDFILES);
+ listitem_T *li;
+ long nr = 0;
+
+ if (l == NULL) {
+ msg((char_u *)_("No old files"));
+ } else {
+ msg_start();
+ msg_scroll = true;
+ for (li = l->lv_first; li != NULL && !got_int; li = li->li_next) {
+ nr++;
+ const char *fname = tv_get_string(&li->li_tv);
+ if (!message_filtered((char_u *)fname)) {
+ msg_outnum(nr);
+ MSG_PUTS(": ");
+ msg_outtrans((char_u *)tv_get_string(&li->li_tv));
+ msg_clr_eos();
+ msg_putchar('\n');
+ ui_flush(); // output one line at a time
+ os_breakcheck();
+ }
+ }
+
+ // Assume "got_int" was set to truncate the listing.
+ got_int = false;
+
+ // File selection prompt on ":browse oldfiles"
+ if (cmdmod.browse) {
+ quit_more = false;
+ nr = prompt_for_number(false);
+ msg_starthere();
+ if (nr > 0 && nr <= l->lv_len) {
+ const char *const p = tv_list_find_str(l, nr - 1);
+ if (p == NULL) {
+ return;
+ }
+ char *const s = (char *)expand_env_save((char_u *)p);
+ eap->arg = (char_u *)s;
+ eap->cmdidx = CMD_edit;
+ cmdmod.browse = false;
+ do_exedit(eap, NULL);
+ xfree(s);
+ }
+ }
+ }
+}
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 92f0669422..523740444d 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -931,6 +931,12 @@ return {
func='ex_filetype',
},
{
+ command='filter',
+ flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM),
+ addr_type=ADDR_LINES,
+ func='ex_wrongmodifier',
+ },
+ {
command='find',
flags=bit.bor(RANGE, NOTADR, BANG, FILE1, EDITCMD, ARGOPT, TRLBAR),
addr_type=ADDR_LINES,
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 133c37cef4..d72b83404e 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -6,6 +6,7 @@
#include "nvim/pos.h" // for linenr_T
#include "nvim/normal.h"
+#include "nvim/regexp_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_cmds_enum.generated.h"
@@ -163,18 +164,20 @@ struct expand {
/// flag. This needs to be saved for recursive commands, put them in a
/// structure for easy manipulation.
typedef struct {
- int split; ///< flags for win_split()
- int tab; ///< > 0 when ":tab" was used
- bool browse; ///< true to invoke file dialog
- bool confirm; ///< true to invoke yes/no dialog
- bool hide; ///< true when ":hide" was used
- bool keepalt; ///< true when ":keepalt" was used
- bool keepjumps; ///< true when ":keepjumps" was used
- bool keepmarks; ///< true when ":keepmarks" was used
- bool keeppatterns; ///< true when ":keeppatterns" was used
- bool lockmarks; ///< true when ":lockmarks" was used
- bool noswapfile; ///< true when ":noswapfile" was used
- char_u *save_ei; ///< saved value of 'eventignore'
+ int split; ///< flags for win_split()
+ int tab; ///< > 0 when ":tab" was used
+ bool browse; ///< true to invoke file dialog
+ bool confirm; ///< true to invoke yes/no dialog
+ bool hide; ///< true when ":hide" was used
+ bool keepalt; ///< true when ":keepalt" was used
+ bool keepjumps; ///< true when ":keepjumps" was used
+ bool keepmarks; ///< true when ":keepmarks" was used
+ bool keeppatterns; ///< true when ":keeppatterns" was used
+ bool lockmarks; ///< true when ":lockmarks" was used
+ bool noswapfile; ///< true when ":noswapfile" was used
+ char_u *save_ei; ///< saved value of 'eventignore'
+ regmatch_T filter_regmatch; ///< set by :filter /pat/
+ bool filter_force; ///< set for :filter!
} cmdmod_T;
#endif // NVIM_EX_CMDS_DEFS_H
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 7568d71ac0..72b2e0f29b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1350,6 +1350,31 @@ static char_u * do_one_cmd(char_u **cmdlinep,
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, &reg_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))
@@ -1452,6 +1477,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
break;
}
+ char_u *after_modifier = ea.cmd;
ea.skip = did_emsg || got_int || did_throw || (cstack->cs_idx >= 0
&& !(cstack->cs_flags[cstack->
@@ -1734,7 +1760,13 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (!ea.skip) {
STRCPY(IObuff, _("E492: Not an editor command"));
if (!(flags & DOCMD_VERBOSE)) {
- append_command(*cmdlinep);
+ // If the modifier was parsed OK the error must be in the following
+ // command
+ if (after_modifier != NULL) {
+ append_command(after_modifier);
+ } else {
+ append_command(*cmdlinep);
+ }
}
errormsg = IObuff;
did_emsg_syntax = TRUE;
@@ -2104,6 +2136,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
case CMD_echomsg:
case CMD_echon:
case CMD_execute:
+ case CMD_filter:
case CMD_help:
case CMD_hide:
case CMD_ijump:
@@ -2255,6 +2288,10 @@ doend:
free_string_option(cmdmod.save_ei);
}
+ if (cmdmod.filter_regmatch.regprog != NULL) {
+ vim_regfree(cmdmod.filter_regmatch.regprog);
+ }
+
cmdmod = save_cmdmod;
if (save_msg_silent != -1) {
@@ -2540,28 +2577,29 @@ static struct cmdmod {
int minlen;
int has_count; /* :123verbose :3tab */
} cmdmods[] = {
- {"aboveleft", 3, FALSE},
- {"belowright", 3, FALSE},
- {"botright", 2, FALSE},
- {"browse", 3, FALSE},
- {"confirm", 4, FALSE},
- {"hide", 3, FALSE},
- {"keepalt", 5, FALSE},
- {"keepjumps", 5, FALSE},
- {"keepmarks", 3, FALSE},
- {"keeppatterns", 5, FALSE},
- {"leftabove", 5, FALSE},
- {"lockmarks", 3, FALSE},
- {"noautocmd", 3, FALSE},
- {"noswapfile", 3, FALSE},
- {"rightbelow", 6, FALSE},
- {"sandbox", 3, FALSE},
- {"silent", 3, FALSE},
- {"tab", 3, TRUE},
- {"topleft", 2, FALSE},
- {"unsilent", 3, FALSE},
- {"verbose", 4, TRUE},
- {"vertical", 4, FALSE},
+ { "aboveleft", 3, false },
+ { "belowright", 3, false },
+ { "botright", 2, false },
+ { "browse", 3, false },
+ { "confirm", 4, false },
+ { "filter", 4, false },
+ { "hide", 3, false },
+ { "keepalt", 5, false },
+ { "keepjumps", 5, false },
+ { "keepmarks", 3, false },
+ { "keeppatterns", 5, false },
+ { "leftabove", 5, false },
+ { "lockmarks", 3, false },
+ { "noautocmd", 3, false },
+ { "noswapfile", 3, false },
+ { "rightbelow", 6, false },
+ { "sandbox", 3, false },
+ { "silent", 3, false },
+ { "tab", 3, true },
+ { "topleft", 2, false },
+ { "unsilent", 3, false },
+ { "verbose", 4, true },
+ { "vertical", 4, false },
};
/*
@@ -3031,6 +3069,16 @@ const char * set_one_cmd_context(
case CMD_windo:
return arg;
+ case CMD_filter:
+ if (*arg != NUL) {
+ arg = (const char *)skip_vimgrep_pat((char_u *)arg, NULL, NULL);
+ }
+ if (arg == NULL || *arg == NUL) {
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+ }
+ return (const char *)skipwhite((const char_u *)arg);
+
case CMD_match:
if (*arg == NUL || !ends_excmd(*arg)) {
/* also complete "None" */
@@ -4851,9 +4899,12 @@ static void uc_list(char_u *name, size_t name_len)
cmd = USER_CMD_GA(gap, i);
a = cmd->uc_argt;
- /* Skip commands which don't match the requested prefix */
- if (STRNCMP(name, cmd->uc_name, name_len) != 0)
+ // Skip commands which don't match the requested prefix and
+ // commands filtered out.
+ if (STRNCMP(name, cmd->uc_name, name_len) != 0
+ || message_filtered(cmd->uc_name)) {
continue;
+ }
/* Put out the title first time */
if (!found)
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 9d32df5a68..6e21ee96e8 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1592,7 +1592,7 @@ vungetc ( /* unget one character (can only be done once!) */
/// This may do a blocking wait if "advance" is TRUE.
///
/// if "advance" is TRUE (vgetc()):
-/// really get the character.
+/// Really get the character.
/// KeyTyped is set to TRUE in the case the user typed the key.
/// KeyStuffed is TRUE if the character comes from the stuff buffer.
/// if "advance" is FALSE (vpeekc()):
@@ -3168,6 +3168,10 @@ showmap (
{
size_t len = 1;
+ if (message_filtered(mp->m_keys) && message_filtered(mp->m_str)) {
+ return;
+ }
+
if (msg_didout || msg_silent != 0) {
msg_putchar('\n');
if (got_int) /* 'q' typed at MORE prompt */
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 696855e3aa..057ce75f79 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -31,6 +31,7 @@
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/normal.h"
+#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
@@ -148,6 +149,12 @@ msg_attr_keep (
int retval;
char_u *buf = NULL;
+ // Skip messages not match ":filter pattern".
+ // Don't filter when there is an error.
+ if (!emsg_on_display && message_filtered(s)) {
+ return true;
+ }
+
if (attr == 0) {
set_vim_var_string(VV_STATUSMSG, (char *) s, -1);
}
@@ -1783,6 +1790,18 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
msg_check();
}
+/// Return true when ":filter pattern" was used and "msg" does not match
+/// "pattern".
+bool message_filtered(char_u *msg)
+{
+ if (cmdmod.filter_regmatch.regprog == NULL) {
+ return false;
+ }
+
+ bool match = vim_regexec(&cmdmod.filter_regmatch, msg, (colnr_T)0);
+ return cmdmod.filter_force ? match : !match;
+}
+
/*
* Scroll the screen up one line for displaying the next message line.
*/
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 112498ae20..0ec0d5df9d 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3766,52 +3766,6 @@ theend:
}
/*
- * Skip over the pattern argument of ":vimgrep /pat/[g][j]".
- * Put the start of the pattern in "*s", unless "s" is NULL.
- * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP.
- * If "s" is not NULL terminate the pattern with a NUL.
- * Return a pointer to the char just past the pattern plus flags.
- */
-char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
-{
- int c;
-
- if (vim_isIDc(*p)) {
- /* ":vimgrep pattern fname" */
- if (s != NULL)
- *s = p;
- p = skiptowhite(p);
- if (s != NULL && *p != NUL)
- *p++ = NUL;
- } else {
- /* ":vimgrep /pattern/[g][j] fname" */
- if (s != NULL)
- *s = p + 1;
- c = *p;
- p = skip_regexp(p + 1, c, TRUE, NULL);
- if (*p != c)
- return NULL;
-
- /* Truncate the pattern. */
- if (s != NULL)
- *p = NUL;
- ++p;
-
- /* Find the flags */
- while (*p == 'g' || *p == 'j') {
- if (flags != NULL) {
- if (*p == 'g')
- *flags |= VGR_GLOBAL;
- else
- *flags |= VGR_NOJUMP;
- }
- ++p;
- }
- }
- return p;
-}
-
-/*
* Restore current working directory to "dirname_start" if they differ, taking
* into account whether it is set locally or globally.
*/
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 1cf7ab475c..140b67a1a5 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -72,6 +72,7 @@ let v:testing = 1
set directory^=.
set backspace=
set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
+set listchars=eol:$
" Prevent Nvim log from writing to stderr.
let $NVIM_LOG_FILE='Xnvim.log'
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 99d9835996..5da9a8b0f4 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -8,6 +8,7 @@ source test_ex_undo.vim
source test_expr.vim
source test_expr_utf8.vim
source test_feedkeys.vim
+source test_filter_cmd.vim
source test_filter_map.vim
source test_goto.vim
source test_jumps.vim
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
new file mode 100644
index 0000000000..5aa5fa64df
--- /dev/null
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -0,0 +1,76 @@
+" Test the :filter command modifier
+
+func Test_filter()
+ edit Xdoesnotmatch
+ edit Xwillmatch
+ call assert_equal('"Xwillmatch"', substitute(execute('filter willma ls'), '[^"]*\(".*"\)[^"]*', '\1', ''))
+ bwipe Xdoesnotmatch
+ bwipe Xwillmatch
+
+ new
+ call setline(1, ['foo1', 'foo2', 'foo3', 'foo4', 'foo5'])
+ call assert_equal("\nfoo2\nfoo4", execute('filter /foo[24]/ 1,$print'))
+ call assert_equal("\n 2 foo2\n 4 foo4", execute('filter /foo[24]/ 1,$number'))
+ call assert_equal("\nfoo2$\nfoo4$", execute('filter /foo[24]/ 1,$list'))
+
+ call assert_equal("\nfoo1$\nfoo3$\nfoo5$", execute('filter! /foo[24]/ 1,$list'))
+ bwipe!
+
+ command XTryThis echo 'this'
+ command XTryThat echo 'that'
+ command XDoThat echo 'that'
+ let lines = split(execute('filter XTry command'), "\n")
+ call assert_equal(3, len(lines))
+ call assert_match("XTryThat", lines[1])
+ call assert_match("XTryThis", lines[2])
+ delcommand XTryThis
+ delcommand XTryThat
+ delcommand XDoThat
+
+ map f1 the first key
+ map f2 the second key
+ map f3 not a key
+ let lines = split(execute('filter the map f'), "\n")
+ call assert_equal(2, len(lines))
+ call assert_match("f2", lines[0])
+ call assert_match("f1", lines[1])
+ unmap f1
+ unmap f2
+ unmap f3
+endfunc
+
+func Test_filter_fails()
+ call assert_fails('filter', 'E471:')
+ call assert_fails('filter pat', 'E476:')
+ call assert_fails('filter /pat', 'E476:')
+ call assert_fails('filter /pat/', 'E476:')
+ call assert_fails('filter /pat/ asdf', 'E492:')
+
+ call assert_fails('filter!', 'E471:')
+ call assert_fails('filter! pat', 'E476:')
+ call assert_fails('filter! /pat', 'E476:')
+ call assert_fails('filter! /pat/', 'E476:')
+ call assert_fails('filter! /pat/ asdf', 'E492:')
+endfunc
+
+function s:complete_filter_cmd(filtcmd)
+ let keystroke = "\<TAB>\<C-R>=execute('let cmdline = getcmdline()')\<CR>\<C-C>"
+ let cmdline = ''
+ call feedkeys(':' . a:filtcmd . keystroke, 'ntx')
+ return cmdline
+endfunction
+
+func Test_filter_cmd_completion()
+ " Do not complete pattern
+ call assert_equal("filter \t", s:complete_filter_cmd('filter '))
+ call assert_equal("filter pat\t", s:complete_filter_cmd('filter pat'))
+ call assert_equal("filter /pat\t", s:complete_filter_cmd('filter /pat'))
+ call assert_equal("filter /pat/\t", s:complete_filter_cmd('filter /pat/'))
+
+ " Complete after string pattern
+ call assert_equal('filter pat print', s:complete_filter_cmd('filter pat pri'))
+
+ " Complete after regexp pattern
+ call assert_equal('filter /pat/ print', s:complete_filter_cmd('filter /pat/ pri'))
+ call assert_equal('filter #pat# print', s:complete_filter_cmd('filter #pat# pri'))
+endfunc
diff --git a/src/nvim/version.c b/src/nvim/version.c
index b1aa8e2a4b..b579cdef12 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -181,7 +181,7 @@ static const int included_patches[] = {
2266,
2265,
2264,
- // 2263,
+ 2263,
// 2262 NA
// 2261 NA
// 2260 NA
@@ -198,14 +198,14 @@ static const int included_patches[] = {
2249,
2248,
// 2247 NA
- // 2246,
- // 2245,
- // 2244,
+ 2246,
+ 2245,
+ 2244,
// 2243 NA
2242,
2241,
2240,
- // 2239,
+ 2239,
// 2238 NA
2237,
2236,
@@ -213,7 +213,7 @@ static const int included_patches[] = {
// 2234 NA
2233,
// 2232 NA
- // 2231,
+ 2231,
2230,
// 2229,
2228,
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 656b3f9bae..4002855c24 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -4,13 +4,15 @@ local helpers = require('test.functional.helpers')(after_each)
local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command
local feed, nvim_prog, wait = helpers.feed, helpers.nvim_prog, helpers.wait
local ok, set_session, spawn = helpers.ok, helpers.set_session, helpers.spawn
+local eval = helpers.eval
-local shada_file = 'test.shada'
+local shada_file = 'Xtest.shada'
local function _clear()
- set_session(spawn({nvim_prog, '--embed', '-u', 'NONE', '--cmd',
+ set_session(spawn({nvim_prog, '--embed', '-u', 'NONE',
-- Need shada for these tests.
- 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}))
+ '-i', shada_file,
+ '--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}))
end
describe(':oldfiles', function()
@@ -29,8 +31,8 @@ describe(':oldfiles', function()
screen:attach()
feed_command('edit testfile1')
feed_command('edit testfile2')
- feed_command('wshada ' .. shada_file)
- feed_command('rshada! ' .. shada_file)
+ feed_command('wshada')
+ feed_command('rshada!')
local oldfiles = helpers.meths.get_vvar('oldfiles')
feed_command('oldfiles')
screen:expect([[
@@ -41,6 +43,38 @@ describe(':oldfiles', function()
Press ENTER or type command to continue^ |
]])
end)
+
+ it('can be filtered with :filter', function()
+ feed_command('edit file_one.txt')
+ local file1 = buf.get_name()
+ feed_command('edit file_two.txt')
+ local file2 = buf.get_name()
+ feed_command('edit another.txt')
+ local another = buf.get_name()
+ feed_command('wshada')
+ feed_command('rshada!')
+
+ local function get_oldfiles(cmd)
+ local t = eval([[split(execute(']]..cmd..[['), "\n")]])
+ for i, _ in ipairs(t) do
+ t[i] = t[i]:gsub('^%d+:%s+', '')
+ end
+ table.sort(t)
+ return t
+ end
+
+ local oldfiles = get_oldfiles('oldfiles')
+ eq({another, file1, file2}, oldfiles)
+
+ oldfiles = get_oldfiles('filter file_ oldfiles')
+ eq({file1, file2}, oldfiles)
+
+ oldfiles = get_oldfiles('filter /another/ oldfiles')
+ eq({another}, oldfiles)
+
+ oldfiles = get_oldfiles('filter! file_ oldfiles')
+ eq({another}, oldfiles)
+ end)
end)
describe(':browse oldfiles', function()
@@ -54,10 +88,9 @@ describe(':browse oldfiles', function()
filename = buf.get_name()
feed_command('edit testfile2')
filename2 = buf.get_name()
- feed_command('wshada ' .. shada_file)
+ feed_command('wshada')
wait()
_clear()
- feed_command('rshada! ' .. shada_file)
-- Ensure nvim is out of "Press ENTER..." prompt.
feed('<cr>')