aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/popupmenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/popupmenu.c')
-rw-r--r--src/nvim/popupmenu.c167
1 files changed, 108 insertions, 59 deletions
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index a4afe97ac8..92db2db735 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -28,28 +28,29 @@
#include "nvim/popupmenu.h"
#include "nvim/search.h"
#include "nvim/strings.h"
+#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
#include "nvim/vim.h"
#include "nvim/window.h"
static pumitem_T *pum_array = NULL; // items of displayed pum
-static int pum_size; // nr of items in "pum_array"
-static int pum_selected; // index of selected item or -1
-static int pum_first = 0; // index of top item
-
-static int pum_height; // nr of displayed pum items
-static int pum_width; // width of displayed pum items
-static int pum_base_width; // width of pum items base
-static int pum_kind_width; // width of pum items kind column
-static int pum_extra_width; // width of extra stuff
-static int pum_scrollbar; // one when scrollbar present, else zero
-static bool pum_rl; // true when popupmenu is drawn 'rightleft'
-
-static int pum_anchor_grid; // grid where position is defined
-static int pum_row; // top row of pum
-static int pum_col; // left column of pum
-static bool pum_above; // pum is drawn above cursor line
+static int pum_size; // nr of items in "pum_array"
+static int pum_selected; // index of selected item or -1
+static int pum_first = 0; // index of top item
+
+static int pum_height; // nr of displayed pum items
+static int pum_width; // width of displayed pum items
+static int pum_base_width; // width of pum items base
+static int pum_kind_width; // width of pum items kind column
+static int pum_extra_width; // width of extra stuff
+static int pum_scrollbar; // one when scrollbar present, else zero
+static bool pum_rl; // true when popupmenu is drawn 'rightleft'
+
+static int pum_anchor_grid; // grid where position is defined
+static int pum_row; // top row of pum
+static int pum_col; // left column of pum
+static bool pum_above; // pum is drawn above cursor line
static bool pum_is_visible = false;
static bool pum_is_drawn = false;
@@ -60,6 +61,15 @@ static bool pum_invalid = false; // the screen was just cleared
# include "popupmenu.c.generated.h"
#endif
#define PUM_DEF_HEIGHT 10
+#define PUM_DEF_WIDTH 15
+
+static int str_dispnsize(char *s, int len);
+static int str_dispsize(char *s);
+
+// Forward declarations of needed syn functions.
+int syn_id2attr(int hl_id);
+char_u *syn_id2name(int id);
+int syn_name2id(char_u*);
static void pum_compute_size(void)
{
@@ -70,19 +80,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 = str_dispsize((char*) 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 = str_dispsize((char*) 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 = str_dispsize((char*) pum_array[i].pum_extra) + 1;
if (pum_extra_width < w) {
pum_extra_width = w;
}
@@ -178,7 +188,8 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
int def_width = (int)p_pw;
win_T *pvwin = NULL;
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab)
+ {
if (wp->w_p_pvw) {
pvwin = wp;
break;
@@ -286,8 +297,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
def_width = max_width;
}
- if ((((cursor_col < Columns - p_pw) || (cursor_col < Columns - max_width))
- && !pum_rl)
+ if ((((cursor_col < Columns - p_pw) || (cursor_col < Columns - max_width)) && !pum_rl)
|| (pum_rl && ((cursor_col > p_pw) || (cursor_col > max_width)))) {
// align pum with "cursor_col"
pum_col = cursor_col;
@@ -300,8 +310,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
pum_width = Columns - pum_col - pum_scrollbar;
}
- if ((pum_width > max_width + pum_kind_width + pum_extra_width + 1)
- && (pum_width > p_pw)) {
+ if ((pum_width > max_width + pum_kind_width + pum_extra_width + 1) && (pum_width > p_pw)) {
// the width is more than needed for the items, make it
// narrower
pum_width = max_width + pum_kind_width + pum_extra_width + 1;
@@ -310,8 +319,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
pum_width = (int)p_pw;
}
} else if (((cursor_col > p_pw || cursor_col > max_width) && !pum_rl)
- || (pum_rl && (cursor_col < Columns - p_pw
- || cursor_col < Columns - max_width))) {
+ || (pum_rl && (cursor_col < Columns - p_pw || cursor_col < Columns - max_width))) {
// align pum edge with "cursor_col"
if (pum_rl && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) {
pum_col = cursor_col + max_width + pum_scrollbar + 1;
@@ -319,8 +327,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
pum_col = Columns - 1;
}
} else if (!pum_rl) {
- if (curwin->w_wincol > Columns - max_width - pum_scrollbar
- && max_width <= p_pw) {
+ if (curwin->w_wincol > Columns - max_width - pum_scrollbar && max_width <= p_pw) {
// use full width to end of the screen
pum_col = Columns - max_width - pum_scrollbar;
if (pum_col < 0) {
@@ -460,8 +467,7 @@ void pum_redraw(void)
if (thumb_height == 0) {
thumb_height = 1;
}
- thumb_pos = (pum_first * (pum_height - thumb_height)
- + (pum_size - pum_height) / 2)
+ thumb_pos = (pum_first * (pum_height - thumb_height) + (pum_size - pum_height) / 2)
/ (pum_size - pum_height);
}
@@ -503,6 +509,7 @@ void pum_redraw(void)
break;
}
+ int cur_attr = attr;
if (p != NULL) {
for (;; MB_PTR_ADV(p)) {
if (s == NULL) {
@@ -510,7 +517,7 @@ void pum_redraw(void)
}
w = ptr2cells((char *)p);
- if ((*p == NUL) || (*p == TAB) || (totwidth + w > pum_width)) {
+ if ((*p == NUL) || (*p == TAB) || (*p == '%' && *(p + 1) == '#') || (totwidth + w > pum_width)) {
// Display the text that fits or comes before a Tab.
// First convert it to printable characters.
char_u *st;
@@ -525,9 +532,9 @@ void pum_redraw(void)
}
if (pum_rl) {
- char *rt = (char *)reverse_text(st);
+ char *rt = (char *) reverse_text(st);
char *rt_start = rt;
- int size = vim_strsize(rt);
+ int size = str_dispsize(rt);
if (size > pum_width) {
do {
@@ -550,28 +557,47 @@ void pum_redraw(void)
grid_col -= width;
} else {
// use grid_puts_len() to truncate the text
- grid_puts(&pum_grid, st, row, grid_col, attr);
+ grid_puts(&pum_grid, st, row, grid_col, cur_attr);
xfree(st);
grid_col += width;
}
- if (*p != TAB) {
- break;
- }
-
// Display two spaces for a Tab.
- if (pum_rl) {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col - 1,
- attr);
- grid_col -= 2;
+ if (*p == TAB) {
+ if (pum_rl) {
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col - 1, attr);
+ grid_col -= 2;
+ } else {
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col, attr);
+ grid_col += 2;
+ }
+ totwidth += 2;
+ // start text at next char
+ s = NULL;
+ width = 0;
+ } else if (*p == '%' && *(p + 1) == '#') {
+ // Parse highlights. Highlights are status-line-like.
+ char_u hl_attr[128];
+ unsigned pi = 0;
+ p += 2;
+ while (*p != '#' && *p != '\0') {
+ if (pi < sizeof(hl_attr) - 1) {
+ hl_attr[pi++] = *p;
+ }
+ p ++;
+ }
+ hl_attr[pi] = 0;
+ if (*p == 0)
+ break;
+ cur_attr =
+ hl_combine_attr(attr, syn_id2attr(syn_name2id(hl_attr)));
+
+ // Start the next char.
+ s = NULL;
+ width = 0;
} else {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col, attr);
- grid_col += 2;
+ break;
}
- totwidth += 2;
- // start text at next char
- s = NULL;
- width = 0;
} else {
width += w;
}
@@ -585,11 +611,8 @@ void pum_redraw(void)
}
// Stop when there is nothing more to display.
- if ((round == 3)
- || ((round == 2)
- && (pum_array[idx].pum_extra == NULL))
- || ((round == 1)
- && (pum_array[idx].pum_kind == NULL)
+ if ((round == 3) || ((round == 2) && (pum_array[idx].pum_extra == NULL))
+ || ((round == 1) && (pum_array[idx].pum_kind == NULL)
&& (pum_array[idx].pum_extra == NULL))
|| (pum_base_width + n >= pum_width)) {
break;
@@ -618,12 +641,10 @@ void pum_redraw(void)
if (pum_scrollbar > 0) {
if (pum_rl) {
grid_putchar(&pum_grid, ' ', row, col_off - pum_width,
- i >= thumb_pos && i < thumb_pos + thumb_height
- ? attr_thumb : attr_scroll);
+ i >= thumb_pos && i < thumb_pos + thumb_height ? attr_thumb : attr_scroll);
} else {
grid_putchar(&pum_grid, ' ', row, col_off + pum_width,
- i >= thumb_pos && i < thumb_pos + thumb_height
- ? attr_thumb : attr_scroll);
+ i >= thumb_pos && i < thumb_pos + thumb_height ? attr_thumb : attr_scroll);
}
}
grid_puts_line_flush(false);
@@ -936,8 +957,36 @@ void pum_set_event_info(dict_T *dict)
(void)tv_dict_add_float(dict, S_LEN("row"), r);
(void)tv_dict_add_float(dict, S_LEN("col"), c);
(void)tv_dict_add_nr(dict, S_LEN("size"), pum_size);
- (void)tv_dict_add_bool(dict, S_LEN("scrollbar"),
- pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
+ (void)tv_dict_add_bool(dict, S_LEN("scrollbar"), pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
+}
+
+static int str_dispnsize(char *s, int len)
+{
+ assert(s != NULL);
+ int size = 0;
+ int on = 1;
+
+ while (*s != NUL && --len >= 0) {
+ if (*s == '%' && *(s + 1) == '#') {
+ on = 0;
+ s += 2;
+ len -= 2;
+ } else {
+ int l = (*utfc_ptr2len)(s);
+ if (on)
+ size += ptr2cells(s);
+ s += l;
+ len -= l - 1;
+ if (*s == '#')
+ on = 1;
+ }
+ }
+ return size;
+}
+
+static int str_dispsize(char *s)
+{
+ return str_dispnsize(s, MAXCOL);
}
static void pum_position_at_mouse(int min_width)