nvim-neorocks / nvim-best-practices

Collection of DOs and DON'Ts for modern Neovim Lua plugin development
Creative Commons Zero v1.0 Universal
237 stars 3 forks source link

The subcommand auto-completion example doesn't work #4

Closed ColinKennedy closed 1 month ago

ColinKennedy commented 1 month ago
---@class MyCmdSubcommand
---@field impl fun(args:string[], opts: table) The command implementation
---@field complete? fun(subcmd_arg_lead: string): string[] (optional) Command completions callback, taking the lead of the subcommand's arguments

---@type table<string, MyCmdSubcommand>
local subcommand_tbl = {
    update = {
        impl = function(args, opts)
          -- Implementation (args is a list of strings)
        end,
        -- This subcommand has no completions
    },
    install = {
        impl = function(args, opts)
            -- Implementation
        end,
        complete = function(subcmd_arg_lead)
            -- Simplified example
            local install_args = {
                "neorg",
                "rest.nvim",
                "rustaceanvim",
            }
            return vim.iter(install_args)
                :filter(function(install_arg)
                    -- If the user has typed `:Rocks install ne`,
                    -- this will match 'neorg'
                    return install_arg:find(subcmd_arg_lead) ~= nil
                end)
                :totable()
        end,
        -- ...
    },
}

---@param opts table :h lua-guide-commands-create
local function my_cmd(opts)
    local fargs = opts.fargs
    local subcommand_key = fargs[1]
    -- Get the subcommand's arguments, if any
    local args = #fargs > 1 and vim.list_slice(fargs, 2, #fargs) or {}
    local subcommand = subcommand_tbl[subcommand_key]
    if not subcommand then
        vim.notify("Rocks: Unknown command: " .. cmd, vim.log.levels.ERROR)
        return
    end
    -- Invoke the subcommand
    subcommand.impl(args, opts)
end

-- NOTE: the options will vary, based on your use case.
vim.api.nvim_create_user_command("Rocks", my_cmd, {
    nargs = "+",
    desc = "My awesome command with subcommand completions",
    complete = function(arg_lead, cmdline, _)
        -- Get the subcommand.
        local subcmd_key, subcmd_arg_lead = cmdline:match("^Rocks[!]*%s(%S+)%s(.*)$")
        if subcmd_key and subcmd_arg_lead and subcommand_tbl[subcmd_key] and subcommand_tbl[subcmd_key].complete then
            -- The subcommand has completions. Return them.
            return subcommand_tbl[subcmd_key].complete(subcmd_arg_lead)
        end
        -- Check if cmdline is a subcommand
        if cmdline:match("^Rocks[!]*%s+%w*$") then
            -- Filter subcommands that match
            local subcommand_keys = vim.tbl_keys(subcommand_tbl)
            return vim.iter(subcommand_keys)
                :filter(function(key)
                    return key:find(arg_lead) ~= nil
                end)
                :totable()
        end
    end,
    bang = true, -- If you want to support ! modifiers
})

Add that to some plugin/foo.lua in 'runtimepath' and type :Rocks install ne. The Neovim command-line should complete to ne to neorg but doesn't.

Also worth mentioning that there's a bug in the README.md. The snippet above as the fix listed in https://github.com/nvim-neorocks/nvim-best-practices/pull/3

mrcjkb commented 1 month ago

That's strange. I copy/pasted your snippet and it works just fine for me:

The screenshot is nvim-cmp. With bare nvim (no plugins installed), it completes to neorg when I hit <tab>.

ColinKennedy commented 1 month ago

Tried again just now. The issue is actually wilder.nvim. And probably this other GitHub issue is related: https://github.com/gelguy/wilder.nvim/issues/159

Since there's nothing wrong here, I'll close this issue and chat over at wilder.nvim, thank you for double-checking!