From 6cc7e21412487ff8bd531c73ac9325f5ba2409a9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 14:05:24 +0200 Subject: [PATCH 01/21] patch 8.1.1641: garbage collection may run at a wrong moment Problem: Garbage collection may run at a wrong moment. (Trygve Aaberge) Solution: Postpone garbage collection while parsing messages. (closes #4620) --- src/misc2.c | 9 +++++++++ src/version.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/misc2.c b/src/misc2.c index 892fbc56a8..000f043e13 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -4444,12 +4444,19 @@ parse_queued_messages(void) { win_T *old_curwin = curwin; int i; + int save_may_garbage_collect = may_garbage_collect; // Do not handle messages while redrawing, because it may cause buffers to // change or be wiped while they are being redrawn. if (updating_screen) return; + // may_garbage_collect is set in main_loop() to do garbage collection when + // blocking to wait on a character. We don't want that while parsing + // messages, a callback may invoke vgetc() while lists and dicts are in use + // in the call stack. + may_garbage_collect = FALSE; + // Loop when a job ended, but don't keep looping forever. for (i = 0; i < MAX_REPEAT_PARSE; ++i) { @@ -4485,6 +4492,8 @@ parse_queued_messages(void) break; } + may_garbage_collect = save_may_garbage_collect; + // If the current window changed we need to bail out of the waiting loop. // E.g. when a job exit callback closes the terminal window. if (curwin != old_curwin) diff --git a/src/version.c b/src/version.c index 85cf7b2e21..663f92f49d 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 */ +/**/ + 1641, /**/ 1640, /**/ From ec572ad6a6cb0d4e71901951a70a4f038d48cb17 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 14:26:59 +0200 Subject: [PATCH 02/21] patch 8.1.1642: may use uninitialized variable Problem: May use uninitialized variable. (Patrick Palka) Solution: Initialize variables earlier. (closes #4623) --- src/screen.c | 26 ++++++++++++++------------ src/testdir/test_number.vim | 11 +++++++++++ src/version.c | 2 ++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/screen.c b/src/screen.c index 58866bf48a..825b7ab0e8 100644 --- a/src/screen.c +++ b/src/screen.c @@ -607,6 +607,7 @@ update_screen(int type_arg) curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */ return FAIL; } + updating_screen = TRUE; #ifdef FEAT_TEXT_PROP // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot @@ -614,7 +615,6 @@ update_screen(int type_arg) may_update_popup_mask(type); #endif - updating_screen = TRUE; #ifdef FEAT_SYN_HL ++display_tick; /* let syntax code know we're in a next round of * display updating */ @@ -3189,9 +3189,10 @@ win_line( int n_skip = 0; /* nr of chars to skip for 'nowrap' */ - int fromcol, tocol; /* start/end of inverting */ - int fromcol_prev = -2; /* start of inverting after cursor */ - int noinvcur = FALSE; /* don't invert the cursor */ + int fromcol = -10; // start of inverting + int tocol = MAXCOL; // end of inverting + int fromcol_prev = -2; // start of inverting after cursor + int noinvcur = FALSE; // don't invert the cursor pos_T *top, *bot; int lnum_in_visual_area = FALSE; pos_T pos; @@ -3451,39 +3452,40 @@ win_line( #endif /* - * handle visual active in this window + * handle Visual active in this window */ - fromcol = -10; - tocol = MAXCOL; if (VIsual_active && wp->w_buffer == curwin->w_buffer) { - /* Visual is after curwin->w_cursor */ if (LTOREQ_POS(curwin->w_cursor, VIsual)) { + // Visual is after curwin->w_cursor top = &curwin->w_cursor; bot = &VIsual; } - else /* Visual is before curwin->w_cursor */ + else { + // Visual is before curwin->w_cursor top = &VIsual; bot = &curwin->w_cursor; } lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum); - if (VIsual_mode == Ctrl_V) /* block mode */ + if (VIsual_mode == Ctrl_V) { + // block mode if (lnum_in_visual_area) { fromcol = wp->w_old_cursor_fcol; tocol = wp->w_old_cursor_lcol; } } - else /* non-block mode */ + else { + // non-block mode if (lnum > top->lnum && lnum <= bot->lnum) fromcol = 0; else if (lnum == top->lnum) { - if (VIsual_mode == 'V') /* linewise */ + if (VIsual_mode == 'V') // linewise fromcol = 0; else { diff --git a/src/testdir/test_number.vim b/src/testdir/test_number.vim index 415aefc858..81326bce14 100644 --- a/src/testdir/test_number.vim +++ b/src/testdir/test_number.vim @@ -252,3 +252,14 @@ func Test_numberwidth_adjusted() call s:compare_lines(expect, lines) call s:close_windows() endfunc + +" This was causing a memcheck error +func Test_relativenumber_uninitialised() + new + set rnu + call setline(1, ["a", "b"]) + redraw + call feedkeys("j", 'xt') + redraw + bwipe! +endfunc diff --git a/src/version.c b/src/version.c index 663f92f49d..f71c75c760 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 */ +/**/ + 1642, /**/ 1641, /**/ From 899f20deae22d8cfc89d88d5f1869e5191d4b360 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 14:56:25 +0200 Subject: [PATCH 03/21] patch 8.1.1643: sign placement is wrong when 'foldcolumn' is set Problem: Sign placement is wrong when 'foldcolumn' is set. Solution: Adjust the column computation. (Yee Cheng Chin, closes #4627) --- src/gui.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui.c b/src/gui.c index 634f3fbc54..7c378c6fe1 100644 --- a/src/gui.c +++ b/src/gui.c @@ -2253,7 +2253,7 @@ gui_outstr_nowrap( int col = gui.col; #ifdef FEAT_SIGN_ICONS int draw_sign = FALSE; - int signcol = 0; + int signcol = col; char_u extra[18]; # ifdef FEAT_NETBEANS_INTG int multi_sign = FALSE; @@ -2289,7 +2289,7 @@ gui_outstr_nowrap( --col; len = (int)STRLEN(s); if (len > 2) - signcol = len - 3; // Right align sign icon in the number column + signcol = col + len - 3; // Right align sign icon in the number column draw_sign = TRUE; highlight_mask = 0; } diff --git a/src/version.c b/src/version.c index f71c75c760..c7e2a1633a 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 */ +/**/ + 1643, /**/ 1642, /**/ From 5b19e5b919ec568792e2e2301899f0e58cf9e550 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 15:12:12 +0200 Subject: [PATCH 04/21] patch 8.1.1644: sound test does not work on Travis Problem: Sound test does not work on Travis. Solution: Use "sg" command to enable audio. (Ozaki Kiichi, closes #4624) --- .travis.yml | 5 ++++- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b669a908f6..77503084b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,6 +75,7 @@ anchors: - sh -e /etc/init.d/xvfb start && sleep 3 - sudo modprobe snd-dummy - sudo usermod -a -G audio $USER + - do_test() { sg audio "sg $(id -gn) '$*'"; } osx: &osx os: osx @@ -91,6 +92,8 @@ anchors: - rvm reset # Lua is not installed on Travis OSX - export LUA_PREFIX=/usr/local + before_script: + - do_test() { "$@"; } 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 @@ -139,7 +142,7 @@ script: "${SRCDIR}"/vim --not-a-term -u NONE -S "${SRCDIR}"/testdir/if_ver-2.vim -c quit > /dev/null cat if_ver.txt fi - - make ${SHADOWOPT} ${TEST} + - do_test make ${SHADOWOPT} ${TEST} - echo -en "travis_fold:end:test\\r\\033[0K" # instead of a 2*2*8 matrix (2*os + 2*compiler + 8*env), diff --git a/src/version.c b/src/version.c index c7e2a1633a..754155bfd2 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 */ +/**/ + 1644, /**/ 1643, /**/ From b3d17a20d243f65bcfe23de08b7afd948c5132c2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 18:28:14 +0200 Subject: [PATCH 05/21] patch 8.1.1645: cannot use a popup window for a balloon Problem: Cannot use a popup window for a balloon. Solution: Add popup_beval(). Add the "mousemoved" property. Add the screenpos() function. --- runtime/doc/eval.txt | 19 ++ runtime/doc/popup.txt | 64 ++++++- runtime/doc/usr_41.txt | 3 + src/beval.c | 88 ++++++--- src/evalfunc.c | 2 + src/move.c | 90 +++++++++ src/normal.c | 3 + src/popupmnu.c | 7 +- src/popupwin.c | 190 ++++++++++++++++--- src/proto/beval.pro | 1 + src/proto/move.pro | 1 + src/proto/popupwin.pro | 2 + src/testdir/dumps/Test_popupwin_beval_1.dump | 10 + src/testdir/dumps/Test_popupwin_beval_2.dump | 10 + src/testdir/dumps/Test_popupwin_beval_3.dump | 10 + src/testdir/test_cursor_func.vim | 28 +++ src/testdir/test_popupwin.vim | 55 +++++- src/version.c | 2 + 18 files changed, 522 insertions(+), 63 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_beval_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_beval_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_beval_3.dump diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 24253d15dd..aa68fc7fdb 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2535,6 +2535,7 @@ or({expr}, {expr}) Number bitwise OR pathshorten({expr}) String shorten directory names in a path perleval({expr}) any evaluate |Perl| expression popup_atcursor({what}, {options}) Number create popup window near the cursor +popup_beval({what}, {options}) Number create popup window for 'ballooneval' popup_clear() none close all popup windows popup_close({id} [, {result}]) none close popup window {id} popup_create({what}, {options}) Number create a popup window @@ -2613,6 +2614,7 @@ screenattr({row}, {col}) Number attribute at screen position screenchar({row}, {col}) Number character at screen position screenchars({row}, {col}) List List of characters at screen position screencol() Number current cursor column +screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character screenrow() Number current cursor row screenstring({row}, {col}) String characters at screen position search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) @@ -7907,6 +7909,23 @@ screencol() *screencol()* nnoremap GG ":echom ".screencol()."\n" nnoremap GG :echom screencol() < +screenpos({winid}, {lnum}, {col}) *screenpos()* + The result is a Dict with the screen position of the text + character in window {winid} at buffer line {lnum} and column + {col}. {col} is a one-based byte index. + The Dict has these members: + row screen row + col first screen column + endcol last screen column + curscol cursor screen column + If the specified position is not visible, all values are zero. + The "endcol" value differs from "col" when the character + occupies more than one screen cell. E.g. for a Tab "col" can + be 1 and "endcol" can be 8. + The "curscol" value is where the cursor would be placed. For + a Tab it would be the same as "endcol", while for a double + width character it would be the same as "col". + screenrow() *screenrow()* The result is a Number, which is the current screen row of the cursor. The top line has number one. diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 3fb6f6bf8e..13674109ee 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -146,6 +146,8 @@ Creating a popup window: |popup_create()| centered in the screen |popup_atcursor()| just above the cursor position, closes when the cursor moves away + |popup_beval()| at the position indicated by v:beval_ + variables, closes when the mouse moves away |popup_notification()| show a notification for three seconds |popup_dialog()| centered with padding and border |popup_menu()| prompt for selecting an item from a list @@ -184,6 +186,20 @@ popup_atcursor({what}, {options}) *popup_atcursor()* < Use {options} to change the properties. +popup_beval({what}, {options}) *popup_beval()* + Show the {what} above the position from 'ballooneval' and + close it when the mouse moves. This works like: > + let pos = screenpos(v:beval_winnr, v:beval_lnum, v:beval_col) + call popup_create({what}, { + \ 'pos': 'botleft', + \ 'line': pos.lnum - 1, + \ 'col': pos.col, + \ 'mousemoved': 'WORD', + \ }) +< Use {options} to change the properties. + See |popup_beval_example| for an example use. + + *popup_clear()* popup_clear() Emergency solution to a misbehaving plugin: close all popup windows for the current tab and global popups. @@ -276,8 +292,11 @@ popup_getoptions({id}) *popup_getoptions()* A zero value means the option was not set. For "zindex" the default value is returned, not zero. - The "moved" entry is a list with minimum and maximum column, - [0, 0] when not set. + The "moved" entry is a list with line number, minimum and + maximum column, [0, 0, 0] when not set. + + The "mousemoved" entry is a list with screen row, minimum and + maximum screen column, [0, 0, 0] when not set. "border" and "padding" are not included when all values are zero. When all values are one then an empty list is included. @@ -566,6 +585,7 @@ The second argument of |popup_create()| is a dictionary with options: - "any": if the cursor moved at all - "word": if the cursor moved outside || - "WORD": if the cursor moved outside || + - "expr": if the cursor moved outside || - [{start}, {end}]: if the cursor moved before column {start} or after {end} The popup also closes if the cursor moves to another @@ -736,5 +756,45 @@ Extend popup_filter_menu() with shortcut keys: > return popup_filter_menu(a:id, a:key) endfunc < + *popup_beval_example* +Example for using a popup window for 'ballooneval': > + + set ballooneval balloonevalterm + set balloonexpr=BalloonExpr() + let s:winid = 0 + + func BalloonExpr() + if s:winid + call popup_close(s:winid) + let s:winid = 0 + endif + let s:winid = popup_beval([bufname(v:beval_bufnr), v:beval_text], {}) + return '' + endfunc +< +If the text has to be obtained asynchronously return an empty string from the +expression function and call popup_beval() once the text is available. In +this example similated with a timer callback: > + + set ballooneval balloonevalterm + set balloonexpr=BalloonExpr() + let s:winid = 0 + + func BalloonExpr() + if s:winid + call popup_close(s:winid) + let s:winid = 0 + endif + " simulate an asynchronous loopup for the text to display + let s:balloonFile = bufname(v:beval_bufnr) + let s:balloonWord = v:beval_text + call timer_start(100, 'ShowPopup') + return '' + endfunc + + func ShowPopup(id) + let s:winid = popup_beval([s:balloonFile, s:balloonWord], {}) + endfunc +< vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 6a4e4a66fd..34d60f101b 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -720,6 +720,7 @@ Cursor and mark position: *cursor-functions* *mark-functions* cursor() position the cursor at a line/column screencol() get screen column of the cursor screenrow() get screen row of the cursor + screenpos() screen row and col of a text character getcurpos() get position of the cursor getpos() get position of cursor, mark, etc. setpos() set position of cursor, mark, etc. @@ -1046,6 +1047,8 @@ Popup window: *popup-window-functions* popup_create() create popup centered in the screen popup_atcursor() create popup just above the cursor position, closes when the cursor moves away + popup_beval() at the position indicated by v:beval_ + variables, closes when the mouse moves away popup_notification() show a notification for three seconds popup_dialog() create popup centered with padding and border popup_menu() prompt for selecting an item from a list diff --git a/src/beval.c b/src/beval.c index e89b1fe50b..2cbe7ea1f0 100644 --- a/src/beval.c +++ b/src/beval.c @@ -14,7 +14,7 @@ /* * Get the text and position to be evaluated for "beval". - * If "getword" is true the returned text is not the whole line but the + * If "getword" is TRUE the returned text is not the whole line but the * relevant word in allocated memory. * Returns OK or FAIL. */ @@ -27,12 +27,8 @@ get_beval_info( char_u **textp, int *colp) { - win_T *wp; int row, col; - char_u *lbuf; - linenr_T lnum; - *textp = NULL; # ifdef FEAT_BEVAL_TERM # ifdef FEAT_GUI if (!gui.in_use) @@ -49,22 +45,68 @@ get_beval_info( col = X_2_COL(beval->x); } #endif + if (find_word_under_cursor(row, col, getword, + FIND_IDENT + FIND_STRING + FIND_EVAL, + winp, lnump, textp, colp) == OK) + { +#ifdef FEAT_VARTABS + vim_free(beval->vts); + beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array); + if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL) + { + if (getword) + vim_free(*textp); + return FAIL; + } +#endif + beval->ts = (*winp)->w_buffer->b_p_ts; + return OK; + } + + return FAIL; +} + +/* + * Find text under the mouse position "row" / "col". + * If "getword" is TRUE the returned text in "*textp" is not the whole line but + * the relevant word in allocated memory. + * Return OK if found. + * Return FAIL if not found, no text at the mouse position. + */ + int +find_word_under_cursor( + int mouserow, + int mousecol, + int getword, + int flags, // flags for find_ident_at_pos() + win_T **winp, // can be NULL + linenr_T *lnump, // can be NULL + char_u **textp, + int *colp) +{ + int row = mouserow; + int col = mousecol; + win_T *wp; + char_u *lbuf; + linenr_T lnum; + + *textp = NULL; 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 - * number. */ + // Found a window and the cursor is in the text. Now find the line + // number. if (!mouse_comp_pos(wp, &row, &col, &lnum)) { - /* Not past end of the file. */ + // Not past end of the file. lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE); if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL)) { - /* Not past end of line. */ + // Not past end of line. if (getword) { - /* For Netbeans we get the relevant part of the line - * instead of the whole line. */ + // For Netbeans we get the relevant part of the line + // instead of the whole line. int len; pos_T *spos = NULL, *epos = NULL; @@ -93,9 +135,9 @@ get_beval_info( ? col <= (int)epos->col : lnum < epos->lnum)) { - /* Visual mode and pointing to the line with the - * Visual selection: return selected text, with a - * maximum of one line. */ + // Visual mode and pointing to the line with the + // Visual selection: return selected text, with a + // maximum of one line. if (spos->lnum != epos->lnum || spos->col == epos->col) return FAIL; @@ -109,10 +151,10 @@ get_beval_info( } else { - /* Find the word under the cursor. */ + // Find the word under the cursor. ++emsg_off; len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf, - FIND_IDENT + FIND_STRING + FIND_EVAL); + flags); --emsg_off; if (len == 0) return FAIL; @@ -120,22 +162,16 @@ get_beval_info( } } - *winp = wp; - *lnump = lnum; + if (winp != NULL) + *winp = wp; + if (lnump != NULL) + *lnump = lnum; *textp = lbuf; *colp = col; -#ifdef FEAT_VARTABS - vim_free(beval->vts); - beval->vts = tabstop_copy(wp->w_buffer->b_p_vts_array); - if (wp->w_buffer->b_p_vts_array != NULL && beval->vts == NULL) - return FAIL; -#endif - beval->ts = wp->w_buffer->b_p_ts; return OK; } } } - return FAIL; } diff --git a/src/evalfunc.c b/src/evalfunc.c index 925040d2b0..b6998993f6 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -771,6 +771,7 @@ static struct fst #endif #ifdef FEAT_TEXT_PROP {"popup_atcursor", 2, 2, f_popup_atcursor}, + {"popup_beval", 2, 2, f_popup_beval}, {"popup_clear", 0, 0, f_popup_clear}, {"popup_close", 1, 2, f_popup_close}, {"popup_create", 2, 2, f_popup_create}, @@ -849,6 +850,7 @@ static struct fst {"screenchar", 2, 2, f_screenchar}, {"screenchars", 2, 2, f_screenchars}, {"screencol", 0, 0, f_screencol}, + {"screenpos", 3, 3, f_screenpos}, {"screenrow", 0, 0, f_screenrow}, {"screenstring", 2, 2, f_screenstring}, {"search", 1, 4, f_search}, diff --git a/src/move.c b/src/move.c index 232a87506d..0df4fe5ba4 100644 --- a/src/move.c +++ b/src/move.c @@ -1189,6 +1189,96 @@ curs_columns( curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; } +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Compute the screen position of text character at "pos" in window "wp" + * The resulting values are one-based, zero when character is not visible. + */ + static void +textpos2screenpos( + win_T *wp, + pos_T *pos, + int *rowp, // screen row + int *scolp, // start screen column + int *ccolp, // cursor screen column + int *ecolp) // end screen column +{ + colnr_T scol = 0, ccol = 0, ecol = 0; + int row = 0; + int rowoff = 0; + colnr_T coloff = 0; + + if (pos->lnum >= wp->w_topline && pos->lnum < wp->w_botline) + { + colnr_T off; + colnr_T col; + int width; + + row = plines_m_win(wp, wp->w_topline, pos->lnum - 1) + 1; + getvcol(wp, pos, &scol, &ccol, &ecol); + + // similar to what is done in validate_cursor_col() + col = scol; + off = win_col_off(wp); + col += off; + width = wp->w_width - off + win_col_off2(wp); + + /* long line wrapping, adjust row */ + if (wp->w_p_wrap + && col >= (colnr_T)wp->w_width + && width > 0) + { + /* use same formula as what is used in curs_columns() */ + rowoff = ((col - wp->w_width) / width + 1); + col -= rowoff * width; + } + col -= wp->w_leftcol; + if (col >= width) + col = -1; + if (col >= 0) + coloff = col - scol + wp->w_wincol + 1; + else + // character is left or right of the window + row = scol = ccol = ecol = 0; + } + *rowp = wp->w_winrow + row + rowoff; + *scolp = scol + coloff; + *ccolp = ccol + coloff; + *ecolp = ecol + coloff; +} + +/* + * "screenpos({winid}, {lnum}, {col})" function + */ + void +f_screenpos(typval_T *argvars UNUSED, typval_T *rettv) +{ + dict_T *dict; + win_T *wp; + pos_T pos; + int row = 0; + int scol = 0, ccol = 0, ecol = 0; + + if (rettv_dict_alloc(rettv) != OK) + return; + dict = rettv->vval.v_dict; + + wp = find_win_by_nr_or_id(&argvars[0]); + if (wp == NULL) + return; + + pos.lnum = tv_get_number(&argvars[1]); + pos.col = tv_get_number(&argvars[2]) - 1; + pos.coladd = 0; + textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol); + + dict_add_number(dict, "row", row); + dict_add_number(dict, "col", scol); + dict_add_number(dict, "curscol", ccol); + dict_add_number(dict, "endcol", ecol); +} +#endif + /* * Scroll the current window down by "line_count" logical lines. "CTRL-Y" */ diff --git a/src/normal.c b/src/normal.c index 5c9f929d55..f626f45dc1 100644 --- a/src/normal.c +++ b/src/normal.c @@ -2328,6 +2328,9 @@ do_mouse( profile_setlimit(p_bdlay, &bevalexpr_due); bevalexpr_due_set = TRUE; } +#endif +#ifdef FEAT_TEXT_PROP + popup_handle_mouse_moved(); #endif return FALSE; } diff --git a/src/popupmnu.c b/src/popupmnu.c index 5fbb3bbd28..9569ffdfc4 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -992,8 +992,6 @@ pum_position_at_mouse(int min_width) # if defined(FEAT_BEVAL_TERM) || defined(PROTO) static pumitem_T *balloon_array = NULL; static int balloon_arraysize; -static int balloon_mouse_row = 0; -static int balloon_mouse_col = 0; #define BALLOON_MIN_WIDTH 50 #define BALLOON_MIN_HEIGHT 10 @@ -1209,8 +1207,9 @@ ui_post_balloon(char_u *mesg, list_T *list) void ui_may_remove_balloon(void) { - if (mouse_row != balloon_mouse_row || mouse_col != balloon_mouse_col) - ui_remove_balloon(); + // For now: remove the balloon whenever the mouse moves to another screen + // cell. + ui_remove_balloon(); } # endif diff --git a/src/popupwin.c b/src/popupwin.c index 02aa83edad..401f1fbea9 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -167,6 +167,35 @@ set_moved_columns(win_T *wp, int flags) } } +/* + * Used when popup options contain "mousemoved": set default moved values. + */ + static void +set_mousemoved_values(win_T *wp) +{ + wp->w_popup_mouse_row = mouse_row; + wp->w_popup_mouse_mincol = mouse_col; + wp->w_popup_mouse_maxcol = mouse_col; +} + +/* + * Used when popup options contain "moved" with "word" or "WORD". + */ + static void +set_mousemoved_columns(win_T *wp, int flags) +{ + char_u *text; + int col; + + if (find_word_under_cursor(mouse_row, mouse_col, TRUE, flags, + NULL, NULL, &text, &col) == OK) + { + wp->w_popup_mouse_mincol = col; + wp->w_popup_mouse_maxcol = col + STRLEN(text) - 1; + vim_free(text); + } +} + /* * Return TRUE if "row"/"col" is on the border of the popup. * The values are relative to the top-left corner. @@ -335,6 +364,53 @@ apply_move_options(win_T *wp, dict_T *d) get_pos_options(wp, d); } + static void +handle_moved_argument(win_T *wp, dictitem_T *di, int mousemoved) +{ + if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) + { + char_u *s = di->di_tv.vval.v_string; + int flags = 0; + + if (STRCMP(s, "word") == 0) + flags = FIND_IDENT | FIND_STRING; + else if (STRCMP(s, "WORD") == 0) + flags = FIND_STRING; + else if (STRCMP(s, "expr") == 0) + flags = FIND_IDENT | FIND_STRING | FIND_EVAL; + else if (STRCMP(s, "any") != 0) + semsg(_(e_invarg2), s); + if (flags != 0) + { + if (mousemoved) + set_mousemoved_columns(wp, flags); + else + set_moved_columns(wp, flags); + } + } + else if (di->di_tv.v_type == VAR_LIST + && di->di_tv.vval.v_list != NULL + && di->di_tv.vval.v_list->lv_len == 2) + { + list_T *l = di->di_tv.vval.v_list; + int mincol = tv_get_number(&l->lv_first->li_tv); + int maxcol = tv_get_number(&l->lv_first->li_next->li_tv); + + if (mousemoved) + { + wp->w_popup_mouse_mincol = mincol; + wp->w_popup_mouse_maxcol = maxcol; + } + else + { + wp->w_popup_mincol = mincol; + wp->w_popup_maxcol = maxcol; + } + } + else + semsg(_(e_invarg2), tv_get_string(&di->di_tv)); +} + static void check_highlight(dict_T *dict, char *name, char_u **pval) { @@ -541,31 +617,14 @@ apply_general_options(win_T *wp, dict_T *dict) if (di != NULL) { set_moved_values(wp); - if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) - { - char_u *s = di->di_tv.vval.v_string; - int flags = 0; + handle_moved_argument(wp, di, FALSE); + } - if (STRCMP(s, "word") == 0) - flags = FIND_IDENT | FIND_STRING; - else if (STRCMP(s, "WORD") == 0) - flags = FIND_STRING; - else if (STRCMP(s, "any") != 0) - semsg(_(e_invarg2), s); - if (flags != 0) - set_moved_columns(wp, flags); - } - else if (di->di_tv.v_type == VAR_LIST - && di->di_tv.vval.v_list != NULL - && di->di_tv.vval.v_list->lv_len == 2) - { - list_T *l = di->di_tv.vval.v_list; - - wp->w_popup_mincol = tv_get_number(&l->lv_first->li_tv); - wp->w_popup_maxcol = tv_get_number(&l->lv_first->li_next->li_tv); - } - else - semsg(_(e_invarg2), tv_get_string(&di->di_tv)); + di = dict_find(dict, (char_u *)"mousemoved", -1); + if (di != NULL) + { + set_mousemoved_values(wp); + handle_moved_argument(wp, di, TRUE); } di = dict_find(dict, (char_u *)"filter", -1); @@ -956,6 +1015,7 @@ typedef enum { TYPE_NORMAL, TYPE_ATCURSOR, + TYPE_BEVAL, TYPE_NOTIFICATION, TYPE_DIALOG, TYPE_MENU @@ -1137,17 +1197,33 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) { wp->w_popup_pos = POPPOS_BOTLEFT; setcursor_mayforce(TRUE); - wp->w_wantline = screen_screenrow(); + wp->w_wantline = curwin->w_winrow + curwin->w_wrow; if (wp->w_wantline == 0) // cursor in first line { wp->w_wantline = 2; wp->w_popup_pos = POPPOS_TOPLEFT; } - wp->w_wantcol = screen_screencol() + 1; + wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1; set_moved_values(wp); set_moved_columns(wp, FIND_STRING); } + if (type == TYPE_BEVAL) + { + wp->w_popup_pos = POPPOS_BOTLEFT; + + // by default use the mouse position + wp->w_wantline = mouse_row; + if (wp->w_wantline <= 0) // mouse on first line + { + wp->w_wantline = 2; + wp->w_popup_pos = POPPOS_TOPLEFT; + } + wp->w_wantcol = mouse_col + 1; + set_mousemoved_values(wp); + set_mousemoved_columns(wp, FIND_IDENT + FIND_STRING + FIND_EVAL); + } + // set default values wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX; wp->w_popup_close = POPCLOSE_NONE; @@ -1275,6 +1351,15 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv) popup_create(argvars, rettv, TYPE_ATCURSOR); } +/* + * popup_beval({text}, {options}) + */ + void +f_popup_beval(typval_T *argvars, typval_T *rettv) +{ + popup_create(argvars, rettv, TYPE_BEVAL); +} + /* * Invoke the close callback for window "wp" with value "result". * Careful: The callback may make "wp" invalid! @@ -1334,6 +1419,48 @@ popup_close_for_mouse_click(win_T *wp) popup_close_and_callback(wp, &res); } + static void +check_mouse_moved(win_T *wp, win_T *mouse_wp) +{ + // Close the popup when all if these are true: + // - the mouse is not on this popup + // - "mousemoved" was used + // - the mouse is no longer on the same screen row or the mouse column is + // outside of the relevant text + if (wp != mouse_wp + && wp->w_popup_mouse_row != 0 + && (wp->w_popup_mouse_row != mouse_row + || mouse_col < wp->w_popup_mouse_mincol + || mouse_col > wp->w_popup_mouse_maxcol)) + { + typval_T res; + + res.v_type = VAR_NUMBER; + res.vval.v_number = -2; + popup_close_and_callback(wp, &res); + } +} + +/* + * Called when the mouse moved: may close a popup with "mousemoved". + */ + void +popup_handle_mouse_moved(void) +{ + win_T *wp; + win_T *mouse_wp; + int row = mouse_row; + int col = mouse_col; + + // find the window where the mouse is in + mouse_wp = mouse_find_win(&row, &col, FIND_POPUP); + + for (wp = first_popupwin; wp != NULL; wp = wp->w_next) + check_mouse_moved(wp, mouse_wp); + for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next) + check_mouse_moved(wp, mouse_wp); +} + /* * In a filter: check if the typed key is a mouse event that is used for * dragging the popup. @@ -1821,7 +1948,7 @@ get_borderchars(dict_T *dict, win_T *wp) } /* - * For popup_getoptions(): add a "moved" entry to "dict". + * For popup_getoptions(): add a "moved" and "mousemoved" entry to "dict". */ static void get_moved_list(dict_T *dict, win_T *wp) @@ -1832,9 +1959,18 @@ get_moved_list(dict_T *dict, win_T *wp) if (list != NULL) { dict_add_list(dict, "moved", list); + list_append_number(list, wp->w_popup_lnum); list_append_number(list, wp->w_popup_mincol); list_append_number(list, wp->w_popup_maxcol); } + list = list_alloc(); + if (list != NULL) + { + dict_add_list(dict, "mousemoved", list); + list_append_number(list, wp->w_popup_mouse_row); + list_append_number(list, wp->w_popup_mouse_mincol); + list_append_number(list, wp->w_popup_mouse_maxcol); + } } /* diff --git a/src/proto/beval.pro b/src/proto/beval.pro index 2be64a0da1..0238907ea2 100644 --- a/src/proto/beval.pro +++ b/src/proto/beval.pro @@ -1,5 +1,6 @@ /* beval.c */ int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); +int find_word_under_cursor(int mouserow, int mousecol, int getword, int flags, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); void post_balloon(BalloonEval *beval, char_u *mesg, list_T *list); int can_use_beval(void); void general_beval_cb(BalloonEval *beval, int state); diff --git a/src/proto/move.pro b/src/proto/move.pro index ed45c4dc1e..c2ec8d5953 100644 --- a/src/proto/move.pro +++ b/src/proto/move.pro @@ -27,6 +27,7 @@ int curwin_col_off(void); int win_col_off2(win_T *wp); int curwin_col_off2(void); void curs_columns(int may_scroll); +void f_screenpos(typval_T *argvars, typval_T *rettv); void scrolldown(long line_count, int byfold); void scrollup(long line_count, int byfold); void check_topfill(win_T *wp, int down); diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index a251f9ad56..7733368578 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -11,7 +11,9 @@ 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_beval(typval_T *argvars, typval_T *rettv); void popup_close_for_mouse_click(win_T *wp); +void popup_handle_mouse_moved(void); 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); diff --git a/src/testdir/dumps/Test_popupwin_beval_1.dump b/src/testdir/dumps/Test_popupwin_beval_1.dump new file mode 100644 index 0000000000..410ac5c434 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_beval_1.dump @@ -0,0 +1,10 @@ +|1+0&#ffffff0| @73 +>2| @73 +|3| @73 +|4| @12|t+0#0000001#ffd7ff255|e|x|t| +0#0000000#ffffff0@56 +|h|e|r|e| |i|s| |s|o|m|e| |t|e|x|t| |t|o| |h|o|v|e|r| |o|v|e|r| @43 +|6| @73 +|7| @73 +|8| @73 +|9| @73 +|:|c|a|l@1| |H|o|v|e|r|(|)| @43|2|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_beval_2.dump b/src/testdir/dumps/Test_popupwin_beval_2.dump new file mode 100644 index 0000000000..34b222d181 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_beval_2.dump @@ -0,0 +1,10 @@ +|1+0&#ffffff0| @73 +>2| @73 +|3| @73 +|4| @12|t+0#0000001#ffd7ff255|e|x|t| +0#0000000#ffffff0@56 +|h|e|r|e| |i|s| |s|o|m|e| |t|e|x|t| |t|o| |h|o|v|e|r| |o|v|e|r| @43 +|6| @73 +|7| @73 +|8| @73 +|9| @73 +|:|c|a|l@1| |M|o|v|e|O|n|t|o|P|o|p|u|p|(|)| @35|2|,|1| @10|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_beval_3.dump b/src/testdir/dumps/Test_popupwin_beval_3.dump new file mode 100644 index 0000000000..2e8e419354 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_beval_3.dump @@ -0,0 +1,10 @@ +|1+0&#ffffff0| @73 +>2| @73 +|3| @73 +|4| @73 +|h|e|r|e| |i|s| |s|o|m|e| |t|e|x|t| |t|o| |h|o|v|e|r| |o|v|e|r| @43 +|6| @73 +|7| @73 +|8| @73 +|9| @73 +|:|c|a|l@1| |M|o|v|e|A|w|a|y|(|)| @40|2|,|1| @10|T|o|p| diff --git a/src/testdir/test_cursor_func.vim b/src/testdir/test_cursor_func.vim index 12319577c6..0f638b3575 100644 --- a/src/testdir/test_cursor_func.vim +++ b/src/testdir/test_cursor_func.vim @@ -72,3 +72,31 @@ func Test_curswant_with_cursorline() call assert_equal(6, winsaveview().curswant) quit! endfunc + +func Test_screenpos() + rightbelow new + rightbelow 20vsplit + call setline(1, ["\tsome text", "long wrapping line here", "next line"]) + redraw + let winid = win_getid() + let [winrow, wincol] = win_screenpos(winid) + call assert_equal({'row': winrow, + \ 'col': wincol + 0, + \ 'curscol': wincol + 7, + \ 'endcol': wincol + 7}, screenpos(winid, 1, 1)) + call assert_equal({'row': winrow, + \ 'col': wincol + 13, + \ 'curscol': wincol + 13, + \ 'endcol': wincol + 13}, screenpos(winid, 1, 7)) + call assert_equal({'row': winrow + 2, + \ 'col': wincol + 1, + \ 'curscol': wincol + 1, + \ 'endcol': wincol + 1}, screenpos(winid, 2, 22)) + setlocal number + call assert_equal({'row': winrow + 3, + \ 'col': wincol + 9, + \ 'curscol': wincol + 9, + \ 'endcol': wincol + 9}, screenpos(winid, 2, 22)) + close + bwipe! +endfunc diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 00cc2878e4..f952a42fe7 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1005,6 +1005,53 @@ func Test_popup_atcursor() bwipe! endfunc +func Test_popup_beval() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + let lines =<< trim END + call setline(1, range(1, 20)) + call setline(5, 'here is some text to hover over') + set balloonevalterm + set balloonexpr=BalloonExpr() + set balloondelay=100 + func BalloonExpr() + let s:winid = popup_beval([v:beval_text], {}) + return '' + endfunc + func Hover() + call test_setmouse(5, 15) + call feedkeys("\\", "xt") + sleep 100m + endfunc + func MoveOntoPopup() + call test_setmouse(4, 17) + call feedkeys("\\\", "xt") + endfunc + func MoveAway() + call test_setmouse(5, 13) + call feedkeys("\\\", "xt") + endfunc + END + call writefile(lines, 'XtestPopupBeval') + let buf = RunVimInTerminal('-S XtestPopupBeval', {'rows': 10}) + call term_wait(buf, 100) + call term_sendkeys(buf, 'j') + call term_sendkeys(buf, ":call Hover()\") + call VerifyScreenDump(buf, 'Test_popupwin_beval_1', {}) + + call term_sendkeys(buf, ":call MoveOntoPopup()\") + call VerifyScreenDump(buf, 'Test_popupwin_beval_2', {}) + + call term_sendkeys(buf, ":call MoveAway()\") + call VerifyScreenDump(buf, 'Test_popupwin_beval_3', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XtestPopupBeval') +endfunc + func Test_popup_filter() new call setline(1, 'some text') @@ -1413,7 +1460,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) + call assert_equal([1, 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)) @@ -1423,7 +1470,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 assert_equal([1, 4, 7], popup_getoptions(winid).moved) call feedkeys("hi\", 'xt') call assert_equal({}, popup_getpos(winid)) call popup_clear() @@ -1432,7 +1479,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 assert_equal([1, 4, 7], popup_getoptions(winid).moved) call feedkeys("li\", 'xt') call assert_equal(1, popup_getpos(winid).visible) call feedkeys("ei\", 'xt') @@ -1446,7 +1493,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 assert_equal([2, 2, 15], popup_getoptions(winid).moved) call feedkeys("eli\", 'xt') call assert_equal(1, popup_getpos(winid).visible) call feedkeys("wi\", 'xt') diff --git a/src/version.c b/src/version.c index 754155bfd2..61651330c0 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 */ +/**/ + 1645, /**/ 1644, /**/ From 56a63120992cc3e1f50d654a3f8aeace40bf12ef Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 18:38:34 +0200 Subject: [PATCH 06/21] patch 8.1.1646: build failure Problem: build failure Solution: Add changes to structure. --- src/structs.h | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/structs.h b/src/structs.h index 4c4ce7df0a..57a09fa985 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2941,6 +2941,9 @@ 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_mouse_row; // close popup if mouse moves away + int w_popup_mouse_mincol; // close popup if mouse moves away + int w_popup_mouse_maxcol; // close popup if mouse moves away int w_popup_drag; // allow moving the popup with the mouse popclose_T w_popup_close; // allow closing the popup with the mouse diff --git a/src/version.c b/src/version.c index 61651330c0..52bce3b683 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 */ +/**/ + 1646, /**/ 1645, /**/ From d84b2c3d88b08722dd4f686256a22c26788ea122 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 19:16:58 +0200 Subject: [PATCH 07/21] patch 8.1.1647: build error with GTK and hangulinput feature Problem: Build error with GTK and hangulinput feature, im_get_status() defined twice. (Dominique Pelle) Solution: Adjust im_get_status(). (closes #4628) --- src/hangulin.c | 2 ++ src/mbyte.c | 5 +++++ src/version.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/hangulin.c b/src/hangulin.c index e08fe6317a..337ea84f4c 100644 --- a/src/hangulin.c +++ b/src/hangulin.c @@ -404,11 +404,13 @@ hangul_input_state_set(int state) hangul_input_clear(); } +#if (!defined(FEAT_XIM) && !defined(FEAT_GUI_GTK)) || defined(PROTO) int im_get_status(void) { return hangul_input_state_get(); } +#endif void hangul_input_state_toggle(void) diff --git a/src/mbyte.c b/src/mbyte.c index 9c03f08d82..94adddf7ef 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -5848,6 +5848,11 @@ xim_queue_key_press_event(GdkEventKey *event, int down) int im_get_status(void) { +# ifdef FEAT_HANGULIN + if (hangul_input_state_get()) + return TRUE; +# endif + # ifdef FEAT_EVAL if (USE_IMSTATUSFUNC) return call_imstatusfunc(); diff --git a/src/version.c b/src/version.c index 52bce3b683..5cf7da3356 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 */ +/**/ + 1647, /**/ 1646, /**/ From 3f3e954d9676e374f222a18786c78e50af5041cb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 20:30:48 +0200 Subject: [PATCH 08/21] patch 8.1.1648: MS-Windows: build error with normal feaures Problem: MS-Windows: build error with normal feaures. Solution: Adjust #ifdef for find_word_under_cursor(). --- src/beval.c | 114 ++++++++++++++++++++++---------------------- src/proto/beval.pro | 2 +- src/version.c | 2 + 3 files changed, 61 insertions(+), 57 deletions(-) diff --git a/src/beval.c b/src/beval.c index 2cbe7ea1f0..010e201051 100644 --- a/src/beval.c +++ b/src/beval.c @@ -10,62 +10,7 @@ #include "vim.h" -#if defined(FEAT_BEVAL) || defined(PROTO) - -/* - * Get the text and position to be evaluated for "beval". - * If "getword" is TRUE the returned text is not the whole line but the - * relevant word in allocated memory. - * Returns OK or FAIL. - */ - int -get_beval_info( - BalloonEval *beval, - int getword, - win_T **winp, - linenr_T *lnump, - char_u **textp, - int *colp) -{ - int row, col; - -# ifdef FEAT_BEVAL_TERM -# ifdef FEAT_GUI - if (!gui.in_use) -# endif - { - row = mouse_row; - col = mouse_col; - } -# endif -# ifdef FEAT_GUI - if (gui.in_use) - { - row = Y_2_ROW(beval->y); - col = X_2_COL(beval->x); - } -#endif - if (find_word_under_cursor(row, col, getword, - FIND_IDENT + FIND_STRING + FIND_EVAL, - winp, lnump, textp, colp) == OK) - { -#ifdef FEAT_VARTABS - vim_free(beval->vts); - beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array); - if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL) - { - if (getword) - vim_free(*textp); - return FAIL; - } -#endif - beval->ts = (*winp)->w_buffer->b_p_ts; - return OK; - } - - return FAIL; -} - +#if defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) || defined(PROT) /* * Find text under the mouse position "row" / "col". * If "getword" is TRUE the returned text in "*textp" is not the whole line but @@ -174,6 +119,63 @@ find_word_under_cursor( } return FAIL; } +#endif + +#if defined(FEAT_BEVAL) || defined(PROTO) + +/* + * Get the text and position to be evaluated for "beval". + * If "getword" is TRUE the returned text is not the whole line but the + * relevant word in allocated memory. + * Returns OK or FAIL. + */ + int +get_beval_info( + BalloonEval *beval, + int getword, + win_T **winp, + linenr_T *lnump, + char_u **textp, + int *colp) +{ + int row, col; + +# ifdef FEAT_BEVAL_TERM +# ifdef FEAT_GUI + if (!gui.in_use) +# endif + { + row = mouse_row; + col = mouse_col; + } +# endif +# ifdef FEAT_GUI + if (gui.in_use) + { + row = Y_2_ROW(beval->y); + col = X_2_COL(beval->x); + } +#endif + if (find_word_under_cursor(row, col, getword, + FIND_IDENT + FIND_STRING + FIND_EVAL, + winp, lnump, textp, colp) == OK) + { +#ifdef FEAT_VARTABS + vim_free(beval->vts); + beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array); + if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL) + { + if (getword) + vim_free(*textp); + return FAIL; + } +#endif + beval->ts = (*winp)->w_buffer->b_p_ts; + return OK; + } + + return FAIL; +} /* * Show a balloon with "mesg" or "list". diff --git a/src/proto/beval.pro b/src/proto/beval.pro index 0238907ea2..62eba9ef0b 100644 --- a/src/proto/beval.pro +++ b/src/proto/beval.pro @@ -1,6 +1,6 @@ /* beval.c */ -int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); int find_word_under_cursor(int mouserow, int mousecol, int getword, int flags, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); +int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); void post_balloon(BalloonEval *beval, char_u *mesg, list_T *list); int can_use_beval(void); void general_beval_cb(BalloonEval *beval, int state); diff --git a/src/version.c b/src/version.c index 5cf7da3356..4952b7088f 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 */ +/**/ + 1648, /**/ 1647, /**/ From 3e35d05b1f99419be27ea5be70c7d0610202c163 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 7 Jul 2019 20:43:34 +0200 Subject: [PATCH 09/21] patch 8.1.1649: Illegal memory access when closing popup window Problem: Illegal memory access when closing popup window. Solution: Get w_next before closing the window. --- src/popupwin.c | 13 ++++++++++--- src/version.c | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 401f1fbea9..32f486181e 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1437,6 +1437,7 @@ check_mouse_moved(win_T *wp, win_T *mouse_wp) res.v_type = VAR_NUMBER; res.vval.v_number = -2; + // Careful: this makes "wp" invalid. popup_close_and_callback(wp, &res); } } @@ -1447,7 +1448,7 @@ check_mouse_moved(win_T *wp, win_T *mouse_wp) void popup_handle_mouse_moved(void) { - win_T *wp; + win_T *wp, *nextwp; win_T *mouse_wp; int row = mouse_row; int col = mouse_col; @@ -1455,10 +1456,16 @@ popup_handle_mouse_moved(void) // find the window where the mouse is in mouse_wp = mouse_find_win(&row, &col, FIND_POPUP); - for (wp = first_popupwin; wp != NULL; wp = wp->w_next) + for (wp = first_popupwin; wp != NULL; wp = nextwp) + { + nextwp = wp->w_next; check_mouse_moved(wp, mouse_wp); - for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next) + } + for (wp = curtab->tp_first_popupwin; wp != NULL; wp = nextwp) + { + nextwp = wp->w_next; check_mouse_moved(wp, mouse_wp); + } } /* diff --git a/src/version.c b/src/version.c index 4952b7088f..82f90932ca 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 */ +/**/ + 1649, /**/ 1648, /**/ From ee9e604124682b0cd89e4f987a2f6f3fe4160920 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 8 Jul 2019 20:08:44 +0200 Subject: [PATCH 10/21] patch 8.1.1650: warning for using uninitialized variable Problem: Warning for using uninitialized variable. (Tony Mechelynck) Solution: Simplify the code by always using the mouse coordinates. --- src/beval.c | 24 ++++++++---------------- src/version.c | 2 ++ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/beval.c b/src/beval.c index 010e201051..68df2be9ea 100644 --- a/src/beval.c +++ b/src/beval.c @@ -131,24 +131,16 @@ find_word_under_cursor( */ int get_beval_info( - BalloonEval *beval, - int getword, - win_T **winp, - linenr_T *lnump, - char_u **textp, - int *colp) + BalloonEval *beval, + int getword, + win_T **winp, + linenr_T *lnump, + char_u **textp, + int *colp) { - int row, col; + int row = mouse_row; + int col = mouse_col; -# ifdef FEAT_BEVAL_TERM -# ifdef FEAT_GUI - if (!gui.in_use) -# endif - { - row = mouse_row; - col = mouse_col; - } -# endif # ifdef FEAT_GUI if (gui.in_use) { diff --git a/src/version.c b/src/version.c index 82f90932ca..6ad48828b7 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 */ +/**/ + 1650, /**/ 1649, /**/ From 999224422633935eaa8b804ce3d1c2f9ca195d0a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 8 Jul 2019 20:58:25 +0200 Subject: [PATCH 11/21] patch 8.1.1651: suspend test is flaky on some systems Problem: Suspend test is flaky on some systems. Solution: Wait for the shell prompt to show. (Yee Cheng Chin, closes #4632) --- src/testdir/test_suspend.vim | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/testdir/test_suspend.vim b/src/testdir/test_suspend.vim index 8b326f51f6..4b3bd5eadf 100644 --- a/src/testdir/test_suspend.vim +++ b/src/testdir/test_suspend.vim @@ -54,6 +54,8 @@ func Test_suspend() " Quit gracefully to dump coverage information. call term_sendkeys(buf, ":qall!\") call term_wait(buf) + " Wait until Vim actually exited and shell shows a prompt + call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))}) call StopShellInTerminal(buf) exe buf . 'bwipe!' diff --git a/src/version.c b/src/version.c index 6ad48828b7..cbfee049c8 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 */ +/**/ + 1651, /**/ 1650, /**/ From 49fe95f22517b775506ef34681000d84bb417eb3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 8 Jul 2019 21:57:30 +0200 Subject: [PATCH 12/21] patch 8.1.1652: GUI: popup window doesn't close on mouse movement Problem: GUI: popup window doesn't close on mouse movement. (Paul Jolly) Solution: Generate mouse-move events when a popup window is visible. --- src/globals.h | 12 +++++------- src/gui.c | 32 +++++++++++++++++++++++++------- src/version.c | 2 ++ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/globals.h b/src/globals.h index ddafcc13df..3562b5ee6c 100644 --- a/src/globals.h +++ b/src/globals.h @@ -603,6 +603,11 @@ 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 *popup_dragwin INIT(= NULL); // popup window being dragged + +// Set to TRUE if there is any visible popup. +EXTERN int popup_visible INIT(= FALSE); + +EXTERN int text_prop_frozen INIT(= 0); #endif /* @@ -1680,10 +1685,3 @@ typedef int HINSTANCE; EXTERN int ctrl_break_was_pressed INIT(= FALSE); EXTERN HINSTANCE g_hinst INIT(= NULL); #endif - -#ifdef FEAT_TEXT_PROP -EXTERN int text_prop_frozen INIT(= 0); - -// Set to TRUE if there is any visible popup. -EXTERN int popup_visible INIT(= FALSE); -#endif diff --git a/src/gui.c b/src/gui.c index 7c378c6fe1..5dcab515ae 100644 --- a/src/gui.c +++ b/src/gui.c @@ -4823,18 +4823,15 @@ gui_focus_change(int in_focus) } /* - * Called when the mouse moved (but not when dragging). + * When mouse moved: apply 'mousefocus'. + * Also updates the mouse pointer shape. */ - void -gui_mouse_moved(int x, int y) + static void +gui_mouse_focus(int x, int y) { win_T *wp; char_u st[8]; - /* Ignore this while still starting up. */ - if (!gui.in_use || gui.starting) - return; - #ifdef FEAT_MOUSESHAPE /* Get window pointer, and update mouse shape as well. */ wp = xy2win(x, y); @@ -4893,6 +4890,27 @@ gui_mouse_moved(int x, int y) } } +/* + * Called when the mouse moved (but not when dragging). + */ + void +gui_mouse_moved(int x, int y) +{ + // Ignore this while still starting up. + if (!gui.in_use || gui.starting) + return; + + // apply 'mousefocus' and pointer shape + gui_mouse_focus(x, y); + +#ifdef FEAT_TEXT_PROP + if (popup_visible) + // Generate a mouse-moved event, so that the popup can perhaps be + // closed, just like in the terminal. + gui_send_mouse_event(MOUSE_DRAG, x, y, FALSE, 0); +#endif +} + /* * Called when mouse should be moved to window with focus. */ diff --git a/src/version.c b/src/version.c index cbfee049c8..50615798e2 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 */ +/**/ + 1652, /**/ 1651, /**/ From 0d07155c8bbaca1a527b79da358438253a60839f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 8 Jul 2019 22:04:03 +0200 Subject: [PATCH 13/21] patch 8.1.1653: ubsan warns for possibly passing NULL pointer Problem: Ubsan warns for possibly passing NULL pointer. Solution: Skip code when length is zero. (Dominique Pelle, closes #4631) --- src/channel.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/channel.c b/src/channel.c index eb5af0aa46..5d1b83aafa 100644 --- a/src/channel.c +++ b/src/channel.c @@ -3990,7 +3990,7 @@ channel_send( writeq_T *last = wq->wq_prev; /* append to the last entry */ - if (ga_grow(&last->wq_ga, len) == OK) + if (len > 0 && ga_grow(&last->wq_ga, len) == OK) { mch_memmove((char *)last->wq_ga.ga_data + last->wq_ga.ga_len, @@ -4012,7 +4012,7 @@ channel_send( wq->wq_prev->wq_next = last; wq->wq_prev = last; ga_init2(&last->wq_ga, 1, 1000); - if (ga_grow(&last->wq_ga, len) == OK) + if (len > 0 && ga_grow(&last->wq_ga, len) == OK) { mch_memmove(last->wq_ga.ga_data, buf, len); last->wq_ga.ga_len = len; diff --git a/src/version.c b/src/version.c index 50615798e2..03361ca2fa 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 */ +/**/ + 1653, /**/ 1652, /**/ From 8a7383b6d28be02413cf115d4b8ed1b44d60dd9f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 8 Jul 2019 22:23:33 +0200 Subject: [PATCH 14/21] patch 8.1.1654: GUI: screen updates from 'balloonexpr' are not displayed Problem: GUI: screen updates from 'balloonexpr' are not displayed. Solution: Update the screen if needed. Also avoid the cursor being displayed in the wrong position. --- src/beval.c | 14 ++++++++++---- src/version.c | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/beval.c b/src/beval.c index 68df2be9ea..ef307c5246 100644 --- a/src/beval.c +++ b/src/beval.c @@ -294,11 +294,17 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); if (result != NULL && result[0] != NUL) - { post_balloon(beval, result, NULL); - recursive = FALSE; - return; - } + +# ifdef FEAT_GUI + // The 'balloonexpr' evaluation may show something on the screen + // that requires a screen update. + if (gui.in_use && must_redraw) + redraw_after_callback(FALSE); +# endif + + recursive = FALSE; + return; } } #endif diff --git a/src/version.c b/src/version.c index 03361ca2fa..d35560adc5 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 */ +/**/ + 1654, /**/ 1653, /**/ From 3dabd718f4b2d8e09de9e2ec73832620b91c2f79 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 8 Jul 2019 23:30:22 +0200 Subject: [PATCH 15/21] patch 8.1.1655: popup window border drawn wrong with multi-byte char Problem: Popup window border drawn wrong with multi-byte char. (Marcin Szamotulski) Solution: Correct check in mb_fix_col(). (closes #4635) --- src/mbyte.c | 10 +++++++--- src/testdir/dumps/Test_popupwin_24.dump | 12 ++++++++++++ src/testdir/test_popupwin.vim | 9 +++++++++ src/version.c | 2 ++ 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 src/testdir/dumps/Test_popupwin_24.dump diff --git a/src/mbyte.c b/src/mbyte.c index 94adddf7ef..2b76400662 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4266,14 +4266,18 @@ mb_lefthalve(int row, int col) int mb_fix_col(int col, int row) { + int off; + col = check_col(col); row = check_row(row); + off = LineOffset[row] + col; if (has_mbyte && ScreenLines != NULL && col > 0 && ((enc_dbcs - && ScreenLines[LineOffset[row] + col] != NUL + && ScreenLines[off] != NUL && dbcs_screen_head_off(ScreenLines + LineOffset[row], - ScreenLines + LineOffset[row] + col)) - || (enc_utf8 && ScreenLines[LineOffset[row] + col] == 0))) + ScreenLines + off)) + || (enc_utf8 && ScreenLines[off] == 0 + && ScreenLinesUC[off] == 0))) return col - 1; return col; } diff --git a/src/testdir/dumps/Test_popupwin_24.dump b/src/testdir/dumps/Test_popupwin_24.dump new file mode 100644 index 0000000000..f5386c9542 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_24.dump @@ -0,0 +1,12 @@ +>1+0&#ffffff0| @73 +|2| |╔+0fd7ff255|═@11|╗| +0&#ffffff0@5|╔+0&#dadada255|═@11|╗+0a8a8a255| +0&#ffffff0@5|x+0fd7ff255@13| +0&#ffffff0@2|#+0fd7ff255|x@11|#| +0&#ffffff0@1 +|3| |║+0fd7ff255|h+0#0000001#ffd7ff255|e|l@1|o| |b|o|r|d|e|r|║+0#0000000#5fd7ff255| +0&#ffffff0@5|║+0&#a8a8a8255|h+0#0000001#ffd7ff255|e|l@1|o| |b|o|r|d|e|r|║+0#0000000#8a8a8a255| +0&#ffffff0@5|x+0fd7ff255|h+0#0000001#ffd7ff255|e|l@1|o| |b|o|r|d|e|r|x+0#0000000#5fd7ff255| +0&#ffffff0@2|x+0fd7ff255|h+0#0000001#ffd7ff255|e|l@1|o| |b|o|r|d|e|r|x+0#0000000#5fd7ff255| +0&#ffffff0@1 +|4| |╚+0fd7ff255|═@11|╝| +0&#ffffff0@5|║+0&#a8a8a8255|a+0#0000001#ffd7ff255|n|d| |m|o|r|e| @3|║+0#0000000#8a8a8a255| +0&#ffffff0@5|x+0fd7ff255|l+0#0000001#ffd7ff255|i|n|e|s| |o|n|l|y| @1|x+0#0000000#5fd7ff255| +0&#ffffff0@2|x+0fd7ff255|w+0#0000001#ffd7ff255|i|t|h| |c|o|r|n|e|r|s|x+0#0000000#5fd7ff255| +0&#ffffff0@1 +|5| @20|╚+0�|═@11|╝| +0&#ffffff0@5|x+0fd7ff255@13| +0&#ffffff0@2|#+0fd7ff255|x@11|#| +0&#ffffff0@1 +|6| |e+0fd7ff255|a@11|f| +0&#ffffff0@58 +|7| |d+0fd7ff255|h+0#0000001#ffd7ff255|e|l@1|o| |b|o|r|d|e|r|b+0#0000000#5fd7ff255| +0&#ffffff0@5| +0fd7ff255@13| +0&#ffffff0@38 +|8| |d+0fd7ff255|w+0#0000001#ffd7ff255|i|t|h| |n|u|m|b|e|r|s|b+0#0000000#5fd7ff255| +0&#ffffff0@5| +0fd7ff255|h+0#0000001#ffd7ff255|e|l@1|o| |b|o|r|d|e|r| +0#0000000#5fd7ff255| +0&#ffffff0@5|┌+0#0000001#ffd7ff255|─@4|┐| +0#0000000#ffffff0@25 +|9| |h+0fd7ff255|c@11|g| +0&#ffffff0@5| +0fd7ff255|j+0#0000001#ffd7ff255|u|s|t| |b|l|a|n|k|s| | +0#0000000#5fd7ff255| +0&#ffffff0@5|│+0#0000001#ffd7ff255|h|e|l@1|o|│| +0#0000000#ffffff0@25 +|1|0| @19| +0fd7ff255@13| +0&#ffffff0@5|└+0#0000001#ffd7ff255|─@4|┘| +0#0000000#ffffff0@25 +|1@1| @72 +|:|c|a|l@1| |M|u|l|t|i|B|y|t|e|(|)| @39|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index f952a42fe7..0ec4f76004 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -113,6 +113,9 @@ func Test_popup_with_border_and_padding() call popup_create(['hello border', 'with corners'], {'line': 2, 'col': 60, 'border': [], 'borderhighlight': ['BlueColor'], 'borderchars': ['x', '#']}) let winid = popup_create(['hello border', 'with numbers'], {'line': 6, 'col': 3, 'border': [], 'borderhighlight': ['BlueColor'], 'borderchars': ['0', '1', '2', '3', '4', '5', '6', '7']}) call popup_create(['hello border', 'just blanks'], {'line': 7, 'col': 23, 'border': [], 'borderhighlight': ['BlueColor'], 'borderchars': [' ']}) + func MultiByte() + call popup_create(['hello'], {'line': 8, 'col': 43, 'border': [], 'borderchars': ['─', '│', '─', '│', '┌', '┐', '┘', '└']}) + endfunc END call writefile(lines, 'XtestPopupBorder') let buf = RunVimInTerminal('-S XtestPopupBorder', {'rows': 12}) @@ -122,6 +125,12 @@ func Test_popup_with_border_and_padding() call term_sendkeys(buf, ":call popup_setoptions(winid, {'borderchars': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']})\") call VerifyScreenDump(buf, 'Test_popupwin_23', {}) + " check multi-byte border only with 'ambiwidth' single + if &ambiwidth == 'single' + call term_sendkeys(buf, ":call MultiByte()\") + call VerifyScreenDump(buf, 'Test_popupwin_24', {}) + endif + call StopVimInTerminal(buf) call delete('XtestPopupBorder') diff --git a/src/version.c b/src/version.c index d35560adc5..62b95579dc 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 */ +/**/ + 1655, /**/ 1654, /**/ From e089c3fd6937524a14d22baa7562b0820f1343ac Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 9 Jul 2019 20:25:25 +0200 Subject: [PATCH 16/21] patch 8.1.1656: popup window width is wrong when using Tabs Problem: Popup window width is wrong when using Tabs. (Paul Jolly) Solution: Count tabs correctly. (closes #4637) --- src/popupwin.c | 4 +++- src/testdir/dumps/Test_popupwin_11.dump | 10 +++++----- src/testdir/test_popupwin.vim | 2 +- src/version.c | 2 ++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 32f486181e..a997cde87d 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -880,7 +880,9 @@ popup_adjust_position(win_T *wp) 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)); + // count Tabs for what they are worth + int len = win_linetabsize(wp, ml_get_buf(wp->w_buffer, lnum, FALSE), + (colnr_T)MAXCOL); if (wp->w_p_wrap) { diff --git a/src/testdir/dumps/Test_popupwin_11.dump b/src/testdir/dumps/Test_popupwin_11.dump index 21460ddb84..f67a314645 100644 --- a/src/testdir/dumps/Test_popupwin_11.dump +++ b/src/testdir/dumps/Test_popupwin_11.dump @@ -1,10 +1,10 @@ >1+0&#ffffff0| @73 |2| @73 -|3| @18|#+0#e000e06#e0e0e08|i|n|c|l|u|d|e| |<+0#e000002&|s|t|d|i|o|.|h|>| +0#0000000#ffffff0@36 -|4| @18|i+0#00e0003#e0e0e08|n|t| +0#0000000&|m|a|i|n|(|v+0#00e0003&|o|i|d|)+0#0000000&| @3| +0&#ffffff0@36 -|5| @18|{+0&#e0e0e08| @16| +0&#ffffff0@36 -|6| @18| +0&#e0e0e08@3|p|r|i|n|t|f|(|5+0#e000002&|6|7|)+0#0000000&|;| @1| +0&#ffffff0@36 -|7| @18|}+0&#e0e0e08| @16| +0&#ffffff0@36 +|3| @18|#+0#e000e06#e0e0e08|i|n|c|l|u|d|e| |<+0#e000002&|s|t|d|i|o|.|h|>| +0#0000000&@1| +0&#ffffff0@34 +|4| @18|i+0#00e0003#e0e0e08|n|t| +0#0000000&|m|a|i|n|(|v+0#00e0003&|o|i|d|)+0#0000000&| @5| +0&#ffffff0@34 +|5| @18|{+0&#e0e0e08| @18| +0&#ffffff0@34 +|6| @18| +0&#e0e0e08@7|p|r|i|n|t|f|(|5+0#e000002&|6|7|)+0#0000000&|;| +0&#ffffff0@34 +|7| @18|}+0&#e0e0e08| @18| +0&#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 0ec4f76004..4e3170ce3a 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -225,7 +225,7 @@ func Test_popup_with_syntax_setbufvar() \ '#include ', \ 'int main(void)', \ '{', - \ ' printf(567);', + \ "\tprintf(567);", \ '}', \], {'line': 3, 'col': 21, 'highlight': 'PopupColor'}) call setbufvar(winbufnr(winid), '&syntax', 'cpp') diff --git a/src/version.c b/src/version.c index 62b95579dc..c58cbc588f 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 */ +/**/ + 1656, /**/ 1655, /**/ From 7ba343e63483b09584d4bf5a997fc1d1c09f19f7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 9 Jul 2019 23:22:15 +0200 Subject: [PATCH 17/21] patch 8.1.1657: Terminal: screen updates from 'balloonexpr' are not displayed Problem: Terminal: screen updates from 'balloonexpr' are not displayed. Solution: Update the screen if needed. Fix the word position for "mousemoved". --- src/beval.c | 19 ++++++++------- src/normal.c | 56 ++++++++++++++++++++++++-------------------- src/popupwin.c | 3 ++- src/proto/beval.pro | 2 +- src/proto/normal.pro | 4 ++-- src/version.c | 2 ++ 6 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/beval.c b/src/beval.c index ef307c5246..dc8966fe2f 100644 --- a/src/beval.c +++ b/src/beval.c @@ -27,10 +27,12 @@ find_word_under_cursor( win_T **winp, // can be NULL linenr_T *lnump, // can be NULL char_u **textp, - int *colp) + int *colp, // column where mouse hovers, can be NULL + int *startcolp) // column where text starts, can be NULL { int row = mouserow; int col = mousecol; + int scol; win_T *wp; char_u *lbuf; linenr_T lnum; @@ -98,8 +100,8 @@ find_word_under_cursor( { // Find the word under the cursor. ++emsg_off; - len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf, - flags); + len = find_ident_at_pos(wp, lnum, (colnr_T)col, + &lbuf, &scol, flags); --emsg_off; if (len == 0) return FAIL; @@ -112,7 +114,10 @@ find_word_under_cursor( if (lnump != NULL) *lnump = lnum; *textp = lbuf; - *colp = col; + if (colp != NULL) + *colp = col; + if (startcolp != NULL) + *startcolp = scol; return OK; } } @@ -150,7 +155,7 @@ get_beval_info( #endif if (find_word_under_cursor(row, col, getword, FIND_IDENT + FIND_STRING + FIND_EVAL, - winp, lnump, textp, colp) == OK) + winp, lnump, textp, colp, NULL) == OK) { #ifdef FEAT_VARTABS vim_free(beval->vts); @@ -296,12 +301,10 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) if (result != NULL && result[0] != NUL) post_balloon(beval, result, NULL); -# ifdef FEAT_GUI // The 'balloonexpr' evaluation may show something on the screen // that requires a screen update. - if (gui.in_use && must_redraw) + if (must_redraw) redraw_after_callback(FALSE); -# endif recursive = FALSE; return; diff --git a/src/normal.c b/src/normal.c index f626f45dc1..6cac553155 100644 --- a/src/normal.c +++ b/src/normal.c @@ -2325,6 +2325,7 @@ do_mouse( ui_may_remove_balloon(); if (p_bevalterm) { +ch_log(NULL, "setting balloon timer"); profile_setlimit(p_bdlay, &bevalexpr_due); bevalexpr_due_set = TRUE; } @@ -3327,28 +3328,28 @@ find_is_eval_item( * Find the identifier under or to the right of the cursor. * "find_type" can have one of three values: * FIND_IDENT: find an identifier (keyword) - * FIND_STRING: find any non-white string - * FIND_IDENT + FIND_STRING: find any non-white string, identifier preferred. + * FIND_STRING: find any non-white text + * FIND_IDENT + FIND_STRING: find any non-white text, identifier preferred. * FIND_EVAL: find text useful for C program debugging * * There are three steps: - * 1. Search forward for the start of an identifier/string. Doesn't move if + * 1. Search forward for the start of an identifier/text. Doesn't move if * already on one. - * 2. Search backward for the start of this identifier/string. + * 2. Search backward for the start of this identifier/text. * This doesn't match the real Vi but I like it a little better and it * shouldn't bother anyone. - * 3. Search forward to the end of this identifier/string. + * 3. Search forward to the end of this identifier/text. * When FIND_IDENT isn't defined, we backup until a blank. * - * Returns the length of the string, or zero if no string is found. - * If a string is found, a pointer to the string is put in "*string". This - * string is not always NUL terminated. + * Returns the length of the text, or zero if no text is found. + * If text is found, a pointer to the text is put in "*text". This + * points into the current buffer line and is not always NUL terminated. */ int -find_ident_under_cursor(char_u **string, int find_type) +find_ident_under_cursor(char_u **text, int find_type) { return find_ident_at_pos(curwin, curwin->w_cursor.lnum, - curwin->w_cursor.col, string, find_type); + curwin->w_cursor.col, text, NULL, find_type); } /* @@ -3360,33 +3361,34 @@ find_ident_at_pos( win_T *wp, linenr_T lnum, colnr_T startcol, - char_u **string, + char_u **text, + int *textcol, // column where "text" starts, can be NULL int find_type) { char_u *ptr; - int col = 0; /* init to shut up GCC */ + int col = 0; // init to shut up GCC int i; int this_class = 0; int prev_class; int prevcol; - int bn = 0; /* bracket nesting */ + int bn = 0; // bracket nesting /* * if i == 0: try to find an identifier - * if i == 1: try to find any non-white string + * if i == 1: try to find any non-white text */ ptr = ml_get_buf(wp->w_buffer, lnum, FALSE); for (i = (find_type & FIND_IDENT) ? 0 : 1; i < 2; ++i) { /* - * 1. skip to start of identifier/string + * 1. skip to start of identifier/text */ col = startcol; if (has_mbyte) { while (ptr[col] != NUL) { - /* Stop at a ']' to evaluate "a[x]". */ + // Stop at a ']' to evaluate "a[x]". if ((find_type & FIND_EVAL) && ptr[col] == ']') break; this_class = mb_get_class(ptr + col); @@ -3402,11 +3404,11 @@ find_ident_at_pos( ) ++col; - /* When starting on a ']' count it, so that we include the '['. */ + // When starting on a ']' count it, so that we include the '['. bn = ptr[col] == ']'; /* - * 2. Back up to start of identifier/string. + * 2. Back up to start of identifier/text. */ if (has_mbyte) { @@ -3432,8 +3434,8 @@ find_ident_at_pos( col = prevcol; } - /* If we don't want just any old string, or we've found an - * identifier, stop searching. */ + // If we don't want just any old text, or we've found an + // identifier, stop searching. if (this_class > 2) this_class = 2; if (!(find_type & FIND_STRING) || this_class == 2) @@ -3454,8 +3456,8 @@ find_ident_at_pos( )) --col; - /* If we don't want just any old string, or we've found an - * identifier, stop searching. */ + // If we don't want just any old text, or we've found an + // identifier, stop searching. if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col])) break; } @@ -3464,7 +3466,7 @@ find_ident_at_pos( if (ptr[col] == NUL || (i == 0 && (has_mbyte ? this_class != 2 : !vim_iswordc(ptr[col])))) { - // didn't find an identifier or string + // didn't find an identifier or text if ((find_type & FIND_NOERROR) == 0) { if (find_type & FIND_STRING) @@ -3475,17 +3477,19 @@ find_ident_at_pos( return 0; } ptr += col; - *string = ptr; + *text = ptr; + if (textcol != NULL) + *textcol = col; /* - * 3. Find the end if the identifier/string. + * 3. Find the end if the identifier/text. */ bn = 0; startcol -= col; col = 0; if (has_mbyte) { - /* Search for point of changing multibyte character class. */ + // Search for point of changing multibyte character class. this_class = mb_get_class(ptr); while (ptr[col] != NUL && ((i == 0 ? mb_get_class(ptr + col) == this_class diff --git a/src/popupwin.c b/src/popupwin.c index a997cde87d..59aaa6617b 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -188,7 +188,7 @@ set_mousemoved_columns(win_T *wp, int flags) int col; if (find_word_under_cursor(mouse_row, mouse_col, TRUE, flags, - NULL, NULL, &text, &col) == OK) + NULL, NULL, &text, NULL, &col) == OK) { wp->w_popup_mouse_mincol = col; wp->w_popup_mouse_maxcol = col + STRLEN(text) - 1; @@ -1437,6 +1437,7 @@ check_mouse_moved(win_T *wp, win_T *mouse_wp) { typval_T res; +ch_log(NULL, "closing popup %d", wp->w_id); res.v_type = VAR_NUMBER; res.vval.v_number = -2; // Careful: this makes "wp" invalid. diff --git a/src/proto/beval.pro b/src/proto/beval.pro index 62eba9ef0b..8b67e383db 100644 --- a/src/proto/beval.pro +++ b/src/proto/beval.pro @@ -1,5 +1,5 @@ /* beval.c */ -int find_word_under_cursor(int mouserow, int mousecol, int getword, int flags, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); +int find_word_under_cursor(int mouserow, int mousecol, int getword, int flags, win_T **winp, linenr_T *lnump, char_u **textp, int *colp, int *startcolp); int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); void post_balloon(BalloonEval *beval, char_u *mesg, list_T *list); int can_use_beval(void); diff --git a/src/proto/normal.pro b/src/proto/normal.pro index 55d12bb292..cc4bf7dfc9 100644 --- a/src/proto/normal.pro +++ b/src/proto/normal.pro @@ -7,8 +7,8 @@ void check_visual_highlight(void); void end_visual_mode(void); void reset_VIsual_and_resel(void); void reset_VIsual(void); -int find_ident_under_cursor(char_u **string, int find_type); -int find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **string, int find_type); +int find_ident_under_cursor(char_u **text, int find_type); +int find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **text, int *textcol, int find_type); void clear_showcmd(void); int add_to_showcmd(int c); void add_to_showcmd_c(int c); diff --git a/src/version.c b/src/version.c index c58cbc588f..fb21f07712 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 */ +/**/ + 1657, /**/ 1656, /**/ From 3b849af90a691f2a9999222b0e69bd161bebc5e2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 10 Jul 2019 16:15:04 +0200 Subject: [PATCH 18/21] patch 8.1.1658: debug statements included in patch Problem: Debug statements included in patch. Solution: Remove the debug statements. --- src/normal.c | 1 - src/popupwin.c | 1 - src/version.c | 2 ++ 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/normal.c b/src/normal.c index 6cac553155..ce1acb555e 100644 --- a/src/normal.c +++ b/src/normal.c @@ -2325,7 +2325,6 @@ do_mouse( ui_may_remove_balloon(); if (p_bevalterm) { -ch_log(NULL, "setting balloon timer"); profile_setlimit(p_bdlay, &bevalexpr_due); bevalexpr_due_set = TRUE; } diff --git a/src/popupwin.c b/src/popupwin.c index 59aaa6617b..c6355e122a 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1437,7 +1437,6 @@ check_mouse_moved(win_T *wp, win_T *mouse_wp) { typval_T res; -ch_log(NULL, "closing popup %d", wp->w_id); res.v_type = VAR_NUMBER; res.vval.v_number = -2; // Careful: this makes "wp" invalid. diff --git a/src/version.c b/src/version.c index fb21f07712..5cede94f95 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 */ +/**/ + 1658, /**/ 1657, /**/ From b05caa782dbab51db8de60940eff7992f8cfd882 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 10 Jul 2019 21:55:54 +0200 Subject: [PATCH 19/21] patch 8.1.1659: popup window "mousemoved" values not correct Problem: Popup window "mousemoved" values not correct. Solution: Convert text column to mouse column. --- runtime/doc/popup.txt | 29 ++++++++++++++++++++--------- src/popupwin.c | 16 +++++++++++++--- src/version.c | 2 ++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 13674109ee..ba4dc3fc15 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -192,7 +192,7 @@ popup_beval({what}, {options}) *popup_beval()* let pos = screenpos(v:beval_winnr, v:beval_lnum, v:beval_col) call popup_create({what}, { \ 'pos': 'botleft', - \ 'line': pos.lnum - 1, + \ 'line': pos.row - 1, \ 'col': pos.col, \ 'mousemoved': 'WORD', \ }) @@ -762,38 +762,49 @@ Example for using a popup window for 'ballooneval': > set ballooneval balloonevalterm set balloonexpr=BalloonExpr() let s:winid = 0 + let s:last_text = '' func BalloonExpr() - if s:winid + if s:winid && popup_getpos(s:winid) != {} + " previous popup window still shows + if v:beval_text == s:last_text + " Still the same text, keep the existing popup + return '' + endif call popup_close(s:winid) - let s:winid = 0 endif - let s:winid = popup_beval([bufname(v:beval_bufnr), v:beval_text], {}) + let s:winid = popup_beval(v:beval_text, {'mousemoved': 'word'}) + let s:last_text = v:beval_text return '' endfunc < If the text has to be obtained asynchronously return an empty string from the expression function and call popup_beval() once the text is available. In -this example similated with a timer callback: > +this example simulated with a timer callback: > set ballooneval balloonevalterm set balloonexpr=BalloonExpr() let s:winid = 0 + let s:balloonText = '' func BalloonExpr() - if s:winid + if s:winid && popup_getpos(s:winid) != {} + " previous popup window still shows + if v:beval_text == s:balloonText + " Still the same text, keep the existing popup + return '' + endif call popup_close(s:winid) let s:winid = 0 endif " simulate an asynchronous loopup for the text to display - let s:balloonFile = bufname(v:beval_bufnr) - let s:balloonWord = v:beval_text + let s:balloonText = v:beval_text call timer_start(100, 'ShowPopup') return '' endfunc func ShowPopup(id) - let s:winid = popup_beval([s:balloonFile, s:balloonWord], {}) + let s:winid = popup_beval(s:balloonText, {'mousemoved': 'word'}) endfunc < diff --git a/src/popupwin.c b/src/popupwin.c index c6355e122a..f2b31300f0 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -184,14 +184,24 @@ set_mousemoved_values(win_T *wp) static void set_mousemoved_columns(win_T *wp, int flags) { + win_T *textwp; char_u *text; int col; + pos_T pos; + colnr_T mcol; if (find_word_under_cursor(mouse_row, mouse_col, TRUE, flags, - NULL, NULL, &text, NULL, &col) == OK) + &textwp, &pos.lnum, &text, NULL, &col) == OK) { - wp->w_popup_mouse_mincol = col; - wp->w_popup_mouse_maxcol = col + STRLEN(text) - 1; + // convert text column to mouse column + pos.col = col; + pos.coladd = 0; + getvcol(textwp, &pos, &mcol, NULL, NULL); + wp->w_popup_mouse_mincol = mcol; + + pos.col = col + STRLEN(text) - 1; + getvcol(textwp, &pos, NULL, NULL, &mcol); + wp->w_popup_mouse_maxcol = mcol; vim_free(text); } } diff --git a/src/version.c b/src/version.c index 5cede94f95..5e83159edf 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 */ +/**/ + 1659, /**/ 1658, /**/ From 7780e5c1c5485a979ab6e3914a43e17912e213a8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 10 Jul 2019 22:04:48 +0200 Subject: [PATCH 20/21] patch 8.1.1660: assert_fails() does not fail inside try/catch Problem: Assert_fails() does not fail inside try/catch. Solution: Set trylevel to zero. (Ozaki Kiichi, closes #4639) --- src/eval.c | 7 ++++++- src/testdir/test_assert.vim | 6 ++++++ src/version.c | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/eval.c b/src/eval.c index 26fad0c5fa..d89093cb33 100644 --- a/src/eval.c +++ b/src/eval.c @@ -9910,10 +9910,14 @@ assert_fails(typval_T *argvars) char_u *cmd = tv_get_string_chk(&argvars[0]); garray_T ga; int ret = 0; + int save_trylevel = trylevel; + // trylevel must be zero for a ":throw" command to be considered failed + trylevel = 0; called_emsg = FALSE; suppress_errthrow = TRUE; emsg_silent = TRUE; + do_cmdline_cmd(cmd); if (!called_emsg) { @@ -9939,10 +9943,11 @@ assert_fails(typval_T *argvars) assert_append_cmd_or_arg(&ga, argvars, cmd); assert_error(&ga); ga_clear(&ga); - ret = 1; + ret = 1; } } + trylevel = save_trylevel; called_emsg = FALSE; suppress_errthrow = FALSE; emsg_silent = FALSE; diff --git a/src/testdir/test_assert.vim b/src/testdir/test_assert.vim index 0d59a43a2d..900710b893 100644 --- a/src/testdir/test_assert.vim +++ b/src/testdir/test_assert.vim @@ -166,6 +166,12 @@ func Test_assert_fail_fails() call remove(v:errors, 0) endfunc +func Test_assert_fails_in_try_block() + try + call assert_equal(0, assert_fails('throw "error"')) + endtry +endfunc + func Test_assert_beeps() new call assert_equal(0, assert_beeps('normal h')) diff --git a/src/version.c b/src/version.c index 5e83159edf..6af9abaaab 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 */ +/**/ + 1660, /**/ 1659, /**/ From 247bf0de465411e4ebb1c0fe1a9e07f4a7f77e91 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 10 Jul 2019 22:21:48 +0200 Subject: [PATCH 21/21] patch 8.1.1661: cannot build with +textprop but without +balloon_eval Problem: Cannot build with +textprop but without +balloon_eval. Solution: Adjust #ifdefs. (closes #4645) --- src/proto.h | 11 ++++++----- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/proto.h b/src/proto.h index 81023e2748..1c37bfa183 100644 --- a/src/proto.h +++ b/src/proto.h @@ -230,13 +230,14 @@ void qsort(void *base, size_t elm_count, size_t elm_size, int (*cmp)(const void # include "if_ruby.pro" # endif -/* Ugly solution for "BalloonEval" not being defined while it's used in some - * .pro files. */ -# ifdef FEAT_BEVAL -# include "beval.pro" -# else +// Ugly solution for "BalloonEval" not being defined while it's used in some +// .pro files. +# ifndef FEAT_BEVAL # define BalloonEval int # endif +# if defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) +# include "beval.pro" +# endif # ifdef FEAT_NETBEANS_INTG # include "netbeans.pro" diff --git a/src/version.c b/src/version.c index 6af9abaaab..9e8fcbad01 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 */ +/**/ + 1661, /**/ 1660, /**/