diff --git a/README.md b/README.md index 4bfe935..6edcfcc 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,11 @@ EOF dim = 0.18, -- dim the color of `message` cleaning_interval = 1250, -- (milliseconds) automatically clean MsgArea after displaying `message`. See :h MsgArea }, - trigger_events = {"InsertLeave", "TextChanged"}, -- vim events that trigger auto-save. See :h events + trigger_events = { -- See :h events + immediate_save = { "BufLeave", "FocusLost" }, -- vim events that trigger an immediate save + defer_save = { "InsertLeave", "TextChanged" }, -- vim events that trigger a deferred save (saves after `debounce_delay`) + cancel_defered_save = { "InsertEnter" }, -- vim events that cancel a pending deferred save + }, -- function that determines whether to save the current buffer or not -- return true: if buffer is ok to be saved -- return false: if it's not ok to be saved @@ -122,7 +126,7 @@ EOF return false -- can't save end, write_all_buffers = false, -- write all buffers when the current one meets `condition` - debounce_delay = 135, -- saves the file at most every `debounce_delay` milliseconds + debounce_delay = 1000, -- delay after which a pending save is executed callbacks = { -- functions to be executed at different intervals enabling = nil, -- ran when enabling auto-save disabling = nil, -- ran when disabling auto-save diff --git a/lua/auto-save/config.lua b/lua/auto-save/config.lua index bbfdbaf..94af8fe 100644 --- a/lua/auto-save/config.lua +++ b/lua/auto-save/config.lua @@ -9,7 +9,11 @@ Config = { dim = 0.18, -- dim the color of `message` cleaning_interval = 1250, -- (milliseconds) automatically clean MsgArea after displaying `message`. See :h MsgArea }, - trigger_events = { "InsertLeave", "TextChanged" }, -- vim events that trigger auto-save. See :h events + trigger_events = { -- See :h events + immediate_save = { "BufLeave", "FocusLost" }, -- vim events that trigger an immediate save + defer_save = { "InsertLeave", "TextChanged" }, -- vim events that trigger a deferred save (saves after `debounce_delay`) + cancel_defered_save = { "InsertEnter" }, -- vim events that cancel a pending deferred save + }, -- function that determines whether to save the current buffer or not -- return true: if buffer is ok to be saved -- return false: if it's not ok to be saved @@ -23,7 +27,7 @@ Config = { return false -- can't save end, write_all_buffers = false, -- write all buffers when the current one meets `condition` - debounce_delay = 135, -- saves the file at most every `debounce_delay` milliseconds + debounce_delay = 1000, -- delay after which a pending save is executed callbacks = { -- functions to be executed at different intervals enabling = nil, -- ran when enabling auto-save disabling = nil, -- ran when disabling auto-save diff --git a/lua/auto-save/init.lua b/lua/auto-save/init.lua index 1445fa7..2475dc6 100644 --- a/lua/auto-save/init.lua +++ b/lua/auto-save/init.lua @@ -18,38 +18,26 @@ api.nvim_create_augroup("AutoSave", { clear = true, }) -local global_vars = {} +local timers_by_buffer = {} -local function set_buf_var(buf, name, value) - if buf == nil then - global_vars[name] = value - else - if api.nvim_buf_is_valid(buf) then - api.nvim_buf_set_var(buf, "autosave_" .. name, value) - end +local function cancel_timer(buf) + local timer = timers_by_buffer[buf] + if timer ~= nil then + timer:close() + timers_by_buffer[buf] = nil end end -local function get_buf_var(buf, name) - if buf == nil then - return global_vars[name] - end - local success, mod = pcall(api.nvim_buf_get_var, buf, "autosave_" .. name) - return success and mod or nil -end - local function debounce(lfn, duration) - local function inner_debounce() - local buf = api.nvim_get_current_buf() - if not get_buf_var(buf, "queued") then - vim.defer_fn(function() - set_buf_var(buf, "queued", false) - lfn(buf) - end, duration) - set_buf_var(buf, "queued", true) - end + local function inner_debounce(buf) + -- instead of canceling the timer we could check if there is one already running for this buffer and restart it (`:again`) + cancel_timer(buf) + local timer = vim.defer_fn(function() + lfn(buf) + timers_by_buffer[buf] = nil + end, duration) + timers_by_buffer[buf] = timer end - return inner_debounce end @@ -64,9 +52,7 @@ local function echo_execution_message() end end -function M.save(buf) - buf = buf or api.nvim_get_current_buf() - +local function save(buf) callback("before_asserting_save") if cnf.opts.condition(buf) == false then @@ -79,6 +65,8 @@ function M.save(buf) callback("before_saving") + -- why is this needed? auto_save_abort is never set to true? + -- TODO: remove? if g.auto_save_abort == true then return end @@ -98,23 +86,48 @@ function M.save(buf) end end -local save_func = nil +function M.immediate_save(buf) + buf = buf or api.nvim_get_current_buf() + cancel_timer(buf) + save(buf) +end -local function perform_save() + +local save_func = nil +local function defer_save(buf) + -- why is this needed? auto_save_abort is never set to true anyways? + -- TODO: remove? g.auto_save_abort = false + + -- is it really needed to cache this function + -- TODO: remove? if save_func == nil then - save_func = (cnf.opts.debounce_delay > 0 and debounce(M.save, cnf.opts.debounce_delay) or M.save) + save_func = (cnf.opts.debounce_delay > 0 and debounce(save, cnf.opts.debounce_delay) or save) end - save_func() + save_func(buf) end function M.on() - api.nvim_create_autocmd(cnf.opts.trigger_events, { - callback = function() - perform_save() + api.nvim_create_autocmd(cnf.opts.trigger_events.immediate_save, { + callback = function (opts) + M.immediate_save(opts.buf) end, - pattern = "*", group = "AutoSave", + desc = "Immediately save a buffer" + }) + api.nvim_create_autocmd(cnf.opts.trigger_events.defer_save, { + callback = function(opts) + defer_save(opts.buf) + end, + group = "AutoSave", + desc = "Save a buffer after the `debounce_delay`" + }) + api.nvim_create_autocmd(cnf.opts.trigger_events.cancel_defered_save, { + callback = function (opts) + cancel_timer(opts.buf) + end, + group = "AutoSave", + desc = "Cancel a pending save timer for a buffer" }) api.nvim_create_autocmd({ "VimEnter", "ColorScheme", "UIEnter" }, { @@ -144,7 +157,6 @@ function M.on() end end) end, - pattern = "*", group = "AutoSave", })