1
0
forked from aniani/vim

patch 8.0.0630: it is not easy to work on lines without a match

Problem:    The :global command does not work recursively, which makes it
            difficult to execute a command on a line where one pattern matches
            and another does not match. (Miles Cranmer)
Solution:   Allow for recursion if it is for only one line. (closes #1760)
This commit is contained in:
Bram Moolenaar 2017-06-10 14:29:52 +02:00
parent 6b1da3312e
commit f84b122a99
4 changed files with 79 additions and 40 deletions

View File

@ -1,4 +1,4 @@
*repeat.txt* For Vim version 8.0. Last change: 2017 Feb 06
*repeat.txt* For Vim version 8.0. Last change: 2017 Jun 10
VIM REFERENCE MANUAL by Bram Moolenaar
@ -46,7 +46,7 @@ of area is used, see |visual-repeat|.
==============================================================================
2. Multiple repeats *multi-repeat*
*:g* *:global* *E147* *E148*
*:g* *:global* *E148*
:[range]g[lobal]/{pattern}/[cmd]
Execute the Ex command [cmd] (default ":p") on the
lines within [range] where {pattern} matches.
@ -79,8 +79,15 @@ The default for [range] is the whole buffer (1,$). Use "CTRL-C" to interrupt
the command. If an error message is given for a line, the command for that
line is aborted and the global command continues with the next marked or
unmarked line.
*E147*
When the command is used recursively, it only works on one line. Giving a
range is then not allowed. This is useful to find all lines that match a
pattern and do not match another pattern: >
:g/found/v/notfound/{cmd}
This first finds all lines containing "found", but only executes {cmd} when
there is no match for "notfound".
To repeat a non-Ex command, you can use the ":normal" command: >
To execute a non-Ex command, you can use the `:normal` command: >
:g/pat/normal {commands}
Make sure that {commands} ends with a whole command, otherwise Vim will wait
for you to type the rest of the command for each match. The screen will not

View File

@ -5903,6 +5903,17 @@ do_sub_msg(
return FALSE;
}
static void
global_exe_one(char_u *cmd, linenr_T lnum)
{
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = 0;
if (*cmd == NUL || *cmd == '\n')
do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT);
else
do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT);
}
/*
* Execute a global command of the form:
*
@ -5933,9 +5944,13 @@ ex_global(exarg_T *eap)
int match;
int which_pat;
if (global_busy)
/* When nesting the command works on one line. This allows for
* ":g/found/v/notfound/command". */
if (global_busy && (eap->line1 != 1
|| eap->line2 != curbuf->b_ml.ml_line_count))
{
EMSG(_("E147: Cannot do :global recursive")); /* will increment global_busy */
/* will increment global_busy to break out of the loop */
EMSG(_("E147: Cannot do :global recursive with a range"));
return;
}
@ -5993,6 +6008,16 @@ ex_global(exarg_T *eap)
return;
}
if (global_busy)
{
lnum = curwin->w_cursor.lnum;
match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL);
if ((type == 'g' && match) || (type == 'v' && !match))
global_exe_one(cmd, lnum);
}
else
{
/*
* pass 1: set marks for each (not) matching line
*/
@ -6033,6 +6058,8 @@ ex_global(exarg_T *eap)
}
ml_clearmarked(); /* clear rest of the marks */
}
vim_regfree(regmatch.regprog);
}
@ -6063,12 +6090,7 @@ global_exe(char_u *cmd)
old_lcount = curbuf->b_ml.ml_line_count;
while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1)
{
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = 0;
if (*cmd == NUL || *cmd == '\n')
do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT);
else
do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT);
global_exe_one(cmd, lnum);
ui_breakcheck();
}
@ -8514,4 +8536,3 @@ ex_oldfiles(exarg_T *eap UNUSED)
}
}
#endif

View File

@ -9,3 +9,12 @@ func Test_yank_put_clipboard()
set clipboard&
bwipe!
endfunc
func Test_nested_global()
new
call setline(1, ['nothing', 'found', 'found bad', 'bad'])
call assert_fails('g/found/3v/bad/s/^/++/', 'E147')
g/found/v/bad/s/^/++/
call assert_equal(['nothing', '++found', 'found bad', 'bad'], getline(1, 4))
bwipe!
endfunc

View File

@ -764,6 +764,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
630,
/**/
629,
/**/