connorgmeean
2 years ago
5 changed files with 308 additions and 104 deletions
@ -0,0 +1,144 @@ |
|||
--- AutoCommands Service, |
|||
--- Provides functions to wrap neovims APIs to set and remove autocmds |
|||
--- Acts as a compatibility layer between different API versions. |
|||
--- Manages references to all commands to be cleared for :DoomReload |
|||
|
|||
-- TYPES |
|||
|
|||
--- @class AutoCommandArgs |
|||
--- @field args string Args parsed to command (if any) |
|||
--- @field fargs string[] Args split by unescaped whitespace (if any) |
|||
--- @field line1 number Starting line of the command range |
|||
--- @field line2 number Final line of the command range |
|||
--- @field count number Any count supplied (if any) |
|||
|
|||
--- @class SetAutoCommandOptions |
|||
--- @field nested boolean|nil |
|||
--- @field once boolean|nil |
|||
|
|||
--- IMPLEMENTATIONS |
|||
--- Wraps the nvim functionality to handle different neovim versions. |
|||
local utils = require("doom.utils") |
|||
|
|||
-- Data to be stored globally so it can be accessed from the nvim-0.5 implementation |
|||
local data = _G._doom_autocmds_service_data |
|||
or { |
|||
-- Stores data relating to the auto command so they can be deleted on neovim < 0.8 |
|||
autocmd_signatures = {}, |
|||
-- Stores the lua function handlers for nvim version < 0.8 |
|||
autocmd_actions = {}, |
|||
-- Stores created autocommand ids from vim.api.nvim_create_autocmd (or custom shim in the v0.5 version) |
|||
autocmd_ids = {}, |
|||
} |
|||
_G._doom_autocmds_service_data = data |
|||
|
|||
-- Store all autocommands inside of an augroup for doom-nvim |
|||
if vim.fn.has("nvim-0.8") then |
|||
vim.api.nvim_create_augroup("DoomAutoCommands", { clear = true }) |
|||
else |
|||
vim.cmd([[ |
|||
augroup DoomAutoCommands |
|||
autocmd! |
|||
augroup END |
|||
]]) |
|||
end |
|||
|
|||
local set_autocmd_implementations = { |
|||
["nvim-0.5"] = function(event, pattern, action, opts) |
|||
local cmd_string = "autocmd! " |
|||
cmd_string = cmd_string .. ("%s %s "):format(event, pattern) |
|||
|
|||
local uid = utils.unique_index() |
|||
data.autocmd_ids[uid] = true |
|||
data.autocmd_signatures = cmd_string |
|||
|
|||
if opts.nested then |
|||
cmd_string = cmd_string .. "++nested " |
|||
end |
|||
if opts.once then |
|||
cmd_string = cmd_string .. "++once " |
|||
end |
|||
|
|||
if type(action) == "string" then |
|||
cmd_string = cmd_string .. action .. " " |
|||
else |
|||
data.autocmd_actions[uid] = action |
|||
|
|||
cmd_string = cmd_string .. (":lua _doom_autocmds_service_data.autocmd_actions[%d]()"):format(uid) |
|||
end |
|||
vim.cmd(cmd_string) |
|||
return uid |
|||
end, |
|||
["latest"] = function(event, pattern, action, opts) |
|||
local merged_opts = vim.tbl_extend('keep', opts, { |
|||
callback = action, |
|||
pattern = pattern, |
|||
group = "DoomAutoCommands" |
|||
}) |
|||
local id = vim.api.nvim_create_autocmd(event, merged_opts) |
|||
data.autocmd_ids[id] = true |
|||
data.autocmd_signatures[id] = ("%s %s"):format(event, pattern) |
|||
return id |
|||
end, |
|||
} |
|||
local set_autocmd_fn = utils.pick_compatible_field(set_autocmd_implementations) |
|||
|
|||
local del_autocmd_implementations = { |
|||
["nvim-0.5"] = function(id) |
|||
local delete_signature = data.autocmd_signatures[id] |
|||
if delete_signature then |
|||
vim.cmd(delete_signature) |
|||
end |
|||
end, |
|||
["latest"] = function(id) |
|||
vim.api.nvim_del_autocmd(id) |
|||
end, |
|||
} |
|||
local del_autocmd_fn = utils.pick_compatible_field(del_autocmd_implementations) |
|||
|
|||
local del_all_autocmd_implementations = { |
|||
["nvim-0.5"] = function() |
|||
vim.cmd([[ |
|||
augroup DoomAutoCommands |
|||
autocmd! |
|||
augroup END |
|||
]]) |
|||
end, |
|||
["latest"] = function() |
|||
vim.api.nvim_create_augroup("DoomAutoCommands", { clear = true }) |
|||
end, |
|||
} |
|||
local del_all_autocmd_fn = utils.pick_compatible_field(del_all_autocmd_implementations) |
|||
|
|||
-- API |
|||
local autocmds_service = {} |
|||
|
|||
--- Set a neovim autocmd |
|||
---@param event string Name of autocmd |
|||
---@param pattern string Pattern to match autocommand with |
|||
---@param action string|function(AutoCommandArgs) |
|||
---@param opts SetAutoCommandOptions|nil |
|||
---@return number ID of autocommand, used to delete it later on |
|||
autocmds_service.set = function(event, pattern, action, opts) |
|||
local resolved_opts = opts or {} |
|||
local stripped_opts = { |
|||
nested = resolved_opts.nested or false, |
|||
once = resolved_opts.once or false, |
|||
} |
|||
return set_autocmd_fn(event, pattern, action, stripped_opts) |
|||
end |
|||
|
|||
--- Deletes an autocommand from a given id |
|||
---@param id number ID of autocommand to delete |
|||
autocmds_service.del = function(id) |
|||
del_autocmd_fn(id) |
|||
data.autocmd_ids[id] = nil |
|||
data.autocmd_signatures[id] = nil |
|||
data.autocmd_actions[id] = nil |
|||
end |
|||
|
|||
autocmds_service.del_all = function() |
|||
del_all_autocmd_fn() |
|||
end |
|||
|
|||
return autocmds_service |
@ -0,0 +1,101 @@ |
|||
--- Commands Service, |
|||
--- Provides functions to wrap neovims APIs to set and remove commands |
|||
--- Acts as a compatibility layer between different API versions. |
|||
--- Manages references to all commands to be cleared for :DoomReload |
|||
|
|||
-- TYPES |
|||
|
|||
--- @class CommandArgs |
|||
--- @field args string Args parsed to command (if any) |
|||
--- @field fargs string[] Args split by unescaped whitespace (if any) |
|||
--- @field line1 number Starting line of the command range |
|||
--- @field line2 number Final line of the command range |
|||
--- @field count number Any count supplied (if any) |
|||
|
|||
--- @class SetCommandOptions |
|||
--- @field nargs number|'*'|nil Number of expected arguments for the command. '*' for variable. |
|||
|
|||
--- IMPLEMENTATIONS |
|||
--- Wraps the nvim functionality to handle different neovim versions. |
|||
local utils = require("doom.utils") |
|||
|
|||
-- Data to be stored globally so it can be accessed from the nvim-0.5 implementation |
|||
local data = _G._doom_commands_service_data or { |
|||
command_actions = {}, |
|||
} |
|||
_G._doom_commands_service_data = data |
|||
|
|||
local set_command_implementations = { |
|||
["nvim-0.5"] = function(name, command, opts) |
|||
-- Build the command constructor |
|||
local cmd_string = "command! " |
|||
if opts and opts.nargs ~= nil then |
|||
cmd_string = cmd_string .. ("-nargs=%s "):format(opts.nargs) |
|||
end |
|||
if opts and opts.completion ~= nil then |
|||
cmd_string = cmd_string .. ("-complete=%s "):format(table.concat(opts.complete, ",")) |
|||
end |
|||
cmd_string = cmd_string .. " " .. name .. " " |
|||
|
|||
if type(command) == "string" then |
|||
cmd_string = cmd_string .. command .. " " |
|||
else |
|||
local uid = utils.unique_index() |
|||
data.command_actions[uid] = command |
|||
|
|||
cmd_string = cmd_string .. ("lua _doom_commands_service_data.command_actions[%d]"):format(uid) |
|||
if opts.nargs ~= nil then |
|||
cmd_string = cmd_string .. "(<f-args>)" |
|||
else |
|||
cmd_string = cmd_string .. "()" |
|||
end |
|||
end |
|||
vim.cmd(cmd_string) |
|||
end, |
|||
["nvim-0.8"] = function(name, command, opts) |
|||
vim.api.nvim_create_user_command(name, command, opts) |
|||
end, |
|||
} |
|||
local set_command_fn = utils.pick_compatible_field(set_command_implementations) |
|||
|
|||
local del_command_implementations = { |
|||
["nvim-0.5"] = function(name) |
|||
vim.cmd(("delcommand %s"):format(name)) |
|||
end, |
|||
["nvim-0.8"] = function(name) |
|||
vim.api.nvim_del_user_command(name) |
|||
end, |
|||
} |
|||
local del_command_fn = utils.pick_compatible_field(del_command_implementations) |
|||
|
|||
-- API |
|||
local commands_service = {} |
|||
|
|||
--- List of all commands set so they can be deleted by `commands.del_all()` |
|||
--- @type table<string,boolean|nil> |
|||
commands_service.stored_names = {} |
|||
|
|||
--- Set a neovim command |
|||
---@param name string Name of command |
|||
---@param command string|function(CommandArgs) |
|||
---@param opts SetCommandOptions|nil |
|||
commands_service.set = function(name, command, opts) |
|||
commands_service.stored_names[name] = true |
|||
set_command_fn(name, command, opts or {}) |
|||
end |
|||
|
|||
commands_service.del = function(name) |
|||
commands_service.stored_names[name] = nil |
|||
del_command_fn(name) |
|||
end |
|||
|
|||
commands_service.del_all = function() |
|||
for name, _ in pairs(commands_service.stored_names) do |
|||
if name then |
|||
del_command_fn(name) |
|||
end |
|||
end |
|||
commands_service.stored_names = {} |
|||
end |
|||
|
|||
return commands_service |
Loading…
Reference in new issue