folke / noice.nvim

💥 Highly experimental plugin that completely replaces the UI for messages, cmdline and the popupmenu.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

feature: Override vim.ui.select with a nui menu (very basic implementation shown)

theKnightsOfRohan opened this issue · comments

Did you check the docs?

  • I have read all the noice.nvim docs

Is your feature request related to a problem? Please describe.

Whether using notify or mini as the message mechanism, it's a little disconcerting to have the selection dialog appear in the same place as your notifications, and have no visual indication of escaping out/selecting an item. I've tried doing this myself, and it works okay, but I think integrating it into noice as a preset or something would be "noice". 🙃

Describe the solution you'd like

Since the nui menu is pretty robust, I think just the ability to create a menu at the cursor or at an arbitrary position on the screen whenever vim.ui.select() is called would be enough. The reason I care about cursor position is for vim.lsp.buf.code_action(), which I use a lot, so that eye position is maintained.

Describe alternatives you've considered

I guess custom creating a menu from scratch, or a special input buffer would be an alternative? But the nui menu seems like a pretty 1:1 layer between inputs, so I don't see anything that would be too much better. I guess you could make the selection menu part of the configuration options if there are multiple ways to implement it.

Additional context

Here's a very basic 1-afternoon implementation of what I mean (note that I am no lua whiz):

return {
    "MunifTanjim/nui.nvim",
    config = function()
        local Menu = require("nui.menu")

        vim.ui.select = function(items, opts, on_choice)
            vim.validate({
                items = { items, 'table', false },
                on_choice = { on_choice, 'function', false },
            })
            opts = opts or {}
            local format_item = opts.format_item or tostring

            Menu({
                relative = "cursor",
                position = {
                    row = 2,
                    col = 0,
                },
                size = {
                    width = 40,
                },
                border = {
                    style = "rounded",
                    text = {
                        top = opts.prompt or "Select an item",
                        top_align = "center",
                    },
                },
            }, {
                lines = (function()
                    ---@type NuiTree.Node[]
                    local selections = {}

                    for _, item in ipairs(items) do
                        if type(item) == "string" then
                            table.insert(selections, Menu.item(item))
                        elseif type(item) == "table" then
                            table.insert(selections, Menu.item(format_item(item), item))
                        end
                    end

                    return selections
                end)(),

                on_close = function()
                    print("Closed")
                end,
                on_submit = function(selected)
                    on_choice(selected)
                end,
            }):mount()
        end

        vim.keymap.set("n", "<leader><leader>", function()
            vim.ui.select({ 'One', 'Two', 'Three' }, {}, function(selected)
                print("Selected: " .. selected)
            end)
        end)
    end,
}

This implementation works with both vim.lsp.buf.code_action() and the string example keymapped below, which should mean that it works with both the table and string versions of nui's Menu.

By the way, someone made a PR last year, but they deleted their fork. You might also wanna look into dressing.nvim, which is what most people use AFAIK.

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.

This issue was closed because it has been stalled for 7 days with no activity.