diff options
Diffstat (limited to 'src/nvim/eval/window.c')
-rw-r--r-- | src/nvim/eval/window.c | 94 |
1 files changed, 82 insertions, 12 deletions
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index e0abbad477..b8aa0c9641 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -9,19 +9,22 @@ #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" -#include "nvim/buffer_defs.h" #include "nvim/cursor.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/window.h" #include "nvim/garray.h" -#include "nvim/gettext.h" +#include "nvim/garray_defs.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/macros_defs.h" +#include "nvim/mark_defs.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/move.h" +#include "nvim/option_vars.h" +#include "nvim/os/fs.h" #include "nvim/pos_defs.h" #include "nvim/types_defs.h" #include "nvim/vim_defs.h" @@ -480,6 +483,68 @@ void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = nr; } +/// Switch to a window for executing user code. +/// Caller must call win_execute_after() later regardless of return value. +/// +/// @return whether switching the window succeeded. +bool win_execute_before(win_execute_T *args, win_T *wp, tabpage_T *tp) +{ + args->wp = wp; + args->curpos = wp->w_cursor; + args->cwd_status = FAIL; + args->apply_acd = false; + + // Getting and setting directory can be slow on some systems, only do + // this when the current or target window/tab have a local directory or + // 'acd' is set. + if (curwin != wp + && (curwin->w_localdir != NULL || wp->w_localdir != NULL + || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) + || p_acd)) { + args->cwd_status = os_dirname(args->cwd, MAXPATHL); + } + + // If 'acd' is set, check we are using that directory. If yes, then + // apply 'acd' afterwards, otherwise restore the current directory. + if (args->cwd_status == OK && p_acd) { + do_autochdir(); + char autocwd[MAXPATHL]; + if (os_dirname(autocwd, MAXPATHL) == OK) { + args->apply_acd = strcmp(args->cwd, autocwd) == 0; + } + } + + if (switch_win_noblock(&args->switchwin, wp, tp, true) == OK) { + check_cursor(); + return true; + } + return false; +} + +/// Restore the previous window after executing user code. +void win_execute_after(win_execute_T *args) +{ + restore_win_noblock(&args->switchwin, true); + + if (args->apply_acd) { + do_autochdir(); + } else if (args->cwd_status == OK) { + os_chdir(args->cwd); + } + + // Update the status line if the cursor moved. + if (win_valid(args->wp) && !equalpos(args->curpos, args->wp->w_cursor)) { + args->wp->w_redr_status = true; + } + + // In case the command moved the cursor or changed the Visual area, + // check it is valid. + check_cursor(); + if (VIsual_active) { + check_pos(curbuf, &VIsual); + } +} + /// "win_execute(win_id, command)" function void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -494,7 +559,11 @@ void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, 1)); + win_execute_T win_execute_args; + if (win_execute_before(&win_execute_args, wp, tp)) { + execute_common(argvars, rettv, 1); + } + win_execute_after(&win_execute_args); } /// "win_findbuf()" function @@ -607,13 +676,13 @@ static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags // Remove the old window and frame from the tree of frames int dir; - (void)winframe_remove(wp, &dir, NULL); + winframe_remove(wp, &dir, NULL); win_remove(wp, NULL); last_status(false); // may need to remove last status line - (void)win_comp_pos(); // recompute window positions + win_comp_pos(); // recompute window positions // Split a window on the desired side and put the old window there - (void)win_split_ins(size, flags, wp, dir); + win_split_ins(size, flags, wp, dir); // If splitting horizontally, try to preserve height if (size == 0 && !(flags & WSP_VERT)) { @@ -642,7 +711,8 @@ void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - int flags = 0, size = 0; + int flags = 0; + int size = 0; if (argvars[2].v_type != VAR_UNKNOWN) { dict_T *d; @@ -685,7 +755,7 @@ void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_string = xstrdup("preview"); } else if (wp->w_floating) { rettv->vval.v_string = xstrdup("popup"); - } else if (wp == curwin && cmdwin_type != 0) { + } else if (wp == cmdwin_win) { rettv->vval.v_string = xstrdup("command"); } else if (bt_quickfix(wp->w_buffer)) { rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix")); @@ -914,16 +984,16 @@ int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool n return OK; } -// Restore current tabpage and window saved by switch_win(), if still valid. -// When "no_display" is true the display won't be affected, no redraw is -// triggered. +/// Restore current tabpage and window saved by switch_win(), if still valid. +/// When "no_display" is true the display won't be affected, no redraw is +/// triggered. void restore_win(switchwin_T *switchwin, bool no_display) { restore_win_noblock(switchwin, no_display); unblock_autocmds(); } -// As restore_win() but without unblocking autocommands. +/// As restore_win() but without unblocking autocommands. void restore_win_noblock(switchwin_T *switchwin, bool no_display) { if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) { |