BREAKING CHANGES: plugin rewrite

This commit is contained in:
Pocco81
2022-07-31 00:27:43 -05:00
parent 8df684bcb3
commit 0288839edd
18 changed files with 430 additions and 807 deletions
+43
View File
@@ -0,0 +1,43 @@
local config = {}
config.options = {
enabled = true, -- start auto-save when the plugin is loaded (i.e. when your package manager loads it)
execution_message = {
message = function() -- message to print on save
return ("AutoSave: saved at " .. vim.fn.strftime("%H:%M:%S"))
end,
dim = 0.18, -- dim the color of `message`
cleaning_interval = 4000, -- (milliseconds) automatically clean MsgArea after displaying `message`. See :h MsgArea
},
trigger_events = {"InsertLeave", "TextChanged"}, -- vim events that trigger auto-save. See :h events
-- 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
condition = function(buf)
local fn = vim.fn
local utils = require("auto-save.utils.data")
if
fn.getbufvar(buf, "&modifiable") == 1 or
utils.not_in(fn.getbufvar(buf, "&filetype"), {}) then
return true -- met condition(s), can save
end
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
callbacks = { -- functions to be executed at different intervals
enabling = nil, -- ran when enabling auto-save
disabling = nil, -- ran when disabling auto-save
before_asserting_save = nil, -- ran before checking `condition`
before_saving = nil, -- ran before doing the actual save
after_saving = nil -- ran after doing the actual save
}
}
function config.set_options(opts)
opts = opts or {}
config.options = vim.tbl_deep_extend("keep", opts, config.options)
end
return config
+149
View File
@@ -0,0 +1,149 @@
local M = {}
local cnf = require("auto-save.config").options
local callback = require("auto-save.utils.data").do_callback
local colors = require("auto-save.utils.colors")
local echo = require("auto-save.utils.echo")
local autosave_running
local api = vim.api
local g = vim.g
local fn = vim.fn
local cmd = vim.cmd
local o = vim.o
api.nvim_create_augroup("AutoSave", {
clear = true,
})
local global_vars = {}
local function set_buf_var(buf, name, value)
if buf == nil then
global_vars[name] = value
else
api.nvim_buf_set_var(buf, 'autosave_' .. name, value)
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
end
return inner_debounce
end
function M.save(buf)
buf = buf or api.nvim_get_current_buf()
callback("before_asserting_save")
if cnf.condition(buf) == false then
return
end
if not api.nvim_buf_get_option(buf, 'modified') then
return
end
callback("before_saving")
if g.auto_save_abort == true then
return
end
if cnf.write_all_buffers then
cmd("silent! wall")
else
api.nvim_buf_call(buf, function () cmd("silent! write") end)
end
callback("after_saving")
api.nvim_echo({ { (type(cnf.execution_message.message) == "function" and cnf.execution_message.message() or cnf.execution_message.message), 'AutoSaveText' } }, true, {})
if cnf.execution_message.cleaning_interval > 0 then
fn.timer_start(
cnf.execution_message.cleaning_interval,
function()
cmd([[echon '']])
end
)
end
end
local save_func = (cnf.debounce_delay > 0 and debounce(M.save, cnf.debounce_delay) or M.save)
local function perform_save()
g.auto_save_abort = false
save_func()
end
function M.on()
api.nvim_create_autocmd(cnf.trigger_events, {
callback = function()
perform_save()
end,
pattern = "*",
group = "AutoSave",
})
api.nvim_create_autocmd("VimEnter", {
callback = function()
if cnf.execution_message.dim > 0 then
MSG_AREA = colors.get_hl("MsgArea")
MSG_AREA.background = (MSG_AREA.background or colors.get_hl("Normal")["background"])
local foreground = (
o.background == "dark" and
colors.darken((MSG_AREA.background or "#000000"), cnf.execution_message.dim, MSG_AREA.foreground) or
colors.lighten((MSG_AREA.background or "#ffffff"), cnf.execution_message.dim, MSG_AREA.foreground)
)
colors.highlight("AutoSaveText", { fg = foreground })
end
end,
once = true,
group = "AutoSave",
})
callback("enabling")
autosave_running = true
end
function M.off()
api.nvim_create_augroup("AutoSave", {
clear = true,
})
callback("disabling")
autosave_running = false
end
function M.toggle()
if autosave_running then
M.off()
else
M.on()
end
end
function M.setup(custom_opts)
require("auto-save.config").set_options(custom_opts)
end
return M
+70
View File
@@ -0,0 +1,70 @@
local M = {}
---@param hex_str string hexadecimal value of a color
local hex_to_rgb = function(hex_str)
local hex = "[abcdef0-9][abcdef0-9]"
local pat = "^#(" .. hex .. ")(" .. hex .. ")(" .. hex .. ")$"
hex_str = string.lower(hex_str)
assert(string.find(hex_str, pat) ~= nil, "hex_to_rgb: invalid hex_str: " .. tostring(hex_str))
local red, green, blue = string.match(hex_str, pat)
return { tonumber(red, 16), tonumber(green, 16), tonumber(blue, 16) }
end
function M.highlight(group, color, force)
if color.link then
vim.api.nvim_set_hl(0, group, {
link = color.link,
})
else
if color.style then
for _, style in ipairs(color.style) do
color[style] = true
end
end
color.style = nil
if force then
vim.cmd("hi " .. group .. " guifg=" .. (color.fg or "NONE") .. " guibg=" .. (color.bg or "NONE"))
return
end
vim.api.nvim_set_hl(0, group, color)
end
end
function M.get_hl(name)
local ok, hl = pcall(vim.api.nvim_get_hl_by_name, name, true)
if not ok then
return
end
for _, key in pairs({ "foreground", "background", "special" }) do
if hl[key] then
hl[key] = string.format("#%06x", hl[key])
end
end
return hl
end
---@param fg string forecrust color
---@param bg string background color
---@param alpha number number between 0 and 1. 0 results in bg, 1 results in fg
function M.blend(fg, bg, alpha)
bg = hex_to_rgb(bg)
fg = hex_to_rgb(fg)
local blendChannel = function(i)
local ret = (alpha * fg[i] + ((1 - alpha) * bg[i]))
return math.floor(math.min(math.max(0, ret), 255) + 0.5)
end
return string.format("#%02X%02X%02X", blendChannel(1), blendChannel(2), blendChannel(3))
end
function M.darken(hex, amount, bg)
return M.blend(hex, bg or M.bg, math.abs(amount))
end
function M.lighten(hex, amount, fg)
return M.blend(hex, fg or M.fg, math.abs(amount))
end
return M
+25
View File
@@ -0,0 +1,25 @@
local M = {}
local cnf = require("auto-save.config").options
function M.set_of(list)
local set = {}
for i = 1, #list do
set[list[i]] = true
end
return set
end
function M.not_in(var, arr)
if M.set_of(arr)[var] == nil then
return true
end
end
function M.do_callback(callback_name)
if type(cnf.callbacks[callback_name]) == "function" then
cnf.callbacks[callback_name]()
end
end
return M
+25
View File
@@ -0,0 +1,25 @@
local TITLE = "auto-save"
return function(msg, kind)
local has_notify_plugin = pcall(require, "notify")
local level = {}
if kind == "error" then
level.log = vim.log.levels.ERROR
level.type = "error"
elseif kind == "warn" then
level.log = vim.log.levels.WARN
level.type = "error"
else
level.log = kind or vim.log.levels.INFO
level.type = "info"
end
if has_notify_plugin then
vim.notify(msg, level.log, {
title = TITLE,
})
else
vim.notify(("%s (%s): %s"):format(TITLE, level.type, msg), level.log)
end
end
-29
View File
@@ -1,29 +0,0 @@
local config = {}
config.options = {
enabled = true,
execution_message = "AutoSave: saved at " .. vim.fn.strftime("%H:%M:%S"),
events = {"InsertLeave", "TextChanged"},
conditions = {
exists = true,
filename_is_not = {},
filetype_is_not = {},
modifiable = true,
},
write_all_buffers = false,
on_off_commands = false,
clean_command_line_interval = 0,
debounce_delay = 135
}
function config.set_options(opts)
opts = opts or {}
for opt, _ in pairs(opts) do
if (config.options[opt] ~= nil) then -- not nil
config.options[opt] = opts[opt]
end
end
end
return config
-28
View File
@@ -1,28 +0,0 @@
local opts = require("autosave.config").options
local cmd = vim.cmd
local M = {}
local function setup_load()
if opts["enabled"] == true then
vim.g.autosave_state = true
require("autosave.main").main("on")
else
vim.g.autosave_state = false
end
end
local function setup_commands()
if opts["on_off_commands"] == true then
cmd([[command! ASOn lua require'autosave.main'.main('on')]])
cmd([[command! ASOff lua require'autosave.main'.main('off')]])
end
end
function M.setup(custom_opts)
require("autosave.config").set_options(custom_opts)
setup_load()
setup_commands()
end
return M
-51
View File
@@ -1,51 +0,0 @@
local autocmds = require("autosave.modules.autocmds")
local autosave = require("autosave")
local g = vim.g
local M = {}
require("autosave.utils.viml_funcs")
local function on()
if (autosave.hook_before_on ~= nil) then
autosave.hook_before_on()
end
autocmds.load_autocommands()
g.autosave_state = true
if (autosave.hook_after_on ~= nil) then
autosave.hook_after_on()
end
end
local function off()
if (autosave.hook_before_off ~= nil) then
autosave.hook_before_off()
end
autocmds.unload_autocommands()
g.autosave_state = false
if (autosave.hook_after_off ~= nil) then
autosave.hook_after_off()
end
end
function M.main(option)
option = option or 'load'
if (option == 'toggle') then
if (g.autosave_state == true) then
off()
else
on()
end
elseif (option == 'on') then
on()
elseif (option == 'off') then
off()
end
end
return M
-192
View File
@@ -1,192 +0,0 @@
local api = vim.api
local fn = vim.fn
local cmd = vim.cmd
local opts = require("autosave.config").options
local autosave = require("autosave")
local default_events = { "InsertLeave", "TextChanged" }
local modified
local M = {}
local function table_has_value(tbl, value)
for key, _ in pairs(tbl) do
if tbl[key] == value then
return true
end
end
return false
end
local function set_modified(value)
modified = value
end
local function get_modified()
return modified
end
local function actual_save()
-- might use update, but in that case it can't be checked if a file was modified and so it will always
-- print opts["execution_message"]
if api.nvim_eval([[&modified]]) == 1 then
local first_char_pos = fn.getpos("'[")
local last_char_pos = fn.getpos("']")
if opts["write_all_buffers"] then
cmd("silent! wall")
else
cmd("silent! write")
end
fn.setpos("'[", first_char_pos)
fn.setpos("']", last_char_pos)
if get_modified() == nil or get_modified() == false then
set_modified(true)
end
M.message_and_interval()
end
end
local function assert_user_conditions()
local sc_exists, sc_filename, sc_filetype, sc_modifiable = true, true, true, true
for condition, value in pairs(opts["conditions"]) do
if condition == "exists" then
if value == true then
if fn.filereadable(fn.expand("%:p")) == 0 then
sc_exists = false
break
end
end
elseif condition == "modifiable" then
if value == true then
if api.nvim_eval([[&modifiable]]) == 0 then
sc_modifiable = false
break
end
end
elseif condition == "filename_is_not" then
if not (next(opts["conditions"]["filename_is_not"]) == nil) then
if table_has_value(opts["conditions"]["filename_is_not"], vim.fn.expand('%:t')) == true then
sc_filename = false
break
end
end
elseif condition == "filetype_is_not" then
if not (next(opts["conditions"]["filetype_is_not"]) == nil) then
if table_has_value(opts["conditions"]["filetype_is_not"], api.nvim_eval([[&filetype]])) == true then
sc_filetype = false
break
end
end
end
end
return { sc_exists, sc_filename, sc_filetype, sc_modifiable }
end
local function assert_return(values, expected)
for key, value in pairs(values) do
if value ~= expected then
return false
end
end
return true
end
function M.message_and_interval()
if get_modified() == true then
set_modified(false)
if opts["execution_message"] ~= "" then
print(opts["execution_message"])
end
if opts["clean_command_line_interval"] > 0 then
cmd(
[[call timer_start(]]
.. opts["clean_command_line_interval"]
.. [[, funcref('g:AutoSaveClearCommandLine'))]]
)
end
end
end
local function debounce(lfn, duration)
local queued = false
local function inner_debounce()
if not queued then
vim.defer_fn(function()
queued = false
lfn()
end, duration)
queued = true
end
end
return inner_debounce
end
function M.do_save()
if assert_return(assert_user_conditions(), true) then
M.debounced_save()
end
end
function M.save()
if autosave.hook_before_saving ~= nil then
autosave.hook_before_saving()
end
M.do_save()
if autosave.hook_after_saving ~= nil then
autosave.hook_after_saving()
end
end
local function get_events()
if next(opts["events"]) == nil or opts["events"] == nil then
return default_events
else
return opts["events"]
end
end
local function parse_events()
return table.concat(get_events(), ",")
end
function M.load_autocommands()
if opts["debounce_delay"] == 0 then
M.debounced_save = actual_save
else
M.debounced_save = debounce(actual_save, opts["debounce_delay"])
end
api.nvim_exec([[
aug autosave_save
au!
au ]] .. parse_events() .. [[ * execute "lua require'autosave.modules.autocmds'.save()"
aug END
]], false)
end
function M.unload_autocommands()
api.nvim_exec(
[[
aug autosave_save
au!
aug END
]],
false
)
end
return M
-12
View File
@@ -1,12 +0,0 @@
local api = vim.api
api.nvim_exec(
[[
function! g:AutoSaveClearCommandLine(timer)
if mode() != 'c'
echon ''
endif
endfunction
]],
false
)