diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/popupwin.c | 38 | ||||
-rw-r--r-- | src/structs.h | 9 | ||||
-rw-r--r-- | src/testdir/test_popupwin.vim | 183 | ||||
-rw-r--r-- | src/version.c | 2 |
4 files changed, 224 insertions, 8 deletions
diff --git a/src/popupwin.c b/src/popupwin.c index 4e07bdb597..297faeb4ee 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 2100135ac6..591c5a2fc2 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 0eb171a68b..e4f7cd2322 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 83181abd9f..90c77ead3d 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, |