mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:9.1.0147: Cannot keep a buffer focused in a window
Problem: Cannot keep a buffer focused in a window
(Amit Levy)
Solution: Add the 'winfixbuf' window-local option
(Colin Kennedy)
fixes: vim/vim#6445
closes: vim/vim#13903
2157035637
N/A patch:
vim-patch:58f1e5c0893a
This commit is contained in:
parent
a09ddd7ce5
commit
141182d6c6
@ -114,6 +114,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
|
You cannot have two buffers with exactly the same name. This includes the
|
||||||
path leading to the file.
|
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* >
|
*E72* >
|
||||||
Close error on swap file
|
Close error on swap file
|
||||||
|
|
||||||
|
@ -160,6 +160,8 @@ The following new APIs and features were added.
|
|||||||
• 'breakindent' performance is significantly improved for wrapped lines.
|
• 'breakindent' performance is significantly improved for wrapped lines.
|
||||||
• Cursor movement, insertion with [count] and |screenpos()| are now faster.
|
• Cursor movement, insertion with [count] and |screenpos()| are now faster.
|
||||||
|
|
||||||
|
• |'winfixbuf'| keeps a window focused onto a specific buffer
|
||||||
|
|
||||||
• |vim.iter()| provides a generic iterator interface for tables and Lua
|
• |vim.iter()| provides a generic iterator interface for tables and Lua
|
||||||
iterators |for-in|.
|
iterators |for-in|.
|
||||||
|
|
||||||
|
@ -6271,6 +6271,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
"split" when both are present.
|
"split" when both are present.
|
||||||
uselast If included, jump to the previously used window when
|
uselast If included, jump to the previously used window when
|
||||||
jumping to errors with |quickfix| commands.
|
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'*
|
||||||
'synmaxcol' 'smc' number (default 3000)
|
'synmaxcol' 'smc' number (default 3000)
|
||||||
@ -7170,6 +7172,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
|
Note: Do not confuse this with the height of the Vim window, use
|
||||||
'lines' for that.
|
'lines' for that.
|
||||||
|
|
||||||
|
*'winfixbuf'* *'wfb'* *'nowinfixbuf'* *'nowfb'*
|
||||||
|
'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'* *'nowinfixheight'* *'nowfh'*
|
||||||
'winfixheight' 'wfh' boolean (default off)
|
'winfixheight' 'wfh' boolean (default off)
|
||||||
local to window |local-noglobal|
|
local to window |local-noglobal|
|
||||||
|
@ -939,6 +939,7 @@ Short explanation of each option: *option-list*
|
|||||||
'wildoptions' 'wop' specifies how command line completion is done
|
'wildoptions' 'wop' specifies how command line completion is done
|
||||||
'winaltkeys' 'wak' when the windows system handles ALT keys
|
'winaltkeys' 'wak' when the windows system handles ALT keys
|
||||||
'window' 'wi' nr of lines to scroll for CTRL-F and CTRL-B
|
'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
|
'winfixheight' 'wfh' keep window height when opening/closing windows
|
||||||
'winfixwidth' 'wfw' keep window width when opening/closing windows
|
'winfixwidth' 'wfw' keep window width when opening/closing windows
|
||||||
'winheight' 'wh' minimum number of lines for the current window
|
'winheight' 'wh' minimum number of lines for the current window
|
||||||
|
@ -402,17 +402,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 !
|
performed actions depend on whether the current file was changed, whether a !
|
||||||
is added to the command and on the 'autowrite' option:
|
is added to the command and on the 'autowrite' option:
|
||||||
|
|
||||||
tag in file autowrite ~
|
tag in file autowrite ~
|
||||||
current file changed ! option action ~
|
current file changed ! winfixbuf option action ~
|
||||||
---------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
yes x x x goto tag
|
yes x x no x goto tag
|
||||||
no no x x read other file, goto tag
|
no no x no x read other file, goto tag
|
||||||
no yes yes x abandon current file, read other file, goto
|
no yes yes no x abandon current file,
|
||||||
tag
|
read other file, goto tag
|
||||||
no yes no on write current file, read other file, goto
|
no yes no no on write current file,
|
||||||
tag
|
read other file, goto tag
|
||||||
no yes no off fail
|
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 the current file, the command will always work.
|
||||||
- If the tag is in another file and the current file was not changed, the
|
- If the tag is in another file and the current file was not changed, the
|
||||||
@ -428,6 +433,8 @@ current file changed ! option action ~
|
|||||||
the changes, use the ":w" command and then use ":tag" without an argument.
|
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
|
This works because the tag is put on the stack anyway. If you want to lose
|
||||||
the changes you can use the ":tag!" command.
|
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*
|
*tag-security*
|
||||||
Note that Vim forbids some commands, for security reasons. This works like
|
Note that Vim forbids some commands, for security reasons. This works like
|
||||||
|
14
runtime/lua/vim/_meta/options.lua
generated
14
runtime/lua/vim/_meta/options.lua
generated
@ -6746,6 +6746,8 @@ vim.bo.swf = vim.bo.swapfile
|
|||||||
--- "split" when both are present.
|
--- "split" when both are present.
|
||||||
--- uselast If included, jump to the previously used window when
|
--- uselast If included, jump to the previously used window when
|
||||||
--- jumping to errors with `quickfix` commands.
|
--- jumping to errors with `quickfix` commands.
|
||||||
|
--- If a window has 'winfixbuf' enabled, 'switchbuf' is currently not
|
||||||
|
--- applied to the split window.
|
||||||
---
|
---
|
||||||
--- @type string
|
--- @type string
|
||||||
vim.o.switchbuf = "uselast"
|
vim.o.switchbuf = "uselast"
|
||||||
@ -7874,6 +7876,18 @@ vim.o.wi = vim.o.window
|
|||||||
vim.go.window = vim.o.window
|
vim.go.window = vim.o.window
|
||||||
vim.go.wi = vim.go.window
|
vim.go.wi = vim.go.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.
|
||||||
|
---
|
||||||
|
--- @type boolean
|
||||||
|
vim.o.winfixbuf = false
|
||||||
|
vim.o.wfb = vim.o.winfixbuf
|
||||||
|
vim.wo.winfixbuf = vim.o.winfixbuf
|
||||||
|
vim.wo.wfb = vim.wo.winfixbuf
|
||||||
|
|
||||||
--- Keep the window height when windows are opened or closed and
|
--- Keep the window height when windows are opened or closed and
|
||||||
--- 'equalalways' is set. Also for `CTRL-W_=`. Set by default for the
|
--- 'equalalways' is set. Also for `CTRL-W_=`. Set by default for the
|
||||||
--- `preview-window` and `quickfix-window`.
|
--- `preview-window` and `quickfix-window`.
|
||||||
|
@ -444,6 +444,7 @@ if has("statusline")
|
|||||||
call <SID>AddOption("statusline", gettext("alternate format to be used for a status line"))
|
call <SID>AddOption("statusline", gettext("alternate format to be used for a status line"))
|
||||||
call <SID>OptionG("stl", &stl)
|
call <SID>OptionG("stl", &stl)
|
||||||
endif
|
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>AddOption("equalalways", gettext("make all windows the same size when adding/removing windows"))
|
||||||
call <SID>BinOptionG("ea", &ea)
|
call <SID>BinOptionG("ea", &ea)
|
||||||
call <SID>AddOption("eadirection", gettext("in which direction 'equalalways' works: \"ver\", \"hor\" or \"both\""))
|
call <SID>AddOption("eadirection", gettext("in which direction 'equalalways' works: \"ver\", \"hor\" or \"both\""))
|
||||||
@ -452,6 +453,8 @@ call <SID>AddOption("winheight", gettext("minimal number of lines used for the c
|
|||||||
call append("$", " \tset wh=" . &wh)
|
call append("$", " \tset wh=" . &wh)
|
||||||
call <SID>AddOption("winminheight", gettext("minimal number of lines used for any window"))
|
call <SID>AddOption("winminheight", gettext("minimal number of lines used for any window"))
|
||||||
call append("$", " \tset wmh=" . &wmh)
|
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 <SID>AddOption("winfixheight", gettext("keep the height of the window"))
|
||||||
call append("$", "\t" .. s:local_to_window)
|
call append("$", "\t" .. s:local_to_window)
|
||||||
call <SID>BinOptionL("wfh")
|
call <SID>BinOptionL("wfh")
|
||||||
|
@ -876,6 +876,11 @@ void nvim_set_current_buf(Buffer buffer, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (curwin->w_p_wfb) {
|
||||||
|
api_set_error(err, kErrorTypeException, "%s", e_winfixbuf_cannot_go_to_buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try_start();
|
try_start();
|
||||||
int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0);
|
int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0);
|
||||||
if (!try_end(err) && result == FAIL) {
|
if (!try_end(err) && result == FAIL) {
|
||||||
|
@ -61,6 +61,12 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
|
|||||||
if (!win || !buf) {
|
if (!win || !buf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (win->w_p_wfb) {
|
||||||
|
api_set_error(err, kErrorTypeException, "%s", e_winfixbuf_cannot_go_to_buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (win == cmdwin_win || win == cmdwin_old_curwin || buf == cmdwin_buf) {
|
if (win == cmdwin_win || win == cmdwin_old_curwin || buf == cmdwin_buf) {
|
||||||
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
|
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
|
||||||
return;
|
return;
|
||||||
|
@ -623,6 +623,8 @@ void ex_argument(exarg_T *eap)
|
|||||||
/// Edit file "argn" of the argument lists.
|
/// Edit file "argn" of the argument lists.
|
||||||
void do_argfile(exarg_T *eap, int argn)
|
void do_argfile(exarg_T *eap, int argn)
|
||||||
{
|
{
|
||||||
|
bool is_split_cmd = *eap->cmd == 's';
|
||||||
|
|
||||||
int old_arg_idx = curwin->w_arg_idx;
|
int old_arg_idx = curwin->w_arg_idx;
|
||||||
|
|
||||||
if (argn < 0 || argn >= ARGCOUNT) {
|
if (argn < 0 || argn >= ARGCOUNT) {
|
||||||
@ -637,10 +639,16 @@ void do_argfile(exarg_T *eap, int argn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_split_cmd
|
||||||
|
&& (&ARGLIST[argn])->ae_fnum != curbuf->b_fnum
|
||||||
|
&& !check_can_set_curbuf_forceit(eap->forceit)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setpcmark();
|
setpcmark();
|
||||||
|
|
||||||
// split window or create new tab page first
|
// 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) {
|
if (win_split(0, 0) == FAIL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1305,6 +1305,12 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
|
|||||||
}
|
}
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action == DOBUF_GOTO && buf != curbuf && !check_can_set_curbuf_forceit(forceit)) {
|
||||||
|
// disallow navigating to another buffer when 'winfixbuf' is applied
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((action == DOBUF_GOTO || action == DOBUF_SPLIT) && (buf->b_flags & BF_DUMMY)) {
|
if ((action == DOBUF_GOTO || action == DOBUF_SPLIT) && (buf->b_flags & BF_DUMMY)) {
|
||||||
// disallow navigating to the dummy buffer
|
// disallow navigating to the dummy buffer
|
||||||
semsg(_(e_nobufnr), count);
|
semsg(_(e_nobufnr), count);
|
||||||
|
@ -139,6 +139,8 @@ typedef struct {
|
|||||||
#define w_ve_flags w_onebuf_opt.wo_ve_flags // flags for 'virtualedit'
|
#define w_ve_flags w_onebuf_opt.wo_ve_flags // flags for 'virtualedit'
|
||||||
OptInt wo_nuw;
|
OptInt wo_nuw;
|
||||||
#define w_p_nuw w_onebuf_opt.wo_nuw // 'numberwidth'
|
#define w_p_nuw w_onebuf_opt.wo_nuw // 'numberwidth'
|
||||||
|
int wo_wfb;
|
||||||
|
#define w_p_wfb w_onebuf_opt.wo_wfb // 'winfixbuf'
|
||||||
int wo_wfh;
|
int wo_wfh;
|
||||||
#define w_p_wfh w_onebuf_opt.wo_wfh // 'winfixheight'
|
#define w_p_wfh w_onebuf_opt.wo_wfh // 'winfixheight'
|
||||||
int wo_wfw;
|
int wo_wfw;
|
||||||
|
@ -2008,6 +2008,10 @@ static int check_readonly(int *forceit, buf_T *buf)
|
|||||||
/// GETFILE_OPEN_OTHER for successfully opening another file.
|
/// GETFILE_OPEN_OTHER for successfully opening another file.
|
||||||
int getfile(int fnum, char *ffname_arg, char *sfname_arg, bool setpm, linenr_T lnum, bool forceit)
|
int getfile(int fnum, char *ffname_arg, char *sfname_arg, bool setpm, linenr_T lnum, bool forceit)
|
||||||
{
|
{
|
||||||
|
if (!check_can_set_curbuf_forceit(forceit)) {
|
||||||
|
return GETFILE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
char *ffname = ffname_arg;
|
char *ffname = ffname_arg;
|
||||||
char *sfname = sfname_arg;
|
char *sfname = sfname_arg;
|
||||||
bool other;
|
bool other;
|
||||||
|
@ -812,7 +812,7 @@ module.cmds = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
command = 'drop',
|
command = 'drop',
|
||||||
flags = bit.bor(FILES, CMDARG, NEEDARG, ARGOPT, TRLBAR),
|
flags = bit.bor(BANG, FILES, CMDARG, NEEDARG, ARGOPT, TRLBAR),
|
||||||
addr_type = 'ADDR_NONE',
|
addr_type = 'ADDR_NONE',
|
||||||
func = 'ex_drop',
|
func = 'ex_drop',
|
||||||
},
|
},
|
||||||
|
@ -444,6 +444,27 @@ int buf_write_all(buf_T *buf, bool forceit)
|
|||||||
/// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
|
/// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
|
||||||
void ex_listdo(exarg_T *eap)
|
void ex_listdo(exarg_T *eap)
|
||||||
{
|
{
|
||||||
|
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 = {
|
||||||
|
.cmdidx = CMD_split,
|
||||||
|
.cmd = "split",
|
||||||
|
.arg = "",
|
||||||
|
};
|
||||||
|
ex_splitview(&new_eap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *save_ei = NULL;
|
char *save_ei = NULL;
|
||||||
|
|
||||||
// Temporarily override SHM_OVER and SHM_OVERALL to avoid that file
|
// Temporarily override SHM_OVER and SHM_OVERALL to avoid that file
|
||||||
|
@ -5334,6 +5334,10 @@ static void ex_resize(exarg_T *eap)
|
|||||||
/// ":find [+command] <file>" command.
|
/// ":find [+command] <file>" command.
|
||||||
static void ex_find(exarg_T *eap)
|
static void ex_find(exarg_T *eap)
|
||||||
{
|
{
|
||||||
|
if (!check_can_set_curbuf_forceit(eap->forceit)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char *file_to_find = NULL;
|
char *file_to_find = NULL;
|
||||||
char *search_ctx = NULL;
|
char *search_ctx = NULL;
|
||||||
char *fname = find_file_in_path(eap->arg, strlen(eap->arg),
|
char *fname = find_file_in_path(eap->arg, strlen(eap->arg),
|
||||||
@ -5364,6 +5368,14 @@ static void ex_find(exarg_T *eap)
|
|||||||
/// ":edit", ":badd", ":balt", ":visual".
|
/// ":edit", ":badd", ":balt", ":visual".
|
||||||
static void ex_edit(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);
|
do_exedit(eap, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6670,7 +6682,7 @@ static void ex_checkpath(exarg_T *eap)
|
|||||||
{
|
{
|
||||||
find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1,
|
find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1,
|
||||||
eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
|
eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
|
||||||
1, (linenr_T)MAXLNUM);
|
1, (linenr_T)MAXLNUM, eap->forceit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ":psearch"
|
/// ":psearch"
|
||||||
@ -6729,7 +6741,7 @@ static void ex_findpat(exarg_T *eap)
|
|||||||
if (!eap->skip) {
|
if (!eap->skip) {
|
||||||
find_pattern_in_path(eap->arg, 0, strlen(eap->arg), whole, !eap->forceit,
|
find_pattern_in_path(eap->arg, 0, strlen(eap->arg), whole, !eap->forceit,
|
||||||
*eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY,
|
*eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY,
|
||||||
n, action, eap->line1, eap->line2);
|
n, action, eap->line1, eap->line2, eap->forceit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -971,6 +971,9 @@ EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s"));
|
|||||||
EXTERN const char e_undobang_cannot_redo_or_move_branch[]
|
EXTERN const char e_undobang_cannot_redo_or_move_branch[]
|
||||||
INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
|
INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
|
||||||
|
|
||||||
|
EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
|
||||||
|
INIT(= N_("E1513: Cannot edit buffer. 'winfixbuf' is enabled"));
|
||||||
|
|
||||||
EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
|
EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
|
||||||
|
|
||||||
EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s"));
|
EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s"));
|
||||||
|
@ -3027,7 +3027,7 @@ static void get_next_include_file_completion(int compl_type)
|
|||||||
((compl_type == CTRL_X_PATH_DEFINES
|
((compl_type == CTRL_X_PATH_DEFINES
|
||||||
&& !(compl_cont_status & CONT_SOL))
|
&& !(compl_cont_status & CONT_SOL))
|
||||||
? FIND_DEFINE : FIND_ANY),
|
? FIND_DEFINE : FIND_ANY),
|
||||||
1, ACTION_EXPAND, 1, MAXLNUM);
|
1, ACTION_EXPAND, 1, MAXLNUM, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next set of words matching "compl_pattern" in dictionary or
|
/// Get the next set of words matching "compl_pattern" in dictionary or
|
||||||
|
@ -3896,6 +3896,10 @@ static void nv_gotofile(cmdarg_T *cap)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_can_set_curbuf_disabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char *ptr = grab_file_name(cap->count1, &lnum);
|
char *ptr = grab_file_name(cap->count1, &lnum);
|
||||||
|
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
@ -4232,7 +4236,8 @@ static void nv_brackets(cmdarg_T *cap)
|
|||||||
(cap->cmdchar == ']'
|
(cap->cmdchar == ']'
|
||||||
? curwin->w_cursor.lnum + 1
|
? curwin->w_cursor.lnum + 1
|
||||||
: 1),
|
: 1),
|
||||||
MAXLNUM);
|
MAXLNUM,
|
||||||
|
false);
|
||||||
xfree(ptr);
|
xfree(ptr);
|
||||||
curwin->w_set_curswant = true;
|
curwin->w_set_curswant = true;
|
||||||
}
|
}
|
||||||
|
@ -4629,6 +4629,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
|
|||||||
return &(win->w_p_rnu);
|
return &(win->w_p_rnu);
|
||||||
case PV_NUW:
|
case PV_NUW:
|
||||||
return &(win->w_p_nuw);
|
return &(win->w_p_nuw);
|
||||||
|
case PV_WFB:
|
||||||
|
return &(win->w_p_wfb);
|
||||||
case PV_WFH:
|
case PV_WFH:
|
||||||
return &(win->w_p_wfh);
|
return &(win->w_p_wfh);
|
||||||
case PV_WFW:
|
case PV_WFW:
|
||||||
|
@ -8406,6 +8406,8 @@ return {
|
|||||||
"split" when both are present.
|
"split" when both are present.
|
||||||
uselast If included, jump to the previously used window when
|
uselast If included, jump to the previously used window when
|
||||||
jumping to errors with |quickfix| commands.
|
jumping to errors with |quickfix| commands.
|
||||||
|
If a window has 'winfixbuf' enabled, 'switchbuf' is currently not
|
||||||
|
applied to the split window.
|
||||||
]=],
|
]=],
|
||||||
expand_cb = 'expand_set_switchbuf',
|
expand_cb = 'expand_set_switchbuf',
|
||||||
full_name = 'switchbuf',
|
full_name = 'switchbuf',
|
||||||
@ -9816,6 +9818,23 @@ return {
|
|||||||
type = 'number',
|
type = 'number',
|
||||||
varname = 'p_window',
|
varname = 'p_window',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
abbreviation = 'wfb',
|
||||||
|
defaults = { if_true = false },
|
||||||
|
desc = [=[
|
||||||
|
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.
|
||||||
|
]=],
|
||||||
|
full_name = 'winfixbuf',
|
||||||
|
pv_name = 'p_wfb',
|
||||||
|
redraw = { 'current_window' },
|
||||||
|
scope = { 'window' },
|
||||||
|
short_desc = N_('pin a window to a specific buffer'),
|
||||||
|
type = 'boolean',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
abbreviation = 'wfh',
|
abbreviation = 'wfh',
|
||||||
defaults = { if_true = false },
|
defaults = { if_true = false },
|
||||||
|
@ -2699,7 +2699,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
|
|||||||
// Didn't find it, go to the window before the quickfix
|
// Didn't find it, go to the window before the quickfix
|
||||||
// window, unless 'switchbuf' contains 'uselast': in this case we
|
// window, unless 'switchbuf' contains 'uselast': in this case we
|
||||||
// try to jump to the previously used window first.
|
// 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;
|
win = prevwin;
|
||||||
} else if (altwin != NULL) {
|
} else if (altwin != NULL) {
|
||||||
win = altwin;
|
win = altwin;
|
||||||
@ -2714,6 +2714,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
|
|||||||
// Remember a usable window.
|
// Remember a usable window.
|
||||||
if (altwin == NULL
|
if (altwin == NULL
|
||||||
&& !win->w_p_pvw
|
&& !win->w_p_pvw
|
||||||
|
&& !win->w_p_wfb
|
||||||
&& bt_normal(win->w_buffer)) {
|
&& bt_normal(win->w_buffer)) {
|
||||||
altwin = win;
|
altwin = win;
|
||||||
}
|
}
|
||||||
@ -2802,6 +2803,25 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int
|
|||||||
ECMD_HIDE + ECMD_SET_HELP,
|
ECMD_HIDE + ECMD_SET_HELP,
|
||||||
prev_winid == curwin->handle ? curwin : NULL);
|
prev_winid == curwin->handle ? curwin : NULL);
|
||||||
} else {
|
} 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 = {
|
||||||
|
.cmdidx = CMD_split,
|
||||||
|
.cmd = "split",
|
||||||
|
.arg = "",
|
||||||
|
};
|
||||||
|
ex_splitview(&new_eap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
retval = buflist_getfile(qf_ptr->qf_fnum, 1,
|
retval = buflist_getfile(qf_ptr->qf_fnum, 1,
|
||||||
GETF_SETMARK | GETF_SWITCH, forceit);
|
GETF_SETMARK | GETF_SWITCH, forceit);
|
||||||
}
|
}
|
||||||
@ -4297,6 +4317,11 @@ static void qf_jump_first(qf_info_T *qi, unsigned save_qfid, int forceit)
|
|||||||
if (qf_restore_list(qi, save_qfid) == FAIL) {
|
if (qf_restore_list(qi, save_qfid) == FAIL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_can_set_curbuf_forceit(forceit)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Autocommands might have cleared the list, check for that
|
// Autocommands might have cleared the list, check for that
|
||||||
if (!qf_list_empty(qf_get_curlist(qi))) {
|
if (!qf_list_empty(qf_get_curlist(qi))) {
|
||||||
qf_jump(qi, 0, 0, forceit);
|
qf_jump(qi, 0, 0, forceit);
|
||||||
@ -5125,7 +5150,7 @@ void ex_cfile(exarg_T *eap)
|
|||||||
|
|
||||||
// This function is used by the :cfile, :cgetfile and :caddfile
|
// This function is used by the :cfile, :cgetfile and :caddfile
|
||||||
// commands.
|
// 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.
|
// first error.
|
||||||
// :cgetfile creates a new quickfix list but doesn't jump to the
|
// :cgetfile creates a new quickfix list but doesn't jump to the
|
||||||
// first error.
|
// first error.
|
||||||
@ -5587,6 +5612,10 @@ theend:
|
|||||||
/// ":lvimgrepadd {pattern} file(s)"
|
/// ":lvimgrepadd {pattern} file(s)"
|
||||||
void ex_vimgrep(exarg_T *eap)
|
void ex_vimgrep(exarg_T *eap)
|
||||||
{
|
{
|
||||||
|
if (!check_can_set_curbuf_forceit(eap->forceit)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char *au_name = vgr_get_auname(eap->cmdidx);
|
char *au_name = vgr_get_auname(eap->cmdidx);
|
||||||
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
|
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
|
||||||
curbuf->b_fname, true, curbuf)) {
|
curbuf->b_fname, true, curbuf)) {
|
||||||
|
@ -3564,8 +3564,10 @@ static char *get_line_and_copy(linenr_T lnum, char *buf)
|
|||||||
/// @param action What to do when we find it
|
/// @param action What to do when we find it
|
||||||
/// @param start_lnum first line to start searching
|
/// @param start_lnum first line to start searching
|
||||||
/// @param end_lnum last line for searching
|
/// @param end_lnum last line for searching
|
||||||
|
/// @param forceit If true, always switch to the found path
|
||||||
void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool skip_comments,
|
void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool skip_comments,
|
||||||
int type, int count, int action, linenr_T start_lnum, linenr_T end_lnum)
|
int type, int count, int action, linenr_T start_lnum, linenr_T end_lnum,
|
||||||
|
int forceit)
|
||||||
{
|
{
|
||||||
SearchedFile *files; // Stack of included files
|
SearchedFile *files; // Stack of included files
|
||||||
SearchedFile *bigger; // When we need more space
|
SearchedFile *bigger; // When we need more space
|
||||||
@ -4025,7 +4027,7 @@ search_line:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!GETFILE_SUCCESS(getfile(curwin_save->w_buffer->b_fnum, NULL,
|
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
|
break; // failed to jump to file
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -4035,7 +4037,7 @@ search_line:
|
|||||||
check_cursor();
|
check_cursor();
|
||||||
} else {
|
} else {
|
||||||
if (!GETFILE_SUCCESS(getfile(0, files[depth].name, NULL, true,
|
if (!GETFILE_SUCCESS(getfile(0, files[depth].name, NULL, true,
|
||||||
files[depth].lnum, false))) {
|
files[depth].lnum, forceit))) {
|
||||||
break; // failed to jump to file
|
break; // failed to jump to file
|
||||||
}
|
}
|
||||||
// autocommands may have changed the lnum, we don't
|
// autocommands may have changed the lnum, we don't
|
||||||
|
@ -290,6 +290,10 @@ void set_buflocal_tfu_callback(buf_T *buf)
|
|||||||
/// @param verbose print "tag not found" message
|
/// @param verbose print "tag not found" message
|
||||||
void do_tag(char *tag, int type, int count, int forceit, bool verbose)
|
void do_tag(char *tag, int type, int count, int forceit, bool verbose)
|
||||||
{
|
{
|
||||||
|
if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
taggy_T *tagstack = curwin->w_tagstack;
|
taggy_T *tagstack = curwin->w_tagstack;
|
||||||
int tagstackidx = curwin->w_tagstackidx;
|
int tagstackidx = curwin->w_tagstackidx;
|
||||||
int tagstacklen = curwin->w_tagstacklen;
|
int tagstacklen = curwin->w_tagstacklen;
|
||||||
@ -2784,6 +2788,10 @@ static char *tag_full_fname(tagptrs_T *tagp)
|
|||||||
/// @return OK for success, NOTAGFILE when file not found, FAIL otherwise.
|
/// @return OK for success, NOTAGFILE when file not found, FAIL otherwise.
|
||||||
static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help)
|
static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help)
|
||||||
{
|
{
|
||||||
|
if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit)) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
char *pbuf_end;
|
char *pbuf_end;
|
||||||
char *tofree_fname = NULL;
|
char *tofree_fname = NULL;
|
||||||
tagptrs_T tagp;
|
tagptrs_T tagp;
|
||||||
|
@ -133,6 +133,35 @@ static void log_frame_layout(frame_T *frame)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Check if the current window is allowed to move to a different buffer.
|
||||||
|
///
|
||||||
|
/// @return If the window has 'winfixbuf', or this function will return false.
|
||||||
|
bool check_can_set_curbuf_disabled(void)
|
||||||
|
{
|
||||||
|
if (curwin->w_p_wfb) {
|
||||||
|
semsg("%s", e_winfixbuf_cannot_go_to_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the current window is allowed to move to a different buffer.
|
||||||
|
///
|
||||||
|
/// @param forceit If true, do not error. If false and 'winfixbuf' is enabled, error.
|
||||||
|
///
|
||||||
|
/// @return If the window has 'winfixbuf', then forceit must be true
|
||||||
|
/// or this function will return false.
|
||||||
|
bool check_can_set_curbuf_forceit(int forceit)
|
||||||
|
{
|
||||||
|
if (!forceit && curwin->w_p_wfb) {
|
||||||
|
semsg("%s", e_winfixbuf_cannot_go_to_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// @return the current window, unless in the cmdline window and "prevwin" is
|
/// @return the current window, unless in the cmdline window and "prevwin" is
|
||||||
/// set, then return "prevwin".
|
/// set, then return "prevwin".
|
||||||
win_T *prevwin_curwin(void)
|
win_T *prevwin_curwin(void)
|
||||||
@ -597,7 +626,7 @@ wingotofile:
|
|||||||
ptr = xmemdupz(ptr, len);
|
ptr = xmemdupz(ptr, len);
|
||||||
|
|
||||||
find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
|
find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
|
||||||
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM);
|
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM, false);
|
||||||
xfree(ptr);
|
xfree(ptr);
|
||||||
curwin->w_set_curswant = true;
|
curwin->w_set_curswant = true;
|
||||||
break;
|
break;
|
||||||
|
54
test/functional/options/winfixbuf_spec.lua
Normal file
54
test/functional/options/winfixbuf_spec.lua
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local clear = helpers.clear
|
||||||
|
local exec_lua = helpers.exec_lua
|
||||||
|
|
||||||
|
describe("Nvim API calls with 'winfixbuf'", function()
|
||||||
|
before_each(function()
|
||||||
|
clear()
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("Calling vim.api.nvim_win_set_buf with 'winfixbuf'", function()
|
||||||
|
local results = exec_lua([[
|
||||||
|
local function _setup_two_buffers()
|
||||||
|
local buffer = vim.api.nvim_create_buf(true, true)
|
||||||
|
|
||||||
|
vim.api.nvim_create_buf(true, true) -- Make another buffer
|
||||||
|
|
||||||
|
local current_window = 0
|
||||||
|
vim.api.nvim_set_option_value("winfixbuf", true, {win=current_window})
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
local other_buffer = _setup_two_buffers()
|
||||||
|
local current_window = 0
|
||||||
|
local results, _ = pcall(vim.api.nvim_win_set_buf, current_window, other_buffer)
|
||||||
|
|
||||||
|
return results
|
||||||
|
]])
|
||||||
|
|
||||||
|
assert(results == false)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("Calling vim.api.nvim_set_current_buf with 'winfixbuf'", function()
|
||||||
|
local results = exec_lua([[
|
||||||
|
local function _setup_two_buffers()
|
||||||
|
local buffer = vim.api.nvim_create_buf(true, true)
|
||||||
|
|
||||||
|
vim.api.nvim_create_buf(true, true) -- Make another buffer
|
||||||
|
|
||||||
|
local current_window = 0
|
||||||
|
vim.api.nvim_set_option_value("winfixbuf", true, {win=current_window})
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
local other_buffer = _setup_two_buffers()
|
||||||
|
local results, _ = pcall(vim.api.nvim_set_current_buf, other_buffer)
|
||||||
|
|
||||||
|
return results
|
||||||
|
]])
|
||||||
|
|
||||||
|
assert(results == false)
|
||||||
|
end)
|
||||||
|
end)
|
3131
test/old/testdir/test_winfixbuf.vim
Normal file
3131
test/old/testdir/test_winfixbuf.vim
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user