To: vim_dev@googlegroups.com Subject: Patch 8.1.0062 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0062 Problem: Popup menu broken if a callback changes the window layout. (Qiming Zhao) Solution: Recompute the popup menu position if needed. Redraw the ruler even when the popup menu is displayed. Files: src/popupmnu.c, src/proto/popupmnu.pro, src/screen.c *** ../vim-8.1.0061/src/popupmnu.c 2018-05-14 23:05:31.000000000 +0200 --- src/popupmnu.c 2018-06-17 14:41:52.487403691 +0200 *************** *** 29,34 **** --- 29,40 ---- static int pum_row; /* top row of pum */ static int pum_col; /* left column of pum */ + static int pum_win_row; + static int pum_win_height; + static int pum_win_col; + static int pum_win_wcol; + static int pum_win_width; + static int pum_do_redraw = FALSE; /* do redraw anyway */ static int pum_set_selected(int n, int repeat); *************** *** 81,87 **** { int def_width; int max_width; - int row; int context_lines; int cursor_col; int above_row; --- 87,92 ---- *************** *** 103,109 **** validate_cursor_col(); pum_array = NULL; ! row = curwin->w_wrow + W_WINROW(curwin); #if defined(FEAT_QUICKFIX) FOR_ALL_WINDOWS(pvwin) --- 108,120 ---- validate_cursor_col(); pum_array = NULL; ! // Remember the essential parts of the window position and size, so we ! // can decide when to reposition the popup menu. ! pum_win_row = curwin->w_wrow + W_WINROW(curwin); ! pum_win_height = curwin->w_height; ! pum_win_col = curwin->w_wincol; ! pum_win_wcol = curwin->w_wcol; ! pum_win_width = curwin->w_width; #if defined(FEAT_QUICKFIX) FOR_ALL_WINDOWS(pvwin) *************** *** 128,139 **** if (p_ph > 0 && pum_height > p_ph) pum_height = p_ph; ! /* 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" */ /* Leave two lines of context if possible */ if (curwin->w_wrow - curwin->w_cline_row >= 2) --- 139,150 ---- if (p_ph > 0 && pum_height > p_ph) pum_height = p_ph; ! /* Put the pum below "pum_win_row" if possible. If there are few lines decide * on where there is more room. */ ! if (pum_win_row + 2 >= below_row - pum_height ! && pum_win_row - above_row > (below_row - above_row) / 2) { ! /* pum above "pum_win_row" */ /* Leave two lines of context if possible */ if (curwin->w_wrow - curwin->w_cline_row >= 2) *************** *** 141,155 **** else context_lines = curwin->w_wrow - curwin->w_cline_row; ! if (row >= size + context_lines) { ! pum_row = row - size - context_lines; pum_height = size; } else { pum_row = 0; ! pum_height = row - context_lines; } if (p_ph > 0 && pum_height > p_ph) { --- 152,166 ---- else context_lines = curwin->w_wrow - curwin->w_cline_row; ! if (pum_win_row >= size + context_lines) { ! pum_row = pum_win_row - size - context_lines; pum_height = size; } else { pum_row = 0; ! pum_height = pum_win_row - context_lines; } if (p_ph > 0 && pum_height > p_ph) { *************** *** 159,165 **** } else { ! /* pum below "row" */ /* Leave two lines of context if possible */ if (curwin->w_cline_row --- 170,176 ---- } else { ! /* pum below "pum_win_row" */ /* Leave two lines of context if possible */ if (curwin->w_cline_row *************** *** 169,175 **** context_lines = curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow; ! pum_row = row + context_lines; if (size > below_row - pum_row) pum_height = below_row - pum_row; else --- 180,186 ---- context_lines = curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow; ! pum_row = pum_win_row + context_lines; if (size > below_row - pum_row) pum_height = below_row - pum_row; else *************** *** 823,828 **** --- 834,875 ---- } /* + * Reposition the popup menu to adjust for window layout changes. + */ + void + pum_may_redraw(void) + { + pumitem_T *array = pum_array; + int len = pum_size; + int selected = pum_selected; + + if (!pum_visible()) + return; // nothing to do + + if (pum_win_row == curwin->w_wrow + W_WINROW(curwin) + && pum_win_height == curwin->w_height + && pum_win_col == curwin->w_wincol + && pum_win_width == curwin->w_width) + { + // window position didn't change, redraw in the same position + pum_redraw(); + } + else + { + int wcol = curwin->w_wcol; + + // Window layout changed, recompute the position. + // Use the remembered w_wcol value, the cursor may have moved when a + // completion was inserted, but we want the menu in the same position. + pum_undisplay(); + curwin->w_wcol = pum_win_wcol; + curwin->w_valid |= VALID_WCOL; + pum_display(array, len, selected); + curwin->w_wcol = wcol; + } + } + + /* * Return the height of the popup menu, the number of entries visible. * Only valid when pum_visible() returns TRUE! */ *** ../vim-8.1.0061/src/proto/popupmnu.pro 2018-05-17 13:52:48.000000000 +0200 --- src/proto/popupmnu.pro 2018-06-17 14:12:56.177812770 +0200 *************** *** 4,9 **** --- 4,10 ---- void pum_undisplay(void); void pum_clear(void); int pum_visible(void); + void pum_may_redraw(void); int pum_get_height(void); int split_message(char_u *mesg, pumitem_T **array); void ui_remove_balloon(void); *** ../vim-8.1.0061/src/screen.c 2018-06-16 16:20:48.768597967 +0200 --- src/screen.c 2018-06-17 14:37:49.760753642 +0200 *************** *** 171,177 **** static void win_redr_custom(win_T *wp, int draw_ruler); #endif #ifdef FEAT_CMDL_INFO ! static void win_redr_ruler(win_T *wp, int always); #endif /* Ugly global: overrule attribute used by screen_char() */ --- 171,177 ---- static void win_redr_custom(win_T *wp, int draw_ruler); #endif #ifdef FEAT_CMDL_INFO ! static void win_redr_ruler(win_T *wp, int always, int ignore_pum); #endif /* Ugly global: overrule attribute used by screen_char() */ *************** *** 783,790 **** #endif #ifdef FEAT_INS_EXPAND /* May need to redraw the popup menu. */ ! if (pum_visible()) ! pum_redraw(); #endif /* Reset b_mod_set flags. Going through all windows is probably faster --- 783,789 ---- #endif #ifdef FEAT_INS_EXPAND /* May need to redraw the popup menu. */ ! pum_may_redraw(); #endif /* Reset b_mod_set flags. Going through all windows is probably faster *************** *** 7002,7008 **** - 1 + wp->w_wincol), attr); #ifdef FEAT_CMDL_INFO ! win_redr_ruler(wp, TRUE); #endif } --- 7001,7007 ---- - 1 + wp->w_wincol), attr); #ifdef FEAT_CMDL_INFO ! win_redr_ruler(wp, TRUE, ignore_pum); #endif } *************** *** 10455,10461 **** /* If the last window has no status line, the ruler is after the mode * message and must be redrawn */ if (redrawing() && lastwin->w_status_height == 0) ! win_redr_ruler(lastwin, TRUE); #endif redraw_cmdline = FALSE; clear_cmdline = FALSE; --- 10454,10460 ---- /* If the last window has no status line, the ruler is after the mode * message and must be redrawn */ if (redrawing() && lastwin->w_status_height == 0) ! win_redr_ruler(lastwin, TRUE, FALSE); #endif redraw_cmdline = FALSE; clear_cmdline = FALSE; *************** *** 10874,10879 **** --- 10873,10879 ---- (int)wp->w_width, FALSE); } #endif + /* * Show current status info in ruler and various other places * If always is FALSE, only show ruler if position has changed. *************** *** 10899,10905 **** else #endif #ifdef FEAT_CMDL_INFO ! win_redr_ruler(curwin, always); #endif #ifdef FEAT_TITLE --- 10899,10905 ---- else #endif #ifdef FEAT_CMDL_INFO ! win_redr_ruler(curwin, always, FALSE); #endif #ifdef FEAT_TITLE *************** *** 10918,10924 **** #ifdef FEAT_CMDL_INFO static void ! win_redr_ruler(win_T *wp, int always) { #define RULER_BUF_LEN 70 char_u buffer[RULER_BUF_LEN]; --- 10918,10924 ---- #ifdef FEAT_CMDL_INFO static void ! win_redr_ruler(win_T *wp, int always, int ignore_pum) { #define RULER_BUF_LEN 70 char_u buffer[RULER_BUF_LEN]; *************** *** 10951,10958 **** if (wp == lastwin && lastwin->w_status_height == 0) if (edit_submode != NULL) return; ! /* Don't draw the ruler when the popup menu is visible, it may overlap. */ ! if (pum_visible()) return; #endif --- 10951,10959 ---- if (wp == lastwin && lastwin->w_status_height == 0) if (edit_submode != NULL) return; ! // Don't draw the ruler when the popup menu is visible, it may overlap. ! // Except when the popup menu will be redrawn anyway. ! if (!ignore_pum && pum_visible()) return; #endif *** ../vim-8.1.0061/src/version.c 2018-06-16 22:58:11.791025515 +0200 --- src/version.c 2018-06-17 14:39:53.964061772 +0200 *************** *** 763,764 **** --- 763,766 ---- { /* Add new patch number below this line */ + /**/ + 62, /**/ -- hundred-and-one symptoms of being an internet addict: 58. You turn on your computer and turn off your wife. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///