# HG changeset patch # User Bram Moolenaar # Date 1567196104 -7200 # Node ID fb773f73a4beadfa680b5519084a15162aac476d # Parent d3e61b35a3b67594189d3f8063a9b662726deda1 patch 8.1.1949: cannot scroll a popup window to the very bottom Commit: https://github.com/vim/vim/commit/8c6173c7d3431dd8bc2b6ffc076ef49512a7e175 Author: Bram Moolenaar Date: Fri Aug 30 22:08:34 2019 +0200 patch 8.1.1949: cannot scroll a popup window to the very bottom Problem: Cannot scroll a popup window to the very bottom. Solution: Scroll to the bottom when the "firstline" property was set to -1. (closes #4577) Allow resetting min/max width/height. diff --git a/src/dict.c b/src/dict.c --- a/src/dict.c +++ b/src/dict.c @@ -617,11 +617,21 @@ dict_get_string(dict_T *d, char_u *key, varnumber_T dict_get_number(dict_T *d, char_u *key) { + return dict_get_number_def(d, key, 0); +} + +/* + * Get a number item from a dictionary. + * Returns "def" if the entry doesn't exist. + */ + varnumber_T +dict_get_number_def(dict_T *d, char_u *key, int def) +{ dictitem_T *di; di = dict_find(d, key, -1); if (di == NULL) - return 0; + return def; return tv_get_number(&di->di_tv); } diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -399,13 +399,13 @@ apply_move_options(win_T *wp, dict_T *d) char_u *str; dictitem_T *di; - if ((nr = dict_get_number(d, (char_u *)"minwidth")) > 0) + if ((nr = dict_get_number_def(d, (char_u *)"minwidth", -1)) >= 0) wp->w_minwidth = nr; - if ((nr = dict_get_number(d, (char_u *)"minheight")) > 0) + if ((nr = dict_get_number_def(d, (char_u *)"minheight", -1)) >= 0) wp->w_minheight = nr; - if ((nr = dict_get_number(d, (char_u *)"maxwidth")) > 0) + if ((nr = dict_get_number_def(d, (char_u *)"maxwidth", -1)) >= 0) wp->w_maxwidth = nr; - if ((nr = dict_get_number(d, (char_u *)"maxheight")) > 0) + if ((nr = dict_get_number_def(d, (char_u *)"maxheight", -1)) >= 0) wp->w_maxheight = nr; nr = popup_options_one(d, (char_u *)"line"); @@ -609,9 +609,11 @@ apply_general_options(win_T *wp, dict_T di = dict_find(dict, (char_u *)"firstline", -1); if (di != NULL) + { wp->w_firstline = dict_get_number(dict, (char_u *)"firstline"); - if (wp->w_firstline < 0) - wp->w_firstline = 0; + if (wp->w_firstline < 0) + wp->w_firstline = -1; + } di = dict_find(dict, (char_u *)"scrollbar", -1); if (di != NULL) @@ -1146,7 +1148,7 @@ popup_adjust_position(win_T *wp) } // start at the desired first line - if (wp->w_firstline != 0) + if (wp->w_firstline > 0) wp->w_topline = wp->w_firstline; if (wp->w_topline > wp->w_buffer->b_ml.ml_line_count) wp->w_topline = wp->w_buffer->b_ml.ml_line_count; @@ -1154,9 +1156,15 @@ popup_adjust_position(win_T *wp) // Compute width based on longest text line and the 'wrap' option. // Use a minimum width of one, so that something shows when there is no // text. + // When "firstline" is -1 then start with the last buffer line and go + // backwards. // TODO: more accurate wrapping wp->w_width = 1; - for (lnum = wp->w_topline; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum) + if (wp->w_firstline < 0) + lnum = wp->w_buffer->b_ml.ml_line_count; + else + lnum = wp->w_topline; + while (lnum >= 1 && lnum <= wp->w_buffer->b_ml.ml_line_count) { int len; int w_width = wp->w_width; @@ -1206,10 +1214,21 @@ popup_adjust_position(win_T *wp) } // do not use the width of lines we're not going to show if (wp->w_maxheight > 0 - && lnum - wp->w_topline + 1 + wrapped > wp->w_maxheight) + && (wp->w_firstline >= 0 + ? lnum - wp->w_topline + : wp->w_buffer->b_ml.ml_line_count - lnum) + + 1 + wrapped > wp->w_maxheight) break; + + if (wp->w_firstline < 0) + --lnum; + else + ++lnum; } + if (wp->w_firstline < 0) + wp->w_topline = lnum > 0 ? lnum + 1 : lnum; + wp->w_has_scrollbar = wp->w_want_scrollbar && (wp->w_topline > 1 || lnum <= wp->w_buffer->b_ml.ml_line_count); if (wp->w_has_scrollbar) diff --git a/src/proto/dict.pro b/src/proto/dict.pro --- a/src/proto/dict.pro +++ b/src/proto/dict.pro @@ -26,6 +26,7 @@ long dict_len(dict_T *d); dictitem_T *dict_find(dict_T *d, char_u *key, int len); char_u *dict_get_string(dict_T *d, char_u *key, int save); varnumber_T dict_get_number(dict_T *d, char_u *key); +varnumber_T dict_get_number_def(dict_T *d, char_u *key, int def); varnumber_T dict_get_number_check(dict_T *d, char_u *key); char_u *dict2string(typval_T *tv, int copyID, int restore_copyID); int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate, int literal); diff --git a/src/testdir/dumps/Test_popupwin_firstline.dump b/src/testdir/dumps/Test_popupwin_firstline_1.dump rename from src/testdir/dumps/Test_popupwin_firstline.dump rename to src/testdir/dumps/Test_popupwin_firstline_1.dump diff --git a/src/testdir/dumps/Test_popupwin_firstline_2.dump b/src/testdir/dumps/Test_popupwin_firstline_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_firstline_2.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @73 +|3| @73 +|4| @27|6+0#0000001#ffd7ff255@5| @9| +0#0000000#a8a8a8255| +0&#ffffff0@28 +|5| @27|7+0#0000001#ffd7ff255@4| @10| +0#0000000#a8a8a8255| +0&#ffffff0@28 +|6| @27|8+0#0000001#ffd7ff255@2| @12| +0#0000000#0000001| +0&#ffffff0@28 +|7| @27|9+0#0000001#ffd7ff255@15| +0#0000000#0000001| +0&#ffffff0@28 +|8| @73 +|9| @73 +|:| @55|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_scroll_10.dump b/src/testdir/dumps/Test_popupwin_scroll_10.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_scroll_10.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @31|╔+0#0000001#ffd7ff255|═@5|X| +0#0000000#ffffff0@33 +|3| @31|║+0#0000001#ffd7ff255|f|i|v|e| | +0#0000000#ff404010|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@33 +|4| @31|║+0#0000001#ffd7ff255|s|i|x| @1| +0#0000000#ff404010|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@33 +|5| @31|║+0#0000001#ffd7ff255|s|e|v|e|n| +0#0000000#4040ff13|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@33 +|6| @31|║+0#0000001#ffd7ff255|e|i|g|h|t| +0#0000000#4040ff13|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@33 +|7| @31|║+0#0000001#ffd7ff255|n|i|n|e| | +0#0000000#4040ff13|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@33 +|8| @31|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@33 +|9| @73 +|:|c|a|l@1| |p|o|p|u|p|_|s|e|t|o|p|t|i|o|n|s|(|w|i|n|i|d|,| |#|{|m|a|x|h|e|i|g|h|t|:| |0|,| |m|i|n|w|i|d|t|h|:| |0|1|,|1| @10|T|o|p| 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 @@ -313,14 +313,18 @@ func Test_popup_firstline() let lines =<< trim END call setline(1, range(1, 20)) - call popup_create(['1111', '222222', '33333', '44', '5', '666666', '77777', '888', '9999999999999999'], #{ + let winid = popup_create(['1111', '222222', '33333', '44', '5', '666666', '77777', '888', '9999999999999999'], #{ \ maxheight: 4, \ firstline: 3, \ }) END call writefile(lines, 'XtestPopupFirstline') let buf = RunVimInTerminal('-S XtestPopupFirstline', #{rows: 10}) - call VerifyScreenDump(buf, 'Test_popupwin_firstline', {}) + call VerifyScreenDump(buf, 'Test_popupwin_firstline_1', {}) + + call term_sendkeys(buf, ":call popup_setoptions(winid, #{firstline: -1})\") + call term_sendkeys(buf, ":\") + call VerifyScreenDump(buf, 'Test_popupwin_firstline_2', {}) " clean up call StopVimInTerminal(buf) @@ -1729,6 +1733,10 @@ func Test_popup_scrollbar() call term_sendkeys(buf, ":call ClickBot()\") call VerifyScreenDump(buf, 'Test_popupwin_scroll_9', {}) + " remove the minwidth and maxheight + call term_sendkeys(buf, ":call popup_setoptions(winid, #{maxheight: 0, minwidth: 0})\") + call VerifyScreenDump(buf, 'Test_popupwin_scroll_10', {}) + " clean up call StopVimInTerminal(buf) call delete('XtestPopupScroll') diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1949, +/**/ 1948, /**/ 1947,