mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 02:34:59 -07:00
Merge pull request #24723 from glepnir/popup
feat(complete): completeopt support popup like vim
This commit is contained in:
commit
5ed55ff14c
@ -700,6 +700,21 @@ nvim_chan_send({chan}, {data}) *nvim_chan_send()*
|
|||||||
• {chan} id of the channel
|
• {chan} id of the channel
|
||||||
• {data} data to write. 8-bit clean: can contain NUL bytes.
|
• {data} data to write. 8-bit clean: can contain NUL bytes.
|
||||||
|
|
||||||
|
nvim_complete_set({index}, {*opts}) *nvim_complete_set()*
|
||||||
|
Set info for the completion candidate index. if the info was shown in a
|
||||||
|
window, then the window and buffer ids are returned for further
|
||||||
|
customization. If the text was not shown, an empty dict is returned.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
• {index} the completion candidate index
|
||||||
|
• {opts} Optional parameters.
|
||||||
|
• info: (string) info text.
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
Dictionary containing these keys:
|
||||||
|
• winid: (number) floating window id
|
||||||
|
• bufnr: (number) buffer id in floating window
|
||||||
|
|
||||||
nvim_create_buf({listed}, {scratch}) *nvim_create_buf()*
|
nvim_create_buf({listed}, {scratch}) *nvim_create_buf()*
|
||||||
Creates a new, empty, unnamed buffer.
|
Creates a new, empty, unnamed buffer.
|
||||||
|
|
||||||
|
2
runtime/doc/builtin.txt
generated
2
runtime/doc/builtin.txt
generated
@ -802,6 +802,8 @@ complete_info([{what}]) *complete_info()*
|
|||||||
no item is selected when using the <Up> or
|
no item is selected when using the <Up> or
|
||||||
<Down> keys)
|
<Down> keys)
|
||||||
inserted Inserted string. [NOT IMPLEMENTED YET]
|
inserted Inserted string. [NOT IMPLEMENTED YET]
|
||||||
|
preview_winid Info floating preview window id.
|
||||||
|
preview_bufnr Info floating preview buffer id.
|
||||||
|
|
||||||
*complete_info_mode*
|
*complete_info_mode*
|
||||||
mode values are:
|
mode values are:
|
||||||
|
@ -252,6 +252,9 @@ The following new APIs and features were added.
|
|||||||
• |vim.text.hexencode()| and |vim.text.hexdecode()| convert strings to and
|
• |vim.text.hexencode()| and |vim.text.hexdecode()| convert strings to and
|
||||||
from byte representations.
|
from byte representations.
|
||||||
|
|
||||||
|
• 'completeopt' option supports "popup" flags to show extra information in
|
||||||
|
in floating window.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
CHANGED FEATURES *news-changed*
|
CHANGED FEATURES *news-changed*
|
||||||
|
|
||||||
|
@ -1516,6 +1516,10 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
select one from the menu. Only works in combination with
|
select one from the menu. Only works in combination with
|
||||||
"menu" or "menuone".
|
"menu" or "menuone".
|
||||||
|
|
||||||
|
popup Show extra information about the currently selected
|
||||||
|
completion in a popup window. Only works in combination
|
||||||
|
with "menu" or "menuone". Overrides "preview".
|
||||||
|
|
||||||
*'completeslash'* *'csl'*
|
*'completeslash'* *'csl'*
|
||||||
'completeslash' 'csl' string (default "")
|
'completeslash' 'csl' string (default "")
|
||||||
local to buffer
|
local to buffer
|
||||||
|
10
runtime/lua/vim/_meta/api.lua
generated
10
runtime/lua/vim/_meta/api.lua
generated
@ -773,6 +773,16 @@ function vim.api.nvim_command(command) end
|
|||||||
--- @return string
|
--- @return string
|
||||||
function vim.api.nvim_command_output(command) end
|
function vim.api.nvim_command_output(command) end
|
||||||
|
|
||||||
|
--- Set info for the completion candidate index. if the info was shown in a
|
||||||
|
--- window, then the window and buffer ids are returned for further
|
||||||
|
--- customization. If the text was not shown, an empty dict is returned.
|
||||||
|
---
|
||||||
|
--- @param index integer the completion candidate index
|
||||||
|
--- @param opts vim.api.keyset.complete_set Optional parameters.
|
||||||
|
--- • info: (string) info text.
|
||||||
|
--- @return table<string,any>
|
||||||
|
function vim.api.nvim_complete_set(index, opts) end
|
||||||
|
|
||||||
--- Create or get an autocommand group `autocmd-groups`.
|
--- Create or get an autocommand group `autocmd-groups`.
|
||||||
--- To get an existing group id, do:
|
--- To get an existing group id, do:
|
||||||
---
|
---
|
||||||
|
3
runtime/lua/vim/_meta/api_keysets.lua
generated
3
runtime/lua/vim/_meta/api_keysets.lua
generated
@ -68,6 +68,9 @@ error('Cannot require a meta file')
|
|||||||
--- @class vim.api.keyset.cmd_opts
|
--- @class vim.api.keyset.cmd_opts
|
||||||
--- @field output? boolean
|
--- @field output? boolean
|
||||||
|
|
||||||
|
--- @class vim.api.keyset.complete_set
|
||||||
|
--- @field info? string
|
||||||
|
|
||||||
--- @class vim.api.keyset.context
|
--- @class vim.api.keyset.context
|
||||||
--- @field types? any[]
|
--- @field types? any[]
|
||||||
|
|
||||||
|
4
runtime/lua/vim/_meta/options.lua
generated
4
runtime/lua/vim/_meta/options.lua
generated
@ -1061,6 +1061,10 @@ vim.bo.cfu = vim.bo.completefunc
|
|||||||
--- select one from the menu. Only works in combination with
|
--- select one from the menu. Only works in combination with
|
||||||
--- "menu" or "menuone".
|
--- "menu" or "menuone".
|
||||||
---
|
---
|
||||||
|
--- popup Show extra information about the currently selected
|
||||||
|
--- completion in a popup window. Only works in combination
|
||||||
|
--- with "menu" or "menuone". Overrides "preview".
|
||||||
|
---
|
||||||
--- @type string
|
--- @type string
|
||||||
vim.o.completeopt = "menu,preview"
|
vim.o.completeopt = "menu,preview"
|
||||||
vim.o.cot = vim.o.completeopt
|
vim.o.cot = vim.o.completeopt
|
||||||
|
2
runtime/lua/vim/_meta/vimfn.lua
generated
2
runtime/lua/vim/_meta/vimfn.lua
generated
@ -1024,6 +1024,8 @@ function vim.fn.complete_check() end
|
|||||||
--- no item is selected when using the <Up> or
|
--- no item is selected when using the <Up> or
|
||||||
--- <Down> keys)
|
--- <Down> keys)
|
||||||
--- inserted Inserted string. [NOT IMPLEMENTED YET]
|
--- inserted Inserted string. [NOT IMPLEMENTED YET]
|
||||||
|
--- preview_winid Info floating preview window id.
|
||||||
|
--- preview_bufnr Info floating preview buffer id.
|
||||||
---
|
---
|
||||||
--- *complete_info_mode*
|
--- *complete_info_mode*
|
||||||
--- mode values are:
|
--- mode values are:
|
||||||
|
@ -346,3 +346,8 @@ typedef struct {
|
|||||||
LuaRef on_input;
|
LuaRef on_input;
|
||||||
Boolean force_crlf;
|
Boolean force_crlf;
|
||||||
} Dict(open_term);
|
} Dict(open_term);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
OptionalKeys is_set__complete_set_;
|
||||||
|
String info;
|
||||||
|
} Dict(complete_set);
|
||||||
|
@ -2300,3 +2300,29 @@ void nvim_error_event(uint64_t channel_id, Integer lvl, String data)
|
|||||||
// if we fork nvim processes as async workers
|
// if we fork nvim processes as async workers
|
||||||
ELOG("async error on channel %" PRId64 ": %s", channel_id, data.size ? data.data : "");
|
ELOG("async error on channel %" PRId64 ": %s", channel_id, data.size ? data.data : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set info for the completion candidate index.
|
||||||
|
/// if the info was shown in a window, then the
|
||||||
|
/// window and buffer ids are returned for further
|
||||||
|
/// customization. If the text was not shown, an
|
||||||
|
/// empty dict is returned.
|
||||||
|
///
|
||||||
|
/// @param index the completion candidate index
|
||||||
|
/// @param opts Optional parameters.
|
||||||
|
/// - info: (string) info text.
|
||||||
|
/// @return Dictionary containing these keys:
|
||||||
|
/// - winid: (number) floating window id
|
||||||
|
/// - bufnr: (number) buffer id in floating window
|
||||||
|
Dictionary nvim_complete_set(Integer index, Dict(complete_set) *opts)
|
||||||
|
FUNC_API_SINCE(12)
|
||||||
|
{
|
||||||
|
Dictionary rv = ARRAY_DICT_INIT;
|
||||||
|
if (HAS_KEY(opts, complete_set, info)) {
|
||||||
|
win_T *wp = pum_set_info((int)index, opts->info.data);
|
||||||
|
if (wp) {
|
||||||
|
PUT(rv, "winid", WINDOW_OBJ(wp->handle));
|
||||||
|
PUT(rv, "bufnr", BUFFER_OBJ(wp->w_buffer->handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
@ -1286,7 +1286,8 @@ struct window_S {
|
|||||||
ScreenGrid w_grid; // the grid specific to the window
|
ScreenGrid w_grid; // the grid specific to the window
|
||||||
ScreenGrid w_grid_alloc; // the grid specific to the window
|
ScreenGrid w_grid_alloc; // the grid specific to the window
|
||||||
bool w_pos_changed; // true if window position changed
|
bool w_pos_changed; // true if window position changed
|
||||||
bool w_floating; ///< whether the window is floating
|
bool w_floating; ///< whether the window is floating
|
||||||
|
bool w_float_is_info; // the floating window is info float
|
||||||
FloatConfig w_float_config;
|
FloatConfig w_float_config;
|
||||||
|
|
||||||
// w_fraction is the fractional row of the cursor within the window, from
|
// w_fraction is the fractional row of the cursor within the window, from
|
||||||
|
@ -1373,6 +1373,8 @@ M.funcs = {
|
|||||||
no item is selected when using the <Up> or
|
no item is selected when using the <Up> or
|
||||||
<Down> keys)
|
<Down> keys)
|
||||||
inserted Inserted string. [NOT IMPLEMENTED YET]
|
inserted Inserted string. [NOT IMPLEMENTED YET]
|
||||||
|
preview_winid Info floating preview window id.
|
||||||
|
preview_bufnr Info floating preview buffer id.
|
||||||
|
|
||||||
*complete_info_mode*
|
*complete_info_mode*
|
||||||
mode values are:
|
mode values are:
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/vim_defs.h"
|
#include "nvim/vim_defs.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
|
#include "nvim/winfloat.h"
|
||||||
|
|
||||||
// Definitions used for CTRL-X submode.
|
// Definitions used for CTRL-X submode.
|
||||||
// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
|
// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
|
||||||
@ -1290,6 +1291,28 @@ void ins_compl_show_pum(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// used for set or update info
|
||||||
|
void compl_set_info(int pum_idx)
|
||||||
|
{
|
||||||
|
compl_T *comp = compl_first_match;
|
||||||
|
char *pum_text = compl_match_array[pum_idx].pum_text;
|
||||||
|
|
||||||
|
while (comp != NULL) {
|
||||||
|
if (pum_text == comp->cp_str
|
||||||
|
|| pum_text == comp->cp_text[CPT_ABBR]) {
|
||||||
|
comp->cp_text[CPT_INFO] = compl_match_array[pum_idx].pum_info;
|
||||||
|
|
||||||
|
// if comp is current match update completed_item value
|
||||||
|
if (comp == compl_curr_match) {
|
||||||
|
dict_T *dict = ins_compl_dict_alloc(compl_curr_match);
|
||||||
|
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
comp = comp->cp_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define DICT_FIRST (1) ///< use just first element in "dict"
|
#define DICT_FIRST (1) ///< use just first element in "dict"
|
||||||
#define DICT_EXACT (2) ///< "dict" is the exact name of a file
|
#define DICT_EXACT (2) ///< "dict" is the exact name of a file
|
||||||
|
|
||||||
@ -2813,6 +2836,11 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
|
|||||||
ret = tv_dict_add_nr(retdict, S_LEN("selected"),
|
ret = tv_dict_add_nr(retdict, S_LEN("selected"),
|
||||||
(compl_curr_match != NULL)
|
(compl_curr_match != NULL)
|
||||||
? compl_curr_match->cp_number - 1 : -1);
|
? compl_curr_match->cp_number - 1 : -1);
|
||||||
|
win_T *wp = win_float_find_preview();
|
||||||
|
if (wp != NULL) {
|
||||||
|
tv_dict_add_nr(retdict, S_LEN("preview_winid"), wp->handle);
|
||||||
|
tv_dict_add_nr(retdict, S_LEN("preview_bufnr"), wp->w_buffer->handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)ret;
|
(void)ret;
|
||||||
|
@ -1450,6 +1450,10 @@ return {
|
|||||||
noselect Do not select a match in the menu, force the user to
|
noselect Do not select a match in the menu, force the user to
|
||||||
select one from the menu. Only works in combination with
|
select one from the menu. Only works in combination with
|
||||||
"menu" or "menuone".
|
"menu" or "menuone".
|
||||||
|
|
||||||
|
popup Show extra information about the currently selected
|
||||||
|
completion in a popup window. Only works in combination
|
||||||
|
with "menu" or "menuone". Overrides "preview".
|
||||||
]=],
|
]=],
|
||||||
expand_cb = 'expand_set_completeopt',
|
expand_cb = 'expand_set_completeopt',
|
||||||
full_name = 'completeopt',
|
full_name = 'completeopt',
|
||||||
|
@ -116,7 +116,7 @@ static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
|
|||||||
"syntax", "diff", NULL };
|
"syntax", "diff", NULL };
|
||||||
static char *(p_fcl_values[]) = { "all", NULL };
|
static char *(p_fcl_values[]) = { "all", NULL };
|
||||||
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect",
|
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect",
|
||||||
NULL };
|
"popup", NULL };
|
||||||
#ifdef BACKSLASH_IN_FILENAME
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
static char *(p_csl_values[]) = { "slash", "backslash", NULL };
|
static char *(p_csl_values[]) = { "slash", "backslash", NULL };
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,8 +8,11 @@
|
|||||||
|
|
||||||
#include "nvim/api/private/defs.h"
|
#include "nvim/api/private/defs.h"
|
||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
|
#include "nvim/api/vim.h"
|
||||||
#include "nvim/ascii_defs.h"
|
#include "nvim/ascii_defs.h"
|
||||||
|
#include "nvim/autocmd.h"
|
||||||
#include "nvim/buffer.h"
|
#include "nvim/buffer.h"
|
||||||
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
#include "nvim/eval/typval.h"
|
#include "nvim/eval/typval.h"
|
||||||
@ -29,6 +32,8 @@
|
|||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/option_vars.h"
|
#include "nvim/option_vars.h"
|
||||||
|
#include "nvim/optionstr.h"
|
||||||
|
#include "nvim/plines.h"
|
||||||
#include "nvim/popupmenu.h"
|
#include "nvim/popupmenu.h"
|
||||||
#include "nvim/pos_defs.h"
|
#include "nvim/pos_defs.h"
|
||||||
#include "nvim/state_defs.h"
|
#include "nvim/state_defs.h"
|
||||||
@ -37,6 +42,7 @@
|
|||||||
#include "nvim/ui_compositor.h"
|
#include "nvim/ui_compositor.h"
|
||||||
#include "nvim/vim_defs.h"
|
#include "nvim/vim_defs.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
|
#include "nvim/winfloat.h"
|
||||||
|
|
||||||
static pumitem_T *pum_array = NULL; // items of displayed pum
|
static pumitem_T *pum_array = NULL; // items of displayed pum
|
||||||
static int pum_size; // nr of items in "pum_array"
|
static int pum_size; // nr of items in "pum_array"
|
||||||
@ -654,6 +660,142 @@ void pum_redraw(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// create a floting preview window for info
|
||||||
|
/// @return NULL when no enough room to show
|
||||||
|
static win_T *pum_create_float_preview(bool enter)
|
||||||
|
{
|
||||||
|
FloatConfig config = FLOAT_CONFIG_INIT;
|
||||||
|
config.relative = kFloatRelativeEditor;
|
||||||
|
// when pum_above is SW otherwise is NW
|
||||||
|
config.anchor = pum_above ? kFloatAnchorSouth : 0;
|
||||||
|
int col = pum_col + pum_width + pum_scrollbar + 1;
|
||||||
|
// TODO(glepnir): support config align border by using completepopup
|
||||||
|
// align menu
|
||||||
|
config.row = pum_row;
|
||||||
|
int right_extra = Columns - col;
|
||||||
|
if (right_extra > 0) {
|
||||||
|
config.width = right_extra;
|
||||||
|
config.col = col - 1;
|
||||||
|
} else if (pum_col - 2 > 0) {
|
||||||
|
config.width = pum_col - 2;
|
||||||
|
config.col = pum_col - config.width - 1;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
config.height = pum_height;
|
||||||
|
config.style = kWinStyleMinimal;
|
||||||
|
config.hide = true;
|
||||||
|
Error err = ERROR_INIT;
|
||||||
|
win_T *wp = win_new_float(NULL, true, config, &err);
|
||||||
|
// TODO(glepnir): remove win_enter usage
|
||||||
|
if (enter) {
|
||||||
|
win_enter(wp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new buffer
|
||||||
|
Buffer b = nvim_create_buf(false, true, &err);
|
||||||
|
if (!b) {
|
||||||
|
win_free(wp, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buf_T *buf = find_buffer_by_handle(b, &err);
|
||||||
|
set_string_option_direct_in_buf(buf, kOptBufhidden, "wipe", OPT_FREE | OPT_LOCAL, 0);
|
||||||
|
wp->w_float_is_info = true;
|
||||||
|
wp->w_p_diff = false;
|
||||||
|
buf->b_p_bl = false;
|
||||||
|
win_set_buf(wp, buf, true, &err);
|
||||||
|
return wp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set info text to preview buffer.
|
||||||
|
static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *max_width)
|
||||||
|
{
|
||||||
|
for (char *p = info; *p != NUL;) {
|
||||||
|
int text_width = 0;
|
||||||
|
char *e = vim_strchr(p, '\n');
|
||||||
|
if (e == NULL) {
|
||||||
|
ml_append_buf(buf, (*lnum)++, p, 0, false);
|
||||||
|
text_width = (int)mb_string2cells(p);
|
||||||
|
if (text_width > *max_width) {
|
||||||
|
*max_width = text_width;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*e = NUL;
|
||||||
|
ml_append_buf(buf, (*lnum)++, p, (int)(e - p + 1), false);
|
||||||
|
text_width = (int)mb_string2cells(p);
|
||||||
|
if (text_width > *max_width) {
|
||||||
|
*max_width = text_width;
|
||||||
|
}
|
||||||
|
*e = '\n';
|
||||||
|
p = e + 1;
|
||||||
|
}
|
||||||
|
// delete the empty last line
|
||||||
|
ml_delete_buf(buf, buf->b_ml.ml_line_count, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// adjust floating preview window width and height
|
||||||
|
static void pum_adjust_float_position(win_T *wp, int height, int width)
|
||||||
|
{
|
||||||
|
// when floating window in right and right no enough room to show
|
||||||
|
// but left has enough room, adjust floating window to left.
|
||||||
|
if (wp->w_float_config.width < width && wp->w_float_config.col > pum_col) {
|
||||||
|
if ((pum_col - 2) > width) {
|
||||||
|
wp->w_float_config.width = width;
|
||||||
|
wp->w_float_config.col = pum_col - width - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wp->w_float_config.width = MIN(wp->w_float_config.width, width);
|
||||||
|
wp->w_float_config.height = MIN(Rows, height);
|
||||||
|
wp->w_float_config.hide = false;
|
||||||
|
win_config_float(wp, wp->w_float_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// used in nvim_complete_set
|
||||||
|
win_T *pum_set_info(int pum_idx, char *info)
|
||||||
|
{
|
||||||
|
if (!pum_is_visible || pum_idx < 0 || pum_idx > pum_size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pum_array[pum_idx].pum_info = xstrdup(info);
|
||||||
|
compl_set_info(pum_idx);
|
||||||
|
bool use_float = strstr(p_cot, "popup") != NULL ? true : false;
|
||||||
|
if (pum_idx != pum_selected || !use_float) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_autocmds();
|
||||||
|
RedrawingDisabled++;
|
||||||
|
no_u_sync++;
|
||||||
|
win_T *wp = win_float_find_preview();
|
||||||
|
if (wp == NULL) {
|
||||||
|
wp = pum_create_float_preview(false);
|
||||||
|
// no enough room to show
|
||||||
|
if (!wp) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// clean exist buffer
|
||||||
|
while (!buf_is_empty(wp->w_buffer)) {
|
||||||
|
ml_delete_buf(wp->w_buffer, (linenr_T)1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
no_u_sync--;
|
||||||
|
RedrawingDisabled--;
|
||||||
|
|
||||||
|
linenr_T lnum = 0;
|
||||||
|
int max_info_width = 0;
|
||||||
|
pum_preview_set_text(wp->w_buffer, info, &lnum, &max_info_width);
|
||||||
|
redraw_later(wp, UPD_SOME_VALID);
|
||||||
|
|
||||||
|
if (wp->w_p_wrap) {
|
||||||
|
lnum += plines_win(wp, lnum, true);
|
||||||
|
}
|
||||||
|
pum_adjust_float_position(wp, lnum, max_info_width);
|
||||||
|
unblock_autocmds();
|
||||||
|
return wp;
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the index of the currently selected item. The menu will scroll when
|
/// Set the index of the currently selected item. The menu will scroll when
|
||||||
/// necessary. When "n" is out of range don't scroll.
|
/// necessary. When "n" is out of range don't scroll.
|
||||||
/// This may be repeated when the preview window is used:
|
/// This may be repeated when the preview window is used:
|
||||||
@ -670,6 +812,7 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
{
|
{
|
||||||
int resized = false;
|
int resized = false;
|
||||||
int context = pum_height / 2;
|
int context = pum_height / 2;
|
||||||
|
int prev_selected = pum_selected;
|
||||||
|
|
||||||
pum_selected = n;
|
pum_selected = n;
|
||||||
|
|
||||||
@ -718,6 +861,10 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
pum_first = pum_selected + context - pum_height + 1;
|
pum_first = pum_selected + context - pum_height + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// adjust for the number of lines displayed
|
||||||
|
if (pum_first > pum_size - pum_height) {
|
||||||
|
pum_first = pum_size - pum_height;
|
||||||
|
}
|
||||||
|
|
||||||
// Show extra info in the preview window if there is something and
|
// Show extra info in the preview window if there is something and
|
||||||
// 'completeopt' contains "preview".
|
// 'completeopt' contains "preview".
|
||||||
@ -730,6 +877,11 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
&& (vim_strchr(p_cot, 'p') != NULL)) {
|
&& (vim_strchr(p_cot, 'p') != NULL)) {
|
||||||
win_T *curwin_save = curwin;
|
win_T *curwin_save = curwin;
|
||||||
tabpage_T *curtab_save = curtab;
|
tabpage_T *curtab_save = curtab;
|
||||||
|
bool use_float = strstr(p_cot, "popup") != NULL ? true : false;
|
||||||
|
|
||||||
|
if (use_float) {
|
||||||
|
block_autocmds();
|
||||||
|
}
|
||||||
|
|
||||||
// Open a preview window. 3 lines by default. Prefer
|
// Open a preview window. 3 lines by default. Prefer
|
||||||
// 'previewheight' if set and smaller.
|
// 'previewheight' if set and smaller.
|
||||||
@ -742,12 +894,26 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
// Prevent undo sync here, if an autocommand syncs undo weird
|
// Prevent undo sync here, if an autocommand syncs undo weird
|
||||||
// things can happen to the undo tree.
|
// things can happen to the undo tree.
|
||||||
no_u_sync++;
|
no_u_sync++;
|
||||||
resized = prepare_tagpreview(false);
|
|
||||||
|
if (!use_float) {
|
||||||
|
resized = prepare_tagpreview(false);
|
||||||
|
} else {
|
||||||
|
win_T *wp = win_float_find_preview();
|
||||||
|
if (wp) {
|
||||||
|
win_enter(wp, false);
|
||||||
|
} else {
|
||||||
|
wp = pum_create_float_preview(true);
|
||||||
|
if (wp) {
|
||||||
|
resized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
no_u_sync--;
|
no_u_sync--;
|
||||||
RedrawingDisabled--;
|
RedrawingDisabled--;
|
||||||
g_do_tagpreview = 0;
|
g_do_tagpreview = 0;
|
||||||
|
|
||||||
if (curwin->w_p_pvw) {
|
if (curwin->w_p_pvw || curwin->w_float_is_info) {
|
||||||
int res = OK;
|
int res = OK;
|
||||||
if (!resized
|
if (!resized
|
||||||
&& (curbuf->b_nwindows == 1)
|
&& (curbuf->b_nwindows == 1)
|
||||||
@ -777,22 +943,11 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
|
|
||||||
if (res == OK) {
|
if (res == OK) {
|
||||||
linenr_T lnum = 0;
|
linenr_T lnum = 0;
|
||||||
|
int max_info_width = 0;
|
||||||
for (char *p = pum_array[pum_selected].pum_info; *p != NUL;) {
|
pum_preview_set_text(curbuf, pum_array[pum_selected].pum_info, &lnum, &max_info_width);
|
||||||
char *e = vim_strchr(p, '\n');
|
|
||||||
if (e == NULL) {
|
|
||||||
ml_append(lnum++, p, 0, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*e = NUL;
|
|
||||||
ml_append(lnum++, p, (int)(e - p + 1), false);
|
|
||||||
*e = '\n';
|
|
||||||
p = e + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increase the height of the preview window to show the
|
// Increase the height of the preview window to show the
|
||||||
// text, but no more than 'previewheight' lines.
|
// text, but no more than 'previewheight' lines.
|
||||||
if (repeat == 0) {
|
if (repeat == 0 && !use_float) {
|
||||||
if (lnum > p_pvh) {
|
if (lnum > p_pvh) {
|
||||||
lnum = (linenr_T)p_pvh;
|
lnum = (linenr_T)p_pvh;
|
||||||
}
|
}
|
||||||
@ -805,9 +960,22 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
|
|
||||||
curbuf->b_changed = false;
|
curbuf->b_changed = false;
|
||||||
curbuf->b_p_ma = false;
|
curbuf->b_p_ma = false;
|
||||||
|
if (pum_selected != prev_selected) {
|
||||||
|
curwin->w_topline = 1;
|
||||||
|
} else if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
|
||||||
|
curwin->w_topline = curbuf->b_ml.ml_line_count;
|
||||||
|
}
|
||||||
curwin->w_cursor.lnum = 1;
|
curwin->w_cursor.lnum = 1;
|
||||||
curwin->w_cursor.col = 0;
|
curwin->w_cursor.col = 0;
|
||||||
|
|
||||||
|
if (use_float) {
|
||||||
|
if (curwin->w_p_wrap) {
|
||||||
|
lnum += plines_win(curwin, lnum, true);
|
||||||
|
}
|
||||||
|
// adjust floting window by actually height and max info text width
|
||||||
|
pum_adjust_float_position(curwin, lnum, max_info_width);
|
||||||
|
}
|
||||||
|
|
||||||
if ((curwin != curwin_save && win_valid(curwin_save))
|
if ((curwin != curwin_save && win_valid(curwin_save))
|
||||||
|| (curtab != curtab_save && valid_tabpage(curtab_save))) {
|
|| (curtab != curtab_save && valid_tabpage(curtab_save))) {
|
||||||
if (curtab != curtab_save && valid_tabpage(curtab_save)) {
|
if (curtab != curtab_save && valid_tabpage(curtab_save)) {
|
||||||
@ -829,7 +997,7 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
// update the view on the buffer. Only go back to
|
// update the view on the buffer. Only go back to
|
||||||
// the window when needed, otherwise it will always be
|
// the window when needed, otherwise it will always be
|
||||||
// redrawn.
|
// redrawn.
|
||||||
if (resized) {
|
if (resized && win_valid(curwin_save)) {
|
||||||
no_u_sync++;
|
no_u_sync++;
|
||||||
win_enter(curwin_save, true);
|
win_enter(curwin_save, true);
|
||||||
no_u_sync--;
|
no_u_sync--;
|
||||||
@ -858,6 +1026,10 @@ static bool pum_set_selected(int n, int repeat)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_float) {
|
||||||
|
unblock_autocmds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,6 +1064,10 @@ void pum_check_clear(void)
|
|||||||
}
|
}
|
||||||
pum_is_drawn = false;
|
pum_is_drawn = false;
|
||||||
pum_external = false;
|
pum_external = false;
|
||||||
|
win_T *wp = win_float_find_preview();
|
||||||
|
if (wp != NULL) {
|
||||||
|
win_close(wp, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
|
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/grid_defs.h"
|
#include "nvim/grid_defs.h"
|
||||||
#include "nvim/macros_defs.h"
|
#include "nvim/macros_defs.h"
|
||||||
|
@ -4978,7 +4978,7 @@ void free_wininfo(wininfo_T *wip, buf_T *bp)
|
|||||||
/// Remove window 'wp' from the window list and free the structure.
|
/// Remove window 'wp' from the window list and free the structure.
|
||||||
///
|
///
|
||||||
/// @param tp tab page "win" is in, NULL for current
|
/// @param tp tab page "win" is in, NULL for current
|
||||||
static void win_free(win_T *wp, tabpage_T *tp)
|
void win_free(win_T *wp, tabpage_T *tp)
|
||||||
{
|
{
|
||||||
pmap_del(int)(&window_handles, wp->handle, NULL);
|
pmap_del(int)(&window_handles, wp->handle, NULL);
|
||||||
clearFolding(wp);
|
clearFolding(wp);
|
||||||
|
@ -286,3 +286,13 @@ bool win_float_valid(const win_T *win)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
win_T *win_float_find_preview(void)
|
||||||
|
{
|
||||||
|
for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
|
||||||
|
if (wp->w_float_is_info) {
|
||||||
|
return wp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -1431,7 +1431,7 @@ describe('builtin popupmenu', function()
|
|||||||
feed('<C-N>')
|
feed('<C-N>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
1info |
|
1info |
|
||||||
|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{3:[Scratch] [Preview] }|
|
{3:[Scratch] [Preview] }|
|
||||||
one^ |
|
one^ |
|
||||||
@ -1469,6 +1469,208 @@ describe('builtin popupmenu', function()
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe("floating window preview #popup", function()
|
||||||
|
it('pum popup preview', function()
|
||||||
|
--row must > 10
|
||||||
|
screen:try_resize(30, 11)
|
||||||
|
exec([[
|
||||||
|
funct Omni_test(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return col(".") - 1
|
||||||
|
endif
|
||||||
|
return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three"}]
|
||||||
|
endfunc
|
||||||
|
set omnifunc=Omni_test
|
||||||
|
set completeopt=menu,popup
|
||||||
|
|
||||||
|
funct Set_info()
|
||||||
|
let comp_info = complete_info()
|
||||||
|
if comp_info['selected'] == 2
|
||||||
|
call nvim_complete_set(comp_info['selected'], {"info": "3info"})
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
autocmd CompleteChanged * call Set_info()
|
||||||
|
]])
|
||||||
|
feed('Gi<C-x><C-o>')
|
||||||
|
|
||||||
|
--floating preview in right
|
||||||
|
if multigrid then
|
||||||
|
screen:expect{grid=[[
|
||||||
|
## grid 1
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[3:------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
one^ |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
## grid 3
|
||||||
|
{2:-- }{5:match 1 of 3} |
|
||||||
|
## grid 4
|
||||||
|
{n:1info}|
|
||||||
|
{n: }|
|
||||||
|
## grid 5
|
||||||
|
{s:one }|
|
||||||
|
{n:two }|
|
||||||
|
{n:three }|
|
||||||
|
]], float_pos={
|
||||||
|
[5] = {{id = -1}, "NW", 2, 1, 0, false, 100};
|
||||||
|
[4] = {{id = 1001}, "NW", 1, 1, 15, true, 50};
|
||||||
|
}}
|
||||||
|
else
|
||||||
|
screen:expect{grid=[[
|
||||||
|
one^ |
|
||||||
|
{s:one }{n:1info}{1: }|
|
||||||
|
{n:two }{1: }|
|
||||||
|
{n:three }{1: }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{2:-- }{5:match 1 of 3} |
|
||||||
|
]], unchanged = true}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- test nvim_complete_set_info
|
||||||
|
feed('<C-N><C-N>')
|
||||||
|
helpers.sleep(10)
|
||||||
|
if multigrid then
|
||||||
|
screen:expect{grid=[[
|
||||||
|
## grid 1
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[3:------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
three^ |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
## grid 3
|
||||||
|
{2:-- }{5:match 3 of 3} |
|
||||||
|
## grid 4
|
||||||
|
{n:3info}|
|
||||||
|
{n: }|
|
||||||
|
## grid 5
|
||||||
|
{n:one }|
|
||||||
|
{n:two }|
|
||||||
|
{s:three }|
|
||||||
|
]], float_pos={
|
||||||
|
[5] = {{id = -1}, "NW", 2, 1, 0, false, 100};
|
||||||
|
[4] = {{id = 1001}, "NW", 1, 1, 15, true, 50};
|
||||||
|
}}
|
||||||
|
else
|
||||||
|
screen:expect{grid=[[
|
||||||
|
three^ |
|
||||||
|
{n:one 3info}{1: }|
|
||||||
|
{n:two }{1: }|
|
||||||
|
{s:three }{1: }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{2:-- }{5:match 3 of 3} |
|
||||||
|
]]}
|
||||||
|
end
|
||||||
|
-- make sure info has set
|
||||||
|
feed('<C-y>')
|
||||||
|
eq('3info', exec_lua('return vim.v.completed_item.info'))
|
||||||
|
|
||||||
|
-- preview in left
|
||||||
|
feed('<ESC>cc')
|
||||||
|
insert(('test'):rep(5))
|
||||||
|
feed('i<C-x><C-o>')
|
||||||
|
if multigrid then
|
||||||
|
screen:expect{grid=[[
|
||||||
|
## grid 1
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[3:------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
itesttesttesttesttesone^t |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
## grid 3
|
||||||
|
{2:-- }{5:match 1 of 3} |
|
||||||
|
## grid 5
|
||||||
|
{s: one }|
|
||||||
|
{n: two }|
|
||||||
|
{n: three }|
|
||||||
|
## grid 6
|
||||||
|
{n:1info}|
|
||||||
|
{n: }|
|
||||||
|
]], float_pos={
|
||||||
|
[5] = {{id = -1}, "NW", 2, 1, 19, false, 100};
|
||||||
|
[6] = {{id = 1002}, "NW", 1, 1, 1, true, 50};
|
||||||
|
}, win_viewport={
|
||||||
|
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 23, linecount = 1, sum_scroll_delta = 0};
|
||||||
|
[6] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
|
||||||
|
}}
|
||||||
|
else
|
||||||
|
screen:expect{grid=[[
|
||||||
|
itesttesttesttesttesone^t |
|
||||||
|
{1:~}{n:1info}{1: }{s: one }{1: }|
|
||||||
|
{1:~}{n: }{1: }{n: two }{1: }|
|
||||||
|
{1:~ }{n: three }{1: }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{2:-- }{5:match 1 of 3} |
|
||||||
|
]]}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
it('with vsplits', function()
|
it('with vsplits', function()
|
||||||
screen:try_resize(32, 8)
|
screen:try_resize(32, 8)
|
||||||
insert('aaa aab aac\n')
|
insert('aaa aab aac\n')
|
||||||
|
Loading…
Reference in New Issue
Block a user