Merge pull request #13664 from ivechan/win_exectute

vim-patch:8.1.{1418,1425,1832,2124},8.2.{0137, 2340}
This commit is contained in:
Jan Edmund Lazo
2021-05-07 08:34:28 -04:00
committed by GitHub
8 changed files with 166 additions and 13 deletions

View File

@@ -2529,6 +2529,8 @@ visualmode([expr]) String last visual mode used
wait({timeout}, {condition}[, {interval}]) wait({timeout}, {condition}[, {interval}])
Number Wait until {condition} is satisfied Number Wait until {condition} is satisfied
wildmenumode() Number whether 'wildmenu' mode is active wildmenumode() Number whether 'wildmenu' mode is active
win_execute({id}, {command} [, {silent}])
String execute {command} in window {id}
win_findbuf({bufnr}) List find windows containing {bufnr} win_findbuf({bufnr}) List find windows containing {bufnr}
win_getid([{win} [, {tab}]]) Number get |window-ID| for {win} in {tab} win_getid([{win} [, {tab}]]) Number get |window-ID| for {win} in {tab}
win_gettype([{nr}]) String type of window {nr} win_gettype([{nr}]) String type of window {nr}
@@ -3543,6 +3545,8 @@ execute({command} [, {silent}]) *execute()*
Note: If nested, an outer execute() will not observe output of Note: If nested, an outer execute() will not observe output of
the inner calls. the inner calls.
Note: Text attributes (highlights) are not captured. Note: Text attributes (highlights) are not captured.
To execute a command in another window than the current one
use `win_execute()`.
exepath({expr}) *exepath()* exepath({expr}) *exepath()*
Returns the full path of {expr} if it is an executable and Returns the full path of {expr} if it is an executable and
@@ -9123,6 +9127,12 @@ wildmenumode() *wildmenumode()*
< <
(Note, this needs the 'wildcharm' option set appropriately). (Note, this needs the 'wildcharm' option set appropriately).
win_execute({id}, {command} [, {silent}]) *win_execute()*
Like `execute()` but in the context of window {id}.
The window will temporarily be made the current window,
without triggering autocommands.
Example: >
call win_execute(winid, 'syntax enable')
win_findbuf({bufnr}) *win_findbuf()* win_findbuf({bufnr}) *win_findbuf()*
Returns a |List| with |window-ID|s for windows that contain Returns a |List| with |window-ID|s for windows that contain

View File

