changeset 17905:fb773f73a4be v8.1.1949

patch 8.1.1949: cannot scroll a popup window to the very bottom Commit: https://github.com/vim/vim/commit/8c6173c7d3431dd8bc2b6ffc076ef49512a7e175 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Fri, 30 Aug 2019 22:15:04 +0200
parents d3e61b35a3b6
children b70e65826005
files src/dict.c src/popupwin.c src/proto/dict.pro src/testdir/dumps/Test_popupwin_firstline.dump src/testdir/dumps/Test_popupwin_firstline_1.dump src/testdir/dumps/Test_popupwin_firstline_2.dump src/testdir/dumps/Test_popupwin_scroll_10.dump src/testdir/test_popupwin.vim src/version.c
diffstat 9 files changed, 82 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- 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);
 }
 
--- 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)
--- 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);
rename from src/testdir/dumps/Test_popupwin_firstline.dump
rename to src/testdir/dumps/Test_popupwin_firstline_1.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| 
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| 
--- 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})\<CR>")
+  call term_sendkeys(buf, ":\<CR>")
+  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()\<CR>")
   call VerifyScreenDump(buf, 'Test_popupwin_scroll_9', {})
 
+  " remove the minwidth and maxheight
+  call term_sendkeys(buf, ":call popup_setoptions(winid, #{maxheight: 0, minwidth: 0})\<CR>")
+  call VerifyScreenDump(buf, 'Test_popupwin_scroll_10', {})
+
   " clean up
   call StopVimInTerminal(buf)
   call delete('XtestPopupScroll')
--- 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,