diff --git a/src/buffer.c b/src/buffer.c index d8bfcc9b38..6ddd6c16db 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -3920,7 +3920,6 @@ build_stl_str_hl( struct stl_hlrec *sp; int save_must_redraw = must_redraw; int save_redr_type = curwin->w_redr_type; - int save_highlight_shcnaged = need_highlight_changed; #ifdef FEAT_EVAL /* @@ -4693,12 +4692,13 @@ build_stl_str_hl( sp->userhl = 0; } - /* We do not want redrawing a stausline, ruler, title, etc. to trigger - * another redraw, it may cause an endless loop. This happens when a - * statusline changes a highlight group. */ - must_redraw = save_must_redraw; - curwin->w_redr_type = save_redr_type; - need_highlight_changed = save_highlight_shcnaged; + /* When inside update_screen we do not want redrawing a stausline, ruler, + * title, etc. to trigger another redraw, it may cause an endless loop. */ + if (updating_screen) + { + must_redraw = save_must_redraw; + curwin->w_redr_type = save_redr_type; + } return width; } diff --git a/src/evalfunc.c b/src/evalfunc.c index dfd6e165bf..3c19beb96e 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5190,8 +5190,8 @@ f_gettabvar(typval_T *argvars, typval_T *rettv) /* Set tp to be our tabpage, temporarily. Also set the window to the * first window in the tabpage, otherwise the window is not valid. */ if (switch_win(&oldcurwin, &oldtabpage, - tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE) - == OK) + tp == curtab || tp->tp_firstwin == NULL ? firstwin + : tp->tp_firstwin, tp, TRUE) == OK) { /* look up the variable */ /* Let gettabvar({nr}, "") return the "t:" dictionary. */ diff --git a/src/popupmnu.c b/src/popupmnu.c index c2b3e73619..418f0ca61a 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -64,206 +64,207 @@ pum_display( win_T *pvwin; #endif -redo: - def_width = PUM_DEF_WIDTH; - max_width = 0; - kind_width = 0; - extra_width = 0; - above_row = 0; - below_row = cmdline_row; + do + { + def_width = PUM_DEF_WIDTH; + max_width = 0; + kind_width = 0; + extra_width = 0; + above_row = 0; + below_row = cmdline_row; - /* 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; + /* 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 + W_WINROW(curwin); + row = curwin->w_wrow + W_WINROW(curwin); #if defined(FEAT_QUICKFIX) - FOR_ALL_WINDOWS(pvwin) - if (pvwin->w_p_pvw) - break; - if (pvwin != NULL) - { - if (W_WINROW(pvwin) < W_WINROW(curwin)) - above_row = W_WINROW(pvwin) + pvwin->w_height; - else if (W_WINROW(pvwin) > W_WINROW(curwin) + curwin->w_height) - below_row = W_WINROW(pvwin); - } + FOR_ALL_WINDOWS(pvwin) + if (pvwin->w_p_pvw) + break; + if (pvwin != NULL) + { + if (W_WINROW(pvwin) < W_WINROW(curwin)) + above_row = W_WINROW(pvwin) + pvwin->w_height; + else if (W_WINROW(pvwin) > W_WINROW(curwin) + curwin->w_height) + below_row = W_WINROW(pvwin); + } #endif - /* - * 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 = 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) - context_lines = 2; - else - context_lines = curwin->w_wrow - curwin->w_cline_row; - - if (row >= size + context_lines) - { - pum_row = row - size - context_lines; + /* + * Figure out the size and position of the pum. + */ + if (size < PUM_DEF_HEIGHT) pum_height = size; - } else - { - pum_row = 0; - pum_height = row - context_lines; - } - if (p_ph > 0 && pum_height > p_ph) - { - pum_row += pum_height - p_ph; - pum_height = 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; - - pum_row = row + context_lines; - if (size > below_row - pum_row) - pum_height = below_row - pum_row; - else - pum_height = size; + pum_height = PUM_DEF_HEIGHT; if (p_ph > 0 && pum_height > p_ph) pum_height = 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" */ + + /* 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; + + 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) + { + pum_row += pum_height - p_ph; + pum_height = 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; + + pum_row = row + context_lines; + if (size > below_row - pum_row) + pum_height = below_row - pum_row; + else + pum_height = size; + if (p_ph > 0 && pum_height > p_ph) + pum_height = p_ph; + } + + /* don't display when we only have room for one line */ + if (pum_height < 1 || (pum_height == 1 && size > 1)) + return; #if defined(FEAT_QUICKFIX) - /* If there is a preview window at the above avoid drawing over it. */ - if (pvwin != NULL && pum_row < above_row && pum_height > above_row) - { - pum_row += above_row; - pum_height -= above_row; - } -#endif - - /* 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 (max_width < w) - max_width = w; - if (array[i].pum_kind != NULL) + /* If there is a preview window at the above avoid drawing over it. */ + if (pvwin != NULL && pum_row < above_row && pum_height > above_row) { - w = vim_strsize(array[i].pum_kind) + 1; - if (kind_width < w) - kind_width = w; + pum_row += above_row; + pum_height -= above_row; } - if (array[i].pum_extra != NULL) +#endif + + /* Compute the width of the widest match and the widest extra. */ + for (i = 0; i < size; ++i) { - w = vim_strsize(array[i].pum_extra) + 1; - if (extra_width < w) - extra_width = w; + w = vim_strsize(array[i].pum_text); + if (max_width < w) + max_width = w; + if (array[i].pum_kind != NULL) + { + w = vim_strsize(array[i].pum_kind) + 1; + if (kind_width < w) + kind_width = w; + } + if (array[i].pum_extra != NULL) + { + w = vim_strsize(array[i].pum_extra) + 1; + if (extra_width < w) + extra_width = w; + } } - } - pum_base_width = max_width; - pum_kind_width = kind_width; - - /* Calculate column */ -#ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) - col = curwin->w_wincol + curwin->w_width - curwin->w_wcol - 1; - else -#endif - col = curwin->w_wincol + curwin->w_wcol; - - /* 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 (def_width < max_width) - def_width = max_width; - - if (((col < Columns - PUM_DEF_WIDTH || col < Columns - max_width) -#ifdef FEAT_RIGHTLEFT - && !curwin->w_p_rl) - || (curwin->w_p_rl && (col > PUM_DEF_WIDTH || col > max_width) -#endif - )) - { - /* align pum column with "col" */ - pum_col = col; + pum_base_width = max_width; + pum_kind_width = kind_width; + /* Calculate column */ #ifdef FEAT_RIGHTLEFT if (curwin->w_p_rl) - pum_width = pum_col - pum_scrollbar + 1; + col = curwin->w_wincol + curwin->w_width - curwin->w_wcol - 1; else #endif - pum_width = Columns - pum_col - pum_scrollbar; + col = curwin->w_wincol + curwin->w_wcol; - if (pum_width > max_width + kind_width + extra_width + 1 - && pum_width > PUM_DEF_WIDTH) + /* if there are more items than room we need a scrollbar */ + if (pum_height < size) { - pum_width = max_width + kind_width + extra_width + 1; - if (pum_width < PUM_DEF_WIDTH) - pum_width = PUM_DEF_WIDTH; + pum_scrollbar = 1; + ++max_width; } - } - else if (Columns < def_width) - { - /* not enough room, will use what we have */ -#ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) - pum_col = Columns - 1; else -#endif - pum_col = 0; - pum_width = Columns - 1; - } - else - { - if (max_width > PUM_DEF_WIDTH) - max_width = PUM_DEF_WIDTH; /* truncate */ + pum_scrollbar = 0; + + if (def_width < max_width) + def_width = max_width; + + if (((col < Columns - PUM_DEF_WIDTH || col < Columns - max_width) #ifdef FEAT_RIGHTLEFT - if (curwin->w_p_rl) - pum_col = max_width - 1; - else + && !curwin->w_p_rl) + || (curwin->w_p_rl && (col > PUM_DEF_WIDTH || col > max_width) #endif - pum_col = Columns - max_width; - pum_width = max_width - pum_scrollbar; - } + )) + { + /* align pum column with "col" */ + pum_col = col; - pum_array = array; - pum_size = size; +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + pum_width = pum_col - pum_scrollbar + 1; + else +#endif + pum_width = Columns - pum_col - pum_scrollbar; - /* 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; + 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 */ +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + pum_col = Columns - 1; + else +#endif + pum_col = 0; + pum_width = Columns - 1; + } + else + { + if (max_width > PUM_DEF_WIDTH) + max_width = PUM_DEF_WIDTH; /* truncate */ +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + pum_col = max_width - 1; + else +#endif + pum_col = Columns - max_width; + pum_width = max_width - pum_scrollbar; + } + + 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. */ + } while (pum_set_selected(selected, redo_count) && ++redo_count <= 2); } /* diff --git a/src/syntax.c b/src/syntax.c index 984347c72a..a31bdbce57 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -7378,6 +7378,7 @@ do_highlight( int id; int idx; struct hl_group item_before; + int did_change = FALSE; int dodefault = FALSE; int doclear = FALSE; int dolink = FALSE; @@ -7788,6 +7789,7 @@ do_highlight( /* GUI not started yet, always accept the name. */ vim_free(HL_TABLE()[idx].sg_font_name); HL_TABLE()[idx].sg_font_name = vim_strsave(arg); + did_change = TRUE; } else { @@ -7816,6 +7818,7 @@ do_highlight( gui_mch_free_fontset(temp_sg_fontset); vim_free(HL_TABLE()[idx].sg_font_name); HL_TABLE()[idx].sg_font_name = vim_strsave(arg); + did_change = TRUE; } else HL_TABLE()[idx].sg_fontset = temp_sg_fontset; @@ -7827,6 +7830,7 @@ do_highlight( gui_mch_free_font(temp_sg_font); vim_free(HL_TABLE()[idx].sg_font_name); HL_TABLE()[idx].sg_font_name = vim_strsave(arg); + did_change = TRUE; } else HL_TABLE()[idx].sg_font = temp_sg_font; @@ -7992,6 +7996,7 @@ do_highlight( *namep = vim_strsave(arg); else *namep = NULL; + did_change = TRUE; } # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) # ifdef FEAT_GUI_X11 @@ -8042,6 +8047,7 @@ do_highlight( *namep = vim_strsave(arg); else *namep = NULL; + did_change = TRUE; } # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) # ifdef FEAT_GUI_X11 @@ -8091,6 +8097,7 @@ do_highlight( *namep = vim_strsave(arg); else *namep = NULL; + did_change = TRUE; } # ifdef FEAT_GUI } @@ -8260,13 +8267,18 @@ do_highlight( /* Only call highlight_changed() once, after a sequence of highlight * commands, and only if an attribute actually changed. */ - if (memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0 + if ((did_change + || memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0) #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) && !did_highlight_changed #endif ) { - redraw_all_later(NOT_VALID); + /* Do not trigger a redraw when highlighting is changed while + * redrawing. This may happen when evaluating 'statusline' changes the + * StatusLine group. */ + if (!updating_screen) + redraw_all_later(NOT_VALID); need_highlight_changed = TRUE; } } diff --git a/src/term.c b/src/term.c index 2635be4119..eb06daf590 100644 --- a/src/term.c +++ b/src/term.c @@ -3277,11 +3277,10 @@ set_shellsize(int width, int height, int mustset) if (pum_visible()) { redraw_later(NOT_VALID); - ins_compl_show_pum(); /* This includes the redraw. */ + ins_compl_show_pum(); } - else #endif - update_screen(NOT_VALID); + update_screen(NOT_VALID); if (redrawing()) setcursor(); } diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim index eddcb9dc1f..6bbdb07a95 100644 --- a/src/testdir/shared.vim +++ b/src/testdir/shared.vim @@ -1,5 +1,10 @@ " Functions shared by several tests. +" Only load this script once. +if exists('*WaitFor') + finish +endif + " Get the name of the Python executable. " Also keeps it in s:python. func PythonProg() diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim index 61c3472b2a..189cd82d12 100644 --- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -1,8 +1,6 @@ " A series of tests that can run in one Vim invocation. " This makes testing go faster, since Vim doesn't need to restart. -source shared.vim - set belloff=all source test_assign.vim source test_bufline.vim diff --git a/src/testdir/test_bufline.vim b/src/testdir/test_bufline.vim index f57dd73ef3..cc5c10e985 100644 --- a/src/testdir/test_bufline.vim +++ b/src/testdir/test_bufline.vim @@ -1,8 +1,6 @@ " Tests for setbufline() and getbufline() -if !exists('*GetVimCommand') - source shared.vim -endif +source shared.vim func Test_setbufline_getbufline() new diff --git a/src/testdir/test_getvar.vim b/src/testdir/test_getvar.vim index 0f5dff5d10..d6b6b69aa8 100644 --- a/src/testdir/test_getvar.vim +++ b/src/testdir/test_getvar.vim @@ -86,3 +86,19 @@ func Test_var() call assert_equal(1, gettabwinvar(2, 3, '&nux', 1)) tabonly endfunc + +" It was discovered that "gettabvar()" would fail if called from within the +" tabline when the user closed a window. This test confirms the fix. +func Test_gettabvar_in_tabline() + let t:var_str = 'value' + + set tabline=%{assert_equal('value',gettabvar(1,'var_str'))} + set showtabline=2 + + " Simulate the user opening a split (which becomes window #1) and then + " closing the split, which triggers the redrawing of the tabline. + leftabove split + redrawstatus! + close + redrawstatus! +endfunc diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index e3bd0e19a0..0dfa956fb2 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -1,5 +1,7 @@ " Test for completion menu +source shared.vim + let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] let g:setting = '' @@ -36,6 +38,7 @@ endfu func! Test_popup_complete() new inoremap =ListMonths() + set belloff=all " - select original typed text before the completion started call feedkeys("aJu\\\\", 'tx') @@ -212,6 +215,7 @@ func! Test_popup_complete() call feedkeys("aM\\\", 'tx') call assert_equal(["March", "M", "March"], getline(1,4)) %d + set belloff& endfu @@ -513,6 +517,7 @@ endfunc func Test_completion_respect_bs_option() new + set belloff=all let li = ["aaa", "aaa12345", "aaaabcdef", "aaaABC"] set bs=indent,eol @@ -528,6 +533,7 @@ func Test_completion_respect_bs_option() call feedkeys("A\\\\\\\", "tx") call assert_equal('', getline(1)) + set belloff& bw! endfunc @@ -614,6 +620,7 @@ endfunc func Test_complete_CTRLN_startofbuffer() new + set belloff=all call setline(1, [ 'organize(cupboard, 3, 2);', \ 'prioritize(bureau, 8, 7);', \ 'realize(bannister, 4, 4);', @@ -624,6 +631,40 @@ func Test_complete_CTRLN_startofbuffer() \ 'railing.moralize(3,9);'] call feedkeys("qai\\.\3wdW\q3@a", 'tx') call assert_equal(expected, getline(1,'$')) + set belloff& + bwipe! +endfunc + +func Test_popup_and_window_resize() + if !has('terminal') || has('gui_running') + return + endif + let h = winheight(0) + if h < 15 + return + endif + let g:buf = term_start([$VIMPROG, '--clean', '-c', 'set noswapfile'], {'term_rows': h / 3}) + call term_sendkeys(g:buf, (h / 3 - 1)."o\G") + call term_wait(g:buf, 100) + call term_sendkeys(g:buf, "i\") + call term_wait(g:buf, 100) + call term_sendkeys(g:buf, "\") + call term_wait(g:buf, 100) + " popup first entry "!" must be at the top + call WaitFor('term_getline(g:buf, 1) =~ "^!"') + call assert_match('^!\s*$', term_getline(g:buf, 1)) + exe 'resize +' . (h - 1) + call term_wait(g:buf, 100) + redraw! + " popup shifted down, first line is now empty + call WaitFor('term_getline(g:buf, 1) == ""') + call assert_equal('', term_getline(g:buf, 1)) + sleep 100m + " popup is below cursor line and shows first match "!" + call WaitFor('term_getline(g:buf, term_getcursor(g:buf)[0] + 1) =~ "^!"') + call assert_match('^!\s*$', term_getline(g:buf, term_getcursor(g:buf)[0] + 1)) + " cursor line also shows ! + call assert_match('^!\s*$', term_getline(g:buf, term_getcursor(g:buf)[0])) bwipe! endfunc diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim index 7302fbd862..a3d308caf1 100644 --- a/src/testdir/test_timers.vim +++ b/src/testdir/test_timers.vim @@ -4,9 +4,7 @@ if !has('timers') finish endif -if !exists('*WaitFor') - source shared.vim -endif +source shared.vim func MyHandler(timer) let g:val += 1 diff --git a/src/version.c b/src/version.c index d8b1205303..27cb38aded 100644 --- a/src/version.c +++ b/src/version.c @@ -776,6 +776,18 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1165, +/**/ + 1164, +/**/ + 1163, +/**/ + 1162, +/**/ + 1161, +/**/ + 1160, /**/ 1159, /**/ diff --git a/src/window.c b/src/window.c index 2710c1c0f2..c5d1bd5675 100644 --- a/src/window.c +++ b/src/window.c @@ -4780,13 +4780,14 @@ win_remove( if (wp->w_prev != NULL) wp->w_prev->w_next = wp->w_next; else if (tp == NULL) - firstwin = wp->w_next; + firstwin = curtab->tp_firstwin = wp->w_next; else tp->tp_firstwin = wp->w_next; + if (wp->w_next != NULL) wp->w_next->w_prev = wp->w_prev; else if (tp == NULL) - lastwin = wp->w_prev; + lastwin = curtab->tp_lastwin = wp->w_prev; else tp->tp_lastwin = wp->w_prev; } @@ -6610,11 +6611,11 @@ restore_snapshot_rec(frame_T *sn, frame_T *fr) */ int switch_win( - win_T **save_curwin UNUSED, - tabpage_T **save_curtab UNUSED, - win_T *win UNUSED, - tabpage_T *tp UNUSED, - int no_display UNUSED) + win_T **save_curwin, + tabpage_T **save_curtab, + win_T *win, + tabpage_T *tp, + int no_display) { # ifdef FEAT_AUTOCMD block_autocmds();