Popupmenu - OXY2DEV/ui.nvim GitHub Wiki
💻 Pop-up menu
This file explains how the ui/cmdline.lua file works.
You can change how the pop-up menu looks by listening to the ext_popupmenu
events. You will typically use something like this,
---@type integer Namespace for the UI(s).
local namespace = vim.api.nvim_create_namespace("ui");
vim.ui_attach(namespace, {
ext_popupmenu = true
}, function (event, ...)
--- {event}, Event name
--- {...}, Arguments this event produces.
--- Do stuff...
end);
📜 Event list
[!TIP] You can handle these events without using
vim.schedule()
!
The pop-up menu receives the following events,
-
popupmenu_show
Triggered when the pop-up menu should be shown. -
popupmenu_select
Triggered when the selected item changes in the pop-up menu.
- popupmenu_hide
Triggered when the pop-up menu should be hidden.
✨ Completion text
The completion menu text is shown differently based on the current mode
.
📐 Single line(strip style)
This is used in command
mode and is created by popup.__strip_renderer() function.
It creates a single line by iterating over the lines and applying the highlights to the regions covered by each item.
The rendering process is similar to the command-line
so I won't be explaining it in detail here. It's a simple for loop that adds the completion text to a string and creates regions of highlights for that screen.
The text is then sent to nvim_buf_set_lines()
and the highlights are iterated over and the values are passed to nvim_buf_set_extmark()
.
📐 Multi line(completion style)
This is used in other modes and is created by popup.__completion_renderer() function.
The rendering process here is a single for loop that adds a new line to the buffer(via nvim_buf_set_lines(buffer, -1, -1, false, { ... })
and an extmark for that line.
📏 Completion menu position
When using multi line pop-up menu, the menu gets placed based on the amount of free space around the cursor.
To get the cursor position on the screen we use vim.fn.screenpos()
. The returned value is a table which has a property named curscol
. This tells use which column the cursor is in.
It also has the row
property which tells us which row in the terminal the cursor is on.
┌────────────────────────┬───────┐
│ y = Screen row │ │
│ x = Screen column y │
│ │ │
│ │ │
├────────────x───────────█──w─┬──┤
│ w = Menu width │░░░░┆ │
│ h = Menu height h░░░░┆ │
│ │░░░░┆ │
│ ├┄┄┄┄┘ │
│ │ │
└────────────────────────┴───────┘
A simple condition is used to check which side to open the menu on. It looks like this,
-- Floating window's anchor based on
-- where it should be opened.
--
-- SE | SW
-- ---+---
-- NE | NW
---@type "NE" | "NW" | "SE" | "SW"
local anchor;
if y + h >= vim.o.lines then
-- Above
anchor = "S";
else
-- Below
anchor = "N";
end
if x + w >= vim.o.columns then
-- Left
anchor = anchor .. "E";
else
-- Right
anchor = anchor .. "W";
end