diff options
-rw-r--r-- | runtime/doc/message.txt | 9 | ||||
-rw-r--r-- | runtime/doc/options.txt | 13 | ||||
-rw-r--r-- | runtime/doc/quickref.txt | 3 | ||||
-rw-r--r-- | runtime/doc/tags | 2 | ||||
-rw-r--r-- | runtime/doc/tagsrch.txt | 31 | ||||
-rw-r--r-- | runtime/doc/version9.txt | 4 | ||||
-rw-r--r-- | runtime/optwin.vim | 3 | ||||
-rw-r--r-- | src/arglist.c | 8 | ||||
-rw-r--r-- | src/buffer.c | 7 | ||||
-rw-r--r-- | src/errors.h | 2 | ||||
-rw-r--r-- | src/ex_cmds.c | 3 | ||||
-rw-r--r-- | src/ex_cmds.h | 2 | ||||
-rw-r--r-- | src/ex_cmds2.c | 25 | ||||
-rw-r--r-- | src/ex_docmd.c | 15 | ||||
-rw-r--r-- | src/insexpand.c | 2 | ||||
-rw-r--r-- | src/normal.c | 6 | ||||
-rw-r--r-- | src/option.c | 1 | ||||
-rw-r--r-- | src/option.h | 1 | ||||
-rw-r--r-- | src/optiondefs.h | 4 | ||||
-rw-r--r-- | src/proto/search.pro | 2 | ||||
-rw-r--r-- | src/proto/window.pro | 2 | ||||
-rw-r--r-- | src/quickfix.c | 40 | ||||
-rw-r--r-- | src/search.c | 7 | ||||
-rw-r--r-- | src/structs.h | 2 | ||||
-rw-r--r-- | src/tag.c | 6 | ||||
-rw-r--r-- | src/testdir/Make_all.mak | 1 | ||||
-rw-r--r-- | src/testdir/test_winfixbuf.vim | 3131 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/window.c | 33 |
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; @@ -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 |