0

I'm wrapping a command line script in a function and then in a command, which supplies this script with 2 arguments:

nnoremap <leader>G :BxSedRi 'src/', 's/\<<C-r><C-w>\>
    fun! BxSedRi(Dir,Arg)
        :if len(getbufinfo({'bufmodified': 1}))
            :throw "Must not have modified buffers"
        :endif
        :execute ":silent! !sed_Ri@bx" shellescape(a:Dir) shellescape(a:Arg)
        :bufdo! e!
        :redraw!
    endfun
    command! -nargs=+ BxSedRi call BxSedRi(<args>)

After the script, I was hoping for :bufdo! e! and :redraw! to silently reload all my buffers as the underlying files might have been changed by the script.

However, I am still getting these prompts:

W11: Warning: File "..." has changed since editing started                                                                                                                                │
See ":help W11" for more info.                                                                                                                                                                                 │
[O]K, (L)oad File: 

How can I get rid them and just reload all buffers silently?

2
  • 1
    Question: is your function running a sed in-place edit on all files in a dir? With a substitute? What if I told you there was a vim-native way to do something very similar? – D. Ben Knoble Mar 29 at 12:45
  • Yes. Recursively on the given directory and with some laziness so that files that wouldn't change aren't touched. I'd be happy to learn how to also do it the vim way, of course! ;-) – PSkocik Mar 29 at 13:23
1

Here's two vim versions of the "recursive, lazy, sed substitute" that the function is performing.

Both involve the same technique: filling one of vim's special lists and then calling the corresponding do command.

Using the arglist

The arglist can be filled with files and traversed with :next, :prev, and a few other commands. Conveniently, we can run commands on all files in it with :argdo.

In order to avoid messing with the global arglist, we'll open a new window and use :arglocal:

:new
:arglocal …

What to but in the depends, but in this case let's grab all files under src (this can be a bit slow on large directories):

:arglocal src/**/*

(Unfortunately, this also finds directories; if you're interested in, say, .c files, you can add the extension and get better matches. Otherwise, you need something like :arglocal `find src -type f` on a *nix.)

Now substitute in :argdo, with /e for ignoring files with no match and :update to lazily write the changed files (don't forget /g if you need it):

:argdo %substitute/…/…/e | update

You can wrap it up in a function, if you want (have a look at <f-args>, too).

Using the quickfix list.

Same idea, but more targeted.

In this case, we'll populate the quickfix list with :vimgrep or :grep (your choice; I use ripgrep, so while I use :vimgrep for searching buffers already in vim, I prefer :grep for general code searches).

:vimgrep /…/ src/**/*
" or, e.g.,
:grep -R … src

Now we can traverse all the entries with :cdo or all the files with :cfdo (optionally, filter the entries with :help cfilter-plugin first):

:cdo substitute/…/…/ | update

We don't need /e this time because :substitute will only be run on lines already matching the pattern; similarly, we don't need /g because all matching lines will be there.

Note that if you used :vimgrep and the pattern for the search and substitute are the same, you can write

:cdo substitute//…/ | update

Both solutions avoid modifying files outside of vim, so you don't run into checktime/edit issues.

0

Looks like instead of :bufdo! e! (which also caused buffer highlighting to disappear: Syntax highlighting is gone after :bufdo :e) I needed to do :bufdo! checktime with the autoread option locally disabled:

    :let ar = &autoread
    :set autoread
    :bufdo! checktime
    :redraw!
    :let &autoread=&ar

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.