@@ -54,7 +54,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
return; 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, api_set_error(err,
kErrorTypeException, kErrorTypeException,
"Failed to switch to window %d", "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. // So do it now.
validate_cursor(); 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| /// Gets the (1,0)-indexed cursor position in the window. |api-indexing|

View File

@@ -390,6 +390,7 @@ return {
visualmode={args={0, 1}}, visualmode={args={0, 1}},
wait={args={2,3}}, wait={args={2,3}},
wildmenumode={}, wildmenumode={},
win_execute={args={2, 3}},
win_findbuf={args=1}, win_findbuf={args=1},
win_getid={args={0,2}}, win_getid={args={0,2}},
win_gettype={args={0,1}}, win_gettype={args={0,1}},

View File

@@ -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)); return (char_u *)(s == NULL ? NULL : xstrdup(s));
} }
// "execute(command)" function static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr,
static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) int arg_off)
{ {
const int save_msg_silent = msg_silent; const int save_msg_silent = msg_silent;
const int save_emsg_silent = emsg_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; return;
} }
if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[arg_off + 1].v_type != VAR_UNKNOWN) {
char buf[NUMBUFLEN]; 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) { if (s == NULL) {
return; return;
@@ -1997,10 +1997,10 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
msg_col = 0; // prevent leading spaces msg_col = 0; // prevent leading spaces
} }
if (argvars[0].v_type != VAR_LIST) { if (argvars[arg_off].v_type != VAR_LIST) {
do_cmdline_cmd(tv_get_string(&argvars[0])); do_cmdline_cmd(tv_get_string(&argvars[arg_off]));
} else if (argvars[0].vval.v_list != NULL) { } else if (argvars[arg_off].vval.v_list != NULL) {
list_T *const list = argvars[0].vval.v_list; list_T *const list = argvars[arg_off].vval.v_list;
tv_list_ref(list); tv_list_ref(list);
GetListLineCookie cookie = { GetListLineCookie cookie = {
.l = list, .l = list,
@@ -2032,6 +2032,39 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
capture_ga = save_capture_ga; 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 /// "exepath()" function
static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{ {

View File

@@ -1,5 +1,7 @@
" test execute() " test execute()
source view_util.vim
func NestedEval() func NestedEval()
let nested = execute('echo "nested\nlines"') let nested = execute('echo "nested\nlines"')
echo 'got: "' . nested . '"' echo 'got: "' . nested . '"'
@@ -82,3 +84,54 @@ func Test_execute_not_silent()
endfor endfor
call assert_equal('xyz ', text2) call assert_equal('xyz ', text2)
endfunc 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

View File

@@ -160,7 +160,7 @@ func Test_winfixwidth_on_close()
endfunction endfunction
" Test that 'winfixheight' will be respected even there is non-leaf frame " 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 vsplit
botright 11new botright 11new
let l:wid = win_getid() let l:wid = win_getid()
@@ -173,7 +173,7 @@ fun! Test_winfixheight_non_leaf_frame()
endf endf
" Test that 'winfixwidth' will be respected even there is non-leaf frame " 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 split
topleft 11vnew topleft 11vnew
let l:wid = win_getid() let l:wid = win_getid()
@@ -184,3 +184,13 @@ fun! Test_winfixwidth_non_leaf_frame()
call assert_equal(11, winwidth(l:wid)) call assert_equal(11, winwidth(l:wid))
%bwipe! %bwipe!
endf 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

View File

@@ -3466,6 +3466,9 @@ int win_alloc_first(void)
first_tabpage = alloc_tabpage(); first_tabpage = alloc_tabpage();
first_tabpage->tp_topframe = topframe; first_tabpage->tp_topframe = topframe;
curtab = first_tabpage; curtab = first_tabpage;
curtab->tp_firstwin = firstwin;
curtab->tp_lastwin = lastwin;
curtab->tp_curwin = curwin;
return OK; return OK;
} }
@@ -3634,6 +3637,8 @@ int win_new_tabpage(int after, char_u *filename)
newtp->tp_next = tp->tp_next; newtp->tp_next = tp->tp_next;
tp->tp_next = newtp; tp->tp_next = newtp;
} }
newtp->tp_firstwin = newtp->tp_lastwin = newtp->tp_curwin = curwin;
win_init_size(); win_init_size();
firstwin->w_winrow = tabline_height(); firstwin->w_winrow = tabline_height();
win_comp_scroll(curwin); 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) int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, int no_display)
{ {
block_autocmds(); 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; *save_curwin = curwin;
if (tp != NULL) { if (tp != NULL) {
*save_curtab = curtab; *save_curtab = curtab;
@@ -6360,6 +6372,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 // When "no_display" is true the display won't be affected, no redraw is
// triggered. // triggered.
void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display) 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 (save_curtab != NULL && valid_tabpage(save_curtab)) {
if (no_display) { if (no_display) {
@@ -6375,7 +6395,6 @@ void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display)
curwin = save_curwin; curwin = save_curwin;
curbuf = curwin->w_buffer; curbuf = curwin->w_buffer;
} }
unblock_autocmds();
} }
/// Make "buf" the current buffer. /// Make "buf" the current buffer.
@@ -6807,11 +6826,20 @@ void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
} }
win_T * win_id2wp(typval_T *argvars) 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]); int id = tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) { FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->handle == id) { if (wp->handle == id) {
if (tpp != NULL) {
*tpp = tp;
}
return wp; return wp;
} }
} }

View File

@@ -62,6 +62,24 @@ describe('float window', function()
eq(1000, funcs.win_getid()) eq(1000, funcs.win_getid())
end) end)
it('win_execute() should work' , function()
local buf = meths.create_buf(false, false)
meths.buf_set_lines(buf, 0, -1, true, {'the floatwin'})
local win = meths.open_win(buf, false, {relative='win', width=16, height=1, row=0, col=10})
local line = funcs.win_execute(win, 'echo getline(1)')
eq('\nthe floatwin', line)
funcs.win_execute(win, 'bwipe!')
end)
it('win_execute() call commands that not allowed' , function()
local buf = meths.create_buf(false, false)
meths.buf_set_lines(buf, 0, -1, true, {'the floatwin'})
local win = meths.open_win(buf, true, {relative='win', width=16, height=1, row=0, col=10})
eq(pcall_err(funcs.win_execute, win, 'close'), 'Vim(close):E37: No write since last change (add ! to override)')
eq(pcall_err(funcs.win_execute, win, 'bdelete'), 'Vim(bdelete):E89: No write since last change for buffer 2 (add ! to override)')
funcs.win_execute(win, 'bwipe!')
end)
it('closed immediately by autocmd #11383', function() it('closed immediately by autocmd #11383', function()
eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately', eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
pcall_err(exec_lua, [[ pcall_err(exec_lua, [[