-
Notifications
You must be signed in to change notification settings - Fork 4
Popupmenu
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);Tip
You can handle these events without using vim.schedule()!
The pop-up menu receives the following events,
-
popupmenu_showTriggered when the pop-up menu should be shown. -
popupmenu_selectTriggered when the selected item changes in the pop-up menu.
- popupmenu_hide
Triggered when the pop-up menu should be hidden.
The completion menu text is shown differently based on the current mode.
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().
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.
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