From f6518e55164be3fd2d10bf7738c5d76970fb8d79 Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 24 Apr 2021 23:09:31 +0800 Subject: vim-patch:8.1.1418: win_execute() is not implemented yet Problem: Win_execute() is not implemented yet. Solution: Implement it. https://github.com/vim/vim/commit/868b7b6712ea4f2232eeeae18c5cbbbddf2ee84d --- src/nvim/eval.lua | 1 + src/nvim/eval/funcs.c | 40 +++++++++++++++++++++++++++------- src/nvim/testdir/test_execute_func.vim | 24 ++++++++++++++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 77e7c7b3a9..148804e54c 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -390,6 +390,7 @@ return { visualmode={args={0, 1}}, wait={args={2,3}}, wildmenumode={}, + win_execute={args={2, 3}}, win_findbuf={args=1}, win_getid={args={0,2}}, win_gettype={args={0,1}}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 6d328953f6..fe0a4c29a2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1953,8 +1953,8 @@ static char_u *get_list_line(int c, void *cookie, int indent, bool do_concat) return (char_u *)(s == NULL ? NULL : xstrdup(s)); } -// "execute(command)" function -static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, + int arg_off) { const int save_msg_silent = msg_silent; const int save_emsg_silent = emsg_silent; @@ -1968,9 +1968,9 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - if (argvars[1].v_type != VAR_UNKNOWN) { + if (argvars[arg_off + 1].v_type != VAR_UNKNOWN) { char buf[NUMBUFLEN]; - const char *const s = tv_get_string_buf_chk(&argvars[1], buf); + const char *const s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf); if (s == NULL) { return; @@ -1997,10 +1997,10 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) msg_col = 0; // prevent leading spaces } - if (argvars[0].v_type != VAR_LIST) { - do_cmdline_cmd(tv_get_string(&argvars[0])); - } else if (argvars[0].vval.v_list != NULL) { - list_T *const list = argvars[0].vval.v_list; + if (argvars[arg_off].v_type != VAR_LIST) { + do_cmdline_cmd(tv_get_string(&argvars[arg_off])); + } else if (argvars[arg_off].vval.v_list != NULL) { + list_T *const list = argvars[arg_off].vval.v_list; tv_list_ref(list); GetListLineCookie cookie = { .l = list, @@ -2032,6 +2032,30 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) capture_ga = save_capture_ga; } +// "execute(command)" function +static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + execute_common(argvars, rettv, fptr, 0); +} + +// "win_execute(win_id, command)" function +static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + win_T *wp = win_id2wp(argvars); + win_T *save_curwin = curwin; + + if (wp != NULL) { + curwin = wp; + curbuf = curwin->w_buffer; + check_cursor(); + execute_common(argvars, rettv, fptr, 1); + if (win_valid(save_curwin)) { + curwin = save_curwin; + curbuf = curwin->w_buffer; + } + } +} + /// "exepath()" function static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr) { diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim index eb84a6739d..98e0ea4e09 100644 --- a/src/nvim/testdir/test_execute_func.vim +++ b/src/nvim/testdir/test_execute_func.vim @@ -82,3 +82,27 @@ func Test_execute_not_silent() endfor call assert_equal('xyz ', text2) endfunc + +func Test_win_execute() + let thiswin = win_getid() + new + let otherwin = win_getid() + call setline(1, 'the new window') + call win_gotoid(thiswin) + let line = win_execute(otherwin, 'echo getline(1)') + call assert_match('the new window', line) + + if has('textprop') + let popupwin = popup_create('the popup win', {'line': 2, 'col': 3}) + redraw + let line = win_execute(popupwin, 'echo getline(1)') + call assert_match('the popup win', line) + + call assert_fails('call win_execute(popupwin, "bwipe!")', 'E937:') + + call popup_close(popupwin) + endif + + call win_gotoid(otherwin) + bwipe! +endfunc -- cgit From 97abf8ee63994c19c2119e34bc7a7aa66457a7f2 Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 1 May 2021 10:00:41 +0800 Subject: vim-patch:8.1.1425: win_execute() does not set window pointers properly Problem: Win_execute() does not set window pointers properly. Solution: Use switch_win_noblock(). Also execute autocommands in a popup window. https://github.com/vim/vim/commit/89adc3a1371d211f7766f3dbc0975ecb2f862327 --- src/nvim/eval/funcs.c | 15 +++++++-------- src/nvim/window.c | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index fe0a4c29a2..3a202759b6 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2042,17 +2042,16 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) { win_T *wp = win_id2wp(argvars); - win_T *save_curwin = curwin; + win_T *save_curwin; + tabpage_T *save_curtab; if (wp != NULL) { - curwin = wp; - curbuf = curwin->w_buffer; - check_cursor(); - execute_common(argvars, rettv, fptr, 1); - if (win_valid(save_curwin)) { - curwin = save_curwin; - curbuf = curwin->w_buffer; + if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, true) == + OK) { + check_cursor(); + execute_common(argvars, rettv, fptr, 1); } + restore_win_noblock(save_curwin, save_curtab, true); } } diff --git a/src/nvim/window.c b/src/nvim/window.c index c482d265ff..ddfb4e6ef3 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6335,6 +6335,13 @@ static win_T *get_snapshot_focus(int idx) int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, int no_display) { block_autocmds(); + return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display); +} + +// As switch_win() but without blocking autocommands. +int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab, + win_T *win, tabpage_T *tp, int no_display) +{ *save_curwin = curwin; if (tp != NULL) { *save_curtab = curtab; @@ -6359,6 +6366,14 @@ int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage // When "no_display" is true the display won't be affected, no redraw is // triggered. void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display) +{ + restore_win_noblock(save_curwin, save_curtab, no_display); + unblock_autocmds(); +} + +// As restore_win() but without unblocking autocommands. +void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab, + bool no_display) { if (save_curtab != NULL && valid_tabpage(save_curtab)) { if (no_display) { @@ -6374,7 +6389,6 @@ void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display) curwin = save_curwin; curbuf = curwin->w_buffer; } - unblock_autocmds(); } /// Make "buf" the current buffer. -- cgit From 3c00252248daf54c5ba4ef2c983256cf81c71ded Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 1 May 2021 10:19:21 +0800 Subject: vim-patch:8.1.1440: win_execute() test fails Problem: Win_execute() test fails. Solution: Adjust the expected error number. Move to popup test. https://github.com/vim/vim/commit/2d247849ce612050ba1085df806746b23be1f0a3 --- src/nvim/testdir/test_execute_func.vim | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim index 98e0ea4e09..a634f9fc91 100644 --- a/src/nvim/testdir/test_execute_func.vim +++ b/src/nvim/testdir/test_execute_func.vim @@ -98,8 +98,6 @@ func Test_win_execute() let line = win_execute(popupwin, 'echo getline(1)') call assert_match('the popup win', line) - call assert_fails('call win_execute(popupwin, "bwipe!")', 'E937:') - call popup_close(popupwin) endif -- cgit From 73154bbae033513a937af8092320920a49684ce6 Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 1 May 2021 10:21:14 +0800 Subject: vim-patch:8.1.1832: win_execute() does not work in other tab Problem: Win_execute() does not work in other tab. (Rick Howe) Solution: Take care of the tab. (closes vim/vim#4792) https://github.com/vim/vim/commit/820680b9ff1de8699156c7b060f97e5c0b87ad15 --- src/nvim/eval/funcs.c | 7 ++++--- src/nvim/testdir/test_execute_func.vim | 9 +++++++++ src/nvim/window.c | 9 +++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3a202759b6..0b50f41de3 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2041,12 +2041,13 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) // "win_execute(win_id, command)" function static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - win_T *wp = win_id2wp(argvars); + tabpage_T *tp; + win_T *wp = win_id2wp_tp(argvars, &tp); win_T *save_curwin; tabpage_T *save_curtab; - if (wp != NULL) { - if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, true) == + if (wp != NULL && tp != NULL) { + if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) == OK) { check_cursor(); execute_common(argvars, rettv, fptr, 1); diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim index a634f9fc91..9efed76eda 100644 --- a/src/nvim/testdir/test_execute_func.vim +++ b/src/nvim/testdir/test_execute_func.vim @@ -104,3 +104,12 @@ func Test_win_execute() call win_gotoid(otherwin) bwipe! endfunc + +func Test_win_execute_other_tab() + let thiswin = win_getid() + tabnew + call win_execute(thiswin, 'let xyz = 1') + call assert_equal(1, xyz) + tabclose + unlet xyz +endfunc diff --git a/src/nvim/window.c b/src/nvim/window.c index ddfb4e6ef3..bcd955d1b0 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6820,11 +6820,20 @@ void win_id2tabwin(typval_T *const argvars, typval_T *const rettv) } win_T * win_id2wp(typval_T *argvars) +{ + return win_id2wp_tp(argvars, NULL); +} + +// Return the window and tab pointer of window "id". +win_T * win_id2wp_tp(typval_T *argvars, tabpage_T **tpp) { int id = tv_get_number(&argvars[0]); FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->handle == id) { + if (tpp != NULL) { + *tpp = tp; + } return wp; } } -- cgit From ec3524da29b4d3c6cdccb3ab3608f88e8c4ba183 Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 1 May 2021 10:31:15 +0800 Subject: vim-patch:8.1.2124: ruler is not updated if win_execute() moves cursor Problem: Ruler is not updated if win_execute() moves cursor. Solution: Update the status line. (closes vim/vim#5022) https://github.com/vim/vim/commit/345f28df5482cd35f5fa74b06443376379f113b0 --- src/nvim/eval/funcs.c | 6 ++++++ src/nvim/testdir/test_execute_func.vim | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0b50f41de3..2a046efc0b 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2047,12 +2047,18 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) tabpage_T *save_curtab; if (wp != NULL && tp != NULL) { + pos_T curpos = wp->w_cursor; if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) == OK) { check_cursor(); execute_common(argvars, rettv, fptr, 1); } restore_win_noblock(save_curwin, save_curtab, true); + + // Update the status line if the cursor moved. + if (win_valid(wp) && !equalpos(curpos, wp->w_cursor)) { + wp->w_redr_status = true; + } } } diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim index 9efed76eda..51df61d762 100644 --- a/src/nvim/testdir/test_execute_func.vim +++ b/src/nvim/testdir/test_execute_func.vim @@ -1,5 +1,7 @@ " test execute() +source view_util.vim + func NestedEval() let nested = execute('echo "nested\nlines"') echo 'got: "' . nested . '"' @@ -105,6 +107,24 @@ func Test_win_execute() bwipe! endfunc +func Test_win_execute_update_ruler() + enew + call setline(1, range(500)) + 20 + split + let winid = win_getid() + set ruler + wincmd w + let height = winheight(winid) + redraw + call assert_match('20,1', Screenline(height + 1)) + let line = win_execute(winid, 'call cursor(100, 1)') + redraw + call assert_match('100,1', Screenline(height + 1)) + + bwipe! +endfunc + func Test_win_execute_other_tab() let thiswin = win_getid() tabnew -- cgit From 8fecc5fab89c5141186d4ca2937f9aed8a361aa0 Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 1 May 2021 10:38:43 +0800 Subject: vim-patch:8.2.0137: crash when using win_execute() from a new tab Problem: Crash when using win_execute() from a new tab. Solution: Set the tp_*win pointers. (Ozaki Kiichi, closes vim/vim#5512) https://github.com/vim/vim/commit/a44b3eeafa57d4904a3de86b132008b93404f0fd --- src/nvim/testdir/test_winbuf_close.vim | 14 ++++++++++++-- src/nvim/window.c | 5 +++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_winbuf_close.vim b/src/nvim/testdir/test_winbuf_close.vim index ee43540fdd..7f5b80e8d3 100644 --- a/src/nvim/testdir/test_winbuf_close.vim +++ b/src/nvim/testdir/test_winbuf_close.vim @@ -160,7 +160,7 @@ func Test_winfixwidth_on_close() endfunction " Test that 'winfixheight' will be respected even there is non-leaf frame -fun! Test_winfixheight_non_leaf_frame() +func Test_winfixheight_non_leaf_frame() vsplit botright 11new let l:wid = win_getid() @@ -173,7 +173,7 @@ fun! Test_winfixheight_non_leaf_frame() endf " Test that 'winfixwidth' will be respected even there is non-leaf frame -fun! Test_winfixwidth_non_leaf_frame() +func Test_winfixwidth_non_leaf_frame() split topleft 11vnew let l:wid = win_getid() @@ -184,3 +184,13 @@ fun! Test_winfixwidth_non_leaf_frame() call assert_equal(11, winwidth(l:wid)) %bwipe! endf + +func Test_tabwin_close() + enew + let l:wid = win_getid() + tabedit + call win_execute(l:wid, 'close') + " Should not crash. + call assert_true(v:true) + %bwipe! +endfunc diff --git a/src/nvim/window.c b/src/nvim/window.c index bcd955d1b0..4fa6d8e63c 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3459,6 +3459,9 @@ int win_alloc_first(void) first_tabpage = alloc_tabpage(); first_tabpage->tp_topframe = topframe; curtab = first_tabpage; + curtab->tp_firstwin = firstwin; + curtab->tp_lastwin = lastwin; + curtab->tp_curwin = curwin; return OK; } @@ -3627,6 +3630,8 @@ int win_new_tabpage(int after, char_u *filename) newtp->tp_next = tp->tp_next; tp->tp_next = newtp; } + newtp->tp_firstwin = newtp->tp_lastwin = newtp->tp_curwin = curwin; + win_init_size(); firstwin->w_winrow = tabline_height(); win_comp_scroll(curwin); -- cgit From 03b3ff861082ff09f2903565d928187489225306 Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 1 May 2021 10:44:21 +0800 Subject: vim-patch:8.2.2340: win_execute() unexpectedly returns number zero when failing Problem: win_execute() unexpectedly returns number zero when failing. Solution: Return an empty string. (closes vim/vim#7665) https://github.com/vim/vim/commit/37487e16da7877129edee8d11b9b7f5c8df312c6 --- src/nvim/eval/funcs.c | 3 +++ src/nvim/testdir/test_execute_func.vim | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 2a046efc0b..04e6a73f37 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2045,6 +2045,9 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) win_T *wp = win_id2wp_tp(argvars, &tp); win_T *save_curwin; tabpage_T *save_curtab; + // Return an empty string if something fails. + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; if (wp != NULL && tp != NULL) { pos_T curpos = wp->w_cursor; diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim index 51df61d762..15ba894dbe 100644 --- a/src/nvim/testdir/test_execute_func.vim +++ b/src/nvim/testdir/test_execute_func.vim @@ -93,6 +93,8 @@ func Test_win_execute() call win_gotoid(thiswin) let line = win_execute(otherwin, 'echo getline(1)') call assert_match('the new window', line) + let line = win_execute(134343, 'echo getline(1)') + call assert_equal('', line) if has('textprop') let popupwin = popup_create('the popup win', {'line': 2, 'col': 3}) -- cgit From 1def3d1542d6a65f057e743faea39a760b50db87 Mon Sep 17 00:00:00 2001 From: jing Date: Sat, 9 Jan 2021 13:15:23 +0800 Subject: api/window: use the "noblock" variants in nvim_win_set_buf after commit 92c6383cdca977("vim-patch:8.1.1425: win_execute() does not set window pointers properly"), nvim_win_set_buf can use switch_win_noblock and restore_win_noblock. It makes nvim_win_set_buf don't block autocmds so that it will be more "without side-effects" as said in help text. Signed-off-by: jing --- src/nvim/api/window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 89fa2f86fb..5e2f03f007 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -54,7 +54,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) return; } - if (switch_win(&save_curwin, &save_curtab, win, tab, false) == FAIL) { + if (switch_win_noblock(&save_curwin, &save_curtab, win, tab, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to switch to window %d", @@ -74,7 +74,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) // So do it now. validate_cursor(); - restore_win(save_curwin, save_curtab, false); + restore_win_noblock(save_curwin, save_curtab, false); } /// Gets the (1,0)-indexed cursor position in the window. |api-indexing| -- cgit