summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-06-02 14:49:56 +0200
committerBram Moolenaar <Bram@vim.org>2019-06-02 14:49:56 +0200
commit042fb4b449bb5d8494698803e766dfd288b458cf (patch)
tree10a597d3f5bc0c0ee013ba46117cc1e93878e97a /src
parent988c43310a8dcfad9fbacd110b50ba220227d19a (diff)
downloadvim-git-042fb4b449bb5d8494698803e766dfd288b458cf.tar.gz
patch 8.1.1449: popup text truncated at end of screenv8.1.1449
Problem: Popup text truncated at end of screen. Solution: Move popup left if needed. Add the "fixed" property to disable that. (Ben Jackson , closes #4466)
Diffstat (limited to 'src')
-rw-r--r--src/popupwin.c38
-rw-r--r--src/structs.h9
-rw-r--r--src/testdir/test_popupwin.vim183
-rw-r--r--src/version.c2
4 files changed, 224 insertions, 8 deletions
diff --git a/src/popupwin.c b/src/popupwin.c
index 4e07bdb59..297faeb4e 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -84,6 +84,8 @@ get_pos_options(win_T *wp, dict_T *dict)
if (nr > 0)
wp->w_wantcol = nr;
+ wp->w_popup_fixed = dict_get_number(dict, (char_u *)"fixed") != 0;
+
str = dict_get_string(dict, (char_u *)"pos", FALSE);
if (str != NULL)
{
@@ -379,6 +381,7 @@ popup_adjust_position(win_T *wp)
int maxwidth;
int center_vert = FALSE;
int center_hor = FALSE;
+ int allow_adjust_left = !wp->w_popup_fixed;
wp->w_winrow = 0;
wp->w_wincol = 0;
@@ -412,10 +415,14 @@ popup_adjust_position(win_T *wp)
}
// When centering or right aligned, use maximum width.
- // When left aligned use the space available.
+ // When left aligned use the space available, but shift to the left when we
+ // hit the right of the screen.
maxwidth = Columns - wp->w_wincol;
if (wp->w_maxwidth > 0 && maxwidth > wp->w_maxwidth)
+ {
+ allow_adjust_left = FALSE;
maxwidth = wp->w_maxwidth;
+ }
// Compute width based on longest text line and the 'wrap' option.
// TODO: more accurate wrapping
@@ -424,10 +431,32 @@ popup_adjust_position(win_T *wp)
{
int len = vim_strsize(ml_get_buf(wp->w_buffer, lnum, FALSE));
- while (wp->w_p_wrap && len > maxwidth)
+ if (wp->w_p_wrap)
{
- ++wrapped;
- len -= maxwidth;
+ while (len > maxwidth)
+ {
+ ++wrapped;
+ len -= maxwidth;
+ wp->w_width = maxwidth;
+ }
+ }
+ else if (len > maxwidth
+ && allow_adjust_left
+ && (wp->w_popup_pos == POPPOS_TOPLEFT
+ || wp->w_popup_pos == POPPOS_BOTLEFT))
+ {
+ // adjust leftwise to fit text on screen
+ int shift_by = ( len - maxwidth );
+
+ if ( shift_by > wp->w_wincol )
+ {
+ int truncate_shift = shift_by - wp->w_wincol;
+ len -= truncate_shift;
+ shift_by -= truncate_shift;
+ }
+
+ wp->w_wincol -= shift_by;
+ maxwidth += shift_by;
wp->w_width = maxwidth;
}
if (wp->w_width < len)
@@ -895,6 +924,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
dict_add_number(dict, "maxheight", wp->w_maxheight);
dict_add_number(dict, "maxwidth", wp->w_maxwidth);
dict_add_number(dict, "zindex", wp->w_zindex);
+ dict_add_number(dict, "fixed", wp->w_popup_fixed);
for (i = 0; i < (int)(sizeof(poppos_entries) / sizeof(poppos_entry_T));
++i)
diff --git a/src/structs.h b/src/structs.h
index 2100135ac..591c5a2fc 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -2308,7 +2308,7 @@ struct file_buffer
int b_p_fixeol; /* 'fixendofline' */
int b_p_et; /* 'expandtab' */
int b_p_et_nobin; /* b_p_et saved for binary mode */
- int b_p_et_nopaste; /* b_p_et saved for paste mode */
+ int b_p_et_nopaste; /* b_p_et saved for paste mode */
char_u *b_p_fenc; /* 'fileencoding' */
char_u *b_p_ff; /* 'fileformat' */
char_u *b_p_ft; /* 'filetype' */
@@ -2881,6 +2881,7 @@ struct window_S
#ifdef FEAT_TEXT_PROP
int w_popup_flags; // POPF_ values
poppos_T w_popup_pos;
+ int w_popup_fixed; // do not shift popup to fit on screen
int w_zindex;
int w_minheight; // "minheight" for popup window
int w_minwidth; // "minwidth" for popup window
@@ -3038,8 +3039,8 @@ struct window_S
int w_p_brishift; /* additional shift for breakindent */
int w_p_brisbr; /* sbr in 'briopt' */
#endif
- long w_p_siso; /* 'sidescrolloff' local value */
- long w_p_so; /* 'scrolloff' local value */
+ long w_p_siso; /* 'sidescrolloff' local value */
+ long w_p_so; /* 'scrolloff' local value */
/* transform a pointer to a "onebuf" option into a "allbuf" option */
#define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T))
@@ -3471,7 +3472,7 @@ struct js_reader
int js_used; /* bytes used from js_buf */
int (*js_fill)(struct js_reader *);
/* function to fill the buffer or NULL;
- * return TRUE when the buffer was filled */
+ * return TRUE when the buffer was filled */
void *js_cookie; /* can be used by js_fill */
int js_cookie_arg; /* can be used by js_fill */
};
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index 0eb171a68..e4f7cd232 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -422,6 +422,7 @@ func Test_popup_getoptions()
\ 'maxheight': 21,
\ 'zindex': 100,
\ 'time': 5000,
+ \ 'fixed': 1
\})
redraw
let res = popup_getoptions(winid)
@@ -432,6 +433,7 @@ func Test_popup_getoptions()
call assert_equal(20, res.maxwidth)
call assert_equal(21, res.maxheight)
call assert_equal(100, res.zindex)
+ call assert_equal(1, res.fixed)
if has('timers')
call assert_equal(5000, res.time)
endif
@@ -447,6 +449,7 @@ func Test_popup_getoptions()
call assert_equal(0, res.maxwidth)
call assert_equal(0, res.maxheight)
call assert_equal(50, res.zindex)
+ call assert_equal(0, res.fixed)
if has('timers')
call assert_equal(0, res.time)
endif
@@ -647,3 +650,183 @@ func Test_popup_never_behind()
call StopVimInTerminal(buf)
call delete('XtestPopupBehind')
endfunc
+
+func s:VerifyPosition( p, msg, line, col, width, height )
+ call assert_equal( a:line, popup_getpos( a:p ).line, a:msg . ' (l)' )
+ call assert_equal( a:col, popup_getpos( a:p ).col, a:msg . ' (c)' )
+ call assert_equal( a:width, popup_getpos( a:p ).width, a:msg . ' (w)' )
+ call assert_equal( a:height, popup_getpos( a:p ).height, a:msg . ' (h)' )
+endfunc
+
+func Test_popup_position_adjust()
+ " Anything placed past 2 cells from of the right of the screen is moved to the
+ " left.
+ "
+ " When wrapping is disabled, we also shift to the left to display on the
+ " screen, unless fixed is set.
+
+ " Entries for cases which don't vary based on wrapping.
+ " Format is per tests described below
+ let both_wrap_tests = [
+ \ [ 'a', 5, &columns, 5, &columns - 2, 1, 1 ],
+ \ [ 'b', 5, &columns + 1, 5, &columns - 2, 1, 1 ],
+ \ [ 'c', 5, &columns - 1, 5, &columns - 2, 1, 1 ],
+ \ [ 'd', 5, &columns - 2, 5, &columns - 2, 1, 1 ],
+ \ [ 'e', 5, &columns - 3, 5, &columns - 3, 1, 1 ],
+ \
+ \ [ 'aa', 5, &columns, 5, &columns - 2, 2, 1 ],
+ \ [ 'bb', 5, &columns + 1, 5, &columns - 2, 2, 1 ],
+ \ [ 'cc', 5, &columns - 1, 5, &columns - 2, 2, 1 ],
+ \ [ 'dd', 5, &columns - 2, 5, &columns - 2, 2, 1 ],
+ \ [ 'ee', 5, &columns - 3, 5, &columns - 3, 2, 1 ],
+ \
+ \ [ 'aaa', 5, &columns, 5, &columns - 2, 3, 1 ],
+ \ [ 'bbb', 5, &columns + 1, 5, &columns - 2, 3, 1 ],
+ \ [ 'ccc', 5, &columns - 1, 5, &columns - 2, 3, 1 ],
+ \ [ 'ddd', 5, &columns - 2, 5, &columns - 2, 3, 1 ],
+ \ [ 'eee', 5, &columns - 3, 5, &columns - 3, 3, 1 ],
+ \ ]
+
+ " these test groups are dicts with:
+ " - comment: something to identify the group of tests by
+ " - options: dict of options to merge with the row/col in tests
+ " - tests: list of cases. Each one is a list with elements:
+ " - text
+ " - row
+ " - col
+ " - expected row
+ " - expected col
+ " - expected width
+ " - expected height
+ let tests = [
+ \ {
+ \ 'comment': 'left-aligned with wrapping',
+ \ 'options': {
+ \ 'wrap': 1,
+ \ 'pos': 'botleft',
+ \ },
+ \ 'tests': both_wrap_tests + [
+ \ [ 'aaaa', 5, &columns, 4, &columns - 2, 3, 2 ],
+ \ [ 'bbbb', 5, &columns + 1, 4, &columns - 2, 3, 2 ],
+ \ [ 'cccc', 5, &columns - 1, 4, &columns - 2, 3, 2 ],
+ \ [ 'dddd', 5, &columns - 2, 4, &columns - 2, 3, 2 ],
+ \ [ 'eeee', 5, &columns - 3, 5, &columns - 3, 4, 1 ],
+ \ ],
+ \ },
+ \ {
+ \ 'comment': 'left aligned without wrapping',
+ \ 'options': {
+ \ 'wrap': 0,
+ \ 'pos': 'botleft',
+ \ },
+ \ 'tests': both_wrap_tests + [
+ \ [ 'aaaa', 5, &columns, 5, &columns - 3, 4, 1 ],
+ \ [ 'bbbb', 5, &columns + 1, 5, &columns - 3, 4, 1 ],
+ \ [ 'cccc', 5, &columns - 1, 5, &columns - 3, 4, 1 ],
+ \ [ 'dddd', 5, &columns - 2, 5, &columns - 3, 4, 1 ],
+ \ [ 'eeee', 5, &columns - 3, 5, &columns - 3, 4, 1 ],
+ \ ],
+ \ },
+ \ {
+ \ 'comment': 'left aligned with fixed position',
+ \ 'options': {
+ \ 'wrap': 0,
+ \ 'fixed': 1,
+ \ 'pos': 'botleft',
+ \ },
+ \ 'tests': both_wrap_tests + [
+ \ [ 'aaaa', 5, &columns, 5, &columns - 2, 3, 1 ],
+ \ [ 'bbbb', 5, &columns + 1, 5, &columns - 2, 3, 1 ],
+ \ [ 'cccc', 5, &columns - 1, 5, &columns - 2, 3, 1 ],
+ \ [ 'dddd', 5, &columns - 2, 5, &columns - 2, 3, 1 ],
+ \ [ 'eeee', 5, &columns - 3, 5, &columns - 3, 4, 1 ],
+ \ ],
+ \ },
+ \ ]
+
+ for test_group in tests
+ for test in test_group.tests
+ let [ text, line, col, e_line, e_col, e_width, e_height ] = test
+ let options = {
+ \ 'line': line,
+ \ 'col': col,
+ \ }
+ call extend( options, test_group.options )
+
+ let p = popup_create( text, options )
+
+ let msg = string( extend( options, { 'text': text } ) )
+ call s:VerifyPosition( p, msg, e_line, e_col, e_width, e_height )
+ call popup_close( p )
+ endfor
+ endfor
+
+ popupclear
+ %bwipe!
+endfunc
+
+function Test_adjust_left_past_screen_width()
+ " width of screen
+ let X = join(map(range(&columns), {->'X'}), '')
+
+ let p = popup_create( X, { 'line': 1, 'col': 1, 'wrap': 0 } )
+ call s:VerifyPosition( p, 'full width topleft', 1, 1, &columns, 1 )
+
+ redraw
+ let line = join(map(range(1, &columns + 1), 'screenstring(1, v:val)'), '')
+ call assert_equal(X, line)
+
+ call popup_close( p )
+ redraw
+
+ " Same if placed on the right hand side
+ let p = popup_create( X, { 'line': 1, 'col': &columns, 'wrap': 0 } )
+ call s:VerifyPosition( p, 'full width topright', 1, 1, &columns, 1 )
+
+ redraw
+ let line = join(map(range(1, &columns + 1), 'screenstring(1, v:val)'), '')
+ call assert_equal(X, line)
+
+ call popup_close( p )
+ redraw
+
+ " Extend so > window width
+ let X .= 'x'
+
+ let p = popup_create( X, { 'line': 1, 'col': 1, 'wrap': 0 } )
+ call s:VerifyPosition( p, 'full width + 1 topleft', 1, 1, &columns, 1 )
+
+ redraw
+ let line = join(map(range(1, &columns + 1), 'screenstring(1, v:val)'), '')
+ call assert_equal(X[ : -2 ], line)
+
+ call popup_close( p )
+ redraw
+
+ " Shifted then truncated (the x is not visible)
+ let p = popup_create( X, { 'line': 1, 'col': &columns - 3, 'wrap': 0 } )
+ call s:VerifyPosition( p, 'full width + 1 topright', 1, 1, &columns, 1 )
+
+ redraw
+ let line = join(map(range(1, &columns + 1), 'screenstring(1, v:val)'), '')
+ call assert_equal(X[ : -2 ], line)
+
+ call popup_close( p )
+ redraw
+
+ " Not shifted, just truncated
+ let p = popup_create( X,
+ \ { 'line': 1, 'col': 2, 'wrap': 0, 'fixed': 1 } )
+ call s:VerifyPosition( p, 'full width + 1 fixed', 1, 2, &columns - 1, 1)
+
+ redraw
+ let line = join(map(range(1, &columns + 1), 'screenstring(1, v:val)'), '')
+ let e_line = ' ' . X[ 1 : -2 ]
+ call assert_equal(e_line, line)
+
+ call popup_close( p )
+ redraw
+
+ popupclear
+ %bwipe!
+endfunction
diff --git a/src/version.c b/src/version.c
index 83181abd9..90c77ead3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1449,
+/**/
1448,
/**/
1447,