1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
--[[ 50-autoreload.lua — handle files changed outside Neovim, with opt-in silent reload.
Every loaded buffer is re-stat'd on focus, so an external change surfaces Neovim's usual reload prompt.
A buffer flagged for autoreload is instead reloaded silently on that change, and is re-stat'd on idle /
buffer-enter too so the reload doesn't wait for a focus change. Conflicts (the buffer was also edited
in Neovim) and deletions always defer to the prompt. Autoreload is off by default and per-buffer: the
state lives in `vim.b.autoreload` and shows as the `+R` flag in the statusline (see 50-color.lua).
`autoread` is off so the prompt fires even for unmodified buffers, and the autocmds run `checktime`
explicitly because FocusGained does not trigger FileChangedShell on its own.
User commands:
`AutoreloadToggle`: toggle disk-change autoreload for the current buffer
]]
vim.opt.autoread = false
-- `checktime` is invalid in the command-line window (`q:`/`q/`), which still fires our autocmds (see
-- <nvim-help://E11>).
local function in_cmdwin()
return vim.fn.getcmdwintype() ~= ""
end
-- Re-stat every loaded buffer in one pass; the FileChangedShell handler below decides per buffer.
local function check_all_buffers()
if not in_cmdwin() then
vim.cmd.checktime() -- no argument → all loaded buffers at once
end
end
-- Re-stat only the autoreload-flagged buffers, so an unflagged-but-changed buffer gets no surprise
-- prompt at idle. `checktime {buf}` keeps each check scoped to its buffer.
local function check_flagged_buffers()
if in_cmdwin() then
return
end
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_loaded(buf) and vim.b[buf].autoreload then
vim.cmd.checktime(buf)
end
end
end
-- `nested` so the checktime calls fire the FileChangedShell handler below; without it Neovim
-- suppresses the triggered event and falls back to its default prompt. Focus re-stats every buffer
-- (the baseline prompt-on-change); the idle / buffer-enter events re-stat only flagged buffers.
vim.api.nvim_create_autocmd("FocusGained", {
group = vim.g.dotfiles.augroup,
nested = true,
callback = check_all_buffers,
})
vim.api.nvim_create_autocmd({ "BufEnter", "CursorHold", "CursorHoldI", "TermLeave" }, {
group = vim.g.dotfiles.augroup,
nested = true,
callback = check_flagged_buffers,
})
--[[ Decide what happens when Neovim notices a file changed under it. When the affected buffer has
autoreload on, a plain on-disk change reloads it with no prompt; otherwise a change or conflict falls
back to `ask` and any other reason (deletion, …) to Neovim's default handling.
See <nvim-help://v:fcs_choice>. ]]
vim.api.nvim_create_autocmd("FileChangedShell", {
group = vim.g.dotfiles.augroup,
pattern = "*",
callback = function(args)
if vim.b[args.buf].autoreload and vim.v.fcs_reason == "changed" then
vim.v.fcs_choice = "reload"
elseif vim.v.fcs_reason == "changed" or vim.v.fcs_reason == "conflict" then
vim.v.fcs_choice = "ask"
end
end,
})
-- Flip autoreload for the current buffer; check immediately when turning it on so pending changes
-- catch up.
local function toggle_autoreload()
vim.b.autoreload = not vim.b.autoreload
vim.notify(
"Buffer autoreload " .. (vim.b.autoreload and "enabled" or "disabled") .. " for this buffer"
)
check_flagged_buffers()
vim.cmd.redrawstatus()
end
vim.api.nvim_create_user_command(
"AutoreloadToggle",
toggle_autoreload,
{ desc = "Toggle buffer autoreload" }
)
|