Do you want to save your code before the destroying of the world?
You may say:” That’s easy, I have ability to create an autocmd of TextChanged event to save it”. But it’s too frequent sometimes. Therefore, I am going to tell you how to create a mini auto-save script with delay feature, which is useful.
Thinking
The main means to achieve the goal is to save the buffer after some events with autocmd function and then start a timer. Before the timer ends, the script won’t save the buffer anymore.
What’s more, I hope each buffer use a different timer.
Let’s start
You’re able to run help command in neovim to check more details if necessary
In order to make coding easier, we will use the following variables in all code blocks.
1 2
local api = vim.api local fn = vim.fn
Autocmd
First of all, let’s create a simple autocmd to save the buffer and show the hint for user after each InsertLeave and TextChanged event.
In this tutorial, we use vim.defer_fn to do timer. And we use nvim_buf_set_var and nvim_buf_get_var to mark or get if a buffer is queued. If a buffer is queued, it cannot be saved.
Now, we should know if the buffer is queued. And the script only save the code when the buffer isn’t queued .So add the following codes into callback function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- get the queued value of the buffer local ok, queued = pcall(api.nvim_buf_get_var, ctx.buf, "autosave_queued") -- if cannot get/set buffer variable, end the callback ifnot ok then return end
-- only save the buffer if the buffer isn't queued ifnot queued then vim.cmd("silent w") vim.notify("Saved at " .. os.date("%H:%M:%S")) -- let the buffer queued after saving it api.nvim_buf_set_var(ctx.buf, "autosave_queued", true) end
Then, we’re supposed to cancle the buffer’s queued status with timer. You may want to use the following code to do it after delay.
1 2 3 4 5
vim.defer_fn(function() if api.nvim_buf_is_valid(ctx.buf) then api.nvim_buf_set_var(ctx.buf, "autosave_queued", false) end end, delay)
However, there is a big problem here. We aim at saving the code once at most every delay, but the fact is that, if we tigger the events many times, we will create many timers to set autosave_queued false. So, we need to create another variable to block the timer be like:
1 2 3 4 5 6 7 8 9 10 11 12
local block = api.nvim_buf_get_var(ctx.buf, "autosave_block") ifnot block then api.nvim_buf_set_var(ctx.buf, "autosave_block", true) vim.defer_fn(function() -- check if the buffer valid -- because buffer may disappear after delay if api.nvim_buf_is_valid(ctx.buf) then api.nvim_buf_set_var(ctx.buf, "autosave_queued", false) api.nvim_buf_set_var(ctx.buf, "autosave_block", false) end end, delay) end
Initialization
At last, we ought to initialize the autosave_queued and autosave_block variable after entering a new buffer.
api.nvim_create_autocmd({ "InsertLeave", "TextChanged" }, { pattern = "*", group = autosave, callback = function(ctx) -- conditions that donnot do autosave local disabled_ft = { "acwrite", "oil" } if not vim.bo.modified or fn.findfile(ctx.file, ".") == ""-- a new file or ctx.file:match("wezterm.lua") or vim.tbl_contains(disabled_ft, vim.bo[ctx.buf].ft) then return end
local ok, queued = pcall(api.nvim_buf_get_var, ctx.buf, "autosave_queued") ifnot ok then return end
ifnot queued then vim.cmd("silent w") api.nvim_buf_set_var(ctx.buf, "autosave_queued", true) vim.notify("Saved at " .. os.date("%H:%M:%S")) end
local block = api.nvim_buf_get_var(ctx.buf, "autosave_block") ifnot block then api.nvim_buf_set_var(ctx.buf, "autosave_block", true) vim.defer_fn(function() if api.nvim_buf_is_valid(ctx.buf) then api.nvim_buf_set_var(ctx.buf, "autosave_queued", false) api.nvim_buf_set_var(ctx.buf, "autosave_block", false) end end, delay) end end, })
Ending
Now, an awesome auto-save script have been created, which is customizable. You can add other features into it such as some conditions to save, some callbacks before/after saving( e.g. formatting ), etc.