mirror of
https://github.com/neovim/neovim.git
synced 2026-02-20 01:09:56 +10:00
fix(pum): hide info floating window when insufficient space (#37107)
fix(pum): hide info window when insufficient space Problem: 1. Info window was displayed even with insufficient space. 2. Tab characters counted as single cells. Solution: 1. Hide window when space < 10 columns. Will be configurable via completepopup width option in the future. 2. Use win_linetabsize over mb_string2cells.
This commit is contained in:
@@ -910,15 +910,16 @@ void pum_redraw(void)
|
||||
/// Set the informational text in the preview buffer when the completion
|
||||
/// item does not include a dedicated preview or popup window.
|
||||
///
|
||||
/// @param[in] buf Buffer where the text will be set.
|
||||
/// @param[in] win Window containing buffer where the text will be set.
|
||||
/// @param[in] info Informational text to display in the preview buffer.
|
||||
/// @param[in] lnum Where to start the text. Incremented for each added line.
|
||||
/// @param[out] max_width Maximum width of the displayed text.
|
||||
static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *max_width)
|
||||
static void pum_preview_set_text(win_T *win, char *info, linenr_T *lnum, int *max_width)
|
||||
{
|
||||
Error err = ERROR_INIT;
|
||||
Arena arena = ARENA_EMPTY;
|
||||
Array replacement = ARRAY_DICT_INIT;
|
||||
buf_T *buf = win->w_buffer;
|
||||
buf->b_p_ma = true;
|
||||
|
||||
// Iterate through the string line by line by temporarily replacing newlines with NUL
|
||||
@@ -931,7 +932,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma
|
||||
break;
|
||||
}
|
||||
|
||||
*max_width = MAX(*max_width, (int)mb_string2cells(curr));
|
||||
*max_width = MAX(*max_width, win_linetabsize(win, 0, curr, MAXCOL));
|
||||
ADD(replacement, STRING_OBJ(cstr_to_string(curr)));
|
||||
(*lnum)++;
|
||||
|
||||
@@ -941,9 +942,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma
|
||||
}
|
||||
|
||||
int original_textlock = textlock;
|
||||
if (textlock > 0) {
|
||||
textlock = 0;
|
||||
}
|
||||
textlock = 0;
|
||||
nvim_buf_set_lines(0, buf->handle, 0, -1, false, replacement, &arena, &err);
|
||||
textlock = original_textlock;
|
||||
if (ERROR_SET(&err)) {
|
||||
@@ -956,7 +955,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma
|
||||
}
|
||||
|
||||
/// adjust floating info preview window position
|
||||
static void pum_adjust_info_position(win_T *wp, int width)
|
||||
static bool pum_adjust_info_position(win_T *wp, int width)
|
||||
{
|
||||
int border_width = pum_border_width();
|
||||
int col = pum_col + pum_width + 1 + MAX(border_width, pum_scrollbar);
|
||||
@@ -965,6 +964,14 @@ static void pum_adjust_info_position(win_T *wp, int width)
|
||||
int right_extra = Columns - col;
|
||||
int left_extra = pum_col - 2;
|
||||
|
||||
int max_extra = MAX(right_extra, left_extra);
|
||||
// Close info window if there's insufficient space
|
||||
// TODO(glepnir): Replace the hardcoded value (10) with values from the 'completepopup' width/height options.
|
||||
if (max_extra < 10) {
|
||||
wp->w_config.hide = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (right_extra > width) { // place in right
|
||||
wp->w_config.width = width;
|
||||
wp->w_config.col = col - 1;
|
||||
@@ -973,7 +980,7 @@ static void pum_adjust_info_position(win_T *wp, int width)
|
||||
wp->w_config.col = pum_col - wp->w_config.width - 1;
|
||||
} else { // either width is enough just use the biggest one.
|
||||
const bool place_in_right = right_extra > left_extra;
|
||||
wp->w_config.width = place_in_right ? right_extra : left_extra;
|
||||
wp->w_config.width = max_extra;
|
||||
wp->w_config.col = place_in_right ? col - 1 : pum_col - wp->w_config.width - 1;
|
||||
}
|
||||
// when pum_above is SW otherwise is NW
|
||||
@@ -984,6 +991,7 @@ static void pum_adjust_info_position(win_T *wp, int width)
|
||||
wp->w_config.row = pum_above ? pum_row + wp->w_config.height : pum_row;
|
||||
wp->w_config.hide = false;
|
||||
win_config_float(wp, wp->w_config);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Used for nvim__complete_set
|
||||
@@ -1010,12 +1018,14 @@ win_T *pum_set_info(int selected, char *info)
|
||||
}
|
||||
linenr_T lnum = 0;
|
||||
int max_info_width = 0;
|
||||
pum_preview_set_text(wp->w_buffer, info, &lnum, &max_info_width);
|
||||
pum_preview_set_text(wp, info, &lnum, &max_info_width);
|
||||
no_u_sync--;
|
||||
RedrawingDisabled--;
|
||||
redraw_later(wp, UPD_NOT_VALID);
|
||||
|
||||
pum_adjust_info_position(wp, max_info_width);
|
||||
if (!pum_adjust_info_position(wp, max_info_width)) {
|
||||
wp = NULL;
|
||||
}
|
||||
unblock_autocmds();
|
||||
return wp;
|
||||
}
|
||||
@@ -1167,7 +1177,7 @@ static bool pum_set_selected(int n, int repeat)
|
||||
if (res == OK) {
|
||||
linenr_T lnum = 0;
|
||||
int max_info_width = 0;
|
||||
pum_preview_set_text(curbuf, pum_array[pum_selected].pum_info, &lnum, &max_info_width);
|
||||
pum_preview_set_text(curwin, pum_array[pum_selected].pum_info, &lnum, &max_info_width);
|
||||
// Increase the height of the preview window to show the
|
||||
// text, but no more than 'previewheight' lines.
|
||||
if (repeat == 0 && !use_float) {
|
||||
@@ -1191,7 +1201,9 @@ static bool pum_set_selected(int n, int repeat)
|
||||
|
||||
if (use_float) {
|
||||
// adjust floating window by actually height and max info text width
|
||||
pum_adjust_info_position(curwin, max_info_width);
|
||||
if (!pum_adjust_info_position(curwin, max_info_width) && win_valid(curwin_save)) {
|
||||
win_enter(curwin_save, false);
|
||||
}
|
||||
}
|
||||
|
||||
if ((curwin != curwin_save && win_valid(curwin_save))
|
||||
|
||||
@@ -2238,6 +2238,41 @@ describe('builtin popupmenu', function()
|
||||
feed('S<C-x><C-o><C-N>')
|
||||
eq(1, n.eval([[len(uniq(copy(g:bufnrs))) == 1]]))
|
||||
end)
|
||||
|
||||
it('handles tabs in info width calculation', function()
|
||||
screen:try_resize(50, 11)
|
||||
command([[
|
||||
set cot+=menuone
|
||||
let g:list = [#{word: 'class', info: "\tClassName() = default;"}]
|
||||
]])
|
||||
feed('S<C-x><C-o>')
|
||||
local info = fn.complete_info()
|
||||
eq(30, api.nvim_win_get_width(info.preview_winid))
|
||||
feed('<ESC>')
|
||||
exec([[
|
||||
setlocal tabstop=1
|
||||
autocmd ModeChanged *:i ++once call complete(1, [#{word: 'a'}])
|
||||
\| call nvim__complete_set(0, #{info: "\tfloob\tfloob"})
|
||||
]])
|
||||
feed('i')
|
||||
info = fn.complete_info()
|
||||
eq(21, api.nvim_win_get_width(info.preview_winid))
|
||||
if not multigrid then
|
||||
screen:expect([[
|
||||
a^s |
|
||||
{12:a }{n: floob floob}{1: }|
|
||||
{1:~ }|*8
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
end
|
||||
end)
|
||||
|
||||
it('hide info window when insufficient space', function()
|
||||
screen:try_resize(12, 11)
|
||||
feed('S<C-x><C-o>')
|
||||
local info = fn.complete_info()
|
||||
eq(true, api.nvim_win_get_config(info.preview_winid).hide)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('with vsplits', function()
|
||||
|
||||
Reference in New Issue
Block a user