1

Related to this thread, How can Vim tell me which buffer is changed on disk among multiple buffers?

This Vim configuration automatically checks for changes in opened buffers and notifies when a single file has been modified externally.

set autoread
autocmd FocusGained,BufEnter,CursorHold,CursorHoldI *
  \ if mode() !~ '\v(c|r.?|!|t)' && getcmdwintype() == '' | checktime | endif
autocmd FileChangedShellPost *
  \ echohl WarningMsg | echo "File " . expand('<afile>') . " changed on disk. Buffer reloaded." | echohl None

Desired Feature
When multiple files are changed externally, for example, with the tabs open for files A.cpp, B.cpp, C.cpp, and D.cpp.

If two files (A.cpp and C.cpp) are modified outside Vim, the notification should show: "File A.cpp C.cpp changed on disk. Buffer reloaded."

4
  • The FileChangedShellPost is triggered for each buffer so maybe instead of echoing the message directly you could add the filename to a global variable and then have a function which would be called periodically with a trigger. The function would check the content of the variable, create the message and echo it and empty the global variable.
    – statox
    Jul 15, 2021 at 12:37
  • I don't know much vimscript.. could you please make that function for me?
    – Mega Bang
    Jul 15, 2021 at 12:45
  • 1
    Right now I can't but that would be a good learning opportunity: Try to make your own function and if there is something in particular you have an issue with post it here :) There are a bunch of chapters here which should give you all the info you need to write your code
    – statox
    Jul 15, 2021 at 14:21
  • Couldn't find the solution.
    – Mega Bang
    Oct 10, 2023 at 5:16

1 Answer 1

1

I would do:

set autoread
autocmd FocusGained,BufEnter,CursorHold,CursorHoldI *
  \ if mode() !~ '\v(c|r.?|!|t)' && getcmdwintype() == '' | checktime | endif

let g:filechanged_timer = 0
let g:filechanged = ""

function! FileChangedCallback(timer)
  echohl WarningMsg
  echo "File " . g:filechanged . " changed on disk. Buffer reloaded."
  echohl None

  " Reset the timer and the list of files:
  let g:filechanged_timer = 0
  let g:filechanged = ""
endfunction

function! FileChanged(path)
  if g:filechanged_timer == 0
    " First change detected
    let g:filechanged = a:path
    " Wait 0.1 seconds for a new changes to come:
    let g:filechanged_timer = timer_start(100, 'FileChangedCallback')
  else
    " Some more change detected
    " Add the file path to the list:
    let g:filechanged = g:filechanged .. ', ' .. a:path
  endif
endfunction

autocmd! FileChangedShellPost * call FileChanged(expand('<afile>'))
1
  • 1
    I've tested this. And it works as expected. Maybe I'll get optimized code in the future.
    – Mega Bang
    Oct 10, 2023 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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