From 202d982b36d87cf91d992bd7e30d3223bdc72cd9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 11 Jun 2019 21:56:30 +0200 Subject: [PATCH 01/44] patch 8.1.1518: crash when setting 'columns' while a popup is visible Problem: Crash when setting 'columns' while a popup is visible. Solution: Recompute all positions when clearing the screen. (closes #4467) --- src/screen.c | 12 ++++++++++-- src/testdir/dumps/Test_popupwin_04a.dump | 10 ++++++++++ src/testdir/test_popupwin.vim | 6 ++++++ src/version.c | 2 ++ 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_04a.dump diff --git a/src/screen.c b/src/screen.c index 1ffc729df4..644829ead2 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1029,9 +1029,16 @@ may_update_popup_mask(int type) win_T *wp; short *mask; int line, col; + int redraw_all = FALSE; - if (popup_mask_tab != curtab) + // Need to recompute when switching tabs. + // Also recompute when the type is CLEAR or NOT_VALID, something basic + // (such as the screen size) must have changed. + if (popup_mask_tab != curtab || type >= NOT_VALID) + { popup_mask_refresh = TRUE; + redraw_all = TRUE; + } if (!popup_mask_refresh) { // Check if any buffer has changed. @@ -1070,7 +1077,8 @@ may_update_popup_mask(int type) popup_visible = TRUE; // Recompute the position if the text changed. - if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) + if (redraw_all + || wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) popup_adjust_position(wp); // the width and height are for the inside, add the padding and diff --git a/src/testdir/dumps/Test_popupwin_04a.dump b/src/testdir/dumps/Test_popupwin_04a.dump new file mode 100644 index 0000000000..2e6b6acac5 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_04a.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@11 +|~+0#4040ff13&| @10 +|~| @10 +|~| @6|o+0#0000001#ffd7ff255|t|h|e +|~+0#4040ff13#ffffff0| @6|r+0#0000001#ffd7ff255| |t|a +|~+0#4040ff13#ffffff0| @6|b+0#0000001#ffd7ff255| @2 +|~+0#4040ff13#ffffff0| @6|a+0#0000001#ffd7ff255| |c+0#ff404010&|o +|~+0#4040ff13#ffffff0| @6|m+0#ff404010#ffd7ff255@1|e|n +|~+0#4040ff13#ffffff0| @6|t+0#ff404010#ffd7ff255| +0#0000001&|l|i +| +0#0000000#ffffff0@5|0|,|n+0#0000001#ffd7ff255|e| @1 diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 51eed30669..06a33d4bad 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -41,6 +41,12 @@ func Test_simple_popup() call term_sendkeys(buf, ":quit!\") call VerifyScreenDump(buf, 'Test_popupwin_04', {}) + " set 'columns' to a small value, size must be recomputed + call term_sendkeys(buf, ":let cols = &columns\") + call term_sendkeys(buf, ":set columns=12\") + call VerifyScreenDump(buf, 'Test_popupwin_04a', {}) + call term_sendkeys(buf, ":let &columns = cols\") + " resize popup, show empty line at bottom call term_sendkeys(buf, ":call popup_move(popupwin, {'minwidth': 15, 'maxwidth': 25, 'minheight': 3, 'maxheight': 5})\") call term_sendkeys(buf, ":redraw\") diff --git a/src/version.c b/src/version.c index 7a66295880..7432f70e03 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 */ +/**/ + 1518, /**/ 1517, /**/ From 06e2c81f6d213d197aa60019b33a263cd5176d68 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 12 Jun 2019 19:05:48 +0200 Subject: [PATCH 02/44] patch 8.1.1519: 'backupskip' may contain duplicates Problem: 'backupskip' may contain duplicates. Solution: Add the P_NODUP flag. (Tom Ryder) --- src/option.c | 5 +++-- src/testdir/test_options.vim | 9 +++++++++ src/version.c | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/option.c b/src/option.c index 2146be7ef6..2d22c4c973 100644 --- a/src/option.c +++ b/src/option.c @@ -616,7 +616,7 @@ static struct vimoption options[] = (char_u *)"~", #endif (char_u *)0L} SCTX_INIT}, - {"backupskip", "bsk", P_STRING|P_VI_DEF|P_ONECOMMA, + {"backupskip", "bsk", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP, #ifdef FEAT_WILDIGN (char_u *)&p_bsk, PV_NONE, {(char_u *)"", (char_u *)0L} @@ -4807,7 +4807,8 @@ do_set( * hex numbers. */ vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE); - if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i]))) + if (i == 0 || (arg[i] != NUL + && !VIM_ISWHITE(arg[i]))) { errmsg = N_("E521: Number required after ="); goto skip; diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index 13de719342..9d3065d159 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -419,6 +419,15 @@ func Test_backupskip() call assert_true(found, var . ' (' . varvalue . ') not in option bsk: ' . &bsk) endif endfor + + " Duplicates should be filtered out (option has P_NODUP) + let backupskip = &backupskip + set backupskip= + set backupskip+=/test/dir + set backupskip+=/other/dir + set backupskip+=/test/dir + call assert_equal('/test/dir,/other/dir', &backupskip) + let &backupskip = backupskip endfunc func Test_copy_winopt() diff --git a/src/version.c b/src/version.c index 7432f70e03..5c41f4fbb0 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 */ +/**/ + 1519, /**/ 1518, /**/ From 451d4b5b7c7262631cd1f5057c75d6f5f5772fb1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 12 Jun 2019 20:22:27 +0200 Subject: [PATCH 03/44] patch 8.1.1520: popup windows are ignored when dealing with mouse position Problem: Popup windows are ignored when dealing with mouse position Solution: Find the mouse position inside a popup window. Allow for modeless selection. --- src/beval.c | 5 +-- src/edit.c | 2 +- src/evalfunc.c | 12 +++++-- src/gui.c | 4 +-- src/normal.c | 2 +- src/popupwin.c | 22 +++++++++++++ src/proto/popupwin.pro | 2 ++ src/proto/ui.pro | 2 +- src/screen.c | 15 ++------- src/structs.h | 7 ++++ src/ui.c | 72 +++++++++++++++++++++++++++++++++++++++--- src/version.c | 2 ++ 12 files changed, 120 insertions(+), 27 deletions(-) diff --git a/src/beval.c b/src/beval.c index d51a3f5d84..e89b1fe50b 100644 --- a/src/beval.c +++ b/src/beval.c @@ -49,7 +49,7 @@ get_beval_info( col = X_2_COL(beval->x); } #endif - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width) { /* Found a window and the cursor is in the text. Now find the line @@ -141,6 +141,7 @@ get_beval_info( /* * Show a balloon with "mesg" or "list". + * Hide the balloon when both are NULL. */ void post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED) @@ -153,7 +154,7 @@ post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED) # endif # ifdef FEAT_BEVAL_GUI if (gui.in_use) - /* GUI can't handle a list */ + // GUI can't handle a list gui_mch_post_balloon(beval, mesg); # endif } diff --git a/src/edit.c b/src/edit.c index ad25252e7e..4de17aa180 100644 --- a/src/edit.c +++ b/src/edit.c @@ -5267,7 +5267,7 @@ ins_mousescroll(int dir) col = mouse_col; /* find the window at the pointer coordinates */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return; curwin = wp; diff --git a/src/evalfunc.c b/src/evalfunc.c index 48b848d012..134280f6de 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5154,12 +5154,18 @@ f_getchar(typval_T *argvars, typval_T *rettv) { /* Find the window at the mouse coordinates and compute the * text position. */ - win = mouse_find_win(&row, &col); + win = mouse_find_win(&row, &col, FIND_POPUP); if (win == NULL) return; (void)mouse_comp_pos(win, &row, &col, &lnum); - for (wp = firstwin; wp != win; wp = wp->w_next) - ++winnr; +# ifdef FEAT_TEXT_PROP + if (bt_popup(win->w_buffer)) + winnr = 0; + else +# endif + for (wp = firstwin; wp != win && wp != NULL; + wp = wp->w_next) + ++winnr; set_vim_var_nr(VV_MOUSE_WIN, winnr); set_vim_var_nr(VV_MOUSE_WINID, win->w_id); set_vim_var_nr(VV_MOUSE_LNUM, lnum); diff --git a/src/gui.c b/src/gui.c index c4df7d9a57..a4673f0266 100644 --- a/src/gui.c +++ b/src/gui.c @@ -4926,7 +4926,7 @@ xy2win(int x, int y) col = X_2_COL(x); if (row < 0 || col < 0) /* before first window */ return NULL; - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FALSE); if (wp == NULL) return NULL; #ifdef FEAT_MOUSESHAPE @@ -5382,7 +5382,7 @@ gui_wingoto_xy(int x, int y) if (row >= 0 && col >= 0) { - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp != NULL && wp != curwin) win_goto(wp); } diff --git a/src/normal.c b/src/normal.c index 834a6436da..834b2319cb 100644 --- a/src/normal.c +++ b/src/normal.c @@ -4521,7 +4521,7 @@ nv_mousescroll(cmdarg_T *cap) col = mouse_col; /* find the window at the pointer coordinates */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return; curwin = wp; diff --git a/src/popupwin.c b/src/popupwin.c index 3781c6fe2d..adfa462299 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -423,6 +423,28 @@ add_popup_dicts(buf_T *buf, list_T *l) } } +/* + * Return the height of popup window "wp", including border and padding. + */ + int +popup_height(win_T *wp) +{ + return wp->w_height + + wp->w_popup_padding[0] + wp->w_popup_border[0] + + wp->w_popup_padding[2] + wp->w_popup_border[2]; +} + +/* + * Return the width of popup window "wp", including border and padding. + */ + int +popup_width(win_T *wp) +{ + return wp->w_width + + wp->w_popup_padding[3] + wp->w_popup_border[3] + + wp->w_popup_padding[1] + wp->w_popup_border[1]; +} + /* * Adjust the position and size of the popup to fit on the screen. */ diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 2a377a748f..a27444679e 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -1,4 +1,6 @@ /* popupwin.c */ +int popup_height(win_T *wp); +int popup_width(win_T *wp); void popup_adjust_position(win_T *wp); void f_popup_clear(typval_T *argvars, typval_T *rettv); void f_popup_create(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/ui.pro b/src/proto/ui.pro index 26cfd4715a..e920029afa 100644 --- a/src/proto/ui.pro +++ b/src/proto/ui.pro @@ -65,7 +65,7 @@ int clip_x11_owner_exists(VimClipboard *cbd); void yank_cut_buffer0(Display *dpy, VimClipboard *cbd); int jump_to_mouse(int flags, int *inclusive, int which_button); int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump); -win_T *mouse_find_win(int *rowp, int *colp); +win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup); int get_fpos_of_mouse(pos_T *mpos); int vcol2col(win_T *wp, linenr_T lnum, int vcol); void ui_focus_change(int in_focus); diff --git a/src/screen.c b/src/screen.c index 644829ead2..7248ca221c 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1072,8 +1072,6 @@ may_update_popup_mask(int type) popup_reset_handled(); while ((wp = find_next_popup(TRUE)) != NULL) { - int height_extra, width_extra; - popup_visible = TRUE; // Recompute the position if the text changed. @@ -1081,18 +1079,11 @@ may_update_popup_mask(int type) || wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) popup_adjust_position(wp); - // the width and height are for the inside, add the padding and - // border - height_extra = wp->w_popup_padding[0] + wp->w_popup_border[0] - + wp->w_popup_padding[2] + wp->w_popup_border[2]; - width_extra = wp->w_popup_padding[3] + wp->w_popup_border[3] - + wp->w_popup_padding[1] + wp->w_popup_border[1]; - for (line = wp->w_winrow; - line < wp->w_winrow + wp->w_height + height_extra + line < wp->w_winrow + popup_height(wp) && line < screen_Rows; ++line) for (col = wp->w_wincol; - col < wp->w_wincol + wp->w_width + width_extra + col < wp->w_wincol + popup_width(wp) && col < screen_Columns; ++col) mask[line * screen_Columns + col] = wp->w_zindex; } @@ -1123,7 +1114,7 @@ may_update_popup_mask(int type) int col_cp = col; // find the window where the row is in - wp = mouse_find_win(&line_cp, &col_cp); + wp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP); if (wp != NULL) { if (line_cp >= wp->w_height) diff --git a/src/structs.h b/src/structs.h index 8ec2cb1857..8e6d93f30e 100644 --- a/src/structs.h +++ b/src/structs.h @@ -3626,3 +3626,10 @@ typedef enum { CDSCOPE_TABPAGE, // :tcd CDSCOPE_WINDOW // :lcd } cdscope_T; + +// argument for mouse_find_win() +typedef enum { + IGNORE_POPUP, // only check non-popup windows + FIND_POPUP, // also find popup windows + FAIL_POPUP // return NULL if mouse on popup window +} mouse_find_T; diff --git a/src/ui.c b/src/ui.c index 4a684d2361..62d8ae7d3e 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1455,12 +1455,19 @@ clip_invert_rectangle( int width, int invert) { +#ifdef FEAT_TEXT_PROP + // this goes on top of all popup windows + screen_zindex = 32000; +#endif #ifdef FEAT_GUI if (gui.in_use) gui_mch_invert_rectangle(row, col, height, width); else #endif screen_draw_rectangle(row, col, height, width, invert); +#ifdef FEAT_TEXT_PROP + screen_zindex = 0; +#endif } /* @@ -2832,6 +2839,9 @@ jump_to_mouse( static int on_sep_line = 0; /* on separator right of window */ #ifdef FEAT_MENU static int in_winbar = FALSE; +#endif +#ifdef FEAT_TEXT_PROP + static int in_popup_win = FALSE; #endif static int prev_row = -1; static int prev_col = -1; @@ -2879,7 +2889,7 @@ retnomove: * as a second click in the WinBar. */ if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED)) { - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return IN_UNKNOWN; winbar_click(wp, col); @@ -2893,9 +2903,14 @@ retnomove: redraw_curbuf_later(INVERTED); /* delete the inversion */ } #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD) - /* Continue a modeless selection in another window. */ + // Continue a modeless selection in another window. if (cmdwin_type != 0 && row < curwin->w_winrow) return IN_OTHER_WIN; +#endif +#ifdef FEAT_TEXT_PROP + // Continue a modeless selection in a popup window. + if (in_popup_win) + return IN_OTHER_WIN; #endif return IN_BUFFER; } @@ -2925,11 +2940,26 @@ retnomove: return IN_UNKNOWN; /* find the window where the row is in */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FIND_POPUP); if (wp == NULL) return IN_UNKNOWN; dragwin = NULL; +#ifdef FEAT_TEXT_PROP + // Click in a popup window may start modeless selection, but not much + // else. + if (bt_popup(wp->w_buffer)) + { + on_sep_line = 0; + in_popup_win = TRUE; +# ifdef FEAT_CLIPBOARD + return IN_OTHER_WIN; +# else + return IN_UNKNOWN; +# endif + } + in_popup_win = FALSE; +#endif #ifdef FEAT_MENU if (row == -1) { @@ -3096,6 +3126,11 @@ retnomove: if (cmdwin_type != 0 && row < curwin->w_winrow) return IN_OTHER_WIN; #endif +#ifdef FEAT_TEXT_PROP + // Continue a modeless selection in a popup window. + if (in_popup_win) + return IN_OTHER_WIN; +#endif row -= W_WINROW(curwin); col -= curwin->w_wincol; @@ -3348,14 +3383,41 @@ mouse_comp_pos( /* * Find the window at screen position "*rowp" and "*colp". The positions are * updated to become relative to the top-left of the window. + * When "popup" is FAIL_POPUP and the position is in a popup window then NULL + * is returned. When "popup" is IGNORE_POPUP then do not even check popup + * windows. * Returns NULL when something is wrong. */ win_T * -mouse_find_win(int *rowp, int *colp) +mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED) { frame_T *fp; win_T *wp; +#ifdef FEAT_TEXT_PROP + win_T *pwp = NULL; + + if (popup != IGNORE_POPUP) + { + popup_reset_handled(); + while ((wp = find_next_popup(TRUE)) != NULL) + { + if (*rowp >= wp->w_winrow && *rowp < wp->w_winrow + popup_height(wp) + && *colp >= wp->w_wincol + && *colp < wp->w_wincol + popup_width(wp)) + pwp = wp; + } + if (pwp != NULL) + { + if (popup == FAIL_POPUP) + return NULL; + *rowp -= pwp->w_winrow; + *colp -= pwp->w_wincol; + return pwp; + } + } +#endif + fp = topframe; *rowp -= firstwin->w_winrow; for (;;) @@ -3412,7 +3474,7 @@ get_fpos_of_mouse(pos_T *mpos) return IN_UNKNOWN; /* find the window where the row is in */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return IN_UNKNOWN; /* diff --git a/src/version.c b/src/version.c index 5c41f4fbb0..8f3d0864fd 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 */ +/**/ + 1520, /**/ 1519, /**/ From 7c7f01e2b260c75d9996ca9ab621119eafe13a63 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 12 Jun 2019 21:06:32 +0200 Subject: [PATCH 04/44] patch 8.1.1521: when a popup window is closed the buffer remains Problem: When a popup window is closed the buffer remains. Solution: Wipe out the buffer. --- src/testdir/test_popupwin.vim | 5 +++++ src/version.c | 2 ++ src/window.c | 12 ++++++------ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 06a33d4bad..d100dc9938 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -272,12 +272,17 @@ endfunc func Test_popup_in_tab() " default popup is local to tab, not visible when in other tab let winid = popup_create("text", {}) + let bufnr = winbufnr(winid) call assert_equal(1, popup_getpos(winid).visible) tabnew call assert_equal(0, popup_getpos(winid).visible) quit call assert_equal(1, popup_getpos(winid).visible) + + call assert_equal(1, bufexists(bufnr)) call popup_clear() + " buffer is gone now + call assert_equal(0, bufexists(bufnr)) " global popup is visible in any tab let winid = popup_create("text", {'tab': -1}) diff --git a/src/version.c b/src/version.c index 8f3d0864fd..28877cb560 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 */ +/**/ + 1521, /**/ 1520, /**/ diff --git a/src/window.c b/src/window.c index d293bad441..c15a86111b 100644 --- a/src/window.c +++ b/src/window.c @@ -2324,12 +2324,13 @@ close_last_window_tabpage( } /* - * Close the buffer of "win" and unload it if "free_buf" is TRUE. + * Close the buffer of "win" and unload it if "action" is DOBUF_UNLOAD. + * "action" can also be zero (do nothing) or DOBUF_WIPE. * "abort_if_last" is passed to close_buffer(): abort closing if all other * windows are closed. */ static void -win_close_buffer(win_T *win, int free_buf, int abort_if_last) +win_close_buffer(win_T *win, int action, int abort_if_last) { #ifdef FEAT_SYN_HL // Free independent synblock before the buffer is freed. @@ -2350,8 +2351,7 @@ win_close_buffer(win_T *win, int free_buf, int abort_if_last) set_bufref(&bufref, curbuf); win->w_closing = TRUE; - close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, - abort_if_last); + close_buffer(win, win->w_buffer, action, abort_if_last); if (win_valid_any_tab(win)) win->w_closing = FALSE; // Make sure curbuf is valid. It can become invalid if 'bufhidden' is @@ -2462,7 +2462,7 @@ win_close(win_T *win, int free_buf) out_flush(); #endif - win_close_buffer(win, free_buf, TRUE); + win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, TRUE); if (only_one_window() && win_valid(win) && win->w_buffer == NULL && (last_window() || curtab != prev_curtab @@ -4894,7 +4894,7 @@ win_unlisted(win_T *wp) void win_free_popup(win_T *win) { - win_close_buffer(win, TRUE, FALSE); + win_close_buffer(win, DOBUF_WIPE, FALSE); # if defined(FEAT_TIMERS) if (win->w_popup_timer != NULL) stop_timer(win->w_popup_timer); From 68d48f40a4da79547b53e3164b658812e154d411 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 12 Jun 2019 22:42:41 +0200 Subject: [PATCH 05/44] patch 8.1.1522: poup_notification() not implemented yet Problem: Popup_notification() not implemented yet. Solution: Implement it. --- runtime/doc/popup.txt | 60 ++++++-- src/evalfunc.c | 1 + src/popupwin.c | 138 ++++++++++++++---- src/proto/popupwin.pro | 1 + src/structs.h | 5 +- .../dumps/Test_popupwin_notify_01.dump | 10 ++ .../dumps/Test_popupwin_notify_02.dump | 10 ++ src/testdir/test_popupwin.vim | 28 +++- src/version.c | 2 + 9 files changed, 212 insertions(+), 43 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_notify_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_notify_02.dump diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 0400880579..b80b875595 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.1. Last change: 2019 Jun 10 +*popup.txt* For Vim version 8.1. Last change: 2019 Jun 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -36,7 +36,7 @@ The default color used is "Pmenu". If you prefer something else use the hi MyPopupColor ctermbg=lightblue guibg=lightblue call setwinvar(winid, '&wincolor', 'MyPopupColor') -'hlsearch' and match highlighting are not displayed in a popup window. +'hlsearch' highlighting is not displayed in a popup window. A popup window has a window-ID like other windows, but behaves differently. The size can be up to the whole Vim window and it overlaps other windows. @@ -63,7 +63,7 @@ property. The width of the window is normally equal to the longest line in the buffer. It can be limited with the "maxwidth" property. You can use spaces to -increase the width or the "minwidth" property. +increase the width or use the "minwidth" property. By default the 'wrap' option is set, so that no text disappears. Otherwise, if there is not enough space then the window is shifted left in order to @@ -79,24 +79,32 @@ window it will be placed below the cursor position. When the screen scrolls up for output of an Ex command, popups move too, so that they will not cover the output. +The current cursor position is displayed even when it is under a popup window. +That way you can still see where it is, even though you cannot see the text +that it is in. IMPLEMENTATION: -- buffers remain after a popup was deleted. - Why does 'nrformats' leak from the popup window buffer??? +- Option to set first line to display (useful for a preview window) +- Disable commands, feedkeys(), CTRL-W, etc. in a popup window. + Use NOT_IN_POPUP_WINDOW for more commands. - Add 'balloonpopup': instead of showing text, let the callback open a popup window and return the window ID. The popup will then be closed when the mouse moves, except when it moves inside the popup. - For the "moved" property also include mouse movement? +- When selecting text in the popup with modeless selection, do not select + outside of the popup and don't select the border or padding. +- Allow the user to drag the popup window when the "dragging" property is set. - Make redrawing more efficient and avoid flicker: - put popup menu also put in popup_mask? -- Disable commands, feedkeys(), CTRL-W, etc. in a popup window. - Use NOT_IN_POPUP_WINDOW for more commands. - Invoke filter with character before mapping? - Figure out the size and position better. if wrapping splits a double-wide character if wrapping inserts indent +- When drawing on top half a double-wide character, display ">" or "<" in the + incomplete cell. - Can the buffer be re-used, to avoid using up lots of buffer numbers? - Implement all the unimplemented options and features. @@ -106,7 +114,34 @@ IMPLEMENTATION: THIS IS UNDER DESIGN - ANYTHING MAY STILL CHANGE -[functions to be moved to eval.txt later, keep overview of functions here] +Creating a popup window: + |popup_create()| centered in the screen + |popup_atcursor()| just above the cursor position, closes when + the cursor moves away + |popup_notifiation()| show a notification for three seconds + |popup_dialog()| centered with padding and border + |popup_menu()| prompt for selecting an item from a list + +Manipulating a popup window: + |popup_hide()| hide a popup temporarily + |popup_show()| show a previously hidden popup + |popup_move()| change the position and size of a popup + |popup_setoptions()| override options of a popup + +Closing popup windows: + |popup_close()| close one popup + |popup_clear()| close all popups + +Filter functions: + |popup_filter_menu()| select from a list of items + |popup_filter_yesno()| blocks until 'y' or 'n' is pressed + +Other: + |popup_getoptions()| get current options for a popup + |popup_getpos()| get actual position and size of a popup + + +[functions to be moved to eval.txt later] popup_atcursor({text}, {options}) *popup_atcursor()* Show the {text} above the cursor, and close it when the cursor @@ -162,7 +197,8 @@ popup_dialog({text}, {options}) *popup_dialog()* \ 'border': [], \ 'padding': [], \}) -< Use {options} to change the properties. +< Use {options} to change the properties. E.g. add a 'filter' + option with value 'popup_filter_yesno'. popup_filter_menu({id}, {key}) *popup_filter_menu()* @@ -180,7 +216,7 @@ popup_filter_yesno({id}, {key}) *popup_filter_yesno()* 'y', 'Y' and 'n' or 'N'. Invokes the "callback" of the popup menu with the 1 for 'y' or 'Y' and zero for 'n' or 'N' as the second argument. Pressing Esc and CTRL-C works like - pressing 'n'. + pressing 'n'. Other keys are ignored. popup_getoptions({id}) *popup_getoptions()* @@ -250,7 +286,6 @@ popup_move({id}, {options}) *popup_move()* popup_notification({text}, {options}) *popup_notification()* - {not implemented yet} Show the {text} for 3 seconds at the top of the Vim window. This works like: > call popup_create({text}, { @@ -261,8 +296,11 @@ popup_notification({text}, {options}) *popup_notification()* \ 'zindex': 200, \ 'highlight': 'WarningMsg', \ 'border': [], + \ 'padding': [0,1,0,1], \ }) -< Use {options} to change the properties. +< The position will be adjusted to avoid overlap with other + notifications. + Use {options} to change the properties. popup_show({id}) *popup_show()* diff --git a/src/evalfunc.c b/src/evalfunc.c index 134280f6de..0ef76095f4 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -819,6 +819,7 @@ static struct fst {"popup_getpos", 1, 1, f_popup_getpos}, {"popup_hide", 1, 1, f_popup_hide}, {"popup_move", 2, 2, f_popup_move}, + {"popup_notification", 2, 2, f_popup_notification}, {"popup_show", 1, 1, f_popup_show}, #endif #ifdef FEAT_FLOAT diff --git a/src/popupwin.c b/src/popupwin.c index adfa462299..d0f106fe61 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -110,7 +110,6 @@ get_padding_border(dict_T *dict, int *array, char *name, int max_val) { dictitem_T *di; - vim_memset(array, 0, sizeof(int) * 4); di = dict_find(dict, (char_u *)name, -1); if (di != NULL) { @@ -165,6 +164,26 @@ set_moved_columns(win_T *wp, int flags) } } + +#if defined(FEAT_TIMERS) + static void +popup_add_timeout(win_T *wp, int time) +{ + char_u cbbuf[50]; + char_u *ptr = cbbuf; + typval_T tv; + + vim_snprintf((char *)cbbuf, sizeof(cbbuf), + "{_ -> popup_close(%d)}", wp->w_id); + if (get_lambda_tv(&ptr, &tv, TRUE) == OK) + { + wp->w_popup_timer = create_timer(time, 0); + wp->w_popup_timer->tr_callback = get_callback(&tv); + clear_tv(&tv); + } +} +#endif + /* * Go through the options in "dict" and apply them to buffer "buf" displayed in * popup window "wp". @@ -184,31 +203,22 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) get_pos_options(wp, dict); - wp->w_zindex = dict_get_number(dict, (char_u *)"zindex"); - if (wp->w_zindex < 1) - wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX; - if (wp->w_zindex > 32000) - wp->w_zindex = 32000; + di = dict_find(dict, (char_u *)"zindex", -1); + if (di != NULL) + { + wp->w_zindex = dict_get_number(dict, (char_u *)"zindex"); + if (wp->w_zindex < 1) + wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX; + if (wp->w_zindex > 32000) + wp->w_zindex = 32000; + } -# if defined(FEAT_TIMERS) +#if defined(FEAT_TIMERS) // Add timer to close the popup after some time. nr = dict_get_number(dict, (char_u *)"time"); if (nr > 0) - { - char_u cbbuf[50]; - char_u *ptr = cbbuf; - typval_T tv; - - vim_snprintf((char *)cbbuf, sizeof(cbbuf), - "{_ -> popup_close(%d)}", wp->w_id); - if (get_lambda_tv(&ptr, &tv, TRUE) == OK) - { - wp->w_popup_timer = create_timer(nr, 0); - wp->w_popup_timer->tr_callback = get_callback(&tv); - clear_tv(&tv); - } - } -# endif + popup_add_timeout(wp, nr); +#endif // Option values resulting in setting an option. str = dict_get_string(dict, (char_u *)"highlight", FALSE); @@ -601,7 +611,8 @@ popup_adjust_position(win_T *wp) typedef enum { TYPE_NORMAL, - TYPE_ATCURSOR + TYPE_ATCURSOR, + TYPE_NOTIFICATION } create_type_T; /* @@ -659,7 +670,13 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) // Avoid that 'buftype' is reset when this buffer is entered. buf->b_p_initialized = TRUE; - nr = (int)dict_get_number(d, (char_u *)"tab"); + if (dict_find(d, (char_u *)"tab", -1) != NULL) + nr = (int)dict_get_number(d, (char_u *)"tab"); + else if (type == TYPE_NOTIFICATION) + nr = -1; // notifications are global by default + else + nr = 0; + if (nr == 0) { // popup on current tab @@ -668,9 +685,18 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) } else if (nr < 0) { - // global popup - wp->w_next = first_popupwin; - first_popupwin = wp; + win_T *prev = first_popupwin; + + // Global popup: add at the end, so that it gets displayed on top of + // older ones with the same zindex. Matters for notifications. + if (first_popupwin == NULL) + first_popupwin = wp; + else + { + while (prev->w_next != NULL) + prev = prev->w_next; + prev->w_next = wp; + } } else // TODO: find tab page "nr" @@ -720,9 +746,52 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) // set default values wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX; + if (type == TYPE_NOTIFICATION) + { + win_T *twp, *nextwin; + int height = buf->b_ml.ml_line_count + 3; + int i; + + // Try to not overlap with another global popup. Guess we need 3 + // more screen lines than buffer lines. + wp->w_wantline = 1; + for (twp = first_popupwin; twp != NULL; twp = nextwin) + { + nextwin = twp->w_next; + if (twp != wp + && twp->w_zindex == POPUPWIN_NOTIFICATION_ZINDEX + && twp->w_winrow <= wp->w_wantline - 1 + height + && twp->w_winrow + popup_height(twp) > wp->w_wantline - 1) + { + // move to below this popup and restart the loop to check for + // overlap with other popups + wp->w_wantline = twp->w_winrow + popup_height(twp) + 1; + nextwin = first_popupwin; + } + } + if (wp->w_wantline + height > Rows) + { + // can't avoid overlap, put on top in the hope that message goes + // away soon. + wp->w_wantline = 1; + } + + wp->w_wantcol = 10; + wp->w_zindex = POPUPWIN_NOTIFICATION_ZINDEX; + for (i = 0; i < 4; ++i) + wp->w_popup_border[i] = 1; + wp->w_popup_padding[1] = 1; + wp->w_popup_padding[3] = 1; + set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1, + (char_u *)"WarningMsg", OPT_FREE|OPT_LOCAL, 0); + } + // Deal with options. apply_options(wp, buf, argvars[1].vval.v_dict); + if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL) + popup_add_timeout(wp, 3000); + popup_adjust_position(wp); wp->w_vsep_width = 0; @@ -758,6 +827,15 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv) popup_create(argvars, rettv, TYPE_ATCURSOR); } +/* + * popup_notification({text}, {options}) + */ + void +f_popup_notification(typval_T *argvars, typval_T *rettv) +{ + popup_create(argvars, rettv, TYPE_NOTIFICATION); +} + /* * Find the popup window with window-ID "id". * If the popup window does not exist NULL is returned. @@ -1017,8 +1095,10 @@ f_popup_getpos(typval_T *argvars, typval_T *rettv) dict_add_number(dict, "line", wp->w_winrow + 1); dict_add_number(dict, "col", wp->w_wincol + 1); - dict_add_number(dict, "width", wp->w_width + left_extra + wp->w_popup_border[1] + wp->w_popup_padding[1]); - dict_add_number(dict, "height", wp->w_height + top_extra + wp->w_popup_border[2] + wp->w_popup_padding[2]); + dict_add_number(dict, "width", wp->w_width + left_extra + + wp->w_popup_border[1] + wp->w_popup_padding[1]); + dict_add_number(dict, "height", wp->w_height + top_extra + + wp->w_popup_border[2] + wp->w_popup_padding[2]); dict_add_number(dict, "core_line", wp->w_winrow + 1 + top_extra); dict_add_number(dict, "core_col", wp->w_wincol + 1 + left_extra); diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index a27444679e..03d3729ed0 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -5,6 +5,7 @@ void popup_adjust_position(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); +void f_popup_notification(typval_T *argvars, typval_T *rettv); int popup_any_visible(void); void f_popup_close(typval_T *argvars, typval_T *rettv); void f_popup_hide(typval_T *argvars, typval_T *rettv); diff --git a/src/structs.h b/src/structs.h index 8e6d93f30e..1fd430965d 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1992,8 +1992,9 @@ typedef enum { POPPOS_CENTER } poppos_T; -# define POPUPWIN_DEFAULT_ZINDEX 50 -# define POPUPMENU_ZINDEX 100 +# define POPUPWIN_DEFAULT_ZINDEX 50 +# define POPUPMENU_ZINDEX 100 +# define POPUPWIN_NOTIFICATION_ZINDEX 200 #endif /* diff --git a/src/testdir/dumps/Test_popupwin_notify_01.dump b/src/testdir/dumps/Test_popupwin_notify_01.dump new file mode 100644 index 0000000000..2ecd5ee1d0 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_notify_01.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @7|╔+0#e000002&|═@19|╗| +0#0000000&@43 +|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0#0000000&@43 +|3| @7|╚+0#e000002&|═@19|╝| +0#0000000&@43 +|4| @73 +|5| @73 +|6| @73 +|7| @73 +|8| @73 +|9| @73 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_notify_02.dump b/src/testdir/dumps/Test_popupwin_notify_02.dump new file mode 100644 index 0000000000..10170619a2 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_notify_02.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @7|╔+0#e000002&|═@19|╗| +0#0000000&@43 +|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0#0000000&@43 +|3| @7|╚+0#e000002&|═@19|╝| +0#0000000&@43 +|4| @7|╔+0fd7ff255|═@31|╗| +0&#ffffff0@31 +|5| @7|║+0fd7ff255| |a|n|o|t|h|e|r| |i|m|p|o|r|t|a|n|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0&#ffffff0@31 +|6| @7|╚+0fd7ff255|═@31|╝| +0&#ffffff0@31 +|7| @73 +|8| @73 +|9| @73 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index d100dc9938..9afd84033d 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -428,7 +428,7 @@ endfunc func Test_popup_time() if !has('timers') - return + throw 'Skipped, timer feature not supported' endif topleft vnew call setline(1, 'hello') @@ -1086,3 +1086,29 @@ func Test_popup_moved() bwipe! call test_override('ALL', 0) endfunc + +func Test_notifications() + if !has('timers') + throw 'Skipped, timer feature not supported' + endif + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + call writefile([ + \ "call setline(1, range(1, 20))", + \ "hi Notification ctermbg=lightblue", + \ "call popup_notification('first notification', {})", + \], 'XtestNotifications') + let buf = RunVimInTerminal('-S XtestNotifications', {'rows': 10}) + call VerifyScreenDump(buf, 'Test_popupwin_notify_01', {}) + + " second one goes below the first one + call term_sendkeys(buf, ":call popup_notification('another important notification', {'highlight': 'Notification'})\") + call VerifyScreenDump(buf, 'Test_popupwin_notify_02', {}) + + + " clean up + call StopVimInTerminal(buf) + call delete('XtestNotifications') +endfunc diff --git a/src/version.c b/src/version.c index 28877cb560..9c4d0688ae 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 */ +/**/ + 1522, /**/ 1521, /**/ From 8d241040310a6a27c28d62fa04558f2bfaa5ebde Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 12 Jun 2019 23:40:01 +0200 Subject: [PATCH 06/44] patch 8.1.1523: cannot show range of buffer lines in popup window Problem: Cannot show range of buffer lines in popup window. Solution: Add the "firstline" property. (closes #4523) --- runtime/doc/popup.txt | 4 +++- src/popupwin.c | 19 ++++++++++++++++-- src/structs.h | 1 + .../dumps/Test_popupwin_firstline.dump | 10 ++++++++++ src/testdir/test_popupwin.vim | 20 +++++++++++++++++++ src/version.c | 2 ++ 6 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_firstline.dump diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index b80b875595..7e56d35b9b 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -87,7 +87,6 @@ that it is in. IMPLEMENTATION: - Why does 'nrformats' leak from the popup window buffer??? -- Option to set first line to display (useful for a preview window) - Disable commands, feedkeys(), CTRL-W, etc. in a popup window. Use NOT_IN_POPUP_WINDOW for more commands. - Add 'balloonpopup': instead of showing text, let the callback open a popup @@ -396,6 +395,9 @@ The second argument of |popup_create()| is a dictionary with options: padding. minwidth Minimum width of the contents, excluding border and padding. + firstline First buffer line to display. When larger than one it + looks like the text scrolled up. When out of range + the last buffer line will at the top of the window. hidden When TRUE the popup exists but is not displayed; use `popup_show()` to unhide it. {not implemented yet} diff --git a/src/popupwin.c b/src/popupwin.c index d0f106fe61..5e444aee03 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -226,6 +226,10 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1, str, OPT_FREE|OPT_LOCAL, 0); + wp->w_firstline = dict_get_number(dict, (char_u *)"firstline"); + if (wp->w_firstline < 1) + wp->w_firstline = 1; + di = dict_find(dict, (char_u *)"wrap", -1); if (di != NULL) { @@ -519,10 +523,15 @@ popup_adjust_position(win_T *wp) maxwidth = wp->w_maxwidth; } + // start at the desired first line + 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; + // Compute width based on longest text line and the 'wrap' option. // TODO: more accurate wrapping wp->w_width = 0; - for (lnum = 1; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum) + for (lnum = wp->w_topline; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum) { int len = vim_strsize(ml_get_buf(wp->w_buffer, lnum, FALSE)); @@ -556,6 +565,10 @@ popup_adjust_position(win_T *wp) } if (wp->w_width < len) wp->w_width = len; + // do not use the width of lines we're not going to show + if (wp->w_maxheight > 0 && wp->w_buffer->b_ml.ml_line_count + - wp->w_topline + 1 + wrapped > wp->w_maxheight) + break; } if (wp->w_minwidth > 0 && wp->w_width < wp->w_minwidth) @@ -573,7 +586,8 @@ popup_adjust_position(win_T *wp) wp->w_wincol = wp->w_wantcol - (wp->w_width + extra_width); } - wp->w_height = wp->w_buffer->b_ml.ml_line_count + wrapped; + wp->w_height = wp->w_buffer->b_ml.ml_line_count - wp->w_topline + + 1 + wrapped; if (wp->w_minheight > 0 && wp->w_height < wp->w_minheight) wp->w_height = wp->w_minheight; if (wp->w_maxheight > 0 && wp->w_height > wp->w_maxheight) @@ -1133,6 +1147,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv) dict_add_number(dict, "minheight", wp->w_minheight); dict_add_number(dict, "maxheight", wp->w_maxheight); dict_add_number(dict, "maxwidth", wp->w_maxwidth); + dict_add_number(dict, "firstline", wp->w_firstline); dict_add_number(dict, "zindex", wp->w_zindex); dict_add_number(dict, "fixed", wp->w_popup_fixed); diff --git a/src/structs.h b/src/structs.h index 1fd430965d..da5ed2e53a 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2895,6 +2895,7 @@ struct window_S int w_maxwidth; // "maxwidth" for popup window int w_wantline; // "line" for popup window int w_wantcol; // "col" for popup window + int w_firstline; // "firstline" for popup window int w_popup_padding[4]; // popup padding top/right/bot/left int w_popup_border[4]; // popup border top/right/bot/left char_u *w_border_highlight[4]; // popup border highlight diff --git a/src/testdir/dumps/Test_popupwin_firstline.dump b/src/testdir/dumps/Test_popupwin_firstline.dump new file mode 100644 index 0000000000..276f4e5190 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_firstline.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @73 +|3| @73 +|4| @33|3+0#0000001#ffd7ff255@4| +0#0000000#ffffff0@34 +|5| @33|4+0#0000001#ffd7ff255@1| @2| +0#0000000#ffffff0@34 +|6| @33|5+0#0000001#ffd7ff255| @3| +0#0000000#ffffff0@34 +|7| @33|6+0#0000001#ffd7ff255@4| +0#0000000#ffffff0@34 +|8| @73 +|9| @73 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 9afd84033d..6def8e45a9 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -269,6 +269,26 @@ func Test_popup_all_corners() call delete('XtestPopupCorners') endfunc +func Test_popup_firstline() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + let lines =<< trim END + call setline(1, range(1, 20)) + call 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', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupFirstline') +endfunc + func Test_popup_in_tab() " default popup is local to tab, not visible when in other tab let winid = popup_create("text", {}) diff --git a/src/version.c b/src/version.c index 9c4d0688ae..63eacb0295 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 */ +/**/ + 1523, /**/ 1522, /**/ From b0f94c1ff34d27d33aa9f96204985ea29c2eb0a1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 13 Jun 2019 22:19:53 +0200 Subject: [PATCH 07/44] patch 8.1.1524: tests are silently skipped Problem: Tests are silently skipped. Solution: Throw an exception for skipped tests in more places. --- src/testdir/shared.vim | 2 +- src/testdir/test_assert.vim | 19 +++++++++++++++++++ src/testdir/test_crypt.vim | 2 +- src/testdir/test_cscope.vim | 7 +++++-- src/testdir/test_digraph.vim | 2 +- src/testdir/test_float_func.vim | 2 +- src/testdir/test_gui.vim | 2 +- src/testdir/test_gui_init.vim | 2 +- src/testdir/test_history.vim | 2 +- src/testdir/test_langmap.vim | 2 +- src/testdir/test_listlbr.vim | 7 +++++-- src/testdir/test_listlbr_utf8.vim | 10 ++++++++-- src/testdir/test_lua.vim | 2 +- src/testdir/test_makeencoding.vim | 3 +-- src/testdir/test_matchadd_conceal.vim | 3 ++- src/testdir/test_matchadd_conceal_utf8.vim | 3 ++- src/testdir/test_memory_usage.vim | 16 +++++++++++----- src/testdir/test_menu.vim | 2 +- src/testdir/test_mksession.vim | 2 +- src/testdir/test_mksession_utf8.vim | 2 +- src/testdir/test_netbeans.vim | 5 ++--- src/testdir/test_paste.vim | 9 +++++---- src/testdir/test_perl.vim | 2 +- src/testdir/test_profile.vim | 3 ++- src/testdir/test_prompt_buffer.vim | 2 +- src/testdir/test_python2.vim | 2 +- src/testdir/test_python3.vim | 2 +- src/testdir/test_pyx2.vim | 2 +- src/testdir/test_pyx3.vim | 2 +- src/testdir/test_quickfix.vim | 2 +- src/testdir/test_quotestar.vim | 2 +- src/testdir/test_reltime.vim | 7 +++++-- src/testdir/test_ruby.vim | 2 +- src/testdir/test_sha256.vim | 7 +++++-- src/testdir/test_shortpathname.vim | 2 +- src/testdir/test_signals.vim | 2 +- src/testdir/test_signs.vim | 2 +- src/testdir/test_spell.vim | 2 +- src/testdir/test_syntax.vim | 2 +- src/testdir/test_tcl.vim | 2 +- src/testdir/test_termcodes.vim | 7 +++++-- src/testdir/test_terminal.vim | 2 +- src/testdir/test_terminal_fail.vim | 2 +- src/testdir/test_textobjects.vim | 2 +- src/testdir/test_textprop.vim | 2 +- src/testdir/test_timers.vim | 2 +- src/testdir/test_vartabs.vim | 2 +- src/testdir/test_winbar.vim | 2 +- src/testdir/test_windows_home.vim | 2 +- src/testdir/test_xxd.vim | 2 +- src/version.c | 2 ++ 51 files changed, 115 insertions(+), 65 deletions(-) diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim index 4546be7f74..ae023a73b9 100644 --- a/src/testdir/shared.vim +++ b/src/testdir/shared.vim @@ -330,7 +330,7 @@ endfunc " Get line "lnum" as displayed on the screen. " Trailing white space is trimmed. -func! Screenline(lnum) +func Screenline(lnum) let chars = [] for c in range(1, winwidth(0)) call add(chars, nr2char(screenchar(a:lnum, c))) diff --git a/src/testdir/test_assert.vim b/src/testdir/test_assert.vim index 7df641c6a4..0d59a43a2d 100644 --- a/src/testdir/test_assert.vim +++ b/src/testdir/test_assert.vim @@ -222,6 +222,25 @@ func Test_override() call assert_fails("call test_override('redraw', 'yes')", 'E474') endfunc +func Test_mouse_position() + let save_mouse = &mouse + set mouse=a + new + call setline(1, ['line one', 'line two']) + call assert_equal([0, 1, 1, 0], getpos('.')) + call test_setmouse(1, 5) + call feedkeys("\", "xt") + call assert_equal([0, 1, 5, 0], getpos('.')) + call test_setmouse(2, 20) + call feedkeys("\", "xt") + call assert_equal([0, 2, 8, 0], getpos('.')) + call test_setmouse(5, 1) + call feedkeys("\", "xt") + call assert_equal([0, 2, 1, 0], getpos('.')) + bwipe! + let &mouse = save_mouse +endfunc + func Test_user_is_happy() smile sleep 300m diff --git a/src/testdir/test_crypt.vim b/src/testdir/test_crypt.vim index bf1a511118..db100991ab 100644 --- a/src/testdir/test_crypt.vim +++ b/src/testdir/test_crypt.vim @@ -1,7 +1,7 @@ " Tests for encryption. if !has('cryptv') - finish + throw 'Skipped, encryption feature missing' endif func Common_head_only(text) diff --git a/src/testdir/test_cscope.vim b/src/testdir/test_cscope.vim index 7795ac7af2..a3fcbd77b6 100644 --- a/src/testdir/test_cscope.vim +++ b/src/testdir/test_cscope.vim @@ -1,7 +1,10 @@ " Test for cscope commands. -if !has('cscope') || !executable('cscope') || !has('quickfix') - finish +if !has('cscope') || !has('quickfix') + throw 'Skipped, cscope or quickfix feature missing' +endif +if !executable('cscope') + throw 'Skipped, cscope program missing' endif func CscopeSetupOrClean(setup) diff --git a/src/testdir/test_digraph.vim b/src/testdir/test_digraph.vim index 8d56a1a247..92d4e479a7 100644 --- a/src/testdir/test_digraph.vim +++ b/src/testdir/test_digraph.vim @@ -1,7 +1,7 @@ " Tests for digraphs if !has("digraphs") - finish + throw 'Skipped, digraphs feature missing' endif func Put_Dig(chars) diff --git a/src/testdir/test_float_func.vim b/src/testdir/test_float_func.vim index 29bfc9e2d0..6340b538f5 100644 --- a/src/testdir/test_float_func.vim +++ b/src/testdir/test_float_func.vim @@ -1,7 +1,7 @@ " test float functions if !has('float') - finish + throw 'Skipped, float feature missing' end func Test_abs() diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index 5a1763db8d..d030a6ae6a 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -2,7 +2,7 @@ source shared.vim if !CanRunGui() - finish + throw 'Skipped, cannot run GUI' endif source setup_gui.vim diff --git a/src/testdir/test_gui_init.vim b/src/testdir/test_gui_init.vim index 638708f4f1..a8eefa56b9 100644 --- a/src/testdir/test_gui_init.vim +++ b/src/testdir/test_gui_init.vim @@ -3,7 +3,7 @@ source shared.vim if !CanRunGui() - finish + throw 'Skipped, cannot run GUI' endif source setup_gui.vim diff --git a/src/testdir/test_history.vim b/src/testdir/test_history.vim index 16aad9889e..4b464137bb 100644 --- a/src/testdir/test_history.vim +++ b/src/testdir/test_history.vim @@ -1,7 +1,7 @@ " Tests for the history functions if !has('cmdline_hist') - finish + throw 'Skipped, cmdline_hist feature missing' endif set history=7 diff --git a/src/testdir/test_langmap.vim b/src/testdir/test_langmap.vim index 572fad78ba..4b260f8480 100644 --- a/src/testdir/test_langmap.vim +++ b/src/testdir/test_langmap.vim @@ -1,7 +1,7 @@ " tests for 'langmap' if !has('langmap') - finish + throw 'Skipped, langmap feature missing' endif func Test_langmap() diff --git a/src/testdir/test_listlbr.vim b/src/testdir/test_listlbr.vim index 29e797dc25..5af4133ec8 100644 --- a/src/testdir/test_listlbr.vim +++ b/src/testdir/test_listlbr.vim @@ -3,8 +3,11 @@ set encoding=latin1 scriptencoding latin1 -if !exists("+linebreak") || !has("conceal") - finish +if !exists("+linebreak") + throw 'Skipped, linebreak option missing' +endif +if !has("conceal") + throw 'Skipped, conceal feature missing' endif source view_util.vim diff --git a/src/testdir/test_listlbr_utf8.vim b/src/testdir/test_listlbr_utf8.vim index c38e0c5f3c..1154d6626b 100644 --- a/src/testdir/test_listlbr_utf8.vim +++ b/src/testdir/test_listlbr_utf8.vim @@ -3,8 +3,14 @@ set encoding=utf-8 scriptencoding utf-8 -if !exists("+linebreak") || !has("conceal") || !has("signs") - finish +if !exists("+linebreak") + throw 'Skipped, linebreak option missing' +endif +if !has("conceal") + throw 'Skipped, conceal feature missing' +endif +if !has("signs") + throw 'Skipped, signs feature missing' endif source view_util.vim diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index 604cfedd32..5d2f088e3f 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -1,7 +1,7 @@ " Tests for Lua. if !has('lua') - finish + throw 'Skipped, lua feature missing' endif func TearDown() diff --git a/src/testdir/test_makeencoding.vim b/src/testdir/test_makeencoding.vim index d18b3b6de8..6de3c706f3 100644 --- a/src/testdir/test_makeencoding.vim +++ b/src/testdir/test_makeencoding.vim @@ -4,8 +4,7 @@ source shared.vim let s:python = PythonProg() if s:python == '' - " Can't run this test. - finish + throw 'Skipped, python program missing' endif let s:script = 'test_makeencoding.py' diff --git a/src/testdir/test_matchadd_conceal.vim b/src/testdir/test_matchadd_conceal.vim index 8d774a0005..a7c8b06f53 100644 --- a/src/testdir/test_matchadd_conceal.vim +++ b/src/testdir/test_matchadd_conceal.vim @@ -1,6 +1,7 @@ " Test for matchadd() and conceal feature + if !has('conceal') - finish + throw 'Skipped, conceal feature missing' endif if !has('gui_running') && has('unix') diff --git a/src/testdir/test_matchadd_conceal_utf8.vim b/src/testdir/test_matchadd_conceal_utf8.vim index d280c153ac..fb275777da 100644 --- a/src/testdir/test_matchadd_conceal_utf8.vim +++ b/src/testdir/test_matchadd_conceal_utf8.vim @@ -1,6 +1,7 @@ " Test for matchadd() and conceal feature using utf-8. + if !has('conceal') - finish + throw 'Skipped, conceal feature missing' endif if !has('gui_running') && has('unix') diff --git a/src/testdir/test_memory_usage.vim b/src/testdir/test_memory_usage.vim index 8c2f8f7315..eadd4ea970 100644 --- a/src/testdir/test_memory_usage.vim +++ b/src/testdir/test_memory_usage.vim @@ -1,9 +1,15 @@ " Tests for memory usage. -if !has('terminal') || has('gui_running') || $ASAN_OPTIONS !=# '' +if !has('terminal') + throw 'Skipped, terminal feature missing' +endif +if has('gui_running') + throw 'Skipped, does not work in GUI' +endif +if $ASAN_OPTIONS !=# '' " Skip tests on Travis CI ASAN build because it's difficult to estimate " memory usage. - finish + throw 'Skipped, does not work with ASAN' endif source shared.vim @@ -14,7 +20,7 @@ endfunc if has('win32') if !executable('wmic') - finish + throw 'Skipped, wmic program missing' endif func s:memory_usage(pid) abort let cmd = printf('wmic process where processid=%d get WorkingSetSize', a:pid) @@ -22,13 +28,13 @@ if has('win32') endfunc elseif has('unix') if !executable('ps') - finish + throw 'Skipped, ps program missing' endif func s:memory_usage(pid) abort return s:pick_nr(system('ps -o rss= -p ' . a:pid)) endfunc else - finish + throw 'Skipped, not win32 or unix' endif " Wait for memory usage to level off. diff --git a/src/testdir/test_menu.vim b/src/testdir/test_menu.vim index b57fdc3de2..99f888af19 100644 --- a/src/testdir/test_menu.vim +++ b/src/testdir/test_menu.vim @@ -1,7 +1,7 @@ " Test that the system menu can be loaded. if !has('menu') - finish + throw 'Skipped, menu feature missing' endif func Test_load_menu() diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim index bc413968b4..ee2d148c67 100644 --- a/src/testdir/test_mksession.vim +++ b/src/testdir/test_mksession.vim @@ -4,7 +4,7 @@ set encoding=latin1 scriptencoding latin1 if !has('mksession') - finish + throw 'Skipped, mksession feature missing' endif source shared.vim diff --git a/src/testdir/test_mksession_utf8.vim b/src/testdir/test_mksession_utf8.vim index 36f07512a8..6bf5823ce8 100644 --- a/src/testdir/test_mksession_utf8.vim +++ b/src/testdir/test_mksession_utf8.vim @@ -4,7 +4,7 @@ set encoding=utf-8 scriptencoding utf-8 if !has('mksession') - finish + throw 'Skipped, mksession feature missing' endif func Test_mksession_utf8() diff --git a/src/testdir/test_netbeans.vim b/src/testdir/test_netbeans.vim index 66177ada76..836bddff3c 100644 --- a/src/testdir/test_netbeans.vim +++ b/src/testdir/test_netbeans.vim @@ -1,15 +1,14 @@ " Test the netbeans interface. if !has('netbeans_intg') - finish + throw 'Skipped, netbeans_intg feature missing' endif source shared.vim let s:python = PythonProg() if s:python == '' - " Can't run this test. - finish + throw 'Skipped, python program missing' endif " Run "testfunc" after sarting the server and stop the server afterwards. diff --git a/src/testdir/test_paste.vim b/src/testdir/test_paste.vim index 29206b94bc..ee69641538 100644 --- a/src/testdir/test_paste.vim +++ b/src/testdir/test_paste.vim @@ -1,8 +1,11 @@ " Tests for bracketed paste and other forms of pasting. " Bracketed paste only works with "xterm". Not in GUI or Windows console. -if has('gui_running') || has('win32') - finish +if has('win32') + throw 'Skipped, does not work on MS-Windows' +endif +if has('gui_running') + throw 'Skipped, does not work in the GUI' endif set term=xterm @@ -122,7 +125,6 @@ func Test_xrestore() if !has('xterm_clipboard') return endif -call ch_logfile('logfile', 'w') let display = $DISPLAY new call CheckCopyPaste() @@ -133,6 +135,5 @@ call ch_logfile('logfile', 'w') exe "xrestore " .. display call CheckCopyPaste() -call ch_logfile('', '') bwipe! endfunc diff --git a/src/testdir/test_perl.vim b/src/testdir/test_perl.vim index e24c04f7ce..d38fc07982 100644 --- a/src/testdir/test_perl.vim +++ b/src/testdir/test_perl.vim @@ -1,7 +1,7 @@ " Tests for Perl interface if !has('perl') - finish + throw 'Skipped, perl feature missing' end " FIXME: RunTest don't see any error when Perl abort... diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim index ae47a6d8c3..ddabe3a953 100644 --- a/src/testdir/test_profile.vim +++ b/src/testdir/test_profile.vim @@ -1,6 +1,7 @@ " Test Vim profiler + if !has('profile') - finish + throw 'Skipped, profile feature missing' endif func Test_profile_func() diff --git a/src/testdir/test_prompt_buffer.vim b/src/testdir/test_prompt_buffer.vim index 1b8a1ec749..5cf65d5135 100644 --- a/src/testdir/test_prompt_buffer.vim +++ b/src/testdir/test_prompt_buffer.vim @@ -1,7 +1,7 @@ " Tests for setting 'buftype' to "prompt" if !has('channel') - finish + throw 'Skipped, channel feature missing' endif source shared.vim diff --git a/src/testdir/test_python2.vim b/src/testdir/test_python2.vim index 5703231ed7..5b10852288 100644 --- a/src/testdir/test_python2.vim +++ b/src/testdir/test_python2.vim @@ -2,7 +2,7 @@ " TODO: move tests from test87.in here. if !has('python') - finish + throw 'Skipped, python feature missing' endif func Test_pydo() diff --git a/src/testdir/test_python3.vim b/src/testdir/test_python3.vim index aacc5a5759..e001360e75 100644 --- a/src/testdir/test_python3.vim +++ b/src/testdir/test_python3.vim @@ -2,7 +2,7 @@ " TODO: move tests from test88.in here. if !has('python3') - finish + throw 'Skipped, python3 feature missing' endif func Test_py3do() diff --git a/src/testdir/test_pyx2.vim b/src/testdir/test_pyx2.vim index baaf7fa300..64bd579c26 100644 --- a/src/testdir/test_pyx2.vim +++ b/src/testdir/test_pyx2.vim @@ -2,7 +2,7 @@ set pyx=2 if !has('python') - finish + throw 'Skipped, python feature missing' endif let s:py2pattern = '^2\.[0-7]\.\d\+' diff --git a/src/testdir/test_pyx3.vim b/src/testdir/test_pyx3.vim index 4b6057a8d5..1b7bdae793 100644 --- a/src/testdir/test_pyx3.vim +++ b/src/testdir/test_pyx3.vim @@ -2,7 +2,7 @@ set pyx=3 if !has('python3') - finish + throw 'Skipped, python3 feature missing' endif let s:py2pattern = '^2\.[0-7]\.\d\+' diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index ef0a512028..2fa28c9947 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -1,7 +1,7 @@ " Test for the quickfix feature. if !has('quickfix') - finish + throw 'Skipped, quickfix feature missing' endif set encoding=utf-8 diff --git a/src/testdir/test_quotestar.vim b/src/testdir/test_quotestar.vim index 1334201a7e..b6dab6b571 100644 --- a/src/testdir/test_quotestar.vim +++ b/src/testdir/test_quotestar.vim @@ -2,7 +2,7 @@ source shared.vim if !WorkingClipboard() - finish + throw 'Skipped, no working clipboard' endif source shared.vim diff --git a/src/testdir/test_reltime.vim b/src/testdir/test_reltime.vim index adabf16c1e..1876539103 100644 --- a/src/testdir/test_reltime.vim +++ b/src/testdir/test_reltime.vim @@ -1,7 +1,10 @@ " Tests for reltime() -if !has('reltime') || !has('float') - finish +if !has('reltime') + throw 'Skipped, reltime feature missing' +endif +if !has('float') + throw 'Skipped, float feature missing' endif func Test_reltime() diff --git a/src/testdir/test_ruby.vim b/src/testdir/test_ruby.vim index 3c9df3a058..dcfdc62448 100644 --- a/src/testdir/test_ruby.vim +++ b/src/testdir/test_ruby.vim @@ -1,7 +1,7 @@ " Tests for ruby interface if !has('ruby') - finish + throw 'Skipped, ruby feature missing' end func Test_ruby_change_buffer() diff --git a/src/testdir/test_sha256.vim b/src/testdir/test_sha256.vim index dd4707977e..7f802b143b 100644 --- a/src/testdir/test_sha256.vim +++ b/src/testdir/test_sha256.vim @@ -1,7 +1,10 @@ " Tests for the sha256() function. -if !has('cryptv') || !exists('*sha256') - finish +if !has('cryptv') + throw 'Skipped, cryptv feature missing' +endif +if !exists('*sha256') + throw 'Skipped, sha256 function missing' endif function Test_sha256() diff --git a/src/testdir/test_shortpathname.vim b/src/testdir/test_shortpathname.vim index f151788ced..564cd96123 100644 --- a/src/testdir/test_shortpathname.vim +++ b/src/testdir/test_shortpathname.vim @@ -2,7 +2,7 @@ " Only for use on Win32 systems! if !has('win32') - finish + throw 'Skipped, not on MS-Windows' endif func TestIt(file, bits, expected) diff --git a/src/testdir/test_signals.vim b/src/testdir/test_signals.vim index 5dec1d32b8..365958a387 100644 --- a/src/testdir/test_signals.vim +++ b/src/testdir/test_signals.vim @@ -1,7 +1,7 @@ " Test signal handling. if !has('unix') - finish + throw 'Skipped, not on Unix' endif source shared.vim diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim index 8a6731cc41..4a23e4ba1b 100644 --- a/src/testdir/test_signs.vim +++ b/src/testdir/test_signs.vim @@ -1,7 +1,7 @@ " Test for signs if !has('signs') - finish + throw 'Skipped, signs feature missing' endif func Test_sign() diff --git a/src/testdir/test_spell.vim b/src/testdir/test_spell.vim index b3143c95fd..72599fdc13 100644 --- a/src/testdir/test_spell.vim +++ b/src/testdir/test_spell.vim @@ -1,7 +1,7 @@ " Test spell checking if !has('spell') - finish + throw 'Skipped, spell feature missing' endif func TearDown() diff --git a/src/testdir/test_syntax.vim b/src/testdir/test_syntax.vim index bdcef51147..8d9d7d35c1 100644 --- a/src/testdir/test_syntax.vim +++ b/src/testdir/test_syntax.vim @@ -1,7 +1,7 @@ " Test for syntax and syntax iskeyword option if !has("syntax") - finish + throw 'Skipped, syntax feature missing' endif source view_util.vim diff --git a/src/testdir/test_tcl.vim b/src/testdir/test_tcl.vim index c0eadc6372..8ccd34c6b6 100644 --- a/src/testdir/test_tcl.vim +++ b/src/testdir/test_tcl.vim @@ -1,7 +1,7 @@ " Tests for the Tcl interface. if !has('tcl') - finish + throw 'Skipped, tcl feature missing' end " Helper function as there is no builtin tcleval() function similar diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index 9cfc649831..9d7f6b5fa7 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -1,8 +1,11 @@ " Tests for decoding escape sequences sent by the terminal. " This only works for Unix in a terminal -if has('gui_running') || !has('unix') - finish +if has('gui_running') + throw 'Skipped, does not work in the GUI' +endif +if !has('unix') + throw 'Skipped, not on Unix' endif source shared.vim diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 5fab97510b..09c050aada 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1,7 +1,7 @@ " Tests for the terminal window. if !has('terminal') - finish + throw 'Skipped, terminal feature missing' endif source shared.vim diff --git a/src/testdir/test_terminal_fail.vim b/src/testdir/test_terminal_fail.vim index aad4b98cb5..d010c3b8f1 100644 --- a/src/testdir/test_terminal_fail.vim +++ b/src/testdir/test_terminal_fail.vim @@ -3,7 +3,7 @@ " freed. Since the process exists right away it's not a real leak. if !has('terminal') - finish + throw 'Skipped, terminal feature missing' endif source shared.vim diff --git a/src/testdir/test_textobjects.vim b/src/testdir/test_textobjects.vim index 0baabc0438..5366a35fba 100644 --- a/src/testdir/test_textobjects.vim +++ b/src/testdir/test_textobjects.vim @@ -1,7 +1,7 @@ " Test for textobjects if !has('textobjects') - finish + throw 'Skipped, textobjects feature missing' endif func CpoM(line, useM, expected) diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim index bfd39d5da0..cb27f5877c 100644 --- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -2,7 +2,7 @@ " buffer. if !has('textprop') - finish + throw 'Skipped, textprop feature missing' endif source screendump.vim diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim index 963cc23276..5b09011c75 100644 --- a/src/testdir/test_timers.vim +++ b/src/testdir/test_timers.vim @@ -1,7 +1,7 @@ " Test for timers if !has('timers') - finish + throw 'Skipped, timers feature missing' endif source shared.vim diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim index df61c0ea66..640aa0b305 100644 --- a/src/testdir/test_vartabs.vim +++ b/src/testdir/test_vartabs.vim @@ -1,7 +1,7 @@ " Test for variable tabstops if !has("vartabs") - finish + throw 'Skipped, vartabs feature missing' endif source view_util.vim diff --git a/src/testdir/test_winbar.vim b/src/testdir/test_winbar.vim index c0b43b934e..51ef0a8633 100644 --- a/src/testdir/test_winbar.vim +++ b/src/testdir/test_winbar.vim @@ -1,7 +1,7 @@ " Test WinBar if !has('menu') - finish + throw 'Skipped, menu feature missing' endif source shared.vim diff --git a/src/testdir/test_windows_home.vim b/src/testdir/test_windows_home.vim index 2e311b9aa5..da95ed27c8 100644 --- a/src/testdir/test_windows_home.vim +++ b/src/testdir/test_windows_home.vim @@ -1,7 +1,7 @@ " Test for $HOME on Windows. if !has('win32') - finish + throw 'Skipped, not on MS-Windows' endif let s:env = {} diff --git a/src/testdir/test_xxd.vim b/src/testdir/test_xxd.vim index 6b9dd547bd..63ac574abb 100644 --- a/src/testdir/test_xxd.vim +++ b/src/testdir/test_xxd.vim @@ -2,7 +2,7 @@ if empty($XXD) && executable('..\xxd\xxd.exe') let s:xxd_cmd = '..\xxd\xxd.exe' elseif empty($XXD) || !executable($XXD) - finish + throw 'Skipped, xxd program missing' else let s:xxd_cmd = $XXD endif diff --git a/src/version.c b/src/version.c index 63eacb0295..9835fcc7e2 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 */ +/**/ + 1524, /**/ 1523, /**/ From b53fb31a1e27a806396e38592055cfb3ebf43cf9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 13 Jun 2019 23:59:52 +0200 Subject: [PATCH 08/44] patch 8.1.1525: cannot move a popup window with the mouse Problem: Cannot move a popup window with the mouse. Solution: Add the "drag" property and make it possible to drag a popup window by its border. --- runtime/doc/popup.txt | 13 ++++++--- src/popupwin.c | 65 ++++++++++++++++++++++++++++++++++++++++++ src/proto/popupwin.pro | 3 ++ src/proto/window.pro | 1 + src/structs.h | 1 + src/ui.c | 43 ++++++++++++++++++++++------ src/version.c | 2 ++ src/window.c | 2 +- 8 files changed, 117 insertions(+), 13 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 7e56d35b9b..7da0d16896 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -95,7 +95,7 @@ IMPLEMENTATION: - For the "moved" property also include mouse movement? - When selecting text in the popup with modeless selection, do not select outside of the popup and don't select the border or padding. -- Allow the user to drag the popup window when the "dragging" property is set. +- Add test for dragging the popup window. - Make redrawing more efficient and avoid flicker: - put popup menu also put in popup_mask? - Invoke filter with character before mapping? @@ -277,7 +277,7 @@ popup_menu({text}, {options}) *popup_menu()* popup_move({id}, {options}) *popup_move()* - Move popup {id} to the position speficied with {options}. + Move popup {id} to the position specified with {options}. {options} may contain the items from |popup_create()| that specify the popup position: "line", "col", "pos", "maxheight", "minheight", "maxwidth" and "minwidth". @@ -293,6 +293,7 @@ popup_notification({text}, {options}) *popup_notification()* \ 'time': 3000, \ 'tab': -1, \ 'zindex': 200, + \ 'drag': 1, \ 'highlight': 'WarningMsg', \ 'border': [], \ 'padding': [0,1,0,1], @@ -409,9 +410,13 @@ The second argument of |popup_create()| is a dictionary with options: {only -1 and 0 are implemented} title Text to be displayed above the first item in the popup, on top of any border. If there is no top - border on line of padding is added to put the title on. + border one line of padding is added to put the title + on. {not implemented yet} wrap TRUE to make the lines wrap (default TRUE). + drag TRUE to allow the popup to be dragged with the mouse + by grabbing at at the border. Has no effect if the + popup does not have a border. highlight Highlight group name to use for the text, stored in the 'wincolor' option. padding List with numbers, defining the padding @@ -442,7 +447,7 @@ The second argument of |popup_create()| is a dictionary with options: By default a double line is used all around when 'encoding' is "utf-8", otherwise ASCII characters are used. - zindex Priority for the popup, default 50. Mininum value is + zindex Priority for the popup, default 50. Minimum value is 1, maximum value is 32000. time Time in milliseconds after which the popup will close. When omitted |popup_close()| must be used. diff --git a/src/popupwin.c b/src/popupwin.c index 5e444aee03..f773958bee 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -164,6 +164,68 @@ set_moved_columns(win_T *wp, int flags) } } +/* + * Return TRUE if "row"/"col" is on the border of the popup. + * The values are relative to the top-left corner. + */ + int +popup_on_border(win_T *wp, int row, int col) +{ + return (row == 0 && wp->w_popup_border[0] > 0) + || (row == popup_height(wp) - 1 && wp->w_popup_border[2] > 0) + || (col == 0 && wp->w_popup_border[3] > 0) + || (col == popup_width(wp) - 1 && wp->w_popup_border[1] > 0); +} + +// Values set when dragging a popup window starts. +static int drag_start_row; +static int drag_start_col; +static int drag_start_wantline; +static int drag_start_wantcol; + +/* + * Mouse down on border of popup window: start dragging it. + * Uses mouse_col and mouse_row. + */ + void +popup_start_drag(win_T *wp) +{ + drag_start_row = mouse_row; + drag_start_col = mouse_col; + // TODO: handle using different corner + if (wp->w_wantline == 0) + drag_start_wantline = wp->w_winrow + 1; + else + drag_start_wantline = wp->w_wantline; + if (wp->w_wantcol == 0) + drag_start_wantcol = wp->w_wincol + 1; + else + drag_start_wantcol = wp->w_wantcol; +} + +/* + * Mouse moved while dragging a popup window: adjust the window popup position. + */ + void +popup_drag(win_T *wp) +{ + // The popup may be closed before dragging stops. + if (!win_valid_popup(wp)) + return; + + wp->w_wantline = drag_start_wantline + (mouse_row - drag_start_row); + if (wp->w_wantline < 1) + wp->w_wantline = 1; + if (wp->w_wantline > Rows) + wp->w_wantline = Rows; + wp->w_wantcol = drag_start_wantcol + (mouse_col - drag_start_col); + if (wp->w_wantcol < 1) + wp->w_wantcol = 1; + if (wp->w_wantcol > Columns) + wp->w_wantcol = Columns; + + popup_adjust_position(wp); +} #if defined(FEAT_TIMERS) static void @@ -237,6 +299,8 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) wp->w_p_wrap = nr != 0; } + wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag"); + di = dict_find(dict, (char_u *)"callback", -1); if (di != NULL) { @@ -798,6 +862,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) wp->w_popup_padding[3] = 1; set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1, (char_u *)"WarningMsg", OPT_FREE|OPT_LOCAL, 0); + wp->w_popup_drag = 1; } // Deal with options. diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 03d3729ed0..eeabafa9a6 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -1,4 +1,7 @@ /* popupwin.c */ +int popup_on_border(win_T *wp, int row, int col); +void popup_start_drag(win_T *wp); +void popup_drag(win_T *wp); int popup_height(win_T *wp); int popup_width(win_T *wp); void popup_adjust_position(win_T *wp); diff --git a/src/proto/window.pro b/src/proto/window.pro index 1424c3de5a..94b9f083a1 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -3,6 +3,7 @@ void do_window(int nchar, long Prenum, int xchar); void get_wincmd_addr_type(char_u *arg, exarg_T *eap); int win_split(int size, int flags); int win_split_ins(int size, int flags, win_T *new_wp, int dir); +int win_valid_popup(win_T *win); int win_valid(win_T *win); int win_valid_any_tab(win_T *win); int win_count(void); diff --git a/src/structs.h b/src/structs.h index da5ed2e53a..04e21a106c 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2909,6 +2909,7 @@ struct window_S linenr_T w_popup_lnum; // close popup if cursor not on this line colnr_T w_popup_mincol; // close popup if cursor before this col colnr_T w_popup_maxcol; // close popup if cursor after this col + int w_popup_drag; // allow moving the popup with the mouse # if defined(FEAT_TIMERS) timer_T *w_popup_timer; // timer for closing popup window diff --git a/src/ui.c b/src/ui.c index 62d8ae7d3e..08b3011c0e 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1002,7 +1002,7 @@ static void clip_update_modeless_selection(VimClipboard *, int, int, /* * Start, continue or end a modeless selection. Used when editing the - * command-line and in the cmdline window. + * command-line, in the cmdline window and when the mouse is in a popup window. */ void clip_modeless(int button, int is_click, int is_drag) @@ -2841,7 +2841,8 @@ jump_to_mouse( static int in_winbar = FALSE; #endif #ifdef FEAT_TEXT_PROP - static int in_popup_win = FALSE; + static int in_popup_win = FALSE; + static win_T *popup_dragwin = NULL; #endif static int prev_row = -1; static int prev_col = -1; @@ -2869,6 +2870,9 @@ jump_to_mouse( flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE); dragwin = NULL; did_drag = FALSE; +#ifdef FEAT_TEXT_PROP + popup_dragwin = NULL; +#endif } if ((flags & MOUSE_DID_MOVE) @@ -2910,7 +2914,15 @@ retnomove: #ifdef FEAT_TEXT_PROP // Continue a modeless selection in a popup window. if (in_popup_win) + { + if (popup_dragwin != NULL) + { + // dragging a popup window + popup_drag(popup_dragwin); + return IN_UNKNOWN; + } return IN_OTHER_WIN; + } #endif return IN_BUFFER; } @@ -2936,29 +2948,36 @@ retnomove: if (!(flags & MOUSE_FOCUS)) { - if (row < 0 || col < 0) /* check if it makes sense */ + if (row < 0 || col < 0) // check if it makes sense return IN_UNKNOWN; - /* find the window where the row is in */ + // find the window where the row is in wp = mouse_find_win(&row, &col, FIND_POPUP); if (wp == NULL) return IN_UNKNOWN; dragwin = NULL; #ifdef FEAT_TEXT_PROP - // Click in a popup window may start modeless selection, but not much - // else. + // Click in a popup window may start dragging or modeless selection, + // but not much else. if (bt_popup(wp->w_buffer)) { on_sep_line = 0; in_popup_win = TRUE; + if (wp->w_popup_drag && popup_on_border(wp, row, col)) + { + popup_dragwin = wp; + popup_start_drag(wp); + return IN_UNKNOWN; + } # ifdef FEAT_CLIPBOARD return IN_OTHER_WIN; # else return IN_UNKNOWN; # endif } - in_popup_win = FALSE; + in_popup_win = FALSE; + popup_dragwin = NULL; #endif #ifdef FEAT_MENU if (row == -1) @@ -3127,9 +3146,17 @@ retnomove: return IN_OTHER_WIN; #endif #ifdef FEAT_TEXT_PROP - // Continue a modeless selection in a popup window. if (in_popup_win) + { + if (popup_dragwin != NULL) + { + // dragging a popup window + popup_drag(popup_dragwin); + return IN_UNKNOWN; + } + // continue a modeless selection in a popup window return IN_OTHER_WIN; + } #endif row -= W_WINROW(curwin); diff --git a/src/version.c b/src/version.c index 9835fcc7e2..058dbc702d 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 */ +/**/ + 1525, /**/ 1524, /**/ diff --git a/src/window.c b/src/window.c index c15a86111b..436912934e 100644 --- a/src/window.c +++ b/src/window.c @@ -1371,7 +1371,7 @@ win_init_some(win_T *newp, win_T *oldp) /* * Return TRUE if "win" is a global popup or a popup in the current tab page. */ - static int + int win_valid_popup(win_T *win UNUSED) { #ifdef FEAT_TEXT_PROP From 37df9a4401f6737d6216306ea77a7e080c942aea Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 14:39:51 +0200 Subject: [PATCH 09/44] patch 8.1.1526: no numerical value for the patchlevel Problem: No numerical value for the patchlevel. Solution: Add v:versionlong. --- runtime/doc/eval.txt | 11 +++++++++++ src/eval.c | 8 +++++--- src/testdir/test_eval_stuff.vim | 3 +++ src/version.c | 11 ++++------- src/vim.h | 3 ++- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 5f8156003f..da45de805a 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2173,6 +2173,17 @@ v:version Version number of Vim: Major version number times 100 plus version 5.0 and 5.1 may have a patch 123, but these are completely different. + *v:versionlong* *versionlong-variable* +v:versionlong Like v:version, but also including the patchlevel. Version + 8.1 with patch 1234 has value 8011234. This can be used like + this: > + if v:versionlong >= 8011234 +< However, if there are gaps in the list of patches included + this will not work well. This can happen if a recent patch + was included into an older version, e.g. for a security fix. + Use the has() function to make sure the patch is actually + included. + *v:vim_did_enter* *vim_did_enter-variable* v:vim_did_enter Zero until most of startup is done. It is set to one just before |VimEnter| autocommands are triggered. diff --git a/src/eval.c b/src/eval.c index c86d0a6646..e2d3d48bd3 100644 --- a/src/eval.c +++ b/src/eval.c @@ -193,9 +193,10 @@ static struct vimvar {VV_NAME("termrfgresp", VAR_STRING), VV_RO}, {VV_NAME("termrbgresp", VAR_STRING), VV_RO}, {VV_NAME("termu7resp", VAR_STRING), VV_RO}, - {VV_NAME("termstyleresp", VAR_STRING), VV_RO}, - {VV_NAME("termblinkresp", VAR_STRING), VV_RO}, - {VV_NAME("event", VAR_DICT), VV_RO}, + {VV_NAME("termstyleresp", VAR_STRING), VV_RO}, + {VV_NAME("termblinkresp", VAR_STRING), VV_RO}, + {VV_NAME("event", VAR_DICT), VV_RO}, + {VV_NAME("versionlong", VAR_NUMBER), VV_RO}, }; /* shorthand */ @@ -354,6 +355,7 @@ eval_init(void) hash_add(&compat_hashtab, p->vv_di.di_key); } vimvars[VV_VERSION].vv_nr = VIM_VERSION_100; + vimvars[VV_VERSIONLONG].vv_nr = VIM_VERSION_100 * 10000 + highest_patch(); set_vim_var_nr(VV_SEARCHFORWARD, 1L); set_vim_var_nr(VV_HLSEARCH, 1L); diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim index db68e2a402..08ab59ea53 100644 --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -171,6 +171,9 @@ func Test_vvar_scriptversion2() echo version call assert_fails('let version = 1', 'E46:') call assert_equal(v:version, version) + + call assert_equal(v:version, v:versionlong / 10000) + call assert_true(v:versionlong > 8011525) endfunc func Test_scriptversion() diff --git a/src/version.c b/src/version.c index 058dbc702d..8a9885c399 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 */ +/**/ + 1526, /**/ 1525, /**/ @@ -3847,13 +3849,8 @@ static char *(extra_patches[]) = int highest_patch(void) { - int i; - int h = 0; - - for (i = 0; included_patches[i] != 0; ++i) - if (included_patches[i] > h) - h = included_patches[i]; - return h; + // this relies on the highest patch number to be the first entry + return included_patches[0]; } #if defined(FEAT_EVAL) || defined(PROTO) diff --git a/src/vim.h b/src/vim.h index 3b4582bc91..90208cdc7e 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1960,7 +1960,8 @@ typedef int sock_T; #define VV_TERMSTYLERESP 85 #define VV_TERMBLINKRESP 86 #define VV_EVENT 87 -#define VV_LEN 88 /* number of v: vars */ +#define VV_VERSIONLONG 88 +#define VV_LEN 89 // number of v: vars /* used for v_number in VAR_SPECIAL */ #define VVAL_FALSE 0L From a540f8aa3b2570f1d903b63413301ec3d48b27d5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 19:23:57 +0200 Subject: [PATCH 10/44] patch 8.1.1527: when moving popup window over the cmdline it is not redrawn Problem: When moving a popup window over the command line it is not redrawn. Solution: Redraw the command line. Move popup redrawing code to the popupwin file. --- src/popupwin.c | 306 ++++++++++++++++++ src/proto/popupwin.pro | 2 + src/proto/screen.pro | 1 + src/screen.c | 309 +------------------ src/testdir/dumps/Test_popupwin_drag_01.dump | 10 + src/testdir/dumps/Test_popupwin_drag_02.dump | 10 + src/testdir/test_popupwin.vim | 30 ++ src/version.c | 2 + 8 files changed, 364 insertions(+), 306 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_drag_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_02.dump diff --git a/src/popupwin.c b/src/popupwin.c index f773958bee..85bbac8848 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1372,4 +1372,310 @@ popup_check_cursor_pos() } } +/* + * Update "popup_mask" if needed. + * Also recomputes the popup size and positions. + * Also updates "popup_visible". + * Also marks window lines for redrawing. + */ + void +may_update_popup_mask(int type) +{ + win_T *wp; + short *mask; + int line, col; + int redraw_all = FALSE; + + // Need to recompute when switching tabs. + // Also recompute when the type is CLEAR or NOT_VALID, something basic + // (such as the screen size) must have changed. + if (popup_mask_tab != curtab || type >= NOT_VALID) + { + popup_mask_refresh = TRUE; + redraw_all = TRUE; + } + if (!popup_mask_refresh) + { + // Check if any buffer has changed. + for (wp = first_popupwin; wp != NULL; wp = wp->w_next) + if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) + popup_mask_refresh = TRUE; + for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next) + if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) + popup_mask_refresh = TRUE; + if (!popup_mask_refresh) + return; + } + + // Need to update the mask, something has changed. + popup_mask_refresh = FALSE; + popup_mask_tab = curtab; + popup_visible = FALSE; + + // If redrawing everything, just update "popup_mask". + // If redrawing only what is needed, update "popup_mask_next" and then + // compare with "popup_mask" to see what changed. + if (type >= SOME_VALID) + mask = popup_mask; + else + mask = popup_mask_next; + vim_memset(mask, 0, screen_Rows * screen_Columns * sizeof(short)); + + // Find the window with the lowest zindex that hasn't been handled yet, + // so that the window with a higher zindex overwrites the value in + // popup_mask. + popup_reset_handled(); + while ((wp = find_next_popup(TRUE)) != NULL) + { + popup_visible = TRUE; + + // Recompute the position if the text changed. + if (redraw_all + || wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) + popup_adjust_position(wp); + + for (line = wp->w_winrow; + line < wp->w_winrow + popup_height(wp) + && line < screen_Rows; ++line) + for (col = wp->w_wincol; + col < wp->w_wincol + popup_width(wp) + && col < screen_Columns; ++col) + mask[line * screen_Columns + col] = wp->w_zindex; + } + + // Only check which lines are to be updated if not already + // updating all lines. + if (mask == popup_mask_next) + for (line = 0; line < screen_Rows; ++line) + { + int col_done = 0; + + for (col = 0; col < screen_Columns; ++col) + { + int off = line * screen_Columns + col; + + if (popup_mask[off] != popup_mask_next[off]) + { + popup_mask[off] = popup_mask_next[off]; + + if (line >= cmdline_row) + { + // the command line needs to be cleared if text below + // the popup is now visible. + if (!msg_scrolled && popup_mask_next[off] == 0) + clear_cmdline = TRUE; + } + else if (col >= col_done) + { + linenr_T lnum; + int line_cp = line; + int col_cp = col; + + // The screen position "line" / "col" needs to be + // redrawn. Figure out what window that is and update + // w_redraw_top and w_redr_bot. Only needs to be done + // once for each window line. + wp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP); + if (wp != NULL) + { + if (line_cp >= wp->w_height) + // In (or below) status line + wp->w_redr_status = TRUE; + // compute the position in the buffer line from the + // position on the screen + else if (mouse_comp_pos(wp, &line_cp, &col_cp, + &lnum)) + // past bottom + wp->w_redr_status = TRUE; + else + redrawWinline(wp, lnum); + + // This line is going to be redrawn, no need to + // check until the right side of the window. + col_done = wp->w_wincol + wp->w_width - 1; + } + } + } + } + } +} + +/* + * Return a string of "len" spaces in IObuff. + */ + static char_u * +get_spaces(int len) +{ + vim_memset(IObuff, ' ', (size_t)len); + IObuff[len] = NUL; + return IObuff; +} + +/* + * Update popup windows. They are drawn on top of normal windows. + * "win_update" is called for each popup window, lowest zindex first. + */ + void +update_popups(void (*win_update)(win_T *wp)) +{ + win_T *wp; + int top_off; + int left_off; + int total_width; + int total_height; + int popup_attr; + int border_attr[4]; + int border_char[8]; + char_u buf[MB_MAXBYTES]; + int row; + int i; + + // Find the window with the lowest zindex that hasn't been updated yet, + // so that the window with a higher zindex is drawn later, thus goes on + // top. + popup_reset_handled(); + while ((wp = find_next_popup(TRUE)) != NULL) + { + // This drawing uses the zindex of the popup window, so that it's on + // top of the text but doesn't draw when another popup with higher + // zindex is on top of the character. + screen_zindex = wp->w_zindex; + + // adjust w_winrow and w_wincol for border and padding, since + // win_update() doesn't handle them. + top_off = wp->w_popup_padding[0] + wp->w_popup_border[0]; + left_off = wp->w_popup_padding[3] + wp->w_popup_border[3]; + wp->w_winrow += top_off; + wp->w_wincol += left_off; + + // Draw the popup text. + win_update(wp); + + wp->w_winrow -= top_off; + wp->w_wincol -= left_off; + + total_width = wp->w_popup_border[3] + wp->w_popup_padding[3] + + wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1]; + total_height = wp->w_popup_border[0] + wp->w_popup_padding[0] + + wp->w_height + wp->w_popup_padding[2] + wp->w_popup_border[2]; + popup_attr = get_wcr_attr(wp); + + // We can only use these line drawing characters when 'encoding' is + // "utf-8" and 'ambiwidth' is "single". + if (enc_utf8 && *p_ambw == 's') + { + border_char[0] = border_char[2] = 0x2550; + border_char[1] = border_char[3] = 0x2551; + border_char[4] = 0x2554; + border_char[5] = 0x2557; + border_char[6] = 0x255d; + border_char[7] = 0x255a; + } + else + { + border_char[0] = border_char[2] = '-'; + border_char[1] = border_char[3] = '|'; + for (i = 4; i < 8; ++i) + border_char[i] = '+'; + } + for (i = 0; i < 8; ++i) + if (wp->w_border_char[i] != 0) + border_char[i] = wp->w_border_char[i]; + + for (i = 0; i < 4; ++i) + { + border_attr[i] = popup_attr; + if (wp->w_border_highlight[i] != NULL) + border_attr[i] = syn_name2attr(wp->w_border_highlight[i]); + } + + if (wp->w_popup_border[0] > 0) + { + // top border + screen_fill(wp->w_winrow, wp->w_winrow + 1, + wp->w_wincol, + wp->w_wincol + total_width, + wp->w_popup_border[3] != 0 + ? border_char[4] : border_char[0], + border_char[0], border_attr[0]); + if (wp->w_popup_border[1] > 0) + { + buf[mb_char2bytes(border_char[5], buf)] = NUL; + screen_puts(buf, wp->w_winrow, + wp->w_wincol + total_width - 1, border_attr[1]); + } + } + + if (wp->w_popup_padding[0] > 0) + { + // top padding + row = wp->w_winrow + wp->w_popup_border[0]; + screen_fill(row, row + wp->w_popup_padding[0], + wp->w_wincol + wp->w_popup_border[3], + wp->w_wincol + total_width - wp->w_popup_border[1], + ' ', ' ', popup_attr); + } + + for (row = wp->w_winrow + wp->w_popup_border[0]; + row < wp->w_winrow + total_height - wp->w_popup_border[2]; + ++row) + { + // left border + if (wp->w_popup_border[3] > 0) + { + buf[mb_char2bytes(border_char[3], buf)] = NUL; + screen_puts(buf, row, wp->w_wincol, border_attr[3]); + } + // left padding + if (wp->w_popup_padding[3] > 0) + screen_puts(get_spaces(wp->w_popup_padding[3]), row, + wp->w_wincol + wp->w_popup_border[3], popup_attr); + // right border + if (wp->w_popup_border[1] > 0) + { + buf[mb_char2bytes(border_char[1], buf)] = NUL; + screen_puts(buf, row, + wp->w_wincol + total_width - 1, border_attr[1]); + } + // right padding + if (wp->w_popup_padding[1] > 0) + screen_puts(get_spaces(wp->w_popup_padding[1]), row, + wp->w_wincol + wp->w_popup_border[3] + + wp->w_popup_padding[3] + wp->w_width, popup_attr); + } + + if (wp->w_popup_padding[2] > 0) + { + // bottom padding + row = wp->w_winrow + wp->w_popup_border[0] + + wp->w_popup_padding[0] + wp->w_height; + screen_fill(row, row + wp->w_popup_padding[2], + wp->w_wincol + wp->w_popup_border[3], + wp->w_wincol + total_width - wp->w_popup_border[1], + ' ', ' ', popup_attr); + } + + if (wp->w_popup_border[2] > 0) + { + // bottom border + row = wp->w_winrow + total_height - 1; + screen_fill(row , row + 1, + wp->w_wincol, + wp->w_wincol + total_width, + wp->w_popup_border[3] != 0 + ? border_char[7] : border_char[2], + border_char[2], border_attr[2]); + if (wp->w_popup_border[1] > 0) + { + buf[mb_char2bytes(border_char[6], buf)] = NUL; + screen_puts(buf, row, + wp->w_wincol + total_width - 1, border_attr[2]); + } + } + + // Back to the normal zindex. + screen_zindex = 0; + } +} + #endif // FEAT_TEXT_PROP diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index eeabafa9a6..0b9dc42560 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -24,4 +24,6 @@ void popup_reset_handled(void); win_T *find_next_popup(int lowest); int popup_do_filter(int c); void popup_check_cursor_pos(void); +void may_update_popup_mask(int type); +void update_popups(void (*win_update)(win_T *wp)); /* vim: set ft=c : */ diff --git a/src/proto/screen.pro b/src/proto/screen.pro index ab73e0ba9b..0aaed5fbe6 100644 --- a/src/proto/screen.pro +++ b/src/proto/screen.pro @@ -16,6 +16,7 @@ int update_screen(int type_arg); int conceal_cursor_line(win_T *wp); void conceal_check_cursor_line(void); void update_debug_sign(buf_T *buf, linenr_T lnum); +int get_wcr_attr(win_T *wp); void updateWindow(win_T *wp); int screen_get_current_line_off(void); void screen_line(int row, int coloff, int endcol, int clear_width, int flags); diff --git a/src/screen.c b/src/screen.c index 7248ca221c..8708fd7c21 100644 --- a/src/screen.c +++ b/src/screen.c @@ -121,10 +121,6 @@ static int redrawing_for_callback = 0; */ static schar_T *current_ScreenLine; -#ifdef FEAT_TEXT_PROP -static void may_update_popup_mask(int type); -static void update_popups(void); -#endif static void win_update(win_T *wp); static void win_redr_status(win_T *wp, int ignore_pum); static void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl); @@ -826,7 +822,7 @@ update_screen(int type_arg) #ifdef FEAT_TEXT_PROP // Display popup windows on top of the windows. - update_popups(); + update_popups(win_update); #endif #ifdef FEAT_GUI @@ -1001,7 +997,7 @@ update_debug_sign(buf_T *buf, linenr_T lnum) * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup * window then get the "Pmenu" highlight attribute. */ - static int + int get_wcr_attr(win_T *wp) { int wcr_attr = 0; @@ -1015,305 +1011,6 @@ get_wcr_attr(win_T *wp) return wcr_attr; } -#ifdef FEAT_TEXT_PROP - -/* - * Update "popup_mask" if needed. - * Also recomputes the popup size and positions. - * Also updates "popup_visible". - * Also marks window lines for redrawing. - */ - static void -may_update_popup_mask(int type) -{ - win_T *wp; - short *mask; - int line, col; - int redraw_all = FALSE; - - // Need to recompute when switching tabs. - // Also recompute when the type is CLEAR or NOT_VALID, something basic - // (such as the screen size) must have changed. - if (popup_mask_tab != curtab || type >= NOT_VALID) - { - popup_mask_refresh = TRUE; - redraw_all = TRUE; - } - if (!popup_mask_refresh) - { - // Check if any buffer has changed. - for (wp = first_popupwin; wp != NULL; wp = wp->w_next) - if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) - popup_mask_refresh = TRUE; - for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next) - if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) - popup_mask_refresh = TRUE; - if (!popup_mask_refresh) - return; - } - - // Need to update the mask, something has changed. - popup_mask_refresh = FALSE; - popup_mask_tab = curtab; - popup_visible = FALSE; - - // If redrawing everything, just update "popup_mask". - // If redrawing only what is needed, update "popup_mask_next" and then - // compare with "popup_mask" to see what changed. - if (type >= SOME_VALID) - mask = popup_mask; - else - mask = popup_mask_next; - vim_memset(mask, 0, screen_Rows * screen_Columns * sizeof(short)); - - // Find the window with the lowest zindex that hasn't been handled yet, - // so that the window with a higher zindex overwrites the value in - // popup_mask. - popup_reset_handled(); - while ((wp = find_next_popup(TRUE)) != NULL) - { - popup_visible = TRUE; - - // Recompute the position if the text changed. - if (redraw_all - || wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) - popup_adjust_position(wp); - - for (line = wp->w_winrow; - line < wp->w_winrow + popup_height(wp) - && line < screen_Rows; ++line) - for (col = wp->w_wincol; - col < wp->w_wincol + popup_width(wp) - && col < screen_Columns; ++col) - mask[line * screen_Columns + col] = wp->w_zindex; - } - - // Only check which lines are to be updated if not already - // updating all lines. - if (mask == popup_mask_next) - for (line = 0; line < screen_Rows; ++line) - { - int col_done = 0; - - for (col = 0; col < screen_Columns; ++col) - { - int off = line * screen_Columns + col; - - if (popup_mask[off] != popup_mask_next[off]) - { - popup_mask[off] = popup_mask_next[off]; - - // The screen position "line" / "col" needs to be redrawn. - // Figure out what window that is and update w_redraw_top - // and w_redr_bot. Only needs to be done for each window - // line. - if (col >= col_done) - { - linenr_T lnum; - int line_cp = line; - int col_cp = col; - - // find the window where the row is in - wp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP); - if (wp != NULL) - { - if (line_cp >= wp->w_height) - // In (or below) status line - wp->w_redr_status = TRUE; - // compute the position in the buffer line from the - // position on the screen - else if (mouse_comp_pos(wp, &line_cp, &col_cp, - &lnum)) - // past bottom - wp->w_redr_status = TRUE; - else - redrawWinline(wp, lnum); - - // This line is going to be redrawn, no need to - // check until the right side of the window. - col_done = wp->w_wincol + wp->w_width - 1; - } - } - } - } - } -} - -/* - * Return a string of "len" spaces in IObuff. - */ - static char_u * -get_spaces(int len) -{ - vim_memset(IObuff, ' ', (size_t)len); - IObuff[len] = NUL; - return IObuff; -} - - static void -update_popups(void) -{ - win_T *wp; - int top_off; - int left_off; - int total_width; - int total_height; - int popup_attr; - int border_attr[4]; - int border_char[8]; - char_u buf[MB_MAXBYTES]; - int row; - int i; - - // Find the window with the lowest zindex that hasn't been updated yet, - // so that the window with a higher zindex is drawn later, thus goes on - // top. - popup_reset_handled(); - while ((wp = find_next_popup(TRUE)) != NULL) - { - // This drawing uses the zindex of the popup window, so that it's on - // top of the text but doesn't draw when another popup with higher - // zindex is on top of the character. - screen_zindex = wp->w_zindex; - - // adjust w_winrow and w_wincol for border and padding, since - // win_update() doesn't handle them. - top_off = wp->w_popup_padding[0] + wp->w_popup_border[0]; - left_off = wp->w_popup_padding[3] + wp->w_popup_border[3]; - wp->w_winrow += top_off; - wp->w_wincol += left_off; - - // Draw the popup text. - win_update(wp); - - wp->w_winrow -= top_off; - wp->w_wincol -= left_off; - - total_width = wp->w_popup_border[3] + wp->w_popup_padding[3] - + wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1]; - total_height = wp->w_popup_border[0] + wp->w_popup_padding[0] - + wp->w_height + wp->w_popup_padding[2] + wp->w_popup_border[2]; - popup_attr = get_wcr_attr(wp); - - // We can only use these line drawing characters when 'encoding' is - // "utf-8" and 'ambiwidth' is "single". - if (enc_utf8 && *p_ambw == 's') - { - border_char[0] = border_char[2] = 0x2550; - border_char[1] = border_char[3] = 0x2551; - border_char[4] = 0x2554; - border_char[5] = 0x2557; - border_char[6] = 0x255d; - border_char[7] = 0x255a; - } - else - { - border_char[0] = border_char[2] = '-'; - border_char[1] = border_char[3] = '|'; - for (i = 4; i < 8; ++i) - border_char[i] = '+'; - } - for (i = 0; i < 8; ++i) - if (wp->w_border_char[i] != 0) - border_char[i] = wp->w_border_char[i]; - - for (i = 0; i < 4; ++i) - { - border_attr[i] = popup_attr; - if (wp->w_border_highlight[i] != NULL) - border_attr[i] = syn_name2attr(wp->w_border_highlight[i]); - } - - if (wp->w_popup_border[0] > 0) - { - // top border - screen_fill(wp->w_winrow, wp->w_winrow + 1, - wp->w_wincol, - wp->w_wincol + total_width, - wp->w_popup_border[3] != 0 - ? border_char[4] : border_char[0], - border_char[0], border_attr[0]); - if (wp->w_popup_border[1] > 0) - { - buf[mb_char2bytes(border_char[5], buf)] = NUL; - screen_puts(buf, wp->w_winrow, - wp->w_wincol + total_width - 1, border_attr[1]); - } - } - - if (wp->w_popup_padding[0] > 0) - { - // top padding - row = wp->w_winrow + wp->w_popup_border[0]; - screen_fill(row, row + wp->w_popup_padding[0], - wp->w_wincol + wp->w_popup_border[3], - wp->w_wincol + total_width - wp->w_popup_border[1], - ' ', ' ', popup_attr); - } - - for (row = wp->w_winrow + wp->w_popup_border[0]; - row < wp->w_winrow + total_height - wp->w_popup_border[2]; - ++row) - { - // left border - if (wp->w_popup_border[3] > 0) - { - buf[mb_char2bytes(border_char[3], buf)] = NUL; - screen_puts(buf, row, wp->w_wincol, border_attr[3]); - } - // left padding - if (wp->w_popup_padding[3] > 0) - screen_puts(get_spaces(wp->w_popup_padding[3]), row, - wp->w_wincol + wp->w_popup_border[3], popup_attr); - // right border - if (wp->w_popup_border[1] > 0) - { - buf[mb_char2bytes(border_char[1], buf)] = NUL; - screen_puts(buf, row, - wp->w_wincol + total_width - 1, border_attr[1]); - } - // right padding - if (wp->w_popup_padding[1] > 0) - screen_puts(get_spaces(wp->w_popup_padding[1]), row, - wp->w_wincol + wp->w_popup_border[3] - + wp->w_popup_padding[3] + wp->w_width, popup_attr); - } - - if (wp->w_popup_padding[2] > 0) - { - // bottom padding - row = wp->w_winrow + wp->w_popup_border[0] - + wp->w_popup_padding[0] + wp->w_height; - screen_fill(row, row + wp->w_popup_padding[2], - wp->w_wincol + wp->w_popup_border[3], - wp->w_wincol + total_width - wp->w_popup_border[1], - ' ', ' ', popup_attr); - } - - if (wp->w_popup_border[2] > 0) - { - // bottom border - row = wp->w_winrow + total_height - 1; - screen_fill(row , row + 1, - wp->w_wincol, - wp->w_wincol + total_width, - wp->w_popup_border[3] != 0 - ? border_char[7] : border_char[2], - border_char[2], border_attr[2]); - if (wp->w_popup_border[1] > 0) - { - buf[mb_char2bytes(border_char[6], buf)] = NUL; - screen_puts(buf, row, - wp->w_wincol + total_width - 1, border_attr[2]); - } - } - - // Back to the normal zindex. - screen_zindex = 0; - } -} -#endif - #if defined(FEAT_GUI) || defined(PROTO) /* * Update a single window, its status line and maybe the command line msg. @@ -1354,7 +1051,7 @@ updateWindow(win_T *wp) #ifdef FEAT_TEXT_PROP // Display popup windows on top of everything. - update_popups(); + update_popups(win_update); #endif update_finish(); diff --git a/src/testdir/dumps/Test_popupwin_drag_01.dump b/src/testdir/dumps/Test_popupwin_drag_01.dump new file mode 100644 index 0000000000..e47fbc4fa3 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_drag_01.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @73 +|3| @73 +|4| @73 +|5| @73 +|6| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@32 +|7| @32|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@32 +|8| @32|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@32 +|9| @32|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@32 +@34|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@14|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_drag_02.dump b/src/testdir/dumps/Test_popupwin_drag_02.dump new file mode 100644 index 0000000000..7e8c30ee6d --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_drag_02.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@32 +|3| @32|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@32 +|4| @32|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@32 +|5| @32|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@32 +|6| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@32 +|7| @73 +|8| @73 +|9| @73 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 6def8e45a9..c084c7ccf1 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -289,6 +289,36 @@ func Test_popup_firstline() call delete('XtestPopupFirstline') endfunc +func Test_popup_drag() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + " create a popup that covers the command line + let lines =<< trim END + call setline(1, range(1, 20)) + let winid = popup_create(['1111', '222222', '33333'], { + \ 'drag': 1, + \ 'border': [], + \ 'line': &lines - 4, + \ }) + func Dragit() + call feedkeys("\\\\\", "xt") + endfunc + map :call test_setmouse(&lines - 4, &columns / 2) + map :call test_setmouse(&lines - 8, &columns / 2) + END + call writefile(lines, 'XtestPopupDrag') + let buf = RunVimInTerminal('-S XtestPopupDrag', {'rows': 10}) + call VerifyScreenDump(buf, 'Test_popupwin_drag_01', {}) + + call term_sendkeys(buf, ":call Dragit()\") + call VerifyScreenDump(buf, 'Test_popupwin_drag_02', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupDrag') +endfunc + func Test_popup_in_tab() " default popup is local to tab, not visible when in other tab let winid = popup_create("text", {}) diff --git a/src/version.c b/src/version.c index 8a9885c399..1356fda348 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 */ +/**/ + 1527, /**/ 1526, /**/ From b4086ffa32d97831f2d25a37f8c1340223dee5eb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 20:00:48 +0200 Subject: [PATCH 11/44] patch 8.1.1528: popup_any_visible() is unused Problem: Popup_any_visible() is unused. Solution: Remove it. --- src/popupwin.c | 17 ----------------- src/proto/popupwin.pro | 1 - src/version.c | 2 ++ 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 85bbac8848..5265b4b9b3 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -933,23 +933,6 @@ find_popup_win(int id) return wp; } -/* - * Return TRUE if there any popups that are not hidden. - */ - int -popup_any_visible(void) -{ - win_T *wp; - - for (wp = first_popupwin; wp != NULL; wp = wp->w_next) - if ((wp->w_popup_flags & POPF_HIDDEN) == 0) - return TRUE; - for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next) - if ((wp->w_popup_flags & POPF_HIDDEN) == 0) - return TRUE; - return FALSE; -} - /* * Invoke the close callback for window "wp" with value "result". * Careful: The callback may make "wp" invalid! diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 0b9dc42560..cde0cae6e8 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -9,7 +9,6 @@ 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); void f_popup_notification(typval_T *argvars, typval_T *rettv); -int popup_any_visible(void); void f_popup_close(typval_T *argvars, typval_T *rettv); void f_popup_hide(typval_T *argvars, typval_T *rettv); void f_popup_show(typval_T *argvars, typval_T *rettv); diff --git a/src/version.c b/src/version.c index 1356fda348..aa3986dbbb 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 */ +/**/ + 1528, /**/ 1527, /**/ From 21606676d9ebc6f159c56ee90733e5d5720ab3d7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 20:40:58 +0200 Subject: [PATCH 12/44] patch 8.1.1529: libcanberra is linked with even when not used Problem: Libcanberra is linked with even when not used. Solution: Have configure check for libcanberra only when wanted. (suggestions by Libor Bukata) --- src/Makefile | 7 ++++- src/auto/configure | 67 +++++++++++++++++++++++++++++----------------- src/configure.ac | 53 +++++++++++++++++++++++------------- src/feature.h | 2 +- src/version.c | 2 ++ 5 files changed, 87 insertions(+), 44 deletions(-) diff --git a/src/Makefile b/src/Makefile index eef91ece2f..9c4a42893b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -528,6 +528,11 @@ CClink = $(CC) # though you have /dev/sysmouse and includes. #CONF_OPT_SYSMOUSE = --disable-sysmouse +# libcanberra - For sound support. Default is on for big features. +# Uncomment one of the two to chose otherwise. +# CONF_OPT_CANBERRA = --enable-canberra +# CONF_OPT_CANBERRA = --disable-canberra + # FEATURES - For creating Vim with more or less features # Uncomment one of these lines when you want to include few to many features. # The default is "huge" for most systems. @@ -1952,7 +1957,7 @@ config auto/config.mk: auto/configure config.mk.in config.h.in $(CONF_ARGS4) $(CONF_ARGS5) $(CONF_ARGS6) \ $(CONF_OPT_MZSCHEME) $(CONF_OPT_PLTHOME) \ $(CONF_OPT_LUA) $(CONF_OPT_LUA_PREFIX) \ - $(CONF_OPT_SYSMOUSE); \ + $(CONF_OPT_SYSMOUSE) $(CONF_OPT_CANBERRA); \ fi # Use "make reconfig" to rerun configure without cached values. diff --git a/src/auto/configure b/src/auto/configure index d5b4f6053e..c326abf16c 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -840,6 +840,7 @@ enable_desktop_database_update with_motif_lib with_tlib enable_largefile +enable_canberra enable_acl enable_gpm enable_sysmouse @@ -1515,6 +1516,7 @@ Optional Features: --disable-icon-cache-update update disabled --disable-desktop-database-update update disabled --disable-largefile omit support for large files + --disable-canberra Do not use libcanberra. --disable-acl No check for ACL support. --disable-gpm Don't use gpm (Linux mouse daemon). --disable-sysmouse Don't use sysmouse (mouse in *BSD console). @@ -12925,40 +12927,56 @@ rm -rf conftest* fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-canberra argument" >&5 +$as_echo_n "checking --enable-canberra argument... " >&6; } +# Check whether --enable-canberra was given. +if test "${enable_canberra+set}" = set; then : + enableval=$enable_canberra; +else + enable_canberra="maybe" +fi -if test "x$PKG_CONFIG" != "xno"; then - canberra_lib=`$PKG_CONFIG --libs libcanberrax 2>/dev/null` - canberra_cflags=`$PKG_CONFIG --cflags libcanberrax 2>/dev/null` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_lib: $canberra_lib" >&5 -$as_echo "canberra_lib: $canberra_lib" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_cflags: $canberra_cflags" >&5 -$as_echo "canberra_cflags: $canberra_cflags" >&6; } + +if test "$enable_canberra" = "maybe"; then + if test "$features" = "big" -o "$features" = "huge"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to yes" >&5 +$as_echo "Defaulting to yes" >&6; } + enable_canberra="yes" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to no" >&5 +$as_echo "Defaulting to no" >&6; } + enable_canberra="no" + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_canberra" >&5 +$as_echo "$enable_canberra" >&6; } fi -if test "x$canberra_lib" = "x"; then - canberra_lib=-lcanberra - canberra_cflags=-D_REENTRANT -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_lib: $canberra_lib" >&5 -$as_echo "canberra_lib: $canberra_lib" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_cflags: $canberra_cflags" >&5 -$as_echo "canberra_cflags: $canberra_cflags" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcanberra" >&5 +if test "$enable_canberra" = "yes"; then + if test "x$PKG_CONFIG" != "xno"; then + canberra_lib=`$PKG_CONFIG --libs libcanberra 2>/dev/null` + canberra_cflags=`$PKG_CONFIG --cflags libcanberra 2>/dev/null` + fi + if test "x$canberra_lib" = "x"; then + canberra_lib=-lcanberra + canberra_cflags=-D_REENTRANT + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcanberra" >&5 $as_echo_n "checking for libcanberra... " >&6; } -ac_save_CFLAGS="$CFLAGS" -ac_save_LIBS="$LIBS" -CFLAGS="$CFLAGS $canberra_cflags" -LIBS="$LIBS $canberra_lib" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $canberra_cflags" + LIBS="$LIBS $canberra_lib" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -# include + # include int main () { - ca_context *hello; - ca_context_create(&hello); + ca_context *hello; + ca_context_create(&hello); ; return 0; } @@ -12973,6 +12991,7 @@ $as_echo "no" >&6; }; CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for st_blksize" >&5 diff --git a/src/configure.ac b/src/configure.ac index 7e821e63b5..dbf4f42b86 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -3751,27 +3751,44 @@ dnl define _LARGE_FILES, _FILE_OFFSET_BITS and _LARGEFILE_SOURCE when dnl appropriate, so that off_t is 64 bits when needed. AC_SYS_LARGEFILE +AC_MSG_CHECKING(--enable-canberra argument) +AC_ARG_ENABLE(canberra, + [ --disable-canberra Do not use libcanberra.], + , [enable_canberra="maybe"]) -if test "x$PKG_CONFIG" != "xno"; then - canberra_lib=`$PKG_CONFIG --libs libcanberra 2>/dev/null` - canberra_cflags=`$PKG_CONFIG --cflags libcanberra 2>/dev/null` +if test "$enable_canberra" = "maybe"; then + if test "$features" = "big" -o "$features" = "huge"; then + AC_MSG_RESULT(Defaulting to yes) + enable_canberra="yes" + else + AC_MSG_RESULT(Defaulting to no) + enable_canberra="no" + fi +else + AC_MSG_RESULT($enable_canberra) fi -if test "x$canberra_lib" = "x"; then - canberra_lib=-lcanberra - canberra_cflags=-D_REENTRANT +if test "$enable_canberra" = "yes"; then + if test "x$PKG_CONFIG" != "xno"; then + canberra_lib=`$PKG_CONFIG --libs libcanberra 2>/dev/null` + canberra_cflags=`$PKG_CONFIG --cflags libcanberra 2>/dev/null` + fi + if test "x$canberra_lib" = "x"; then + canberra_lib=-lcanberra + canberra_cflags=-D_REENTRANT + fi + AC_MSG_CHECKING(for libcanberra) + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $canberra_cflags" + LIBS="$LIBS $canberra_lib" + AC_TRY_LINK([ + # include + ], [ + ca_context *hello; + ca_context_create(&hello);], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_CANBERRA), + AC_MSG_RESULT(no); CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS") fi -AC_MSG_CHECKING(for libcanberra) -ac_save_CFLAGS="$CFLAGS" -ac_save_LIBS="$LIBS" -CFLAGS="$CFLAGS $canberra_cflags" -LIBS="$LIBS $canberra_lib" -AC_TRY_LINK([ -# include - ], [ - ca_context *hello; - ca_context_create(&hello);], - AC_MSG_RESULT(yes); AC_DEFINE(HAVE_CANBERRA), - AC_MSG_RESULT(no); CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS") dnl fstatfs() can take 2 to 4 arguments, try to use st_blksize if possible diff --git a/src/feature.h b/src/feature.h index c5d7d777e6..eb474ab07e 100644 --- a/src/feature.h +++ b/src/feature.h @@ -663,7 +663,7 @@ /* * sound - currently only with libcanberra */ -#if !defined(FEAT_SOUND) && defined(FEAT_BIG) && defined(HAVE_CANBERRA) +#if !defined(FEAT_SOUND) && defined(HAVE_CANBERRA) # define FEAT_SOUND #endif diff --git a/src/version.c b/src/version.c index aa3986dbbb..44ce639035 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 */ +/**/ + 1529, /**/ 1528, /**/ From f42397c395ec8ff2dffef914805b4d9cbf1d600b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 20:47:49 +0200 Subject: [PATCH 13/44] patch 8.1.1530: Travis config is not optimal Problem: Travis config is not optimal. Solution: Remove system conditions. Do not use excluding matrix. Cache OSX results. (Ozaki Kiichi, closes #4521) --- .travis.yml | 311 +++++++++++++++++++++++++++----------------------- src/version.c | 2 + 2 files changed, 173 insertions(+), 140 deletions(-) diff --git a/.travis.yml b/.travis.yml index 407ee725b4..8e122404f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,138 +1,113 @@ language: c -dist: trusty -os: - - osx - - linux +anchors: + envs: + - &tiny-nogui + BUILD=yes TEST=test COVERAGE=no FEATURES=tiny "CONFOPT='--disable-gui'" SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no + - &tiny + BUILD=yes TEST=test COVERAGE=no FEATURES=tiny CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no + - &small + BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no + - &normal + BUILD=yes TEST=test COVERAGE=no FEATURES=normal CONFOPT= SHADOWOPT="-C src/shadow" SRCDIR=./src/shadow CHECK_AUTOCONF=no + - &linux-huge + BUILD=yes TEST="scripttests test_libvterm" COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" + - &osx-huge # macOS build + BUILD=yes TEST=test COVERAGE=no FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" + - &unittests + BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes + - &asan # ASAN build + SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer" + ASAN_OPTIONS="print_stacktrace=1 log_path=asan" LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/src/testdir/lsan-suppress.txt" -compiler: - - clang - - gcc + linux: &linux + os: linux + dist: trusty + addons: + apt: + sources: + # Need msgfmt 0.19.8 to be able to generate .desktop files + - sourceline: 'ppa:ricotz/toolchain' + packages: + - autoconf + - clang + - lcov + - gettext + - libcanberra-dev + - libperl-dev + - python-dev + - python3-dev + - liblua5.2-dev + - lua5.2 + - ruby-dev + - tcl-dev + - cscope + - libgtk2.0-dev + - desktop-file-utils + before_install: + - rvm reset + # Remove /opt/python/3.x.x/bin from $PATH for using system python3. + # ("pyenv global system" doesn't seem to work.) + - | + if [[ "$(which python3)" =~ ^/opt/python/ ]]; then + export PATH=$(py3=$(which python3); echo ${PATH//${py3%/python3}:/}) + fi + - | + if [[ "${COVERAGE}" = "yes" ]]; then + pip install --user cpp-coveralls + fi + # needed for https support for coveralls + # building cffi only works with gcc, not with clang + - | + if [[ "${COVERAGE}" = "yes" ]]; then + CC=gcc pip install --user pyopenssl ndg-httpsclient pyasn1 + fi + # Use llvm-cov instead of gcov when compiler is clang. + - | + if [[ "${CC}" = "clang" ]]; then + ln -sf "$(which llvm-cov)" /home/travis/bin/gcov + fi + before_script: + # Start virtual framebuffer to be able to test the GUI. Does not work on OS X. + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start && sleep 3 + - sudo modprobe snd-dummy + - sudo usermod -a -G audio $USER -env: - - &tiny-nogui - BUILD=yes TEST=test COVERAGE=no FEATURES=tiny "CONFOPT='--disable-gui'" SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - - &tiny - BUILD=yes TEST=test COVERAGE=no FEATURES=tiny CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - - &asan # ASAN build - BUILD=yes TEST=test SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer" - FEATURES=huge SRCDIR=./src CHECK_AUTOCONF=no ASAN_OPTIONS="print_stacktrace=1 log_path=asan" LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/src/testdir/lsan-suppress.txt" - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" - - &linux-huge - BUILD=yes TEST="scripttests test_libvterm" COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" - - &unittests - BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes - - &normal - BUILD=yes TEST=test COVERAGE=no FEATURES=normal CONFOPT= SHADOWOPT="-C src/shadow" SRCDIR=./src/shadow CHECK_AUTOCONF=no - - &small - BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - - &osx-huge # Mac OSX build - BUILD=yes TEST=test COVERAGE=no FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" + osx: &osx + os: osx + addons: + homebrew: + packages: + - lua + update: true + cache: + directories: + - /usr/local/Homebrew/Library/Homebrew/vendor/ + - /usr/local/Homebrew/Library/Taps/ + before_install: + - rvm reset + # Lua is not installed on Travis OSX + - export LUA_PREFIX=/usr/local + + coverage: &coverage + - ~/.local/bin/coveralls -b "${SRCDIR}" -x .xs -e "${SRCDIR}"/if_perl.c -e "${SRCDIR}"/xxd -e "${SRCDIR}"/libvterm --encodings utf-8 latin-1 EUC-KR + - (cd "${SRCDIR}" && bash <(curl -s https://codecov.io/bash)) + + asan_symbolize: &asan_symbolize + - | + while read log; do + asan_symbolize < "${log}" + done < <(find . -type f -name 'asan.*' -size +0) sudo: false -# instead of a 2*2*8 matrix (2*os + 2*compiler + 8*env), -# exclude some builds on mac os x and linux -# on mac os x "tiny" is always without GUI -# linux: 2*compiler + 5*env + mac: 2*compiler + 2*env -matrix: - exclude: - - os: osx - env: *tiny - - os: osx - env: *normal - - os: osx - env: *unittests - - os: osx - env: *small - - os: osx - env: *linux-huge - - os: osx - env: *asan - - os: linux - compiler: clang - env: *asan - - os: linux - compiler: clang - env: *unittests - - os: linux - compiler: clang - env: *small - - os: linux - env: *osx-huge - branches: except: - /^v[0-9]/ -addons: - apt: - sources: - # Need msgfmt 0.19.8 to be able to generate .desktop files - - sourceline: 'ppa:ricotz/toolchain' - packages: - - autoconf - - clang - - lcov - - gettext - - libcanberra-dev - - libperl-dev - - python-dev - - python3-dev - - liblua5.2-dev - - lua5.2 - - ruby-dev - - tcl-dev - - cscope - - libgtk2.0-dev - - desktop-file-utils - homebrew: - packages: - - lua - update: true - -before_install: - - rvm reset - # Remove /opt/python/3.x.x/bin from $PATH for using system python3. - # ("pyenv global system" doesn't seem to work.) - - | - if [[ "${TRAVIS_OS_NAME}" = "linux" ]] && [[ "$(which python3)" =~ ^/opt/python/ ]]; then - export PATH=$(py3=$(which python3); echo ${PATH//${py3%/python3}:/}) - fi - - | - if [[ "${COVERAGE}" = "yes" ]]; then - pip install --user cpp-coveralls - fi - # needed for https support for coveralls - # building cffi only works with gcc, not with clang - - | - if [[ "${COVERAGE}" = "yes" ]]; then - CC=gcc pip install --user pyopenssl ndg-httpsclient pyasn1 - fi - # Lua is not installed on Travis OSX - - | - if [[ "${TRAVIS_OS_NAME}" = "osx" ]]; then - export LUA_PREFIX=/usr/local - fi - # Use llvm-cov instead of gcov when compiler is clang. - - | - if [[ "${TRAVIS_OS_NAME}" = "linux" ]] && [[ "${CC}" = "clang" ]]; then - ln -sf "$(which llvm-cov)" /home/travis/bin/gcov - fi - -before_script: - # Start virtual framebuffer to be able to test the GUI. Does not work on OS X. - # Install dummy device for sound. - - | - if [[ "${TRAVIS_OS_NAME}" = "linux" ]]; then - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start && sleep 3 - sudo modprobe snd-dummy - sudo usermod -a -G audio $USER - fi - script: - NPROC=$(getconf _NPROCESSORS_ONLN) - set -o errexit @@ -166,22 +141,78 @@ script: fi - make ${SHADOWOPT} ${TEST} - echo -en "travis_fold:end:test\\r\\033[0K" - - | - if [[ -n "${ASAN_OPTIONS}" ]]; then - while read log; do - asan_symbolize < "${log}" - false # exit 1 if there are ASAN logs - done < <(find . -type f -name 'asan.*' -size +0) - fi -after_success: - - | - if [[ "${COVERAGE}" = "yes" ]]; then - ~/.local/bin/coveralls -b "${SRCDIR}" -x .xs -e "${SRCDIR}"/if_perl.c -e "${SRCDIR}"/xxd -e "${SRCDIR}"/libvterm --encodings utf-8 latin-1 EUC-KR - fi - - | - if [[ "${COVERAGE}" = "yes" ]]; then - (cd "${SRCDIR}" && bash <(curl -s https://codecov.io/bash)) - fi +# instead of a 2*2*8 matrix (2*os + 2*compiler + 8*env), +# exclude some builds on mac os x and linux +# on mac os x "tiny" is always without GUI +# linux: 2*compiler + 5*env + mac: 2*compiler + 2*env +matrix: + include: + - <<: *osx + name: tiny-nogui/clang + compiler: clang + env: *tiny-nogui + - <<: *osx + name: tiny-nogui/gcc + compiler: gcc + env: *tiny-nogui + - <<: *osx + name: huge/clang + compiler: clang + env: *osx-huge + - <<: *osx + name: huge/gcc + compiler: gcc + env: *osx-huge + - <<: *linux + name: tiny-nogui/clang + compiler: clang + env: *tiny-nogui + - <<: *linux + name: tiny-nogui/gcc + compiler: gcc + env: *tiny-nogui + - <<: *linux + name: tiny/clang + compiler: clang + env: *tiny + - <<: *linux + name: tiny/gcc + compiler: gcc + env: *tiny + - <<: *linux + name: small/gcc + compiler: gcc + env: *small + - <<: *linux + name: normal/clang + compiler: clang + env: *normal + - <<: *linux + name: normal/gcc + compiler: gcc + env: *normal + - <<: *linux + name: huge+coverage/clang + compiler: clang + env: *linux-huge + after_success: *coverage + - <<: *linux + name: huge+coverage/gcc + compiler: gcc + env: *linux-huge + after_success: *coverage + - <<: *linux + name: unittests+coverage/gcc + compiler: gcc + env: *unittests + after_success: *coverage + - <<: *linux # ASAN + name: huge+asan/gcc + compiler: gcc + env: + - *linux-huge + - *asan + after_failure: *asan_symbolize # vim:set sts=2 sw=2 tw=0 et: diff --git a/src/version.c b/src/version.c index 44ce639035..510587b11f 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 */ +/**/ + 1530, /**/ 1529, /**/ From 0554fa478d27c611d23a814c987eb66f9daae6f7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 21:36:54 +0200 Subject: [PATCH 14/44] patch 8.1.1531: clipboard type name is inconsistent Problem: Clipboard type name is inconsistent. Solution: Rename VimClipboard to Clipboard_T. --- src/globals.h | 6 ++--- src/gui_gtk_x11.c | 14 +++++----- src/gui_mac.c | 8 +++--- src/gui_x11.c | 8 +++--- src/ops.c | 8 +++--- src/os_qnx.c | 8 +++--- src/os_unix.c | 8 +++--- src/proto.h | 8 +++--- src/proto/gui_gtk_x11.pro | 10 +++---- src/proto/gui_mac.pro | 8 +++--- src/proto/gui_x11.pro | 8 +++--- src/proto/ops.pro | 8 +++--- src/proto/os_qnx.pro | 8 +++--- src/proto/os_unix.pro | 8 +++--- src/proto/ui.pro | 30 ++++++++++----------- src/proto/winclip.pro | 8 +++--- src/ui.c | 55 +++++++++++++++++++-------------------- src/version.c | 2 ++ src/winclip.c | 10 +++---- 19 files changed, 112 insertions(+), 111 deletions(-) diff --git a/src/globals.h b/src/globals.h index 3e61545734..992ce2a543 100644 --- a/src/globals.h +++ b/src/globals.h @@ -545,11 +545,11 @@ EXTERN int gui_win_y INIT(= -1); #endif #ifdef FEAT_CLIPBOARD -EXTERN VimClipboard clip_star; /* PRIMARY selection in X11 */ +EXTERN Clipboard_T clip_star; // PRIMARY selection in X11 # ifdef FEAT_X11 -EXTERN VimClipboard clip_plus; /* CLIPBOARD selection in X11 */ +EXTERN Clipboard_T clip_plus; // CLIPBOARD selection in X11 # else -# define clip_plus clip_star /* there is only one clipboard */ +# define clip_plus clip_star // there is only one clipboard # define ONE_CLIPBOARD # endif diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index a994869a59..509cfc2b50 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -1394,7 +1394,7 @@ selection_received_cb(GtkWidget *widget UNUSED, guint time_ UNUSED, gpointer user_data UNUSED) { - VimClipboard *cbd; + Clipboard_T *cbd; char_u *text; char_u *tmpbuf = NULL; guchar *tmpbuf_utf8 = NULL; @@ -1511,7 +1511,7 @@ selection_get_cb(GtkWidget *widget UNUSED, int length; int motion_type; GdkAtom type; - VimClipboard *cbd; + Clipboard_T *cbd; if (gtk_selection_data_get_selection(selection_data) == clip_plus.gtk_sel_atom) @@ -6602,7 +6602,7 @@ gui_mch_insert_lines(int row, int num_lines) * X Selection stuff, for cutting and pasting text to other windows. */ void -clip_mch_request_selection(VimClipboard *cbd) +clip_mch_request_selection(Clipboard_T *cbd) { GdkAtom target; unsigned i; @@ -6639,7 +6639,7 @@ clip_mch_request_selection(VimClipboard *cbd) * Disown the selection. */ void -clip_mch_lose_selection(VimClipboard *cbd UNUSED) +clip_mch_lose_selection(Clipboard_T *cbd UNUSED) { if (!in_selection_clear_event) { @@ -6652,7 +6652,7 @@ clip_mch_lose_selection(VimClipboard *cbd UNUSED) * Own the selection and return OK if it worked. */ int -clip_mch_own_selection(VimClipboard *cbd) +clip_mch_own_selection(Clipboard_T *cbd) { int success; @@ -6667,13 +6667,13 @@ clip_mch_own_selection(VimClipboard *cbd) * will fill in the selection only when requested by another app. */ void -clip_mch_set_selection(VimClipboard *cbd UNUSED) +clip_mch_set_selection(Clipboard_T *cbd UNUSED) { } #if (defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) || defined(PROTO) int -clip_gtk_owner_exists(VimClipboard *cbd) +clip_gtk_owner_exists(Clipboard_T *cbd) { return gdk_selection_owner_get(cbd->gtk_sel_atom) != NULL; } diff --git a/src/gui_mac.c b/src/gui_mac.c index bb0aa9d870..b43ed8506f 100644 --- a/src/gui_mac.c +++ b/src/gui_mac.c @@ -4434,7 +4434,7 @@ gui_mch_insert_lines(int row, int num_lines) */ void -clip_mch_request_selection(VimClipboard *cbd) +clip_mch_request_selection(Clipboard_T *cbd) { Handle textOfClip; @@ -4524,7 +4524,7 @@ clip_mch_request_selection(VimClipboard *cbd) } void -clip_mch_lose_selection(VimClipboard *cbd) +clip_mch_lose_selection(Clipboard_T *cbd) { /* * TODO: Really nothing to do? @@ -4532,7 +4532,7 @@ clip_mch_lose_selection(VimClipboard *cbd) } int -clip_mch_own_selection(VimClipboard *cbd) +clip_mch_own_selection(Clipboard_T *cbd) { return OK; } @@ -4541,7 +4541,7 @@ clip_mch_own_selection(VimClipboard *cbd) * Send the current selection to the clipboard. */ void -clip_mch_set_selection(VimClipboard *cbd) +clip_mch_set_selection(Clipboard_T *cbd) { Handle textOfClip; long scrapSize; diff --git a/src/gui_x11.c b/src/gui_x11.c index edf69dd40f..3555ffae09 100644 --- a/src/gui_x11.c +++ b/src/gui_x11.c @@ -2872,26 +2872,26 @@ gui_x11_check_copy_area(void) */ void -clip_mch_lose_selection(VimClipboard *cbd) +clip_mch_lose_selection(Clipboard_T *cbd) { clip_x11_lose_selection(vimShell, cbd); } int -clip_mch_own_selection(VimClipboard *cbd) +clip_mch_own_selection(Clipboard_T *cbd) { return clip_x11_own_selection(vimShell, cbd); } void -clip_mch_request_selection(VimClipboard *cbd) +clip_mch_request_selection(Clipboard_T *cbd) { clip_x11_request_selection(vimShell, gui.dpy, cbd); } void clip_mch_set_selection( - VimClipboard *cbd) + Clipboard_T *cbd) { clip_x11_set_selection(cbd); } diff --git a/src/ops.c b/src/ops.c index f5dad6dfde..826a03cb50 100644 --- a/src/ops.c +++ b/src/ops.c @@ -6460,7 +6460,7 @@ x11_export_final_selection(void) #endif void -clip_free_selection(VimClipboard *cbd) +clip_free_selection(Clipboard_T *cbd) { yankreg_T *y_ptr = y_current; @@ -6477,7 +6477,7 @@ clip_free_selection(VimClipboard *cbd) * Get the selected text and put it in register '*' or '+'. */ void -clip_get_selection(VimClipboard *cbd) +clip_get_selection(Clipboard_T *cbd) { yankreg_T *old_y_previous, *old_y_current; pos_T old_cursor; @@ -6542,7 +6542,7 @@ clip_yank_selection( int type, char_u *str, long len, - VimClipboard *cbd) + Clipboard_T *cbd) { yankreg_T *y_ptr; @@ -6562,7 +6562,7 @@ clip_yank_selection( * Returns the motion type, or -1 for failure. */ int -clip_convert_selection(char_u **str, long_u *len, VimClipboard *cbd) +clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd) { char_u *p; int lnum; diff --git a/src/os_qnx.c b/src/os_qnx.c index 79b7ec0f68..a6f195e509 100644 --- a/src/os_qnx.c +++ b/src/os_qnx.c @@ -48,18 +48,18 @@ void qnx_clip_init(void) /* No support for owning the clipboard */ int -clip_mch_own_selection(VimClipboard *cbd) +clip_mch_own_selection(Clipboard_T *cbd) { return FALSE; } void -clip_mch_lose_selection(VimClipboard *cbd) +clip_mch_lose_selection(Clipboard_T *cbd) { } void -clip_mch_request_selection(VimClipboard *cbd) +clip_mch_request_selection(Clipboard_T *cbd) { int type = MLINE, clip_length = 0, is_type_set = FALSE; void *cbdata; @@ -102,7 +102,7 @@ clip_mch_request_selection(VimClipboard *cbd) } void -clip_mch_set_selection(VimClipboard *cbd) +clip_mch_set_selection(Clipboard_T *cbd) { int type; long_u len; diff --git a/src/os_unix.c b/src/os_unix.c index 01f5f5946c..a15d66057f 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -7775,7 +7775,7 @@ xterm_update(void) } int -clip_xterm_own_selection(VimClipboard *cbd) +clip_xterm_own_selection(Clipboard_T *cbd) { if (xterm_Shell != (Widget)0) return clip_x11_own_selection(xterm_Shell, cbd); @@ -7783,21 +7783,21 @@ clip_xterm_own_selection(VimClipboard *cbd) } void -clip_xterm_lose_selection(VimClipboard *cbd) +clip_xterm_lose_selection(Clipboard_T *cbd) { if (xterm_Shell != (Widget)0) clip_x11_lose_selection(xterm_Shell, cbd); } void -clip_xterm_request_selection(VimClipboard *cbd) +clip_xterm_request_selection(Clipboard_T *cbd) { if (xterm_Shell != (Widget)0) clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd); } void -clip_xterm_set_selection(VimClipboard *cbd) +clip_xterm_set_selection(Clipboard_T *cbd) { clip_x11_set_selection(cbd); } diff --git a/src/proto.h b/src/proto.h index 264cbb9e45..81023e2748 100644 --- a/src/proto.h +++ b/src/proto.h @@ -320,9 +320,9 @@ extern char *vim_SelFile(Widget toplevel, char *prompt, char *init_path, int (*s #endif #if defined(MACOS_X_DARWIN) && defined(FEAT_CLIPBOARD) && !defined(FEAT_GUI) /* functions in os_macosx.m */ -void clip_mch_lose_selection(VimClipboard *cbd); -int clip_mch_own_selection(VimClipboard *cbd); -void clip_mch_request_selection(VimClipboard *cbd); -void clip_mch_set_selection(VimClipboard *cbd); +void clip_mch_lose_selection(Clipboard_T *cbd); +int clip_mch_own_selection(Clipboard_T *cbd); +void clip_mch_request_selection(Clipboard_T *cbd); +void clip_mch_set_selection(Clipboard_T *cbd); #endif #endif /* !PROTO && !NOPROTO */ diff --git a/src/proto/gui_gtk_x11.pro b/src/proto/gui_gtk_x11.pro index 111cac7c99..708e68dd5e 100644 --- a/src/proto/gui_gtk_x11.pro +++ b/src/proto/gui_gtk_x11.pro @@ -59,11 +59,11 @@ void gui_mch_clear_block(int row1arg, int col1arg, int row2arg, int col2arg); void gui_mch_clear_all(void); void gui_mch_delete_lines(int row, int num_lines); void gui_mch_insert_lines(int row, int num_lines); -void clip_mch_request_selection(VimClipboard *cbd); -void clip_mch_lose_selection(VimClipboard *cbd); -int clip_mch_own_selection(VimClipboard *cbd); -void clip_mch_set_selection(VimClipboard *cbd); -int clip_gtk_owner_exists(VimClipboard *cbd); +void clip_mch_request_selection(Clipboard_T *cbd); +void clip_mch_lose_selection(Clipboard_T *cbd); +int clip_mch_own_selection(Clipboard_T *cbd); +void clip_mch_set_selection(Clipboard_T *cbd); +int clip_gtk_owner_exists(Clipboard_T *cbd); void gui_mch_menu_grey(vimmenu_T *menu, int grey); void gui_mch_menu_hidden(vimmenu_T *menu, int hidden); void gui_mch_draw_menubar(void); diff --git a/src/proto/gui_mac.pro b/src/proto/gui_mac.pro index 011ef2888e..a36ad903cf 100644 --- a/src/proto/gui_mac.pro +++ b/src/proto/gui_mac.pro @@ -111,10 +111,10 @@ void mch_post_buffer_write (buf_T *buf); void mch_errmsg(char *str); void mch_display_error(void); -void clip_mch_lose_selection(VimClipboard *cbd); -void clip_mch_request_selection(VimClipboard *cbd); -void clip_mch_set_selection(VimClipboard *cbd); -int clip_mch_own_selection(VimClipboard *cbd); +void clip_mch_lose_selection(Clipboard_T *cbd); +void clip_mch_request_selection(Clipboard_T *cbd); +void clip_mch_set_selection(Clipboard_T *cbd); +int clip_mch_own_selection(Clipboard_T *cbd); pascal OSErr FindProcessBySignature( const OSType targetType, const OSType targetCreator, ProcessSerialNumberPtr psnPtr ); diff --git a/src/proto/gui_x11.pro b/src/proto/gui_x11.pro index 955f374a66..5dde37d462 100644 --- a/src/proto/gui_x11.pro +++ b/src/proto/gui_x11.pro @@ -46,10 +46,10 @@ void gui_mch_clear_block(int row1, int col1, int row2, int col2); void gui_mch_clear_all(void); void gui_mch_delete_lines(int row, int num_lines); void gui_mch_insert_lines(int row, int num_lines); -void clip_mch_lose_selection(VimClipboard *cbd); -int clip_mch_own_selection(VimClipboard *cbd); -void clip_mch_request_selection(VimClipboard *cbd); -void clip_mch_set_selection(VimClipboard *cbd); +void clip_mch_lose_selection(Clipboard_T *cbd); +int clip_mch_own_selection(Clipboard_T *cbd); +void clip_mch_request_selection(Clipboard_T *cbd); +void clip_mch_set_selection(Clipboard_T *cbd); void gui_mch_menu_grey(vimmenu_T *menu, int grey); void gui_mch_menu_hidden(vimmenu_T *menu, int hidden); void gui_mch_draw_menubar(void); diff --git a/src/proto/ops.pro b/src/proto/ops.pro index 01df56f2f7..0ff27a2c82 100644 --- a/src/proto/ops.pro +++ b/src/proto/ops.pro @@ -53,10 +53,10 @@ int read_viminfo_register(vir_T *virp, int force); void handle_viminfo_register(garray_T *values, int force); void write_viminfo_registers(FILE *fp); void x11_export_final_selection(void); -void clip_free_selection(VimClipboard *cbd); -void clip_get_selection(VimClipboard *cbd); -void clip_yank_selection(int type, char_u *str, long len, VimClipboard *cbd); -int clip_convert_selection(char_u **str, long_u *len, VimClipboard *cbd); +void clip_free_selection(Clipboard_T *cbd); +void clip_get_selection(Clipboard_T *cbd); +void clip_yank_selection(int type, char_u *str, long len, Clipboard_T *cbd); +int clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd); void dnd_yank_drag_data(char_u *str, long len); char_u get_reg_type(int regname, long *reglen); char_u *get_reg_contents(int regname, int flags); diff --git a/src/proto/os_qnx.pro b/src/proto/os_qnx.pro index 89a250f94d..a3fab620f1 100644 --- a/src/proto/os_qnx.pro +++ b/src/proto/os_qnx.pro @@ -1,8 +1,8 @@ /* os_qnx.c */ void qnx_init(void); void qnx_clip_init (void); -int clip_mch_own_selection(VimClipboard *cbd); -void clip_mch_lose_selection(VimClipboard *cbd); -void clip_mch_request_selection(VimClipboard *cbd); -void clip_mch_set_selection(VimClipboard *cbd); +int clip_mch_own_selection(Clipboard_T *cbd); +void clip_mch_lose_selection(Clipboard_T *cbd); +void clip_mch_request_selection(Clipboard_T *cbd); +void clip_mch_set_selection(Clipboard_T *cbd); /* vim: set ft=c : */ diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index 0e7c609f39..449b3e96f5 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -79,10 +79,10 @@ void setup_term_clip(void); void start_xterm_trace(int button); void stop_xterm_trace(void); void clear_xterm_clip(void); -int clip_xterm_own_selection(VimClipboard *cbd); -void clip_xterm_lose_selection(VimClipboard *cbd); -void clip_xterm_request_selection(VimClipboard *cbd); -void clip_xterm_set_selection(VimClipboard *cbd); +int clip_xterm_own_selection(Clipboard_T *cbd); +void clip_xterm_lose_selection(Clipboard_T *cbd); +void clip_xterm_request_selection(Clipboard_T *cbd); +void clip_xterm_set_selection(Clipboard_T *cbd); int xsmp_handle_requests(void); void xsmp_init(void); void xsmp_close(void); diff --git a/src/proto/ui.pro b/src/proto/ui.pro index e920029afa..7b28a32a2b 100644 --- a/src/proto/ui.pro +++ b/src/proto/ui.pro @@ -15,9 +15,9 @@ int ui_get_winpos(int *x, int *y, varnumber_T timeout); void ui_breakcheck(void); void ui_breakcheck_force(int force); void clip_init(int can_use); -void clip_update_selection(VimClipboard *clip); -void clip_own_selection(VimClipboard *cbd); -void clip_lose_selection(VimClipboard *cbd); +void clip_update_selection(Clipboard_T *clip); +void clip_own_selection(Clipboard_T *cbd); +void clip_lose_selection(Clipboard_T *cbd); void start_global_changes(void); int is_clipboard_needs_update(void); void end_global_changes(void); @@ -28,15 +28,15 @@ void clip_modeless(int button, int is_click, int is_drag); void clip_start_selection(int col, int row, int repeated_click); void clip_process_selection(int button, int col, int row, int_u repeated_click); void clip_may_redraw_selection(int row, int col, int len); -void clip_clear_selection(VimClipboard *cbd); +void clip_clear_selection(Clipboard_T *cbd); void clip_may_clear_selection(int row1, int row2); void clip_scroll_selection(int rows); void clip_copy_modeless_selection(int both); -int clip_gen_own_selection(VimClipboard *cbd); -void clip_gen_lose_selection(VimClipboard *cbd); -void clip_gen_set_selection(VimClipboard *cbd); -void clip_gen_request_selection(VimClipboard *cbd); -int clip_gen_owner_exists(VimClipboard *cbd); +int clip_gen_own_selection(Clipboard_T *cbd); +void clip_gen_lose_selection(Clipboard_T *cbd); +void clip_gen_set_selection(Clipboard_T *cbd); +void clip_gen_request_selection(Clipboard_T *cbd); +int clip_gen_owner_exists(Clipboard_T *cbd); int vim_is_input_buf_full(void); int vim_is_input_buf_empty(void); int vim_free_in_input_buf(void); @@ -57,12 +57,12 @@ int check_row(int row); void open_app_context(void); void x11_setup_atoms(Display *dpy); void x11_setup_selection(Widget w); -void clip_x11_request_selection(Widget myShell, Display *dpy, VimClipboard *cbd); -void clip_x11_lose_selection(Widget myShell, VimClipboard *cbd); -int clip_x11_own_selection(Widget myShell, VimClipboard *cbd); -void clip_x11_set_selection(VimClipboard *cbd); -int clip_x11_owner_exists(VimClipboard *cbd); -void yank_cut_buffer0(Display *dpy, VimClipboard *cbd); +void clip_x11_request_selection(Widget myShell, Display *dpy, Clipboard_T *cbd); +void clip_x11_lose_selection(Widget myShell, Clipboard_T *cbd); +int clip_x11_own_selection(Widget myShell, Clipboard_T *cbd); +void clip_x11_set_selection(Clipboard_T *cbd); +int clip_x11_owner_exists(Clipboard_T *cbd); +void yank_cut_buffer0(Display *dpy, Clipboard_T *cbd); int jump_to_mouse(int flags, int *inclusive, int which_button); int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump); win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup); diff --git a/src/proto/winclip.pro b/src/proto/winclip.pro index 990c1cfb09..c7cba71a29 100644 --- a/src/proto/winclip.pro +++ b/src/proto/winclip.pro @@ -4,10 +4,10 @@ int utf16_to_utf8(short_u *instr, int inlen, char_u *outstr); void MultiByteToWideChar_alloc(UINT cp, DWORD flags, LPCSTR in, int inlen, LPWSTR *out, int *outlen); void WideCharToMultiByte_alloc(UINT cp, DWORD flags, LPCWSTR in, int inlen, LPSTR *out, int *outlen, LPCSTR def, LPBOOL useddef); void win_clip_init(void); -int clip_mch_own_selection(VimClipboard *cbd); -void clip_mch_lose_selection(VimClipboard *cbd); -void clip_mch_request_selection(VimClipboard *cbd); -void clip_mch_set_selection(VimClipboard *cbd); +int clip_mch_own_selection(Clipboard_T *cbd); +void clip_mch_lose_selection(Clipboard_T *cbd); +void clip_mch_request_selection(Clipboard_T *cbd); +void clip_mch_set_selection(Clipboard_T *cbd); short_u *enc_to_utf16(char_u *str, int *lenp); char_u *utf16_to_enc(short_u *str, int *lenp); void acp_to_enc(char_u *str, int str_size, char_u **out, int *outlen); diff --git a/src/ui.c b/src/ui.c index 08b3011c0e..2748da403b 100644 --- a/src/ui.c +++ b/src/ui.c @@ -724,7 +724,7 @@ ui_breakcheck_force(int force) void clip_init(int can_use) { - VimClipboard *cb; + Clipboard_T *cb; cb = &clip_star; for (;;) @@ -751,7 +751,7 @@ clip_init(int can_use) * this is called whenever VIsual mode is ended. */ void -clip_update_selection(VimClipboard *clip) +clip_update_selection(Clipboard_T *clip) { pos_T start, end; @@ -786,7 +786,7 @@ clip_update_selection(VimClipboard *clip) } void -clip_own_selection(VimClipboard *cbd) +clip_own_selection(Clipboard_T *cbd) { /* * Also want to check somehow that we are reading from the keyboard rather @@ -822,7 +822,7 @@ clip_own_selection(VimClipboard *cbd) } void -clip_lose_selection(VimClipboard *cbd) +clip_lose_selection(Clipboard_T *cbd) { #ifdef FEAT_X11 int was_owned = cbd->owned; @@ -860,7 +860,7 @@ clip_lose_selection(VimClipboard *cbd) } static void -clip_copy_selection(VimClipboard *clip) +clip_copy_selection(Clipboard_T *clip) { if (VIsual_active && (State & NORMAL) && clip->available) { @@ -990,10 +990,9 @@ clip_isautosel_plus(void) static void clip_invert_area(int, int, int, int, int how); static void clip_invert_rectangle(int row, int col, int height, int width, int invert); -static void clip_get_word_boundaries(VimClipboard *, int, int); +static void clip_get_word_boundaries(Clipboard_T *, int, int); static int clip_get_line_end(int); -static void clip_update_modeless_selection(VimClipboard *, int, int, - int, int); +static void clip_update_modeless_selection(Clipboard_T *, int, int, int, int); /* flags for clip_invert_area() */ #define CLIP_CLEAR 1 @@ -1058,7 +1057,7 @@ clip_compare_pos( void clip_start_selection(int col, int row, int repeated_click) { - VimClipboard *cb = &clip_star; + Clipboard_T *cb = &clip_star; if (cb->state == SELECT_DONE) clip_clear_selection(cb); @@ -1130,9 +1129,9 @@ clip_process_selection( int row, int_u repeated_click) { - VimClipboard *cb = &clip_star; - int diff; - int slen = 1; /* cursor shape width */ + Clipboard_T *cb = &clip_star; + int diff; + int slen = 1; // cursor shape width if (button == MOUSE_RELEASE) { @@ -1326,7 +1325,7 @@ clip_may_redraw_selection(int row, int col, int len) * Called from outside to clear selected region from the display */ void -clip_clear_selection(VimClipboard *cbd) +clip_clear_selection(Clipboard_T *cbd) { if (cbd->state == SELECT_CLEARED) @@ -1651,7 +1650,7 @@ clip_copy_modeless_selection(int both UNUSED) #define CHAR_CLASS(c) (c <= ' ' ? ' ' : vim_iswordc(c)) static void -clip_get_word_boundaries(VimClipboard *cb, int row, int col) +clip_get_word_boundaries(Clipboard_T *cb, int row, int col) { int start_class; int temp_col; @@ -1712,7 +1711,7 @@ clip_get_line_end(int row) */ static void clip_update_modeless_selection( - VimClipboard *cb, + Clipboard_T *cb, int row1, int col1, int row2, @@ -1738,7 +1737,7 @@ clip_update_modeless_selection( } int -clip_gen_own_selection(VimClipboard *cbd) +clip_gen_own_selection(Clipboard_T *cbd) { #ifdef FEAT_XCLIPBOARD # ifdef FEAT_GUI @@ -1753,7 +1752,7 @@ clip_gen_own_selection(VimClipboard *cbd) } void -clip_gen_lose_selection(VimClipboard *cbd) +clip_gen_lose_selection(Clipboard_T *cbd) { #ifdef FEAT_XCLIPBOARD # ifdef FEAT_GUI @@ -1768,7 +1767,7 @@ clip_gen_lose_selection(VimClipboard *cbd) } void -clip_gen_set_selection(VimClipboard *cbd) +clip_gen_set_selection(Clipboard_T *cbd) { if (!clip_did_set_selection) { @@ -1794,7 +1793,7 @@ clip_gen_set_selection(VimClipboard *cbd) } void -clip_gen_request_selection(VimClipboard *cbd) +clip_gen_request_selection(Clipboard_T *cbd) { #ifdef FEAT_XCLIPBOARD # ifdef FEAT_GUI @@ -1810,7 +1809,7 @@ clip_gen_request_selection(VimClipboard *cbd) #if (defined(FEAT_X11) && defined(USE_SYSTEM)) || defined(PROTO) int -clip_gen_owner_exists(VimClipboard *cbd UNUSED) +clip_gen_owner_exists(Clipboard_T *cbd UNUSED) { #ifdef FEAT_XCLIPBOARD # ifdef FEAT_GUI_GTK @@ -2372,7 +2371,7 @@ clip_x11_request_selection_cb( long_u len; char_u *p; char **text_list = NULL; - VimClipboard *cbd; + Clipboard_T *cbd; char_u *tmpbuf = NULL; if (*sel_atom == clip_plus.sel_atom) @@ -2463,7 +2462,7 @@ clip_x11_request_selection_cb( clip_x11_request_selection( Widget myShell, Display *dpy, - VimClipboard *cbd) + Clipboard_T *cbd) { XEvent event; Atom type; @@ -2566,7 +2565,7 @@ clip_x11_convert_selection_cb( static long_u save_length = 0; char_u *string; int motion_type; - VimClipboard *cbd; + Clipboard_T *cbd; int i; if (*sel_atom == clip_plus.sel_atom) @@ -2692,7 +2691,7 @@ clip_x11_lose_ownership_cb(Widget w UNUSED, Atom *sel_atom) } void -clip_x11_lose_selection(Widget myShell, VimClipboard *cbd) +clip_x11_lose_selection(Widget myShell, Clipboard_T *cbd) { XtDisownSelection(myShell, cbd->sel_atom, XtLastTimestampProcessed(XtDisplay(myShell))); @@ -2705,7 +2704,7 @@ clip_x11_notify_cb(Widget w UNUSED, Atom *sel_atom UNUSED, Atom *target UNUSED) } int -clip_x11_own_selection(Widget myShell, VimClipboard *cbd) +clip_x11_own_selection(Widget myShell, Clipboard_T *cbd) { /* When using the GUI we have proper timestamps, use the one of the last * event. When in the console we don't get events (the terminal gets @@ -2737,14 +2736,14 @@ clip_x11_own_selection(Widget myShell, VimClipboard *cbd) * will fill in the selection only when requested by another app. */ void -clip_x11_set_selection(VimClipboard *cbd UNUSED) +clip_x11_set_selection(Clipboard_T *cbd UNUSED) { } #if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) \ || defined(PROTO) int -clip_x11_owner_exists(VimClipboard *cbd) +clip_x11_owner_exists(Clipboard_T *cbd) { return XGetSelectionOwner(X_DISPLAY, cbd->sel_atom) != None; } @@ -2757,7 +2756,7 @@ clip_x11_owner_exists(VimClipboard *cbd) * Get the contents of the X CUT_BUFFER0 and put it in "cbd". */ void -yank_cut_buffer0(Display *dpy, VimClipboard *cbd) +yank_cut_buffer0(Display *dpy, Clipboard_T *cbd) { int nbytes = 0; char_u *buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0); diff --git a/src/version.c b/src/version.c index 510587b11f..d252a1475e 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 */ +/**/ + 1531, /**/ 1530, /**/ diff --git a/src/winclip.c b/src/winclip.c index 9b7f3f6ae6..4dcbc43865 100644 --- a/src/winclip.c +++ b/src/winclip.c @@ -191,7 +191,7 @@ win_clip_init(void) /* * Vim's own clipboard format recognises whether the text is char, line, * or rectangular block. Only useful for copying between two Vims. - * "VimClipboard" was used for previous versions, using the first + * "Clipboard_T" was used for previous versions, using the first * character to specify MCHAR, MLINE or MBLOCK. */ clip_star.format = RegisterClipboardFormat("VimClipboard2"); @@ -212,7 +212,7 @@ typedef struct * Make vim the owner of the current selection. Return OK upon success. */ int -clip_mch_own_selection(VimClipboard *cbd UNUSED) +clip_mch_own_selection(Clipboard_T *cbd UNUSED) { /* * Never actually own the clipboard. If another application sets the @@ -225,7 +225,7 @@ clip_mch_own_selection(VimClipboard *cbd UNUSED) * Make vim NOT the owner of the current selection. */ void -clip_mch_lose_selection(VimClipboard *cbd UNUSED) +clip_mch_lose_selection(Clipboard_T *cbd UNUSED) { /* Nothing needs to be done here */ } @@ -293,7 +293,7 @@ vim_open_clipboard(void) * */ void -clip_mch_request_selection(VimClipboard *cbd) +clip_mch_request_selection(Clipboard_T *cbd) { VimClipType_t metadata = { -1, -1, -1, -1 }; HGLOBAL hMem = NULL; @@ -453,7 +453,7 @@ clip_mch_request_selection(VimClipboard *cbd) * Send the current selection to the clipboard. */ void -clip_mch_set_selection(VimClipboard *cbd) +clip_mch_set_selection(Clipboard_T *cbd) { char_u *str = NULL; VimClipType_t metadata; From d2cea96f6cd5352b270b5d9e257bb0670c934146 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 23:14:45 +0200 Subject: [PATCH 15/44] patch 8.1.1532: build fails Problem: Build fails. Solution: Add missing changes. --- src/version.c | 2 ++ src/vim.h | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/version.c b/src/version.c index d252a1475e..146f996806 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 */ +/**/ + 1532, /**/ 1531, /**/ diff --git a/src/vim.h b/src/vim.h index 90208cdc7e..a44fb58142 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2006,7 +2006,7 @@ typedef int sock_T; # endif /* Info about selected text */ -typedef struct VimClipboard +typedef struct { int available; /* Is clipboard available? */ int owned; /* Flag: do we own the selection? */ @@ -2037,9 +2037,9 @@ typedef struct VimClipboard int_u format; /* Vim's own special clipboard format */ int_u format_raw; /* Vim's raw text clipboard format */ # endif -} VimClipboard; +} Clipboard_T; #else -typedef int VimClipboard; /* This is required for the prototypes. */ +typedef int Clipboard_T; // This is required for the prototypes. #endif /* Use 64-bit stat structure if available. */ From 2fc39aeeb5ff5101530a89838049e09e2959ad0e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 23:27:29 +0200 Subject: [PATCH 16/44] patch 8.1.1533: GUI build fails on Mac Problem: GUI build fails on Mac. Solution: Change VimClipboard type in non-C file. --- src/os_macosx.m | 8 ++++---- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/os_macosx.m b/src/os_macosx.m index 3b5c35adb9..4c04395ea4 100644 --- a/src/os_macosx.m +++ b/src/os_macosx.m @@ -40,13 +40,13 @@ NSString *VimPboardType = @"VimPboardType"; void -clip_mch_lose_selection(VimClipboard *cbd UNUSED) +clip_mch_lose_selection(Clipboard_T *cbd UNUSED) { } int -clip_mch_own_selection(VimClipboard *cbd UNUSED) +clip_mch_own_selection(Clipboard_T *cbd UNUSED) { /* This is called whenever there is a new selection and 'guioptions' * contains the "a" flag (automatically copy selection). Return TRUE, else @@ -58,7 +58,7 @@ clip_mch_own_selection(VimClipboard *cbd UNUSED) void -clip_mch_request_selection(VimClipboard *cbd) +clip_mch_request_selection(Clipboard_T *cbd) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -148,7 +148,7 @@ releasepool: * Send the current selection to the clipboard. */ void -clip_mch_set_selection(VimClipboard *cbd) +clip_mch_set_selection(Clipboard_T *cbd) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; diff --git a/src/version.c b/src/version.c index 146f996806..18ef97e5bc 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 */ +/**/ + 1533, /**/ 1532, /**/ From bd75b5333d10e63f7a667d4b65e80d309435629e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 14 Jun 2019 23:41:55 +0200 Subject: [PATCH 17/44] patch 8.1.1534: modeless selection in popup window selects too much Problem: Modeless selection in popup window selects too much. Solution: Restrict the selection to insde of the popup window. --- .../dumps/Test_popupwin_select_01.dump | 10 ++ .../dumps/Test_popupwin_select_02.dump | 10 ++ src/testdir/test_popupwin.vim | 33 ++++ src/ui.c | 156 ++++++++++++++---- src/version.c | 2 + src/vim.h | 33 ++-- 6 files changed, 197 insertions(+), 47 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_select_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_select_02.dump diff --git a/src/testdir/dumps/Test_popupwin_select_01.dump b/src/testdir/dumps/Test_popupwin_select_01.dump new file mode 100644 index 0000000000..779047de50 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_select_01.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @73 +|3| @7|╔+0#0000001#ffd7ff255|═@17|╗| +0#0000000#ffffff0@45 +|4| @7|║+0#0000001#ffd7ff255|t|h|e| |w+1#0000000#ffffff0|o|r|d| @9|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@45 +|5| @7|║+0#0000001#ffd7ff255|s+1#0000000#ffffff0|o|m|e| |m|o|r|e| @8|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@45 +|6| @7|║+0#0000001#ffd7ff255|s+1#0000000#ffffff0|e|v|e|r|a|l| |w|o|r|d|s| +0#0000001#ffd7ff255|h|e|r|e|║| +0#0000000#ffffff0@45 +|7| @7|╚+0#0000001#ffd7ff255|═@17|╝| +0#0000000#ffffff0@45 +|8| @73 +|9| @73 +|:|c|a|l@1| |S|e|l|e|c|t|1|(|)| @41|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_select_02.dump b/src/testdir/dumps/Test_popupwin_select_02.dump new file mode 100644 index 0000000000..550e0db7ea --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_select_02.dump @@ -0,0 +1,10 @@ +|1+0&#ffffff0>w|o|r|d| @69 +|s|o|m|e| |m|o|r|e| @65 +|s|e|v|e|r|a|l| |w|o|r|d|s| @61 +|2| @73 +|3| @73 +|4| @73 +|5| @73 +|6| @73 +|7| @73 +@57|1|,|2| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index c084c7ccf1..6e11bba73a 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -319,6 +319,39 @@ func Test_popup_drag() call delete('XtestPopupDrag') endfunc +func Test_popup_select() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + " create a popup with some text to be selected + let lines =<< trim END + call setline(1, range(1, 20)) + let winid = popup_create(['the word', 'some more', 'several words here'], { + \ 'drag': 1, + \ 'border': [], + \ 'line': 3, + \ 'col': 10, + \ }) + func Select1() + call feedkeys("\\\\\", "xt") + endfunc + map :call test_setmouse(4, 15) + map :call test_setmouse(6, 23) + END + call writefile(lines, 'XtestPopupSelect') + let buf = RunVimInTerminal('-S XtestPopupSelect', {'rows': 10}) + call term_sendkeys(buf, ":call Select1()\") + call VerifyScreenDump(buf, 'Test_popupwin_select_01', {}) + + call term_sendkeys(buf, ":call popup_close(winid)\") + call term_sendkeys(buf, "\"*p") + call VerifyScreenDump(buf, 'Test_popupwin_select_02', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupSelect') +endfunc + func Test_popup_in_tab() " default popup is local to tab, not visible when in other tab let winid = popup_create("text", {}) diff --git a/src/ui.c b/src/ui.c index 2748da403b..9e387b4cea 100644 --- a/src/ui.c +++ b/src/ui.c @@ -988,13 +988,13 @@ clip_isautosel_plus(void) * Stuff for general mouse selection, without using Visual mode. */ -static void clip_invert_area(int, int, int, int, int how); -static void clip_invert_rectangle(int row, int col, int height, int width, int invert); +static void clip_invert_area(Clipboard_T *, int, int, int, int, int how); +static void clip_invert_rectangle(Clipboard_T *, int row, int col, int height, int width, int invert); static void clip_get_word_boundaries(Clipboard_T *, int, int); -static int clip_get_line_end(int); +static int clip_get_line_end(Clipboard_T *, int); static void clip_update_modeless_selection(Clipboard_T *, int, int, int, int); -/* flags for clip_invert_area() */ +// "how" flags for clip_invert_area() #define CLIP_CLEAR 1 #define CLIP_SET 2 #define CLIP_TOGGLE 3 @@ -1071,6 +1071,33 @@ clip_start_selection(int col, int row, int repeated_click) cb->end = cb->start; cb->origin_row = (short_u)cb->start.lnum; cb->state = SELECT_IN_PROGRESS; +#ifdef FEAT_TEXT_PROP + { + win_T *wp; + int row_cp = row; + int col_cp = col; + + wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP); + if (wp != NULL && bt_popup(wp->w_buffer)) + { + // Click in a popup window restricts selection to that window, + // excluding the border. + cb->min_col = wp->w_wincol + wp->w_popup_border[3]; + cb->max_col = wp->w_wincol + popup_width(wp) - 1 + - wp->w_popup_border[1]; + cb->min_row = wp->w_winrow + wp->w_popup_border[0]; + cb->max_row = wp->w_winrow + popup_height(wp) - 1 + - wp->w_popup_border[2]; + } + else + { + cb->min_col = 0; + cb->max_col = screen_Columns; + cb->min_row = 0; + cb->max_row = screen_Rows; + } + } +#endif if (repeated_click) { @@ -1090,7 +1117,7 @@ clip_start_selection(int col, int row, int repeated_click) { case SELECT_MODE_CHAR: cb->origin_start_col = cb->start.col; - cb->word_end_col = clip_get_line_end((int)cb->start.lnum); + cb->word_end_col = clip_get_line_end(cb, (int)cb->start.lnum); break; case SELECT_MODE_WORD: @@ -1098,14 +1125,14 @@ clip_start_selection(int col, int row, int repeated_click) cb->origin_start_col = cb->word_start_col; cb->origin_end_col = cb->word_end_col; - clip_invert_area((int)cb->start.lnum, cb->word_start_col, + clip_invert_area(cb, (int)cb->start.lnum, cb->word_start_col, (int)cb->end.lnum, cb->word_end_col, CLIP_SET); cb->start.col = cb->word_start_col; cb->end.col = cb->word_end_col; break; case SELECT_MODE_LINE: - clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum, + clip_invert_area(cb, (int)cb->start.lnum, 0, (int)cb->start.lnum, (int)Columns, CLIP_SET); cb->start.col = 0; cb->end.col = Columns; @@ -1223,7 +1250,7 @@ clip_process_selection( case SELECT_MODE_CHAR: /* If we're on a different line, find where the line ends */ if (row != cb->prev.lnum) - cb->word_end_col = clip_get_line_end(row); + cb->word_end_col = clip_get_line_end(cb, row); /* See if we are before or after the origin of the selection */ if (clip_compare_pos(row, col, cb->origin_row, @@ -1316,7 +1343,7 @@ clip_may_redraw_selection(int row, int col, int len) if (row == clip_star.end.lnum && end > (int)clip_star.end.col) end = clip_star.end.col; if (end > start) - clip_invert_area(row, start, row, end, 0); + clip_invert_area(&clip_star, row, start, row, end, 0); } } # endif @@ -1331,8 +1358,8 @@ clip_clear_selection(Clipboard_T *cbd) if (cbd->state == SELECT_CLEARED) return; - clip_invert_area((int)cbd->start.lnum, cbd->start.col, (int)cbd->end.lnum, - cbd->end.col, CLIP_CLEAR); + clip_invert_area(cbd, (int)cbd->start.lnum, cbd->start.col, + (int)cbd->end.lnum, cbd->end.col, CLIP_CLEAR); cbd->state = SELECT_CLEARED; } @@ -1388,13 +1415,21 @@ clip_scroll_selection( */ static void clip_invert_area( - int row1, - int col1, - int row2, - int col2, - int how) + Clipboard_T *cbd, + int row1, + int col1, + int row2, + int col2, + int how) { int invert = FALSE; + int max_col; + +#ifdef FEAT_TEXT_PROP + max_col = cbd->max_col; +#else + max_col = Columns - 1; +#endif if (how == CLIP_SET) invert = TRUE; @@ -1417,28 +1452,29 @@ clip_invert_area( /* If all on the same line, do it the easy way */ if (row1 == row2) { - clip_invert_rectangle(row1, col1, 1, col2 - col1, invert); + clip_invert_rectangle(cbd, row1, col1, 1, col2 - col1, invert); } else { /* Handle a piece of the first line */ if (col1 > 0) { - clip_invert_rectangle(row1, col1, 1, (int)Columns - col1, invert); + clip_invert_rectangle(cbd, row1, col1, 1, + (int)Columns - col1, invert); row1++; } /* Handle a piece of the last line */ - if (col2 < Columns - 1) + if (col2 < max_col) { - clip_invert_rectangle(row2, 0, 1, col2, invert); + clip_invert_rectangle(cbd, row2, 0, 1, col2, invert); row2--; } /* Handle the rectangle thats left */ if (row2 >= row1) - clip_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns, - invert); + clip_invert_rectangle(cbd, row1, 0, row2 - row1 + 1, + (int)Columns, invert); } } @@ -1448,15 +1484,36 @@ clip_invert_area( */ static void clip_invert_rectangle( - int row, - int col, - int height, - int width, - int invert) + Clipboard_T *cbd, + int row_arg, + int col_arg, + int height_arg, + int width_arg, + int invert) { + int row = row_arg; + int col = col_arg; + int height = height_arg; + int width = width_arg; + #ifdef FEAT_TEXT_PROP // this goes on top of all popup windows screen_zindex = 32000; + + if (col < cbd->min_col) + { + width -= cbd->min_col - col; + col = cbd->min_col; + } + if (width > cbd->max_col - col + 1) + width = cbd->max_col - col + 1; + if (row < cbd->min_row) + { + height -= cbd->min_row - row; + row = cbd->min_row; + } + if (height > cbd->max_row - row + 1) + height = cbd->max_row - row + 1; #endif #ifdef FEAT_GUI if (gui.in_use) @@ -1507,6 +1564,16 @@ clip_copy_modeless_selection(int both UNUSED) { row = col1; col1 = col2; col2 = row; } +#ifdef FEAT_TEXT_PROP + if (col1 < clip_star.min_col) + col1 = clip_star.min_col; + if (col2 > clip_star.max_col + 1) + col2 = clip_star.max_col + 1; + if (row1 < clip_star.min_row) + row1 = clip_star.min_row; + if (row2 > clip_star.max_row) + row2 = clip_star.max_row; +#endif /* correct starting point for being on right halve of double-wide char */ p = ScreenLines + LineOffset[row1]; if (enc_dbcs != 0) @@ -1530,17 +1597,31 @@ clip_copy_modeless_selection(int both UNUSED) if (row == row1) start_col = col1; else +#ifdef FEAT_TEXT_PROP + start_col = clip_star.min_col; +#else start_col = 0; +#endif if (row == row2) end_col = col2; else +#ifdef FEAT_TEXT_PROP + end_col = clip_star.max_col + 1; +#else end_col = Columns; +#endif - line_end_col = clip_get_line_end(row); + line_end_col = clip_get_line_end(&clip_star, row); /* See if we need to nuke some trailing whitespace */ - if (end_col >= Columns && (row < row2 || end_col > line_end_col)) + if (end_col >= +#ifdef FEAT_TEXT_PROP + clip_star.max_col + 1 +#else + Columns +#endif + && (row < row2 || end_col > line_end_col)) { /* Get rid of trailing whitespace */ end_col = line_end_col; @@ -1556,6 +1637,7 @@ clip_copy_modeless_selection(int both UNUSED) if (row > row1 && !LineWraps[row - 1]) *bufp++ = NL; + // Safetey check for in case resizing went wrong if (row < screen_Rows && end_col <= screen_Columns) { if (enc_dbcs != 0) @@ -1690,16 +1772,22 @@ clip_get_word_boundaries(Clipboard_T *cb, int row, int col) /* * Find the column position for the last non-whitespace character on the given - * line. + * line at or before start_col. */ static int -clip_get_line_end(int row) +clip_get_line_end(Clipboard_T *cbd UNUSED, int row) { int i; if (row >= screen_Rows || ScreenLines == NULL) return 0; - for (i = screen_Columns; i > 0; i--) + for (i = +#ifdef FEAT_TEXT_PROP + cbd->max_col + 1; +#else + screen_Columns; +#endif + i > 0; i--) if (ScreenLines[LineOffset[row] + i - 1] != ' ') break; return i; @@ -1720,7 +1808,7 @@ clip_update_modeless_selection( /* See if we changed at the beginning of the selection */ if (row1 != cb->start.lnum || col1 != (int)cb->start.col) { - clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col, + clip_invert_area(cb, row1, col1, (int)cb->start.lnum, cb->start.col, CLIP_TOGGLE); cb->start.lnum = row1; cb->start.col = col1; @@ -1729,7 +1817,7 @@ clip_update_modeless_selection( /* See if we changed at the end of the selection */ if (row2 != cb->end.lnum || col2 != (int)cb->end.col) { - clip_invert_area((int)cb->end.lnum, cb->end.col, row2, col2, + clip_invert_area(cb, (int)cb->end.lnum, cb->end.col, row2, col2, CLIP_TOGGLE); cb->end.lnum = row2; cb->end.col = col2; diff --git a/src/version.c b/src/version.c index 18ef97e5bc..851cd5fa1c 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 */ +/**/ + 1534, /**/ 1533, /**/ diff --git a/src/vim.h b/src/vim.h index a44fb58142..d6bc6c3714 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2008,34 +2008,41 @@ typedef int sock_T; /* Info about selected text */ typedef struct { - int available; /* Is clipboard available? */ - int owned; /* Flag: do we own the selection? */ - pos_T start; /* Start of selected area */ - pos_T end; /* End of selected area */ - int vmode; /* Visual mode character */ + int available; // Is clipboard available? + int owned; // Flag: do we own the selection? + pos_T start; // Start of selected area + pos_T end; // End of selected area + int vmode; // Visual mode character - /* Fields for selection that doesn't use Visual mode */ + // Fields for selection that doesn't use Visual mode short_u origin_row; short_u origin_start_col; short_u origin_end_col; short_u word_start_col; short_u word_end_col; +#ifdef FEAT_TEXT_PROP + // limits for selection inside a popup window + short_u min_col; + short_u max_col; + short_u min_row; + short_u max_row; +#endif - pos_T prev; /* Previous position */ - short_u state; /* Current selection state */ - short_u mode; /* Select by char, word, or line. */ + pos_T prev; // Previous position + short_u state; // Current selection state + short_u mode; // Select by char, word, or line. # if defined(FEAT_GUI_X11) || defined(FEAT_XCLIPBOARD) - Atom sel_atom; /* PRIMARY/CLIPBOARD selection ID */ + Atom sel_atom; // PRIMARY/CLIPBOARD selection ID # endif # ifdef FEAT_GUI_GTK - GdkAtom gtk_sel_atom; /* PRIMARY/CLIPBOARD selection ID */ + GdkAtom gtk_sel_atom; // PRIMARY/CLIPBOARD selection ID # endif # if defined(MSWIN) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD) - int_u format; /* Vim's own special clipboard format */ - int_u format_raw; /* Vim's raw text clipboard format */ + int_u format; // Vim's own special clipboard format + int_u format_raw; // Vim's raw text clipboard format # endif } Clipboard_T; #else From 650a63748c349bbb60adb912273e9bedd2b677c5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 00:29:33 +0200 Subject: [PATCH 18/44] patch 8.1.1535: popup select test fails on Mac Problem: Popup select test fails on Mac. Solution: Skip test if clipboard feature not available. --- src/testdir/test_popupwin.vim | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 6e11bba73a..79207c8b26 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -323,6 +323,9 @@ func Test_popup_select() if !CanRunVimInTerminal() throw 'Skipped: cannot make screendumps' endif + if !has('clipboard') + throw 'Skipped: clipboard feature missing' + endif " create a popup with some text to be selected let lines =<< trim END call setline(1, range(1, 20)) diff --git a/src/version.c b/src/version.c index 851cd5fa1c..7d4d06d113 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 */ +/**/ + 1535, /**/ 1534, /**/ From 1755ec4278ee6dccdbb8030fd5a4cf6054211f81 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 13:13:54 +0200 Subject: [PATCH 19/44] patch 8.1.1536: popup select test still fails on Mac Problem: Popup select test still fails on Mac. Solution: Set 'clipboard' to "autoselect" --- src/testdir/test_popupwin.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 79207c8b26..be86fdc546 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -328,6 +328,7 @@ func Test_popup_select() endif " create a popup with some text to be selected let lines =<< trim END + set clipboard=autoselect call setline(1, range(1, 20)) let winid = popup_create(['the word', 'some more', 'several words here'], { \ 'drag': 1, diff --git a/src/version.c b/src/version.c index 7d4d06d113..f379701ab0 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 */ +/**/ + 1536, /**/ 1535, /**/ From fc06cbbf8601a453b4a62a17558821add09f863f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 14:14:31 +0200 Subject: [PATCH 20/44] patch 8.1.1537: using "tab" for popup window can be confusing Problem: Using "tab" for popup window can be confusing. Solution: Use "tabpage". (Hirohito Higashi, closes #4532) --- runtime/doc/popup.txt | 36 ++++++++++++++++++++++------------- src/popupwin.c | 8 ++++---- src/testdir/test_popupwin.vim | 2 +- src/version.c | 2 ++ 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 7da0d16896..71c7bc0d30 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -40,11 +40,12 @@ The default color used is "Pmenu". If you prefer something else use the A popup window has a window-ID like other windows, but behaves differently. The size can be up to the whole Vim window and it overlaps other windows. -Popup windows can also overlap each other. +Popup windows can also overlap each other. The "zindex" property specifies +what goes on top of what. The popup window contains a buffer, and that buffer is always associated with -the popup window. The window cannot be used in Normal, Visual or Insert mode, -it does not get keyboard focus. You can use functions like `setbufline()` to +the popup window. The window cannot be in Normal, Visual or Insert mode, it +does not get keyboard focus. You can use functions like `setbufline()` to change the text in the buffer. There are more differences from how this window and buffer behave compared to regular windows and buffers, see |popup-buffer|. @@ -85,17 +86,16 @@ that it is in. -IMPLEMENTATION: +TODO: - Why does 'nrformats' leak from the popup window buffer??? - Disable commands, feedkeys(), CTRL-W, etc. in a popup window. Use NOT_IN_POPUP_WINDOW for more commands. - Add 'balloonpopup': instead of showing text, let the callback open a popup window and return the window ID. The popup will then be closed when the mouse moves, except when it moves inside the popup. +- For notifications use the PopupNotification highlight group, fall back to + WarningMsg if it isn't defined. - For the "moved" property also include mouse movement? -- When selecting text in the popup with modeless selection, do not select - outside of the popup and don't select the border or padding. -- Add test for dragging the popup window. - Make redrawing more efficient and avoid flicker: - put popup menu also put in popup_mask? - Invoke filter with character before mapping? @@ -105,7 +105,17 @@ IMPLEMENTATION: - When drawing on top half a double-wide character, display ">" or "<" in the incomplete cell. - Can the buffer be re-used, to avoid using up lots of buffer numbers? -- Implement all the unimplemented options and features. +- Implement: + popup_dialog({text}, {options}) + popup_filter_menu({id}, {key}) + popup_filter_yesno({id}, {key}) + popup_menu({text}, {options}) + popup_setoptions({id}, {options}) + flip option + hidden option + tabpage option with number + title option + transparent text property ============================================================================== @@ -140,7 +150,7 @@ Other: |popup_getpos()| get actual position and size of a popup -[functions to be moved to eval.txt later] +[functions help to be moved to eval.txt later] popup_atcursor({text}, {options}) *popup_atcursor()* Show the {text} above the cursor, and close it when the cursor @@ -291,7 +301,7 @@ popup_notification({text}, {options}) *popup_notification()* \ 'line': 1, \ 'col': 10, \ 'time': 3000, - \ 'tab': -1, + \ 'tabpage': -1, \ 'zindex': 200, \ 'drag': 1, \ 'highlight': 'WarningMsg', @@ -402,11 +412,11 @@ The second argument of |popup_create()| is a dictionary with options: hidden When TRUE the popup exists but is not displayed; use `popup_show()` to unhide it. {not implemented yet} - tab When -1: display the popup on all tabs. + tabpage When -1: display the popup on all tabs. When 0 (the default): display the popup on the current - tab. + tab page. Otherwise the number of the tab page the popup is - displayed on; when invalid the current tab is used. + displayed on; when invalid the current tab page is used. {only -1 and 0 are implemented} title Text to be displayed above the first item in the popup, on top of any border. If there is no top diff --git a/src/popupwin.c b/src/popupwin.c index 5265b4b9b3..594fca8a00 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -748,8 +748,8 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) // Avoid that 'buftype' is reset when this buffer is entered. buf->b_p_initialized = TRUE; - if (dict_find(d, (char_u *)"tab", -1) != NULL) - nr = (int)dict_get_number(d, (char_u *)"tab"); + if (dict_find(d, (char_u *)"tabpage", -1) != NULL) + nr = (int)dict_get_number(d, (char_u *)"tabpage"); else if (type == TYPE_NOTIFICATION) nr = -1; // notifications are global by default else @@ -757,7 +757,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) if (nr == 0) { - // popup on current tab + // popup on current tab page wp->w_next = curtab->tp_first_popupwin; curtab->tp_first_popupwin = wp; } @@ -1228,7 +1228,7 @@ not_in_popup_window() /* * Reset all the POPF_HANDLED flags in global popup windows and popup windows - * in the current tab. + * in the current tab page. */ void popup_reset_handled() diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index be86fdc546..789c8599f7 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -372,7 +372,7 @@ func Test_popup_in_tab() call assert_equal(0, bufexists(bufnr)) " global popup is visible in any tab - let winid = popup_create("text", {'tab': -1}) + let winid = popup_create("text", {'tabpage': -1}) call assert_equal(1, popup_getpos(winid).visible) tabnew call assert_equal(1, popup_getpos(winid).visible) diff --git a/src/version.c b/src/version.c index f379701ab0..f36b98689d 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 */ +/**/ + 1537, /**/ 1536, /**/ From dfa97f2aed3d8ca195d09e2ce91cef227f933961 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 14:31:55 +0200 Subject: [PATCH 21/44] patch 8.1.1538: cannot specify highlighting for notifications Problem: Cannot specify highlighting for notifications. Solution: Use the PopupNotification group if it exists. Add a minimal width to notifications. --- runtime/doc/popup.txt | 7 ++++--- src/popupwin.c | 12 +++++++++--- src/testdir/dumps/Test_popupwin_notify_01.dump | 6 +++--- src/testdir/dumps/Test_popupwin_notify_02.dump | 8 ++++---- src/testdir/test_popupwin.vim | 3 ++- src/version.c | 2 ++ 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 71c7bc0d30..3ee92f2698 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.1. Last change: 2019 Jun 12 +*popup.txt* For Vim version 8.1. Last change: 2019 Jun 15 VIM REFERENCE MANUAL by Bram Moolenaar @@ -93,8 +93,6 @@ TODO: - Add 'balloonpopup': instead of showing text, let the callback open a popup window and return the window ID. The popup will then be closed when the mouse moves, except when it moves inside the popup. -- For notifications use the PopupNotification highlight group, fall back to - WarningMsg if it isn't defined. - For the "moved" property also include mouse movement? - Make redrawing more efficient and avoid flicker: - put popup menu also put in popup_mask? @@ -300,6 +298,7 @@ popup_notification({text}, {options}) *popup_notification()* call popup_create({text}, { \ 'line': 1, \ 'col': 10, + \ 'minwidth': 20, \ 'time': 3000, \ 'tabpage': -1, \ 'zindex': 200, @@ -308,6 +307,8 @@ popup_notification({text}, {options}) *popup_notification()* \ 'border': [], \ 'padding': [0,1,0,1], \ }) +< The PopupNotification highlight group is used instead of + WarningMsg if it is defined. < The position will be adjusted to avoid overlap with other notifications. Use {options} to change the properties. diff --git a/src/popupwin.c b/src/popupwin.c index 594fca8a00..aeed2e79b4 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -258,7 +258,9 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) dictitem_T *di; int i; - wp->w_minwidth = dict_get_number(dict, (char_u *)"minwidth"); + di = dict_find(dict, (char_u *)"minwidth", -1); + if (di != NULL) + wp->w_minwidth = dict_get_number(dict, (char_u *)"minwidth"); wp->w_minheight = dict_get_number(dict, (char_u *)"minheight"); wp->w_maxwidth = dict_get_number(dict, (char_u *)"maxwidth"); wp->w_maxheight = dict_get_number(dict, (char_u *)"maxheight"); @@ -856,13 +858,17 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) wp->w_wantcol = 10; wp->w_zindex = POPUPWIN_NOTIFICATION_ZINDEX; + wp->w_minwidth = 20; + wp->w_popup_drag = 1; for (i = 0; i < 4; ++i) wp->w_popup_border[i] = 1; wp->w_popup_padding[1] = 1; wp->w_popup_padding[3] = 1; + + nr = syn_name2id((char_u *)"PopupNotification"); set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1, - (char_u *)"WarningMsg", OPT_FREE|OPT_LOCAL, 0); - wp->w_popup_drag = 1; + (char_u *)(nr == 0 ? "WarningMsg" : "PopupNotification"), + OPT_FREE|OPT_LOCAL, 0); } // Deal with options. diff --git a/src/testdir/dumps/Test_popupwin_notify_01.dump b/src/testdir/dumps/Test_popupwin_notify_01.dump index 2ecd5ee1d0..bad62f6d9a 100644 --- a/src/testdir/dumps/Test_popupwin_notify_01.dump +++ b/src/testdir/dumps/Test_popupwin_notify_01.dump @@ -1,6 +1,6 @@ ->1+0&#ffffff0| @7|╔+0#e000002&|═@19|╗| +0#0000000&@43 -|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0#0000000&@43 -|3| @7|╚+0#e000002&|═@19|╝| +0#0000000&@43 +>1+0&#ffffff0| @7|╔+0#e000002&|═@21|╗| +0#0000000&@41 +|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| @2|║| +0#0000000&@41 +|3| @7|╚+0#e000002&|═@21|╝| +0#0000000&@41 |4| @73 |5| @73 |6| @73 diff --git a/src/testdir/dumps/Test_popupwin_notify_02.dump b/src/testdir/dumps/Test_popupwin_notify_02.dump index 10170619a2..72e2895f16 100644 --- a/src/testdir/dumps/Test_popupwin_notify_02.dump +++ b/src/testdir/dumps/Test_popupwin_notify_02.dump @@ -1,10 +1,10 @@ ->1+0&#ffffff0| @7|╔+0#e000002&|═@19|╗| +0#0000000&@43 -|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0#0000000&@43 -|3| @7|╚+0#e000002&|═@19|╝| +0#0000000&@43 +>1+0&#ffffff0| @7|╔+0#e000002&|═@21|╗| +0#0000000&@41 +|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| @2|║| +0#0000000&@41 +|3| @7|╚+0#e000002&|═@21|╝| +0#0000000&@41 |4| @7|╔+0fd7ff255|═@31|╗| +0&#ffffff0@31 |5| @7|║+0fd7ff255| |a|n|o|t|h|e|r| |i|m|p|o|r|t|a|n|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0&#ffffff0@31 |6| @7|╚+0fd7ff255|═@31|╝| +0&#ffffff0@31 |7| @73 |8| @73 |9| @73 -@57|1|,|1| @10|T|o|p| +|:|c|a|l@1| |p|o|p|u|p|_|n|o|t|i|f|i|c|a|t|i|o|n|(|'|a|n|o|t|h|e|r| |i|m|p|o|r|t|a|n|t| |n|o|t|i|f|i|c|a|t|i|o|n|'|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 789c8599f7..d9b0b295f7 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1191,7 +1191,8 @@ func Test_notifications() call VerifyScreenDump(buf, 'Test_popupwin_notify_01', {}) " second one goes below the first one - call term_sendkeys(buf, ":call popup_notification('another important notification', {'highlight': 'Notification'})\") + call term_sendkeys(buf, ":hi link PopupNotification Notification\") + call term_sendkeys(buf, ":call popup_notification('another important notification', {})\") call VerifyScreenDump(buf, 'Test_popupwin_notify_02', {}) diff --git a/src/version.c b/src/version.c index f36b98689d..4a6fb006a6 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 */ +/**/ + 1538, /**/ 1537, /**/ From 9937a055437ef67b57a1bdec8f0799b669c9dbf0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 15:45:06 +0200 Subject: [PATCH 22/44] patch 8.1.1539: not easy to define a variable and lock it Problem: Not easy to define a variable and lock it. Solution: Add ":const". --- runtime/doc/eval.txt | 25 +++- src/eval.c | 139 +++++++++++++++++----- src/ex_cmdidxs.h | 50 ++++---- src/ex_cmds.h | 3 + src/proto/eval.pro | 1 + src/testdir/Make_all.mak | 2 + src/testdir/test_const.vim | 228 +++++++++++++++++++++++++++++++++++++ src/version.c | 2 + 8 files changed, 397 insertions(+), 53 deletions(-) create mode 100644 src/testdir/test_const.vim diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index da45de805a..ca3f4ca065 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -11598,8 +11598,31 @@ text... No error message is given for a non-existing variable, also without !. If the system does not support deleting an environment - variable, it is made emtpy. + variable, it is made empty. + *:cons* *:const* *E996* +:cons[t] {var-name} = {expr1} +:cons[t] [{name1}, {name2}, ...] = {expr1} +:cons[t] [{name1}, {name2}, ...] .= {expr1} +:cons[t] [{name}, ..., ; {lastname}] = {expr1} +:cons[t] {var-name} =<< [trim] {marker} +text... +text... +{marker} + Similar to |:let|, but additionally lock the variable + after setting the value. This is the same as locking + the variable with |:lockvar| just after |:let|, thus: > + :const x = 1 +< is equivalent to: > + :let x = 1 + :lockvar 1 x +< This is useful if you want to make sure the variable + is not modified. + *E995* + |:const| does not allow to for changing a variable. > + :let x = 1 + :const x = 2 " Error! +< :lockv[ar][!] [depth] {name} ... *:lockvar* *:lockv* Lock the internal variable {name}. Locking means that it can no longer be changed (until it is unlocked). diff --git a/src/eval.c b/src/eval.c index e2d3d48bd3..cdaf103a28 100644 --- a/src/eval.c +++ b/src/eval.c @@ -28,6 +28,7 @@ static char *e_missbrac = N_("E111: Missing ']'"); static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); static char *e_letwrong = N_("E734: Wrong variable type for %s="); static char *e_illvar = N_("E461: Illegal variable name: %s"); +static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); #ifdef FEAT_FLOAT static char *e_float_as_string = N_("E806: using Float as a String"); #endif @@ -212,7 +213,8 @@ static struct vimvar static dictitem_T vimvars_var; /* variable used for v: */ #define vimvarht vimvardict.dv_hashtab -static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars); +static void ex_let_const(exarg_T *eap, int is_const); +static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, int is_const, char_u *nextchars); static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon); static char_u *skip_var_one(char_u *arg); static void list_glob_vars(int *first); @@ -222,8 +224,8 @@ static void list_tab_vars(int *first); static void list_vim_vars(int *first); static void list_script_vars(int *first); static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first); -static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op); -static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op); +static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int is_const, char_u *endchars, char_u *op); +static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, int is_const, char_u *op); static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep); static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit); @@ -248,6 +250,7 @@ static typval_T *alloc_string_tv(char_u *string); static void delete_var(hashtab_T *ht, hashitem_T *hi); static void list_one_var(dictitem_T *v, char *prefix, int *first); static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first); +static void set_var_const(char_u *name, typval_T *tv, int copy, int is_const); static int tv_check_lock(typval_T *tv, char_u *name, int use_gettext); static char_u *find_option_end(char_u **arg, int *opt_flags); @@ -526,9 +529,9 @@ var_redir_start(char_u *name, int append) tv.v_type = VAR_STRING; tv.vval.v_string = (char_u *)""; if (append) - set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"."); + set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"."); else - set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"="); + set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"="); clear_lval(redir_lval); err = did_emsg; did_emsg |= save_emsg; @@ -601,7 +604,8 @@ var_redir_stop(void) redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0, FNE_CHECK_START); if (redir_endp != NULL && redir_lval->ll_name != NULL) - set_var_lval(redir_lval, redir_endp, &tv, FALSE, (char_u *)"."); + set_var_lval(redir_lval, redir_endp, &tv, FALSE, FALSE, + (char_u *)"."); clear_lval(redir_lval); } @@ -1337,6 +1341,24 @@ heredoc_get(exarg_T *eap, char_u *cmd) */ void ex_let(exarg_T *eap) +{ + ex_let_const(eap, FALSE); +} + +/* + * ":const" list all variable values + * ":const var1 var2" list variable values + * ":const var = expr" assignment command. + * ":const [var1, var2] = expr" unpack list. + */ + void +ex_const(exarg_T *eap) +{ + ex_let_const(eap, TRUE); +} + + static void +ex_let_const(exarg_T *eap, int is_const) { char_u *arg = eap->arg; char_u *expr = NULL; @@ -1396,7 +1418,7 @@ ex_let(exarg_T *eap) op[0] = '='; op[1] = NUL; (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, - op); + is_const, op); clear_tv(&rettv); } } @@ -1429,7 +1451,7 @@ ex_let(exarg_T *eap) else if (i != FAIL) { (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, - op); + is_const, op); clear_tv(&rettv); } } @@ -1447,9 +1469,10 @@ ex_let(exarg_T *eap) ex_let_vars( char_u *arg_start, typval_T *tv, - int copy, /* copy values from "tv", don't move */ - int semicolon, /* from skip_var_list() */ - int var_count, /* from skip_var_list() */ + int copy, // copy values from "tv", don't move + int semicolon, // from skip_var_list() + int var_count, // from skip_var_list() + int is_const, // lock variables for const char_u *nextchars) { char_u *arg = arg_start; @@ -1463,7 +1486,7 @@ ex_let_vars( /* * ":let var = expr" or ":for var in list" */ - if (ex_let_one(arg, tv, copy, nextchars, nextchars) == NULL) + if (ex_let_one(arg, tv, copy, is_const, nextchars, nextchars) == NULL) return FAIL; return OK; } @@ -1493,7 +1516,8 @@ ex_let_vars( while (*arg != ']') { arg = skipwhite(arg + 1); - arg = ex_let_one(arg, &item->li_tv, TRUE, (char_u *)",;]", nextchars); + arg = ex_let_one(arg, &item->li_tv, TRUE, is_const, + (char_u *)",;]", nextchars); item = item->li_next; if (arg == NULL) return FAIL; @@ -1517,8 +1541,8 @@ ex_let_vars( ltv.vval.v_list = l; l->lv_refcount = 1; - arg = ex_let_one(skipwhite(arg + 1), <v, FALSE, - (char_u *)"]", nextchars); + arg = ex_let_one(skipwhite(arg + 1), <v, FALSE, is_const, + (char_u *)"]", nextchars); clear_tv(<v); if (arg == NULL) return FAIL; @@ -1805,11 +1829,12 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first) */ static char_u * ex_let_one( - char_u *arg, /* points to variable name */ - typval_T *tv, /* value to assign to variable */ - int copy, /* copy value from "tv" */ - char_u *endchars, /* valid chars after variable name or NULL */ - char_u *op) /* "+", "-", "." or NULL*/ + char_u *arg, // points to variable name + typval_T *tv, // value to assign to variable + int copy, // copy value from "tv" + int is_const, // lock variable for const + char_u *endchars, // valid chars after variable name or NULL + char_u *op) // "+", "-", "." or NULL { int c1; char_u *name; @@ -1824,6 +1849,11 @@ ex_let_one( */ if (*arg == '$') { + if (is_const) + { + emsg(_("E996: Cannot lock an environment variable")); + return NULL; + } /* Find the end of the name. */ ++arg; name = arg; @@ -1879,6 +1909,11 @@ ex_let_one( */ else if (*arg == '&') { + if (is_const) + { + emsg(_("E996: Cannot lock an option")); + return NULL; + } /* Find the end of the name. */ p = find_option_end(&arg, &opt_flags); if (p == NULL || (endchars != NULL @@ -1943,6 +1978,11 @@ ex_let_one( */ else if (*arg == '@') { + if (is_const) + { + emsg(_("E996: Cannot lock a register")); + return NULL; + } ++arg; if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL) semsg(_(e_letwrong), op); @@ -1988,7 +2028,7 @@ ex_let_one( emsg(_(e_letunexp)); else { - set_var_lval(&lv, p, tv, copy, op); + set_var_lval(&lv, p, tv, copy, is_const, op); arg_end = p; } } @@ -2430,6 +2470,7 @@ set_var_lval( char_u *endp, typval_T *rettv, int copy, + int is_const, // Disallow to modify existing variable for :const char_u *op) { int cc; @@ -2495,6 +2536,13 @@ set_var_lval( { typval_T tv; + if (is_const) + { + emsg(_(e_cannot_mod)); + *endp = cc; + return; + } + // handle +=, -=, *=, /=, %= and .= di = NULL; if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), @@ -2509,7 +2557,7 @@ set_var_lval( } } else - set_var(lp->ll_name, rettv, copy); + set_var_const(lp->ll_name, rettv, copy, is_const); *endp = cc; } else if (var_check_lock(lp->ll_newkey == NULL @@ -2521,6 +2569,12 @@ set_var_lval( listitem_T *ll_li = lp->ll_li; int ll_n1 = lp->ll_n1; + if (is_const) + { + emsg(_("E996: Cannot lock a range")); + return; + } + /* * Check whether any of the list items is locked */ @@ -2574,6 +2628,11 @@ set_var_lval( /* * Assign to a List or Dictionary item. */ + if (is_const) + { + emsg(_("E996: Cannot lock a list or dict")); + return; + } if (lp->ll_newkey != NULL) { if (op != NULL && *op != '=') @@ -2860,8 +2919,8 @@ next_for_item(void *fi_void, char_u *arg) tv.v_lock = VAR_FIXED; tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi); ++fi->fi_bi; - return ex_let_vars(arg, &tv, TRUE, - fi->fi_semicolon, fi->fi_varcount, NULL) == OK; + return ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, + fi->fi_varcount, FALSE, NULL) == OK; } item = fi->fi_lw.lw_item; @@ -2870,8 +2929,8 @@ next_for_item(void *fi_void, char_u *arg) else { fi->fi_lw.lw_item = item->li_next; - result = (ex_let_vars(arg, &item->li_tv, TRUE, - fi->fi_semicolon, fi->fi_varcount, NULL) == OK); + result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon, + fi->fi_varcount, FALSE, NULL) == OK); } return result; } @@ -8051,7 +8110,22 @@ list_one_var_a( set_var( char_u *name, typval_T *tv, - int copy) /* make copy of value in "tv" */ + int copy) // make copy of value in "tv" +{ + set_var_const(name, tv, copy, FALSE); +} + +/* + * Set variable "name" to value in "tv". + * If the variable already exists and "is_const" is FALSE the value is updated. + * Otherwise the variable is created. + */ + static void +set_var_const( + char_u *name, + typval_T *tv, + int copy, // make copy of value in "tv" + int is_const) // disallow to modify existing variable { dictitem_T *v; char_u *varname; @@ -8075,6 +8149,12 @@ set_var( if (v != NULL) { + if (is_const) + { + emsg(_(e_cannot_mod)); + return; + } + /* existing variable, need to clear the value */ if (var_check_ro(v->di_flags, name, FALSE) || var_check_lock(v->di_tv.v_lock, name, FALSE)) @@ -8152,6 +8232,8 @@ set_var( return; } v->di_flags = DI_FLAGS_ALLOC; + if (is_const) + v->di_flags |= DI_FLAGS_LOCK; } if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) @@ -8162,6 +8244,9 @@ set_var( v->di_tv.v_lock = 0; init_tv(tv); } + + if (is_const) + v->di_tv.v_lock |= VAR_LOCKED; } /* diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h index 0103a1741a..fdb2cdfe7c 100644 --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -8,29 +8,29 @@ static const unsigned short cmdidxs1[26] = /* a */ 0, /* b */ 19, /* c */ 42, - /* d */ 107, - /* e */ 129, - /* f */ 149, - /* g */ 165, - /* h */ 171, - /* i */ 180, - /* j */ 198, - /* k */ 200, - /* l */ 205, - /* m */ 267, - /* n */ 285, - /* o */ 305, - /* p */ 317, - /* q */ 356, - /* r */ 359, - /* s */ 379, - /* t */ 447, - /* u */ 492, - /* v */ 503, - /* w */ 521, - /* x */ 535, - /* y */ 545, - /* z */ 546 + /* d */ 108, + /* e */ 130, + /* f */ 150, + /* g */ 166, + /* h */ 172, + /* i */ 181, + /* j */ 199, + /* k */ 201, + /* l */ 206, + /* m */ 268, + /* n */ 286, + /* o */ 306, + /* p */ 318, + /* q */ 357, + /* r */ 360, + /* s */ 380, + /* t */ 448, + /* u */ 493, + /* v */ 504, + /* w */ 522, + /* x */ 536, + /* y */ 546, + /* z */ 547 }; /* @@ -43,7 +43,7 @@ static const unsigned char cmdidxs2[26][26] = { /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 }, /* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 }, - /* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 55, 57, 58, 59, 0, 61, 0, 64, 0, 0, 0 }, + /* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 56, 58, 59, 60, 0, 62, 0, 65, 0, 0, 0 }, /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 0, 16, 0, 0, 17, 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, 0 }, /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0 }, /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 }, @@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] = /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const int command_count = 559; +static const int command_count = 560; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 5ec69be364..4e5c0aac27 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -401,6 +401,9 @@ EX(CMD_continue, "continue", ex_continue, EX(CMD_confirm, "confirm", ex_wrongmodifier, NEEDARG|EXTRA|NOTRLCOM|CMDWIN, ADDR_NONE), +EX(CMD_const, "const", ex_const, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN, + ADDR_NONE), EX(CMD_copen, "copen", ex_copen, RANGE|COUNT|TRLBAR, ADDR_OTHER), diff --git a/src/proto/eval.pro b/src/proto/eval.pro index f501300a38..5e800adc89 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -28,6 +28,7 @@ void *call_func_retstr(char_u *func, int argc, typval_T *argv); void *call_func_retlist(char_u *func, int argc, typval_T *argv); int eval_foldexpr(char_u *arg, int *cp); void ex_let(exarg_T *eap); +void ex_const(exarg_T *eap); void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first); char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags); void clear_lval(lval_T *lp); diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 08f6c5bca6..9e551c1e1c 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -87,6 +87,7 @@ NEW_TESTS = \ test_comparators \ test_compiler \ test_conceal \ + test_const \ test_crypt \ test_cscope \ test_cursor_func \ @@ -312,6 +313,7 @@ NEW_TESTS_RES = \ test_command_count.res \ test_comparators.res \ test_conceal.res \ + test_const.res \ test_crypt.res \ test_cscope.res \ test_curswant.res \ diff --git a/src/testdir/test_const.vim b/src/testdir/test_const.vim new file mode 100644 index 0000000000..f0b9a052cc --- /dev/null +++ b/src/testdir/test_const.vim @@ -0,0 +1,228 @@ +" Test for :const + +func s:noop() +endfunc + +func Test_define_var_with_lock() + const i = 1 + const f = 1.1 + const s = 'vim' + const F = funcref('s:noop') + const l = [1, 2, 3] + const d = {'foo': 10} + if has('channel') + const j = test_null_job() + const c = test_null_channel() + endif + const b = v:true + const n = v:null + const bl = 0zC0FFEE + const here =<< trim EOS + hello + EOS + + call assert_fails('let i = 1', 'E741:') + call assert_fails('let f = 1.1', 'E741:') + call assert_fails('let s = "vim"', 'E741:') + call assert_fails('let F = funcref("s:noop")', 'E741:') + call assert_fails('let l = [1, 2, 3]', 'E741:') + call assert_fails('let d = {"foo": 10}', 'E741:') + if has('channel') + call assert_fails('let j = test_null_job()', 'E741:') + call assert_fails('let c = test_null_channel()', 'E741:') + endif + call assert_fails('let b = v:true', 'E741:') + call assert_fails('let n = v:null', 'E741:') + call assert_fails('let bl = 0zC0FFEE', 'E741:') + call assert_fails('let here = "xxx"', 'E741:') + + " Unlet + unlet i + unlet f + unlet s + unlet F + unlet l + unlet d + unlet j + unlet c + unlet b + unlet n + unlet bl + unlet here +endfunc + +func Test_define_l_var_with_lock() + " With l: prefix + const l:i = 1 + const l:f = 1.1 + const l:s = 'vim' + const l:F = funcref('s:noop') + const l:l = [1, 2, 3] + const l:d = {'foo': 10} + if has('channel') + const l:j = test_null_job() + const l:c = test_null_channel() + endif + const l:b = v:true + const l:n = v:null + const l:bl = 0zC0FFEE + const l:here =<< trim EOS + hello + EOS + + call assert_fails('let l:i = 1', 'E741:') + call assert_fails('let l:f = 1.1', 'E741:') + call assert_fails('let l:s = "vim"', 'E741:') + call assert_fails('let l:F = funcref("s:noop")', 'E741:') + call assert_fails('let l:l = [1, 2, 3]', 'E741:') + call assert_fails('let l:d = {"foo": 10}', 'E741:') + if has('channel') + call assert_fails('let l:j = test_null_job()', 'E741:') + call assert_fails('let l:c = test_null_channel()', 'E741:') + endif + call assert_fails('let l:b = v:true', 'E741:') + call assert_fails('let l:n = v:null', 'E741:') + call assert_fails('let l:bl = 0zC0FFEE', 'E741:') + call assert_fails('let l:here = "xxx"', 'E741:') + + " Unlet + unlet l:i + unlet l:f + unlet l:s + unlet l:F + unlet l:l + unlet l:d + unlet l:j + unlet l:c + unlet l:b + unlet l:n + unlet l:bl + unlet l:here +endfunc + +func Test_define_script_var_with_lock() + const s:x = 0 + call assert_fails('let s:x = 1', 'E741:') + unlet s:x +endfunc + +func Test_descructuring_with_lock() + const [a, b, c] = [1, 1.1, 'vim'] + + call assert_fails('let a = 1', 'E741:') + call assert_fails('let b = 1.1', 'E741:') + call assert_fails('let c = "vim"', 'E741:') + + const [d; e] = [1, 1.1, 'vim'] + call assert_fails('let d = 1', 'E741:') + call assert_fails('let e = [2.2, "a"]', 'E741:') +endfunc + +func Test_cannot_modify_existing_variable() + let i = 1 + let f = 1.1 + let s = 'vim' + let F = funcref('s:noop') + let l = [1, 2, 3] + let d = {'foo': 10} + if has('channel') + let j = test_null_job() + let c = test_null_channel() + endif + let b = v:true + let n = v:null + let bl = 0zC0FFEE + + call assert_fails('const i = 1', 'E995:') + call assert_fails('const f = 1.1', 'E995:') + call assert_fails('const s = "vim"', 'E995:') + call assert_fails('const F = funcref("s:noop")', 'E995:') + call assert_fails('const l = [1, 2, 3]', 'E995:') + call assert_fails('const d = {"foo": 10}', 'E995:') + if has('channel') + call assert_fails('const j = test_null_job()', 'E995:') + call assert_fails('const c = test_null_channel()', 'E995:') + endif + call assert_fails('const b = v:true', 'E995:') + call assert_fails('const n = v:null', 'E995:') + call assert_fails('const bl = 0zC0FFEE', 'E995:') + call assert_fails('const [i, f, s] = [1, 1.1, "vim"]', 'E995:') + + const i2 = 1 + const f2 = 1.1 + const s2 = 'vim' + const F2 = funcref('s:noop') + const l2 = [1, 2, 3] + const d2 = {'foo': 10} + if has('channel') + const j2 = test_null_job() + const c2 = test_null_channel() + endif + const b2 = v:true + const n2 = v:null + const bl2 = 0zC0FFEE + + call assert_fails('const i2 = 1', 'E995:') + call assert_fails('const f2 = 1.1', 'E995:') + call assert_fails('const s2 = "vim"', 'E995:') + call assert_fails('const F2 = funcref("s:noop")', 'E995:') + call assert_fails('const l2 = [1, 2, 3]', 'E995:') + call assert_fails('const d2 = {"foo": 10}', 'E995:') + if has('channel') + call assert_fails('const j2 = test_null_job()', 'E995:') + call assert_fails('const c2 = test_null_channel()', 'E995:') + endif + call assert_fails('const b2 = v:true', 'E995:') + call assert_fails('const n2 = v:null', 'E995:') + call assert_fails('const bl2 = 0zC0FFEE', 'E995:') + call assert_fails('const [i2, f2, s2] = [1, 1.1, "vim"]', 'E995:') +endfunc + +func Test_const_with_index_access() + let l = [1, 2, 3] + call assert_fails('const l[0] = 4', 'E996:') + call assert_fails('const l[0:1] = [1, 2]', 'E996:') + + let d = {'aaa': 0} + call assert_fails("const d['aaa'] = 4", 'E996:') + call assert_fails("const d.aaa = 4", 'E996:') +endfunc + +func Test_const_with_compound_assign() + let i = 0 + call assert_fails('const i += 4', 'E995:') + call assert_fails('const i -= 4', 'E995:') + call assert_fails('const i *= 4', 'E995:') + call assert_fails('const i /= 4', 'E995:') + call assert_fails('const i %= 4', 'E995:') + + let s = 'a' + call assert_fails('const s .= "b"', 'E995:') + + let [a, b, c] = [1, 2, 3] + call assert_fails('const [a, b, c] += [4, 5, 6]', 'E995:') + + let [d; e] = [1, 2, 3] + call assert_fails('const [d; e] += [4, 5, 6]', 'E995:') +endfunc + +func Test_const_with_special_variables() + call assert_fails('const $FOO = "hello"', 'E996:') + call assert_fails('const @a = "hello"', 'E996:') + call assert_fails('const &filetype = "vim"', 'E996:') + call assert_fails('const &l:filetype = "vim"', 'E996:') + call assert_fails('const &g:encoding = "utf-8"', 'E996:') +endfunc + +func Test_lock_depth_is_1() + const l = [1, 2, 3] + const d = {'foo': 10} + + " Modify list + call add(l, 4) + let l[0] = 42 + + " Modify dict + let d['bar'] = 'hello' + let d.foo = 44 +endfunc diff --git a/src/version.c b/src/version.c index 4a6fb006a6..45af9c0954 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 */ +/**/ + 1539, /**/ 1538, /**/ From 0abb4273f6c14f9ebca8be67d42c6e67b4f612cf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 16:06:00 +0200 Subject: [PATCH 23/44] patch 8.1.1540: cannot build without the +eval feature Problem: Cannot build without the +eval feature. Solution: Define ex_const if needed. --- src/ex_docmd.c | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index cc6a920a23..91ced52a5f 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -296,6 +296,7 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name); # define ex_endtry ex_ni # define ex_endfunction ex_ni # define ex_let ex_ni +# define ex_const ex_ni # define ex_unlet ex_ni # define ex_lockvar ex_ni # define ex_unlockvar ex_ni @@ -4852,6 +4853,7 @@ replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep) /* * Expand file name in Ex command argument. + * When an error is detected, "errormsgp" is set to a non-NULL pointer. * Return FAIL for failure, OK otherwise. */ int diff --git a/src/version.c b/src/version.c index 45af9c0954..7e9cac3f24 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 */ +/**/ + 1540, /**/ 1539, /**/ From bffc50494d52a3690cbbc5c7b34a835f9153184e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 16:34:21 +0200 Subject: [PATCH 24/44] patch 8.1.1541: check for ASAN is not reliable Problem: Check for ASAN is not reliable. Solution: Check the version output. (Dominique Pelle, closes #4543) --- src/testdir/test_memory_usage.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_memory_usage.vim b/src/testdir/test_memory_usage.vim index eadd4ea970..519ac4b9a3 100644 --- a/src/testdir/test_memory_usage.vim +++ b/src/testdir/test_memory_usage.vim @@ -6,7 +6,7 @@ endif if has('gui_running') throw 'Skipped, does not work in GUI' endif -if $ASAN_OPTIONS !=# '' +if execute('version') =~# '-fsanitize=[a-z,]*\' " Skip tests on Travis CI ASAN build because it's difficult to estimate " memory usage. throw 'Skipped, does not work with ASAN' diff --git a/src/version.c b/src/version.c index 7e9cac3f24..abafa7e921 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 */ +/**/ + 1541, /**/ 1540, /**/ From d7c968794710f338d491072171df48f96612cf72 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 17:12:48 +0200 Subject: [PATCH 25/44] patch 8.1.1542: an OptionSet autocommand does not get enough info Problem: An OptionSet autocommand does not get enough info. Solution: Add v:option_command, v:option_oldlocal and v:option_oldglobal. (Latrice Wilgus, closes #4118) --- runtime/doc/autocmd.txt | 36 ++- runtime/doc/eval.txt | 21 +- runtime/doc/version8.txt | 3 + src/eval.c | 11 +- src/option.c | 176 +++++++++++- src/structs.h | 8 +- src/testdir/test_autocmd.vim | 517 +++++++++++++++++++++++++++++++++-- src/version.c | 2 + src/vim.h | 61 +++-- 9 files changed, 750 insertions(+), 85 deletions(-) diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index c82669514a..c922df18ac 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -1,4 +1,4 @@ -*autocmd.txt* For Vim version 8.1. Last change: 2019 Jun 02 +*autocmd.txt* For Vim version 8.1. Last change: 2019 Jun 15 VIM REFERENCE MANUAL by Bram Moolenaar @@ -873,15 +873,33 @@ MenuPopup Just before showing the popup menu (under the *OptionSet* OptionSet After setting an option. The pattern is matched against the long option name. - The |v:option_old| variable indicates the - old option value, |v:option_new| variable - indicates the newly set value, the - |v:option_type| variable indicates whether - it's global or local scoped and || - indicates what option has been set. + || indicates what option has been set. - Is not triggered on startup and for the 'key' - option for obvious reasons. + |v:option_type| indicates whether it's global + or local scoped + |v:option_command| indicates what type of + set/let command was used (follow the tag to + see the table). + |v:option_new| indicates the newly set value. + |v:option_oldlocal| hass the old local value. + |v:option_oldglobal| hass the old global + value + |v:option_old| indicates the old option value. + + |v:option_oldlocal| is only set when |:set| + or |:setlocal| or a |modeline| was used to set + the option. Similarly |v:option_oldglobal| is + only set when |:set| or |:setglobal| was used. + + Note that when setting a |global-local| string + option with |:set|, then |v:option_old| is the + old global value. However, for all other kinds + of options (local string options, global-local + number options, ...) it is the old local + value. + + OptionSet is not triggered on startup and for + the 'key' option for obvious reasons. Usage example: Check for the existence of the directory in the 'backupdir' and 'undodir' diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index ca3f4ca065..83a89957f2 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1943,10 +1943,29 @@ v:option_new New value of the option. Valid while executing an |OptionSet| autocommand. *v:option_old* v:option_old Old value of the option. Valid while executing an |OptionSet| - autocommand. + autocommand. Depending on the command used for setting and the + kind of option this is either the local old value or the + global old value. + *v:option_oldlocal* +v:option_oldlocal + Old local value of the option. Valid while executing an + |OptionSet| autocommand. + *v:option_oldglobal* +v:option_oldglobal + Old global value of the option. Valid while executing an + |OptionSet| autocommand. *v:option_type* v:option_type Scope of the set command. Valid while executing an |OptionSet| autocommand. Can be either "global" or "local" + *v:option_command* +v:option_command + Command used to set the option. Valid while executing an + |OptionSet| autocommand. + value option was set via ~ + "setlocal" |:setlocal| or ":let l:xxx" + "setglobal" |:setglobal| or ":let g:xxx" + "set" |:set| or |:let| + "modeline" |modeline| *v:operator* *operator-variable* v:operator The last operator given in Normal mode. This is a single character except for commands starting with or , diff --git a/runtime/doc/version8.txt b/runtime/doc/version8.txt index 1dcef7efed..73db5f05b4 100644 --- a/runtime/doc/version8.txt +++ b/runtime/doc/version8.txt @@ -336,7 +336,10 @@ New Vim variables: ~ |v:null| an empty String, used for JSON |v:option_new| new value of the option, used by |OptionSet| |v:option_old| old value of the option, used by |OptionSet| +|v:option_oldlocal| old local value of the option, used by |OptionSet| +|v:option_oldglobal| old global value of the option, used by |OptionSet| |v:option_type| scope of the set command, used by |OptionSet| +|v:option_command| command used to set the option, used by |OptionSet| |v:progpath| the command with which Vim was invoked |v:t_bool| value of Boolean type |v:t_channel| value of Channel type diff --git a/src/eval.c b/src/eval.c index cdaf103a28..43866e657e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -172,6 +172,9 @@ static struct vimvar {VV_NAME("completed_item", VAR_DICT), VV_RO}, {VV_NAME("option_new", VAR_STRING), VV_RO}, {VV_NAME("option_old", VAR_STRING), VV_RO}, + {VV_NAME("option_oldlocal", VAR_STRING), VV_RO}, + {VV_NAME("option_oldglobal", VAR_STRING), VV_RO}, + {VV_NAME("option_command", VAR_STRING), VV_RO}, {VV_NAME("option_type", VAR_STRING), VV_RO}, {VV_NAME("errors", VAR_LIST), 0}, {VV_NAME("false", VAR_SPECIAL), VV_RO}, @@ -337,7 +340,7 @@ eval_init(void) for (i = 0; i < VV_LEN; ++i) { p = &vimvars[i]; - if (STRLEN(p->vv_name) > 16) + if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN) { iemsg("INTERNAL: name too long, increase size of dictitem16_T"); getout(1); @@ -9500,14 +9503,18 @@ last_set_msg(sctx_T script_ctx) } /* - * Reset v:option_new, v:option_old and v:option_type. + * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal, + * v:option_type, and v:option_command. */ void reset_v_option_vars(void) { set_vim_var_string(VV_OPTION_NEW, NULL, -1); set_vim_var_string(VV_OPTION_OLD, NULL, -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1); set_vim_var_string(VV_OPTION_TYPE, NULL, -1); + set_vim_var_string(VV_OPTION_COMMAND, NULL, -1); } /* diff --git a/src/option.c b/src/option.c index 2d22c4c973..12a0816f3d 100644 --- a/src/option.c +++ b/src/option.c @@ -4336,12 +4336,25 @@ set_title_defaults(void) #endif #if defined(FEAT_EVAL) +/* + * Trigger the OptionSet autocommand. + * "opt_idx" is the index of the option being set. + * "opt_flags" can be OPT_LOCAL etc. + * "oldval" the old value + * "oldval_l" the old local value (only non-NULL if global and local value + * are set) + * "oldval_g" the old global value (only non-NULL if global and local value + * are set) + * "newval" the new value + */ static void trigger_optionsset_string( int opt_idx, int opt_flags, - char_u *oldval, - char_u *newval) + char_u *oldval, + char_u *oldval_l, + char_u *oldval_g, + char_u *newval) { // Don't do this recursively. if (oldval != NULL && newval != NULL @@ -4354,6 +4367,27 @@ trigger_optionsset_string( set_vim_var_string(VV_OPTION_OLD, oldval, -1); set_vim_var_string(VV_OPTION_NEW, newval, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); + if (opt_flags & OPT_LOCAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); + } + if (opt_flags & OPT_GLOBAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1); + } + if (opt_flags & OPT_MODELINE) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); + } apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, FALSE, NULL); reset_v_option_vars(); @@ -4836,8 +4870,12 @@ do_set( char_u *oldval = NULL; /* previous value if *varp */ char_u *newval; char_u *origval = NULL; + char_u *origval_l = NULL; + char_u *origval_g = NULL; #if defined(FEAT_EVAL) char_u *saved_origval = NULL; + char_u *saved_origval_l = NULL; + char_u *saved_origval_g = NULL; char_u *saved_newval = NULL; #endif unsigned newlen; @@ -4857,8 +4895,23 @@ do_set( * new value is valid. */ oldval = *(char_u **)varp; - /* When setting the local value of a global - * option, the old value may be the global value. */ + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + { + origval_l = *(char_u **)get_varp_scope( + &(options[opt_idx]), OPT_LOCAL); + origval_g = *(char_u **)get_varp_scope( + &(options[opt_idx]), OPT_GLOBAL); + + // A global-local string option might have an empty + // option as value to indicate that the global + // value should be used. + if (((int)options[opt_idx].indir & PV_BOTH) + && origval_l == empty_option) + origval_l = origval_g; + } + + // When setting the local value of a global + // option, the old value may be the global value. if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) origval = *(char_u **)get_varp( @@ -4944,6 +4997,10 @@ do_set( vim_free(oldval); if (origval == oldval) origval = *(char_u **)varp; + if (origval_l == oldval) + origval_l = *(char_u **)varp; + if (origval_g == oldval) + origval_g = *(char_u **)varp; oldval = *(char_u **)varp; } /* @@ -5201,6 +5258,10 @@ do_set( /* newval (and varp) may become invalid if the * buffer is closed by autocommands. */ saved_newval = vim_strsave(newval); + if (origval_l != NULL) + saved_origval_l = vim_strsave(origval_l); + if (origval_g != NULL) + saved_origval_g = vim_strsave(origval_g); } #endif @@ -5234,9 +5295,13 @@ do_set( #if defined(FEAT_EVAL) if (errmsg == NULL) - trigger_optionsset_string(opt_idx, opt_flags, - saved_origval, saved_newval); + trigger_optionsset_string( + opt_idx, opt_flags, saved_origval, + saved_origval_l, saved_origval_g, + saved_newval); vim_free(saved_origval); + vim_free(saved_origval_l); + vim_free(saved_origval_g); vim_free(saved_newval); #endif /* If error detected, print the error message. */ @@ -6070,8 +6135,12 @@ set_string_option( char_u *s; char_u **varp; char_u *oldval; + char_u *oldval_l = NULL; + char_u *oldval_g = NULL; #if defined(FEAT_EVAL) char_u *saved_oldval = NULL; + char_u *saved_oldval_l = NULL; + char_u *saved_oldval_g = NULL; char_u *saved_newval = NULL; #endif char *r = NULL; @@ -6089,6 +6158,13 @@ set_string_option( ? OPT_GLOBAL : OPT_LOCAL) : opt_flags); oldval = *varp; + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + { + oldval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), + OPT_LOCAL); + oldval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), + OPT_GLOBAL); + } *varp = s; #if defined(FEAT_EVAL) @@ -6098,6 +6174,10 @@ set_string_option( # endif ) { + if (oldval_l != NULL) + saved_oldval_l = vim_strsave(oldval_l); + if (oldval_g != NULL) + saved_oldval_g = vim_strsave(oldval_g); saved_oldval = vim_strsave(oldval); saved_newval = vim_strsave(s); } @@ -6110,8 +6190,11 @@ set_string_option( /* call autocommand after handling side effects */ if (r == NULL) trigger_optionsset_string(opt_idx, opt_flags, - saved_oldval, saved_newval); + saved_oldval, saved_oldval_l, + saved_oldval_g, saved_newval); vim_free(saved_oldval); + vim_free(saved_oldval_l); + vim_free(saved_oldval_g); vim_free(saved_newval); #endif } @@ -8442,6 +8525,7 @@ set_bool_option( int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */ { int old_value = *(int *)varp; + int old_global_value = 0; /* Disallow changing some options from secure mode */ if ((secure @@ -8451,6 +8535,13 @@ set_bool_option( ) && (options[opt_idx].flags & P_SECURE)) return e_secure; + // Save the global value before changing anything. This is needed as for + // a global-only option setting the "local value" in fact sets the global + // value (since there is only one value). + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + old_global_value = *(int *)get_varp_scope(&(options[opt_idx]), + OPT_GLOBAL); + *(int *)varp = value; /* set the new value */ #ifdef FEAT_EVAL /* Remember where the option was set. */ @@ -8976,15 +9067,40 @@ set_bool_option( // Don't do this while starting up or recursively. if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { - char_u buf_old[2], buf_new[2], buf_type[7]; + char_u buf_old[2], buf_old_global[2], buf_new[2], buf_type[7]; vim_snprintf((char *)buf_old, 2, "%d", old_value ? TRUE: FALSE); + vim_snprintf((char *)buf_old_global, 2, "%d", + old_global_value ? TRUE: FALSE); vim_snprintf((char *)buf_new, 2, "%d", value ? TRUE: FALSE); - vim_snprintf((char *)buf_type, 7, "%s", (opt_flags & OPT_LOCAL) ? "local" : "global"); + vim_snprintf((char *)buf_type, 7, "%s", + (opt_flags & OPT_LOCAL) ? "local" : "global"); set_vim_var_string(VV_OPTION_NEW, buf_new, -1); set_vim_var_string(VV_OPTION_OLD, buf_old, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - apply_autocmds(EVENT_OPTIONSET, (char_u *) options[opt_idx].fullname, NULL, FALSE, NULL); + if (opt_flags & OPT_LOCAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + if (opt_flags & OPT_GLOBAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); + } + if (opt_flags & OPT_MODELINE) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, + NULL, FALSE, NULL); reset_v_option_vars(); } #endif @@ -9014,8 +9130,10 @@ set_num_option( { char *errmsg = NULL; long old_value = *(long *)varp; - long old_Rows = Rows; /* remember old Rows */ - long old_Columns = Columns; /* remember old Columns */ + long old_global_value = 0; // only used when setting a local and + // global option + long old_Rows = Rows; // remember old Rows + long old_Columns = Columns; // remember old Columns long *pp = (long *)varp; /* Disallow changing some options from secure mode. */ @@ -9026,6 +9144,12 @@ set_num_option( ) && (options[opt_idx].flags & P_SECURE)) return e_secure; + // Save the global value before changing anything. This is needed as for + // a global-only option setting the "local value" infact sets the global + // value (since there is only one value). + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + old_global_value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + *pp = value; #ifdef FEAT_EVAL /* Remember where the option was set. */ @@ -9533,15 +9657,37 @@ set_num_option( // Don't do this while starting up, failure or recursively. if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { - char_u buf_old[11], buf_new[11], buf_type[7]; - + char_u buf_old[11], buf_old_global[11], buf_new[11], buf_type[7]; vim_snprintf((char *)buf_old, 10, "%ld", old_value); + vim_snprintf((char *)buf_old_global, 10, "%ld", old_global_value); vim_snprintf((char *)buf_new, 10, "%ld", value); vim_snprintf((char *)buf_type, 7, "%s", (opt_flags & OPT_LOCAL) ? "local" : "global"); set_vim_var_string(VV_OPTION_NEW, buf_new, -1); set_vim_var_string(VV_OPTION_OLD, buf_old, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - apply_autocmds(EVENT_OPTIONSET, (char_u *) options[opt_idx].fullname, NULL, FALSE, NULL); + if (opt_flags & OPT_LOCAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + if (opt_flags & OPT_GLOBAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); + } + if (opt_flags & OPT_MODELINE) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, + NULL, FALSE, NULL); reset_v_option_vars(); } #endif diff --git a/src/structs.h b/src/structs.h index 04e21a106c..59259274a1 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1369,12 +1369,16 @@ struct dictitem_S }; typedef struct dictitem_S dictitem_T; -/* A dictitem with a 16 character key (plus NUL). */ +/* + * A dictitem with a 16 character key (plus NUL). This is an efficient way to + * have a fixed-size dictitem. + */ +#define DICTITEM16_KEY_LEN 16 struct dictitem16_S { typval_T di_tv; /* type and value of the variable */ char_u di_flags; /* flags (only used for variable) */ - char_u di_key[17]; /* key */ + char_u di_key[DICTITEM16_KEY_LEN + 1]; /* key */ }; typedef struct dictitem16_S dictitem16_T; diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 0a4177cd77..3254db8cdc 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -495,9 +495,10 @@ func Test_empty_doau() endfunc func s:AutoCommandOptionSet(match) + let template = "Option: <%s>, OldVal: <%s>, OldValLocal: <%s>, OldValGlobal: <%s>, NewVal: <%s>, Scope: <%s>, Command: <%s>\n" let item = remove(g:options, 0) - let expected = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", item[0], item[1], item[2], item[3]) - let actual = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", a:match, v:option_old, v:option_new, v:option_type) + let expected = printf(template, item[0], item[1], item[2], item[3], item[4], item[5], item[6]) + let actual = printf(template, a:match, v:option_old, v:option_oldlocal, v:option_oldglobal, v:option_new, v:option_type, v:option_command) let g:opt = [expected, actual] "call assert_equal(expected, actual) endfunc @@ -514,92 +515,100 @@ func Test_OptionSet() au OptionSet * :call s:AutoCommandOptionSet(expand("")) " 1: Setting number option" - let g:options=[['number', 0, 1, 'global']] + let g:options=[['number', 0, 0, 0, 1, 'global', 'set']] set nu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 2: Setting local number option" - let g:options=[['number', 1, 0, 'local']] + let g:options=[['number', 1, 1, '', 0, 'local', 'setlocal']] setlocal nonu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 3: Setting global number option" - let g:options=[['number', 1, 0, 'global']] + let g:options=[['number', 1, '', 1, 0, 'global', 'setglobal']] setglobal nonu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 4: Setting local autoindent option" - let g:options=[['autoindent', 0, 1, 'local']] + let g:options=[['autoindent', 0, 0, '', 1, 'local', 'setlocal']] setlocal ai call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 5: Setting global autoindent option" - let g:options=[['autoindent', 0, 1, 'global']] + let g:options=[['autoindent', 0, '', 0, 1, 'global', 'setglobal']] setglobal ai call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 6: Setting global autoindent option" - let g:options=[['autoindent', 1, 0, 'global']] + let g:options=[['autoindent', 1, 1, 1, 0, 'global', 'set']] + set ai! + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 6a: Setting global autoindent option" + let g:options=[['autoindent', 1, 1, 0, 0, 'global', 'set']] + noa setlocal ai + noa setglobal noai set ai! call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " Should not print anything, use :noa " 7: don't trigger OptionSet" - let g:options=[['invalid', 1, 1, 'invalid']] + let g:options=[['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']] noa set nonu - call assert_equal([['invalid', 1, 1, 'invalid']], g:options) + call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 8: Setting several global list and number option" - let g:options=[['list', 0, 1, 'global'], ['number', 0, 1, 'global']] + let g:options=[['list', 0, 0, 0, 1, 'global', 'set'], ['number', 0, 0, 0, 1, 'global', 'set']] set list nu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 9: don't trigger OptionSet" - let g:options=[['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']] + let g:options=[['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']] noa set nolist nonu - call assert_equal([['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']], g:options) + call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 10: Setting global acd" - let g:options=[['autochdir', 0, 1, 'local']] + let g:options=[['autochdir', 0, 0, '', 1, 'local', 'setlocal']] setlocal acd call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 11: Setting global autoread (also sets local value)" - let g:options=[['autoread', 0, 1, 'global']] + let g:options=[['autoread', 0, 0, 0, 1, 'global', 'set']] set ar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 12: Setting local autoread" - let g:options=[['autoread', 1, 1, 'local']] + let g:options=[['autoread', 1, 1, '', 1, 'local', 'setlocal']] setlocal ar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 13: Setting global autoread" - let g:options=[['autoread', 1, 0, 'global']] + let g:options=[['autoread', 1, '', 1, 0, 'global', 'setglobal']] setglobal invar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 14: Setting option backspace through :let" - let g:options=[['backspace', '', 'eol,indent,start', 'global']] + let g:options=[['backspace', '', '', '', 'eol,indent,start', 'global', 'set']] let &bs="eol,indent,start" call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 15: Setting option backspace through setbufvar()" - let g:options=[['backup', 0, 1, 'local']] + let g:options=[['backup', 0, 0, '', 1, 'local', 'setlocal']] " try twice, first time, shouldn't trigger because option name is invalid, " second time, it should trigger let bnum = bufnr('%') @@ -610,34 +619,488 @@ func Test_OptionSet() call assert_equal(g:opt[0], g:opt[1]) " 16: Setting number option using setwinvar" - let g:options=[['number', 0, 1, 'local']] + let g:options=[['number', 0, 0, '', 1, 'local', 'setlocal']] call setwinvar(0, '&number', 1) call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 17: Setting key option, shouldn't trigger" - let g:options=[['key', 'invalid', 'invalid1', 'invalid']] + let g:options=[['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']] setlocal key=blah setlocal key= - call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options) + call assert_equal([['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']], g:options) call assert_equal(g:opt[0], g:opt[1]) - " 18: Setting string option" + + " 18a: Setting string global option" + let oldval = &backupext + let g:options=[['backupext', oldval, oldval, oldval, 'foo', 'global', 'set']] + set backupext=foo + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 18b: Resetting string global option" + let g:options=[['backupext', 'foo', 'foo', 'foo', oldval, 'global', 'set']] + set backupext& + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 18c: Setting global string global option" + let g:options=[['backupext', oldval, '', oldval, 'bar', 'global', 'setglobal']] + setglobal backupext=bar + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 18d: Setting local string global option" + " As this is a global option this sets the global value even though + " :setlocal is used! + noa set backupext& " Reset global and local value (without triggering autocmd) + let g:options=[['backupext', oldval, oldval, '', 'baz', 'local', 'setlocal']] + setlocal backupext=baz + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 18e: Setting again string global option" + noa setglobal backupext=ext_global " Reset global and local value (without triggering autocmd) + noa setlocal backupext=ext_local " Sets the global(!) value! + let g:options=[['backupext', 'ext_local', 'ext_local', 'ext_local', 'fuu', 'global', 'set']] + set backupext=fuu + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 19a: Setting string local-global (to buffer) option" let oldval = &tags - let g:options=[['tags', oldval, 'tagpath', 'global']] + let g:options=[['tags', oldval, oldval, oldval, 'tagpath', 'global', 'set']] set tags=tagpath call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) - " 1l: Resetting string option" - let g:options=[['tags', 'tagpath', oldval, 'global']] + " 19b: Resetting string local-global (to buffer) option" + let g:options=[['tags', 'tagpath', 'tagpath', 'tagpath', oldval, 'global', 'set']] set tags& call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) + " 19c: Setting global string local-global (to buffer) option " + let g:options=[['tags', oldval, '', oldval, 'tagpath1', 'global', 'setglobal']] + setglobal tags=tagpath1 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 19d: Setting local string local-global (to buffer) option" + let g:options=[['tags', 'tagpath1', 'tagpath1', '', 'tagpath2', 'local', 'setlocal']] + setlocal tags=tagpath2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 19e: Setting again string local-global (to buffer) option" + " Note: v:option_old is the old global value for local-global string options + " but the old local value for all other kinds of options. + noa setglobal tags=tag_global " Reset global and local value (without triggering autocmd) + noa setlocal tags=tag_local + let g:options=[['tags', 'tag_global', 'tag_local', 'tag_global', 'tagpath', 'global', 'set']] + set tags=tagpath + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 19f: Setting string local-global (to buffer) option to an empty string" + " Note: v:option_old is the old global value for local-global string options + " but the old local value for all other kinds of options. + noa set tags=tag_global " Reset global and local value (without triggering autocmd) + noa setlocal tags= " empty string + let g:options=[['tags', 'tag_global', '', 'tag_global', 'tagpath', 'global', 'set']] + set tags=tagpath + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 20a: Setting string local (to buffer) option" + let oldval = &spelllang + let g:options=[['spelllang', oldval, oldval, oldval, 'elvish,klingon', 'global', 'set']] + set spelllang=elvish,klingon + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 20b: Resetting string local (to buffer) option" + let g:options=[['spelllang', 'elvish,klingon', 'elvish,klingon', 'elvish,klingon', oldval, 'global', 'set']] + set spelllang& + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 20c: Setting global string local (to buffer) option" + let g:options=[['spelllang', oldval, '', oldval, 'elvish', 'global', 'setglobal']] + setglobal spelllang=elvish + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 20d: Setting local string local (to buffer) option" + noa set spelllang& " Reset global and local value (without triggering autocmd) + let g:options=[['spelllang', oldval, oldval, '', 'klingon', 'local', 'setlocal']] + setlocal spelllang=klingon + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 20e: Setting again string local (to buffer) option" + " Note: v:option_old is the old global value for local-global string options + " but the old local value for all other kinds of options. + noa setglobal spelllang=spellglobal " Reset global and local value (without triggering autocmd) + noa setlocal spelllang=spelllocal + let g:options=[['spelllang', 'spelllocal', 'spelllocal', 'spellglobal', 'foo', 'global', 'set']] + set spelllang=foo + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 21a: Setting string local-global (to window) option" + let oldval = &statusline + let g:options=[['statusline', oldval, oldval, oldval, 'foo', 'global', 'set']] + set statusline=foo + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 21b: Resetting string local-global (to window) option" + " Note: v:option_old is the old global value for local-global string options + " but the old local value for all other kinds of options. + let g:options=[['statusline', 'foo', 'foo', 'foo', oldval, 'global', 'set']] + set statusline& + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 21c: Setting global string local-global (to window) option" + let g:options=[['statusline', oldval, '', oldval, 'bar', 'global', 'setglobal']] + setglobal statusline=bar + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 21d: Setting local string local-global (to window) option" + noa set statusline& " Reset global and local value (without triggering autocmd) + let g:options=[['statusline', oldval, oldval, '', 'baz', 'local', 'setlocal']] + setlocal statusline=baz + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 21e: Setting again string local-global (to window) option" + " Note: v:option_old is the old global value for local-global string options + " but the old local value for all other kinds of options. + noa setglobal statusline=bar " Reset global and local value (without triggering autocmd) + noa setlocal statusline=baz + let g:options=[['statusline', 'bar', 'baz', 'bar', 'foo', 'global', 'set']] + set statusline=foo + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 22a: Setting string local (to window) option" + let oldval = &foldignore + let g:options=[['foldignore', oldval, oldval, oldval, 'fo', 'global', 'set']] + set foldignore=fo + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 22b: Resetting string local (to window) option" + let g:options=[['foldignore', 'fo', 'fo', 'fo', oldval, 'global', 'set']] + set foldignore& + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 22c: Setting global string local (to window) option" + let g:options=[['foldignore', oldval, '', oldval, 'bar', 'global', 'setglobal']] + setglobal foldignore=bar + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 22d: Setting local string local (to window) option" + noa set foldignore& " Reset global and local value (without triggering autocmd) + let g:options=[['foldignore', oldval, oldval, '', 'baz', 'local', 'setlocal']] + setlocal foldignore=baz + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 22e: Setting again string local (to window) option" + noa setglobal foldignore=glob " Reset global and local value (without triggering autocmd) + noa setlocal foldignore=loc + let g:options=[['foldignore', 'loc', 'loc', 'glob', 'fo', 'global', 'set']] + set foldignore=fo + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 23a: Setting global number local option" + noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd) + noa setlocal cmdheight=1 " Sets the global(!) value! + let g:options=[['cmdheight', '1', '', '1', '2', 'global', 'setglobal']] + setglobal cmdheight=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 23b: Setting local number global option" + noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd) + noa setlocal cmdheight=1 " Sets the global(!) value! + let g:options=[['cmdheight', '1', '1', '', '2', 'local', 'setlocal']] + setlocal cmdheight=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 23c: Setting again number global option" + noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd) + noa setlocal cmdheight=1 " Sets the global(!) value! + let g:options=[['cmdheight', '1', '1', '1', '2', 'global', 'set']] + set cmdheight=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 23d: Setting again number global option" + noa set cmdheight=8 " Reset global and local value (without triggering autocmd) + let g:options=[['cmdheight', '8', '8', '8', '2', 'global', 'set']] + set cmdheight=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 24a: Setting global number global-local (to buffer) option" + noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd) + noa setlocal undolevels=1 + let g:options=[['undolevels', '8', '', '8', '2', 'global', 'setglobal']] + setglobal undolevels=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 24b: Setting local number global-local (to buffer) option" + noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd) + noa setlocal undolevels=1 + let g:options=[['undolevels', '1', '1', '', '2', 'local', 'setlocal']] + setlocal undolevels=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 24c: Setting again number global-local (to buffer) option" + noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd) + noa setlocal undolevels=1 + let g:options=[['undolevels', '1', '1', '8', '2', 'global', 'set']] + set undolevels=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 24d: Setting again global number global-local (to buffer) option" + noa set undolevels=8 " Reset global and local value (without triggering autocmd) + let g:options=[['undolevels', '8', '8', '8', '2', 'global', 'set']] + set undolevels=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 25a: Setting global number local (to buffer) option" + noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd) + noa setlocal wrapmargin=1 + let g:options=[['wrapmargin', '8', '', '8', '2', 'global', 'setglobal']] + setglobal wrapmargin=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 25b: Setting local number local (to buffer) option" + noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd) + noa setlocal wrapmargin=1 + let g:options=[['wrapmargin', '1', '1', '', '2', 'local', 'setlocal']] + setlocal wrapmargin=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 25c: Setting again number local (to buffer) option" + noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd) + noa setlocal wrapmargin=1 + let g:options=[['wrapmargin', '1', '1', '8', '2', 'global', 'set']] + set wrapmargin=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 25d: Setting again global number local (to buffer) option" + noa set wrapmargin=8 " Reset global and local value (without triggering autocmd) + let g:options=[['wrapmargin', '8', '8', '8', '2', 'global', 'set']] + set wrapmargin=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 26: Setting number global-local (to window) option. + " Such option does currently not exist. + + + " 27a: Setting global number local (to window) option" + noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd) + noa setlocal foldcolumn=1 + let g:options=[['foldcolumn', '8', '', '8', '2', 'global', 'setglobal']] + setglobal foldcolumn=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 27b: Setting local number local (to window) option" + noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd) + noa setlocal foldcolumn=1 + let g:options=[['foldcolumn', '1', '1', '', '2', 'local', 'setlocal']] + setlocal foldcolumn=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 27c: Setting again number local (to window) option" + noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd) + noa setlocal foldcolumn=1 + let g:options=[['foldcolumn', '1', '1', '8', '2', 'global', 'set']] + set foldcolumn=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 27d: Ssettin again global number local (to window) option" + noa set foldcolumn=8 " Reset global and local value (without triggering autocmd) + let g:options=[['foldcolumn', '8', '8', '8', '2', 'global', 'set']] + set foldcolumn=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 28a: Setting global boolean global option" + noa setglobal nowrapscan " Reset global and local value (without triggering autocmd) + noa setlocal wrapscan " Sets the global(!) value! + let g:options=[['wrapscan', '1', '', '1', '0', 'global', 'setglobal']] + setglobal nowrapscan + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 28b: Setting local boolean global option" + noa setglobal nowrapscan " Reset global and local value (without triggering autocmd) + noa setlocal wrapscan " Sets the global(!) value! + let g:options=[['wrapscan', '1', '1', '', '0', 'local', 'setlocal']] + setlocal nowrapscan + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 28c: Setting again boolean global option" + noa setglobal nowrapscan " Reset global and local value (without triggering autocmd) + noa setlocal wrapscan " Sets the global(!) value! + let g:options=[['wrapscan', '1', '1', '1', '0', 'global', 'set']] + set nowrapscan + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 28d: Setting again global boolean global option" + noa set nowrapscan " Reset global and local value (without triggering autocmd) + let g:options=[['wrapscan', '0', '0', '0', '1', 'global', 'set']] + set wrapscan + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 29a: Setting global boolean global-local (to buffer) option" + noa setglobal noautoread " Reset global and local value (without triggering autocmd) + noa setlocal autoread + let g:options=[['autoread', '0', '', '0', '1', 'global', 'setglobal']] + setglobal autoread + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 29b: Setting local boolean global-local (to buffer) option" + noa setglobal noautoread " Reset global and local value (without triggering autocmd) + noa setlocal autoread + let g:options=[['autoread', '1', '1', '', '0', 'local', 'setlocal']] + setlocal noautoread + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 29c: Setting again boolean global-local (to buffer) option" + noa setglobal noautoread " Reset global and local value (without triggering autocmd) + noa setlocal autoread + let g:options=[['autoread', '1', '1', '0', '1', 'global', 'set']] + set autoread + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 29d: Setting again global boolean global-local (to buffer) option" + noa set noautoread " Reset global and local value (without triggering autocmd) + let g:options=[['autoread', '0', '0', '0', '1', 'global', 'set']] + set autoread + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 30a: Setting global boolean local (to buffer) option" + noa setglobal nocindent " Reset global and local value (without triggering autocmd) + noa setlocal cindent + let g:options=[['cindent', '0', '', '0', '1', 'global', 'setglobal']] + setglobal cindent + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 30b: Setting local boolean local (to buffer) option" + noa setglobal nocindent " Reset global and local value (without triggering autocmd) + noa setlocal cindent + let g:options=[['cindent', '1', '1', '', '0', 'local', 'setlocal']] + setlocal nocindent + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 30c: Setting again boolean local (to buffer) option" + noa setglobal nocindent " Reset global and local value (without triggering autocmd) + noa setlocal cindent + let g:options=[['cindent', '1', '1', '0', '1', 'global', 'set']] + set cindent + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 30d: Setting again global boolean local (to buffer) option" + noa set nocindent " Reset global and local value (without triggering autocmd) + let g:options=[['cindent', '0', '0', '0', '1', 'global', 'set']] + set cindent + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 31: Setting boolean global-local (to window) option + " Currently no such option exists. + + + " 32a: Setting global boolean local (to window) option" + noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd) + noa setlocal cursorcolumn + let g:options=[['cursorcolumn', '0', '', '0', '1', 'global', 'setglobal']] + setglobal cursorcolumn + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 32b: Setting local boolean local (to window) option" + noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd) + noa setlocal cursorcolumn + let g:options=[['cursorcolumn', '1', '1', '', '0', 'local', 'setlocal']] + setlocal nocursorcolumn + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 32c: Setting again boolean local (to window) option" + noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd) + noa setlocal cursorcolumn + let g:options=[['cursorcolumn', '1', '1', '0', '1', 'global', 'set']] + set cursorcolumn + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 32d: Setting again global boolean local (to window) option" + noa set nocursorcolumn " Reset global and local value (without triggering autocmd) + let g:options=[['cursorcolumn', '0', '0', '0', '1', 'global', 'set']] + set cursorcolumn + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + + " 33: Test autocomands when an option value is converted internally. + noa set backspace=1 " Reset global and local value (without triggering autocmd) + let g:options=[['backspace', 'indent,eol', 'indent,eol', 'indent,eol', '2', 'global', 'set']] + set backspace=2 + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " Cleanup au! OptionSet - for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp'] + for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'backupext', 'tags', 'spelllang', 'statusline', 'foldignore', 'cmdheight', 'undolevels', 'wrapmargin', 'foldcolumn', 'wrapscan', 'autoread', 'cindent', 'cursorcolumn'] exe printf(":set %s&vim", opt) endfor call test_override('starting', 0) diff --git a/src/version.c b/src/version.c index abafa7e921..931b3af8f1 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 */ +/**/ + 1542, /**/ 1541, /**/ diff --git a/src/vim.h b/src/vim.h index d6bc6c3714..481d0651a4 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1935,41 +1935,44 @@ typedef int sock_T; #define VV_COMPLETED_ITEM 60 #define VV_OPTION_NEW 61 #define VV_OPTION_OLD 62 -#define VV_OPTION_TYPE 63 -#define VV_ERRORS 64 -#define VV_FALSE 65 -#define VV_TRUE 66 -#define VV_NULL 67 -#define VV_NONE 68 -#define VV_VIM_DID_ENTER 69 -#define VV_TESTING 70 -#define VV_TYPE_NUMBER 71 -#define VV_TYPE_STRING 72 -#define VV_TYPE_FUNC 73 -#define VV_TYPE_LIST 74 -#define VV_TYPE_DICT 75 -#define VV_TYPE_FLOAT 76 -#define VV_TYPE_BOOL 77 -#define VV_TYPE_NONE 78 -#define VV_TYPE_JOB 79 -#define VV_TYPE_CHANNEL 80 -#define VV_TYPE_BLOB 81 -#define VV_TERMRFGRESP 82 -#define VV_TERMRBGRESP 83 -#define VV_TERMU7RESP 84 -#define VV_TERMSTYLERESP 85 -#define VV_TERMBLINKRESP 86 -#define VV_EVENT 87 -#define VV_VERSIONLONG 88 -#define VV_LEN 89 // number of v: vars +#define VV_OPTION_OLDLOCAL 63 +#define VV_OPTION_OLDGLOBAL 64 +#define VV_OPTION_COMMAND 65 +#define VV_OPTION_TYPE 66 +#define VV_ERRORS 67 +#define VV_FALSE 68 +#define VV_TRUE 69 +#define VV_NULL 70 +#define VV_NONE 71 +#define VV_VIM_DID_ENTER 72 +#define VV_TESTING 73 +#define VV_TYPE_NUMBER 74 +#define VV_TYPE_STRING 75 +#define VV_TYPE_FUNC 76 +#define VV_TYPE_LIST 77 +#define VV_TYPE_DICT 78 +#define VV_TYPE_FLOAT 79 +#define VV_TYPE_BOOL 80 +#define VV_TYPE_NONE 81 +#define VV_TYPE_JOB 82 +#define VV_TYPE_CHANNEL 83 +#define VV_TYPE_BLOB 84 +#define VV_TERMRFGRESP 85 +#define VV_TERMRBGRESP 86 +#define VV_TERMU7RESP 87 +#define VV_TERMSTYLERESP 88 +#define VV_TERMBLINKRESP 89 +#define VV_EVENT 90 +#define VV_VERSIONLONG 91 +#define VV_LEN 92 // number of v: vars -/* used for v_number in VAR_SPECIAL */ +// used for v_number in VAR_SPECIAL #define VVAL_FALSE 0L #define VVAL_TRUE 1L #define VVAL_NONE 2L #define VVAL_NULL 3L -/* Type values for type(). */ +// Type values for type(). #define VAR_TYPE_NUMBER 0 #define VAR_TYPE_STRING 1 #define VAR_TYPE_FUNC 2 From b6e3b88ec8b757b3acf940f8b4938e975c39ba67 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 17:50:57 +0200 Subject: [PATCH 26/44] patch 8.1.1543: const test fails with small features Problem: Const test fails with small features. Solution: Don't unlet non-existing variables. --- src/testdir/test_const.vim | 12 ++++++++---- src/version.c | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/testdir/test_const.vim b/src/testdir/test_const.vim index f0b9a052cc..bb47e5e5fd 100644 --- a/src/testdir/test_const.vim +++ b/src/testdir/test_const.vim @@ -43,8 +43,10 @@ func Test_define_var_with_lock() unlet F unlet l unlet d - unlet j - unlet c + if has('channel') + unlet j + unlet c + endif unlet b unlet n unlet bl @@ -92,8 +94,10 @@ func Test_define_l_var_with_lock() unlet l:F unlet l:l unlet l:d - unlet l:j - unlet l:c + if has('channel') + unlet l:j + unlet l:c + endif unlet l:b unlet l:n unlet l:bl diff --git a/src/version.c b/src/version.c index 931b3af8f1..0b036d031b 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 */ +/**/ + 1543, /**/ 1542, /**/ From b46fecd3454399f8ebdc5055302e4bfc5a10f98b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 17:58:09 +0200 Subject: [PATCH 27/44] patch 8.1.1544: some balloon tests don't run when they can Problem: Some balloon tests don't run when they can. Solution: Split GUI balloon tests off into a separate file. (Ozaki Kiichi, closes #4538) Change the feature check into a command for consistency. --- Filelist | 1 + src/testdir/Make_all.mak | 2 ++ src/testdir/check.vim | 23 +++++++++++++++++ src/testdir/test_arabic.vim | 5 ++-- src/testdir/test_balloon.vim | 30 ++++------------------ src/testdir/test_balloon_gui.vim | 22 ++++++++++++++++ src/testdir/test_crypt.vim | 5 ++-- src/testdir/test_cscope.vim | 9 ++++--- src/testdir/test_digraph.vim | 5 ++-- src/testdir/test_float_func.vim | 5 ++-- src/testdir/test_gui.vim | 2 +- src/testdir/test_gui_init.vim | 2 +- src/testdir/test_history.vim | 5 ++-- src/testdir/test_langmap.vim | 5 ++-- src/testdir/test_listlbr.vim | 9 +++---- src/testdir/test_listlbr_utf8.vim | 13 +++------- src/testdir/test_lua.vim | 5 ++-- src/testdir/test_makeencoding.vim | 2 +- src/testdir/test_matchadd_conceal.vim | 5 ++-- src/testdir/test_matchadd_conceal_utf8.vim | 5 ++-- src/testdir/test_memory_usage.vim | 16 ++++++------ src/testdir/test_menu.vim | 5 ++-- src/testdir/test_mksession.vim | 5 ++-- src/testdir/test_mksession_utf8.vim | 5 ++-- src/testdir/test_netbeans.vim | 7 +++-- src/testdir/test_paste.vim | 4 +-- src/testdir/test_perl.vim | 5 ++-- src/testdir/test_popupwin.vim | 9 +++---- src/testdir/test_profile.vim | 5 ++-- src/testdir/test_prompt_buffer.vim | 5 ++-- src/testdir/test_python2.vim | 5 ++-- src/testdir/test_python3.vim | 5 ++-- src/testdir/test_pyx2.vim | 5 ++-- src/testdir/test_pyx3.vim | 5 ++-- src/testdir/test_quickfix.vim | 5 ++-- src/testdir/test_quotestar.vim | 2 +- src/testdir/test_reltime.vim | 9 +++---- src/testdir/test_ruby.vim | 5 ++-- src/testdir/test_sha256.vim | 9 +++---- src/testdir/test_shortpathname.vim | 2 +- src/testdir/test_signals.vim | 2 +- src/testdir/test_signs.vim | 5 ++-- src/testdir/test_spell.vim | 5 ++-- src/testdir/test_syntax.vim | 5 ++-- src/testdir/test_tcl.vim | 5 ++-- src/testdir/test_termcodes.vim | 4 +-- src/testdir/test_terminal.vim | 5 ++-- src/testdir/test_terminal_fail.vim | 5 ++-- src/testdir/test_textobjects.vim | 5 ++-- src/testdir/test_textprop.vim | 5 ++-- src/testdir/test_timers.vim | 5 ++-- src/testdir/test_vartabs.vim | 5 ++-- src/testdir/test_winbar.vim | 5 ++-- src/testdir/test_windows_home.vim | 2 +- src/testdir/test_xxd.vim | 2 +- src/version.c | 2 ++ 56 files changed, 164 insertions(+), 181 deletions(-) create mode 100644 src/testdir/check.vim create mode 100644 src/testdir/test_balloon_gui.vim diff --git a/Filelist b/Filelist index 99e10048ff..63088a6912 100644 --- a/Filelist +++ b/Filelist @@ -120,6 +120,7 @@ SRC_ALL = \ src/testdir/sautest/autoload/*.vim \ src/testdir/runtest.vim \ src/testdir/summarize.vim \ + src/testdir/check.vim \ src/testdir/shared.vim \ src/testdir/screendump.vim \ src/testdir/view_util.vim \ diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 9e551c1e1c..eb014a95c2 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -65,6 +65,7 @@ NEW_TESTS = \ test_backspace_opt \ test_backup \ test_balloon \ + test_balloon_gui \ test_behave \ test_blob \ test_blockedit \ @@ -297,6 +298,7 @@ NEW_TESTS_RES = \ test_autoload.res \ test_backspace_opt.res \ test_balloon.res \ + test_balloon_gui.res \ test_blob.res \ test_blockedit.res \ test_breakindent.res \ diff --git a/src/testdir/check.vim b/src/testdir/check.vim new file mode 100644 index 0000000000..7f37f1c96e --- /dev/null +++ b/src/testdir/check.vim @@ -0,0 +1,23 @@ +" Command to check for the presence of a feature. +command -nargs=1 CheckFeature call CheckFeature() +func CheckFeature(name) + if !has(a:name) + throw 'Skipped: ' .. a:name .. ' feature missing' + endif +endfunc + +" Command to check for the presence of a working option. +command -nargs=1 CheckOption call CheckOption() +func CheckOption(name) + if !exists('+' .. a:name) + throw 'Skipped: ' .. a:name .. ' option not supported' + endif +endfunc + +" Command to check for the presence of a function. +command -nargs=1 CheckFunction call CheckFunction() +func CheckFunction(name) + if !exists('*' .. a:name) + throw 'Skipped: ' .. a:name .. ' function missing' + endif +endfunc diff --git a/src/testdir/test_arabic.vim b/src/testdir/test_arabic.vim index 450c6f98f5..b679ec4520 100644 --- a/src/testdir/test_arabic.vim +++ b/src/testdir/test_arabic.vim @@ -2,9 +2,8 @@ " NOTE: This just checks if the code works. If you know Arabic please add " functional tests that check the shaping works with real text. -if !has('arabic') - throw 'Skipped: arabic feature missing' -endif +source check.vim +CheckFeature arabic source view_util.vim diff --git a/src/testdir/test_balloon.vim b/src/testdir/test_balloon.vim index abf7d6944e..793eb3a571 100644 --- a/src/testdir/test_balloon.vim +++ b/src/testdir/test_balloon.vim @@ -1,11 +1,12 @@ " Tests for 'balloonevalterm'. +" A few tests only work in the terminal. -if !has('balloon_eval_term') - throw 'Skipped: balloon_eval_term feature missing' +if has('gui_running') + throw 'Skipped: only work in the terminal' endif -" A few tests only work in the terminal. -if !has('gui_running') +source check.vim +CheckFeature balloon_eval_term source screendump.vim if !CanRunVimInTerminal() @@ -56,24 +57,3 @@ func Test_balloon_eval_term_visual() call StopVimInTerminal(buf) call delete('XTest_beval_visual') endfunc - -endif - -" Tests that only work in the GUI -if has('gui_running') - -func Test_balloon_show_gui() - let msg = 'this this this this' - call balloon_show(msg) - call assert_equal(msg, balloon_gettext()) - sleep 10m - call balloon_show('') - - let msg = 'that that' - call balloon_show(msg) - call assert_equal(msg, balloon_gettext()) - sleep 10m - call balloon_show('') -endfunc - -endif diff --git a/src/testdir/test_balloon_gui.vim b/src/testdir/test_balloon_gui.vim new file mode 100644 index 0000000000..fd01309c15 --- /dev/null +++ b/src/testdir/test_balloon_gui.vim @@ -0,0 +1,22 @@ +" Tests for 'ballooneval' in the GUI. + +if !has('gui_running') + throw 'Skipped: only works in the GUI' +endif + +source check.vim +CheckFeature balloon_eval + +func Test_balloon_show_gui() + let msg = 'this this this this' + call balloon_show(msg) + call assert_equal(msg, balloon_gettext()) + sleep 10m + call balloon_show('') + + let msg = 'that that' + call balloon_show(msg) + call assert_equal(msg, balloon_gettext()) + sleep 10m + call balloon_show('') +endfunc diff --git a/src/testdir/test_crypt.vim b/src/testdir/test_crypt.vim index db100991ab..ab62d84708 100644 --- a/src/testdir/test_crypt.vim +++ b/src/testdir/test_crypt.vim @@ -1,8 +1,7 @@ " Tests for encryption. -if !has('cryptv') - throw 'Skipped, encryption feature missing' -endif +source check.vim +CheckFeature cryptv func Common_head_only(text) " This was crashing Vim diff --git a/src/testdir/test_cscope.vim b/src/testdir/test_cscope.vim index a3fcbd77b6..c776be1138 100644 --- a/src/testdir/test_cscope.vim +++ b/src/testdir/test_cscope.vim @@ -1,10 +1,11 @@ " Test for cscope commands. -if !has('cscope') || !has('quickfix') - throw 'Skipped, cscope or quickfix feature missing' -endif +source check.vim +CheckFeature cscope +CheckFeature quickfix + if !executable('cscope') - throw 'Skipped, cscope program missing' + throw 'Skipped: cscope program missing' endif func CscopeSetupOrClean(setup) diff --git a/src/testdir/test_digraph.vim b/src/testdir/test_digraph.vim index 92d4e479a7..6435c86fa4 100644 --- a/src/testdir/test_digraph.vim +++ b/src/testdir/test_digraph.vim @@ -1,8 +1,7 @@ " Tests for digraphs -if !has("digraphs") - throw 'Skipped, digraphs feature missing' -endif +source check.vim +CheckFeature digraphs func Put_Dig(chars) exe "norm! o\".a:chars diff --git a/src/testdir/test_float_func.vim b/src/testdir/test_float_func.vim index 6340b538f5..f407f40eb0 100644 --- a/src/testdir/test_float_func.vim +++ b/src/testdir/test_float_func.vim @@ -1,8 +1,7 @@ " test float functions -if !has('float') - throw 'Skipped, float feature missing' -end +source check.vim +CheckFeature float func Test_abs() call assert_equal('1.23', string(abs(1.23))) diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index d030a6ae6a..7f94e6a8d9 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -2,7 +2,7 @@ source shared.vim if !CanRunGui() - throw 'Skipped, cannot run GUI' + throw 'Skipped: cannot run GUI' endif source setup_gui.vim diff --git a/src/testdir/test_gui_init.vim b/src/testdir/test_gui_init.vim index a8eefa56b9..ecc8fc9efe 100644 --- a/src/testdir/test_gui_init.vim +++ b/src/testdir/test_gui_init.vim @@ -3,7 +3,7 @@ source shared.vim if !CanRunGui() - throw 'Skipped, cannot run GUI' + throw 'Skipped: cannot run GUI' endif source setup_gui.vim diff --git a/src/testdir/test_history.vim b/src/testdir/test_history.vim index 4b464137bb..215fc0a55a 100644 --- a/src/testdir/test_history.vim +++ b/src/testdir/test_history.vim @@ -1,8 +1,7 @@ " Tests for the history functions -if !has('cmdline_hist') - throw 'Skipped, cmdline_hist feature missing' -endif +source check.vim +CheckFeature cmdline_hist set history=7 diff --git a/src/testdir/test_langmap.vim b/src/testdir/test_langmap.vim index 4b260f8480..420ff0fe8a 100644 --- a/src/testdir/test_langmap.vim +++ b/src/testdir/test_langmap.vim @@ -1,8 +1,7 @@ " tests for 'langmap' -if !has('langmap') - throw 'Skipped, langmap feature missing' -endif +source check.vim +CheckFeature langmap func Test_langmap() new diff --git a/src/testdir/test_listlbr.vim b/src/testdir/test_listlbr.vim index 5af4133ec8..a2abc93b7e 100644 --- a/src/testdir/test_listlbr.vim +++ b/src/testdir/test_listlbr.vim @@ -3,12 +3,9 @@ set encoding=latin1 scriptencoding latin1 -if !exists("+linebreak") - throw 'Skipped, linebreak option missing' -endif -if !has("conceal") - throw 'Skipped, conceal feature missing' -endif +source check.vim +CheckOption linebreak +CheckFeature conceal source view_util.vim diff --git a/src/testdir/test_listlbr_utf8.vim b/src/testdir/test_listlbr_utf8.vim index 1154d6626b..ddce6f36d6 100644 --- a/src/testdir/test_listlbr_utf8.vim +++ b/src/testdir/test_listlbr_utf8.vim @@ -3,15 +3,10 @@ set encoding=utf-8 scriptencoding utf-8 -if !exists("+linebreak") - throw 'Skipped, linebreak option missing' -endif -if !has("conceal") - throw 'Skipped, conceal feature missing' -endif -if !has("signs") - throw 'Skipped, signs feature missing' -endif +source check.vim +CheckOption linebreak +CheckFeature conceal +CheckFeature signs source view_util.vim diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index 5d2f088e3f..65753dc4a6 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -1,8 +1,7 @@ " Tests for Lua. -if !has('lua') - throw 'Skipped, lua feature missing' -endif +source check.vim +CheckFeature lua func TearDown() " Run garbage collection after each test to exercise luaV_setref(). diff --git a/src/testdir/test_makeencoding.vim b/src/testdir/test_makeencoding.vim index 6de3c706f3..09d36eac9a 100644 --- a/src/testdir/test_makeencoding.vim +++ b/src/testdir/test_makeencoding.vim @@ -4,7 +4,7 @@ source shared.vim let s:python = PythonProg() if s:python == '' - throw 'Skipped, python program missing' + throw 'Skipped: python program missing' endif let s:script = 'test_makeencoding.py' diff --git a/src/testdir/test_matchadd_conceal.vim b/src/testdir/test_matchadd_conceal.vim index a7c8b06f53..6684378f66 100644 --- a/src/testdir/test_matchadd_conceal.vim +++ b/src/testdir/test_matchadd_conceal.vim @@ -1,8 +1,7 @@ " Test for matchadd() and conceal feature -if !has('conceal') - throw 'Skipped, conceal feature missing' -endif +source check.vim +CheckFeature conceal if !has('gui_running') && has('unix') set term=ansi diff --git a/src/testdir/test_matchadd_conceal_utf8.vim b/src/testdir/test_matchadd_conceal_utf8.vim index fb275777da..98ed2cbe60 100644 --- a/src/testdir/test_matchadd_conceal_utf8.vim +++ b/src/testdir/test_matchadd_conceal_utf8.vim @@ -1,8 +1,7 @@ " Test for matchadd() and conceal feature using utf-8. -if !has('conceal') - throw 'Skipped, conceal feature missing' -endif +source check.vim +CheckFeature conceal if !has('gui_running') && has('unix') set term=ansi diff --git a/src/testdir/test_memory_usage.vim b/src/testdir/test_memory_usage.vim index 519ac4b9a3..b51a110e01 100644 --- a/src/testdir/test_memory_usage.vim +++ b/src/testdir/test_memory_usage.vim @@ -1,15 +1,15 @@ " Tests for memory usage. -if !has('terminal') - throw 'Skipped, terminal feature missing' -endif +source check.vim +CheckFeature terminal + if has('gui_running') - throw 'Skipped, does not work in GUI' + throw 'Skipped: does not work in GUI' endif if execute('version') =~# '-fsanitize=[a-z,]*\' " Skip tests on Travis CI ASAN build because it's difficult to estimate " memory usage. - throw 'Skipped, does not work with ASAN' + throw 'Skipped: does not work with ASAN' endif source shared.vim @@ -20,7 +20,7 @@ endfunc if has('win32') if !executable('wmic') - throw 'Skipped, wmic program missing' + throw 'Skipped: wmic program missing' endif func s:memory_usage(pid) abort let cmd = printf('wmic process where processid=%d get WorkingSetSize', a:pid) @@ -28,13 +28,13 @@ if has('win32') endfunc elseif has('unix') if !executable('ps') - throw 'Skipped, ps program missing' + throw 'Skipped: ps program missing' endif func s:memory_usage(pid) abort return s:pick_nr(system('ps -o rss= -p ' . a:pid)) endfunc else - throw 'Skipped, not win32 or unix' + throw 'Skipped: not win32 or unix' endif " Wait for memory usage to level off. diff --git a/src/testdir/test_menu.vim b/src/testdir/test_menu.vim index 99f888af19..efbb982b04 100644 --- a/src/testdir/test_menu.vim +++ b/src/testdir/test_menu.vim @@ -1,8 +1,7 @@ " Test that the system menu can be loaded. -if !has('menu') - throw 'Skipped, menu feature missing' -endif +source check.vim +CheckFeature menu func Test_load_menu() try diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim index ee2d148c67..e7aa25ca7a 100644 --- a/src/testdir/test_mksession.vim +++ b/src/testdir/test_mksession.vim @@ -3,9 +3,8 @@ set encoding=latin1 scriptencoding latin1 -if !has('mksession') - throw 'Skipped, mksession feature missing' -endif +source check.vim +CheckFeature mksession source shared.vim diff --git a/src/testdir/test_mksession_utf8.vim b/src/testdir/test_mksession_utf8.vim index 6bf5823ce8..7d9a909cac 100644 --- a/src/testdir/test_mksession_utf8.vim +++ b/src/testdir/test_mksession_utf8.vim @@ -3,9 +3,8 @@ set encoding=utf-8 scriptencoding utf-8 -if !has('mksession') - throw 'Skipped, mksession feature missing' -endif +source check.vim +CheckFeature mksession func Test_mksession_utf8() tabnew diff --git a/src/testdir/test_netbeans.vim b/src/testdir/test_netbeans.vim index 836bddff3c..690ac673c1 100644 --- a/src/testdir/test_netbeans.vim +++ b/src/testdir/test_netbeans.vim @@ -1,14 +1,13 @@ " Test the netbeans interface. -if !has('netbeans_intg') - throw 'Skipped, netbeans_intg feature missing' -endif +source check.vim +CheckFeature netbeans_intg source shared.vim let s:python = PythonProg() if s:python == '' - throw 'Skipped, python program missing' + throw 'Skipped: python program missing' endif " Run "testfunc" after sarting the server and stop the server afterwards. diff --git a/src/testdir/test_paste.vim b/src/testdir/test_paste.vim index ee69641538..a22e8e505e 100644 --- a/src/testdir/test_paste.vim +++ b/src/testdir/test_paste.vim @@ -2,10 +2,10 @@ " Bracketed paste only works with "xterm". Not in GUI or Windows console. if has('win32') - throw 'Skipped, does not work on MS-Windows' + throw 'Skipped: does not work on MS-Windows' endif if has('gui_running') - throw 'Skipped, does not work in the GUI' + throw 'Skipped: does not work in the GUI' endif set term=xterm diff --git a/src/testdir/test_perl.vim b/src/testdir/test_perl.vim index d38fc07982..8f23f2c136 100644 --- a/src/testdir/test_perl.vim +++ b/src/testdir/test_perl.vim @@ -1,8 +1,7 @@ " Tests for Perl interface -if !has('perl') - throw 'Skipped, perl feature missing' -end +source check.vim +CheckFeature perl " FIXME: RunTest don't see any error when Perl abort... perl $SIG{__WARN__} = sub { die "Unexpected warnings from perl: @_" }; diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index d9b0b295f7..a3f2046f4c 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1,8 +1,7 @@ " Tests for popup windows -if !has('textprop') - throw 'Skipped: textprop feature missing' -endif +source check.vim +CheckFeature textprop source screendump.vim @@ -515,7 +514,7 @@ endfunc func Test_popup_time() if !has('timers') - throw 'Skipped, timer feature not supported' + throw 'Skipped: timer feature not supported' endif topleft vnew call setline(1, 'hello') @@ -1176,7 +1175,7 @@ endfunc func Test_notifications() if !has('timers') - throw 'Skipped, timer feature not supported' + throw 'Skipped: timer feature not supported' endif if !CanRunVimInTerminal() throw 'Skipped: cannot make screendumps' diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim index ddabe3a953..babed36dbd 100644 --- a/src/testdir/test_profile.vim +++ b/src/testdir/test_profile.vim @@ -1,8 +1,7 @@ " Test Vim profiler -if !has('profile') - throw 'Skipped, profile feature missing' -endif +source check.vim +CheckFeature profile func Test_profile_func() let lines =<< trim [CODE] diff --git a/src/testdir/test_prompt_buffer.vim b/src/testdir/test_prompt_buffer.vim index 5cf65d5135..58be50bcbf 100644 --- a/src/testdir/test_prompt_buffer.vim +++ b/src/testdir/test_prompt_buffer.vim @@ -1,8 +1,7 @@ " Tests for setting 'buftype' to "prompt" -if !has('channel') - throw 'Skipped, channel feature missing' -endif +source check.vim +CheckFeature channel source shared.vim source screendump.vim diff --git a/src/testdir/test_python2.vim b/src/testdir/test_python2.vim index 5b10852288..61cf959bad 100644 --- a/src/testdir/test_python2.vim +++ b/src/testdir/test_python2.vim @@ -1,9 +1,8 @@ " Test for python 2 commands. " TODO: move tests from test87.in here. -if !has('python') - throw 'Skipped, python feature missing' -endif +source check.vim +CheckFeature python func Test_pydo() " Check deleting lines does not trigger ml_get error. diff --git a/src/testdir/test_python3.vim b/src/testdir/test_python3.vim index e001360e75..7f48619209 100644 --- a/src/testdir/test_python3.vim +++ b/src/testdir/test_python3.vim @@ -1,9 +1,8 @@ " Test for python 3 commands. " TODO: move tests from test88.in here. -if !has('python3') - throw 'Skipped, python3 feature missing' -endif +source check.vim +CheckFeature python3 func Test_py3do() " Check deleting lines does not trigger an ml_get error. diff --git a/src/testdir/test_pyx2.vim b/src/testdir/test_pyx2.vim index 64bd579c26..40e93c227b 100644 --- a/src/testdir/test_pyx2.vim +++ b/src/testdir/test_pyx2.vim @@ -1,9 +1,8 @@ " Test for pyx* commands and functions with Python 2. set pyx=2 -if !has('python') - throw 'Skipped, python feature missing' -endif +source check.vim +CheckFeature python let s:py2pattern = '^2\.[0-7]\.\d\+' let s:py3pattern = '^3\.\d\+\.\d\+' diff --git a/src/testdir/test_pyx3.vim b/src/testdir/test_pyx3.vim index 1b7bdae793..5dfa6cd21c 100644 --- a/src/testdir/test_pyx3.vim +++ b/src/testdir/test_pyx3.vim @@ -1,9 +1,8 @@ " Test for pyx* commands and functions with Python 3. set pyx=3 -if !has('python3') - throw 'Skipped, python3 feature missing' -endif +source check.vim +CheckFeature python3 let s:py2pattern = '^2\.[0-7]\.\d\+' let s:py3pattern = '^3\.\d\+\.\d\+' diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 2fa28c9947..7d85f629be 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -1,8 +1,7 @@ " Test for the quickfix feature. -if !has('quickfix') - throw 'Skipped, quickfix feature missing' -endif +source check.vim +CheckFeature quickfix set encoding=utf-8 diff --git a/src/testdir/test_quotestar.vim b/src/testdir/test_quotestar.vim index b6dab6b571..d21ab35fcc 100644 --- a/src/testdir/test_quotestar.vim +++ b/src/testdir/test_quotestar.vim @@ -2,7 +2,7 @@ source shared.vim if !WorkingClipboard() - throw 'Skipped, no working clipboard' + throw 'Skipped: no working clipboard' endif source shared.vim diff --git a/src/testdir/test_reltime.vim b/src/testdir/test_reltime.vim index 1876539103..404ea3f7aa 100644 --- a/src/testdir/test_reltime.vim +++ b/src/testdir/test_reltime.vim @@ -1,11 +1,8 @@ " Tests for reltime() -if !has('reltime') - throw 'Skipped, reltime feature missing' -endif -if !has('float') - throw 'Skipped, float feature missing' -endif +source check.vim +CheckFeature reltime +CheckFeature float func Test_reltime() let now = reltime() diff --git a/src/testdir/test_ruby.vim b/src/testdir/test_ruby.vim index dcfdc62448..f679bbd5f4 100644 --- a/src/testdir/test_ruby.vim +++ b/src/testdir/test_ruby.vim @@ -1,8 +1,7 @@ " Tests for ruby interface -if !has('ruby') - throw 'Skipped, ruby feature missing' -end +source check.vim +CheckFeature ruby func Test_ruby_change_buffer() call setline(line('$'), ['1 line 1']) diff --git a/src/testdir/test_sha256.vim b/src/testdir/test_sha256.vim index 7f802b143b..d0f92b1bad 100644 --- a/src/testdir/test_sha256.vim +++ b/src/testdir/test_sha256.vim @@ -1,11 +1,8 @@ " Tests for the sha256() function. -if !has('cryptv') - throw 'Skipped, cryptv feature missing' -endif -if !exists('*sha256') - throw 'Skipped, sha256 function missing' -endif +source check.vim +CheckFeature cryptv +CheckFunction sha256 function Test_sha256() " test for empty string: diff --git a/src/testdir/test_shortpathname.vim b/src/testdir/test_shortpathname.vim index 564cd96123..2d48f4b715 100644 --- a/src/testdir/test_shortpathname.vim +++ b/src/testdir/test_shortpathname.vim @@ -2,7 +2,7 @@ " Only for use on Win32 systems! if !has('win32') - throw 'Skipped, not on MS-Windows' + throw 'Skipped: not on MS-Windows' endif func TestIt(file, bits, expected) diff --git a/src/testdir/test_signals.vim b/src/testdir/test_signals.vim index 365958a387..44732df88d 100644 --- a/src/testdir/test_signals.vim +++ b/src/testdir/test_signals.vim @@ -1,7 +1,7 @@ " Test signal handling. if !has('unix') - throw 'Skipped, not on Unix' + throw 'Skipped: not on Unix' endif source shared.vim diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim index 4a23e4ba1b..3b17eccf07 100644 --- a/src/testdir/test_signs.vim +++ b/src/testdir/test_signs.vim @@ -1,8 +1,7 @@ " Test for signs -if !has('signs') - throw 'Skipped, signs feature missing' -endif +source check.vim +CheckFeature signs func Test_sign() new diff --git a/src/testdir/test_spell.vim b/src/testdir/test_spell.vim index 72599fdc13..48bc3b3e2e 100644 --- a/src/testdir/test_spell.vim +++ b/src/testdir/test_spell.vim @@ -1,8 +1,7 @@ " Test spell checking -if !has('spell') - throw 'Skipped, spell feature missing' -endif +source check.vim +CheckFeature spell func TearDown() set nospell diff --git a/src/testdir/test_syntax.vim b/src/testdir/test_syntax.vim index 8d9d7d35c1..c9808bec4f 100644 --- a/src/testdir/test_syntax.vim +++ b/src/testdir/test_syntax.vim @@ -1,8 +1,7 @@ " Test for syntax and syntax iskeyword option -if !has("syntax") - throw 'Skipped, syntax feature missing' -endif +source check.vim +CheckFeature syntax source view_util.vim source screendump.vim diff --git a/src/testdir/test_tcl.vim b/src/testdir/test_tcl.vim index 8ccd34c6b6..9923a2e332 100644 --- a/src/testdir/test_tcl.vim +++ b/src/testdir/test_tcl.vim @@ -1,8 +1,7 @@ " Tests for the Tcl interface. -if !has('tcl') - throw 'Skipped, tcl feature missing' -end +source check.vim +CheckFeature tcl " Helper function as there is no builtin tcleval() function similar " to perleval, luaevel(), pyeval(), etc. diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index 9d7f6b5fa7..c6327db6ac 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -2,10 +2,10 @@ " This only works for Unix in a terminal if has('gui_running') - throw 'Skipped, does not work in the GUI' + throw 'Skipped: does not work in the GUI' endif if !has('unix') - throw 'Skipped, not on Unix' + throw 'Skipped: not on Unix' endif source shared.vim diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 09c050aada..f1cd7da33d 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1,8 +1,7 @@ " Tests for the terminal window. -if !has('terminal') - throw 'Skipped, terminal feature missing' -endif +source check.vim +CheckFeature terminal source shared.vim source screendump.vim diff --git a/src/testdir/test_terminal_fail.vim b/src/testdir/test_terminal_fail.vim index d010c3b8f1..f33ade6342 100644 --- a/src/testdir/test_terminal_fail.vim +++ b/src/testdir/test_terminal_fail.vim @@ -2,9 +2,8 @@ " leaks under valgrind. That is because when fork/exec fails memory is not " freed. Since the process exists right away it's not a real leak. -if !has('terminal') - throw 'Skipped, terminal feature missing' -endif +source check.vim +CheckFeature terminal source shared.vim diff --git a/src/testdir/test_textobjects.vim b/src/testdir/test_textobjects.vim index 5366a35fba..a3e3851f42 100644 --- a/src/testdir/test_textobjects.vim +++ b/src/testdir/test_textobjects.vim @@ -1,8 +1,7 @@ " Test for textobjects -if !has('textobjects') - throw 'Skipped, textobjects feature missing' -endif +source check.vim +CheckFeature textobjects func CpoM(line, useM, expected) new diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim index cb27f5877c..08c079cfa4 100644 --- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -1,9 +1,8 @@ " Tests for defining text property types and adding text properties to the " buffer. -if !has('textprop') - throw 'Skipped, textprop feature missing' -endif +source check.vim +CheckFeature textprop source screendump.vim diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim index 5b09011c75..03391d8f52 100644 --- a/src/testdir/test_timers.vim +++ b/src/testdir/test_timers.vim @@ -1,8 +1,7 @@ " Test for timers -if !has('timers') - throw 'Skipped, timers feature missing' -endif +source check.vim +CheckFeature timers source shared.vim source screendump.vim diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim index 640aa0b305..b0f3e15aab 100644 --- a/src/testdir/test_vartabs.vim +++ b/src/testdir/test_vartabs.vim @@ -1,8 +1,7 @@ " Test for variable tabstops -if !has("vartabs") - throw 'Skipped, vartabs feature missing' -endif +source check.vim +CheckFeature vartabs source view_util.vim diff --git a/src/testdir/test_winbar.vim b/src/testdir/test_winbar.vim index 51ef0a8633..5e4366717a 100644 --- a/src/testdir/test_winbar.vim +++ b/src/testdir/test_winbar.vim @@ -1,8 +1,7 @@ " Test WinBar -if !has('menu') - throw 'Skipped, menu feature missing' -endif +source check.vim +CheckFeature menu source shared.vim diff --git a/src/testdir/test_windows_home.vim b/src/testdir/test_windows_home.vim index da95ed27c8..8ac9ce0fde 100644 --- a/src/testdir/test_windows_home.vim +++ b/src/testdir/test_windows_home.vim @@ -1,7 +1,7 @@ " Test for $HOME on Windows. if !has('win32') - throw 'Skipped, not on MS-Windows' + throw 'Skipped: not on MS-Windows' endif let s:env = {} diff --git a/src/testdir/test_xxd.vim b/src/testdir/test_xxd.vim index 63ac574abb..cf47c8a9c0 100644 --- a/src/testdir/test_xxd.vim +++ b/src/testdir/test_xxd.vim @@ -2,7 +2,7 @@ if empty($XXD) && executable('..\xxd\xxd.exe') let s:xxd_cmd = '..\xxd\xxd.exe' elseif empty($XXD) || !executable($XXD) - throw 'Skipped, xxd program missing' + throw 'Skipped: xxd program missing' else let s:xxd_cmd = $XXD endif diff --git a/src/version.c b/src/version.c index 0b036d031b..e4ef380d88 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 */ +/**/ + 1544, /**/ 1543, /**/ From 45aa07d3c126e887c614f8a4ebdb88aed673a9f1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 18:20:38 +0200 Subject: [PATCH 28/44] patch 8.1.1545: when the screen is to small there is no message about that Problem: When the screen is to small there is no message about that. (Daniel Hahler) Solution: Do not use :cquit. (closes #4534) --- src/testdir/runtest.vim | 7 +++++-- src/version.c | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index f81c76df15..45d3b1d5ef 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -38,8 +38,11 @@ if &lines < 24 || &columns < 80 echoerr error split test.log $put =error - w - cquit + write + split messages + call append(line('$'), error) + write + qa! endif if has('reltime') diff --git a/src/version.c b/src/version.c index e4ef380d88..51101f81c0 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 */ +/**/ + 1545, /**/ 1544, /**/ From 0331faf71200a274377e1569fcda4f00c9cf3e2a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 18:40:37 +0200 Subject: [PATCH 29/44] patch 8.1.1546: in some tests 'tags' is set but not restored Problem: In some tests 'tags' is set but not restored. (Daniel Hahler) Solution: Restore 'tags'. (closes #4535) --- src/testdir/test_autocmd.vim | 1 + src/testdir/test_cmdline.vim | 1 + src/testdir/test_options.vim | 1 + src/testdir/test_tagcase.vim | 1 + src/testdir/test_tagjump.vim | 5 ++++- src/testdir/test_taglist.vim | 4 ++++ src/version.c | 2 ++ 7 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 3254db8cdc..d762c91948 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -1100,6 +1100,7 @@ func Test_OptionSet() " Cleanup au! OptionSet + " set tags& for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'backupext', 'tags', 'spelllang', 'statusline', 'foldignore', 'cmdheight', 'undolevels', 'wrapmargin', 'foldcolumn', 'wrapscan', 'autoread', 'cindent', 'cursorcolumn'] exe printf(":set %s&vim", opt) endfor diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 3b275b617d..f0d83c62d0 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -378,6 +378,7 @@ func Test_getcompletion() endfor call delete('Xtags') + set tags& call assert_fails('call getcompletion("", "burp")', 'E475:') endfunc diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index 9d3065d159..e8eaef038f 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -237,6 +237,7 @@ func Test_set_completion() call feedkeys(":set tags=./\\\\ dif\\\"\", 'tx') call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:) + set tags& endfunc func Test_set_errors() diff --git a/src/testdir/test_tagcase.vim b/src/testdir/test_tagcase.vim index 83e532822d..08782b3f1b 100644 --- a/src/testdir/test_tagcase.vim +++ b/src/testdir/test_tagcase.vim @@ -44,6 +44,7 @@ func Test_tagcase() endfor call delete('Xtags') + set tags& set ic& setg tc& setl tc& diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim index 7e64ac4358..e4084b314a 100644 --- a/src/testdir/test_tagjump.vim +++ b/src/testdir/test_tagjump.vim @@ -20,6 +20,7 @@ func Test_cancel_ptjump() call assert_equal(2, winnr('$')) call delete('Xtags') + set tags& quit endfunc @@ -104,6 +105,7 @@ func Test_tagjump_switchbuf() enew | only call delete('Xfile1') call delete('Xtags') + set tags& set switchbuf&vim endfunc @@ -431,7 +433,7 @@ func Test_tagnr_recall() tag call assert_equal(bufname('%'), 'Xtest.h') - set tag& + set tags& call delete('Xtags') bwipe Xtest.h bwipe Xtest.c @@ -467,6 +469,7 @@ func Test_tag_line_toolong() endtry call assert_equal('Ignoring long line in tags file', split(execute('messages'), '\n')[-1]) call delete('Xtags') + set tags& let &verbose = old_vbs endfunc diff --git a/src/testdir/test_taglist.vim b/src/testdir/test_taglist.vim index 6506c3f1d1..9ddefc5153 100644 --- a/src/testdir/test_taglist.vim +++ b/src/testdir/test_taglist.vim @@ -30,6 +30,7 @@ func Test_taglist() call assert_equal('call cursor(3, 4)', cmd[0]['cmd']) call delete('Xtags') + set tags& bwipe endfunc @@ -50,6 +51,7 @@ func Test_taglist_native_etags() \ map(taglist('set_signals'), {i, v -> [v.name, v.cmd]})) call delete('Xtags') + set tags& endfunc func Test_taglist_ctags_etags() @@ -69,6 +71,7 @@ func Test_taglist_ctags_etags() \ map(taglist('set_signals'), {i, v -> [v.name, v.cmd]})) call delete('Xtags') + set tags& endfunc func Test_tags_too_long() @@ -110,4 +113,5 @@ func Test_tagsfile_without_trailing_newline() call assert_equal('Foo', tl[0].name) call delete('Xtags') + set tags& endfunc diff --git a/src/version.c b/src/version.c index 51101f81c0..675beb8f8c 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 */ +/**/ + 1546, /**/ 1545, /**/ From 26910de8b0da6abab87bd5a397330f9cbe483309 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 19:37:15 +0200 Subject: [PATCH 30/44] patch 8.1.1547: functionality of bt_nofile() is confusing Problem: Functionality of bt_nofile() is confusing. Solution: Split into bt_nofile() and bt_nofilename(). --- src/buffer.c | 13 +++++++++++-- src/evalfunc.c | 2 +- src/ex_cmds.c | 2 +- src/ex_docmd.c | 6 +++--- src/fileio.c | 10 +++++----- src/popupmnu.c | 2 +- src/proto/buffer.pro | 1 + src/quickfix.c | 2 +- src/version.c | 2 ++ 9 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index e6ae09d255..c3911ae2bb 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -5698,7 +5698,7 @@ bt_popup(buf_T *buf) * buffer. This means the buffer name is not a file name. */ int -bt_nofile(buf_T *buf) +bt_nofilename(buf_T *buf) { return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') || buf->b_p_bt[0] == 'a' @@ -5706,6 +5706,15 @@ bt_nofile(buf_T *buf) || buf->b_p_bt[0] == 'p'); } +/* + * Return TRUE if "buf" has 'buftype' set to "nofile". + */ + int +bt_nofile(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f'; +} + /* * Return TRUE if "buf" is a "nowrite", "nofile", "terminal" or "prompt" * buffer. @@ -5772,7 +5781,7 @@ buf_spname(buf_T *buf) /* There is no _file_ when 'buftype' is "nofile", b_sfname * contains the name as specified by the user. */ - if (bt_nofile(buf)) + if (bt_nofilename(buf)) { #ifdef FEAT_TERMINAL if (buf->b_term != NULL) diff --git a/src/evalfunc.c b/src/evalfunc.c index 0ef76095f4..544426fa6d 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1943,7 +1943,7 @@ find_buffer(typval_T *avar) if (buf->b_fname != NULL && (path_with_url(buf->b_fname) #ifdef FEAT_QUICKFIX - || bt_nofile(buf) + || bt_nofilename(buf) #endif ) && STRCMP(buf->b_fname, avar->vval.v_string) == 0) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index d7a4187b86..d1068c7cff 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -3399,7 +3399,7 @@ check_overwrite( || (buf->b_flags & BF_READERR)) && !p_wa #ifdef FEAT_QUICKFIX - && !bt_nofile(buf) + && !bt_nofilename(buf) #endif && vim_fexists(ffname)) { diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 91ced52a5f..438cb355aa 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -9909,7 +9909,7 @@ makeopens( && wp->w_buffer->b_ffname != NULL && !bt_help(wp->w_buffer) #ifdef FEAT_QUICKFIX - && !bt_nofile(wp->w_buffer) + && !bt_nofilename(wp->w_buffer) #endif ) { @@ -10236,7 +10236,7 @@ ses_do_win(win_T *wp) if (wp->w_buffer->b_fname == NULL #ifdef FEAT_QUICKFIX /* When 'buftype' is "nofile" can't restore the window contents. */ - || bt_nofile(wp->w_buffer) + || bt_nofilename(wp->w_buffer) #endif ) return (ssop_flags & SSOP_BLANK); @@ -10323,7 +10323,7 @@ put_view( */ if (wp->w_buffer->b_ffname != NULL # ifdef FEAT_QUICKFIX - && !bt_nofile(wp->w_buffer) + && !bt_nofilename(wp->w_buffer) # endif ) { diff --git a/src/fileio.c b/src/fileio.c index e6fb6bfaee..03183255e3 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3160,7 +3160,7 @@ buf_write( && whole && buf == curbuf #ifdef FEAT_QUICKFIX - && !bt_nofile(buf) + && !bt_nofilename(buf) #endif && !filtering && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) @@ -3237,7 +3237,7 @@ buf_write( sfname, sfname, FALSE, curbuf, eap))) { #ifdef FEAT_QUICKFIX - if (overwriting && bt_nofile(curbuf)) + if (overwriting && bt_nofilename(curbuf)) nofile_err = TRUE; else #endif @@ -3270,7 +3270,7 @@ buf_write( else { #ifdef FEAT_QUICKFIX - if (overwriting && bt_nofile(curbuf)) + if (overwriting && bt_nofilename(curbuf)) nofile_err = TRUE; else #endif @@ -3284,7 +3284,7 @@ buf_write( sfname, sfname, FALSE, curbuf, eap))) { #ifdef FEAT_QUICKFIX - if (overwriting && bt_nofile(curbuf)) + if (overwriting && bt_nofilename(curbuf)) nofile_err = TRUE; else #endif @@ -6083,7 +6083,7 @@ shorten_buf_fname(buf_T *buf, char_u *dirname, int force) if (buf->b_fname != NULL #ifdef FEAT_QUICKFIX - && !bt_nofile(buf) + && !bt_nofilename(buf) #endif && !path_with_url(buf->b_fname) && (force diff --git a/src/popupmnu.c b/src/popupmnu.c index 09faa69e88..5fbb3bbd28 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -727,7 +727,7 @@ pum_set_selected(int n, int repeat) if (!resized && curbuf->b_nwindows == 1 && curbuf->b_fname == NULL - && curbuf->b_p_bt[0] == 'n' && curbuf->b_p_bt[2] == 'f' + && bt_nofile(curbuf) && curbuf->b_p_bh[0] == 'w') { /* Already a "wipeout" buffer, make it empty. */ diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro index 1748fb51f8..81be7e4bd0 100644 --- a/src/proto/buffer.pro +++ b/src/proto/buffer.pro @@ -62,6 +62,7 @@ int bt_terminal(buf_T *buf); int bt_help(buf_T *buf); int bt_prompt(buf_T *buf); int bt_popup(buf_T *buf); +int bt_nofilename(buf_T *buf); int bt_nofile(buf_T *buf); int bt_dontwrite(buf_T *buf); int bt_dontwrite_msg(buf_T *buf); diff --git a/src/quickfix.c b/src/quickfix.c index 290f6bcccc..d2d3302636 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4135,7 +4135,7 @@ qf_open_new_cwindow(qf_info_T *qi, int height) // Set the options for the quickfix buffer/window (if not already done) // Do this even if the quickfix buffer was already present, as an autocmd // might have previously deleted (:bdelete) the quickfix buffer. - if (curbuf->b_p_bt[0] != 'q') + if (bt_quickfix(curbuf)) qf_set_cwindow_options(); // Only set the height when still in the same tab page and there is no diff --git a/src/version.c b/src/version.c index 675beb8f8c..113fb97ce0 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 */ +/**/ + 1547, /**/ 1546, /**/ From a42d945efc60e6130c15f72b5a5aa9fd2b63241a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 21:46:30 +0200 Subject: [PATCH 31/44] patch 8.1.1548: popup_dialog() is not implemented Problem: Popup_dialog() is not implemented. Solution: Implement popup_dialog() and popup_filter_yesno(). --- runtime/doc/popup.txt | 32 +++++--- src/evalfunc.c | 2 + src/globals.h | 3 +- src/popupwin.c | 149 +++++++++++++++++++++++++++------- src/proto/popupwin.pro | 2 + src/structs.h | 3 +- src/testdir/test_popupwin.vim | 30 +++++++ src/version.c | 2 + 8 files changed, 177 insertions(+), 46 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 3ee92f2698..a9f55be279 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -103,10 +103,10 @@ TODO: - When drawing on top half a double-wide character, display ">" or "<" in the incomplete cell. - Can the buffer be re-used, to avoid using up lots of buffer numbers? +- Use a popup window for the "info" item of completion instead of using a + preview window. - Implement: - popup_dialog({text}, {options}) popup_filter_menu({id}, {key}) - popup_filter_yesno({id}, {key}) popup_menu({text}, {options}) popup_setoptions({id}, {options}) flip option @@ -196,16 +196,23 @@ popup_create({text}, {options}) *popup_create()* popup_dialog({text}, {options}) *popup_dialog()* - {not implemented yet} Just like |popup_create()| but with these default options: > call popup_create({text}, { \ 'pos': 'center', \ 'zindex': 200, + \ 'drag': 1, \ 'border': [], \ 'padding': [], \}) < Use {options} to change the properties. E.g. add a 'filter' - option with value 'popup_filter_yesno'. + option with value 'popup_filter_yesno'. Example: > + call popup_create('do you want to quit (Yes/no)?', { + \ 'filter': 'popup_filter_yesno', + \ 'callback': 'QuitCallback', + \ }) + +< By default the dialog can be dragged, so that text below it + can be read if needed. popup_filter_menu({id}, {key}) *popup_filter_menu()* @@ -218,12 +225,12 @@ popup_filter_menu({id}, {key}) *popup_filter_menu()* popup_filter_yesno({id}, {key}) *popup_filter_yesno()* - {not implemented yet} Filter that can be used for a popup. It handles only the keys 'y', 'Y' and 'n' or 'N'. Invokes the "callback" of the popup menu with the 1 for 'y' or 'Y' and zero for 'n' or 'N' - as the second argument. Pressing Esc and CTRL-C works like - pressing 'n'. Other keys are ignored. + as the second argument. Pressing Esc and 'x' works like + pressing 'n'. CTRL-C invokes the callback with -1. Other + keys are ignored. popup_getoptions({id}) *popup_getoptions()* @@ -301,7 +308,7 @@ popup_notification({text}, {options}) *popup_notification()* \ 'minwidth': 20, \ 'time': 3000, \ 'tabpage': -1, - \ 'zindex': 200, + \ 'zindex': 300, \ 'drag': 1, \ 'highlight': 'WarningMsg', \ 'border': [], @@ -521,7 +528,7 @@ filter is also called. The filter of the popup window with the highest zindex is called first. The filter function is called with two arguments: the ID of the popup and the -key, e.g.: > +key as a string, e.g.: > func MyFilter(winid, key) if a:key == "\" " do something @@ -556,15 +563,14 @@ Vim recognizes the Esc key. If you do use Esc, it is recommended to set the POPUP CALLBACK *popup-callback* -A callback that is invoked when the popup closes. Used by -|popup_filter_menu()|. +A callback that is invoked when the popup closes. The callback is invoked with two arguments: the ID of the popup window and the result, which could be an index in the popup lines, or whatever was passed as the second argument of `popup_close()`. -If the popup is closed because the cursor moved, the number -1 is passed to -the callback. +If the popup is force-closed, e.g. because the cursor moved or CTRL-C was +pressed, the number -1 is passed to the callback. ============================================================================== 3. Examples *popup-examples* diff --git a/src/evalfunc.c b/src/evalfunc.c index 544426fa6d..d371c28b66 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -815,6 +815,8 @@ static struct fst {"popup_clear", 0, 0, f_popup_clear}, {"popup_close", 1, 2, f_popup_close}, {"popup_create", 2, 2, f_popup_create}, + {"popup_dialog", 2, 2, f_popup_dialog}, + {"popup_filter_yesno", 2, 2, f_popup_filter_yesno}, {"popup_getoptions", 1, 1, f_popup_getoptions}, {"popup_getpos", 1, 1, f_popup_getpos}, {"popup_hide", 1, 1, f_popup_hide}, diff --git a/src/globals.h b/src/globals.h index 992ce2a543..ec42984944 100644 --- a/src/globals.h +++ b/src/globals.h @@ -599,7 +599,8 @@ EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */ EXTERN int aucmd_win_used INIT(= FALSE); /* aucmd_win is being used */ #ifdef FEAT_TEXT_PROP -EXTERN win_T *first_popupwin; // first global popup window +EXTERN win_T *first_popupwin; // first global popup window +EXTERN win_T *popup_dragwin INIT(= NULL); // popup window being dragged #endif /* diff --git a/src/popupwin.c b/src/popupwin.c index aeed2e79b4..adbc729149 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -201,6 +201,10 @@ popup_start_drag(win_T *wp) drag_start_wantcol = wp->w_wincol + 1; else drag_start_wantcol = wp->w_wantcol; + + // Stop centering the popup + if (wp->w_popup_pos == POPPOS_CENTER) + wp->w_popup_pos = POPPOS_TOPLEFT; } /* @@ -301,7 +305,9 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) wp->w_p_wrap = nr != 0; } - wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag"); + di = dict_find(dict, (char_u *)"drag", -1); + if (di != NULL) + wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag"); di = dict_find(dict, (char_u *)"callback", -1); if (di != NULL) @@ -692,13 +698,13 @@ typedef enum { TYPE_NORMAL, TYPE_ATCURSOR, - TYPE_NOTIFICATION + TYPE_NOTIFICATION, + TYPE_DIALOG } create_type_T; /* * popup_create({text}, {options}) * popup_atcursor({text}, {options}) - * When called from f_popup_atcursor() "type" is TYPE_ATCURSOR. */ static void popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) @@ -871,6 +877,20 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) OPT_FREE|OPT_LOCAL, 0); } + if (type == TYPE_DIALOG) + { + int i; + + wp->w_popup_pos = POPPOS_CENTER; + wp->w_zindex = POPUPWIN_DIALOG_ZINDEX; + wp->w_popup_drag = 1; + for (i = 0; i < 4; ++i) + { + wp->w_popup_border[i] = 1; + wp->w_popup_padding[i] = 1; + } + } + // Deal with options. apply_options(wp, buf, argvars[1].vval.v_dict); @@ -912,33 +932,6 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv) popup_create(argvars, rettv, TYPE_ATCURSOR); } -/* - * popup_notification({text}, {options}) - */ - void -f_popup_notification(typval_T *argvars, typval_T *rettv) -{ - popup_create(argvars, rettv, TYPE_NOTIFICATION); -} - -/* - * Find the popup window with window-ID "id". - * If the popup window does not exist NULL is returned. - * If the window is not a popup window, and error message is given. - */ - static win_T * -find_popup_win(int id) -{ - win_T *wp = win_id2wp(id); - - if (wp != NULL && !bt_popup(wp->w_buffer)) - { - semsg(_("E993: window %d is not a popup window"), id); - return NULL; - } - return wp; -} - /* * Invoke the close callback for window "wp" with value "result". * Careful: The callback may make "wp" invalid! @@ -985,6 +978,90 @@ popup_close_and_callback(win_T *wp, typval_T *arg) popup_close(id); } +/* + * popup_filter_yesno({text}, {options}) + */ + void +f_popup_filter_yesno(typval_T *argvars, typval_T *rettv) +{ + int id = tv_get_number(&argvars[0]); + win_T *wp = win_id2wp(id); + char_u *key = tv_get_string(&argvars[1]); + typval_T res; + + // If the popup has been closed don't consume the key. + if (wp == NULL) + return; + + // consume all keys until done + rettv->vval.v_number = 1; + + if (STRCMP(key, "y") == 0 || STRCMP(key, "Y") == 0) + res.vval.v_number = 1; + else if (STRCMP(key, "n") == 0 || STRCMP(key, "N") == 0 + || STRCMP(key, "x") == 0 || STRCMP(key, "X") == 0 + || STRCMP(key, "\x1b") == 0) + res.vval.v_number = 0; + else + { + int c = *key; + int row = mouse_row; + int col = mouse_col; + + if (c == K_SPECIAL && key[1] != NUL) + c = TO_SPECIAL(key[1], key[2]); + if (wp->w_popup_drag + && is_mouse_key(c) + && (wp == popup_dragwin + || wp == mouse_find_win(&row, &col, FIND_POPUP))) + // allow for dragging the popup + rettv->vval.v_number = 0; + + // ignore this key + return; + } + + // Invoke callback + res.v_type = VAR_NUMBER; + popup_close_and_callback(wp, &res); +} + +/* + * popup_dialog({text}, {options}) + */ + void +f_popup_dialog(typval_T *argvars, typval_T *rettv) +{ + popup_create(argvars, rettv, TYPE_DIALOG); +} + +/* + * popup_notification({text}, {options}) + */ + void +f_popup_notification(typval_T *argvars, typval_T *rettv) +{ + popup_create(argvars, rettv, TYPE_NOTIFICATION); +} + +/* + * Find the popup window with window-ID "id". + * If the popup window does not exist NULL is returned. + * If the window is not a popup window, and error message is given. + */ + static win_T * +find_popup_win(int id) +{ + win_T *wp = win_id2wp(id); + + if (wp != NULL && !bt_popup(wp->w_buffer)) + { + semsg(_("E993: window %d is not a popup window"), id); + return NULL; + } + return wp; +} + /* * popup_close({id}) */ @@ -1299,6 +1376,15 @@ invoke_popup_filter(win_T *wp, int c) typval_T argv[3]; char_u buf[NUMBUFLEN]; + // Emergency exit: CTRL-C closes the popup. + if (c == Ctrl_C) + { + rettv.v_type = VAR_NUMBER; + rettv.vval.v_number = -1; + popup_close_and_callback(wp, &rettv); + return 1; + } + argv[0].v_type = VAR_NUMBER; argv[0].vval.v_number = (varnumber_T)wp->w_id; @@ -1310,6 +1396,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. call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL); res = tv_get_number(&rettv); @@ -1326,7 +1413,7 @@ invoke_popup_filter(win_T *wp, int c) popup_do_filter(int c) { int res = FALSE; - win_T *wp; + win_T *wp; popup_reset_handled(); diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index cde0cae6e8..6e93791e61 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -8,6 +8,8 @@ void popup_adjust_position(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); +void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv); +void f_popup_dialog(typval_T *argvars, typval_T *rettv); void f_popup_notification(typval_T *argvars, typval_T *rettv); void f_popup_close(typval_T *argvars, typval_T *rettv); void f_popup_hide(typval_T *argvars, typval_T *rettv); diff --git a/src/structs.h b/src/structs.h index 59259274a1..09158a0cc5 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1998,7 +1998,8 @@ typedef enum { # define POPUPWIN_DEFAULT_ZINDEX 50 # define POPUPMENU_ZINDEX 100 -# define POPUPWIN_NOTIFICATION_ZINDEX 200 +# define POPUPWIN_DIALOG_ZINDEX 200 +# define POPUPWIN_NOTIFICATION_ZINDEX 300 #endif /* diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index a3f2046f4c..f7a319c23f 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -870,6 +870,36 @@ func Test_popup_filter() call popup_clear() endfunc +func ShowDialog(key, result) + let s:cb_res = 999 + let winid = popup_dialog('do you want to quit (Yes/no)?', { + \ 'filter': 'popup_filter_yesno', + \ 'callback': 'QuitCallback', + \ }) + redraw + call feedkeys(a:key, "xt") + call assert_equal(winid, s:cb_winid) + call assert_equal(a:result, s:cb_res) +endfunc + +func Test_popup_dialog() + func QuitCallback(id, res) + let s:cb_winid = a:id + let s:cb_res = a:res + endfunc + + let winid = ShowDialog("y", 1) + let winid = ShowDialog("Y", 1) + let winid = ShowDialog("n", 0) + let winid = ShowDialog("N", 0) + let winid = ShowDialog("x", 0) + let winid = ShowDialog("X", 0) + let winid = ShowDialog("\", 0) + let winid = ShowDialog("\", -1) + + delfunc QuitCallback +endfunc + func Test_popup_close_callback() func PopupDone(id, result) let g:result = a:result diff --git a/src/version.c b/src/version.c index 113fb97ce0..9d457038e1 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 */ +/**/ + 1548, /**/ 1547, /**/ From 61eeeea8e6455b1f36905c45a62ea8414f2f1dab Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 21:56:17 +0200 Subject: [PATCH 32/44] patch 8.1.1549: quickfix test fails Problem: Quickfix test fails. Solution: Negate result of bt_quickfix(). --- src/quickfix.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quickfix.c b/src/quickfix.c index d2d3302636..8c25915326 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4135,7 +4135,7 @@ qf_open_new_cwindow(qf_info_T *qi, int height) // Set the options for the quickfix buffer/window (if not already done) // Do this even if the quickfix buffer was already present, as an autocmd // might have previously deleted (:bdelete) the quickfix buffer. - if (bt_quickfix(curbuf)) + if (!bt_quickfix(curbuf)) qf_set_cwindow_options(); // Only set the height when still in the same tab page and there is no diff --git a/src/version.c b/src/version.c index 9d457038e1..4d491737b4 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 */ +/**/ + 1549, /**/ 1548, /**/ From 51c313104096c7af5024aebbf295f7f03486874b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 22:27:23 +0200 Subject: [PATCH 33/44] patch 8.1.1550: when a popup has left padding text may be cut off Problem: When a popup has left padding text may be cut off. Solution: Add the border and padding when computing the size. --- src/popupwin.c | 7 ++++--- src/testdir/dumps/Test_popupwin_20.dump | 10 +++++----- src/testdir/dumps/Test_popupwin_21.dump | 10 +++++----- src/testdir/test_popupwin.vim | 2 ++ src/version.c | 2 ++ 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index adbc729149..c0b5e1300c 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -588,7 +588,7 @@ popup_adjust_position(win_T *wp) // When centering or right aligned, use maximum width. // 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; + maxwidth = Columns - wp->w_wincol - left_extra; if (wp->w_maxwidth > 0 && maxwidth > wp->w_maxwidth) { allow_adjust_left = FALSE; @@ -622,11 +622,12 @@ popup_adjust_position(win_T *wp) || wp->w_popup_pos == POPPOS_BOTLEFT)) { // adjust leftwise to fit text on screen - int shift_by = ( len - maxwidth ); + int shift_by = len - maxwidth; - if ( shift_by > wp->w_wincol ) + if (shift_by > wp->w_wincol) { int truncate_shift = shift_by - wp->w_wincol; + len -= truncate_shift; shift_by -= truncate_shift; } diff --git a/src/testdir/dumps/Test_popupwin_20.dump b/src/testdir/dumps/Test_popupwin_20.dump index 237b1de8d3..14487ffb3e 100644 --- a/src/testdir/dumps/Test_popupwin_20.dump +++ b/src/testdir/dumps/Test_popupwin_20.dump @@ -5,11 +5,11 @@ |5| @40||+0#0000001#ffd7ff255| @11||| +0#0000000#ffffff0@18 |6| |++0#0000001#ffd7ff255|-@8| +0#0000000#ffffff0@9| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@4|++0#0000001#ffd7ff255|-@11|+| +0#0000000#ffffff0@18 |7| ||+0#0000001#ffd7ff255|b|o|r|d|e|r| |T|L| +0#0000000#ffffff0@9| +0#0000001#ffd7ff255@3|p|a|d@1|i|n|g|s| @2| +0#0000000#ffffff0@37 -|8| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@37 -|9| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@37 -|1|0| @72 -|1@1| @72 -|1|2| @72 +|8| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@16||+0#0000001#ffd7ff255| @2|w|r|a|p@1|e|d| |l|o|n|g|e|r| |t|e +|9+0#0000000#ffffff0| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@16||+0#0000001#ffd7ff255| @2|x|t| @14 +|1+0#0000000#ffffff0|0| @72 +|1@1| @50||+0#0000001#ffd7ff255| @2|r|i|g|h|t| |a|l|i|g|n|e|d| |t|e|x|t +|1+0#0000000#ffffff0|2| @72 |1|3| @72 |1|4| @72 @57|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_21.dump b/src/testdir/dumps/Test_popupwin_21.dump index 836abe4e06..4a32eaa4c0 100644 --- a/src/testdir/dumps/Test_popupwin_21.dump +++ b/src/testdir/dumps/Test_popupwin_21.dump @@ -5,11 +5,11 @@ |5| @40|║+0#0000001#ffd7ff255| @11|║| +0#0000000#ffffff0@18 |6| |╔+0#0000001#ffd7ff255|═@8| +0#0000000#ffffff0@9| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@4|╚+0#0000001#ffd7ff255|═@11|╝| +0#0000000#ffffff0@18 |7| |║+0#0000001#ffd7ff255|b|o|r|d|e|r| |T|L| +0#0000000#ffffff0@9| +0#0000001#ffd7ff255@3|p|a|d@1|i|n|g|s| @2| +0#0000000#ffffff0@37 -|8| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@37 -|9| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@37 -|1|0| @72 -|1@1| @72 -|1|2| @72 +|8| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@16|║+0#0000001#ffd7ff255| @2|w|r|a|p@1|e|d| |l|o|n|g|e|r| |t|e +|9+0#0000000#ffffff0| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@16|║+0#0000001#ffd7ff255| @2|x|t| @14 +|1+0#0000000#ffffff0|0| @72 +|1@1| @50|║+0#0000001#ffd7ff255| @2|r|i|g|h|t| |a|l|i|g|n|e|d| |t|e|x|t +|1+0#0000000#ffffff0|2| @72 |1|3| @72 |1|4| @72 @57|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index f7a319c23f..ae41512be5 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -87,6 +87,8 @@ func Test_popup_with_border_and_padding() \ "call popup_create('hello both', {'line': 2, 'col': 43, 'border': [], 'padding': []})", \ "call popup_create('border TL', {'line': 6, 'col': 3, 'border': [1, 0, 0, 4]})", \ "call popup_create('paddings', {'line': 6, 'col': 23, 'padding': [1, 3, 2, 4]})", + \ "call popup_create('wrapped longer text', {'line': 8, 'col': 55, 'padding': [0, 3, 0, 3], 'border': [0, 1, 0, 1]})", + \ "call popup_create('right aligned text', {'line': 11, 'col': 56, 'wrap': 0, 'padding': [0, 3, 0, 3], 'border': [0, 1, 0, 1]})", \], 'XtestPopupBorder') let buf = RunVimInTerminal('-S XtestPopupBorder', {'rows': 15}) call VerifyScreenDump(buf, 'Test_popupwin_2' .. iter, {}) diff --git a/src/version.c b/src/version.c index 4d491737b4..96670c6fb8 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 */ +/**/ + 1550, /**/ 1549, /**/ From 6c17543b5634ccccedfbffa4993e9fbd4a990067 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 Jun 2019 23:10:30 +0200 Subject: [PATCH 34/44] patch 8.1.1551: warning for shadowing popup_dragwin Problem: Warning for shadowing popup_dragwin. (Dominique Pelle) Solution: Add missing change. --- src/ui.c | 1 - src/version.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui.c b/src/ui.c index 9e387b4cea..db878e61a1 100644 --- a/src/ui.c +++ b/src/ui.c @@ -2929,7 +2929,6 @@ jump_to_mouse( #endif #ifdef FEAT_TEXT_PROP static int in_popup_win = FALSE; - static win_T *popup_dragwin = NULL; #endif static int prev_row = -1; static int prev_col = -1; diff --git a/src/version.c b/src/version.c index 96670c6fb8..b213bda110 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 */ +/**/ + 1551, /**/ 1550, /**/ From f85e40afc204c241c6a01023be3e7b8101d36367 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 13:55:40 +0200 Subject: [PATCH 35/44] patch 8.1.1552: cursor position is wrong after sign column changes Problem: Cursor position is wrong after sign column appears or disappears. (Yegappan Lakshmanan) Solution: Call changed_line_abv_curs() instead of changed_cline_bef_curs(). --- src/sign.c | 6 ++--- src/testdir/dumps/Test_sign_cursor_01.dump | 6 +++++ src/testdir/dumps/Test_sign_cursor_02.dump | 6 +++++ src/testdir/test_signs.vim | 30 ++++++++++++++++++++++ src/version.c | 2 ++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 src/testdir/dumps/Test_sign_cursor_01.dump create mode 100644 src/testdir/dumps/Test_sign_cursor_02.dump diff --git a/src/sign.c b/src/sign.c index e8288d6283..240785385a 100644 --- a/src/sign.c +++ b/src/sign.c @@ -231,7 +231,7 @@ insert_sign( if (buf->b_signlist == NULL) { redraw_buf_later(buf, NOT_VALID); - changed_cline_bef_curs(); + changed_line_abv_curs(); } // first sign in signlist @@ -531,7 +531,7 @@ buf_delsign( if (buf->b_signlist == NULL) { redraw_buf_later(buf, NOT_VALID); - changed_cline_bef_curs(); + changed_line_abv_curs(); } return lnum; @@ -651,7 +651,7 @@ buf_delete_signs(buf_T *buf, char_u *group) if (buf->b_signlist != NULL && curwin != NULL) { redraw_buf_later(buf, NOT_VALID); - changed_cline_bef_curs(); + changed_line_abv_curs(); } lastp = &buf->b_signlist; diff --git a/src/testdir/dumps/Test_sign_cursor_01.dump b/src/testdir/dumps/Test_sign_cursor_01.dump new file mode 100644 index 0000000000..9ca4481935 --- /dev/null +++ b/src/testdir/dumps/Test_sign_cursor_01.dump @@ -0,0 +1,6 @@ +| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0@72 +| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0@1| @70 +|=+0&#ffff4012|>>m+0&#ffffff0@3| @68 +| +0#0000e05#a8a8a8255@1|y+0#0000000#ffffff0@3| @68 +|~+0#4040ff13&| @73 +| +0#0000000&@56|2|,|1| @10|A|l@1| diff --git a/src/testdir/dumps/Test_sign_cursor_02.dump b/src/testdir/dumps/Test_sign_cursor_02.dump new file mode 100644 index 0000000000..92643c3276 --- /dev/null +++ b/src/testdir/dumps/Test_sign_cursor_02.dump @@ -0,0 +1,6 @@ +|x+0&#ffffff0@74 +>m@3| @70 +|y@3| @70 +|~+0#4040ff13&| @73 +|~| @73 +|:+0#0000000&|s|i|g|n| |u|n|p|l|a|c|e| |1|0| @40|2|,|1| @10|A|l@1| diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim index 3b17eccf07..140aa82349 100644 --- a/src/testdir/test_signs.vim +++ b/src/testdir/test_signs.vim @@ -3,6 +3,8 @@ source check.vim CheckFeature signs +source screendump.vim + func Test_sign() new call setline(1, ['a', 'b', 'c', 'd']) @@ -1706,3 +1708,31 @@ func Test_sign_jump_func() sign undefine sign1 enew! | only! endfunc + +" Test for correct cursor position after the sign column appears or disappears. +func Test_sign_cursor_position() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + let lines =<< trim END + call setline(1, [repeat('x', 75), 'mmmm', 'yyyy']) + call cursor(2,1) + sign define s1 texthl=Search text==> + redraw + sign place 10 line=2 name=s1 + END + call writefile(lines, 'XtestSigncolumn') + let buf = RunVimInTerminal('-S XtestSigncolumn', {'rows': 6}) + call VerifyScreenDump(buf, 'Test_sign_cursor_01', {}) + + " update cursor position calculation + call term_sendkeys(buf, "lh") + call term_sendkeys(buf, ":sign unplace 10\") + call VerifyScreenDump(buf, 'Test_sign_cursor_02', {}) + + + " clean up + call StopVimInTerminal(buf) + call delete('XtestSigncolumn') +endfunc diff --git a/src/version.c b/src/version.c index b213bda110..f960d52fa3 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 */ +/**/ + 1552, /**/ 1551, /**/ From dc2ce58b5ac72e2af765385eb426660104816344 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 15:32:14 +0200 Subject: [PATCH 36/44] patch 8.1.1553: not easy to change the text in a popup window Problem: Not easy to change the text in a popup window. Solution: Add popup_settext(). (Ben Jackson, closes #4549) Also display a space for an empty popup. --- runtime/doc/popup.txt | 26 ++++-- src/evalfunc.c | 1 + src/popupwin.c | 88 ++++++++++++++------ src/proto/popupwin.pro | 1 + src/testdir/dumps/Test_popup_settext_01.dump | 10 +++ src/testdir/dumps/Test_popup_settext_02.dump | 10 +++ src/testdir/dumps/Test_popup_settext_03.dump | 10 +++ src/testdir/dumps/Test_popup_settext_04.dump | 10 +++ src/testdir/dumps/Test_popup_settext_05.dump | 10 +++ src/testdir/dumps/Test_popup_settext_06.dump | 10 +++ src/testdir/test_popupwin.vim | 48 ++++++++++- src/version.c | 2 + 12 files changed, 192 insertions(+), 34 deletions(-) create mode 100644 src/testdir/dumps/Test_popup_settext_01.dump create mode 100644 src/testdir/dumps/Test_popup_settext_02.dump create mode 100644 src/testdir/dumps/Test_popup_settext_03.dump create mode 100644 src/testdir/dumps/Test_popup_settext_04.dump create mode 100644 src/testdir/dumps/Test_popup_settext_05.dump create mode 100644 src/testdir/dumps/Test_popup_settext_06.dump diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index a9f55be279..02c66c3b30 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -104,15 +104,18 @@ TODO: incomplete cell. - Can the buffer be re-used, to avoid using up lots of buffer numbers? - Use a popup window for the "info" item of completion instead of using a - preview window. + preview window. Ideas in issue #4544. + How to add highlighting? +- When the lines do not fit show a scrollbar (like in the popup menu). + Use the mouse wheel for scrolling. - Implement: popup_filter_menu({id}, {key}) popup_menu({text}, {options}) popup_setoptions({id}, {options}) - flip option hidden option tabpage option with number title option + flip option transparent text property @@ -134,6 +137,7 @@ Manipulating a popup window: |popup_show()| show a previously hidden popup |popup_move()| change the position and size of a popup |popup_setoptions()| override options of a popup + |popup_settext()| replace the popup buffer contents Closing popup windows: |popup_close()| close one popup @@ -330,6 +334,11 @@ popup_setoptions({id}, {options}) *popup_setoptions()* {not implemented yet} Override options in popup {id} with entries in {options}. +popup_settext({id}, {text}) *popup_settext()* + Set the text of the buffer in poup win {id}. {text} is the + same as supplied to |popup_create()|. + Does not change the window size or position, other than caused + by the different text. POPUP BUFFER AND WINDOW *popup-buffer* @@ -365,8 +374,9 @@ need them. POPUP_CREATE() ARGUMENTS *popup_create-usage* -The first argument of |popup_create()| specifies the text to be displayed, and -optionally text properties. It is in one of three forms: +The first argument of |popup_create()| (and the second argument to +|popup_setttext()|) specifies the text to be displayed, and optionally text +properties. It is in one of three forms: - a string - a list of strings - a list of dictionaries, where each dictionary has these entries: @@ -404,7 +414,9 @@ The second argument of |popup_create()| is a dictionary with options: flip When TRUE (the default) and the position is relative to the cursor, flip to below or above the cursor to avoid overlap with the |popupmenu-completion| or - another popup with a higher "zindex". + another popup with a higher "zindex". When there is + no space above/below the cursor then show the popup to + the side of the popup or popup menu. {not implemented yet} maxheight Maximum height of the contents, excluding border and padding. @@ -434,7 +446,9 @@ The second argument of |popup_create()| is a dictionary with options: wrap TRUE to make the lines wrap (default TRUE). drag TRUE to allow the popup to be dragged with the mouse by grabbing at at the border. Has no effect if the - popup does not have a border. + popup does not have a border. As soon as dragging + starts and "pos" is "center" it is changed to + "topleft". highlight Highlight group name to use for the text, stored in the 'wincolor' option. padding List with numbers, defining the padding diff --git a/src/evalfunc.c b/src/evalfunc.c index d371c28b66..8c8bb4d638 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -822,6 +822,7 @@ static struct fst {"popup_hide", 1, 1, f_popup_hide}, {"popup_move", 2, 2, f_popup_move}, {"popup_notification", 2, 2, f_popup_notification}, + {"popup_settext", 2, 2, f_popup_settext}, {"popup_show", 1, 1, f_popup_show}, #endif #ifdef FEAT_FLOAT diff --git a/src/popupwin.c b/src/popupwin.c index c0b5e1300c..99ef2908cd 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -601,8 +601,10 @@ popup_adjust_position(win_T *wp) wp->w_topline = wp->w_buffer->b_ml.ml_line_count; // 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. // TODO: more accurate wrapping - wp->w_width = 0; + wp->w_width = 1; for (lnum = wp->w_topline; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum) { int len = vim_strsize(ml_get_buf(wp->w_buffer, lnum, FALSE)); @@ -703,6 +705,48 @@ typedef enum TYPE_DIALOG } create_type_T; +/* + * Make "buf" empty and set the contents to "text". + * Used by popup_create() and popup_settext(). + */ + static void +popup_set_buffer_text(buf_T *buf, typval_T text) +{ + int lnum; + + // Clear the buffer, then replace the lines. + curbuf = buf; + for (lnum = buf->b_ml.ml_line_count; lnum > 0; --lnum) + ml_delete(lnum, FALSE); + curbuf = curwin->w_buffer; + + // Add text to the buffer. + if (text.v_type == VAR_STRING) + { + // just a string + ml_append_buf(buf, 0, text.vval.v_string, (colnr_T)0, TRUE); + } + else + { + list_T *l = text.vval.v_list; + + if (l->lv_len > 0) + { + if (l->lv_first->li_tv.v_type == VAR_STRING) + // list of strings + add_popup_strings(buf, l); + else + // list of dictionaries + add_popup_dicts(buf, l); + } + } + + // delete the line that was in the empty buffer + curbuf = buf; + ml_delete(buf->b_ml.ml_line_count, FALSE); + curbuf = curwin->w_buffer; +} + /* * popup_create({text}, {options}) * popup_atcursor({text}, {options}) @@ -789,31 +833,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) // TODO: find tab page "nr" emsg("Not implemented yet"); - // Add text to the buffer. - if (argvars[0].v_type == VAR_STRING) - { - // just a string - ml_append_buf(buf, 0, argvars[0].vval.v_string, (colnr_T)0, TRUE); - } - else - { - list_T *l = argvars[0].vval.v_list; - - if (l->lv_len > 0) - { - if (l->lv_first->li_tv.v_type == VAR_STRING) - // list of strings - add_popup_strings(buf, l); - else - // list of dictionaries - add_popup_dicts(buf, l); - } - } - - // Delete the line of the empty buffer. - curbuf = buf; - ml_delete(buf->b_ml.ml_line_count, FALSE); - curbuf = curwin->w_buffer; + popup_set_buffer_text(buf, argvars[0]); if (type == TYPE_ATCURSOR) { @@ -1112,6 +1132,22 @@ f_popup_show(typval_T *argvars, typval_T *rettv UNUSED) } } +/* + * popup_settext({id}, {text}) + */ + void +f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED) +{ + int id = (int)tv_get_number(&argvars[0]); + win_T *wp = find_popup_win(id); + + if (wp != NULL) + { + popup_set_buffer_text(wp->w_buffer, argvars[1]); + popup_adjust_position(wp); + } +} + static void popup_free(win_T *wp) { diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 6e93791e61..e026506c5a 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -14,6 +14,7 @@ void f_popup_notification(typval_T *argvars, typval_T *rettv); void f_popup_close(typval_T *argvars, typval_T *rettv); void f_popup_hide(typval_T *argvars, typval_T *rettv); void f_popup_show(typval_T *argvars, typval_T *rettv); +void f_popup_settext(typval_T *argvars, typval_T *rettv); void popup_close(int id); void popup_close_tabpage(tabpage_T *tp, int id); void close_all_popups(void); diff --git a/src/testdir/dumps/Test_popup_settext_01.dump b/src/testdir/dumps/Test_popup_settext_01.dump new file mode 100644 index 0000000000..768c1bdf40 --- /dev/null +++ b/src/testdir/dumps/Test_popup_settext_01.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @28|t+0#0000001#ffd7ff255|h|i|s| |i|s| |a| |t|e|x|t| +0#4040ff13#ffffff0@30 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popup_settext_02.dump b/src/testdir/dumps/Test_popup_settext_02.dump new file mode 100644 index 0000000000..565e97fea2 --- /dev/null +++ b/src/testdir/dumps/Test_popup_settext_02.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @35| +0#0000001#ffd7ff255| +0#4040ff13#ffffff0@36 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|:+0#0000000&|c|a|l@1| |p|o|p|u|p|_|s|e|t@1|e|x|t|(|p|,| |'@1|)| @30|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popup_settext_03.dump b/src/testdir/dumps/Test_popup_settext_03.dump new file mode 100644 index 0000000000..b2c05042d3 --- /dev/null +++ b/src/testdir/dumps/Test_popup_settext_03.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @35|a+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@36 +|~| @35|b+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@36 +|~| @35|c+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@36 +|~| @73 +|~| @73 +|~| @73 +|:+0#0000000&|c|a|l@1| |p|o|p|u|p|_|s|e|t@1|e|x|t|(|p|,| |[|'|a|'|,|'|b|'|,|'|c|'|]|)| @19|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popup_settext_04.dump b/src/testdir/dumps/Test_popup_settext_04.dump new file mode 100644 index 0000000000..8e20916d10 --- /dev/null +++ b/src/testdir/dumps/Test_popup_settext_04.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @35|a+0#0000001#ffd7ff255| +0#4040ff13#ffffff0@36 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|:+0#0000000&|c|a|l@1| |p|o|p|u|p|_|s|e|t@1|e|x|t|(|p|,| |[|'|a|'|]|)| @27|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popup_settext_05.dump b/src/testdir/dumps/Test_popup_settext_05.dump new file mode 100644 index 0000000000..1ae670e542 --- /dev/null +++ b/src/testdir/dumps/Test_popup_settext_05.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @35| +0#0000001#ffd7ff255| +0#4040ff13#ffffff0@36 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|:+0#0000000&|c|a|l@1| |p|o|p|u|p|_|s|e|t@1|e|x|t|(|p|,| |[|]|)| @30|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_popup_settext_06.dump b/src/testdir/dumps/Test_popup_settext_06.dump new file mode 100644 index 0000000000..99c32c8c4d --- /dev/null +++ b/src/testdir/dumps/Test_popup_settext_06.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @33|a+0#0000001#ffd7ff255@3| +0#4040ff13#ffffff0@35 +|~| @33|b+0#0000001#ffd7ff255@3| +0#4040ff13#ffffff0@35 +|~| @33|c+0#0000001#ffd7ff255@3| +0#4040ff13#ffffff0@35 +|~| @73 +|~| @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 ae41512be5..ebe24004ae 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -916,13 +916,13 @@ func Test_popup_empty() let winid = popup_create('', {'padding': [2,2,2,2]}) redraw let pos = popup_getpos(winid) - call assert_equal(4, pos.width) + call assert_equal(5, pos.width) call assert_equal(5, pos.height) let winid = popup_create([], {'border': []}) redraw let pos = popup_getpos(winid) - call assert_equal(2, pos.width) + call assert_equal(3, pos.width) call assert_equal(3, pos.height) endfunc @@ -1231,3 +1231,47 @@ func Test_notifications() call StopVimInTerminal(buf) call delete('XtestNotifications') endfunc + +function Test_popup_settext() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + let lines =<< trim END + let opts = {'wrap': 0} + let p = popup_create('test', opts) + call popup_settext(p, 'this is a text') + END + + call writefile( lines, 'XtestPopupSetText' ) + let buf = RunVimInTerminal('-S XtestPopupSetText', {'rows': 10}) + call VerifyScreenDump(buf, 'Test_popup_settext_01', {}) + + " Setting to empty string clears it + call term_sendkeys(buf, ":call popup_settext(p, '')\") + call VerifyScreenDump(buf, 'Test_popup_settext_02', {}) + + " Setting a list + call term_sendkeys(buf, ":call popup_settext(p, ['a','b','c'])\") + call VerifyScreenDump(buf, 'Test_popup_settext_03', {}) + + " Shrinking with a list + call term_sendkeys(buf, ":call popup_settext(p, ['a'])\") + call VerifyScreenDump(buf, 'Test_popup_settext_04', {}) + + " Growing with a list + call term_sendkeys(buf, ":call popup_settext(p, ['a','b','c'])\") + call VerifyScreenDump(buf, 'Test_popup_settext_03', {}) + + " Empty list clears + call term_sendkeys(buf, ":call popup_settext(p, [])\") + call VerifyScreenDump(buf, 'Test_popup_settext_05', {}) + + " Dicts + call term_sendkeys(buf, ":call popup_settext(p, [{'text': 'aaaa'}, {'text': 'bbbb'}, {'text': 'cccc'}])\") + call VerifyScreenDump(buf, 'Test_popup_settext_06', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupSetText') +endfunction diff --git a/src/version.c b/src/version.c index f960d52fa3..aa11b7ebc4 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 */ +/**/ + 1553, /**/ 1552, /**/ From 1c196e7b1742c1a50ce0d74190721acaad087f81 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 15:41:58 +0200 Subject: [PATCH 37/44] patch 8.1.1554: docs and tests for :const can be improved Problem: Docs and tests for :const can be improved. Solution: Improve documentation, add a few more tests. (Ryuichi Hayashida, closes #4551) --- runtime/doc/eval.txt | 9 ++++++--- src/testdir/test_const.vim | 26 ++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 83a89957f2..549d27ba9a 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -11619,10 +11619,9 @@ text... If the system does not support deleting an environment variable, it is made empty. - *:cons* *:const* *E996* + *:cons* *:const* :cons[t] {var-name} = {expr1} :cons[t] [{name1}, {name2}, ...] = {expr1} -:cons[t] [{name1}, {name2}, ...] .= {expr1} :cons[t] [{name}, ..., ; {lastname}] = {expr1} :cons[t] {var-name} =<< [trim] {marker} text... @@ -11641,7 +11640,11 @@ text... |:const| does not allow to for changing a variable. > :let x = 1 :const x = 2 " Error! -< +< *E996* + Note that environment variables, option values and + register values cannot be used here, since they cannot + be locked. + :lockv[ar][!] [depth] {name} ... *:lockvar* *:lockv* Lock the internal variable {name}. Locking means that it can no longer be changed (until it is unlocked). diff --git a/src/testdir/test_const.vim b/src/testdir/test_const.vim index bb47e5e5fd..d4dccb1b83 100644 --- a/src/testdir/test_const.vim +++ b/src/testdir/test_const.vim @@ -21,6 +21,21 @@ func Test_define_var_with_lock() hello EOS + call assert_true(exists('i')) + call assert_true(exists('f')) + call assert_true(exists('s')) + call assert_true(exists('F')) + call assert_true(exists('l')) + call assert_true(exists('d')) + if has('channel') + call assert_true(exists('j')) + call assert_true(exists('c')) + endif + call assert_true(exists('b')) + call assert_true(exists('n')) + call assert_true(exists('bl')) + call assert_true(exists('here')) + call assert_fails('let i = 1', 'E741:') call assert_fails('let f = 1.1', 'E741:') call assert_fails('let s = "vim"', 'E741:') @@ -218,6 +233,17 @@ func Test_const_with_special_variables() call assert_fails('const &g:encoding = "utf-8"', 'E996:') endfunc +func Test_const_with_eval_name() + let s = 'foo' + + " eval name with :const should work + const abc_{s} = 1 + const {s}{s} = 1 + + let s2 = 'abc_foo' + call assert_fails('const {s2} = "bar"', 'E995:') +endfunc + func Test_lock_depth_is_1() const l = [1, 2, 3] const d = {'foo': 10} diff --git a/src/version.c b/src/version.c index aa11b7ebc4..fcdf562d47 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 */ +/**/ + 1554, /**/ 1553, /**/ From 8cdbd5b3c4225b04536dea7523718695306b16b5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 15:50:45 +0200 Subject: [PATCH 38/44] patch 8.1.1555: NOT_IN_POPUP_WINDOW is confusing Problem: NOT_IN_POPUP_WINDOW is confusing. (Andy Massimino) Solution: Rename to ERROR_IF_POPUP_WINDOW(). --- src/ex_cmds2.c | 2 +- src/ex_docmd.c | 10 +++++----- src/macros.h | 5 +++-- src/popupwin.c | 2 +- src/proto/popupwin.pro | 2 +- src/version.c | 2 ++ src/window.c | 10 +++++----- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 3c73030e6b..af7aa4b8ea 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -1864,7 +1864,7 @@ do_argfile(exarg_T *eap, int argn) char_u *p; int old_arg_idx = curwin->w_arg_idx; - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; if (argn < 0 || argn >= ARGCOUNT) { diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 438cb355aa..d2a6681c6d 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -5454,7 +5454,7 @@ ex_doautocmd(exarg_T *eap) static void ex_bunload(exarg_T *eap) { - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; eap->errmsg = do_bufdel( eap->cmdidx == CMD_bdelete ? DOBUF_DEL @@ -5470,7 +5470,7 @@ ex_bunload(exarg_T *eap) static void ex_buffer(exarg_T *eap) { - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; if (*eap->arg) eap->errmsg = e_trailing; @@ -6774,7 +6774,7 @@ ex_splitview(exarg_T *eap) || eap->cmdidx == CMD_tabfind || eap->cmdidx == CMD_tabnew; - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; #ifdef FEAT_GUI @@ -6904,7 +6904,7 @@ ex_tabnext(exarg_T *eap) { int tab_number; - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; switch (eap->cmdidx) { @@ -7157,7 +7157,7 @@ do_exedit( int need_hide; int exmode_was = exmode_active; - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; /* * ":vi" command ends Ex mode. diff --git a/src/macros.h b/src/macros.h index 0f5ab7739d..d685deafb9 100644 --- a/src/macros.h +++ b/src/macros.h @@ -340,8 +340,9 @@ /* Wether a command index indicates a user command. */ #define IS_USER_CMDIDX(idx) ((int)(idx) < 0) +// Give an error in curwin is a popup window and evaluate to TRUE. #ifdef FEAT_TEXT_PROP -# define NOT_IN_POPUP_WINDOW not_in_popup_window() +# define ERROR_IF_POPUP_WINDOW error_if_popup_window() #else -# define NOT_IN_POPUP_WINDOW 0 +# define ERROR_IF_POPUP_WINDOW 0 #endif diff --git a/src/popupwin.c b/src/popupwin.c index 99ef2908cd..ea1a1e1e71 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1336,7 +1336,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv) } int -not_in_popup_window() +error_if_popup_window() { if (bt_popup(curwin->w_buffer)) { diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index e026506c5a..1eb2c102a5 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -21,7 +21,7 @@ void close_all_popups(void); void f_popup_move(typval_T *argvars, typval_T *rettv); void f_popup_getpos(typval_T *argvars, typval_T *rettv); void f_popup_getoptions(typval_T *argvars, typval_T *rettv); -int not_in_popup_window(void); +int error_if_popup_window(void); void popup_reset_handled(void); win_T *find_next_popup(int lowest); int popup_do_filter(int c); diff --git a/src/version.c b/src/version.c index fcdf562d47..bf1a1f204d 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 */ +/**/ + 1555, /**/ 1554, /**/ diff --git a/src/window.c b/src/window.c index 436912934e..ee616ee968 100644 --- a/src/window.c +++ b/src/window.c @@ -87,7 +87,7 @@ do_window( #endif char_u cbuf[40]; - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; #ifdef FEAT_CMDWIN @@ -735,7 +735,7 @@ cmd_with_count( int win_split(int size, int flags) { - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return FAIL; /* When the ":tab" modifier was used open a new tab page instead. */ @@ -1523,7 +1523,7 @@ win_exchange(long Prenum) win_T *wp2; int temp; - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; if (ONE_WINDOW) // just one window { @@ -2379,7 +2379,7 @@ win_close(win_T *win, int free_buf) tabpage_T *prev_curtab = curtab; frame_T *win_frame = win->w_frame->fr_parent; - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return FAIL; if (last_window()) @@ -4240,7 +4240,7 @@ win_goto(win_T *wp) win_T *owp = curwin; #endif - if (NOT_IN_POPUP_WINDOW) + if (ERROR_IF_POPUP_WINDOW) return; if (text_locked()) { From 8a5c7ef9bbded87abd8c937b16c576ed2ccbb805 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 16:14:20 +0200 Subject: [PATCH 39/44] patch 8.1.1556: command for failing screenshot does not include directory Problem: The command displayed to show a failing screenshot does not include the "testdir" directory. Solution: Prefix the directory name so that it can be copy-pasted. --- src/testdir/screendump.vim | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/testdir/screendump.vim b/src/testdir/screendump.vim index 50e3384c3c..a147b5afc1 100644 --- a/src/testdir/screendump.vim +++ b/src/testdir/screendump.vim @@ -144,7 +144,7 @@ func VerifyScreenDump(buf, filename, options, ...) if i == 100 " Leave the failed dump around for inspection. if filereadable(reference) - let msg = 'See dump file difference: call term_dumpdiff("' . testfile . '", "' . reference . '")' + let msg = 'See dump file difference: call term_dumpdiff("testdir/' .. testfile .. '", "testdir/' .. reference .. '")' if a:0 == 1 let msg = a:1 . ': ' . msg endif @@ -152,7 +152,7 @@ func VerifyScreenDump(buf, filename, options, ...) let msg = msg . '; line count is ' . len(testdump) . ' instead of ' . len(refdump) endif else - let msg = 'See new dump file: call term_dumpload("' . testfile . '")' + let msg = 'See new dump file: call term_dumpload("testdir/' .. testfile .. '")' endif for i in range(len(refdump)) if i >= len(testdump) diff --git a/src/version.c b/src/version.c index bf1a1f204d..4eb37a7513 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 */ +/**/ + 1556, /**/ 1555, /**/ From 983f2f1403a591779f6edc4dd973c6cf31c65c8b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 16:41:41 +0200 Subject: [PATCH 40/44] patch 8.1.1557: compiler warning for unused variables in tiny version Problem: Compiler warning for unused variables in tiny version. (Tony Mechelynck) Solution: Add #ifdef. --- src/option.c | 15 +++++++++++++-- src/version.c | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/option.c b/src/option.c index 12a0816f3d..51d6212462 100644 --- a/src/option.c +++ b/src/option.c @@ -6135,9 +6135,9 @@ set_string_option( char_u *s; char_u **varp; char_u *oldval; +#if defined(FEAT_EVAL) char_u *oldval_l = NULL; char_u *oldval_g = NULL; -#if defined(FEAT_EVAL) char_u *saved_oldval = NULL; char_u *saved_oldval_l = NULL; char_u *saved_oldval_g = NULL; @@ -6158,6 +6158,7 @@ set_string_option( ? OPT_GLOBAL : OPT_LOCAL) : opt_flags); oldval = *varp; +#if defined(FEAT_EVAL) if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { oldval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), @@ -6165,6 +6166,7 @@ set_string_option( oldval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); } +#endif *varp = s; #if defined(FEAT_EVAL) @@ -8525,7 +8527,9 @@ set_bool_option( int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */ { int old_value = *(int *)varp; +#if defined(FEAT_EVAL) int old_global_value = 0; +#endif /* Disallow changing some options from secure mode */ if ((secure @@ -8535,12 +8539,14 @@ set_bool_option( ) && (options[opt_idx].flags & P_SECURE)) return e_secure; +#if defined(FEAT_EVAL) // Save the global value before changing anything. This is needed as for // a global-only option setting the "local value" in fact sets the global // value (since there is only one value). if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) old_global_value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); +#endif *(int *)varp = value; /* set the new value */ #ifdef FEAT_EVAL @@ -9130,8 +9136,10 @@ set_num_option( { char *errmsg = NULL; long old_value = *(long *)varp; +#if defined(FEAT_EVAL) long old_global_value = 0; // only used when setting a local and // global option +#endif long old_Rows = Rows; // remember old Rows long old_Columns = Columns; // remember old Columns long *pp = (long *)varp; @@ -9144,11 +9152,14 @@ set_num_option( ) && (options[opt_idx].flags & P_SECURE)) return e_secure; +#if defined(FEAT_EVAL) // Save the global value before changing anything. This is needed as for // a global-only option setting the "local value" infact sets the global // value (since there is only one value). if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) - old_global_value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + old_global_value = *(long *)get_varp_scope(&(options[opt_idx]), + OPT_GLOBAL); +#endif *pp = value; #ifdef FEAT_EVAL diff --git a/src/version.c b/src/version.c index 4eb37a7513..f6bb71c89c 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 */ +/**/ + 1557, /**/ 1556, /**/ From a730e55cc2d3045a79a340a5af1ad4a749058a32 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 19:05:31 +0200 Subject: [PATCH 41/44] patch 8.1.1558: popup_menu() and popup_filter_menu() are not implemented yet Problem: Popup_menu() and popup_filter_menu() are not implemented yet. Solution: Implement the functions. Fix that centering didn't take the border and padding into account. --- runtime/doc/popup.txt | 35 ++-- src/evalfunc.c | 2 + src/popupwin.c | 168 ++++++++++++++++--- src/proto/popupwin.pro | 2 + src/screen.c | 11 +- src/testdir/dumps/Test_popupwin_drag_01.dump | 10 +- src/testdir/dumps/Test_popupwin_drag_02.dump | 10 +- src/testdir/dumps/Test_popupwin_menu_01.dump | 10 ++ src/testdir/dumps/Test_popupwin_menu_02.dump | 10 ++ src/testdir/dumps/Test_popupwin_menu_03.dump | 10 ++ src/testdir/test_popupwin.vim | 58 +++++++ src/version.c | 2 + 12 files changed, 276 insertions(+), 52 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_menu_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_03.dump diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 02c66c3b30..a6dab8b91f 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -89,7 +89,7 @@ that it is in. TODO: - Why does 'nrformats' leak from the popup window buffer??? - Disable commands, feedkeys(), CTRL-W, etc. in a popup window. - Use NOT_IN_POPUP_WINDOW for more commands. + Use ERROR_IF_POPUP_WINDOW for more commands. - Add 'balloonpopup': instead of showing text, let the callback open a popup window and return the window ID. The popup will then be closed when the mouse moves, except when it moves inside the popup. @@ -109,8 +109,6 @@ TODO: - When the lines do not fit show a scrollbar (like in the popup menu). Use the mouse wheel for scrolling. - Implement: - popup_filter_menu({id}, {key}) - popup_menu({text}, {options}) popup_setoptions({id}, {options}) hidden option tabpage option with number @@ -220,12 +218,20 @@ popup_dialog({text}, {options}) *popup_dialog()* popup_filter_menu({id}, {key}) *popup_filter_menu()* - {not implemented yet} - Filter that can be used for a popup. It handles the cursor - keys to move the selected index in the popup. Space and Enter - can be used to select an item. Invokes the "callback" of the - popup menu with the index of the selected line as the second - argument. + Filter that can be used for a popup. These keys can be used: + j select item below + k select item above + accept current selection + x Esc CTRL-C cancel the menu + Other keys are ignored. + + A match is set on that line to highlight it, see + |popup_menu()|. + + When the current selection is accepted the "callback" of the + popup menu is invoked with the index of the selected line as + the second argument. The first entry has index one. + Cancelling the menu invokes the callback with -1. popup_filter_yesno({id}, {key}) *popup_filter_yesno()* @@ -279,7 +285,6 @@ popup_hide({id}) *popup_hide()* popup_menu({text}, {options}) *popup_menu()* - {not implemented yet} Show the {text} near the cursor, handle selecting one of the items with cursorkeys, and close it an item is selected with Space or Enter. {text} should have multiple lines to make this @@ -287,11 +292,16 @@ popup_menu({text}, {options}) *popup_menu()* call popup_create({text}, { \ 'pos': 'center', \ 'zindex': 200, + \ 'drag': 1, \ 'wrap': 0, \ 'border': [], + \ 'padding': [], \ 'filter': 'popup_filter_menu', \ }) -< Use {options} to change the properties. Should at least set +< The current line is highlighted with a match using + PopupSelected, or |PmenuSel| if that is not defined. + + Use {options} to change the properties. Should at least set "callback" to a function that handles the selected item. @@ -320,7 +330,8 @@ popup_notification({text}, {options}) *popup_notification()* \ }) < The PopupNotification highlight group is used instead of WarningMsg if it is defined. -< The position will be adjusted to avoid overlap with other + + The position will be adjusted to avoid overlap with other notifications. Use {options} to change the properties. diff --git a/src/evalfunc.c b/src/evalfunc.c index 8c8bb4d638..b98c7e72ec 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -816,10 +816,12 @@ static struct fst {"popup_close", 1, 2, f_popup_close}, {"popup_create", 2, 2, f_popup_create}, {"popup_dialog", 2, 2, f_popup_dialog}, + {"popup_filter_menu", 2, 2, f_popup_filter_menu}, {"popup_filter_yesno", 2, 2, f_popup_filter_yesno}, {"popup_getoptions", 1, 1, f_popup_getoptions}, {"popup_getpos", 1, 1, f_popup_getpos}, {"popup_hide", 1, 1, f_popup_hide}, + {"popup_menu", 2, 2, f_popup_menu}, {"popup_move", 2, 2, f_popup_move}, {"popup_notification", 2, 2, f_popup_notification}, {"popup_settext", 2, 2, f_popup_settext}, diff --git a/src/popupwin.c b/src/popupwin.c index ea1a1e1e71..ccf1f6685c 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -651,7 +651,11 @@ popup_adjust_position(win_T *wp) if (wp->w_width > maxwidth) wp->w_width = maxwidth; if (center_hor) - wp->w_wincol = (Columns - wp->w_width) / 2; + { + wp->w_wincol = (Columns - wp->w_width - extra_width) / 2; + if (wp->w_wincol < 0) + wp->w_wincol = 0; + } else if (wp->w_popup_pos == POPPOS_BOTRIGHT || wp->w_popup_pos == POPPOS_TOPRIGHT) { @@ -671,7 +675,11 @@ popup_adjust_position(win_T *wp) wp->w_height = Rows - wp->w_winrow; if (center_vert) - wp->w_winrow = (Rows - wp->w_height) / 2; + { + wp->w_winrow = (Rows - wp->w_height - extra_height) / 2; + if (wp->w_winrow < 0) + wp->w_winrow = 0; + } else if (wp->w_popup_pos == POPPOS_BOTRIGHT || wp->w_popup_pos == POPPOS_BOTLEFT) { @@ -702,7 +710,8 @@ typedef enum TYPE_NORMAL, TYPE_ATCURSOR, TYPE_NOTIFICATION, - TYPE_DIALOG + TYPE_DIALOG, + TYPE_MENU } create_type_T; /* @@ -751,7 +760,7 @@ popup_set_buffer_text(buf_T *buf, typval_T text) * popup_create({text}, {options}) * popup_atcursor({text}, {options}) */ - static void + static win_T * popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) { win_T *wp; @@ -764,25 +773,25 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) && !(argvars[0].v_type == VAR_LIST && argvars[0].vval.v_list != NULL)) { emsg(_(e_listreq)); - return; + return NULL; } if (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL) { emsg(_(e_dictreq)); - return; + return NULL; } d = argvars[1].vval.v_dict; // Create the window and buffer. wp = win_alloc_popup_win(); if (wp == NULL) - return; + return NULL; rettv->vval.v_number = wp->w_id; wp->w_popup_pos = POPPOS_TOPLEFT; buf = buflist_new(NULL, NULL, (linenr_T)0, BLN_NEW|BLN_LISTED|BLN_DUMMY); if (buf == NULL) - return; + return NULL; ml_open(buf); win_init_popup_win(wp, buf); @@ -898,7 +907,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) OPT_FREE|OPT_LOCAL, 0); } - if (type == TYPE_DIALOG) + if (type == TYPE_DIALOG || type == TYPE_MENU) { int i; @@ -912,6 +921,20 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) } } + if (type == TYPE_MENU) + { + typval_T tv; + callback_T callback; + + tv.v_type = VAR_STRING; + tv.vval.v_string = (char_u *)"popup_filter_menu"; + callback = get_callback(&tv); + if (callback.cb_name != NULL) + set_callback(&wp->w_filter_cb, &callback); + + wp->w_p_wrap = 0; + } + // Deal with options. apply_options(wp, buf, argvars[1].vval.v_dict); @@ -924,6 +947,8 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) redraw_all_later(NOT_VALID); popup_mask_refresh = TRUE; + + return wp; } /* @@ -999,6 +1024,93 @@ popup_close_and_callback(win_T *wp, typval_T *arg) popup_close(id); } +/* + * In a filter: check if the typed key is a mouse event that is used for + * dragging the popup. + */ + static void +filter_handle_drag(win_T *wp, int c, typval_T *rettv) +{ + int row = mouse_row; + int col = mouse_col; + + if (wp->w_popup_drag + && is_mouse_key(c) + && (wp == popup_dragwin + || wp == mouse_find_win(&row, &col, FIND_POPUP))) + // do not consume the key, allow for dragging the popup + rettv->vval.v_number = 0; +} + + static void +popup_highlight_curline(win_T *wp) +{ + int id; + char buf[100]; + + match_delete(wp, 1, FALSE); + + 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}) + */ + void +f_popup_filter_menu(typval_T *argvars, typval_T *rettv) +{ + int id = tv_get_number(&argvars[0]); + win_T *wp = win_id2wp(id); + char_u *key = tv_get_string(&argvars[1]); + typval_T res; + int c; + linenr_T old_lnum; + + // If the popup has been closed do not consume the key. + if (wp == NULL) + return; + + c = *key; + if (c == K_SPECIAL && key[1] != NUL) + c = TO_SPECIAL(key[1], key[2]); + + // consume all keys until done + rettv->vval.v_number = 1; + res.v_type = VAR_NUMBER; + + old_lnum = wp->w_cursor.lnum; + if ((c == 'k' || c == 'K' || c == K_UP) && wp->w_cursor.lnum > 1) + --wp->w_cursor.lnum; + if ((c == 'j' || c == 'J' || c == K_DOWN) + && wp->w_cursor.lnum < wp->w_buffer->b_ml.ml_line_count) + ++wp->w_cursor.lnum; + if (old_lnum != wp->w_cursor.lnum) + { + popup_highlight_curline(wp); + return; + } + + if (c == 'x' || c == 'X' || c == ESC || c == Ctrl_C) + { + // Cancelled, invoke callback with -1 + res.vval.v_number = -1; + popup_close_and_callback(wp, &res); + return; + } + if (c == ' ' || c == K_KENTER || c == CAR || c == NL) + { + // Invoke callback with current index. + res.vval.v_number = wp->w_cursor.lnum; + popup_close_and_callback(wp, &res); + return; + } + + filter_handle_drag(wp, c, rettv); +} + /* * popup_filter_yesno({text}, {options}) */ @@ -1009,36 +1121,26 @@ f_popup_filter_yesno(typval_T *argvars, typval_T *rettv) win_T *wp = win_id2wp(id); char_u *key = tv_get_string(&argvars[1]); typval_T res; + int c; // If the popup has been closed don't consume the key. if (wp == NULL) return; + c = *key; + if (c == K_SPECIAL && key[1] != NUL) + c = TO_SPECIAL(key[1], key[2]); + // consume all keys until done rettv->vval.v_number = 1; - if (STRCMP(key, "y") == 0 || STRCMP(key, "Y") == 0) + if (c == 'y' || c == 'Y') res.vval.v_number = 1; - else if (STRCMP(key, "n") == 0 || STRCMP(key, "N") == 0 - || STRCMP(key, "x") == 0 || STRCMP(key, "X") == 0 - || STRCMP(key, "\x1b") == 0) + else if (c == 'n' || c == 'N' || c == 'x' || c == 'X' || c == ESC) res.vval.v_number = 0; else { - int c = *key; - int row = mouse_row; - int col = mouse_col; - - if (c == K_SPECIAL && key[1] != NUL) - c = TO_SPECIAL(key[1], key[2]); - if (wp->w_popup_drag - && is_mouse_key(c) - && (wp == popup_dragwin - || wp == mouse_find_win(&row, &col, FIND_POPUP))) - // allow for dragging the popup - rettv->vval.v_number = 0; - - // ignore this key + filter_handle_drag(wp, c, rettv); return; } @@ -1056,6 +1158,18 @@ f_popup_dialog(typval_T *argvars, typval_T *rettv) popup_create(argvars, rettv, TYPE_DIALOG); } +/* + * popup_menu({text}, {options}) + */ + 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_notification({text}, {options}) */ diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 1eb2c102a5..fefb031422 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -8,8 +8,10 @@ void popup_adjust_position(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); +void f_popup_filter_menu(typval_T *argvars, typval_T *rettv); void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv); void f_popup_dialog(typval_T *argvars, typval_T *rettv); +void f_popup_menu(typval_T *argvars, typval_T *rettv); void f_popup_notification(typval_T *argvars, typval_T *rettv); void f_popup_close(typval_T *argvars, typval_T *rettv); void f_popup_hide(typval_T *argvars, typval_T *rettv); diff --git a/src/screen.c b/src/screen.c index 8708fd7c21..9886267419 100644 --- a/src/screen.c +++ b/src/screen.c @@ -4183,7 +4183,7 @@ win_line( */ v = (long)(ptr - line); cur = wp->w_match_head; - shl_flag = (screen_line_flags & SLF_POPUP); + shl_flag = FALSE; while (cur != NULL || shl_flag == FALSE) { if (shl_flag == FALSE @@ -4193,6 +4193,8 @@ win_line( { shl = &search_hl; shl_flag = TRUE; + if (screen_line_flags & SLF_POPUP) + continue; // do not use search_hl } else shl = &cur->hl; @@ -4272,9 +4274,9 @@ win_line( /* Use attributes from match with highest priority among * 'search_hl' and the match list. */ - search_attr = search_hl.attr_cur; cur = wp->w_match_head; shl_flag = FALSE; + search_attr = 0; while (cur != NULL || shl_flag == FALSE) { if (shl_flag == FALSE @@ -4284,6 +4286,8 @@ win_line( { shl = &search_hl; shl_flag = TRUE; + if (screen_line_flags & SLF_POPUP) + continue; // do not use search_hl } else shl = &cur->hl; @@ -5564,7 +5568,6 @@ win_line( { /* Use attributes from match with highest priority among * 'search_hl' and the match list. */ - char_attr = search_hl.attr; cur = wp->w_match_head; shl_flag = FALSE; while (cur != NULL || shl_flag == FALSE) @@ -5576,6 +5579,8 @@ win_line( { shl = &search_hl; shl_flag = TRUE; + if (screen_line_flags & SLF_POPUP) + continue; // do not use search_hl } else shl = &cur->hl; diff --git a/src/testdir/dumps/Test_popupwin_drag_01.dump b/src/testdir/dumps/Test_popupwin_drag_01.dump index e47fbc4fa3..c8867e3ffe 100644 --- a/src/testdir/dumps/Test_popupwin_drag_01.dump +++ b/src/testdir/dumps/Test_popupwin_drag_01.dump @@ -3,8 +3,8 @@ |3| @73 |4| @73 |5| @73 -|6| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@32 -|7| @32|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@32 -|8| @32|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@32 -|9| @32|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@32 -@34|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@14|1|,|1| @10|T|o|p| +|6| @31|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@33 +|7| @31|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@33 +|8| @31|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@33 +|9| @31|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@33 +@33|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@15|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_drag_02.dump b/src/testdir/dumps/Test_popupwin_drag_02.dump index 7e8c30ee6d..f03ecb847b 100644 --- a/src/testdir/dumps/Test_popupwin_drag_02.dump +++ b/src/testdir/dumps/Test_popupwin_drag_02.dump @@ -1,9 +1,9 @@ >1+0&#ffffff0| @73 -|2| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@32 -|3| @32|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@32 -|4| @32|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@32 -|5| @32|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@32 -|6| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@32 +|2| @31|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@33 +|3| @31|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@33 +|4| @31|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@33 +|5| @31|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@33 +|6| @31|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@33 |7| @73 |8| @73 |9| @73 diff --git a/src/testdir/dumps/Test_popupwin_menu_01.dump b/src/testdir/dumps/Test_popupwin_menu_01.dump new file mode 100644 index 0000000000..debd962500 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_menu_01.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @30|╔+0#0000001#ffd7ff255|═@8|╗| +0#0000000#ffffff0@31 +|3| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 +|4| @30|║+0#0000001#ffd7ff255| |o+0#0000000#5fd7ff255|n|e| +0#0000001#ffd7ff255@4|║| +0#0000000#ffffff0@31 +|5| @30|║+0#0000001#ffd7ff255| |t|w|o| @4|║| +0#0000000#ffffff0@31 +|6| @30|║+0#0000001#ffd7ff255| |a|n|o|t|h|e|r| |║| +0#0000000#ffffff0@31 +|7| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 +|8| @30|╚+0#0000001#ffd7ff255|═@8|╝| +0#0000000#ffffff0@31 +|9| @73 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_menu_02.dump b/src/testdir/dumps/Test_popupwin_menu_02.dump new file mode 100644 index 0000000000..2495edfef5 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_menu_02.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @30|╔+0#0000001#ffd7ff255|═@8|╗| +0#0000000#ffffff0@31 +|3| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 +|4| @30|║+0#0000001#ffd7ff255| |o|n|e| @4|║| +0#0000000#ffffff0@31 +|5| @30|║+0#0000001#ffd7ff255| |t|w|o| @4|║| +0#0000000#ffffff0@31 +|6| @30|║+0#0000001#ffd7ff255| |a+0#0000000#5fd7ff255|n|o|t|h|e|r| +0#0000001#ffd7ff255|║| +0#0000000#ffffff0@31 +|7| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 +|8| @30|╚+0#0000001#ffd7ff255|═@8|╝| +0#0000000#ffffff0@31 +|9| @73 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_menu_03.dump b/src/testdir/dumps/Test_popupwin_menu_03.dump new file mode 100644 index 0000000000..1aa7fe805e --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_menu_03.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @73 +|3| @73 +|4| @73 +|5| @73 +|6| @73 +|7| @73 +|8| @73 +|9| @73 +|s|e|l|e|c|t|e|d| |3| @46|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index ebe24004ae..477cda38ae 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -902,6 +902,64 @@ func Test_popup_dialog() delfunc QuitCallback endfunc +func ShowMenu(key, result) + let s:cb_res = 999 + let winid = popup_menu(['one', 'two', 'something else'], { + \ 'callback': 'QuitCallback', + \ }) + redraw + call feedkeys(a:key, "xt") + call assert_equal(winid, s:cb_winid) + call assert_equal(a:result, s:cb_res) +endfunc + +func Test_popup_menu() + func QuitCallback(id, res) + let s:cb_winid = a:id + let s:cb_res = a:res + endfunc + + let winid = ShowMenu(" ", 1) + let winid = ShowMenu("j \", 2) + let winid = ShowMenu("JjK \", 2) + let winid = ShowMenu("jjjjjj ", 3) + let winid = ShowMenu("kkk ", 1) + let winid = ShowMenu("x", -1) + let winid = ShowMenu("X", -1) + let winid = ShowMenu("\", -1) + let winid = ShowMenu("\", -1) + + delfunc QuitCallback +endfunc + +func Test_popup_menu_screenshot() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + let lines =<< trim END + call setline(1, range(1, 20)) + hi PopupSelected ctermbg=lightblue + call popup_menu(['one', 'two', 'another'], {'callback': 'MenuDone'}) + func MenuDone(id, res) + echomsg "selected " .. a:res + endfunc + END + call writefile(lines, 'XtestPopupMenu') + let buf = RunVimInTerminal('-S XtestPopupMenu', {'rows': 10}) + call VerifyScreenDump(buf, 'Test_popupwin_menu_01', {}) + + call term_sendkeys(buf, "jj") + call VerifyScreenDump(buf, 'Test_popupwin_menu_02', {}) + + call term_sendkeys(buf, " ") + call VerifyScreenDump(buf, 'Test_popupwin_menu_03', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupMenu') +endfunc + func Test_popup_close_callback() func PopupDone(id, result) let g:result = a:result diff --git a/src/version.c b/src/version.c index f6bb71c89c..a59803bb9f 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 */ +/**/ + 1558, /**/ 1557, /**/ From eb2310d47d83764a61d63cd5c2788870d7f6eddf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 20:09:10 +0200 Subject: [PATCH 42/44] patch 8.1.1559: popup window title property not implemented yet Problem: Popup window title property not implemented yet. Solution: Implement the title property. --- runtime/doc/popup.txt | 5 +- src/popupwin.c | 55 +++++++++++++++++--- src/structs.h | 1 + src/testdir/dumps/Test_popupwin_menu_01.dump | 14 ++--- src/testdir/dumps/Test_popupwin_menu_02.dump | 14 ++--- src/testdir/dumps/Test_popupwin_title.dump | 10 ++++ src/testdir/test_popupwin.vim | 22 +++++++- src/version.c | 2 + src/window.c | 1 + 9 files changed, 98 insertions(+), 26 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_title.dump diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index a6dab8b91f..398c6cc299 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -112,7 +112,6 @@ TODO: popup_setoptions({id}, {options}) hidden option tabpage option with number - title option flip option transparent text property @@ -452,8 +451,8 @@ The second argument of |popup_create()| is a dictionary with options: title Text to be displayed above the first item in the popup, on top of any border. If there is no top border one line of padding is added to put the title - on. - {not implemented yet} + on. You might want to add one or more spaces at the + start and end as padding. wrap TRUE to make the lines wrap (default TRUE). drag TRUE to allow the popup to be dragged with the mouse by grabbing at at the border. Has no effect if the diff --git a/src/popupwin.c b/src/popupwin.c index ccf1f6685c..3603a1c717 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -294,6 +294,13 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1, str, OPT_FREE|OPT_LOCAL, 0); + str = dict_get_string(dict, (char_u *)"title", FALSE); + if (str != NULL) + { + vim_free(wp->w_popup_title); + wp->w_popup_title = vim_strsave(str); + } + wp->w_firstline = dict_get_number(dict, (char_u *)"firstline"); if (wp->w_firstline < 1) wp->w_firstline = 1; @@ -531,6 +538,19 @@ popup_width(win_T *wp) + wp->w_popup_padding[1] + wp->w_popup_border[1]; } +/* + * Get the padding plus border at the top, adjusted to 1 if there is a title. + */ + static int +popup_top_extra(win_T *wp) +{ + int extra = wp->w_popup_border[0] + wp->w_popup_padding[0]; + + if (extra == 0 && wp->w_popup_title != NULL && *wp->w_popup_title != NUL) + return 1; + return extra; +} + /* * Adjust the position and size of the popup to fit on the screen. */ @@ -543,7 +563,7 @@ popup_adjust_position(win_T *wp) int center_vert = FALSE; int center_hor = FALSE; int allow_adjust_left = !wp->w_popup_fixed; - int top_extra = wp->w_popup_border[0] + wp->w_popup_padding[0]; + int top_extra = popup_top_extra(wp); int right_extra = wp->w_popup_border[1] + wp->w_popup_padding[1]; int bot_extra = wp->w_popup_border[2] + wp->w_popup_padding[2]; int left_extra = wp->w_popup_border[3] + wp->w_popup_padding[3]; @@ -553,6 +573,7 @@ popup_adjust_position(win_T *wp) int org_wincol = wp->w_wincol; int org_width = wp->w_width; int org_height = wp->w_height; + int minwidth; wp->w_winrow = 0; wp->w_wincol = 0; @@ -646,8 +667,17 @@ popup_adjust_position(win_T *wp) break; } - if (wp->w_minwidth > 0 && wp->w_width < wp->w_minwidth) - wp->w_width = wp->w_minwidth; + minwidth = wp->w_minwidth; + if (wp->w_popup_title != NULL && *wp->w_popup_title != NUL) + { + int title_len = vim_strsize(wp->w_popup_title) + 2 - extra_width; + + if (minwidth < title_len) + minwidth = title_len; + } + + if (minwidth > 0 && wp->w_width < minwidth) + wp->w_width = minwidth; if (wp->w_width > maxwidth) wp->w_width = maxwidth; if (center_hor) @@ -1384,7 +1414,7 @@ f_popup_getpos(typval_T *argvars, typval_T *rettv) { if (wp == NULL) return; // invalid {id} - top_extra = wp->w_popup_border[0] + wp->w_popup_padding[0]; + top_extra = popup_top_extra(wp); left_extra = wp->w_popup_border[3] + wp->w_popup_padding[3]; dict = rettv->vval.v_dict; @@ -1750,6 +1780,7 @@ update_popups(void (*win_update)(win_T *wp)) int left_off; int total_width; int total_height; + int top_padding; int popup_attr; int border_attr[4]; int border_char[8]; @@ -1770,7 +1801,7 @@ update_popups(void (*win_update)(win_T *wp)) // adjust w_winrow and w_wincol for border and padding, since // win_update() doesn't handle them. - top_off = wp->w_popup_padding[0] + wp->w_popup_border[0]; + top_off = popup_top_extra(wp); left_off = wp->w_popup_padding[3] + wp->w_popup_border[3]; wp->w_winrow += top_off; wp->w_wincol += left_off; @@ -1783,7 +1814,7 @@ update_popups(void (*win_update)(win_T *wp)) total_width = wp->w_popup_border[3] + wp->w_popup_padding[3] + wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1]; - total_height = wp->w_popup_border[0] + wp->w_popup_padding[0] + total_height = popup_top_extra(wp) + wp->w_height + wp->w_popup_padding[2] + wp->w_popup_border[2]; popup_attr = get_wcr_attr(wp); @@ -1816,6 +1847,7 @@ update_popups(void (*win_update)(win_T *wp)) border_attr[i] = syn_name2attr(wp->w_border_highlight[i]); } + top_padding = wp->w_popup_padding[0]; if (wp->w_popup_border[0] > 0) { // top border @@ -1832,17 +1864,24 @@ update_popups(void (*win_update)(win_T *wp)) wp->w_wincol + total_width - 1, border_attr[1]); } } + else if (wp->w_popup_padding[0] == 0 && popup_top_extra(wp) > 0) + top_padding = 1; - if (wp->w_popup_padding[0] > 0) + if (top_padding > 0) { // top padding row = wp->w_winrow + wp->w_popup_border[0]; - screen_fill(row, row + wp->w_popup_padding[0], + screen_fill(row, row + top_padding, wp->w_wincol + wp->w_popup_border[3], wp->w_wincol + total_width - wp->w_popup_border[1], ' ', ' ', popup_attr); } + // Title goes on top of border or padding. + if (wp->w_popup_title != NULL) + screen_puts(wp->w_popup_title, wp->w_winrow, wp->w_wincol + 1, + wp->w_popup_border[0] > 0 ? border_attr[0] : popup_attr); + for (row = wp->w_winrow + wp->w_popup_border[0]; row < wp->w_winrow + total_height - wp->w_popup_border[2]; ++row) diff --git a/src/structs.h b/src/structs.h index 09158a0cc5..5787d2b40c 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2891,6 +2891,7 @@ struct window_S pos_save_T w_save_cursor; /* backup of cursor pos and topline */ #ifdef FEAT_TEXT_PROP int w_popup_flags; // POPF_ values + char_u *w_popup_title; poppos_T w_popup_pos; int w_popup_fixed; // do not shift popup to fit on screen int w_zindex; diff --git a/src/testdir/dumps/Test_popupwin_menu_01.dump b/src/testdir/dumps/Test_popupwin_menu_01.dump index debd962500..479edf6e02 100644 --- a/src/testdir/dumps/Test_popupwin_menu_01.dump +++ b/src/testdir/dumps/Test_popupwin_menu_01.dump @@ -1,10 +1,10 @@ >1+0&#ffffff0| @73 -|2| @30|╔+0#0000001#ffd7ff255|═@8|╗| +0#0000000#ffffff0@31 -|3| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 -|4| @30|║+0#0000001#ffd7ff255| |o+0#0000000#5fd7ff255|n|e| +0#0000001#ffd7ff255@4|║| +0#0000000#ffffff0@31 -|5| @30|║+0#0000001#ffd7ff255| |t|w|o| @4|║| +0#0000000#ffffff0@31 -|6| @30|║+0#0000001#ffd7ff255| |a|n|o|t|h|e|r| |║| +0#0000000#ffffff0@31 -|7| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 -|8| @30|╚+0#0000001#ffd7ff255|═@8|╝| +0#0000000#ffffff0@31 +|2| @20|╔+0#0000001#ffd7ff255| |m|a|k|e| |a| |c|h|o|i|c|e| |f|r|o|m| |t|h|e| |l|i|s|t| |╗| +0#0000000#ffffff0@21 +|3| @20|║+0#0000001#ffd7ff255| @28|║| +0#0000000#ffffff0@21 +|4| @20|║+0#0000001#ffd7ff255| |o+0#0000000#5fd7ff255|n|e| +0#0000001#ffd7ff255@24|║| +0#0000000#ffffff0@21 +|5| @20|║+0#0000001#ffd7ff255| |t|w|o| @24|║| +0#0000000#ffffff0@21 +|6| @20|║+0#0000001#ffd7ff255| |a|n|o|t|h|e|r| @20|║| +0#0000000#ffffff0@21 +|7| @20|║+0#0000001#ffd7ff255| @28|║| +0#0000000#ffffff0@21 +|8| @20|╚+0#0000001#ffd7ff255|═@28|╝| +0#0000000#ffffff0@21 |9| @73 @57|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_menu_02.dump b/src/testdir/dumps/Test_popupwin_menu_02.dump index 2495edfef5..4a407d472d 100644 --- a/src/testdir/dumps/Test_popupwin_menu_02.dump +++ b/src/testdir/dumps/Test_popupwin_menu_02.dump @@ -1,10 +1,10 @@ >1+0&#ffffff0| @73 -|2| @30|╔+0#0000001#ffd7ff255|═@8|╗| +0#0000000#ffffff0@31 -|3| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 -|4| @30|║+0#0000001#ffd7ff255| |o|n|e| @4|║| +0#0000000#ffffff0@31 -|5| @30|║+0#0000001#ffd7ff255| |t|w|o| @4|║| +0#0000000#ffffff0@31 -|6| @30|║+0#0000001#ffd7ff255| |a+0#0000000#5fd7ff255|n|o|t|h|e|r| +0#0000001#ffd7ff255|║| +0#0000000#ffffff0@31 -|7| @30|║+0#0000001#ffd7ff255| @8|║| +0#0000000#ffffff0@31 -|8| @30|╚+0#0000001#ffd7ff255|═@8|╝| +0#0000000#ffffff0@31 +|2| @20|╔+0#0000001#ffd7ff255| |m|a|k|e| |a| |c|h|o|i|c|e| |f|r|o|m| |t|h|e| |l|i|s|t| |╗| +0#0000000#ffffff0@21 +|3| @20|║+0#0000001#ffd7ff255| @28|║| +0#0000000#ffffff0@21 +|4| @20|║+0#0000001#ffd7ff255| |o|n|e| @24|║| +0#0000000#ffffff0@21 +|5| @20|║+0#0000001#ffd7ff255| |t|w|o| @24|║| +0#0000000#ffffff0@21 +|6| @20|║+0#0000001#ffd7ff255| |a+0#0000000#5fd7ff255|n|o|t|h|e|r| +0#0000001#ffd7ff255@20|║| +0#0000000#ffffff0@21 +|7| @20|║+0#0000001#ffd7ff255| @28|║| +0#0000000#ffffff0@21 +|8| @20|╚+0#0000001#ffd7ff255|═@28|╝| +0#0000000#ffffff0@21 |9| @73 @57|1|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_title.dump b/src/testdir/dumps/Test_popupwin_title.dump new file mode 100644 index 0000000000..ae15279aa8 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_title.dump @@ -0,0 +1,10 @@ +>1+0&#ffffff0| @73 +|2| @73 +|3| @73 +|4| @28| +0#0000001#ffd7ff255|T|i|t|l|e| |S|t|r|i|n|g| | +0#0000000#ffffff0@30 +|5| @28|o+0#0000001#ffd7ff255|n|e| @10| +0#0000000#ffffff0@30 +|6| @28|t+0#0000001#ffd7ff255|w|o| @10| +0#0000000#ffffff0@30 +|7| @28|a+0#0000001#ffd7ff255|n|o|t|h|e|r| @6| +0#0000000#ffffff0@30 +|8| @73 +|9| @73 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 477cda38ae..3f5c9d1691 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -940,7 +940,7 @@ func Test_popup_menu_screenshot() let lines =<< trim END call setline(1, range(1, 20)) hi PopupSelected ctermbg=lightblue - call popup_menu(['one', 'two', 'another'], {'callback': 'MenuDone'}) + call popup_menu(['one', 'two', 'another'], {'callback': 'MenuDone', 'title': ' make a choice from the list '}) func MenuDone(id, res) echomsg "selected " .. a:res endfunc @@ -960,6 +960,26 @@ func Test_popup_menu_screenshot() call delete('XtestPopupMenu') endfunc +func Test_popup_title() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + " Create a popup without title or border, a line of padding will be added to + " put the title on. + let lines =<< trim END + call setline(1, range(1, 20)) + call popup_create(['one', 'two', 'another'], {'title': 'Title String'}) + END + call writefile(lines, 'XtestPopupTitle') + let buf = RunVimInTerminal('-S XtestPopupTitle', {'rows': 10}) + call VerifyScreenDump(buf, 'Test_popupwin_title', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupTitle') +endfunc + func Test_popup_close_callback() func PopupDone(id, result) let g:result = a:result diff --git a/src/version.c b/src/version.c index a59803bb9f..ad09b56ef0 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 */ +/**/ + 1559, /**/ 1558, /**/ diff --git a/src/window.c b/src/window.c index ee616ee968..7f8bb784fa 100644 --- a/src/window.c +++ b/src/window.c @@ -4857,6 +4857,7 @@ win_free( free_callback(&wp->w_filter_cb); for (i = 0; i < 4; ++i) VIM_CLEAR(wp->w_border_highlight[i]); + vim_free(wp->w_popup_title); #endif #ifdef FEAT_SYN_HL From 6313c4f41d0e1d91b4217557685c014ea919915f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 20:39:13 +0200 Subject: [PATCH 43/44] patch 8.1.1560: popup window hidden option not implemented yet Problem: Popup window hidden option not implemented yet. Solution: Implement the hidden option. --- src/popupwin.c | 7 +++++++ src/testdir/test_popupwin.vim | 38 +++++++++++++++++++++++++++++++++-- src/version.c | 2 ++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 3603a1c717..c042fe82d8 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -428,6 +428,13 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) semsg(_(e_invarg2), tv_get_string(&di->di_tv)); } + nr = dict_get_number(dict, (char_u *)"hidden"); + if (nr > 0) + { + wp->w_popup_flags |= POPF_HIDDEN; + --wp->w_buffer->b_nwindows; + } + popup_mask_refresh = TRUE; } diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 3f5c9d1691..749660805c 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1310,7 +1310,7 @@ func Test_notifications() call delete('XtestNotifications') endfunc -function Test_popup_settext() +func Test_popup_settext() if !CanRunVimInTerminal() throw 'Skipped: cannot make screendumps' endif @@ -1352,4 +1352,38 @@ function Test_popup_settext() " clean up call StopVimInTerminal(buf) call delete('XtestPopupSetText') -endfunction +endfunc + +func Test_popup_hidden() + new + + let winid = popup_atcursor('text', {'hidden': 1}) + redraw + call assert_equal(0, popup_getpos(winid).visible) + call popup_close(winid) + + let winid = popup_create('text', {'hidden': 1}) + redraw + call assert_equal(0, popup_getpos(winid).visible) + call popup_close(winid) + + func QuitCallback(id, res) + let s:cb_winid = a:id + let s:cb_res = a:res + endfunc + let winid = popup_dialog('make a choice', {'hidden': 1, + \ 'filter': 'popup_filter_yesno', + \ 'callback': 'QuitCallback', + \ }) + redraw + call assert_equal(0, popup_getpos(winid).visible) + exe "normal anot used by filter\" + call assert_equal('not used by filter', getline(1)) + + call popup_show(winid) + call feedkeys('y', "xt") + call assert_equal(1, s:cb_res) + + bwipe! + delfunc QuitCallback +endfunc diff --git a/src/version.c b/src/version.c index ad09b56ef0..ea203f6913 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 */ +/**/ + 1560, /**/ 1559, /**/ From ae943150d3a2868a89df802c9f530331474451ec Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 Jun 2019 22:54:14 +0200 Subject: [PATCH 44/44] patch 8.1.1561: popup_setoptions() is not implemented yet Problem: Popup_setoptions() is not implemented yet. Solution: Implement popup_setoptions(). Also add more fields to popup_getoptions(). --- runtime/doc/popup.txt | 46 ++++- src/dict.c | 21 +++ src/evalfunc.c | 1 + src/popupwin.c | 312 +++++++++++++++++++++++++--------- src/proto/dict.pro | 1 + src/proto/popupwin.pro | 1 + src/testdir/runtest.vim | 5 + src/testdir/test_popupwin.vim | 64 ++++++- src/version.c | 2 + 9 files changed, 364 insertions(+), 89 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 398c6cc299..51b2849046 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -109,8 +109,6 @@ TODO: - When the lines do not fit show a scrollbar (like in the popup menu). Use the mouse wheel for scrolling. - Implement: - popup_setoptions({id}, {options}) - hidden option tabpage option with number flip option transparent text property @@ -247,11 +245,15 @@ popup_getoptions({id}) *popup_getoptions()* A zero value means the option was not set. For "zindex" the default value is returned, not zero. - The "highlight" entry is omitted, use the 'wincolor' option - for that: > - let hl = getwinvar(winid, '&wincolor') + The "moved" entry is a list with minimum and maximum column, + [0, 0] when not set. -< If popup window {id} is not found an empty Dict is returned. + "border" and "padding" are not included when all values are + zero. When all values are one then an empty list is included. + + "borderhighlight" is not included when all values are empty. + + If popup window {id} is not found an empty Dict is returned. popup_getpos({id}) *popup_getpos()* @@ -307,9 +309,17 @@ popup_menu({text}, {options}) *popup_menu()* popup_move({id}, {options}) *popup_move()* Move popup {id} to the position specified with {options}. {options} may contain the items from |popup_create()| that - specify the popup position: "line", "col", "pos", "maxheight", - "minheight", "maxwidth" and "minwidth". + specify the popup position: + line + col + pos + maxheight + minheight + maxwidth + minwidth + fixed For {id} see `popup_hide()`. + For other options see |popup_setoptions()|. popup_notification({text}, {options}) *popup_notification()* @@ -341,8 +351,26 @@ popup_show({id}) *popup_show()* popup_setoptions({id}, {options}) *popup_setoptions()* - {not implemented yet} Override options in popup {id} with entries in {options}. + These options can be set: + flip + firstline + title + wrap + drag + highlight + padding + border + borderhighlight + borderchars + zindex + time + moved + filter + callback + The options from |popup_move()| can also be used. + For "hidden" use |popup_hide()| and |popup_show()|. + "tabpage" cannot be changed. popup_settext({id}, {text}) *popup_settext()* Set the text of the buffer in poup win {id}. {text} is the diff --git a/src/dict.c b/src/dict.c index c67eb42c58..ffcb100624 100644 --- a/src/dict.c +++ b/src/dict.c @@ -447,6 +447,27 @@ dict_add_list(dict_T *d, char *key, list_T *list) return OK; } +/* + * Add a callback to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_callback(dict_T *d, char *key, callback_T *cb) +{ + dictitem_T *item; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + put_callback(cb, &item->di_tv); + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; +} + /* * Initializes "iter" for iterating over dictionary items with * dict_iterate_next(). diff --git a/src/evalfunc.c b/src/evalfunc.c index b98c7e72ec..66612e8c83 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -824,6 +824,7 @@ static struct fst {"popup_menu", 2, 2, f_popup_menu}, {"popup_move", 2, 2, f_popup_move}, {"popup_notification", 2, 2, f_popup_notification}, + {"popup_setoptions", 2, 2, f_popup_setoptions}, {"popup_settext", 2, 2, f_popup_settext}, {"popup_show", 1, 1, f_popup_show}, #endif diff --git a/src/popupwin.c b/src/popupwin.c index c042fe82d8..d777ae582a 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -106,7 +106,7 @@ get_pos_options(win_T *wp, dict_T *dict) } static void -get_padding_border(dict_T *dict, int *array, char *name, int max_val) +set_padding_border(dict_T *dict, int *array, char *name, int max_val) { dictitem_T *di; @@ -251,48 +251,41 @@ popup_add_timeout(win_T *wp, int time) #endif /* - * Go through the options in "dict" and apply them to buffer "buf" displayed in - * popup window "wp". + * Shared between popup_create() and f_popup_move(). */ static void -apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) +apply_move_options(win_T *wp, dict_T *d) { + int nr; + + if ((nr = dict_get_number(d, (char_u *)"minwidth")) > 0) + wp->w_minwidth = nr; + if ((nr = dict_get_number(d, (char_u *)"minheight")) > 0) + wp->w_minheight = nr; + if ((nr = dict_get_number(d, (char_u *)"maxwidth")) > 0) + wp->w_maxwidth = nr; + if ((nr = dict_get_number(d, (char_u *)"maxheight")) > 0) + wp->w_maxheight = nr; + get_pos_options(wp, d); +} + +/* + * Shared between popup_create() and f_popup_setoptions(). + */ + static void +apply_general_options(win_T *wp, dict_T *dict) +{ + dictitem_T *di; int nr; char_u *str; - dictitem_T *di; - int i; - di = dict_find(dict, (char_u *)"minwidth", -1); + // TODO: flip + + di = dict_find(dict, (char_u *)"firstline", -1); if (di != NULL) - wp->w_minwidth = dict_get_number(dict, (char_u *)"minwidth"); - wp->w_minheight = dict_get_number(dict, (char_u *)"minheight"); - wp->w_maxwidth = dict_get_number(dict, (char_u *)"maxwidth"); - wp->w_maxheight = dict_get_number(dict, (char_u *)"maxheight"); - - get_pos_options(wp, dict); - - di = dict_find(dict, (char_u *)"zindex", -1); - if (di != NULL) - { - wp->w_zindex = dict_get_number(dict, (char_u *)"zindex"); - if (wp->w_zindex < 1) - wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX; - if (wp->w_zindex > 32000) - wp->w_zindex = 32000; - } - -#if defined(FEAT_TIMERS) - // Add timer to close the popup after some time. - nr = dict_get_number(dict, (char_u *)"time"); - if (nr > 0) - popup_add_timeout(wp, nr); -#endif - - // Option values resulting in setting an option. - str = dict_get_string(dict, (char_u *)"highlight", FALSE); - if (str != NULL) - set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1, - str, OPT_FREE|OPT_LOCAL, 0); + wp->w_firstline = dict_get_number(dict, (char_u *)"firstline"); + if (wp->w_firstline < 1) + wp->w_firstline = 1; str = dict_get_string(dict, (char_u *)"title", FALSE); if (str != NULL) @@ -301,10 +294,6 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) wp->w_popup_title = vim_strsave(str); } - wp->w_firstline = dict_get_number(dict, (char_u *)"firstline"); - if (wp->w_firstline < 1) - wp->w_firstline = 1; - di = dict_find(dict, (char_u *)"wrap", -1); if (di != NULL) { @@ -316,29 +305,14 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) if (di != NULL) wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag"); - di = dict_find(dict, (char_u *)"callback", -1); - if (di != NULL) - { - callback_T callback = get_callback(&di->di_tv); + str = dict_get_string(dict, (char_u *)"highlight", FALSE); + if (str != NULL) + set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1, + str, OPT_FREE|OPT_LOCAL, 0); - if (callback.cb_name != NULL) - set_callback(&wp->w_close_cb, &callback); - } + set_padding_border(dict, wp->w_popup_padding, "padding", 999); + set_padding_border(dict, wp->w_popup_border, "border", 1); - di = dict_find(dict, (char_u *)"filter", -1); - if (di != NULL) - { - callback_T callback = get_callback(&di->di_tv); - - if (callback.cb_name != NULL) - set_callback(&wp->w_filter_cb, &callback); - } - - get_padding_border(dict, wp->w_popup_padding, "padding", 999); - get_padding_border(dict, wp->w_popup_border, "border", 1); - - for (i = 0; i < 4; ++i) - VIM_CLEAR(wp->w_border_highlight[i]); di = dict_find(dict, (char_u *)"borderhighlight", -1); if (di != NULL) { @@ -348,6 +322,7 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) { list_T *list = di->di_tv.vval.v_list; listitem_T *li; + int i; if (list != NULL) for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len; @@ -364,8 +339,6 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) } } - for (i = 0; i < 8; ++i) - wp->w_border_char[i] = 0; di = dict_find(dict, (char_u *)"borderchars", -1); if (di != NULL) { @@ -375,6 +348,7 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) { list_T *list = di->di_tv.vval.v_list; listitem_T *li; + int i; if (list != NULL) for (i = 0, li = list->lv_first; i < 8 && i < list->lv_len; @@ -397,6 +371,23 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) } } + di = dict_find(dict, (char_u *)"zindex", -1); + if (di != NULL) + { + wp->w_zindex = dict_get_number(dict, (char_u *)"zindex"); + if (wp->w_zindex < 1) + wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX; + if (wp->w_zindex > 32000) + wp->w_zindex = 32000; + } + +#if defined(FEAT_TIMERS) + // Add timer to close the popup after some time. + nr = dict_get_number(dict, (char_u *)"time"); + if (nr > 0) + popup_add_timeout(wp, nr); +#endif + di = dict_find(dict, (char_u *)"moved", -1); if (di != NULL) { @@ -428,6 +419,42 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict) semsg(_(e_invarg2), tv_get_string(&di->di_tv)); } + di = dict_find(dict, (char_u *)"filter", -1); + if (di != NULL) + { + callback_T callback = get_callback(&di->di_tv); + + if (callback.cb_name != NULL) + { + free_callback(&wp->w_filter_cb); + set_callback(&wp->w_filter_cb, &callback); + } + } + + di = dict_find(dict, (char_u *)"callback", -1); + if (di != NULL) + { + callback_T callback = get_callback(&di->di_tv); + + if (callback.cb_name != NULL) + { + free_callback(&wp->w_close_cb); + set_callback(&wp->w_close_cb, &callback); + } + } +} + +/* + * Go through the options in "dict" and apply them to popup window "wp". + */ + static void +apply_options(win_T *wp, dict_T *dict) +{ + int nr; + + apply_move_options(wp, dict); + apply_general_options(wp, dict); + nr = dict_get_number(dict, (char_u *)"hidden"); if (nr > 0) { @@ -804,6 +831,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) buf_T *buf; dict_T *d; int nr; + int i; // Check arguments look OK. if (!(argvars[0].v_type == VAR_STRING && argvars[0].vval.v_string != NULL) @@ -903,7 +931,6 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) { win_T *twp, *nextwin; int height = buf->b_ml.ml_line_count + 3; - int i; // Try to not overlap with another global popup. Guess we need 3 // more screen lines than buffer lines. @@ -946,8 +973,6 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) if (type == TYPE_DIALOG || type == TYPE_MENU) { - int i; - wp->w_popup_pos = POPPOS_CENTER; wp->w_zindex = POPUPWIN_DIALOG_ZINDEX; wp->w_popup_drag = 1; @@ -972,8 +997,13 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) wp->w_p_wrap = 0; } + for (i = 0; i < 4; ++i) + VIM_CLEAR(wp->w_border_highlight[i]); + for (i = 0; i < 8; ++i) + wp->w_border_char[i] = 0; + // Deal with options. - apply_options(wp, buf, argvars[1].vval.v_dict); + apply_options(wp, argvars[1].vval.v_dict); if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL) popup_add_timeout(wp, 3000); @@ -1375,8 +1405,7 @@ close_all_popups(void) void f_popup_move(typval_T *argvars, typval_T *rettv UNUSED) { - dict_T *d; - int nr; + dict_T *dict; int id = (int)tv_get_number(argvars); win_T *wp = find_popup_win(id); @@ -1388,23 +1417,41 @@ f_popup_move(typval_T *argvars, typval_T *rettv UNUSED) emsg(_(e_dictreq)); return; } - d = argvars[1].vval.v_dict; + dict = argvars[1].vval.v_dict; - if ((nr = dict_get_number(d, (char_u *)"minwidth")) > 0) - wp->w_minwidth = nr; - if ((nr = dict_get_number(d, (char_u *)"minheight")) > 0) - wp->w_minheight = nr; - if ((nr = dict_get_number(d, (char_u *)"maxwidth")) > 0) - wp->w_maxwidth = nr; - if ((nr = dict_get_number(d, (char_u *)"maxheight")) > 0) - wp->w_maxheight = nr; - get_pos_options(wp, d); + apply_move_options(wp, dict); if (wp->w_winrow + wp->w_height >= cmdline_row) clear_cmdline = TRUE; popup_adjust_position(wp); } +/* + * popup_setoptions({id}, {options}) + */ + void +f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED) +{ + dict_T *dict; + int id = (int)tv_get_number(argvars); + win_T *wp = find_popup_win(id); + + if (wp == NULL) + return; // invalid {id} + + if (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL) + { + emsg(_(e_dictreq)); + return; + } + dict = argvars[1].vval.v_dict; + + apply_move_options(wp, dict); + apply_general_options(wp, dict); + + popup_adjust_position(wp); +} + /* * popup_getpos({id}) */ @@ -1443,6 +1490,98 @@ f_popup_getpos(typval_T *argvars, typval_T *rettv) } } +/* + * For popup_getoptions(): add a "border" or "padding" entry to "dict". + */ + static void +get_padding_border(dict_T *dict, int *array, char *name) +{ + list_T *list; + int i; + + if (array[0] == 0 && array[1] == 0 && array[2] == 0 && array[3] == 0) + return; + + list = list_alloc(); + if (list != NULL) + { + dict_add_list(dict, name, list); + if (array[0] != 1 || array[1] != 1 || array[2] != 1 || array[3] != 1) + for (i = 0; i < 4; ++i) + list_append_number(list, array[i]); + } +} + +/* + * For popup_getoptions(): add a "borderhighlight" entry to "dict". + */ + static void +get_borderhighlight(dict_T *dict, win_T *wp) +{ + list_T *list; + int i; + + for (i = 0; i < 4; ++i) + if (wp->w_border_highlight[i] != NULL) + break; + if (i == 4) + return; + + list = list_alloc(); + if (list != NULL) + { + dict_add_list(dict, "borderhighlight", list); + for (i = 0; i < 4; ++i) + list_append_string(list, wp->w_border_highlight[i], -1); + } +} + +/* + * For popup_getoptions(): add a "borderchars" entry to "dict". + */ + static void +get_borderchars(dict_T *dict, win_T *wp) +{ + list_T *list; + int i; + char_u buf[NUMBUFLEN]; + int len; + + for (i = 0; i < 8; ++i) + if (wp->w_border_char[i] != 0) + break; + if (i == 8) + return; + + list = list_alloc(); + if (list != NULL) + { + dict_add_list(dict, "borderchars", list); + for (i = 0; i < 8; ++i) + { + len = mb_char2bytes(wp->w_border_char[i], buf); + list_append_string(list, buf, len); + } + } +} + +/* + * For popup_getoptions(): add a "moved" entry to "dict". + */ + static void +get_moved_list(dict_T *dict, win_T *wp) +{ + list_T *list; + + list = list_alloc(); + if (list != NULL) + { + dict_add_list(dict, "moved", list); + list_append_number(list, wp->w_popup_mincol); + list_append_number(list, wp->w_popup_maxcol); + } +} + /* * popup_getoptions({id}) */ @@ -1469,6 +1608,21 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv) dict_add_number(dict, "firstline", wp->w_firstline); dict_add_number(dict, "zindex", wp->w_zindex); dict_add_number(dict, "fixed", wp->w_popup_fixed); + 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_string(dict, "highlight", wp->w_p_wcr); + + get_padding_border(dict, wp->w_popup_padding, "padding"); + get_padding_border(dict, wp->w_popup_border, "border"); + get_borderhighlight(dict, wp); + get_borderchars(dict, wp); + get_moved_list(dict, wp); + + if (wp->w_filter_cb.cb_name != NULL) + dict_add_callback(dict, "filter", &wp->w_filter_cb); + if (wp->w_close_cb.cb_name != NULL) + dict_add_callback(dict, "callback", &wp->w_close_cb); for (i = 0; i < (int)(sizeof(poppos_entries) / sizeof(poppos_entry_T)); ++i) diff --git a/src/proto/dict.pro b/src/proto/dict.pro index d4820256d1..3d31347a48 100644 --- a/src/proto/dict.pro +++ b/src/proto/dict.pro @@ -18,6 +18,7 @@ int dict_add_special(dict_T *d, char *key, varnumber_T nr); int dict_add_string(dict_T *d, char *key, char_u *str); int dict_add_string_len(dict_T *d, char *key, char_u *str, int len); int dict_add_list(dict_T *d, char *key, list_T *list); +int dict_add_callback(dict_T *d, char *key, callback_T *cb); void dict_iterate_start(typval_T *var, dict_iterator_T *iter); char_u *dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result); int dict_add_dict(dict_T *d, char *key, dict_T *dict); diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index fefb031422..6c5ea46751 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -21,6 +21,7 @@ void popup_close(int id); void popup_close_tabpage(tabpage_T *tp, int id); void close_all_popups(void); void f_popup_move(typval_T *argvars, typval_T *rettv); +void f_popup_setoptions(typval_T *argvars, typval_T *rettv); void f_popup_getpos(typval_T *argvars, typval_T *rettv); void f_popup_getoptions(typval_T *argvars, typval_T *rettv); int error_if_popup_window(void); diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index 45d3b1d5ef..e120e7f23b 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -170,6 +170,11 @@ func RunTheTest(test) au! au SwapExists * call HandleSwapExists() + " Close any stray popup windows + if has('textprop') + call popup_clear() + endif + " Close any extra tab pages and windows and make the current one not modified. while tabpagenr('$') > 1 quit! diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 749660805c..f16a46f261 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -129,9 +129,29 @@ func Test_popup_with_border_and_padding() \ 'visible': 1} let winid = popup_create('hello border', {'line': 2, 'col': 3, 'border': []})", call assert_equal(with_border_or_padding, popup_getpos(winid)) + let options = popup_getoptions(winid) + call assert_equal([], options.border) + call assert_false(has_key(options, "padding")) - let winid = popup_create('hello paddng', {'line': 2, 'col': 3, 'padding': []}) + let winid = popup_create('hello padding', {'line': 2, 'col': 3, 'padding': []}) + let with_border_or_padding.width = 15 + let with_border_or_padding.core_width = 13 call assert_equal(with_border_or_padding, popup_getpos(winid)) + let options = popup_getoptions(winid) + call assert_false(has_key(options, "border")) + call assert_equal([], options.padding) + + call popup_setoptions(winid, { + \ 'padding': [1, 2, 3, 4], + \ 'border': [4, 0, 7, 8], + \ 'borderhighlight': ['Top', 'Right', 'Bottom', 'Left'], + \ 'borderchars': ['1', '^', '2', '>', '3', 'v', '4', '<'], + \ }) + let options = popup_getoptions(winid) + call assert_equal([1, 0, 1, 1], options.border) + call assert_equal([1, 2, 3, 4], options.padding) + call assert_equal(['Top', 'Right', 'Bottom', 'Left'], options.borderhighlight) + call assert_equal(['1', '^', '2', '>', '3', 'v', '4', '<'], options.borderchars) let winid = popup_create('hello both', {'line': 3, 'col': 8, 'border': [], 'padding': []}) call assert_equal({ @@ -144,6 +164,8 @@ func Test_popup_with_border_and_padding() \ 'height': 5, \ 'core_height': 1, \ 'visible': 1}, popup_getpos(winid)) + + call popup_clear() endfunc func Test_popup_with_syntax_win_execute() @@ -288,6 +310,16 @@ func Test_popup_firstline() " clean up call StopVimInTerminal(buf) call delete('XtestPopupFirstline') + + let winid = popup_create(['1111', '222222', '33333', '44444'], { + \ 'maxheight': 2, + \ 'firstline': 3, + \ }) + call assert_equal(3, popup_getoptions(winid).firstline) + call popup_setoptions(winid, {'firstline': 1}) + call assert_equal(1, popup_getoptions(winid).firstline) + + call popup_close(winid) endfunc func Test_popup_drag() @@ -978,6 +1010,13 @@ func Test_popup_title() " clean up call StopVimInTerminal(buf) call delete('XtestPopupTitle') + + let winid = popup_create('something', {'title': 'Some Title'}) + call assert_equal('Some Title', popup_getoptions(winid).title) + call popup_setoptions(winid, {'title': 'Another Title'}) + call assert_equal('Another Title', popup_getoptions(winid).title) + + call popup_clear() endfunc func Test_popup_close_callback() @@ -1230,6 +1269,7 @@ func Test_popup_moved() let winid = popup_atcursor('text', {'moved': 'any'}) redraw call assert_equal(1, popup_getpos(winid).visible) + call assert_equal([4, 4], popup_getoptions(winid).moved) " trigger the check for last_cursormoved by going into insert mode call feedkeys("li\", 'xt') call assert_equal({}, popup_getpos(winid)) @@ -1239,6 +1279,7 @@ func Test_popup_moved() let winid = popup_atcursor('text', {'moved': 'word'}) redraw call assert_equal(1, popup_getpos(winid).visible) + call assert_equal([4, 7], popup_getoptions(winid).moved) call feedkeys("hi\", 'xt') call assert_equal({}, popup_getpos(winid)) call popup_clear() @@ -1247,6 +1288,7 @@ func Test_popup_moved() let winid = popup_atcursor('text', {'moved': 'word'}) redraw call assert_equal(1, popup_getpos(winid).visible) + call assert_equal([4, 7], popup_getoptions(winid).moved) call feedkeys("li\", 'xt') call assert_equal(1, popup_getpos(winid).visible) call feedkeys("ei\", 'xt') @@ -1260,6 +1302,7 @@ func Test_popup_moved() let winid = popup_atcursor('text', {}) redraw call assert_equal(1, popup_getpos(winid).visible) + call assert_equal([2, 15], popup_getoptions(winid).moved) call feedkeys("eli\", 'xt') call assert_equal(1, popup_getpos(winid).visible) call feedkeys("wi\", 'xt') @@ -1377,6 +1420,8 @@ func Test_popup_hidden() \ }) redraw call assert_equal(0, popup_getpos(winid).visible) + call assert_equal(function('popup_filter_yesno'), popup_getoptions(winid).filter) + call assert_equal(function('QuitCallback'), popup_getoptions(winid).callback) exe "normal anot used by filter\" call assert_equal('not used by filter', getline(1)) @@ -1387,3 +1432,20 @@ func Test_popup_hidden() bwipe! delfunc QuitCallback endfunc + +" Test options not checked elsewhere +func Test_set_get_options() + let winid = popup_create('some text', {'highlight': 'Beautiful'}) + let options = popup_getoptions(winid) + call assert_equal(1, options.wrap) + call assert_equal(0, options.drag) + call assert_equal('Beautiful', options.highlight) + + call popup_setoptions(winid, {'wrap': 0, 'drag': 1, 'highlight': 'Another'}) + let options = popup_getoptions(winid) + call assert_equal(0, options.wrap) + call assert_equal(1, options.drag) + call assert_equal('Another', options.highlight) + + call popup_close(winid) +endfunc diff --git a/src/version.c b/src/version.c index ea203f6913..feac0855be 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 */ +/**/ + 1561, /**/ 1560, /**/