summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Kennedy <colinvfx@gmail.com>2024-03-03 16:16:47 +0100
committerChristian Brabandt <cb@256bit.org>2024-03-03 16:16:47 +0100
commit215703563757a4464907ead6fb9edaeb7f430bea (patch)
tree380d7492e2fc174d13a073c6fd4e8dae6714030f
parent353faa373eb132987a1985cf3abe18c006f8cdf0 (diff)
patch 9.1.0147: Cannot keep a buffer focused in a windowv9.1.0147
Problem: Cannot keep a buffer focused in a window (Amit Levy) Solution: Add the 'winfixbuf' window-local option (Colin Kennedy) fixes: #6445 closes: #13903 Signed-off-by: Colin Kennedy <colinvfx@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--runtime/doc/message.txt9
-rw-r--r--runtime/doc/options.txt13
-rw-r--r--runtime/doc/quickref.txt3
-rw-r--r--runtime/doc/tags2
-rw-r--r--runtime/doc/tagsrch.txt31
-rw-r--r--runtime/doc/version9.txt4
-rw-r--r--runtime/optwin.vim3
-rw-r--r--src/arglist.c8
-rw-r--r--src/buffer.c7
-rw-r--r--src/errors.h2
-rw-r--r--src/ex_cmds.c3
-rw-r--r--src/ex_cmds.h2
-rw-r--r--src/ex_cmds2.c25
-rw-r--r--src/ex_docmd.c15
-rw-r--r--src/insexpand.c2
-rw-r--r--src/normal.c6
-rw-r--r--src/option.c1
-rw-r--r--src/option.h1
-rw-r--r--src/optiondefs.h4
-rw-r--r--src/proto/search.pro2
-rw-r--r--src/proto/window.pro2
-rw-r--r--src/quickfix.c40
-rw-r--r--src/search.c7
-rw-r--r--src/structs.h2
-rw-r--r--src/tag.c6
-rw-r--r--src/testdir/Make_all.mak1
-rw-r--r--src/testdir/test_winfixbuf.vim3131
-rw-r--r--src/version.c2
-rw-r--r--src/window.c33
29 files changed, 3336 insertions, 31 deletions
diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt
index 133d47ad11..58480740ed 100644
--- a/runtime/doc/message.txt
+++ b/runtime/doc/message.txt
@@ -1,4 +1,4 @@
-*message.txt* For Vim version 9.1. Last change: 2023 Dec 20
+*message.txt* For Vim version 9.1. Last change: 2024 Mar 03
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -122,6 +122,13 @@ wiped out a buffer which contains a mark or is referenced in another way.
You cannot have two buffers with exactly the same name. This includes the
path leading to the file.
+ *E1513* >
+ Cannot edit buffer. 'winfixbuf' is enabled
+
+If a window has 'winfixbuf' enabled, you cannot change that window's current
+buffer. You need to set 'nowinfixbuf' before continuing. You may use [!] to
+force the window to switch buffers, if your command supports it.
+
*E72*
Close error on swap file ~
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 210bfdcbd6..e38aa81a80 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt* For Vim version 9.1. Last change: 2024 Feb 24
+*options.txt* For Vim version 9.1. Last change: 2024 Mar 03
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -8021,6 +8021,8 @@ A jump table for the options with a short description can be found at |Q_op|.
"split" when both are present.
uselast If included, jump to the previously used window when
jumping to errors with |quickfix| commands.
+ If a window has 'winfixbuf' enabled, 'switchbuf' is currently not
+ applied to the split window.
*'synmaxcol'* *'smc'*
'synmaxcol' 'smc' number (default 3000)
@@ -9471,6 +9473,15 @@ A jump table for the options with a short description can be found at |Q_op|.
Note: Do not confuse this with the height of the Vim window, use
'lines' for that.
+ *'winfixbuf'*
+'winfixbuf' 'wfb' boolean (default off)
+ local to window
+ If enabled, the buffer and any window that displays it are paired.
+ For example, attempting to change the buffer with |:edit| will fail.
+ Other commands which change a window's buffer such as |:cnext| will
+ also skip any window with 'winfixbuf' enabled. However if a command
+ has an "!" option, a window can be forced to switch buffers.
+
*'winfixheight'* *'wfh'* *'nowinfixheight'* *'nowfh'*
'winfixheight' 'wfh' boolean (default off)
local to window |local-noglobal|
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index dcbb52013b..517fa30426 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -1,4 +1,4 @@
-*quickref.txt* For Vim version 9.1. Last change: 2023 Dec 05
+*quickref.txt* For Vim version 9.1. Last change: 2024 Mar 03
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1005,6 +1005,7 @@ Short explanation of each option: *option-list*
'winaltkeys' 'wak' when the windows system handles ALT keys
'wincolor' 'wcr' window-local highlighting
'window' 'wi' nr of lines to scroll for CTRL-F and CTRL-B
+'winfixbuf' 'wfb' keep window focused on a single buffer
'winfixheight' 'wfh' keep window height when opening/closing windows
'winfixwidth' 'wfw' keep window width when opening/closing windows
'winheight' 'wh' minimum number of lines for the current window
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 8af0b573a5..efecedfb2a 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -1294,6 +1294,7 @@ $quote eval.txt /*$quote*
'winaltkeys' options.txt /*'winaltkeys'*
'wincolor' options.txt /*'wincolor'*
'window' options.txt /*'window'*
+'winfixbuf' options.txt /*'winfixbuf'*
'winfixheight' options.txt /*'winfixheight'*
'winfixwidth' options.txt /*'winfixwidth'*
'winheight' options.txt /*'winheight'*
@@ -4541,6 +4542,7 @@ E151 helphelp.txt /*E151*
E1510 change.txt /*E1510*
E1511 options.txt /*E1511*
E1512 options.txt /*E1512*
+E1513 message.txt /*E1513*
E152 helphelp.txt /*E152*
E153 helphelp.txt /*E153*
E154 helphelp.txt /*E154*
diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt
index aa7b9dd48d..ce6d44634b 100644
--- a/runtime/doc/tagsrch.txt
+++ b/runtime/doc/tagsrch.txt
@@ -1,4 +1,4 @@
-*tagsrch.txt* For Vim version 9.1. Last change: 2023 Feb 13
+*tagsrch.txt* For Vim version 9.1. Last change: 2024 Mar 03
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -409,17 +409,22 @@ If the tag is in the current file this will always work. Otherwise the
performed actions depend on whether the current file was changed, whether a !
is added to the command and on the 'autowrite' option:
- tag in file autowrite ~
-current file changed ! option action ~
------------------------------------------------------------------------------
- yes x x x goto tag
- no no x x read other file, goto tag
- no yes yes x abandon current file, read other file, goto
- tag
- no yes no on write current file, read other file, goto
- tag
- no yes no off fail
------------------------------------------------------------------------------
+ tag in file autowrite ~
+current file changed ! winfixbuf option action ~
+ -----------------------------------------------------------------------------
+ yes x x no x goto tag
+ no no x no x read other file, goto tag
+ no yes yes no x abandon current file,
+ read other file, goto tag
+ no yes no no on write current file,
+ read other file, goto tag
+ no yes no no off fail
+ yes x yes x x goto tag
+ no no no yes x fail
+ no yes no yes x fail
+ no yes no yes on fail
+ no yes no yes off fail
+ -----------------------------------------------------------------------------
- If the tag is in the current file, the command will always work.
- If the tag is in another file and the current file was not changed, the
@@ -435,6 +440,8 @@ current file changed ! option action ~
the changes, use the ":w" command and then use ":tag" without an argument.
This works because the tag is put on the stack anyway. If you want to lose
the changes you can use the ":tag!" command.
+- If the tag is in another file and the window includes 'winfixbuf', the
+ command will fail. If the tag is in the same file then it may succeed.
*tag-security*
Note that Vim forbids some commands, for security reasons. This works like
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 7b9a3664a0..7947cb281c 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.1. Last change: 2024 Feb 21
+*version9.txt* For Vim version 9.1. Last change: 2024 Mar 03
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41575,6 +41575,8 @@ Commands: ~
Options: ~
+'winfixbuf' Keep buffer focused in a window
+
==============================================================================
INCOMPATIBLE CHANGES *incompatible-9.2*
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 6e133ce673..d3e1605ed0 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -482,6 +482,7 @@ if has("statusline")
call <SID>AddOption("statusline", gettext("alternate format to be used for a status line"))
call <SID>OptionG("stl", &stl)
endif
+call append("$", "\t" .. s:local_to_window)
call <SID>AddOption("equalalways", gettext("make all windows the same size when adding/removing windows"))
call <SID>BinOptionG("ea", &ea)
call <SID>AddOption("eadirection", gettext("in which direction 'equalalways' works: \"ver\", \"hor\" or \"both\""))
@@ -490,6 +491,8 @@ call <SID>AddOption("winheight", gettext("minimal number of lines used for the c
call append("$", " \tset wh=" . &wh)
call <SID>AddOption("winminheight", gettext("minimal number of lines used for any window"))
call append("$", " \tset wmh=" . &wmh)
+call <SID>AddOption("winfixbuf", gettext("keep window focused on a single buffer"))
+call <SID>OptionG("wfb", &wfb)
call <SID>AddOption("winfixheight", gettext("keep the height of the window"))
call append("$", "\t" .. s:local_to_window)
call <SID>BinOptionL("wfh")
diff --git a/src/arglist.c b/src/arglist.c
index 723133254a..187e16e835 100644
--- a/src/arglist.c
+++ b/src/arglist.c
@@ -682,6 +682,7 @@ do_argfile(exarg_T *eap, int argn)
int other;
char_u *p;
int old_arg_idx = curwin->w_arg_idx;
+ int is_split_cmd = *eap->cmd == 's';
if (ERROR_IF_ANY_POPUP_WINDOW)
return;
@@ -697,13 +698,18 @@ do_argfile(exarg_T *eap, int argn)
return;
}
+ if (!is_split_cmd
+ && (&ARGLIST[argn])->ae_fnum != curbuf->b_fnum
+ && !check_can_set_curbuf_forceit(eap->forceit))
+ return;
+
setpcmark();
#ifdef FEAT_GUI
need_mouse_correct = TRUE;
#endif
// split window or create new tab page first
- if (*eap->cmd == 's' || cmdmod.cmod_tab != 0)
+ if (is_split_cmd || cmdmod.cmod_tab != 0)
{
if (win_split(0, 0) == FAIL)
return;
diff --git a/src/buffer.c b/src/buffer.c
index 8d62e64368..36396e8d28 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1370,6 +1370,13 @@ do_buffer_ext(
if ((flags & DOBUF_NOPOPUP) && bt_popup(buf) && !bt_terminal(buf))
return OK;
#endif
+ if (
+ action == DOBUF_GOTO
+ && buf != curbuf
+ && !check_can_set_curbuf_forceit((flags & DOBUF_FORCEIT) ? TRUE : FALSE))
+ // disallow navigating to another buffer when 'winfixbuf' is applied
+ return FAIL;
+
if ((action == DOBUF_GOTO || action == DOBUF_SPLIT)
&& (buf->b_flags & BF_DUMMY))
{
diff --git a/src/errors.h b/src/errors.h
index dd2bc95b76..65ee4e826e 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3607,3 +3607,5 @@ EXTERN char e_wrong_number_of_characters_for_field_str[]
INIT(= N_("E1511: Wrong number of characters for field \"%s\""));
EXTERN char e_wrong_character_width_for_field_str[]
INIT(= N_("E1512: Wrong character width for field \"%s\""));
+EXTERN char e_winfixbuf_cannot_go_to_buffer[]
+ INIT(= N_("E1513: Cannot edit buffer. 'winfixbuf' is enabled"));
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 720e918bb4..a12d819b3f 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -2428,6 +2428,9 @@ getfile(
int retval;
char_u *free_me = NULL;
+ if (!check_can_set_curbuf_forceit(forceit))
+ return GETFILE_ERROR;
+
if (text_locked())
return GETFILE_ERROR;
if (curbuf_locked())
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 4ae6cc2293..bd26e81dcc 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -521,7 +521,7 @@ EXCMD(CMD_doautoall, "doautoall", ex_doautoall,
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
ADDR_NONE),
EXCMD(CMD_drop, "drop", ex_drop,
- EX_FILES|EX_CMDARG|EX_NEEDARG|EX_ARGOPT|EX_TRLBAR,
+ EX_BANG|EX_FILES|EX_CMDARG|EX_NEEDARG|EX_ARGOPT|EX_TRLBAR,
ADDR_NONE),
EXCMD(CMD_dsearch, "dsearch", ex_findpat,
EX_BANG|EX_RANGE|EX_DFLALL|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK,
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 0bde73070e..c9834d2232 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -457,6 +457,31 @@ ex_listdo(exarg_T *eap)
tabpage_T *tp;
buf_T *buf = curbuf;
int next_fnum = 0;
+
+ if (curwin->w_p_wfb)
+ {
+ if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) && !eap->forceit)
+ {
+ // Disallow :ldo if 'winfixbuf' is applied
+ semsg("%s", e_winfixbuf_cannot_go_to_buffer);
+ return;
+ }
+
+ if (win_valid(prevwin))
+ // Change the current window to another because 'winfixbuf' is enabled
+ curwin = prevwin;
+ else
+ {
+ // Split the window, which will be 'nowinfixbuf', and set curwin to that
+ exarg_T new_eap;
+ CLEAR_FIELD(new_eap);
+ new_eap.cmdidx = CMD_split;
+ new_eap.cmd = (char_u *)"split";
+ new_eap.arg = (char_u *)"";
+ ex_splitview(&new_eap);
+ }
+ }
+
#if defined(FEAT_SYN_HL)
char_u *save_ei = NULL;
#endif
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index c18a9107ec..19b1d85c68 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -7164,6 +7164,9 @@ ex_resize(exarg_T *eap)
static void
ex_find(exarg_T *eap)
{
+ if (!check_can_set_curbuf_forceit(eap->forceit))
+ return;
+
char_u *fname;
int count;
char_u *file_to_find = NULL;
@@ -7245,6 +7248,14 @@ ex_open(exarg_T *eap)
static void
ex_edit(exarg_T *eap)
{
+ // Exclude commands which keep the window's current buffer
+ if (
+ eap->cmdidx != CMD_badd
+ && eap->cmdidx != CMD_balt
+ // All other commands must obey 'winfixbuf' / ! rules
+ && !check_can_set_curbuf_forceit(eap->forceit))
+ return;
+
do_exedit(eap, NULL);
}
@@ -9031,7 +9042,7 @@ ex_checkpath(exarg_T *eap)
{
find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L,
eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
- (linenr_T)1, (linenr_T)MAXLNUM);
+ (linenr_T)1, (linenr_T)MAXLNUM, eap->forceit);
}
#if defined(FEAT_QUICKFIX)
@@ -9101,7 +9112,7 @@ ex_findpat(exarg_T *eap)
find_pattern_in_path(eap->arg, 0, (int)STRLEN(eap->arg),
whole, !eap->forceit,
*eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY,
- n, action, eap->line1, eap->line2);
+ n, action, eap->line1, eap->line2, eap->forceit);
}
#endif
diff --git a/src/insexpand.c b/src/insexpand.c
index 68e970a71a..0847b6c051 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -3407,7 +3407,7 @@ get_next_include_file_completion(int compl_type)
(compl_type == CTRL_X_PATH_DEFINES
&& !(compl_cont_status & CONT_SOL))
? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
- (linenr_T)1, (linenr_T)MAXLNUM);
+ (linenr_T)1, (linenr_T)MAXLNUM, FALSE);
}
#endif
diff --git a/src/normal.c b/src/normal.c
index 791b02f1cd..5ef3a9277c 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -4073,6 +4073,9 @@ nv_gotofile(cmdarg_T *cap)
return;
#endif
+ if (!check_can_set_curbuf_disabled())
+ return;
+
ptr = grab_file_name(cap->count1, &lnum);
if (ptr != NULL)
@@ -4475,7 +4478,8 @@ nv_brackets(cmdarg_T *cap)
SAFE_isupper(cap->nchar) ? ACTION_SHOW_ALL :
SAFE_islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO,
cap->cmdchar == ']' ? curwin->w_cursor.lnum + 1 : (linenr_T)1,
- (linenr_T)MAXLNUM);
+ (linenr_T)MAXLNUM,
+ FALSE);
vim_free(ptr);
curwin->w_set_curswant = TRUE;
}
diff --git a/src/option.c b/src/option.c
index dd3542f895..8123a2a2c6 100644
--- a/src/option.c
+++ b/src/option.c
@@ -6420,6 +6420,7 @@ get_varp(struct vimoption *p)
#ifdef FEAT_LINEBREAK
case PV_NUW: return (char_u *)&(curwin->w_p_nuw);
#endif
+ case PV_WFB: return (char_u *)&(curwin->w_p_wfb);
case PV_WFH: return (char_u *)&(curwin->w_p_wfh);
case PV_WFW: return (char_u *)&(curwin->w_p_wfw);
#if defined(FEAT_QUICKFIX)
diff --git a/src/option.h b/src/option.h
index 75940cce0a..bf889e47de 100644
--- a/src/option.h
+++ b/src/option.h
@@ -1309,6 +1309,7 @@ enum
#ifdef FEAT_STL_OPT
, WV_STL
#endif
+ , WV_WFB
, WV_WFH
, WV_WFW
, WV_WRAP
diff --git a/src/optiondefs.h b/src/optiondefs.h
index 1a09e1c7fb..4ee2e20de3 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -215,6 +215,7 @@
# define PV_STL OPT_BOTH(OPT_WIN(WV_STL))
#endif
#define PV_UL OPT_BOTH(OPT_BUF(BV_UL))
+# define PV_WFB OPT_WIN(WV_WFB)
# define PV_WFH OPT_WIN(WV_WFH)
# define PV_WFW OPT_WIN(WV_WFW)
#define PV_WRAP OPT_WIN(WV_WRAP)
@@ -2850,6 +2851,9 @@ static struct vimoption options[] =
{"window", "wi", P_NUM|P_VI_DEF,
(char_u *)&p_window, PV_NONE, did_set_window, NULL,
{(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"winfixbuf", "wfb", P_BOOL|P_VI_DEF|P_RWIN,
+ (char_u *)VAR_WIN, PV_WFB, NULL, NULL,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
{"winfixheight", "wfh", P_BOOL|P_VI_DEF|P_RSTAT,
(char_u *)VAR_WIN, PV_WFH, NULL, NULL,
{(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
diff --git a/src/proto/search.pro b/src/proto/search.pro
index 99e279dadf..5b2b889317 100644
--- a/src/proto/search.pro
+++ b/src/proto/search.pro
@@ -32,7 +32,7 @@ int check_linecomment(char_u *line);
void showmatch(int c);
int current_search(long count, int forward);
int linewhite(linenr_T lnum);
-void find_pattern_in_path(char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum);
+void find_pattern_in_path(char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum, int forceit);
spat_T *get_spat(int idx);
int get_spat_last_idx(void);
void f_searchcount(typval_T *argvars, typval_T *rettv);
diff --git a/src/proto/window.pro b/src/proto/window.pro
index e5c03969fb..9e66db5a7f 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -1,4 +1,6 @@
/* window.c */
+int check_can_set_curbuf_disabled(void);
+int check_can_set_curbuf_forceit(int forceit);
int window_layout_locked(enum CMD_index cmd);
win_T *prevwin_curwin(void);
win_T *swbuf_goto_win_with_buf(buf_T *buf);
diff --git a/src/quickfix.c b/src/quickfix.c
index d8bcc1232a..1f4176fe54 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -3146,7 +3146,7 @@ qf_goto_win_with_qfl_file(int qf_fnum)
// Didn't find it, go to the window before the quickfix
// window, unless 'switchbuf' contains 'uselast': in this case we
// try to jump to the previously used window first.
- if ((swb_flags & SWB_USELAST) && win_valid(prevwin))
+ if ((swb_flags & SWB_USELAST) && !prevwin->w_p_wfb && win_valid(prevwin))
win = prevwin;
else if (altwin != NULL)
win = altwin;
@@ -3158,7 +3158,7 @@ qf_goto_win_with_qfl_file(int qf_fnum)
}
// Remember a usable window.
- if (altwin == NULL && !win->w_p_pvw && bt_normal(win->w_buffer))
+ if (altwin == NULL && !win->w_p_pvw && !win->w_p_wfb && bt_normal(win->w_buffer))
altwin = win;
}
@@ -3261,8 +3261,32 @@ qf_jump_edit_buffer(
prev_winid == curwin->w_id ? curwin : NULL);
}
else
+ {
+ if (!forceit && curwin->w_p_wfb)
+ {
+ if (qi->qfl_type == QFLT_LOCATION)
+ {
+ // Location lists cannot split or reassign their window
+ // so 'winfixbuf' windows must fail
+ semsg("%s", e_winfixbuf_cannot_go_to_buffer);
+ return QF_ABORT;
+ }
+
+ if (!win_valid(prevwin))
+ {
+ // Split the window, which will be 'nowinfixbuf', and set curwin to that
+ exarg_T new_eap;
+ CLEAR_FIELD(new_eap);
+ new_eap.cmdidx = CMD_split;
+ new_eap.cmd = (char_u *)"split";
+ new_eap.arg = (char_u *)"";
+ ex_splitview(&new_eap);
+ }
+ }
+
retval = buflist_getfile(qf_ptr->qf_fnum,
(linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
+ }
// If a location list, check whether the associated window is still
// present.
@@ -4991,6 +5015,11 @@ qf_jump_first(qf_info_T *qi, int_u save_qfid, int forceit)
if (qf_restore_list(qi, save_qfid) == FAIL)
return;
+
+ if (!check_can_set_curbuf_forceit(forceit))
+ return;
+
+
// Autocommands might have cleared the list, check for that.
if (!qf_list_empty(qf_get_curlist(qi)))
qf_jump(qi, 0, 0, forceit);
@@ -5907,7 +5936,7 @@ ex_cfile(exarg_T *eap)
// This function is used by the :cfile, :cgetfile and :caddfile
// commands.
- // :cfile always creates a new quickfix list and jumps to the
+ // :cfile always creates a new quickfix list and may jump to the
// first error.
// :cgetfile creates a new quickfix list but doesn't jump to the
// first error.
@@ -6497,6 +6526,9 @@ ex_vimgrep(exarg_T *eap)
char_u *au_name = NULL;
int status;
+ if (!check_can_set_curbuf_forceit(eap->forceit))
+ return;
+
au_name = vgr_get_auname(eap->cmdidx);
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
curbuf->b_fname, TRUE, curbuf))
@@ -6558,7 +6590,7 @@ ex_vimgrep(exarg_T *eap)
goto theend;
}
- // Jump to first match.
+ // Jump to first match if the current window is not 'winfixbuf'
if (!qf_list_empty(qf_get_curlist(qi)))
{
if ((args.flags & VGR_NOJUMP) == 0)
diff --git a/src/search.c b/src/search.c
index 1d0542b658..83aaf0ac31 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3292,7 +3292,8 @@ find_pattern_in_path(
long count,
int action, // What to do when we find it
linenr_T start_lnum, // first line to start searching
- linenr_T end_lnum) // last line for searching
+ linenr_T end_lnum, // last line for searching
+ int forceit) // If true, always switch to the found path
{
SearchedFile *files; // Stack of included files
SearchedFile *bigger; // When we need more space
@@ -3829,7 +3830,7 @@ search_line:
break;
if (!GETFILE_SUCCESS(getfile(
curwin_save->w_buffer->b_fnum, NULL,
- NULL, TRUE, lnum, FALSE)))
+ NULL, TRUE, lnum, forceit)))
break; // failed to jump to file
}
else
@@ -3842,7 +3843,7 @@ search_line:
{
if (!GETFILE_SUCCESS(getfile(
0, files[depth].name, NULL, TRUE,
- files[depth].lnum, FALSE)))
+ files[depth].lnum, forceit)))
break; // failed to jump to file
// autocommands may have changed the lnum, we don't
// want that here
diff --git a/src/structs.h b/src/structs.h
index 5b88260f35..df2c005e3d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -246,6 +246,8 @@ typedef struct
long wo_nuw;
# define w_p_nuw w_onebuf_opt.wo_nuw // 'numberwidth'
#endif
+ int wo_wfb;
+#define w_p_wfb w_onebuf_opt.wo_wfb // 'winfixbuf'
int wo_wfh;
# define w_p_wfh w_onebuf_opt.wo_wfh // 'winfixheight'
int wo_wfw;
diff --git a/src/tag.c b/src/tag.c
index 3df767d192..2ac0da2666 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -289,6 +289,9 @@ do_tag(
static char_u **matches = NULL;
static int flags;
+ if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit))
+ return FALSE;
+
#ifdef FEAT_EVAL
if (tfu_in_use)
{
@@ -3705,6 +3708,9 @@ jumpto_tag(
size_t len;
char_u *lbuf;
+ if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit))
+ return FAIL;
+
// Make a copy of the line, it can become invalid when an autocommand calls
// back here recursively.
len = matching_line_len(lbuf_arg) + 1;
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 8dd04e79e3..d365dfc84f 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -325,6 +325,7 @@ NEW_TESTS = \
test_window_cmd \
test_window_id \
test_windows_home \
+ test_winfixbuf \
test_wnext \
test_wordcount \
test_writefile \
diff --git a/src/testdir/test_winfixbuf.vim b/src/testdir/test_winfixbuf.vim
new file mode 100644
index 0000000000..0b15983932
--- /dev/null
+++ b/src/testdir/test_winfixbuf.vim
@@ -0,0 +1,3131 @@
+" Test 'winfixbuf'
+
+source check.vim
+
+" Find the number of open windows in the current tab
+func s:get_windows_count()
+ return tabpagewinnr(tabpagenr(), '$')
+endfunc
+
+" Create some unnamed buffers.
+func s:make_buffers_list()
+ enew
+ file first
+ let l:first = bufnr()
+
+ enew
+ file middle
+ let l:middle = bufnr()
+
+ enew
+ file last
+ let l:last = bufnr()
+
+ set winfixbuf
+
+ return [l:first, l:last]
+endfunc
+
+" Create some unnamed buffers and add them to an args list
+func s:make_args_list()
+ let [l:first, l:last] = s:make_buffers_list()
+
+ args! first middle last
+
+ return [l:first, l:last]
+endfunc
+
+" Create two buffers and then set the window to 'winfixbuf'
+func s:make_buffer_pairs(...)
+ let l:reversed = get(a:, 1, 0)
+
+ if l:reversed == 1
+ enew
+ file original
+
+ set winfixbuf
+
+ enew!
+ file other
+ let l:other = bufnr()
+
+ return l:other
+ endif
+
+ enew
+ file other
+ let l:other = bufnr()
+
+ enew
+ file current
+
+ set winfixbuf
+
+ return l:other
+endfunc
+
+" Create 3 quick buffers and set the window to 'winfixbuf'
+func s:make_buffer_trio()
+ edit first
+ let l:first = bufnr()
+ edit second
+ let l:second = bufnr()
+
+ set winfixbuf
+
+ edit! third
+ let l:third = bufnr()
+
+ execute ":buffer! " . l:second
+
+ return [l:first, l:second, l:third]
+endfunc
+
+" Create a location list with at least 2 entries + a 'winfixbuf' window.
+func s:make_simple_location_list()
+ enew
+ file middle
+ let l:middle = bufnr()
+ call append(0, ["winfix search-term", "another line"])
+
+ enew!
+ file first
+ let l:first = bufnr()
+ call append(0, "first search-term")
+
+ enew!
+ file last
+ let l:last = bufnr()
+ call append(0, "last search-term")
+
+ call setloclist(
+ \ 0,
+ \ [
+ \ {
+ \ "filename": "first",
+ \ "bufnr": l:first,
+ \ "lnum": 1,
+ \ },
+ \ {
+ \ "filename": "middle",
+ \ "bufnr": l:middle,
+ \ "lnum": 1,
+ \ },
+ \ {
+ \ "filename": "middle",
+ \ "bufnr": l:middle,
+ \ "lnum": 2,
+ \ },
+ \ {
+ \ "filename": "last",
+ \ "bufnr": l:last,
+ \ "lnum": 1,
+ \ },
+ \ ]
+ \)
+
+ set winfixbuf
+
+ return [l:first, l:middle, l:last]
+endfunc
+
+" Create a quickfix with at least 2 entries that are in the current 'winfixbuf' window.
+func s:make_simple_quickfix()
+ enew
+ file current
+ let l:current = bufnr()
+ call append(0, ["winfix search-term", "another line"])
+
+ enew!
+ file first
+ let l:first = bufnr()
+ call append(0, "first search-term")
+
+ enew!
+ file last
+ let l:last = bufnr()
+ call append(0, "last search-term")
+
+ call setqflist(
+ \ [
+ \ {
+ \ "filename": "first",
+ \ "bufnr": l:first,
+ \ "lnum": 1,
+ \ },
+ \ {
+ \ "filename": "current",
+ \ "bufnr": l:current,
+ \ "lnum": 1,
+ \ },
+ \ {
+ \ "filename": "current",
+ \ "bufnr": l:current,
+ \ "lnum": 2,
+ \ },
+ \ {
+ \ "filename": "last",
+ \ "bufnr": l:last,
+ \ "lnum": 1,
+ \ },
+ \ ]
+ \)
+
+ set winfixbuf
+
+ return [l:current, l:last]
+endfunc
+
+" Create a quickfix with at least 2 entries that are in the current 'winfixbuf' window.
+func s:make_quickfix_windows()
+ let [l:current, _] = s:make_simple_quickfix()
+ execute "buffer! " . l:current