diff options
Diffstat (limited to 'src/nvim/popupmenu.c')
-rw-r--r-- | src/nvim/popupmenu.c | 167 |
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) |