How do I set up Vim to achieve the effect in the title?
1 Answer
Your question is pretty light on the details but I was in the mood for some vimscripting so this is my interpretation...
" How many minutes to unblock writes
let g:allowwritemins = 5
func! CheckWriteBlock(bufname)
if !exists("b:blockwrite")
let b:blockwrite = 1
endif
if !b:blockwrite
" Not currently blocked. Write the file and unset modified flag
w
set nomodified
return
endif
if input(printf("Warning: Writes are blocked. Enable writes for the next %d minutes? ", g:allowwritemins)) =~? "y"
let b:blockwrite = 0
" This will start a timer for configured number of minutes
" after which blockwrite flag will be reset.
call timer_start(g:allowwritemins * 60 * 1000, {-> setbufvar(a:bufname, "blockwrite", 1)})
redraw
echom "You may write the file now."
endif
endfunc
augroup writeblock
autocmd!
" BufWriteCmd is called before the write and requires the coder to
" do the write themselves if that's what they want.
autocmd BufWriteCmd * call CheckWriteBlock(bufname())
augroup END
Put all of that in your vimrc and for each file that you try to write it will block and ask you if you want to unblock writes. If you enter Y (case insensitive; followed by Enter) then for the configured number of minutes you can then do :w
.
Update: OP asked about using this only on designated buffers rather than any and all buffers. My suggestion was to repurpose b:blockwrite
as a user-controlled flag. It is not defined by default and manually set to 1 for buffers to be protected. That would require just a few changes to the function. The first conditional block is removed and the second conditional is modified. That gives us...
func! CheckWriteBlock(bufname)
" Flag not defined or it's disabled (equal to 0)
if !exists("b:blockwrite") || !b:blockwrite
" Write the file and unset modified flag
w
set nomodified
return
endif
" Last block remains the same so
...snip...
endfunc
I'd also create a convenience mapping for toggling the flag, e.g. ...
nnoremap <leader>b :let b:blockwrite = exists("b:blockwrite") ? !b:blockwrite : 1<cr>
-
Hm, is the timer callback guaranteed to execute in the buffer from which it was created? If I switch buffers before it runs, I have a feeling it will set the wrong buffer’s variable. I wonder if it would be simpler too just to toggle the readonly or modifiable flags (editable vs writable)?– D. Ben Knoble ♦Commented Aug 21, 2021 at 2:03
-
I was aware of that already and knew what to do but wanted to hear if this was even on the right track as far as what OP wants. But since you made it public I fixed it.– B LayerCommented Aug 21, 2021 at 3:33
-
@B Layer, this is exactly the functionality I was looking for. Ty. Only tweaked one thing, bufname() requires an empty string to reference the current buffer, i.e. bufname(''). stackoverflow.com/a/13706784/7503825. Commented Aug 21, 2021 at 6:59
-
@CharlesKong Glad I guessed right. :) FYI,
:h bufname()
says "if {buf} is omitted the current buffer is used" and I verified thatbufname()
does indeed work. If that doesn't work for you maybe you're using an older version of Vim...?– B LayerCommented Aug 21, 2021 at 8:23 -
I see. Strange to see the docs and user experience contradicting. I've got Vim 8.1. BTW if I wanted to apply your func on manually selected files and not all files (still using the event hook), what should I look into in the docs? I'm not looking to persist this list between Vim instances (i.e. neither concurrently running processes nor over time via :mksession). Commented Aug 21, 2021 at 8:58
readonly
andmodifiable
options