To: vim_dev@googlegroups.com Subject: Patch 8.1.1453 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.1453 Problem: Popup window "moved" property not implemented yet. Solution: Implement it. Files: src/main.c, src/edit.c, src/gui.c, src/globals.h, src/structs.h, src/screen.c, src/popupwin.c, src/proto/popupwin.pro, src/testdir/test_popupwin.vim, runtime/doc/popup.txt *** ../vim-8.1.1452/src/main.c 2019-05-24 18:48:36.762128482 +0200 --- src/main.c 2019-06-02 17:03:56.230707184 +0200 *************** *** 1159,1164 **** --- 1159,1167 ---- /* Trigger CursorMoved if the cursor moved. */ if (!finish_op && ( has_cursormoved() + #ifdef FEAT_TEXT_PROP + || popup_visible + #endif #ifdef FEAT_CONCEAL || curwin->w_p_cole > 0 #endif *************** *** 1168,1181 **** if (has_cursormoved()) apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf); ! # ifdef FEAT_CONCEAL if (curwin->w_p_cole > 0) { conceal_old_cursor_line = last_cursormoved.lnum; conceal_new_cursor_line = curwin->w_cursor.lnum; conceal_update_lines = TRUE; } ! # endif last_cursormoved = curwin->w_cursor; } --- 1171,1188 ---- if (has_cursormoved()) apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf); ! #ifdef FEAT_TEXT_PROP ! if (popup_visible) ! popup_check_cursor_pos(); ! #endif ! #ifdef FEAT_CONCEAL if (curwin->w_p_cole > 0) { conceal_old_cursor_line = last_cursormoved.lnum; conceal_new_cursor_line = curwin->w_cursor.lnum; conceal_update_lines = TRUE; } ! #endif last_cursormoved = curwin->w_cursor; } *** ../vim-8.1.1452/src/edit.c 2019-05-24 19:38:59.096545552 +0200 --- src/edit.c 2019-06-02 18:12:32.244392562 +0200 *************** *** 1456,1463 **** * inserting sequences of characters (e.g., for CTRL-R). */ void ! ins_redraw( ! int ready UNUSED) /* not busy with something */ { #ifdef FEAT_CONCEAL linenr_T conceal_old_cursor_line = 0; --- 1456,1462 ---- * inserting sequences of characters (e.g., for CTRL-R). */ void ! ins_redraw(int ready) // not busy with something { #ifdef FEAT_CONCEAL linenr_T conceal_old_cursor_line = 0; *************** *** 1468,1477 **** if (char_avail()) return; - #if defined(FEAT_CONCEAL) /* Trigger CursorMoved if the cursor moved. Not when the popup menu is * visible, the command might delete it. */ if (ready && (has_cursormovedI() # if defined(FEAT_CONCEAL) || curwin->w_p_cole > 0 # endif --- 1467,1478 ---- if (char_avail()) return; /* Trigger CursorMoved if the cursor moved. Not when the popup menu is * visible, the command might delete it. */ if (ready && (has_cursormovedI() + # ifdef FEAT_TEXT_PROP + || popup_visible + # endif # if defined(FEAT_CONCEAL) || curwin->w_p_cole > 0 # endif *************** *** 1497,1502 **** --- 1498,1507 ---- update_curswant(); ins_apply_autocmds(EVENT_CURSORMOVEDI); } + #ifdef FEAT_TEXT_PROP + if (popup_visible) + popup_check_cursor_pos(); + #endif # ifdef FEAT_CONCEAL if (curwin->w_p_cole > 0) { *************** *** 1507,1513 **** # endif last_cursormoved = curwin->w_cursor; } - #endif /* Trigger TextChangedI if b_changedtick differs. */ if (ready && has_textchangedI() --- 1512,1517 ---- *************** *** 3859,3865 **** if (replace_stack_len <= replace_stack_nr) { replace_stack_len += 50; ! p = alloc(sizeof(char_u) * replace_stack_len); if (p == NULL) /* out of memory */ { replace_stack_len -= 50; --- 3863,3869 ---- if (replace_stack_len <= replace_stack_nr) { replace_stack_len += 50; ! p = ALLOC_MULT(char_u, replace_stack_len); if (p == NULL) /* out of memory */ { replace_stack_len -= 50; *** ../vim-8.1.1452/src/gui.c 2019-05-24 18:48:36.758128504 +0200 --- src/gui.c 2019-06-02 17:03:51.394743342 +0200 *************** *** 5117,5122 **** --- 5117,5125 ---- /* Trigger CursorMoved if the cursor moved. */ if (!finish_op && (has_cursormoved() + # ifdef FEAT_TEXT_PROP + || popup_visible + # endif # ifdef FEAT_CONCEAL || curwin->w_p_cole > 0 # endif *************** *** 5124,5129 **** --- 5127,5136 ---- { if (has_cursormoved()) apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf); + #ifdef FEAT_TEXT_PROP + if (popup_visible) + popup_check_cursor_pos(); + #endif # ifdef FEAT_CONCEAL if (curwin->w_p_cole > 0) { *** ../vim-8.1.1452/src/globals.h 2019-05-26 18:48:09.402542633 +0200 --- src/globals.h 2019-06-02 17:04:22.518512240 +0200 *************** *** 558,581 **** EXTERN win_T *firstwin; /* first window */ EXTERN win_T *lastwin; /* last window */ EXTERN win_T *prevwin INIT(= NULL); /* previous window */ ! # define ONE_WINDOW (firstwin == lastwin) ! # define W_NEXT(wp) ((wp)->w_next) ! # define FOR_ALL_WINDOWS(wp) for (wp = firstwin; wp != NULL; wp = wp->w_next) ! # define FOR_ALL_FRAMES(frp, first_frame) \ for (frp = first_frame; frp != NULL; frp = frp->fr_next) ! # define FOR_ALL_TABPAGES(tp) for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) ! # define FOR_ALL_WINDOWS_IN_TAB(tp, wp) \ for ((wp) = ((tp) == NULL || (tp) == curtab) \ ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next) /* * When using this macro "break" only breaks out of the inner loop. Use "goto" * to break out of the tabpage loop. */ ! # define FOR_ALL_TAB_WINDOWS(tp, wp) \ for ((tp) = first_tabpage; (tp) != NULL; (tp) = (tp)->tp_next) \ for ((wp) = ((tp) == curtab) \ ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next) EXTERN win_T *curwin; /* currently active window */ EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */ --- 558,582 ---- EXTERN win_T *firstwin; /* first window */ EXTERN win_T *lastwin; /* last window */ EXTERN win_T *prevwin INIT(= NULL); /* previous window */ ! #define ONE_WINDOW (firstwin == lastwin) ! #define W_NEXT(wp) ((wp)->w_next) ! #define FOR_ALL_WINDOWS(wp) for (wp = firstwin; wp != NULL; wp = wp->w_next) ! #define FOR_ALL_FRAMES(frp, first_frame) \ for (frp = first_frame; frp != NULL; frp = frp->fr_next) ! #define FOR_ALL_TABPAGES(tp) for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) ! #define FOR_ALL_WINDOWS_IN_TAB(tp, wp) \ for ((wp) = ((tp) == NULL || (tp) == curtab) \ ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next) /* * When using this macro "break" only breaks out of the inner loop. Use "goto" * to break out of the tabpage loop. */ ! #define FOR_ALL_TAB_WINDOWS(tp, wp) \ for ((tp) = first_tabpage; (tp) != NULL; (tp) = (tp)->tp_next) \ for ((wp) = ((tp) == curtab) \ ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next) + EXTERN win_T *curwin; /* currently active window */ EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */ *************** *** 1663,1666 **** --- 1664,1668 ---- #ifdef FEAT_TEXT_PROP EXTERN int text_prop_frozen INIT(= 0); + EXTERN int popup_visible INIT(= FALSE); #endif *** ../vim-8.1.1452/src/structs.h 2019-06-02 14:49:52.372891128 +0200 --- src/structs.h 2019-06-02 17:09:32.012375995 +0200 *************** *** 2897,2902 **** --- 2897,2908 ---- // computed callback_T w_close_cb; // popup close callback callback_T w_filter_cb; // popup filter callback + + win_T *w_popup_curwin; // close popup if curwin differs + 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 + # if defined(FEAT_TIMERS) timer_T *w_popup_timer; // timer for closing popup window # endif *** ../vim-8.1.1452/src/screen.c 2019-06-02 15:56:11.839730143 +0200 --- src/screen.c 2019-06-02 17:05:40.501948236 +0200 *************** *** 1050,1055 **** --- 1050,1056 ---- // so that the window with a higher zindex is drawn later, thus goes on // top. // TODO: don't redraw every popup every time. + popup_visible = FALSE; popup_reset_handled(); while ((wp = find_next_popup(TRUE)) != NULL) { *************** *** 1066,1071 **** --- 1067,1073 ---- // Draw the popup text. win_update(wp); + popup_visible = TRUE; wp->w_winrow -= top_off; wp->w_wincol -= left_off; *** ../vim-8.1.1452/src/popupwin.c 2019-06-02 16:51:18.011257964 +0200 --- src/popupwin.c 2019-06-02 17:58:17.393963233 +0200 *************** *** 285,290 **** --- 285,333 ---- } } } + + di = dict_find(dict, (char_u *)"moved", -1); + if (di != NULL) + { + wp->w_popup_curwin = curwin; + wp->w_popup_lnum = curwin->w_cursor.lnum; + wp->w_popup_mincol = curwin->w_cursor.col; + wp->w_popup_maxcol = curwin->w_cursor.col; + 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, "any") != 0) + semsg(_(e_invarg2), s); + if (flags != 0) + { + char_u *ptr; + int len = find_ident_under_cursor(&ptr, flags); + + if (len > 0) + { + wp->w_popup_mincol = (int)(ptr - ml_get_curline()); + wp->w_popup_maxcol = wp->w_popup_mincol + len - 1; + } + } + } + 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)); + } } /* *************** *** 708,713 **** --- 751,771 ---- } /* + * Close popup "wp" and invoke any close callback for it. + */ + static void + popup_close_and_callback(win_T *wp, typval_T *arg) + { + int id = wp->w_id; + + if (wp->w_close_cb.cb_name != NULL) + // Careful: This may make "wp" invalid. + invoke_popup_callback(wp, arg); + + popup_close(id); + } + + /* * popup_close({id}) */ void *************** *** 717,729 **** win_T *wp = find_popup_win(id); if (wp != NULL) ! { ! if (wp->w_close_cb.cb_name != NULL) ! // Careful: This may make "wp" invalid. ! invoke_popup_callback(wp, &argvars[1]); ! ! popup_close(id); ! } } /* --- 775,781 ---- win_T *wp = find_popup_win(id); if (wp != NULL) ! popup_close_and_callback(wp, &argvars[1]); } /* *************** *** 1066,1069 **** --- 1118,1145 ---- return res; } + /* + * Called when the cursor moved: check if any popup needs to be closed if the + * cursor moved far enough. + */ + void + popup_check_cursor_pos() + { + win_T *wp; + typval_T tv; + + popup_reset_handled(); + while ((wp = find_next_popup(TRUE)) != NULL) + if (wp->w_popup_curwin != NULL + && (curwin != wp->w_popup_curwin + || curwin->w_cursor.lnum != wp->w_popup_lnum + || curwin->w_cursor.col < wp->w_popup_mincol + || curwin->w_cursor.col > wp->w_popup_maxcol)) + { + tv.v_type = VAR_NUMBER; + tv.vval.v_number = -1; + popup_close_and_callback(wp, &tv); + } + } + #endif // FEAT_TEXT_PROP *** ../vim-8.1.1452/src/proto/popupwin.pro 2019-06-01 17:13:15.880517743 +0200 --- src/proto/popupwin.pro 2019-06-02 17:15:02.082311611 +0200 *************** *** 17,20 **** --- 17,21 ---- void popup_reset_handled(void); win_T *find_next_popup(int lowest); int popup_do_filter(int c); + void popup_check_cursor_pos(void); /* vim: set ft=c : */ *** ../vim-8.1.1452/src/testdir/test_popupwin.vim 2019-06-02 16:51:18.011257964 +0200 --- src/testdir/test_popupwin.vim 2019-06-02 18:37:10.534590921 +0200 *************** *** 909,915 **** %bwipe! endfunc ! function Test_adjust_left_past_screen_width() " width of screen let X = join(map(range(&columns), {->'X'}), '') --- 909,915 ---- %bwipe! endfunc ! func Test_adjust_left_past_screen_width() " width of screen let X = join(map(range(&columns), {->'X'}), '') *************** *** 973,976 **** popupclear %bwipe! ! endfunction --- 973,1037 ---- popupclear %bwipe! ! endfunc ! ! func Test_popup_moved() ! new ! call test_override('char_avail', 1) ! call setline(1, ['one word to move around', 'a WORD.and->some thing']) ! ! exe "normal gg0/word\" ! let winid = popup_atcursor('text', {'moved': 'any'}) ! redraw ! call assert_equal(1, popup_getpos(winid).visible) ! " trigger the check for last_cursormoved by going into insert mode ! call feedkeys("li\", 'xt') ! call assert_equal({}, popup_getpos(winid)) ! popupclear ! ! exe "normal gg0/word\" ! let winid = popup_atcursor('text', {'moved': 'word'}) ! redraw ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("hi\", 'xt') ! call assert_equal({}, popup_getpos(winid)) ! popupclear ! ! exe "normal gg0/word\" ! let winid = popup_atcursor('text', {'moved': 'word'}) ! redraw ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("li\", 'xt') ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("ei\", 'xt') ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("eli\", 'xt') ! call assert_equal({}, popup_getpos(winid)) ! popupclear ! ! exe "normal gg0/WORD\" ! let winid = popup_atcursor('text', {'moved': 'WORD'}) ! redraw ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("eli\", 'xt') ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("wi\", 'xt') ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("Eli\", 'xt') ! call assert_equal({}, popup_getpos(winid)) ! popupclear ! ! exe "normal gg0/word\" ! let winid = popup_atcursor('text', {'moved': [5, 10]}) ! redraw ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("eli\", 'xt') ! call feedkeys("ei\", 'xt') ! call assert_equal(1, popup_getpos(winid).visible) ! call feedkeys("eli\", 'xt') ! call assert_equal({}, popup_getpos(winid)) ! popupclear ! ! bwipe! ! call test_override('ALL', 0) ! endfunc *** ../vim-8.1.1452/runtime/doc/popup.txt 2019-06-02 14:49:52.368891150 +0200 --- runtime/doc/popup.txt 2019-06-02 17:30:33.520955494 +0200 *************** *** 90,96 **** IMPLEMENTATION: - Code is in popupwin.c - - Fix positioning with border and padding. - Why does 'nrformats' leak from the popup window buffer??? - Make redrawing more efficient and avoid flicker. First draw popups, creating a mask, use the mask in screen_line() when --- 90,95 ---- *************** *** 410,422 **** zindex Priority for the popup, default 50. time Time in milliseconds after which the popup will close. When omitted |popup_close()| must be used. ! moved "cell": close the popup if the cursor moved at least ! one screen cell. ! "word" allows for moving the cursor within || ! "WORD" allows for moving the cursor within || ! a list with two numbers specifies the start and end ! column outside of which the popup will close ! {not implemented yet} filter A callback that can filter typed characters, see |popup-filter|. callback A callback that is called when the popup closes, e.g. --- 409,422 ---- zindex Priority for the popup, default 50. time Time in milliseconds after which the popup will close. When omitted |popup_close()| must be used. ! moved Specifies to close the popup if the cursor moved: ! - "any": if the cursor moved at all ! - "word": if the cursor moved outside || ! - "WORD": 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 ! line or to another window. filter A callback that can filter typed characters, see |popup-filter|. callback A callback that is called when the popup closes, e.g. *************** *** 510,515 **** --- 510,518 ---- 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. + ============================================================================== 3. Examples *popup-examples* *** ../vim-8.1.1452/src/version.c 2019-06-02 16:51:18.011257964 +0200 --- src/version.c 2019-06-02 18:37:36.630426619 +0200 *************** *** 769,770 **** --- 769,772 ---- { /* Add new patch number below this line */ + /**/ + 1453, /**/ -- From "know your smileys": ¯\_(ツ)_/¯ Shrug /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///