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.

+3


source to share


2 answers


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

      

+3


source


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.



gif in action

If anyone can improve on this (especially the sign bit), edit it as you see fit.

+2


source