mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #11943 from yatli/master
[RDY] API/UI: Allow UI to set PUM position and size, and pass the position to CompleteChanged
This commit is contained in:
commit
c7d3630e21
@ -2341,6 +2341,22 @@ nvim_ui_pum_set_height({height}) *nvim_ui_pum_set_height()*
|
||||
Parameters: ~
|
||||
{height} Popupmenu height, must be greater than zero.
|
||||
|
||||
*nvim_ui_pum_set_bounds()*
|
||||
nvim_ui_pum_set_bounds({width}, {height}, {row}, {col})
|
||||
|
||||
Tells Nvim the geometry of the popumenu, to align floating
|
||||
windows with an external popup menu. Note that this method
|
||||
is not to be confused with |nvim_ui_pum_set_height()|, which
|
||||
sets the number of visible items in the popup menu, while
|
||||
this function sets the bounding box of the popup menu,
|
||||
including visual decorations such as boarders and sliders.
|
||||
|
||||
Parameters: ~
|
||||
{width} Popupmenu width.
|
||||
{height} Popupmenu height.
|
||||
{row} Popupmenu row.
|
||||
{height} Popupmenu height.
|
||||
|
||||
nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()*
|
||||
TODO: Documentation
|
||||
|
||||
|
@ -109,7 +109,12 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
|
||||
UI *ui = xcalloc(1, sizeof(UI));
|
||||
ui->width = (int)width;
|
||||
ui->height = (int)height;
|
||||
ui->pum_height = 0;
|
||||
ui->pum_nlines = 0;
|
||||
ui->pum_pos = false;
|
||||
ui->pum_width = 0.0;
|
||||
ui->pum_height = 0.0;
|
||||
ui->pum_row = -1.0;
|
||||
ui->pum_col = -1.0;
|
||||
ui->rgb = true;
|
||||
ui->override = false;
|
||||
ui->grid_resize = remote_ui_grid_resize;
|
||||
@ -340,7 +345,56 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err)
|
||||
"It must support the ext_popupmenu option");
|
||||
return;
|
||||
}
|
||||
ui->pum_height = (int)height;
|
||||
|
||||
ui->pum_nlines = (int)height;
|
||||
}
|
||||
|
||||
/// Tells Nvim the geometry of the popumenu, to align floating windows with an
|
||||
/// external popup menu.
|
||||
///
|
||||
/// Note that this method is not to be confused with |nvim_ui_pum_set_height()|,
|
||||
/// which sets the number of visible items in the popup menu, while this
|
||||
/// function sets the bounding box of the popup menu, including visual
|
||||
/// decorations such as boarders and sliders. Floats need not use the same font
|
||||
/// size, nor be anchored to exact grid corners, so one can set floating-point
|
||||
/// numbers to the popup menu geometry.
|
||||
///
|
||||
/// @param channel_id
|
||||
/// @param width Popupmenu width.
|
||||
/// @param height Popupmenu height.
|
||||
/// @param row Popupmenu row.
|
||||
/// @param col Popupmenu height.
|
||||
/// @param[out] err Error details, if any.
|
||||
void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height,
|
||||
Float row, Float col, Error *err)
|
||||
FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY
|
||||
{
|
||||
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
|
||||
api_set_error(err, kErrorTypeException,
|
||||
"UI not attached to channel: %" PRId64, channel_id);
|
||||
return;
|
||||
}
|
||||
|
||||
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
|
||||
if (!ui->ui_ext[kUIPopupmenu]) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"UI must support the ext_popupmenu option");
|
||||
return;
|
||||
}
|
||||
|
||||
if (width <= 0) {
|
||||
api_set_error(err, kErrorTypeValidation, "Expected width > 0");
|
||||
return;
|
||||
} else if (height <= 0) {
|
||||
api_set_error(err, kErrorTypeValidation, "Expected height > 0");
|
||||
return;
|
||||
}
|
||||
|
||||
ui->pum_row = (double)row;
|
||||
ui->pum_col = (double)col;
|
||||
ui->pum_width = (double)width;
|
||||
ui->pum_height = (double)height;
|
||||
ui->pum_pos = true;
|
||||
}
|
||||
|
||||
/// Pushes data into UI.UIData, to be consumed later by remote_ui_flush().
|
||||
|
@ -1634,6 +1634,28 @@ int tv_dict_add_nr(dict_T *const d, const char *const key,
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Add a floating point number entry to dictionary
|
||||
///
|
||||
/// @param[out] d Dictionary to add entry to.
|
||||
/// @param[in] key Key to add.
|
||||
/// @param[in] key_len Key length.
|
||||
/// @param[in] nr Floating point number to add.
|
||||
///
|
||||
/// @return OK in case of success, FAIL when key already exists.
|
||||
int tv_dict_add_float(dict_T *const d, const char *const key,
|
||||
const size_t key_len, const float_T nr)
|
||||
{
|
||||
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
|
||||
|
||||
item->di_tv.v_type = VAR_FLOAT;
|
||||
item->di_tv.vval.v_float = nr;
|
||||
if (tv_dict_add(d, item) == FAIL) {
|
||||
tv_dict_item_free(item);
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Add a special entry to dictionary
|
||||
///
|
||||
/// @param[out] d Dictionary to add entry to.
|
||||
|
@ -237,6 +237,12 @@ for i = 1, #functions do
|
||||
(j - 1)..'].type == kObjectTypeInteger && args.items['..(j - 1)..'].data.integer >= 0) {')
|
||||
output:write('\n '..converted..' = (handle_T)args.items['..(j - 1)..'].data.integer;')
|
||||
end
|
||||
if rt:match('^Float$') then
|
||||
-- accept integers for Floats
|
||||
output:write('\n } else if (args.items['..
|
||||
(j - 1)..'].type == kObjectTypeInteger) {')
|
||||
output:write('\n '..converted..' = (Float)args.items['..(j - 1)..'].data.integer;')
|
||||
end
|
||||
-- accept empty lua tables as empty dictionarys
|
||||
if rt:match('^Dictionary') then
|
||||
output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeArray && args.items['..(j - 1)..'].data.array.size == 0) {') --luacheck: ignore 631
|
||||
|
@ -908,10 +908,17 @@ void pum_set_event_info(dict_T *dict)
|
||||
if (!pum_visible()) {
|
||||
return;
|
||||
}
|
||||
tv_dict_add_nr(dict, S_LEN("height"), pum_height);
|
||||
tv_dict_add_nr(dict, S_LEN("width"), pum_width);
|
||||
tv_dict_add_nr(dict, S_LEN("row"), pum_row);
|
||||
tv_dict_add_nr(dict, S_LEN("col"), pum_col);
|
||||
double w, h, r, c;
|
||||
if (!ui_pum_get_pos(&w, &h, &r, &c)) {
|
||||
w = (double)pum_width;
|
||||
h = (double)pum_height;
|
||||
r = (double)pum_row;
|
||||
c = (double)pum_col;
|
||||
}
|
||||
tv_dict_add_float(dict, S_LEN("height"), h);
|
||||
tv_dict_add_float(dict, S_LEN("width"), w);
|
||||
tv_dict_add_float(dict, S_LEN("row"), r);
|
||||
tv_dict_add_float(dict, S_LEN("col"), c);
|
||||
tv_dict_add_nr(dict, S_LEN("size"), pum_size);
|
||||
tv_dict_add_special(dict, S_LEN("scrollbar"),
|
||||
pum_scrollbar ? kSpecialVarTrue : kSpecialVarFalse);
|
||||
|
@ -979,9 +979,9 @@ func Test_CompleteChanged()
|
||||
call cursor(4, 1)
|
||||
|
||||
call feedkeys("Sf\<C-N>", 'tx')
|
||||
call assert_equal({'completed_item': {}, 'width': 15,
|
||||
\ 'height': 2, 'size': 2,
|
||||
\ 'col': 0, 'row': 4, 'scrollbar': v:false}, g:event)
|
||||
call assert_equal({'completed_item': {}, 'width': 15.0,
|
||||
\ 'height': 2.0, 'size': 2,
|
||||
\ 'col': 0.0, 'row': 4.0, 'scrollbar': v:false}, g:event)
|
||||
call feedkeys("a\<C-N>\<C-N>\<C-E>", 'tx')
|
||||
call assert_equal('foo', g:word)
|
||||
call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
|
||||
@ -1009,10 +1009,10 @@ func Test_pum_getpos()
|
||||
setlocal completefunc=UserDefinedComplete
|
||||
|
||||
let d = {
|
||||
\ 'height': 5,
|
||||
\ 'width': 15,
|
||||
\ 'row': 1,
|
||||
\ 'col': 0,
|
||||
\ 'height': 5.0,
|
||||
\ 'width': 15.0,
|
||||
\ 'row': 1.0,
|
||||
\ 'col': 0.0,
|
||||
\ 'size': 5,
|
||||
\ 'scrollbar': v:false,
|
||||
\ }
|
||||
|
@ -226,7 +226,7 @@ int ui_pum_get_height(void)
|
||||
{
|
||||
int pum_height = 0;
|
||||
for (size_t i = 1; i < ui_count; i++) {
|
||||
int ui_pum_height = uis[i]->pum_height;
|
||||
int ui_pum_height = uis[i]->pum_nlines;
|
||||
if (ui_pum_height) {
|
||||
pum_height =
|
||||
pum_height != 0 ? MIN(pum_height, ui_pum_height) : ui_pum_height;
|
||||
@ -235,6 +235,21 @@ int ui_pum_get_height(void)
|
||||
return pum_height;
|
||||
}
|
||||
|
||||
bool ui_pum_get_pos(double *pwidth, double *pheight, double *prow, double *pcol)
|
||||
{
|
||||
for (size_t i = 1; i < ui_count; i++) {
|
||||
if (!uis[i]->pum_pos) {
|
||||
continue;
|
||||
}
|
||||
*pwidth = uis[i]->pum_width;
|
||||
*pheight = uis[i]->pum_height;
|
||||
*prow = uis[i]->pum_row;
|
||||
*pcol = uis[i]->pum_col;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ui_refresh_event(void **argv)
|
||||
{
|
||||
ui_refresh();
|
||||
|
@ -53,7 +53,12 @@ struct ui_t {
|
||||
bool ui_ext[kUIExtCount]; ///< Externalized UI capabilities.
|
||||
int width;
|
||||
int height;
|
||||
int pum_height;
|
||||
int pum_nlines; /// actual nr. lines shown in PUM
|
||||
bool pum_pos; /// UI reports back pum position?
|
||||
double pum_row;
|
||||
double pum_col;
|
||||
double pum_height;
|
||||
double pum_width;
|
||||
void *data;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
|
@ -8,7 +8,7 @@ local command = helpers.command
|
||||
local funcs = helpers.funcs
|
||||
local get_pathsep = helpers.get_pathsep
|
||||
local eq = helpers.eq
|
||||
local matches = helpers.matches
|
||||
local pcall_err = helpers.pcall_err
|
||||
|
||||
describe('ui/ext_popupmenu', function()
|
||||
local screen
|
||||
@ -382,7 +382,7 @@ describe('ui/ext_popupmenu', function()
|
||||
end
|
||||
|
||||
describe('pum_set_height', function()
|
||||
it('can be set pum height', function()
|
||||
it('can set pum height', function()
|
||||
source_complete_month()
|
||||
local month_expected = {
|
||||
{'January', '', '', ''},
|
||||
@ -421,22 +421,79 @@ describe('ui/ext_popupmenu', function()
|
||||
end)
|
||||
|
||||
it('an error occurs if set 0 or less', function()
|
||||
local ok, err, _
|
||||
ok, _ = pcall(meths.ui_pum_set_height, 1)
|
||||
eq(ok, true)
|
||||
ok, err = pcall(meths.ui_pum_set_height, 0)
|
||||
eq(ok, false)
|
||||
matches('.*: Expected pum height > 0', err)
|
||||
meths.ui_pum_set_height(1)
|
||||
eq('Expected pum height > 0',
|
||||
pcall_err(meths.ui_pum_set_height, 0))
|
||||
end)
|
||||
|
||||
it('an error occurs when ext_popupmenu is false', function()
|
||||
local ok, err, _
|
||||
ok, _ = pcall(meths.ui_pum_set_height, 1)
|
||||
eq(ok, true)
|
||||
meths.ui_pum_set_height(1)
|
||||
screen:set_option('ext_popupmenu', false)
|
||||
ok, err = pcall(meths.ui_pum_set_height, 1)
|
||||
eq(ok, false)
|
||||
matches('.*: It must support the ext_popupmenu option', err)
|
||||
eq('It must support the ext_popupmenu option',
|
||||
pcall_err(meths.ui_pum_set_height, 1))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('pum_set_bounds', function()
|
||||
it('can set pum bounds', function()
|
||||
source_complete_month()
|
||||
local month_expected = {
|
||||
{'January', '', '', ''},
|
||||
{'February', '', '', ''},
|
||||
{'March', '', '', ''},
|
||||
{'April', '', '', ''},
|
||||
{'May', '', '', ''},
|
||||
{'June', '', '', ''},
|
||||
{'July', '', '', ''},
|
||||
{'August', '', '', ''},
|
||||
{'September', '', '', ''},
|
||||
{'October', '', '', ''},
|
||||
{'November', '', '', ''},
|
||||
{'December', '', '', ''},
|
||||
}
|
||||
local pum_height = 6
|
||||
feed('o<C-r>=TestCompleteMonth()<CR>')
|
||||
meths.ui_pum_set_height(pum_height)
|
||||
-- set bounds w h r c
|
||||
meths.ui_pum_set_bounds(10.5, 5.2, 6.3, 7.4)
|
||||
feed('<PageDown>')
|
||||
-- pos becomes pum_height-2 because it is subtracting 2 to keep some
|
||||
-- context in ins_compl_key2count()
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
January^ |
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{2:-- INSERT --} |
|
||||
]], popupmenu={
|
||||
items=month_expected,
|
||||
pos=pum_height-2,
|
||||
anchor={1,1,0},
|
||||
}}
|
||||
end)
|
||||
|
||||
it('no error occurs if row or col set less than 0', function()
|
||||
meths.ui_pum_set_bounds(1.0, 1.0, 0.0, 1.5)
|
||||
meths.ui_pum_set_bounds(1.0, 1.0, -1.0, 0.0)
|
||||
meths.ui_pum_set_bounds(1.0, 1.0, 0.0, -1.0)
|
||||
end)
|
||||
|
||||
it('an error occurs if width or height set 0 or less', function()
|
||||
meths.ui_pum_set_bounds(1.0, 1.0, 0.0, 1.5)
|
||||
eq('Expected width > 0',
|
||||
pcall_err(meths.ui_pum_set_bounds, 0.0, 1.0, 1.0, 0.0))
|
||||
eq('Expected height > 0',
|
||||
pcall_err(meths.ui_pum_set_bounds, 1.0, -1.0, 1.0, 0.0))
|
||||
end)
|
||||
|
||||
it('an error occurs when ext_popupmenu is false', function()
|
||||
meths.ui_pum_set_bounds(1.0, 1.0, 0.0, 1.5)
|
||||
screen:set_option('ext_popupmenu', false)
|
||||
eq('UI must support the ext_popupmenu option',
|
||||
pcall_err(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5))
|
||||
end)
|
||||
end)
|
||||
|
||||
|
@ -2026,6 +2026,26 @@ describe('typval.c', function()
|
||||
alloc_log:check({})
|
||||
end)
|
||||
end)
|
||||
describe('float()', function()
|
||||
itp('works', function()
|
||||
local d = dict({test=10})
|
||||
alloc_log:clear()
|
||||
eq({test=10}, dct2tbl(d))
|
||||
eq(OK, lib.tv_dict_add_float(d, 'testt', 3, 1.5))
|
||||
local dis = dict_items(d)
|
||||
alloc_log:check({a.di(dis.tes, 'tes')})
|
||||
eq({test=10, tes=1.5}, dct2tbl(d))
|
||||
eq(FAIL, check_emsg(function() return lib.tv_dict_add_float(d, 'testt', 3, 1.5) end,
|
||||
'E685: Internal error: hash_add()'))
|
||||
alloc_log:clear()
|
||||
lib.emsg_skip = lib.emsg_skip + 1
|
||||
eq(FAIL, check_emsg(function() return lib.tv_dict_add_float(d, 'testt', 3, 1.5) end,
|
||||
nil))
|
||||
lib.emsg_skip = lib.emsg_skip - 1
|
||||
alloc_log:clear_tmp_allocs()
|
||||
alloc_log:check({})
|
||||
end)
|
||||
end)
|
||||
describe('str()', function()
|
||||
itp('works', function()
|
||||
local d = dict({test=10})
|
||||
|
Loading…
Reference in New Issue
Block a user