aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/window.c4
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/funcs.c49
-rw-r--r--src/nvim/testdir/test_execute_func.vim53
-rw-r--r--src/nvim/testdir/test_winbuf_close.vim14
-rw-r--r--src/nvim/window.c30
6 files changed, 138 insertions, 13 deletions
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index f942d6b19f..158e149628 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|
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 b3df081932..865abcc110 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,39 @@ 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)
+{
+ tabpage_T *tp;
+ 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;
+ 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;
+ }
+ }
+}
+
/// "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..15ba894dbe 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 . '"'
@@ -82,3 +84,54 @@ 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)
+ 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})
+ redraw
+ let line = win_execute(popupwin, 'echo getline(1)')
+ call assert_match('the popup win', line)
+
+ call popup_close(popupwin)
+ endif
+
+ call win_gotoid(otherwin)
+ 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
+ call win_execute(thiswin, 'let xyz = 1')
+ call assert_equal(1, xyz)
+ tabclose
+ unlet xyz
+endfunc
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 c070f0a32e..d4d00c0a71 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -3466,6 +3466,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;
}
@@ -3634,6 +3637,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);
@@ -6336,6 +6341,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;
@@ -6361,6 +6373,14 @@ int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage
// 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) {
curtab->tp_firstwin = firstwin;
@@ -6375,7 +6395,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.
@@ -6808,10 +6827,19 @@ 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;
}
}