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 VIM REFERENCE MANUAL by Bram Moolenaar
@ -46,7 +46,7 @@ of area is used, see |visual-repeat|.
============================================================================== ==============================================================================
2. Multiple repeats *multi-repeat* 2. Multiple repeats *multi-repeat*
*:g* *:global* *E147* *E148* *:g* *:global* *E148*
:[range]g[lobal]/{pattern}/[cmd] :[range]g[lobal]/{pattern}/[cmd]
Execute the Ex command [cmd] (default ":p") on the Execute the Ex command [cmd] (default ":p") on the
lines within [range] where {pattern} matches. 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 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 line is aborted and the global command continues with the next marked or
unmarked line. 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} :g/pat/normal {commands}
Make sure that {commands} ends with a whole command, otherwise Vim will wait 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 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; 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: * Execute a global command of the form:
* *
@ -5933,9 +5944,13 @@ ex_global(exarg_T *eap)
int match; int match;
int which_pat; 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; return;
} }
@ -5993,6 +6008,16 @@ ex_global(exarg_T *eap)
return; 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 * 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 */ ml_clearmarked(); /* clear rest of the marks */
}
vim_regfree(regmatch.regprog); vim_regfree(regmatch.regprog);
} }
@ -6063,12 +6090,7 @@ global_exe(char_u *cmd)
old_lcount = curbuf->b_ml.ml_line_count; old_lcount = curbuf->b_ml.ml_line_count;
while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1) while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1)
{ {
curwin->w_cursor.lnum = lnum; global_exe_one(cmd, 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);
ui_breakcheck(); ui_breakcheck();
} }
@ -8514,4 +8536,3 @@ ex_oldfiles(exarg_T *eap UNUSED)
} }
} }
#endif #endif

View File

@ -9,3 +9,12 @@ func Test_yank_put_clipboard()
set clipboard& set clipboard&
bwipe! bwipe!
endfunc 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[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
630,
/**/ /**/
629, 629,
/**/ /**/