diff options
Diffstat (limited to 'src/nvim/popupmnu.c')
| -rw-r--r-- | src/nvim/popupmnu.c | 487 | 
1 files changed, 276 insertions, 211 deletions
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index 5ad621e666..056770f2c0 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +  /// @file popupmnu.c  ///  /// Popup menu (PUM) @@ -7,12 +10,12 @@  #include <stdbool.h>  #include "nvim/vim.h" +#include "nvim/api/private/helpers.h"  #include "nvim/ascii.h"  #include "nvim/popupmnu.h"  #include "nvim/charset.h"  #include "nvim/ex_cmds.h"  #include "nvim/memline.h" -#include "nvim/misc2.h"  #include "nvim/move.h"  #include "nvim/option.h"  #include "nvim/screen.h" @@ -21,6 +24,7 @@  #include "nvim/memory.h"  #include "nvim/window.h"  #include "nvim/edit.h" +#include "nvim/ui.h"  static pumitem_T *pum_array = NULL; // items of displayed pum  static int pum_size;                // nr of items in "pum_array" @@ -36,8 +40,8 @@ static int pum_scrollbar;           // TRUE when scrollbar present  static int pum_row;                 // top row of pum  static int pum_col;                 // left column of pum -static int pum_do_redraw = FALSE;   // do redraw anyway - +static bool pum_is_visible = false; +static bool pum_external = false;  #ifdef INCLUDE_GENERATED_DECLARATIONS  # include "popupmnu.c.generated.h" @@ -53,7 +57,10 @@ static int pum_do_redraw = FALSE;   // do redraw anyway  /// @param array  /// @param size  /// @param selected index of initially selected item, none if out of range -void pum_display(pumitem_T *array, int size, int selected) +/// @param array_changed if true, array contains different items since last call +///                      if false, a new item is selected, but the array +///                      is the same +void pum_display(pumitem_T *array, int size, int selected, bool array_changed)  {    int w;    int def_width; @@ -61,213 +68,250 @@ void pum_display(pumitem_T *array, int size, int selected)    int kind_width;    int extra_width;    int i; -  int top_clear; -  int row;    int context_lines; -  int col; -  int above_row = cmdline_row; +  int above_row; +  int below_row;    int redo_count = 0; +  int row; +  int col; -redo: -  def_width = PUM_DEF_WIDTH; -  max_width = 0; -  kind_width = 0; -  extra_width = 0; - -  // Pretend the pum is already there to avoid that must_redraw is set when -  // 'cuc' is on. -  pum_array = (pumitem_T *)1; -  validate_cursor_col(); -  pum_array = NULL; - -  row = curwin->w_wrow + curwin->w_winrow; - -  if (firstwin->w_p_pvw) { -    top_clear = firstwin->w_height; -  } else { -    top_clear = 0; -  } - -  // When the preview window is at the bottom stop just above it.  Also -  // avoid drawing over the status line so that it's clear there is a window -  // boundary. -  if (lastwin->w_p_pvw) { -    above_row -= lastwin->w_height + lastwin->w_status_height + 1; -  } - -  // Figure out the size and position of the pum. -  if (size < PUM_DEF_HEIGHT) { -    pum_height = size; -  } else { -    pum_height = PUM_DEF_HEIGHT; -  } - -  if ((p_ph > 0) && (pum_height > p_ph)) { -    pum_height = (int)p_ph; +  if (!pum_is_visible) { +    // To keep the code simple, we only allow changing the +    // draw mode when the popup menu is not being displayed +    pum_external = ui_is_external(kUIPopupmenu);    } -  // Put the pum below "row" if possible.  If there are few lines decide on -  // where there is more room. -  if ((row  + 2 >= above_row - pum_height) -      && (row > (above_row - top_clear) / 2)) { -    // pum above "row" +  do { +    // Mark the pum as visible already here, +    // to avoid that must_redraw is set when 'cursorcolumn' is on. +    pum_is_visible = true; +    validate_cursor_col(); +    above_row = 0; +    below_row = cmdline_row; -    // Leave two lines of context if possible -    if (curwin->w_wrow - curwin->w_cline_row >= 2) { -      context_lines = 2; +    // anchor position: the start of the completed word +    row = curwin->w_wrow; +    if (curwin->w_p_rl) { +      col = curwin->w_width - curwin->w_wcol - 1;      } else { -      context_lines = curwin->w_wrow - curwin->w_cline_row; +      col = curwin->w_wcol;      } -    if (row >= size + context_lines) { -      pum_row = row - size - context_lines; -      pum_height = size; -    } else { -      pum_row = 0; -      pum_height = row - context_lines; +    int grid = (int)curwin->w_grid.handle; +    if (!ui_is_external(kUIMultigrid)) { +      grid = (int)default_grid.handle; +      row += curwin->w_winrow; +      col += curwin->w_wincol;      } -    if ((p_ph > 0) && (pum_height > p_ph)) { -      pum_row += pum_height - (int)p_ph; -      pum_height = (int)p_ph; +    if (pum_external) { +      if (array_changed) { +        Array arr = ARRAY_DICT_INIT; +        for (i = 0; i < size; i++) { +          Array item = ARRAY_DICT_INIT; +          ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_text))); +          ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_kind))); +          ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_extra))); +          ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_info))); +          ADD(arr, ARRAY_OBJ(item)); +        } +        ui_call_popupmenu_show(arr, selected, row, col, grid); +      } else { +        ui_call_popupmenu_select(selected); +      } +      return;      } -  } else { -    // pum below "row" -    // Leave two lines of context if possible -    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; +    def_width = PUM_DEF_WIDTH; +    max_width = 0; +    kind_width = 0; +    extra_width = 0; + +    win_T *pvwin = NULL; +    FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { +      if (wp->w_p_pvw) { +        pvwin = wp; +        break; +      }      } -    pum_row = row + context_lines; -    if (size > above_row - pum_row) { -      pum_height = above_row - pum_row; -    } else { +    if (pvwin != NULL) { +      if (pvwin->w_winrow < curwin->w_winrow) { +        above_row = pvwin->w_winrow + pvwin->w_height; +      } else if (pvwin->w_winrow > curwin->w_winrow + curwin->w_height) { +        below_row = pvwin->w_winrow; +      } +    } + +    // Figure out the size and position of the pum. +    if (size < PUM_DEF_HEIGHT) {        pum_height = size; +    } else { +      pum_height = PUM_DEF_HEIGHT;      }      if ((p_ph > 0) && (pum_height > p_ph)) {        pum_height = (int)p_ph;      } -  } -  // don't display when we only have room for one line -  if ((pum_height < 1) || ((pum_height == 1) && (size > 1))) { -    return; -  } +    // Put the pum below "row" if possible.  If there are few lines decide on +    // where there is more room. +    if (row + 2 >= below_row - pum_height +        && row - above_row > (below_row - above_row) / 2) { +      // pum above "row" -  // If there is a preview window at the top avoid drawing over it. -  if (firstwin->w_p_pvw -      && (pum_row < firstwin->w_height) -      && (pum_height > firstwin->w_height + 4)) { -    pum_row += firstwin->w_height; -    pum_height -= firstwin->w_height; -  } +      // 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; +      } -  // Compute the width of the widest match and the widest extra. -  for (i = 0; i < size; ++i) { -    w = vim_strsize(array[i].pum_text); +      if (row >= size + context_lines) { +        pum_row = row - size - context_lines; +        pum_height = size; +      } else { +        pum_row = 0; +        pum_height = row - context_lines; +      } -    if (max_width < w) { -      max_width = w; -    } +      if ((p_ph > 0) && (pum_height > p_ph)) { +        pum_row += pum_height - (int)p_ph; +        pum_height = (int)p_ph; +      } +    } else { +      // pum below "row" + +      // Leave two lines of context if possible +      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; +      } -    if (array[i].pum_kind != NULL) { -      w = vim_strsize(array[i].pum_kind) + 1; +      pum_row = row + context_lines; +      if (size > below_row - pum_row) { +        pum_height = below_row - pum_row; +      } else { +        pum_height = size; +      } -      if (kind_width < w) { -        kind_width = w; +      if ((p_ph > 0) && (pum_height > p_ph)) { +        pum_height = (int)p_ph;        }      } -    if (array[i].pum_extra != NULL) { -      w = vim_strsize(array[i].pum_extra) + 1; +    // don't display when we only have room for one line +    if ((pum_height < 1) || ((pum_height == 1) && (size > 1))) { +      return; +    } -      if (extra_width < w) { -        extra_width = w; +    // If there is a preview window above, avoid drawing over it. +    // Do keep at least 10 entries. +    if (pvwin != NULL && pum_row < above_row && pum_height > 10) { +      if (row - above_row < 10) { +        pum_row = row - 10; +        pum_height = 10; +      } else { +        pum_row = above_row; +        pum_height = row - above_row;        }      } -  } -  pum_base_width = max_width; -  pum_kind_width = kind_width; -  // Calculate column -  if (curwin->w_p_rl) { -    col = curwin->w_wincol + curwin->w_width - curwin->w_wcol - 1; -  } else { -    col = curwin->w_wincol + curwin->w_wcol; -  } +    // Compute the width of the widest match and the widest extra. +    for (i = 0; i < size; i++) { +      w = vim_strsize(array[i].pum_text); -  // if there are more items than room we need a scrollbar -  if (pum_height < size) { -    pum_scrollbar = 1; -    max_width++; -  } else { -    pum_scrollbar = 0; -  } +      if (max_width < w) { +        max_width = w; +      } -  if (def_width < max_width) { -    def_width = max_width; -  } +      if (array[i].pum_kind != NULL) { +        w = vim_strsize(array[i].pum_kind) + 1; -  if ((((col < Columns - PUM_DEF_WIDTH) || (col < Columns - max_width)) -       && !curwin->w_p_rl) -      || (curwin->w_p_rl && ((col > PUM_DEF_WIDTH) || (col > max_width)))) { -    // align pum column with "col" -    pum_col = col; -    if (curwin->w_p_rl) { -      pum_width = pum_col - pum_scrollbar + 1; -    } else { -      assert(Columns - pum_col - pum_scrollbar >= INT_MIN -             && Columns - pum_col - pum_scrollbar <= INT_MAX); -      pum_width = (int)(Columns - pum_col - pum_scrollbar); -    } +        if (kind_width < w) { +          kind_width = w; +        } +      } -    if ((pum_width > max_width + kind_width + extra_width + 1) -        && (pum_width > PUM_DEF_WIDTH)) { -      pum_width = max_width + kind_width + extra_width + 1; +      if (array[i].pum_extra != NULL) { +        w = vim_strsize(array[i].pum_extra) + 1; -      if (pum_width < PUM_DEF_WIDTH) { -        pum_width = PUM_DEF_WIDTH; +        if (extra_width < w) { +          extra_width = w; +        }        }      } -  } else if (Columns < def_width) { -    // not enough room, will use what we have -    if (curwin->w_p_rl) { -      assert(Columns - 1 >= INT_MIN); -      pum_col = (int)(Columns - 1); +    pum_base_width = max_width; +    pum_kind_width = kind_width; + +    // if there are more items than room we need a scrollbar +    if (pum_height < size) { +      pum_scrollbar = 1; +      max_width++;      } else { -      pum_col = 0; +      pum_scrollbar = 0;      } -    assert(Columns - 1 >= INT_MIN); -    pum_width = (int)(Columns - 1); -  } else { -    if (max_width > PUM_DEF_WIDTH) { -      // truncate -      max_width = PUM_DEF_WIDTH; + +    if (def_width < max_width) { +      def_width = max_width;      } -    if (curwin->w_p_rl) { -      pum_col = max_width - 1; +    if ((((col < Columns - PUM_DEF_WIDTH) || (col < Columns - max_width)) +         && !curwin->w_p_rl) +        || (curwin->w_p_rl && ((col > PUM_DEF_WIDTH) || (col > max_width)))) { +      // align pum column with "col" +      pum_col = col; +      if (curwin->w_p_rl) { +        pum_width = pum_col - pum_scrollbar + 1; +      } else { +        assert(Columns - pum_col - pum_scrollbar >= INT_MIN +               && Columns - pum_col - pum_scrollbar <= INT_MAX); +        pum_width = (int)(Columns - pum_col - pum_scrollbar); +      } + +      if ((pum_width > max_width + kind_width + extra_width + 1) +          && (pum_width > PUM_DEF_WIDTH)) { +        pum_width = max_width + kind_width + extra_width + 1; + +        if (pum_width < PUM_DEF_WIDTH) { +          pum_width = PUM_DEF_WIDTH; +        } +      } +    } else if (Columns < def_width) { +      // not enough room, will use what we have +      if (curwin->w_p_rl) { +        assert(Columns - 1 >= INT_MIN); +        pum_col = (int)(Columns - 1); +      } else { +        pum_col = 0; +      } +      assert(Columns - 1 >= INT_MIN); +      pum_width = (int)(Columns - 1);      } else { -      assert(Columns - max_width >= INT_MIN && Columns - max_width <= INT_MAX); -      pum_col = (int)(Columns - max_width); +      if (max_width > PUM_DEF_WIDTH) { +        // truncate +        max_width = PUM_DEF_WIDTH; +      } + +      if (curwin->w_p_rl) { +        pum_col = max_width - 1; +      } else { +        assert(Columns - max_width >= INT_MIN +               && Columns - max_width <= INT_MAX); +        pum_col = (int)(Columns - max_width); +      } +      pum_width = max_width - pum_scrollbar;      } -    pum_width = max_width - pum_scrollbar; -  } -  pum_array = array; -  pum_size = size; +    pum_array = array; +    pum_size = size; -  // Set selected item and redraw.  If the window size changed need to redo -  // the positioning.  Limit this to two times, when there is not much -  // room the window size will keep changing. -  if (pum_set_selected(selected, redo_count) && (++redo_count <= 2)) { -    goto redo; -  } +    // Set selected item and redraw.  If the window size changed need to redo +    // the positioning.  Limit this to two times, when there is not much +    // room the window size will keep changing. +  } while (pum_set_selected(selected, redo_count) && (++redo_count <= 2));  }  /// Redraw the popup menu, using "pum_first" and "pum_selected". @@ -275,10 +319,10 @@ void pum_redraw(void)  {    int row = pum_row;    int col; -  int attr_norm = highlight_attr[HLF_PNI]; -  int attr_select = highlight_attr[HLF_PSI]; -  int attr_scroll = highlight_attr[HLF_PSB]; -  int attr_thumb = highlight_attr[HLF_PST]; +  int attr_norm = win_hl_attr(curwin, HLF_PNI); +  int attr_select = win_hl_attr(curwin, HLF_PSI); +  int attr_scroll = win_hl_attr(curwin, HLF_PSB); +  int attr_thumb = win_hl_attr(curwin, HLF_PST);    int attr;    int i;    int idx; @@ -309,13 +353,15 @@ void pum_redraw(void)      idx = i + pum_first;      attr = (idx == pum_selected) ? attr_select : attr_norm; +    screen_puts_line_start(row); +      // prepend a space if there is room      if (curwin->w_p_rl) {        if (pum_col < curwin->w_wincol + curwin->w_width - 1) { -        screen_putchar(' ', row, pum_col + 1, attr); +        grid_putchar(&default_grid, ' ', row, pum_col + 1, attr);        }      } else if (pum_col > 0) { -      screen_putchar(' ', row, pum_col - 1, attr); +      grid_putchar(&default_grid, ' ', row, pum_col - 1, attr);      }      // Display each entry, use two spaces for a Tab. @@ -342,7 +388,7 @@ void pum_redraw(void)        }        if (p != NULL) { -        for (;; mb_ptr_adv(p)) { +        for (;; MB_PTR_ADV(p)) {            if (s == NULL) {              s = p;            } @@ -355,7 +401,7 @@ void pum_redraw(void)              char_u saved = *p;              *p = NUL; -            st = transstr(s); +            st = (char_u *)transstr((const char *)s);              *p = saved;              if (curwin->w_p_rl) { @@ -365,8 +411,8 @@ void pum_redraw(void)                if (size > pum_width) {                  do { -                  size -= has_mbyte ? (*mb_ptr2cells)(rt) : 1; -                  mb_ptr_adv(rt); +                  size -= utf_ptr2cells(rt); +                  MB_PTR_ADV(rt);                  } while (size > pum_width);                  if (size < pum_width) { @@ -377,12 +423,13 @@ void pum_redraw(void)                    size++;                  }                } -              screen_puts_len(rt, (int)STRLEN(rt), row, col - size + 1, attr); +              grid_puts_len(&default_grid, rt, (int)STRLEN(rt), row, +                            col - size + 1, attr);                xfree(rt_start);                xfree(st);                col -= width;              } else { -              screen_puts_len(st, (int)STRLEN(st), row, col, attr); +              grid_puts_len(&default_grid, st, (int)STRLEN(st), row, col, attr);                xfree(st);                col += width;              } @@ -393,10 +440,11 @@ void pum_redraw(void)              // Display two spaces for a Tab.              if (curwin->w_p_rl) { -              screen_puts_len((char_u *)"  ", 2, row, col - 1, attr); +              grid_puts_len(&default_grid, (char_u *)"  ", 2, row, col - 1, +                            attr);                col -= 2;              } else { -              screen_puts_len((char_u *)"  ", 2, row, col, attr); +              grid_puts_len(&default_grid, (char_u *)"  ", 2, row, col, attr);                col += 2;              }              totwidth += 2; @@ -427,35 +475,37 @@ void pum_redraw(void)        }        if (curwin->w_p_rl) { -        screen_fill(row, row + 1, pum_col - pum_base_width - n + 1, -                    col + 1, ' ', ' ', attr); +        grid_fill(&default_grid, row, row + 1, pum_col - pum_base_width - n + 1, +                  col + 1, ' ', ' ', attr);          col = pum_col - pum_base_width - n + 1;        } else { -        screen_fill(row, row + 1, col, pum_col + pum_base_width + n, -                    ' ', ' ', attr); +        grid_fill(&default_grid, row, row + 1, col, +                  pum_col + pum_base_width + n, ' ', ' ', attr);          col = pum_col + pum_base_width + n;        }        totwidth = pum_base_width + n;      }      if (curwin->w_p_rl) { -      screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ', ' ', -                  attr); +      grid_fill(&default_grid, row, row + 1, pum_col - pum_width + 1, col + 1, +                ' ', ' ', attr);      } else { -      screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ', attr); +      grid_fill(&default_grid, row, row + 1, col, pum_col + pum_width, ' ', ' ', +                attr);      }      if (pum_scrollbar > 0) {        if (curwin->w_p_rl) { -        screen_putchar(' ', row, pum_col - pum_width, -                       i >= thumb_pos && i < thumb_pos + thumb_heigth -                       ? attr_thumb : attr_scroll); +        grid_putchar(&default_grid, ' ', row, pum_col - pum_width, +                     i >= thumb_pos && i < thumb_pos + thumb_heigth +                     ? attr_thumb : attr_scroll);        } else { -        screen_putchar(' ', row, pum_col + pum_width, -                       i >= thumb_pos && i < thumb_pos + thumb_heigth -                       ? attr_thumb : attr_scroll); +        grid_putchar(&default_grid, ' ', row, pum_col + pum_width, +                     i >= thumb_pos && i < thumb_pos + thumb_heigth +                     ? attr_thumb : attr_scroll);        }      } +    grid_puts_line_flush(&default_grid, false);      row++;    }  } @@ -535,6 +585,7 @@ static int pum_set_selected(int n, int repeat)          && (repeat <= 1)          && (vim_strchr(p_cot, 'p') != NULL)) {        win_T *curwin_save = curwin; +      tabpage_T *curtab_save = curtab;        int res = OK;        // Open a preview window.  3 lines by default.  Prefer @@ -554,12 +605,14 @@ static int pum_set_selected(int n, int repeat)        g_do_tagpreview = 0;        if (curwin->w_p_pvw) { -        if ((curbuf->b_fname == NULL) +        if (!resized +            && (curbuf->b_nwindows == 1) +            && (curbuf->b_fname == NULL)              && (curbuf->b_p_bt[0] == 'n')              && (curbuf->b_p_bt[2] == 'f')              && (curbuf->b_p_bh[0] == 'w')) {            // Already a "wipeout" buffer, make it empty. -          while (!bufempty()) { +          while (!BUFEMPTY()) {              ml_delete((linenr_T)1, FALSE);            }          } else { @@ -571,13 +624,10 @@ static int pum_set_selected(int n, int repeat)            if (res == OK) {              // Edit a new, empty buffer. Set options for a "wipeout"              // buffer. -            set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); -            set_option_value((char_u *)"bt", 0L, -                             (char_u *)"nofile", OPT_LOCAL); -            set_option_value((char_u *)"bh", 0L, -                             (char_u *)"wipe", OPT_LOCAL); -            set_option_value((char_u *)"diff", 0L, -                             NULL, OPT_LOCAL); +            set_option_value("swf", 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);            }          } @@ -616,7 +666,12 @@ static int pum_set_selected(int n, int repeat)            curwin->w_cursor.lnum = 1;            curwin->w_cursor.col = 0; -          if ((curwin != curwin_save) && win_valid(curwin_save)) { +          if ((curwin != curwin_save && win_valid(curwin_save)) +              || (curtab != curtab_save && valid_tabpage(curtab_save))) { +            if (curtab != curtab_save && valid_tabpage(curtab_save)) { +              goto_tabpage_tp(curtab_save, false, false); +            } +              // When the first completion is done and the preview              // window is not resized, skip the preview window's              // status line redrawing. @@ -641,9 +696,9 @@ static int pum_set_selected(int n, int repeat)              // Update the screen before drawing the popup menu.              // Enable updating the status lines. -            pum_do_redraw = TRUE; +            pum_is_visible = false;              update_screen(0); -            pum_do_redraw = FALSE; +            pum_is_visible = true;              if (!resized && win_valid(curwin_save)) {                no_u_sync++; @@ -653,9 +708,9 @@ static int pum_set_selected(int n, int repeat)              // May need to update the screen again when there are              // autocommands involved. -            pum_do_redraw = TRUE; +            pum_is_visible = false;              update_screen(0); -            pum_do_redraw = FALSE; +            pum_is_visible = true;            }          }        } @@ -672,10 +727,16 @@ static int pum_set_selected(int n, int repeat)  /// Undisplay the popup menu (later).  void pum_undisplay(void)  { +  pum_is_visible = false;    pum_array = NULL; -  redraw_all_later(SOME_VALID); -  redraw_tabline = TRUE; -  status_redraw_all(); + +  if (pum_external) { +    ui_call_popupmenu_hide(); +  } else { +    redraw_all_later(SOME_VALID); +    redraw_tabline = true; +    status_redraw_all(); +  }  }  /// Clear the popup menu.  Currently only resets the offset to the first @@ -685,12 +746,16 @@ void pum_clear(void)    pum_first = 0;  } -/// Overruled when "pum_do_redraw" is set, used to redraw the status lines. -/// -/// @return TRUE if the popup menu is displayed. -int pum_visible(void) +/// @return true if the popup menu is displayed. +bool pum_visible(void) +{ +  return pum_is_visible; +} + +/// @return true if the popup menu is displayed and drawn on the grid. +bool pum_drawn(void)  { -  return !pum_do_redraw && pum_array != NULL; +  return pum_visible() && !pum_external;  }  /// Gets the height of the menu.  | 
