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:
parent
6b1da3312e
commit
f84b122a99
@ -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
|
||||||
|
@ -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,46 +6008,58 @@ ex_global(exarg_T *eap)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (global_busy)
|
||||||
* pass 1: set marks for each (not) matching line
|
|
||||||
*/
|
|
||||||
for (lnum = eap->line1; lnum <= eap->line2 && !got_int; ++lnum)
|
|
||||||
{
|
{
|
||||||
/* a match on this line? */
|
lnum = curwin->w_cursor.lnum;
|
||||||
match = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
match = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
||||||
(colnr_T)0, NULL);
|
(colnr_T)0, NULL);
|
||||||
if ((type == 'g' && match) || (type == 'v' && !match))
|
if ((type == 'g' && match) || (type == 'v' && !match))
|
||||||
{
|
global_exe_one(cmd, lnum);
|
||||||
ml_setmarked(lnum);
|
|
||||||
ndone++;
|
|
||||||
}
|
|
||||||
line_breakcheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pass 2: execute the command for each line that has been marked
|
|
||||||
*/
|
|
||||||
if (got_int)
|
|
||||||
MSG(_(e_interr));
|
|
||||||
else if (ndone == 0)
|
|
||||||
{
|
|
||||||
if (type == 'v')
|
|
||||||
smsg((char_u *)_("Pattern found in every line: %s"), pat);
|
|
||||||
else
|
|
||||||
smsg((char_u *)_("Pattern not found: %s"), pat);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* pass 1: set marks for each (not) matching line
|
||||||
|
*/
|
||||||
|
for (lnum = eap->line1; lnum <= eap->line2 && !got_int; ++lnum)
|
||||||
|
{
|
||||||
|
/* a match on this line? */
|
||||||
|
match = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
||||||
|
(colnr_T)0, NULL);
|
||||||
|
if ((type == 'g' && match) || (type == 'v' && !match))
|
||||||
|
{
|
||||||
|
ml_setmarked(lnum);
|
||||||
|
ndone++;
|
||||||
|
}
|
||||||
|
line_breakcheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pass 2: execute the command for each line that has been marked
|
||||||
|
*/
|
||||||
|
if (got_int)
|
||||||
|
MSG(_(e_interr));
|
||||||
|
else if (ndone == 0)
|
||||||
|
{
|
||||||
|
if (type == 'v')
|
||||||
|
smsg((char_u *)_("Pattern found in every line: %s"), pat);
|
||||||
|
else
|
||||||
|
smsg((char_u *)_("Pattern not found: %s"), pat);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#ifdef FEAT_CLIPBOARD
|
#ifdef FEAT_CLIPBOARD
|
||||||
start_global_changes();
|
start_global_changes();
|
||||||
#endif
|
#endif
|
||||||
global_exe(cmd);
|
global_exe(cmd);
|
||||||
#ifdef FEAT_CLIPBOARD
|
#ifdef FEAT_CLIPBOARD
|
||||||
end_global_changes();
|
end_global_changes();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user