]> granicus.if.org Git - vim/commitdiff
patch 8.1.2265: when popup with "botleft" does not fit it flips incorrectly v8.1.2265
authorBram Moolenaar <Bram@vim.org>
Wed, 6 Nov 2019 18:25:22 +0000 (19:25 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 6 Nov 2019 18:25:22 +0000 (19:25 +0100)
Problem:    When popup with "botleft" does not fit it flips incorrectly.
Solution:   Only flip when there is more space on the other side.  Add the
            "posinvert" option to disable flipping and do it in both
            directions if enabled.  (closes #5151)

src/popupwin.c
src/testdir/dumps/Test_popupwin_nospace.dump [new file with mode: 0644]
src/testdir/test_popupwin.vim
src/version.c
src/vim.h

index ddb1254d1b4a3f75f13525fe7fe5754a0381c2c1..ce2f51da27ad479985dd0b69444a4f596960fa9b 100644 (file)
@@ -673,6 +673,16 @@ apply_general_options(win_T *wp, dict_T *dict)
            wp->w_popup_flags &= ~POPF_DRAG;
     }
 
+    di = dict_find(dict, (char_u *)"posinvert", -1);
+    if (di != NULL)
+    {
+       nr = dict_get_number(dict, (char_u *)"posinvert");
+       if (nr)
+           wp->w_popup_flags |= POPF_POSINVERT;
+       else
+           wp->w_popup_flags &= ~POPF_POSINVERT;
+    }
+
     di = dict_find(dict, (char_u *)"resize", -1);
     if (di != NULL)
     {
@@ -1383,15 +1393,35 @@ popup_adjust_position(win_T *wp)
            wp->w_winrow = 0;
     }
     else if (wp->w_popup_pos == POPPOS_BOTRIGHT
-           || wp->w_popup_pos == POPPOS_BOTLEFT)
+               || wp->w_popup_pos == POPPOS_BOTLEFT)
     {
        if ((wp->w_height + extra_height) <= wantline)
            // bottom aligned: may move down
            wp->w_winrow = wantline - (wp->w_height + extra_height);
+       else if (wantline * 2 >= Rows || !(wp->w_popup_flags & POPF_POSINVERT))
+       {
+           // Bottom aligned but does not fit, and less space on the other
+           // side or "posinvert" is off: reduce height.
+           wp->w_winrow = 0;
+           wp->w_height = wantline - extra_height;
+       }
        else
-           // Not enough space, make top aligned.
+           // Not enough space and more space on the other side: make top
+           // aligned.
            wp->w_winrow = (wantline < 0 ? 0 : wantline) + 1;
     }
+    else if (wp->w_popup_pos == POPPOS_TOPRIGHT
+               || wp->w_popup_pos == POPPOS_TOPLEFT)
+    {
+       if (wantline + (wp->w_height + extra_height) - 1 > Rows
+               && wantline * 2 > Rows
+               && (wp->w_popup_flags & POPF_POSINVERT))
+           // top aligned and not enough space below but there is space above:
+           // make bottom aligned
+           wp->w_winrow = wantline - 2 - wp->w_height - extra_height;
+       else
+           wp->w_winrow = wantline - 1;
+    }
     if (wp->w_winrow >= Rows)
        wp->w_winrow = Rows - 1;
     else if (wp->w_winrow < 0)
@@ -1730,7 +1760,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
     if (rettv != NULL)
        rettv->vval.v_number = wp->w_id;
     wp->w_popup_pos = POPPOS_TOPLEFT;
-    wp->w_popup_flags = POPF_IS_POPUP | POPF_MAPPING;
+    wp->w_popup_flags = POPF_IS_POPUP | POPF_MAPPING | POPF_POSINVERT;
 
     if (buf != NULL)
     {
@@ -2670,6 +2700,8 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
        dict_add_number(dict, "mapping",
                                      (wp->w_popup_flags & POPF_MAPPING) != 0);
        dict_add_number(dict, "resize", (wp->w_popup_flags & POPF_RESIZE) != 0);
+       dict_add_number(dict, "posinvert",
+                                   (wp->w_popup_flags & POPF_POSINVERT) != 0);
        dict_add_number(dict, "cursorline",
                                   (wp->w_popup_flags & POPF_CURSORLINE) != 0);
        dict_add_string(dict, "highlight", wp->w_p_wcr);
@@ -2830,7 +2862,7 @@ invoke_popup_filter(win_T *wp, int c)
 
     argv[2].v_type = VAR_UNKNOWN;
 
-    // NOTE: The callback might close the popup, thus make "wp" invalid.
+    // NOTE: The callback might close the popup and make "wp" invalid.
     call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv);
     if (win_valid_popup(wp) && old_lnum != wp->w_cursor.lnum)
        popup_highlight_curline(wp);
