diff options
Diffstat (limited to 'src/popupmenu.c')
-rw-r--r-- | src/popupmenu.c | 276 |
1 files changed, 222 insertions, 54 deletions
diff --git a/src/popupmenu.c b/src/popupmenu.c index 7419806..6e9d826 100644 --- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -26,6 +26,9 @@ 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; // TRUE when scrollbar present +#ifdef FEAT_RIGHTLEFT +static int pum_rl; // TRUE when pum is drawn 'rightleft' +#endif static int pum_row; // top row of pum static int pum_col; // left column of pum @@ -101,8 +104,9 @@ pum_display( #if defined(FEAT_QUICKFIX) win_T *pvwin; #endif + #ifdef FEAT_RIGHTLEFT - int right_left = State == MODE_CMDLINE ? FALSE : curwin->w_p_rl; + pum_rl = State != MODE_CMDLINE && curwin->w_p_rl; #endif do @@ -243,7 +247,7 @@ pum_display( // w_wcol includes virtual text "above" int wcol = curwin->w_wcol % curwin->w_width; #ifdef FEAT_RIGHTLEFT - if (right_left) + if (pum_rl) cursor_col = curwin->w_wincol + curwin->w_width - wcol - 1; else #endif @@ -264,8 +268,8 @@ pum_display( if (((cursor_col < Columns - p_pw || cursor_col < Columns - max_width) #ifdef FEAT_RIGHTLEFT - && !right_left) - || (right_left && (cursor_col > p_pw || cursor_col > max_width) + && !pum_rl) + || (pum_rl && (cursor_col > p_pw || cursor_col > max_width) #endif )) { @@ -274,7 +278,7 @@ pum_display( // start with the maximum space available #ifdef FEAT_RIGHTLEFT - if (right_left) + if (pum_rl) pum_width = pum_col - pum_scrollbar + 1; else #endif @@ -291,22 +295,22 @@ pum_display( } else if (((cursor_col > p_pw || cursor_col > max_width) #ifdef FEAT_RIGHTLEFT - && !right_left) - || (right_left && (cursor_col < Columns - p_pw + && !pum_rl) + || (pum_rl && (cursor_col < Columns - p_pw || cursor_col < Columns - max_width) #endif )) { // align pum edge with "cursor_col" #ifdef FEAT_RIGHTLEFT - if (right_left + if (pum_rl && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) { pum_col = cursor_col + max_width + pum_scrollbar + 1; if (pum_col >= Columns) pum_col = Columns - 1; } - else if (!right_left) + else if (!pum_rl) #endif { if (curwin->w_wincol > Columns - max_width - pum_scrollbar @@ -320,7 +324,7 @@ pum_display( } #ifdef FEAT_RIGHTLEFT - if (right_left) + if (pum_rl) pum_width = pum_col - pum_scrollbar + 1; else #endif @@ -330,7 +334,7 @@ pum_display( { pum_width = p_pw; #ifdef FEAT_RIGHTLEFT - if (right_left) + if (pum_rl) { if (pum_width > pum_col) pum_width = pum_col; @@ -358,7 +362,7 @@ pum_display( { // not enough room, will use what we have #ifdef FEAT_RIGHTLEFT - if (right_left) + if (pum_rl) pum_col = Columns - 1; else #endif @@ -370,7 +374,7 @@ pum_display( if (max_width > p_pw) max_width = p_pw; // truncate #ifdef FEAT_RIGHTLEFT - if (right_left) + if (pum_rl) pum_col = max_width - 1; else #endif @@ -417,6 +421,119 @@ pum_under_menu(int row, int col, int only_redrawing) } /* + * Computes attributes of text on the popup menu. + * Returns attributes for every cell, or NULL if all attributes are the same. + */ + static int * +pum_compute_text_attrs(char_u *text, hlf_T hlf) +{ + int i; + size_t leader_len; + int char_cells; + int new_attr; + char_u *ptr = text; + int cell_idx = 0; + garray_T *ga = NULL; + int *attrs = NULL; + char_u *leader = NULL; + int in_fuzzy; + int matched_start = FALSE; + int_u char_pos = 0; + + if ((hlf != HLF_PSI && hlf != HLF_PNI) + || (highlight_attr[HLF_PMSI] == highlight_attr[HLF_PSI] + && highlight_attr[HLF_PMNI] == highlight_attr[HLF_PNI])) + return NULL; + + leader = State == MODE_CMDLINE ? cmdline_compl_pattern() + : ins_compl_leader(); + if (leader == NULL || *leader == NUL) + return NULL; + + attrs = ALLOC_MULT(int, vim_strsize(text)); + if (attrs == NULL) + return NULL; + + in_fuzzy = State == MODE_CMDLINE ? cmdline_compl_is_fuzzy() + : (get_cot_flags() & COT_FUZZY) != 0; + leader_len = STRLEN(leader); + + if (in_fuzzy) + ga = fuzzy_match_str_with_pos(text, leader); + else + matched_start = MB_STRNICMP(text, leader, leader_len) == 0; + + while (*ptr != NUL) + { + new_attr = highlight_attr[hlf]; + + if (ga != NULL) + { + // Handle fuzzy matching + for (i = 0; i < ga->ga_len; i++) + { + if (char_pos == ((int_u *)ga->ga_data)[i]) + { + new_attr = highlight_attr[hlf == HLF_PSI + ? HLF_PMSI : HLF_PMNI]; + break; + } + } + } + else if (matched_start && ptr < text + leader_len) + new_attr = highlight_attr[hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI]; + + char_cells = mb_ptr2cells(ptr); + for (i = 0; i < char_cells; i++) + attrs[cell_idx + i] = new_attr; + cell_idx += char_cells; + + MB_PTR_ADV(ptr); + char_pos++; + } + + if (ga != NULL) + { + ga_clear(ga); + vim_free(ga); + } + return attrs; +} + +/* + * Displays text on the popup menu with specific attributes. + */ + static void +pum_screen_puts_with_attrs( + int row, + int col, + int cells UNUSED, + char_u *text, + int textlen, + int *attrs) +{ + int col_start = col; + char_u *ptr = text; + int char_len; + int attr; + + // Render text with proper attributes + while (*ptr != NUL && ptr < text + textlen) + { + char_len = mb_ptr2len(ptr); +#ifdef FEAT_RIGHTLEFT + if (pum_rl) + attr = attrs[col_start + cells - col - 1]; + else +#endif + attr = attrs[col - col_start]; + screen_puts_len(ptr, char_len, row, col, attr); + col += mb_ptr2cells(ptr); + ptr += char_len; + } +} + +/* * Redraw the popup menu, using "pum_first" and "pum_selected". */ void @@ -426,8 +543,9 @@ pum_redraw(void) int col; int attr_scroll = highlight_attr[HLF_PSB]; int attr_thumb = highlight_attr[HLF_PST]; + hlf_T *hlfs; // array used for highlights + hlf_T hlf; int attr; - int *attrs; // array used for highlights int i; int idx; char_u *s; @@ -438,17 +556,17 @@ pum_redraw(void) int round; int n; - int attrsNorm[3]; - int attrsSel[3]; + hlf_T hlfsNorm[3]; + hlf_T hlfsSel[3]; // "word" - attrsNorm[0] = highlight_attr[HLF_PNI]; - attrsSel[0] = highlight_attr[HLF_PSI]; + hlfsNorm[0] = HLF_PNI; + hlfsSel[0] = HLF_PSI; // "kind" - attrsNorm[1] = highlight_attr[HLF_PNK]; - attrsSel[1] = highlight_attr[HLF_PSK]; + hlfsNorm[1] = HLF_PNK; + hlfsSel[1] = HLF_PSK; // "extra text" - attrsNorm[2] = highlight_attr[HLF_PNX]; - attrsSel[2] = highlight_attr[HLF_PSX]; + hlfsNorm[2] = HLF_PNX; + hlfsSel[2] = HLF_PSX; if (call_update_screen) { @@ -483,12 +601,13 @@ pum_redraw(void) for (i = 0; i < pum_height; ++i) { idx = i + pum_first; - attrs = (idx == pum_selected) ? attrsSel : attrsNorm; - attr = attrs[0]; // start with "word" highlight + hlfs = (idx == pum_selected) ? hlfsSel : hlfsNorm; + hlf = hlfs[0]; // start with "word" highlight + attr = highlight_attr[hlf]; // prepend a space if there is room #ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) + if (pum_rl) { if (pum_col < curwin->w_wincol + curwin->w_width - 1) screen_putchar(' ', row, pum_col + 1, attr); @@ -507,7 +626,8 @@ pum_redraw(void) totwidth = 0; for (round = 0; round < 3; ++round) { - attr = attrs[round]; + hlf = hlfs[round]; + attr = highlight_attr[hlf]; width = 0; s = NULL; switch (round) @@ -527,6 +647,7 @@ pum_redraw(void) // Display the text that fits or comes before a Tab. // First convert it to printable characters. char_u *st; + int *attrs; int saved = *p; if (saved != NUL) @@ -534,8 +655,11 @@ pum_redraw(void) st = transstr(s); if (saved != NUL) *p = saved; + + attrs = pum_compute_text_attrs(st, hlf); + #ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) + if (pum_rl) { if (st != NULL) { @@ -544,19 +668,19 @@ pum_redraw(void) if (rt != NULL) { char_u *rt_start = rt; - int size; + int cells; - size = vim_strsize(rt); - if (size > pum_width) + cells = vim_strsize(rt); + if (cells > pum_width) { do { - size -= has_mbyte - ? (*mb_ptr2cells)(rt) : 1; + cells -= has_mbyte + ? (*mb_ptr2cells)(rt) : 1; MB_PTR_ADV(rt); - } while (size > pum_width); + } while (cells > pum_width); - if (size < pum_width) + if (cells < pum_width) { // Most left character requires // 2-cells but only 1 cell is @@ -564,11 +688,18 @@ pum_redraw(void) // '<' on the left of the pum // item *(--rt) = '<'; - size++; + cells++; } } - screen_puts_len(rt, (int)STRLEN(rt), - row, col - size + 1, attr); + + if (attrs == NULL) + screen_puts_len(rt, (int)STRLEN(rt), + row, col - cells + 1, attr); + else + pum_screen_puts_with_attrs(row, + col - cells + 1, cells, rt, + (int)STRLEN(rt), attrs); + vim_free(rt_start); } vim_free(st); @@ -596,18 +727,26 @@ pum_redraw(void) else --cells; } - screen_puts_len(st, size, row, col, attr); + + if (attrs == NULL) + screen_puts_len(st, size, row, col, attr); + else + pum_screen_puts_with_attrs(row, col, cells, + st, size, attrs); + vim_free(st); } col += width; } + vim_free(attrs); + if (*p != TAB) break; // Display two spaces for a Tab. #ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) + if (pum_rl) { screen_puts_len((char_u *)" ", 2, row, col - 1, attr); @@ -640,11 +779,11 @@ pum_redraw(void) || pum_base_width + n >= pum_width) break; #ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) + if (pum_rl) { screen_fill(row, row + 1, pum_col - pum_base_width - n + 1, col + 1, ' ', ' ', attr); - col = pum_col - pum_base_width - n + 1; + col = pum_col - pum_base_width - n; } else #endif @@ -657,7 +796,7 @@ pum_redraw(void) } #ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) + if (pum_rl) screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ', ' ', attr); else @@ -667,7 +806,7 @@ pum_redraw(void) if (pum_scrollbar > 0) { #ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) + if (pum_rl) screen_putchar(' ', row, pum_col - pum_width, i >= thumb_pos && i < thumb_pos + thumb_height ? attr_thumb : attr_scroll); @@ -760,6 +899,7 @@ pum_set_selected(int n, int repeat UNUSED) int context = pum_height / 2; #ifdef FEAT_QUICKFIX int prev_selected = pum_selected; + unsigned cur_cot_flags = get_cot_flags(); #endif #if defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX) int has_info = FALSE; @@ -831,7 +971,7 @@ pum_set_selected(int n, int repeat UNUSED) if (pum_array[pum_selected].pum_info != NULL && Rows > 10 && repeat <= 1 - && vim_strchr(p_cot, 'p') != NULL) + && (cur_cot_flags & COT_ANY_PREVIEW)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; @@ -842,9 +982,9 @@ pum_set_selected(int n, int repeat UNUSED) # endif # ifdef FEAT_PROP_POPUP has_info = TRUE; - if (strstr((char *)p_cot, "popuphidden") != NULL) + if (cur_cot_flags & COT_POPUPHIDDEN) use_popup = USEPOPUP_HIDDEN; - else if (strstr((char *)p_cot, "popup") != NULL) + else if (cur_cot_flags & COT_POPUP) use_popup = USEPOPUP_NORMAL; else use_popup = USEPOPUP_NONE; @@ -1211,16 +1351,34 @@ pum_position_at_mouse(int min_width) pum_row = 0; } } - if (Columns - mouse_col >= pum_base_width - || Columns - mouse_col > min_width) - // Enough space to show at mouse column. - pum_col = mouse_col; + +# ifdef FEAT_RIGHTLEFT + if (pum_rl) + { + if (mouse_col + 1 >= pum_base_width + || mouse_col + 1 > min_width) + // Enough space to show at mouse column. + pum_col = mouse_col; + else + // Not enough space, left align with window. + pum_col = (pum_base_width > min_width + ? min_width : pum_base_width) - 1; + pum_width = pum_col + 1; + } else - // Not enough space, right align with window. - pum_col = Columns - (pum_base_width > min_width +# endif + { + if (Columns - mouse_col >= pum_base_width + || Columns - mouse_col > min_width) + // Enough space to show at mouse column. + pum_col = mouse_col; + else + // Not enough space, right align with window. + pum_col = Columns - (pum_base_width > min_width ? min_width : pum_base_width); + pum_width = Columns - pum_col; + } - pum_width = Columns - pum_col; if (pum_width > pum_base_width + 1) pum_width = pum_base_width + 1; @@ -1444,6 +1602,9 @@ ui_post_balloon(char_u *mesg, list_T *list) pum_compute_size(); pum_scrollbar = 0; pum_height = balloon_arraysize; +# ifdef FEAT_RIGHTLEFT + pum_rl = curwin->w_p_rl; +# endif pum_position_at_mouse(BALLOON_MIN_WIDTH); pum_selected = -1; @@ -1554,6 +1715,9 @@ pum_show_popupmenu(vimmenu_T *menu) pum_compute_size(); pum_scrollbar = 0; pum_height = pum_size; +# ifdef FEAT_RIGHTLEFT + pum_rl = curwin->w_p_rl; +# endif pum_position_at_mouse(20); pum_selected = -1; @@ -1649,7 +1813,11 @@ pum_make_popup(char_u *path_name, int use_mouse_pos) // Hack: set mouse position at the cursor so that the menu pops up // around there. mouse_row = W_WINROW(curwin) + curwin->w_wrow; - mouse_col = curwin->w_wincol + curwin->w_wcol; + mouse_col = +# ifdef FEAT_RIGHTLEFT + curwin->w_p_rl ? W_ENDCOL(curwin) - curwin->w_wcol - 1 : +# endif + curwin->w_wincol + curwin->w_wcol; } menu = gui_find_menu(path_name); |