# HG changeset patch # User Bram Moolenaar # Date 1601151304 -7200 # Node ID 3351d2cd3f1fe912d76da4606dce857de1b03768 # Parent 337df0dbfe0af3efdd48a7cf892f615789a37ae8 patch 8.2.1750: popup_setoptions() setting firstline fails if cursorline set Commit: https://github.com/vim/vim/commit/3697c9bbae755831d3cf2f11179aaff29e343f51 Author: Bram Moolenaar Date: Sat Sep 26 22:03:00 2020 +0200 patch 8.2.1750: popup_setoptions() setting firstline fails if cursorline set Problem: Setting firstline with popup_setoptions() fails if cursorline is set. Solution: Use apply_options(). Update the popup before applying "zz". (closes #7010) diff --git a/src/move.c b/src/move.c --- a/src/move.c +++ b/src/move.c @@ -2144,6 +2144,10 @@ scroll_cursor_halfway(int atend) linenr_T old_topline = curwin->w_topline; #endif +#ifdef FEAT_PROP_POPUP + // if the width changed this needs to be updated first + may_update_popup_position(); +#endif loff.lnum = boff.lnum = curwin->w_cursor.lnum; #ifdef FEAT_FOLDING (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum); diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -579,7 +579,7 @@ popup_show_curline(win_T *wp) if (wp->w_cursor.lnum < wp->w_topline) wp->w_topline = wp->w_cursor.lnum; else if (wp->w_cursor.lnum >= wp->w_botline - && (curwin->w_valid & VALID_BOTLINE)) + && (wp->w_valid & VALID_BOTLINE)) { wp->w_topline = wp->w_cursor.lnum - wp->w_height + 1; if (wp->w_topline < 1) @@ -931,16 +931,17 @@ apply_general_options(win_T *wp, dict_T /* * Go through the options in "dict" and apply them to popup window "wp". - * Only used when creating a new popup window. + * "create" is TRUE when creating a new popup window. */ static void -apply_options(win_T *wp, dict_T *dict) +apply_options(win_T *wp, dict_T *dict, int create) { int nr; apply_move_options(wp, dict); - set_string_option_direct_in_win(wp, (char_u *)"signcolumn", -1, + if (create) + set_string_option_direct_in_win(wp, (char_u *)"signcolumn", -1, (char_u *)"no", OPT_FREE|OPT_LOCAL, 0); apply_general_options(wp, dict); @@ -949,16 +950,17 @@ apply_options(win_T *wp, dict_T *dict) if (nr > 0) wp->w_popup_flags |= POPF_HIDDEN; - // when "firstline" and "cursorline" are both set move the cursor to the - // "firstline". + // when "firstline" and "cursorline" are both set and the cursor would be + // above or below the displayed lines, move the cursor to "firstline". if (wp->w_firstline > 0 && (wp->w_popup_flags & POPF_CURSORLINE)) { if (wp->w_firstline > wp->w_buffer->b_ml.ml_line_count) wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count; - else + else if (wp->w_cursor.lnum < wp->w_firstline + || wp->w_cursor.lnum >= wp->w_firstline + wp->w_height) wp->w_cursor.lnum = wp->w_firstline; - wp->w_topline = wp->w_cursor.lnum; - curwin->w_valid &= ~VALID_BOTLINE; + wp->w_topline = wp->w_firstline; + wp->w_valid &= ~VALID_BOTLINE; } popup_mask_refresh = TRUE; @@ -2106,7 +2108,7 @@ popup_create(typval_T *argvars, typval_T if (d != NULL) // Deal with options. - apply_options(wp, d); + apply_options(wp, d, TRUE); #ifdef FEAT_TIMERS if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL) @@ -2762,13 +2764,10 @@ f_popup_setoptions(typval_T *argvars, ty dict = argvars[1].vval.v_dict; old_firstline = wp->w_firstline; - apply_move_options(wp, dict); - apply_general_options(wp, dict); + apply_options(wp, dict, FALSE); if (old_firstline != wp->w_firstline) redraw_win_later(wp, NOT_VALID); - popup_mask_refresh = TRUE; - popup_highlight_curline(wp); popup_adjust_position(wp); } @@ -3467,13 +3466,14 @@ popup_need_position_adjust(win_T *wp) { if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) return TRUE; - if (win_valid(wp->w_popup_prop_win)) - return wp->w_popup_prop_changedtick - != CHANGEDTICK(wp->w_popup_prop_win->w_buffer) - || wp->w_popup_prop_topline != wp->w_popup_prop_win->w_topline - || ((wp->w_popup_flags & POPF_CURSORLINE) - && wp->w_cursor.lnum != wp->w_popup_last_curline); - return FALSE; + if (win_valid(wp->w_popup_prop_win) + && (wp->w_popup_prop_changedtick + != CHANGEDTICK(wp->w_popup_prop_win->w_buffer) + || wp->w_popup_prop_topline != wp->w_popup_prop_win->w_topline)) + return TRUE; + + // May need to adjust the width if the cursor moved. + return wp->w_cursor.lnum != wp->w_popup_last_curline; } /* @@ -3647,6 +3647,17 @@ may_update_popup_mask(int type) } /* + * If the current window is a popup and something relevant changed, recompute + * the position and size. + */ + void +may_update_popup_position(void) +{ + if (popup_is_popup(curwin) && popup_need_position_adjust(curwin)) + popup_adjust_position(curwin); +} + +/* * Return a string of "len" spaces in IObuff. */ static char_u * diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -50,6 +50,7 @@ int popup_do_filter(int c); int popup_no_mapping(void); void popup_check_cursor_pos(void); void may_update_popup_mask(int type); +void may_update_popup_position(void); void update_popups(void (*win_update)(win_T *wp)); int set_ref_in_popups(int copyID); int popup_is_popup(win_T *wp); diff --git a/src/testdir/dumps/Test_popupwin_set_firstline_1.dump b/src/testdir/dumps/Test_popupwin_set_firstline_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_set_firstline_1.dump @@ -0,0 +1,16 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @25|1+0#0000001#e0e0e08|0| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255@1| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|2| @17| +0#0000000#0000001| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|3| @17| +0#0000000#0000001| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|4| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|5| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|6| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|7| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|8| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|9| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|2+0#0000001#ffd7ff255|0| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_set_firstline_2.dump b/src/testdir/dumps/Test_popupwin_set_firstline_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_set_firstline_2.dump @@ -0,0 +1,16 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @25|5+0#0000001#ffd7ff255| @18| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|6+0#0000001#ffd7ff255| @18| +0#0000000#0000001| +0#4040ff13#ffffff0@26 +|~| @25|7+0#0000001#ffd7ff255| @18| +0#0000000#0000001| +0#4040ff13#ffffff0@26 +|~| @25|8+0#0000001#ffd7ff255| @18| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|9+0#0000001#ffd7ff255| @18| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#e0e0e08|0| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255@1| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|2| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|3| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|4| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @25|1+0#0000001#ffd7ff255|5| @17| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@26 +|~| @73 +|~| @73 +|:+0#0000000&| @55|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_win_execute_cursorline.dump b/src/testdir/dumps/Test_popupwin_win_execute_cursorline.dump --- a/src/testdir/dumps/Test_popupwin_win_execute_cursorline.dump +++ b/src/testdir/dumps/Test_popupwin_win_execute_cursorline.dump @@ -1,14 +1,14 @@ > +0&#ffffff0@74 |~+0#4040ff13&| @73 +|~| @34|1+0#0000001#ffd7ff255|3| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 |~| @34|1+0#0000001#ffd7ff255|4| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 |~| @34|1+0#0000001#ffd7ff255|5| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 |~| @34|1+0#0000001#ffd7ff255|6| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 -|~| @34|1+0#0000001#e0e0e08|7| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 +|~| @34|1+0#0000001#e0e0e08|7| +0#0000000#0000001| +0#4040ff13#ffffff0@35 |~| @34|1+0#0000001#ffd7ff255|8| +0#0000000#0000001| +0#4040ff13#ffffff0@35 |~| @34|1+0#0000001#ffd7ff255|9| +0#0000000#0000001| +0#4040ff13#ffffff0@35 -|~| @34|2+0#0000001#ffd7ff255|0| +0#0000000#0000001| +0#4040ff13#ffffff0@35 +|~| @34|2+0#0000001#ffd7ff255|0| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 |~| @34|2+0#0000001#ffd7ff255|1| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 -|~| @34|2+0#0000001#ffd7ff255@1| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@35 |~| @73 |~| @73 |:+0#0000000&| @55|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1581,6 +1581,34 @@ func Test_popup_filter_win_execute() call delete('XtestPopupWinExecute') endfunc +func Test_popup_set_firstline() + CheckScreendump + + let lines =<< trim END + let lines = range(1, 50)->map({_, v -> string(v)}) + let g:id = popup_create(lines, #{ + \ minwidth: 20, + \ maxwidth: 20, + \ minheight: &lines - 5, + \ maxheight: &lines - 5, + \ cursorline: 1, + \ }) + call popup_setoptions(g:id, #{firstline: 10}) + redraw + END + call writefile(lines, 'XtestPopupWinSetFirstline') + let buf = RunVimInTerminal('-S XtestPopupWinSetFirstline', #{rows: 16}) + + call VerifyScreenDump(buf, 'Test_popupwin_set_firstline_1', {}) + + call term_sendkeys(buf, ":call popup_setoptions(g:id, #{firstline: 5})\") + call term_sendkeys(buf, ":\") + call VerifyScreenDump(buf, 'Test_popupwin_set_firstline_2', {}) + + call StopVimInTerminal(buf) + call delete('XtestPopupWinSetFirstline') +endfunc + " this tests that we don't get stuck with an error in "win_execute()" func Test_popup_filter_win_execute_error() CheckScreendump diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1750, +/**/ 1749, /**/ 1748,