How do I make the vim `: global` command asserted before executing the ex command?
How do I make the vim command :global
ask the user if they want to execute the ex command? Similar to what happens with a command :substite
with the 'c' option, for example%s:Foo:Fighters:gc
I tried:
:g/mypattern/.s:.*\n::gc
and
:g/mypattern/s:.*\n::gc
but if there is a match on the line below, it bounces. For example:
MATCH
NONMATCH
MATCH
MATCH
MATCH
Result:
NONMATCH
MATCH <<-- this should be erased.
The prompted g/FOO/d
will be perfect.
source to share
There is no native way to do this. The typical method would be to record a macro and repeat the macro. Make sure you are n
or /
at the end of the macro to go to the next match. Skipping now simply n
and @@
to execute the macro.
Custom command :Global
However, if you really want to have a command :Global
with acknowledgment, you can emulate that by using confirm()
within your command. The general idea is to do something like this:
:g/pat/if confirm("&yes\n&no", 2) == 1 | cmd | endif
This does not work for the following reasons:
- You don't know where your cursor is. You need something like
:match
and:redraw
- Doesn't stop. Need a way to throw an exception to cancel
- It is very inconvenient to type all this.
I got the following confirmation command :Global
/:G
command! -nargs=+ -range=% -complete=command Global <line1>,<line2>call <SID>global_confirm(<q-args>)
command! -nargs=+ -range=% -complete=command G <line1>,<line2>call <SID>global_confirm(<q-args>)
function! s:global_confirm(args) range
let args = a:args
let sep = args[0]
let [pat, cmd; _] = split(args[1:], '\v([^\\](\\\\)*\\)@<!%d' . char2nr(sep), 1) + ['', '']
match none
let options = ['throw "Global: Abort"', cmd, '', 'throw "Global: Abort"']
let cmd = 'exe ''match IncSearch /\c\%''.line(''.'').''l''.@/.''/'''
let cmd .= '| redraw'
let cmd .= '| exe get(options, confirm("Execute?", "&yes\n&no\n&abort", 2))'
try
execute a:firstline . ',' . a:lastline . 'g'.sep.pat.sep.cmd
catch /Global: Abort/
finally
match none
endtry
endfunction
Note. Use it as is. Uses IncSearch
for emphasis and strength \c
.
Now you can run :G/foo/d
.
Custom command :Confirm
If you'd rather use a similar technique to what @Randy Morris provided and use the following command :Confirm {cmd}
to confirm {cmd}
before executing.
command! -nargs=+ -complete=command Confirm execute <SID>confirm(<q-args>) | match none
function! s:confirm(cmd)
let abort = 'match none | throw "Confirm: Abort"'
let options = [abort, a:cmd, '', abort]
match none
execute 'match IncSearch /\c\%' . line('.') . 'l' . @/ . '/'
redraw
return get(options, confirm('Execute?', "&yes\n&no\n&abort", 2), abort)
endfunction
This will allow you to use :g/foo/Confirm d
For more help see:
:h @
:h q
:h confirm()
:h :exe
:h get()
:h :match
:h :redraw
source to share
As far as I know, there is no way to do this natively. I think I hacked a way to do this, but it was probably wrong as I haven't written vimscript in a long time. In this I have defined a command C
that takes the ex command as its arguments. Each line returned through :global
is then passed to this ex command if you press yor y. Any other key causes this line to be skipped.
let s:GlobalConfirmSignNumber = 42
sign define GlobalConfirmMarker text=>> texthl=Search
function GlobalConfirm(cmd)
let line = getpos(".")[1]
execute "sign place " . s:GlobalConfirmSignNumber . " line=" . line . " name=GlobalConfirmMarker file=" . expand("%:p")
redraw!
echomsg "Execute? (y/N) "
try
let char = nr2char(getchar())
if (char == "y" || char == "Y")
execute a:cmd
endif
finally
" Ensure signs are cleaned up if execution is aborted.
execute "sign unplace " . s:GlobalConfirmSignNumber
endtry
redraw!
endfunction
command -nargs=* C call GlobalConfirm(<q-args>)
Here's a gif of it in action. In this gif, I am running a command norm! gUU
for each line containing ba
. In this case, I confirmed each match by clicking ythree times.
If anyone can improve on this (especially the sign bit), edit it as you see fit.
source to share