From 99a764bccd995a6cfe3206909f0076ef84d77506 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 17 Jul 2019 20:01:48 +0200 Subject: [PATCH 1/9] patch 8.1.1706: typo in #ifdef Problem: Typo in #ifdef. Solution: Change PROT to PROTO. --- src/beval.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/beval.c b/src/beval.c index dc8966fe2f..193964667a 100644 --- a/src/beval.c +++ b/src/beval.c @@ -10,7 +10,7 @@ #include "vim.h" -#if defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) || defined(PROT) +#if defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) || defined(PROTO) /* * Find text under the mouse position "row" / "col". * If "getword" is TRUE the returned text in "*textp" is not the whole line but diff --git a/src/version.c b/src/version.c index bc8dab7280..573f741423 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1706, /**/ 1705, /**/ From cfdbc5adde49cbab939e8164555ed0b8d9ce000b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 17 Jul 2019 21:27:52 +0200 Subject: [PATCH 2/9] patch 8.1.1707: Coverity warns for possibly using a NULL pointer Problem: Coverity warns for possibly using a NULL pointer. Solution: Change the logic to make sure no NULL pointer is used. --- src/popupwin.c | 7 +++---- src/testdir/test_popupwin.vim | 4 ++++ src/version.c | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index e61b793cd4..322537bf87 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -587,14 +587,13 @@ apply_general_options(win_T *wp, dict_T *dict) di = dict_find(dict, (char_u *)"mask", -1); if (di != NULL) { - int ok = TRUE; + int ok = FALSE; - if (di->di_tv.v_type != VAR_LIST) - ok = FALSE; - else if (di->di_tv.vval.v_list != NULL) + if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { listitem_T *li; + ok = TRUE; for (li = di->di_tv.vval.v_list->lv_first; li != NULL; li = li->li_next) { diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 8b1ea1f6f6..26d1c94ae1 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -643,6 +643,10 @@ func Test_popup_invalid_arguments() call popup_clear() call assert_fails('call popup_create([#{text: "text", props: ["none"]}], {})', 'E715:') call popup_clear() + call assert_fails('call popup_create("text", #{mask: ["asdf"]})', 'E475:') + call popup_clear() + call assert_fails('call popup_create("text", #{mask: test_null_list()})', 'E475:') + call popup_clear() endfunc func Test_win_execute_closing_curwin() diff --git a/src/version.c b/src/version.c index 573f741423..b1187db572 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1707, /**/ 1706, /**/ From 3fb4f4762b49a5b5a54c17e0296e49ec815aee6c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 17 Jul 2019 21:32:14 +0200 Subject: [PATCH 3/9] patch 8.1.1708: Coverity warns for using uninitialized variable Problem: Coverity warns for using uninitialized variable. Solution: Set the start col when col is set. --- src/beval.c | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/beval.c b/src/beval.c index 193964667a..3dd9b6770c 100644 --- a/src/beval.c +++ b/src/beval.c @@ -72,6 +72,7 @@ find_word_under_cursor( } col = vcol2col(wp, lnum, col); + scol = col; if (VIsual_active && wp->w_buffer == curwin->w_buffer @@ -95,6 +96,7 @@ find_word_under_cursor( lbuf = vim_strnsave(lbuf + spos->col, len); lnum = spos->lnum; col = spos->col; + scol = col; } else { diff --git a/src/version.c b/src/version.c index b1187db572..d1f5eba6b2 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1708, /**/ 1707, /**/ From 403d090e39abdc741c1b2ec0a05361cffd348289 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 17 Jul 2019 21:37:32 +0200 Subject: [PATCH 4/9] patch 8.1.1709: Coverity warns for possibly using a NULL pointer Problem: Coverity warns for possibly using a NULL pointer. Solution: Make sure no NULL pointer is used. --- src/popupwin.c | 19 +++++++++---------- src/testdir/test_popupwin.vim | 2 ++ src/version.c | 2 ++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 322537bf87..f977517262 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -516,7 +516,7 @@ apply_general_options(win_T *wp, dict_T *dict) di = dict_find(dict, (char_u *)"borderhighlight", -1); if (di != NULL) { - if (di->di_tv.v_type != VAR_LIST) + if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL) emsg(_(e_listreq)); else { @@ -524,17 +524,16 @@ apply_general_options(win_T *wp, dict_T *dict) listitem_T *li; int i; - if (list != NULL) - for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len; - ++i, li = li->li_next) - { - str = tv_get_string(&li->li_tv); - if (*str != NUL) - wp->w_border_highlight[i] = vim_strsave(str); - } + for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len; + ++i, li = li->li_next) + { + str = tv_get_string(&li->li_tv); + if (*str != NUL) + wp->w_border_highlight[i] = vim_strsave(str); + } if (list->lv_len == 1 && wp->w_border_highlight[0] != NULL) for (i = 1; i < 4; ++i) - wp->w_border_highlight[i] = + wp->w_border_highlight[i] = vim_strsave(wp->w_border_highlight[0]); } } diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 26d1c94ae1..740ac61396 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -634,6 +634,8 @@ func Test_popup_invalid_arguments() call popup_clear() call assert_fails('call popup_create("text", #{borderhighlight: "none"})', 'E714:') call popup_clear() + call assert_fails('call popup_create("text", #{borderhighlight: test_null_list()})', 'E714:') + call popup_clear() call assert_fails('call popup_create("text", #{borderchars: "none"})', 'E714:') call popup_clear() diff --git a/src/version.c b/src/version.c index d1f5eba6b2..0ac981ed7a 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1709, /**/ 1708, /**/ From 4a0a161a9bdc074498b85e1dd6bb2aab62a53aee Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 17 Jul 2019 22:00:19 +0200 Subject: [PATCH 5/9] patch 8.1.1710: Coverity found dead code Problem: Coverity found dead code. Solution: Remove merging of listener changes. --- src/change.c | 53 ++++++++++----------------------------------------- src/version.c | 2 ++ 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/src/change.c b/src/change.c index 761e764f85..0f6164b04b 100644 --- a/src/change.c +++ b/src/change.c @@ -155,19 +155,16 @@ changed_internal(void) static long next_listener_id = 0; /* - * Check if the change at "lnum" / "col" is above or overlaps with an existing - * changed. If above then flush changes and invoke listeners. - * If "merge" is TRUE do the merge. + * Check if the change at "lnum" is above or overlaps with an existing + * change. If above then flush changes and invoke listeners. * Returns TRUE if the change was merged. */ static int check_recorded_changes( buf_T *buf, linenr_T lnum, - colnr_T col, linenr_T lnume, - long xtra, - int merge) + long xtra) { if (buf->b_recorded_changes != NULL && xtra != 0) { @@ -182,42 +179,12 @@ check_recorded_changes( li->li_tv.vval.v_dict, (char_u *)"lnum"); prev_lnume = (linenr_T)dict_get_number( li->li_tv.vval.v_dict, (char_u *)"end"); - if (prev_lnum >= lnum || prev_lnum > lnume - || (prev_lnume >= lnum && xtra != 0)) + if (prev_lnum >= lnum || prev_lnum > lnume || prev_lnume >= lnum) { - if (li->li_next == NULL && lnum == prev_lnum - && xtra == 0 - && col + 1 == (colnr_T)dict_get_number( - li->li_tv.vval.v_dict, (char_u *)"col")) - { - if (merge) - { - dictitem_T *di; - - // Same start point and nothing is following, entries - // can be merged. - di = dict_find(li->li_tv.vval.v_dict, - (char_u *)"end", -1); - if (di != NULL) - { - prev_lnum = tv_get_number(&di->di_tv); - if (lnume > prev_lnum) - di->di_tv.vval.v_number = lnume; - } - di = dict_find(li->li_tv.vval.v_dict, - (char_u *)"added", -1); - if (di != NULL) - di->di_tv.vval.v_number += xtra; - return TRUE; - } - } - else - { - // the current change is going to make the line number in - // the older change invalid, flush now - invoke_listeners(curbuf); - break; - } + // the current change is going to make the line number in + // the older change invalid, flush now + invoke_listeners(curbuf); + break; } } } @@ -242,7 +209,7 @@ may_record_change( // If the new change is going to change the line numbers in already listed // changes, then flush. - if (check_recorded_changes(curbuf, lnum, col, lnume, xtra, TRUE)) + if (check_recorded_changes(curbuf, lnum, lnume, xtra)) return; if (curbuf->b_recorded_changes == NULL) @@ -362,7 +329,7 @@ f_listener_remove(typval_T *argvars, typval_T *rettv) void may_invoke_listeners(buf_T *buf, linenr_T lnum, linenr_T lnume, int added) { - check_recorded_changes(buf, lnum, 0, lnume, added, FALSE); + check_recorded_changes(buf, lnum, lnume, added); } /* diff --git a/src/version.c b/src/version.c index 0ac981ed7a..74a16fe367 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1710, /**/ 1709, /**/ From acf7544cf62227972eeb063d6d9ecddaa5682a73 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 17 Jul 2019 22:55:35 +0200 Subject: [PATCH 6/9] patch 8.1.1711: listener callback called at the wrong moment Problem: Listener callback called at the wrong moment Solution: Invoke listeners before calling ml_delete_int(). (closes #4657) --- src/memline.c | 17 +++++++++-------- src/version.c | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/memline.c b/src/memline.c index af3e2f4434..0a947f9273 100644 --- a/src/memline.c +++ b/src/memline.c @@ -3566,6 +3566,15 @@ adjust_text_props_for_delete( ml_delete(linenr_T lnum, int message) { ml_flush_line(curbuf); + if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) + return FAIL; + +#ifdef FEAT_EVAL + // When inserting above recorded changes: flush the changes before changing + // the text. + may_invoke_listeners(curbuf, lnum, lnum + 1, -1); +#endif + return ml_delete_int(curbuf, lnum, message); } @@ -3590,14 +3599,6 @@ ml_delete_int(buf_T *buf, linenr_T lnum, int message) int textprop_save_len; #endif - if (lnum < 1 || lnum > buf->b_ml.ml_line_count) - return FAIL; - -#ifdef FEAT_EVAL - // When inserting above recorded changes: flush the changes before changing - // the text. - may_invoke_listeners(buf, lnum, lnum + 1, -1); -#endif if (lowest_marked && lowest_marked > lnum) lowest_marked--; diff --git a/src/version.c b/src/version.c index 74a16fe367..6c6550b090 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1711, /**/ 1710, /**/ From d6bcff457799e491c3d27880858ec08e758e1849 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 18 Jul 2019 12:48:16 +0200 Subject: [PATCH 7/9] patch 8.1.1712: signs in number column cause text to be misaligned Problem: Signs in number column cause text to be misaligned. Solution: Improve alignment. (Yasuhiro Matsumoto, closes #4694) --- src/screen.c | 9 +++++++-- src/testdir/test_signs.vim | 7 +++++++ src/version.c | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/screen.c b/src/screen.c index 825b7ab0e8..fdb1e0af5b 100644 --- a/src/screen.c +++ b/src/screen.c @@ -3120,8 +3120,13 @@ get_sign_display_info( { if (nrcol) { - sprintf((char *)extra, "%*s ", number_width(wp), - *pp_extra); + int n, width = number_width(wp) - 2; + + for (n = 0; n < width; n++) + extra[n] = ' '; + extra[n] = 0; + STRCAT(extra, *pp_extra); + STRCAT(extra, " "); *pp_extra = extra; } *c_extrap = NUL; diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim index 1b9a29d9fe..3d885d6428 100644 --- a/src/testdir/test_signs.vim +++ b/src/testdir/test_signs.vim @@ -1766,6 +1766,7 @@ func Test_sign_numcol() set number set signcolumn=number sign define sign1 text==> + sign define sign2 text=V sign place 10 line=1 name=sign1 redraw! call assert_equal("=> 01234", s:ScreenLine(1, 1, 8)) @@ -1846,6 +1847,12 @@ func Test_sign_numcol() redraw! call assert_equal("=> 01234", s:ScreenLine(1, 1, 8)) call assert_equal(" 2 abcde", s:ScreenLine(2, 1, 8)) + " Add sign with multi-byte text + set numberwidth=4 + sign place 40 line=2 name=sign2 + redraw! + call assert_equal(" => 01234", s:ScreenLine(1, 1, 9)) + call assert_equal(" V abcde", s:ScreenLine(2, 1, 9)) sign unplace * group=* sign undefine sign1 diff --git a/src/version.c b/src/version.c index 6c6550b090..a6d1492e26 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1712, /**/ 1711, /**/ From df9c6cad8cc318e26e99c3b055f0788e7d6582de Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 18 Jul 2019 13:46:42 +0200 Subject: [PATCH 8/9] patch 8.1.1713: highlighting cursor line only works with popup_menu() Problem: Highlighting cursor line only works with popup_menu(). Solution: Add the "cursorline" property. (Naruhiko Nishino, closes #4671) --- runtime/doc/popup.txt | 17 +- src/popupwin.c | 76 +++++--- .../dumps/Test_popupwin_cursorline_1.dump | 10 + .../dumps/Test_popupwin_cursorline_2.dump | 10 + .../dumps/Test_popupwin_cursorline_3.dump | 10 + .../dumps/Test_popupwin_cursorline_4.dump | 10 + .../dumps/Test_popupwin_cursorline_5.dump | 10 + .../dumps/Test_popupwin_cursorline_6.dump | 10 + .../dumps/Test_popupwin_menu_filter_1.dump | 10 + .../dumps/Test_popupwin_menu_filter_2.dump | 10 + .../dumps/Test_popupwin_menu_filter_3.dump | 10 + .../dumps/Test_popupwin_menu_filter_4.dump | 10 + src/testdir/test_popupwin.vim | 172 ++++++++++++++++++ src/version.c | 2 + src/vim.h | 1 + 15 files changed, 339 insertions(+), 29 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_6.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_4.dump diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index cbe83107de..1b39bcf679 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -303,7 +303,7 @@ popup_getoptions({id}) *popup_getoptions()* zero. When all values are one then an empty list is included. "borderhighlight" is not included when all values are empty. - "scrollbarhighlight" and "thumbhighlight" are onlu included + "scrollbarhighlight" and "thumbhighlight" are only included when set. "tabpage" will be -1 for a global popup, zero for a popup on @@ -345,7 +345,7 @@ popup_hide({id}) *popup_hide()* popup_locate({row}, {col}) *popup_locate()* - Return the |window-ID| of the popup at screen positoin {row} + Return the |window-ID| of the popup at screen position {row} and {col}. If there are multiple popups the one with the highest zindex is returned. If there are no popups at this position then zero is returned. @@ -362,6 +362,7 @@ popup_menu({what}, {options}) *popup_menu()* \ drag: 1, \ wrap: 0, \ border: [], + \ cursorline: 1, \ padding: [0,1,0,1], \ filter: 'popup_filter_menu', \ }) @@ -429,6 +430,7 @@ popup_setoptions({id}, {options}) *popup_setoptions()* callback close drag + cursorline filter firstline flip @@ -598,6 +600,11 @@ The second argument of |popup_create()| is a dictionary with options: {start} or after {end} The popup also closes if the cursor moves to another line or to another window. + cursorline non-zero: Highlight the cursor line. Also scrolls the + text to show this line (only works properly + when 'wrap' is off). + zero: Do not highlight the cursor line. + Default is zero, except for |popup_menu()|. filter A callback that can filter typed characters, see |popup-filter|. callback A callback that is called when the popup closes, e.g. @@ -695,8 +702,8 @@ If the text does not fit in the popup a scrollbar is displayed on the right of the window. This can be disabled by setting the "scrollbar" option to zero. When the scrollbar is displayed mouse scroll events, while the mouse pointer is on the popup, will cause the text to scroll up or down as you would expect. -A click in the upper halve of the scrollbar will scroll the text one line -down. A click in the lower halve wil scroll the text one line up. However, +A click in the upper half of the scrollbar will scroll the text one line +down. A click in the lower half wil scroll the text one line up. However, this is limited so that the popup does not get smaller. @@ -709,7 +716,7 @@ list has four numbers: leftmost, negative for counting from the right, -1 for rightmost endcol last column, like "col" - line start line, positive for conting from the top, 1 for top, + line start line, positive for counting from the top, 1 for top, negative for counting from the bottom, -1 for bottom endline end line, like "line" diff --git a/src/popupwin.c b/src/popupwin.c index f977517262..4fe64fd237 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -441,6 +441,34 @@ check_highlight(dict_T *dict, char *name, char_u **pval) } } +/* + * Highlight the line with the cursor. + * Also scrolls the text to put the cursor line in view. + */ + static void +popup_highlight_curline(win_T *wp) +{ + int id; + char buf[100]; + + match_delete(wp, 1, FALSE); + + if ((wp->w_popup_flags & POPF_CURSORLINE) != 0) + { + // Scroll to show the line with the cursor. This assumes lines don't + // wrap. + while (wp->w_topline + wp->w_height - 1 < wp->w_cursor.lnum) + wp->w_topline++; + while (wp->w_cursor.lnum < wp->w_topline) + wp->w_topline--; + + id = syn_name2id((char_u *)"PopupSelected"); + vim_snprintf(buf, sizeof(buf), "\\%%%dl.*", (int)wp->w_cursor.lnum); + match_add(wp, (char_u *)(id == 0 ? "PmenuSel" : "PopupSelected"), + (char_u *)buf, 10, 1, NULL, NULL); + } +} + /* * Shared between popup_create() and f_popup_setoptions(). */ @@ -635,6 +663,20 @@ apply_general_options(win_T *wp, dict_T *dict) handle_moved_argument(wp, di, TRUE); } + di = dict_find(dict, (char_u *)"cursorline", -1); + if (di != NULL) + { + if (di->di_tv.v_type == VAR_NUMBER) + { + if (di->di_tv.vval.v_number != 0) + wp->w_popup_flags |= POPF_CURSORLINE; + else + wp->w_popup_flags &= ~POPF_CURSORLINE; + } + else + semsg(_(e_invargval), "cursorline"); + } + di = dict_find(dict, (char_u *)"filter", -1); if (di != NULL) { @@ -662,6 +704,7 @@ apply_general_options(win_T *wp, dict_T *dict) /* * Go through the options in "dict" and apply them to popup window "wp". + * Only used when creating a new popup window. */ static void apply_options(win_T *wp, dict_T *dict) @@ -679,6 +722,7 @@ apply_options(win_T *wp, dict_T *dict) } popup_mask_refresh = TRUE; + popup_highlight_curline(wp); } /* @@ -1313,6 +1357,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) set_callback(&wp->w_filter_cb, &callback); wp->w_p_wrap = 0; + wp->w_popup_flags |= POPF_CURSORLINE; } for (i = 0; i < 4; ++i) @@ -1502,26 +1547,6 @@ filter_handle_drag(win_T *wp, int c, typval_T *rettv) rettv->vval.v_number = 0; } - static void -popup_highlight_curline(win_T *wp) -{ - int id; - char buf[100]; - - match_delete(wp, 1, FALSE); - - // Scroll to show the line with the cursor. This assumes lines don't wrap. - while (wp->w_topline + wp->w_height - 1 < wp->w_cursor.lnum) - wp->w_topline++; - while (wp->w_cursor.lnum < wp->w_topline) - wp->w_topline--; - - id = syn_name2id((char_u *)"PopupSelected"); - vim_snprintf(buf, sizeof(buf), "\\%%%dl.*", (int)wp->w_cursor.lnum); - match_add(wp, (char_u *)(id == 0 ? "PmenuSel" : "PopupSelected"), - (char_u *)buf, 10, 1, NULL, NULL); -} - /* * popup_filter_menu({text}, {options}) */ @@ -1630,10 +1655,7 @@ f_popup_dialog(typval_T *argvars, typval_T *rettv) void f_popup_menu(typval_T *argvars, typval_T *rettv) { - win_T *wp = popup_create(argvars, rettv, TYPE_MENU); - - if (wp != NULL) - popup_highlight_curline(wp); + popup_create(argvars, rettv, TYPE_MENU); } /* @@ -1858,6 +1880,7 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED) if (old_firstline != wp->w_firstline) redraw_win_later(wp, NOT_VALID); popup_mask_refresh = TRUE; + popup_highlight_curline(wp); popup_adjust_position(wp); } @@ -2047,6 +2070,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv) dict_add_string(dict, "title", wp->w_popup_title); dict_add_number(dict, "wrap", wp->w_p_wrap); dict_add_number(dict, "drag", wp->w_popup_drag); + dict_add_number(dict, "cursorline", (wp->w_popup_flags & POPF_CURSORLINE) != 0); dict_add_string(dict, "highlight", wp->w_p_wcr); if (wp->w_scrollbar_highlight != NULL) dict_add_string(dict, "scrollbarhighlight", @@ -2181,6 +2205,7 @@ invoke_popup_filter(win_T *wp, int c) int dummy; typval_T argv[3]; char_u buf[NUMBUFLEN]; + linenr_T old_lnum = wp->w_cursor.lnum; // Emergency exit: CTRL-C closes the popup. if (c == Ctrl_C) @@ -2205,6 +2230,9 @@ invoke_popup_filter(win_T *wp, int c) // NOTE: The callback might close the popup, thus make "wp" invalid. call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL); + if (old_lnum != wp->w_cursor.lnum) + popup_highlight_curline(wp); + res = tv_get_number(&rettv); vim_free(argv[1].vval.v_string); clear_tv(&rettv); diff --git a/src/testdir/dumps/Test_popupwin_cursorline_1.dump b/src/testdir/dumps/Test_popupwin_cursorline_1.dump new file mode 100644 index 0000000000..d73b149c1b --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_cursorline_1.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @34|1+0#0000001#ffd7ff255@2| +0#4040ff13#ffffff0@35 +|~| @34|2+0#0000001#ffd7ff255@2| +0#4040ff13#ffffff0@35 +|~| @34|3+0#0000001#ffd7ff255@2| +0#4040ff13#ffffff0@35 +|~| @73 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_cursorline_2.dump b/src/testdir/dumps/Test_popupwin_cursorline_2.dump new file mode 100644 index 0000000000..6c00f96563 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_cursorline_2.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @34|1+0#0000001#e0e0e08@2| +0#4040ff13#ffffff0@35 +|~| @34|2+0#0000001#ffd7ff255@2| +0#4040ff13#ffffff0@35 +|~| @34|3+0#0000001#ffd7ff255@2| +0#4040ff13#ffffff0@35 +|~| @73 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_cursorline_3.dump b/src/testdir/dumps/Test_popupwin_cursorline_3.dump new file mode 100644 index 0000000000..478c59d90b --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_cursorline_3.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |1@2| | +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |2@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_cursorline_4.dump b/src/testdir/dumps/Test_popupwin_cursorline_4.dump new file mode 100644 index 0000000000..85eef41272 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_cursorline_4.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |2@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |3@2| | +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_cursorline_5.dump b/src/testdir/dumps/Test_popupwin_cursorline_5.dump new file mode 100644 index 0000000000..57d24aad88 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_cursorline_5.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |1+0&#e0e0e08@2| +0&#ffd7ff255| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |2@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_cursorline_6.dump b/src/testdir/dumps/Test_popupwin_cursorline_6.dump new file mode 100644 index 0000000000..314c2d1b0c --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_cursorline_6.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |2@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |3+0&#e0e0e08@2| +0&#ffd7ff255| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_menu_filter_1.dump b/src/testdir/dumps/Test_popupwin_menu_filter_1.dump new file mode 100644 index 0000000000..991ddec0e6 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_menu_filter_1.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |1@2| | +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |2+0&#e0e0e08@2| +0&#ffd7ff255| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |3@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_menu_filter_2.dump b/src/testdir/dumps/Test_popupwin_menu_filter_2.dump new file mode 100644 index 0000000000..3862b92d19 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_menu_filter_2.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |1+0&#e0e0e08@2| +0&#ffd7ff255| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |2@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |3@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_menu_filter_3.dump b/src/testdir/dumps/Test_popupwin_menu_filter_3.dump new file mode 100644 index 0000000000..af0735cd62 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_menu_filter_3.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |7@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |8@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |9+0&#e0e0e08@2| +0&#ffd7ff255| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_menu_filter_4.dump b/src/testdir/dumps/Test_popupwin_menu_filter_4.dump new file mode 100644 index 0000000000..3862b92d19 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_menu_filter_4.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |1+0&#e0e0e08@2| +0&#ffd7ff255| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |2@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|║+0#0000001#ffd7ff255| |3@2| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@32 +|~| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#4040ff13#ffffff0@32 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 740ac61396..0ec901cb59 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1921,4 +1921,176 @@ func Test_popup_menu_with_scrollbar() call delete('XtestPopupMenuScroll') endfunc +func Test_popup_menu_filter() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + let lines =<< trim END + function! MyFilter(winid, key) abort + if a:key == "0" + call win_execute(a:winid, "call setpos('.', [0, 1, 1, 0])") + return 1 + endif + if a:key == "G" + call win_execute(a:winid, "call setpos('.', [0, line('$'), 1, 0])") + return 1 + endif + if a:key == "j" + call win_execute(a:winid, "call setpos('.', [0, line('.') + 1, 1, 0])") + return 1 + endif + if a:key == "k" + call win_execute(a:winid, "call setpos('.', [0, line('.') - 1, 1, 0])") + return 1 + endif + if a:key == 'x' + call popup_close(a:winid) + return 1 + endif + return 0 + endfunction + call popup_menu(['111', '222', '333', '444', '555', '666', '777', '888', '999'], #{ + \ maxheight : 3, + \ filter : 'MyFilter' + \ }) + END + call writefile(lines, 'XtestPopupMenuFilter') + let buf = RunVimInTerminal('-S XtestPopupMenuFilter', #{rows: 10}) + + call term_sendkeys(buf, "j") + call VerifyScreenDump(buf, 'Test_popupwin_menu_filter_1', {}) + + call term_sendkeys(buf, "k") + call VerifyScreenDump(buf, 'Test_popupwin_menu_filter_2', {}) + + call term_sendkeys(buf, "G") + call VerifyScreenDump(buf, 'Test_popupwin_menu_filter_3', {}) + + call term_sendkeys(buf, "0") + call VerifyScreenDump(buf, 'Test_popupwin_menu_filter_4', {}) + + call term_sendkeys(buf, "x") + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupMenuFilter') +endfunc + +func Test_popup_cursorline() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + let winid = popup_create('some text', {}) + call assert_equal(0, popup_getoptions(winid).cursorline) + call popup_close(winid) + + let winid = popup_create('some text', #{ cursorline: 1, }) + call assert_equal(1, popup_getoptions(winid).cursorline) + call popup_close(winid) + + let winid = popup_create('some text', #{ cursorline: 0, }) + call assert_equal(0, popup_getoptions(winid).cursorline) + call popup_close(winid) + + let winid = popup_menu('some text', {}) + call assert_equal(1, popup_getoptions(winid).cursorline) + call popup_close(winid) + + let winid = popup_menu('some text', #{ cursorline: 1, }) + call assert_equal(1, popup_getoptions(winid).cursorline) + call popup_close(winid) + + let winid = popup_menu('some text', #{ cursorline: 0, }) + call assert_equal(0, popup_getoptions(winid).cursorline) + call popup_close(winid) + + " --------- + " Pattern 1 + " --------- + let lines =<< trim END + call popup_create(['111', '222', '333'], #{ cursorline : 0 }) + END + call writefile(lines, 'XtestPopupCursorLine') + let buf = RunVimInTerminal('-S XtestPopupCursorLine', #{rows: 10}) + call VerifyScreenDump(buf, 'Test_popupwin_cursorline_1', {}) + call term_sendkeys(buf, ":call popup_clear()\") + call StopVimInTerminal(buf) + + " --------- + " Pattern 2 + " --------- + let lines =<< trim END + call popup_create(['111', '222', '333'], #{ cursorline : 1 }) + END + call writefile(lines, 'XtestPopupCursorLine') + let buf = RunVimInTerminal('-S XtestPopupCursorLine', #{rows: 10}) + call VerifyScreenDump(buf, 'Test_popupwin_cursorline_2', {}) + call term_sendkeys(buf, ":call popup_clear()\") + call StopVimInTerminal(buf) + + " --------- + " Pattern 3 + " --------- + let lines =<< trim END + function! MyFilter(winid, key) abort + if a:key == "j" + call win_execute(a:winid, "call setpos('.', [0, line('.') + 1, 1, 0]) | redraw") + return 1 + endif + if a:key == 'x' + call popup_close(a:winid) + return 1 + endif + return 0 + endfunction + call popup_menu(['111', '222', '333'], #{ + \ cursorline : 0, + \ maxheight : 2, + \ filter : 'MyFilter', + \ }) + END + call writefile(lines, 'XtestPopupCursorLine') + let buf = RunVimInTerminal('-S XtestPopupCursorLine', #{rows: 10}) + call VerifyScreenDump(buf, 'Test_popupwin_cursorline_3', {}) + call term_sendkeys(buf, "j") + call term_sendkeys(buf, "j") + call VerifyScreenDump(buf, 'Test_popupwin_cursorline_4', {}) + call term_sendkeys(buf, "x") + call StopVimInTerminal(buf) + + " --------- + " Pattern 4 + " --------- + let lines =<< trim END + function! MyFilter(winid, key) abort + if a:key == "j" + call win_execute(a:winid, "call setpos('.', [0, line('.') + 1, 1, 0]) | redraw") + return 1 + endif + if a:key == 'x' + call popup_close(a:winid) + return 1 + endif + return 0 + endfunction + call popup_menu(['111', '222', '333'], #{ + \ cursorline : 1, + \ maxheight : 2, + \ filter : 'MyFilter', + \ }) + END + call writefile(lines, 'XtestPopupCursorLine') + let buf = RunVimInTerminal('-S XtestPopupCursorLine', #{rows: 10}) + call VerifyScreenDump(buf, 'Test_popupwin_cursorline_5', {}) + call term_sendkeys(buf, "j") + call term_sendkeys(buf, "j") + call VerifyScreenDump(buf, 'Test_popupwin_cursorline_6', {}) + call term_sendkeys(buf, "x") + call StopVimInTerminal(buf) + + call delete('XtestPopupCursorLine') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index a6d1492e26..492e1ae29f 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1713, /**/ 1712, /**/ diff --git a/src/vim.h b/src/vim.h index 410d9d7e3c..452a9b9319 100644 --- a/src/vim.h +++ b/src/vim.h @@ -617,6 +617,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring); #define POPF_IS_POPUP 1 // this is a popup window #define POPF_HIDDEN 2 // popup is not displayed #define POPF_HANDLED 4 // popup was just redrawn or filtered +#define POPF_CURSORLINE 8 // popup is highlighting at the cursorline #ifdef FEAT_TEXT_PROP # define WIN_IS_POPUP(wp) ((wp)->w_popup_flags != 0) #else From 7964873afe59d0896a921b7c585167674bb784d5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 18 Jul 2019 21:43:07 +0200 Subject: [PATCH 9/9] patch 8.1.1714: cannot preview a file in a popup window Problem: Cannot preview a file in a popup window. Solution: Add the 'previewpopup' option. --- runtime/doc/options.txt | 11 +- runtime/doc/windows.txt | 10 +- src/ex_cmds.c | 32 +- src/ex_docmd.c | 7 +- src/option.c | 18 ++ src/option.h | 3 + src/popupwin.c | 273 ++++++++++++++---- src/proto/popupwin.pro | 6 + .../dumps/Test_popupwin_previewpopup_1.dump | 14 + .../dumps/Test_popupwin_previewpopup_2.dump | 14 + src/testdir/gen_opt_test.vim | 1 + src/version.c | 2 + 12 files changed, 322 insertions(+), 69 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_2.dump diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index ad50bfce3c..7549ed8b10 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5627,7 +5627,16 @@ A jump table for the options with a short description can be found at |Q_op|. {not available when compiled without the |+windows| or |+quickfix| features} Default height for a preview window. Used for |:ptag| and associated - commands. Used for |CTRL-W_}| when no count is given. + commands. Used for |CTRL-W_}| when no count is given. Not used when + 'previewpopup' is set. + + *'previewpopup'* *'pvp'* +'previewpopup' 'pvp' string (default empty) + global + {not available when compiled without the |+windows|, + |+textprop| or |+quickfix| feature} + When not empty a popup window is used for commands that would open a + preview window. See |preview-popup|. *'previewwindow'* *'nopreviewwindow'* *'pvw'* *'nopvw'* *E590* diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index 2c0cdc3b0e..1c6702fc2a 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -864,7 +864,15 @@ height of the preview window when it's opened. The 'previewwindow' option is set in the preview window to be able to recognize it. The 'winfixheight' option is set to have it keep the same height when opening/closing other windows. - + *preview-popup* +Alternatively, a popup window can be used by setting the 'previewpopup' +option. When set, it overrules the 'previewwindow' and 'previewheight' +settings. The option is a comma separated list of values: + height maximum height of the popup + width maximu width of the popup +Example: > + :set previewpopup=height:10,width:60 +< *:pta* *:ptag* :pta[g][!] [tagname] Does ":tag[!] [tagname]" and shows the found tag in a diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 4126fe09f9..e262da1d59 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -6270,9 +6270,20 @@ prepare_tagpreview( */ if (!curwin->w_p_pvw) { - FOR_ALL_WINDOWS(wp) - if (wp->w_p_pvw) - break; +# ifdef FEAT_TEXT_PROP + if (*p_pvp != NUL) + { + wp = popup_find_preview_window(); + if (wp != NULL) + popup_set_wantpos(wp); + } + else +# endif + { + FOR_ALL_WINDOWS(wp) + if (wp->w_p_pvw) + break; + } if (wp != NULL) win_enter(wp, undo_sync); else @@ -6280,18 +6291,21 @@ prepare_tagpreview( /* * There is no preview window open yet. Create one. */ - if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) - == FAIL) +# ifdef FEAT_TEXT_PROP + if (*p_pvp != NUL) + return popup_create_preview_window(); +# endif + if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) == FAIL) return FALSE; curwin->w_p_pvw = TRUE; curwin->w_p_wfh = TRUE; - RESET_BINDING(curwin); /* don't take over 'scrollbind' - and 'cursorbind' */ + RESET_BINDING(curwin); // don't take over 'scrollbind' + // and 'cursorbind' # ifdef FEAT_DIFF - curwin->w_p_diff = FALSE; /* no 'diff' */ + curwin->w_p_diff = FALSE; // no 'diff' # endif # ifdef FEAT_FOLDING - curwin->w_p_fdc = 0; /* no 'foldcolumn' */ + curwin->w_p_fdc = 0; // no 'foldcolumn' # endif return TRUE; } diff --git a/src/ex_docmd.c b/src/ex_docmd.c index a76261b40d..462851d6a1 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -5893,12 +5893,17 @@ ex_pclose(exarg_T *eap) { win_T *win; + // First close any normal window. FOR_ALL_WINDOWS(win) if (win->w_p_pvw) { ex_win_close(eap->forceit, win, NULL); - break; + return; } +# ifdef FEAT_TEXT_PROP + // Also when 'previewpopup' is empty, it might have been cleared. + popup_close_preview(); +# endif } #endif diff --git a/src/option.c b/src/option.c index 4856a598d6..c17e9128a2 100644 --- a/src/option.c +++ b/src/option.c @@ -2079,6 +2079,15 @@ static struct vimoption options[] = (char_u *)NULL, PV_NONE, #endif {(char_u *)12L, (char_u *)0L} SCTX_INIT}, + {"previewpopup", "pvp", P_STRING|P_VI_DEF|P_COMMA|P_NODUP, +#ifdef FEAT_TEXT_PROP + (char_u *)&p_pvp, PV_NONE, + {(char_u *)"", (char_u *)0L} +#else + (char_u *)NULL, PV_NONE, + {(char_u *)NULL, (char_u *)0L} +#endif + SCTX_INIT}, {"previewwindow", "pvw", P_BOOL|P_VI_DEF|P_RSTAT|P_NOGLOB, #if defined(FEAT_QUICKFIX) (char_u *)VAR_WIN, PV_PVW, @@ -7831,6 +7840,15 @@ did_set_string_option( } #endif +#ifdef FEAT_TEXT_PROP + // 'previewpopup' + else if (varp == &p_pvp) + { + if (parse_previewpopup(NULL) == FAIL) + errmsg = e_invarg; + } +#endif + /* Options that are a list of flags. */ else { diff --git a/src/option.h b/src/option.h index 7e657ddc3b..605d588eac 100644 --- a/src/option.h +++ b/src/option.h @@ -499,6 +499,9 @@ EXTERN char_u *p_fp; /* 'formatprg' */ EXTERN int p_fs; /* 'fsync' */ #endif EXTERN int p_gd; /* 'gdefault' */ +#ifdef FEAT_TEXT_PROP +EXTERN char_u *p_pvp; // 'previewpopup' +#endif #ifdef FEAT_PRINTER EXTERN char_u *p_pdev; /* 'printdevice' */ # ifdef FEAT_POSTSCRIPT diff --git a/src/popupwin.c b/src/popupwin.c index 4fe64fd237..47a5c789dc 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -13,7 +13,7 @@ #include "vim.h" -#ifdef FEAT_TEXT_PROP +#if defined(FEAT_TEXT_PROP) || defined(PROTO) typedef struct { char *pp_name; @@ -441,6 +441,18 @@ check_highlight(dict_T *dict, char *name, char_u **pval) } } +/* + * Scroll to show the line with the cursor. This assumes lines don't wrap. + */ + static void +popup_show_curline(win_T *wp) +{ + if (wp->w_cursor.lnum < wp->w_topline) + wp->w_topline = wp->w_cursor.lnum; + else if (wp->w_cursor.lnum >= wp->w_botline) + wp->w_topline = wp->w_cursor.lnum - wp->w_height + 1; +} + /* * Highlight the line with the cursor. * Also scrolls the text to put the cursor line in view. @@ -455,12 +467,7 @@ popup_highlight_curline(win_T *wp) if ((wp->w_popup_flags & POPF_CURSORLINE) != 0) { - // Scroll to show the line with the cursor. This assumes lines don't - // wrap. - while (wp->w_topline + wp->w_height - 1 < wp->w_cursor.lnum) - wp->w_topline++; - while (wp->w_cursor.lnum < wp->w_topline) - wp->w_topline--; + popup_show_curline(wp); id = syn_name2id((char_u *)"PopupSelected"); vim_snprintf(buf, sizeof(buf), "\\%%%dl.*", (int)wp->w_cursor.lnum); @@ -923,7 +930,8 @@ popup_adjust_position(win_T *wp) } // start at the desired first line - wp->w_topline = wp->w_firstline; + 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; @@ -1078,7 +1086,8 @@ typedef enum TYPE_BEVAL, TYPE_NOTIFICATION, TYPE_DIALOG, - TYPE_MENU + TYPE_MENU, + TYPE_PREVIEW } create_type_T; /* @@ -1123,68 +1132,144 @@ popup_set_buffer_text(buf_T *buf, typval_T text) curbuf = curwin->w_buffer; } +/* + * Parse the 'previewpopup' option and apply the values to window "wp" if it + * not NULL. + * Return FAIL if the parsing fails. + */ + int +parse_previewpopup(win_T *wp) +{ + char_u *p; + + for (p = p_pvp; *p != NUL; p += (*p == ',' ? 1 : 0)) + { + char_u *e, *dig; + char_u *s = p; + int x; + + e = vim_strchr(p, ':'); + if (e == NULL || e[1] == NUL) + return FAIL; + + p = vim_strchr(e, ','); + if (p == NULL) + p = e + STRLEN(e); + dig = e + 1; + x = getdigits(&dig); + if (dig != p) + return FAIL; + + if (STRNCMP(s, "height:", 7) == 0) + { + if (wp != NULL) + { + wp->w_minheight = x; + wp->w_maxheight = x; + } + } + else if (STRNCMP(s, "width:", 6) == 0) + { + if (wp != NULL) + { + wp->w_minwidth = x; + wp->w_maxwidth = x; + } + } + else + return FAIL; + } + return OK; +} + +/* + * Set w_wantline and w_wantcol for the cursor position in the current window. + */ + void +popup_set_wantpos(win_T *wp) +{ + setcursor_mayforce(TRUE); + wp->w_wantline = curwin->w_winrow + curwin->w_wrow; + if (wp->w_wantline == 0) // cursor in first line + { + wp->w_wantline = 2; + wp->w_popup_pos = POPPOS_TOPLEFT; + } + wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1; + popup_adjust_position(wp); +} + /* * popup_create({text}, {options}) * popup_atcursor({text}, {options}) + * etc. + * When creating a preview window popup "argvars" and "rettv" are NULL. */ static win_T * popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) { win_T *wp; tabpage_T *tp = NULL; - int tabnr; + int tabnr = 0; int new_buffer; buf_T *buf = NULL; - dict_T *d; + dict_T *d = NULL; int nr; int i; - // Check arguments look OK. - if (argvars[0].v_type == VAR_NUMBER) + if (argvars != NULL) { - buf = buflist_findnr( argvars[0].vval.v_number); - if (buf == NULL) + // Check arguments look OK. + if (argvars[0].v_type == VAR_NUMBER) { - semsg(_(e_nobufnr), argvars[0].vval.v_number); + buf = buflist_findnr( argvars[0].vval.v_number); + if (buf == NULL) + { + semsg(_(e_nobufnr), argvars[0].vval.v_number); + return NULL; + } + } + else if (!(argvars[0].v_type == VAR_STRING + && argvars[0].vval.v_string != NULL) + && !(argvars[0].v_type == VAR_LIST + && argvars[0].vval.v_list != NULL)) + { + emsg(_(e_listreq)); return NULL; } - } - else if (!(argvars[0].v_type == VAR_STRING - && argvars[0].vval.v_string != NULL) - && !(argvars[0].v_type == VAR_LIST - && argvars[0].vval.v_list != NULL)) - { - emsg(_(e_listreq)); - return NULL; - } - if (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL) - { - emsg(_(e_dictreq)); - return NULL; - } - d = argvars[1].vval.v_dict; - - if (dict_find(d, (char_u *)"tabpage", -1) != NULL) - tabnr = (int)dict_get_number(d, (char_u *)"tabpage"); - else if (type == TYPE_NOTIFICATION) - tabnr = -1; // notifications are global by default - else - tabnr = 0; - if (tabnr > 0) - { - tp = find_tabpage(tabnr); - if (tp == NULL) + if (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL) { - semsg(_("E997: Tabpage not found: %d"), tabnr); + emsg(_(e_dictreq)); return NULL; } + d = argvars[1].vval.v_dict; + } + + if (d != NULL) + { + if (dict_find(d, (char_u *)"tabpage", -1) != NULL) + tabnr = (int)dict_get_number(d, (char_u *)"tabpage"); + else if (type == TYPE_NOTIFICATION) + tabnr = -1; // notifications are global by default + else + tabnr = 0; + if (tabnr > 0) + { + tp = find_tabpage(tabnr); + if (tp == NULL) + { + semsg(_("E997: Tabpage not found: %d"), tabnr); + return NULL; + } + } } // Create the window and buffer. wp = win_alloc_popup_win(); if (wp == NULL) return NULL; - rettv->vval.v_number = wp->w_id; + if (rettv != NULL) + rettv->vval.v_number = wp->w_id; wp->w_popup_pos = POPPOS_TOPLEFT; wp->w_popup_flags = POPF_IS_POPUP; @@ -1211,7 +1296,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) set_string_option_direct_in_buf(buf, (char_u *)"buftype", -1, (char_u *)"popup", OPT_FREE|OPT_LOCAL, 0); set_string_option_direct_in_buf(buf, (char_u *)"bufhidden", -1, - (char_u *)"hide", OPT_FREE|OPT_LOCAL, 0); + (char_u *)"wipe", OPT_FREE|OPT_LOCAL, 0); buf->b_p_ul = -1; // no undo buf->b_p_swf = FALSE; // no swap file buf->b_p_bl = FALSE; // unlisted buffer @@ -1250,20 +1335,16 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) } } - if (new_buffer) + if (new_buffer && argvars != NULL) popup_set_buffer_text(buf, argvars[0]); - if (type == TYPE_ATCURSOR) + if (type == TYPE_ATCURSOR || type == TYPE_PREVIEW) { wp->w_popup_pos = POPPOS_BOTLEFT; - setcursor_mayforce(TRUE); - wp->w_wantline = curwin->w_winrow + curwin->w_wrow; - if (wp->w_wantline == 0) // cursor in first line - { - wp->w_wantline = 2; - wp->w_popup_pos = POPPOS_TOPLEFT; - } - wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1; + popup_set_wantpos(wp); + } + if (type == TYPE_ATCURSOR) + { set_moved_values(wp); set_moved_columns(wp, FIND_STRING); } @@ -1360,6 +1441,15 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) wp->w_popup_flags |= POPF_CURSORLINE; } + if (type == TYPE_PREVIEW) + { + wp->w_popup_drag = 1; + wp->w_popup_close = POPCLOSE_BUTTON; + for (i = 0; i < 4; ++i) + wp->w_popup_border[i] = 1; + parse_previewpopup(wp); + } + for (i = 0; i < 4; ++i) VIM_CLEAR(wp->w_border_highlight[i]); for (i = 0; i < 8; ++i) @@ -1367,8 +1457,9 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) wp->w_want_scrollbar = 1; wp->w_popup_fixed = 0; - // Deal with options. - apply_options(wp, argvars[1].vval.v_dict); + if (d != NULL) + // Deal with options. + apply_options(wp, d); #ifdef FEAT_TIMERS if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL) @@ -2839,4 +2930,72 @@ set_ref_in_popups(int copyID) } return abort; } + +/* + * Find an existing popup used as the preview window, in the current tab page. + * Return NULL if not found. + */ + win_T * +popup_find_preview_window(void) +{ + win_T *wp; + + // Preview window popup is always local to tab page. + for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next) + if (wp->w_p_pvw) + return wp; + return wp; +} + + int +popup_is_popup(win_T *wp) +{ + return wp->w_popup_flags != 0; +} + +/* + * Create a popup to be used as the preview window. + * NOTE: this makes the popup the current window, so that the file can be + * edited. However, it must not remain to be the current window, the caller + * must make sure of that. + */ + int +popup_create_preview_window(void) +{ + win_T *wp = popup_create(NULL, NULL, TYPE_PREVIEW); + + if (wp == NULL) + return FAIL; + wp->w_p_pvw = TRUE; + + // Set the width to a reasonable value, so that w_topline can be computed. + if (wp->w_minwidth > 0) + wp->w_width = wp->w_minwidth; + else if (wp->w_maxwidth > 0) + wp->w_width = wp->w_maxwidth; + else + wp->w_width = curwin->w_width; + + // Will switch to another buffer soon, dummy one can be wiped. + wp->w_buffer->b_locked = FALSE; + + win_enter(wp, FALSE); + return OK; +} + + void +popup_close_preview() +{ + win_T *wp = popup_find_preview_window(); + + if (wp != NULL) + { + typval_T res; + + res.v_type = VAR_NUMBER; + res.vval.v_number = -1; + popup_close_and_callback(wp, &res); + } +} + #endif // FEAT_TEXT_PROP diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index d1267e0224..605575b77b 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -8,6 +8,8 @@ void popup_handle_scrollbar_click(win_T *wp, int row, int col); int popup_height(win_T *wp); int popup_width(win_T *wp); void popup_adjust_position(win_T *wp); +int parse_previewpopup(win_T *wp); +void popup_set_wantpos(win_T *wp); void f_popup_clear(typval_T *argvars, typval_T *rettv); void f_popup_create(typval_T *argvars, typval_T *rettv); void f_popup_atcursor(typval_T *argvars, typval_T *rettv); @@ -39,4 +41,8 @@ void popup_check_cursor_pos(void); void may_update_popup_mask(int type); void update_popups(void (*win_update)(win_T *wp)); int set_ref_in_popups(int copyID); +win_T *popup_find_preview_window(void); +int popup_is_popup(win_T *wp); +int popup_create_preview_window(void); +void popup_close_preview(void); /* vim: set ft=c : */ diff --git a/src/testdir/dumps/Test_popupwin_previewpopup_1.dump b/src/testdir/dumps/Test_popupwin_previewpopup_1.dump new file mode 100644 index 0000000000..d23dd677f8 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_previewpopup_1.dump @@ -0,0 +1,14 @@ +|o+0&#ffffff0|n|e| @71 +|t|w|o| @1|╔+0#0000001#ffd7ff255|═@40|X| +0#0000000#ffffff0@26 +|t|h|r|e@1|║+0#0000001#ffd7ff255|2|0| @37| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26 +|f|o|u|r| |║+0#0000001#ffd7ff255|t|h|e|w|o|r|d| |i|s| |h|e|r|e| @24| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26 +|f|i|v|e| |║+0#0000001#ffd7ff255|2@1| @37| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26 +|s|i|x| @1|║+0#0000001#ffd7ff255|2|3| @37| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26 +|s|e|v|e|n|╚+0#0000001#ffd7ff255|═@40|╝| +0#0000000#ffffff0@26 +|f|i|n|d| >t|h|e|w|o|r|d| |s|o|m|e|w|h|e|r|e| @52 +|n|i|n|e| @70 +|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |w|o|r|d| @54 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|:+0#0000000&| @55|8|,|6| @10|A|l@1| diff --git a/src/testdir/dumps/Test_popupwin_previewpopup_2.dump b/src/testdir/dumps/Test_popupwin_previewpopup_2.dump new file mode 100644 index 0000000000..4d0e49ca0d --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_previewpopup_2.dump @@ -0,0 +1,14 @@ +|o+0&#ffffff0|n|e| @71 +|t|w|o| @71 +|t|h|r|e@1| @69 +|f|o|u|r| @3|╔+0#0000001#ffd7ff255|═@40|X| +0#0000000#ffffff0@23 +|f|i|v|e| @3|║+0#0000001#ffd7ff255|2|7| @37| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@23 +|s|i|x| @4|║+0#0000001#ffd7ff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@23 +|s|e|v|e|n| @2|║+0#0000001#ffd7ff255|2|9| @37| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@23 +|f|i|n|d| |t|h|e|║+0#0000001#ffd7ff255|3|0| @37| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@23 +|n|i|n|e| @3|╚+0#0000001#ffd7ff255|═@40|╝| +0#0000000#ffffff0@23 +|t|h|i|s| |i|s| >a|n|o|t|h|e|r| |w|o|r|d| @54 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|/+0#0000000&|a|n|o|t|h|e|r| @48|1|0|,|9| @9|A|l@1| diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim index 22d7c8cdba..e410feb42d 100644 --- a/src/testdir/gen_opt_test.vim +++ b/src/testdir/gen_opt_test.vim @@ -116,6 +116,7 @@ let test_values = { \ 'mousemodel': [['', 'popup'], ['xxx']], \ 'mouseshape': [['', 'n:arrow'], ['xxx']], \ 'nrformats': [['', 'alpha', 'alpha,hex,bin'], ['xxx']], + \ 'previewpopup': [['', 'height:13', 'width:10,height:234'], ['height:yes', 'xxx', 'xxx:99']], \ 'printmbfont': [['', 'r:some', 'b:Bold,c:yes'], ['xxx']], \ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'], ['xxx']], \ 'scrollopt': [['', 'ver', 'ver,hor'], ['xxx']], diff --git a/src/version.c b/src/version.c index 492e1ae29f..64a6daa80a 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1714, /**/ 1713, /**/