diff --git a/src/testdir/dumps/Test_popupwin_nospace.dump b/src/testdir/dumps/Test_popupwin_nospace.dump
new file mode 100644 (file)
index 0000000..f062a68
--- /dev/null
@@ -0,0 +1,12 @@
+|-+0&#ffffff0|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@1|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@8|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@32| @14
+|-|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|a@2|║|-+0#0000000#ffffff0@32| @14
+|-|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|b@2|║|-+0#0000000#ffffff0@15|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@11| @14
+|-|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@1|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|c@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@11| @14
+|-|@|-@5|#|-@5|%|-@5|║+0#0000001#ffd7ff255|d@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1>*|-@8| @14
+|-@14|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|e@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|t|e@1|║|-+0#0000000#ffffff0@1|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@4| @14
+|-@14|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@1|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@15|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|a@2|║|-+0#0000000#ffffff0@4| @14
+|-@14|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|*|-@5|@|-@5|#|-@5|%|-@5|║+0#0000001#ffd7ff255|b@2|║|-+0#0000000#ffffff0@4| @14
+|-@14|║+0#0000001#ffd7ff255|t|e@1|║|-+0#0000000#ffffff0@8|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@1|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|c@2|║|-+0#0000000#ffffff0@4| @14
+|-@14|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|d@2|║|-+0#0000000#ffffff0@4| @14
+|-@28|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|e@2|║|-+0#0000000#ffffff0@4| @14
+@29|╚+0#0000001#ffd7ff255|═@2|╝| +0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|t|e@1|║| +0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|f@2|║| +0#0000000#ffffff0@1|5|,|5|1| @9|T|o|p| 
index e38b7211e0881717170f7f7f97fb08f580d680aa..0a45df4e1fd742ff1202495003573ef41f07ed5e 100644 (file)
@@ -323,6 +323,98 @@ func Test_popup_all_corners()
   call delete('XtestPopupCorners')
 endfunc
 
+func Test_popup_nospace()
+  CheckScreendump
+
+  let lines =<< trim END
+       call setline(1, repeat([repeat('-', 60)], 15))
+       set so=0
+
+       " cursor in a line in top half, using "botleft" with popup that
+       " does fit
+       normal 5G2|r@
+       let winid1 = popup_create(['one', 'two'], #{
+             \ line: 'cursor-1',
+             \ col: 'cursor',
+             \ pos: 'botleft',
+             \ border: [],
+             \ })
+       " cursor in a line in top half, using "botleft" with popup that
+       " doesn't fit: gets truncated
+       normal 5G9|r#
+       let winid1 = popup_create(['one', 'two', 'tee'], #{
+             \ line: 'cursor-1',
+             \ col: 'cursor',
+             \ pos: 'botleft',
+             \ posinvert: 0,
+             \ border: [],
+             \ })
+       " cursor in a line in top half, using "botleft" with popup that
+       " doesn't fit and 'posinvert' set: flips to below.
+       normal 5G16|r%
+       let winid1 = popup_create(['one', 'two', 'tee'], #{
+             \ line: 'cursor-1',
+             \ col: 'cursor',
+             \ pos: 'botleft',
+             \ border: [],
+             \ })
+       " cursor in a line in bottom half, using "botleft" with popup that
+       " doesn't fit: does not flip.
+       normal 8G23|r*
+       let winid1 = popup_create(['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff'], #{
+             \ line: 'cursor-1',
+             \ col: 'cursor',
+             \ pos: 'botleft',
+             \ border: [],
+             \ })
+
+       " cursor in a line in bottom half, using "topleft" with popup that
+       " does fit
+       normal 8G30|r@
+       let winid1 = popup_create(['one', 'two'], #{
+             \ line: 'cursor+1',
+             \ col: 'cursor',
+             \ pos: 'topleft',
+             \ border: [],
+             \ })
+       " cursor in a line in top half, using "topleft" with popup that
+       " doesn't fit: truncated
+       normal 8G37|r#
+       let winid1 = popup_create(['one', 'two', 'tee'], #{
+             \ line: 'cursor+1',
+             \ col: 'cursor',
+             \ pos: 'topleft',
+             \ posinvert: 0,
+             \ border: [],
+             \ })
+       " cursor in a line in top half, using "topleft" with popup that
+       " doesn't fit and "posinvert" set: flips to below.
+       normal 8G44|r%
+       let winid1 = popup_create(['one', 'two', 'tee'], #{
+             \ line: 'cursor+1',
+             \ col: 'cursor',
+             \ pos: 'topleft',
+             \ border: [],
+             \ })
+       " cursor in a line in top half, using "topleft" with popup that
+       " doesn't fit: does not flip.
+       normal 5G51|r*
+       let winid1 = popup_create(['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff'], #{
+             \ line: 'cursor+1',
+             \ col: 'cursor',
+             \ pos: 'topleft',
+             \ border: [],
+             \ })
+  END
+  call writefile(lines, 'XtestPopupNospace')
+  let buf = RunVimInTerminal('-S XtestPopupNospace', #{rows: 12})
+  call VerifyScreenDump(buf, 'Test_popupwin_nospace', {})
+
+  " clean up
+  call StopVimInTerminal(buf)
+  call delete('XtestPopupNospace')
+endfunc
+
 func Test_popup_firstline()
   CheckScreendump
 
@@ -586,6 +678,7 @@ func Test_popup_with_mask()
            \], #{
            \ line: 1,
            \ col: 10,
+           \ posinvert: 0,
            \ wrap: 0,
            \ fixed: 1,
            \ zindex: 90,
@@ -604,6 +697,7 @@ func Test_popup_with_mask()
            \], #{
            \ line: 7,
            \ col: 10,
+           \ posinvert: 0,
            \ wrap: 0,
            \ fixed: 1,
            \ close: 'button',
index 8dcefd48fd1000dc5a0504e3eb328580650ef109..73a0c1f41ae27f29d041292c3895f2f9f2c088e4 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2265,
 /**/
     2264,
 /**/
index 97c1f6cfdac31f9f2ddb15b138746f808f94a207..fe1e982c5d610944f35f4c7be4030f7005cf1333 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -632,6 +632,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 #define POPF_MAPPING   0x80    // mapping keys
 #define POPF_INFO      0x100   // used for info of popup menu
 #define POPF_INFO_MENU 0x200   // align info popup with popup menu
+#define POPF_POSINVERT 0x400   // vertical position can be inverted
 
 #ifdef FEAT_TEXT_PROP
 # define WIN_IS_POPUP(wp) ((wp)->w_popup_flags != 0)