--- 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