aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/popupmenu.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
commit9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch)
tree607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /src/nvim/popupmenu.c
parent9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-usermarks.tar.gz
rneovim-usermarks.tar.bz2
rneovim-usermarks.zip
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'src/nvim/popupmenu.c')
-rw-r--r--src/nvim/popupmenu.c155
1 files changed, 100 insertions, 55 deletions
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index a4afe97ac8..245ce87865 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -6,27 +6,35 @@
/// Popup menu (PUM)
#include <assert.h>
-#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
+#include <string.h>
+#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
-#include "nvim/edit.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds.h"
+#include "nvim/getchar.h"
+#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/highlight.h"
#include "nvim/insexpand.h"
+#include "nvim/keycodes.h"
+#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/menu.h"
+#include "nvim/message.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/popupmenu.h"
-#include "nvim/search.h"
+#include "nvim/pos.h"
+#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
@@ -70,19 +78,19 @@ static void pum_compute_size(void)
for (int i = 0; i < pum_size; i++) {
int w;
if (pum_array[i].pum_text != NULL) {
- w = vim_strsize((char *)pum_array[i].pum_text);
+ w = vim_strsize(pum_array[i].pum_text);
if (pum_base_width < w) {
pum_base_width = w;
}
}
if (pum_array[i].pum_kind != NULL) {
- w = vim_strsize((char *)pum_array[i].pum_kind) + 1;
+ w = vim_strsize(pum_array[i].pum_kind) + 1;
if (pum_kind_width < w) {
pum_kind_width = w;
}
}
if (pum_array[i].pum_extra != NULL) {
- w = vim_strsize((char *)pum_array[i].pum_extra) + 1;
+ w = vim_strsize(pum_array[i].pum_extra) + 1;
if (pum_extra_width < w) {
pum_extra_width = w;
}
@@ -156,19 +164,18 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
if (pum_external) {
if (array_changed) {
Arena arena = ARENA_EMPTY;
- arena_start(&arena, &ui_ext_fixblk);
Array arr = arena_array(&arena, (size_t)size);
for (int i = 0; i < size; i++) {
Array item = arena_array(&arena, 4);
- ADD_C(item, STRING_OBJ(cstr_as_string((char *)array[i].pum_text)));
- ADD_C(item, STRING_OBJ(cstr_as_string((char *)array[i].pum_kind)));
- ADD_C(item, STRING_OBJ(cstr_as_string((char *)array[i].pum_extra)));
- ADD_C(item, STRING_OBJ(cstr_as_string((char *)array[i].pum_info)));
+ ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_text)));
+ ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_kind)));
+ ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_extra)));
+ ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_info)));
ADD_C(arr, ARRAY_OBJ(item));
}
ui_call_popupmenu_show(arr, selected, pum_win_row, cursor_col,
pum_anchor_grid);
- arena_mem_free(arena_finish(&arena), &ui_ext_fixblk);
+ arena_mem_free(arena_finish(&arena));
} else {
ui_call_popupmenu_select(selected);
return;
@@ -211,11 +218,16 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
// pum above "pum_win_row"
pum_above = true;
- // Leave two lines of context if possible
- if (curwin->w_wrow - curwin->w_cline_row >= 2) {
- context_lines = 2;
+ if (State == MODE_CMDLINE) {
+ // for cmdline pum, no need for context lines
+ context_lines = 0;
} else {
- context_lines = curwin->w_wrow - curwin->w_cline_row;
+ // Leave two lines of context if possible
+ if (curwin->w_wrow - curwin->w_cline_row >= 2) {
+ context_lines = 2;
+ } else {
+ context_lines = curwin->w_wrow - curwin->w_cline_row;
+ }
}
if (pum_win_row >= size + context_lines) {
@@ -234,13 +246,17 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
// pum below "pum_win_row"
pum_above = false;
- // Leave two lines of context if possible
- validate_cheight();
- if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) {
- context_lines = 3;
+ if (State == MODE_CMDLINE) {
+ // for cmdline pum, no need for context lines
+ context_lines = 0;
} else {
- context_lines = curwin->w_cline_row
- + curwin->w_cline_height - curwin->w_wrow;
+ // Leave two lines of context if possible
+ validate_cheight();
+ if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) {
+ context_lines = 3;
+ } else {
+ context_lines = curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow;
+ }
}
pum_row = pum_win_row + context_lines;
@@ -265,12 +281,15 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
pum_row = above_row;
pum_height = pum_win_row - above_row;
}
+
+ pum_array = array;
+ // Set "pum_size" before returning so that pum_set_event_info() gets the correct size.
+ pum_size = size;
+
if (pum_external) {
return;
}
- pum_array = array;
- pum_size = size;
pum_compute_size();
int max_width = pum_base_width;
@@ -398,8 +417,8 @@ void pum_redraw(void)
int attr;
int i;
int idx;
- char_u *s;
- char_u *p = NULL;
+ char *s;
+ char *p = NULL;
int totwidth, width, w;
int thumb_pos = 0;
int thumb_height = 1;
@@ -508,24 +527,24 @@ void pum_redraw(void)
if (s == NULL) {
s = p;
}
- w = ptr2cells((char *)p);
+ w = ptr2cells(p);
if ((*p == NUL) || (*p == TAB) || (totwidth + w > pum_width)) {
// Display the text that fits or comes before a Tab.
// First convert it to printable characters.
- char_u *st;
- char_u saved = *p;
+ char *st;
+ char saved = *p;
if (saved != NUL) {
*p = NUL;
}
- st = (char_u *)transstr((const char *)s, true);
+ st = transstr(s, true);
if (saved != NUL) {
*p = saved;
}
if (pum_rl) {
- char *rt = (char *)reverse_text(st);
+ char *rt = reverse_text(st);
char *rt_start = rt;
int size = vim_strsize(rt);
@@ -543,8 +562,7 @@ void pum_redraw(void)
size++;
}
}
- grid_puts_len(&pum_grid, (char_u *)rt, (int)STRLEN(rt), row,
- grid_col - size + 1, attr);
+ grid_puts_len(&pum_grid, rt, (int)strlen(rt), row, grid_col - size + 1, attr);
xfree(rt_start);
xfree(st);
grid_col -= width;
@@ -561,11 +579,11 @@ void pum_redraw(void)
// Display two spaces for a Tab.
if (pum_rl) {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col - 1,
+ grid_puts_len(&pum_grid, " ", 2, row, grid_col - 1,
attr);
grid_col -= 2;
} else {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col, attr);
+ grid_puts_len(&pum_grid, " ", 2, row, grid_col, attr);
grid_col += 2;
}
totwidth += 2;
@@ -704,7 +722,7 @@ static bool pum_set_selected(int n, int repeat)
if ((pum_array[pum_selected].pum_info != NULL)
&& (Rows > 10)
&& (repeat <= 1)
- && (vim_strchr((char *)p_cot, 'p') != NULL)) {
+ && (vim_strchr(p_cot, 'p') != NULL)) {
win_T *curwin_save = curwin;
tabpage_T *curtab_save = curtab;
int res = OK;
@@ -744,29 +762,28 @@ static bool pum_set_selected(int n, int repeat)
if (res == OK) {
// Edit a new, empty buffer. Set options for a "wipeout"
// buffer.
- set_option_value("swf", 0L, NULL, OPT_LOCAL);
- set_option_value("bl", 0L, NULL, OPT_LOCAL);
- set_option_value("bt", 0L, "nofile", OPT_LOCAL);
- set_option_value("bh", 0L, "wipe", OPT_LOCAL);
- set_option_value("diff", 0L, NULL, OPT_LOCAL);
+ set_option_value_give_err("swf", 0L, NULL, OPT_LOCAL);
+ set_option_value_give_err("bl", 0L, NULL, OPT_LOCAL);
+ set_option_value_give_err("bt", 0L, "nofile", OPT_LOCAL);
+ set_option_value_give_err("bh", 0L, "wipe", OPT_LOCAL);
+ set_option_value_give_err("diff", 0L, NULL, OPT_LOCAL);
}
}
if (res == OK) {
- char_u *p, *e;
+ char *p, *e;
linenr_T lnum = 0;
for (p = pum_array[pum_selected].pum_info; *p != NUL;) {
- e = (char_u *)vim_strchr((char *)p, '\n');
+ e = vim_strchr(p, '\n');
if (e == NULL) {
- ml_append(lnum++, (char *)p, 0, false);
+ ml_append(lnum++, p, 0, false);
break;
- } else {
- *e = NUL;
- ml_append(lnum++, (char *)p, (int)(e - p + 1), false);
- *e = '\n';
- p = e + 1;
}
+ *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
@@ -802,12 +819,12 @@ static bool pum_set_selected(int n, int repeat)
// Return cursor to where we were
validate_cursor();
- redraw_later(curwin, SOME_VALID);
+ redraw_later(curwin, UPD_SOME_VALID);
// When the preview window was resized we need to
// update the view on the buffer. Only go back to
// the window when needed, otherwise it will always be
- // redraw.
+ // redrawn.
if (resized) {
no_u_sync++;
win_enter(curwin_save, true);
@@ -820,7 +837,7 @@ static bool pum_set_selected(int n, int repeat)
// TODO(bfredl): can simplify, get rid of the flag munging?
// or at least eliminate extra redraw before win_enter()?
pum_is_visible = false;
- update_screen(0);
+ update_screen();
pum_is_visible = true;
if (!resized && win_valid(curwin_save)) {
@@ -832,7 +849,7 @@ static bool pum_set_selected(int n, int repeat)
// May need to update the screen again when there are
// autocommands involved.
pum_is_visible = false;
- update_screen(0);
+ update_screen();
pum_is_visible = true;
}
}
@@ -870,6 +887,7 @@ void pum_check_clear(void)
grid_free(&pum_grid);
}
pum_is_drawn = false;
+ pum_external = false;
}
}
@@ -903,6 +921,17 @@ void pum_recompose(void)
ui_comp_compose_grid(&pum_grid);
}
+void pum_ext_select_item(int item, bool insert, bool finish)
+{
+ if (!pum_visible() || item < -1 || item >= pum_size) {
+ return;
+ }
+ pum_want.active = true;
+ pum_want.item = item;
+ pum_want.insert = insert;
+ pum_want.finish = finish;
+}
+
/// Gets the height of the menu.
///
/// @return the height of the popup menu, the number of entries visible.
@@ -1032,10 +1061,16 @@ void pum_show_popupmenu(vimmenu_T *menu)
pumitem_T *array = (pumitem_T *)xcalloc((size_t)pum_size, sizeof(pumitem_T));
for (vimmenu_T *mp = menu->children; mp != NULL; mp = mp->next) {
+ char *s = NULL;
+ // Make a copy of the text, the menu may be redefined in a callback.
if (menu_is_separator(mp->dname)) {
- array[idx++].pum_text = (char_u *)"";
+ s = "";
} else if (mp->modes & mp->enabled & mode) {
- array[idx++].pum_text = (char_u *)mp->dname;
+ s = mp->dname;
+ }
+ if (s != NULL) {
+ s = xstrdup(s);
+ array[idx++].pum_text = s;
}
}
@@ -1047,6 +1082,10 @@ void pum_show_popupmenu(vimmenu_T *menu)
pum_selected = -1;
pum_first = 0;
+ if (!p_mousemev) {
+ // Pretend 'mousemoveevent' is set.
+ ui_call_option_set(STATIC_CSTR_AS_STRING("mousemoveevent"), BOOLEAN_OBJ(true));
+ }
for (;;) {
pum_is_visible = true;
@@ -1102,8 +1141,14 @@ void pum_show_popupmenu(vimmenu_T *menu)
}
}
+ for (idx = 0; idx < pum_size; idx++) {
+ xfree(array[idx].pum_text);
+ }
xfree(array);
pum_undisplay(true);
+ if (!p_mousemev) {
+ ui_call_option_set(STATIC_CSTR_AS_STRING("mousemoveevent"), BOOLEAN_OBJ(false));
+ }
}
void pum_make_popup(const char *path_name, int use_mouse_pos)