Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/lua/std/user_command.lua

Raw
--- Creates a new user command
--- @param user_command table Necessary data to create a new user command.
local create_user_command = function( user_command )
	local options = { desc = user_command.description, }
	local merged_options = vim.tbl_deep_extend( 'force', options, user_command.options or {} )
	if user_command.bufnr then
		vim.api.nvim_buf_create_user_command(
			user_command.bufnr,
			user_command.name,
			user_command.command,
			merged_options
		)
	else
		vim.api.nvim_create_user_command(
			user_command.name,
			user_command.command,
			merged_options
		)
	end
end

--- Sets the field `command` in `self` to given value in `command`
--- Then creates a new user command with data in `self`.
--- @param self table any table.
--- @param command function command to be executed when the user command is run.
--- @return function deleter A function that deletes the created user command.
local set_command = function( self, command )
	self.command = command
	create_user_command( self )
	if self.bufnr then
		return function() vim.api.nvim_buf_del_user_command( self.bufnr, self.name ) end
	end
	return function() vim.api.nvim_del_user_command( self.name ) end
end

--- meta table, that sets the function value, when called, to a field named `command`
local COMMAND_SETTER = {
	__call = function( self, command )
		vim.validate( 'command', command, 'function' )
		return set_command( self, command )
	end,
}

--- meta table, that either sets the table value to a field named `options`,
--- or the function value to a field named `command`, when called.
local OPTIONS_OR_COMMAND_SETTER = {
	__call = function( self, options_or_command )
		vim.validate( 'options_or_command', options_or_command, { 'table', 'function', } )
		if type( options_or_command ) == 'table' then
			self.options = options_or_command
			return setmetatable( self, COMMAND_SETTER )
		end
		return set_command( self, options_or_command )
	end,
}

--- meta table, that sets the string value to a field named `description`, when called.
local DESCRIPTION_SETTER = {
	__call = function( self, description )
		vim.validate( 'description', description, 'string' )
		self.description = description
		return setmetatable( self, OPTIONS_OR_COMMAND_SETTER )
	end,
}

local new_cmd = function( name, bufnr )
	local cmd = { name = name }
	if bufnr then cmd.bufnr = bufnr end
	return cmd
end

--- meta table, that sets the string value to a field named `name`, when indexed into.
local COMMAND_NAME_SETTER = {
	__index = function( _, command_name )
		vim.validate( 'command_name', command_name, 'string' )
		return setmetatable( new_cmd( command_name ), DESCRIPTION_SETTER )
	end,
}

--- meta table, that sets the buffer number when called, then returns
--- a fresh command name setter chain with the bufnr attached.
local BUFFER_SETTER = {
	__call = function( _, bufnr )
		vim.validate( 'bufnr', bufnr, 'number' )
		local cmd_mt = {
			__index = function( _, command_name )
				vim.validate( 'command_name', command_name, 'string' )
				return setmetatable( new_cmd( command_name, bufnr ), DESCRIPTION_SETTER )
			end,
		}
		return setmetatable( {}, cmd_mt )
	end,
}

local M = setmetatable( {}, COMMAND_NAME_SETTER )
M.buffer = setmetatable( {}, BUFFER_SETTER )
return M