vim-patch:9.1.0572: cannot specify tab page closing behaviour (#29682)

Problem:  cannot specify tab page closing behaviour
          (Gianluca Pacchiella)
Solution: Add the 'tabclose' option (LemonBoy).

fixes: vim/vim#5967
closes: vim/vim#15204

5247b0b92e

Co-authored-by: LemonBoy <thatlemon@gmail.com>
This commit is contained in:
zeertzjq 2024-07-13 08:56:58 +08:00 committed by GitHub
parent 10256bb760
commit b1aa8f5eb8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 161 additions and 11 deletions

View File

@ -141,6 +141,7 @@ LUA
OPTIONS
• 'completeopt' flag "fuzzy" enables |fuzzy-matching| during |ins-completion|.
• 'tabclose' controls which tab page to focus when closing a tab page.
PERFORMANCE

View File

@ -6343,6 +6343,19 @@ A jump table for the options with a short description can be found at |Q_op|.
'S' flag in 'cpoptions'.
Only normal file name characters can be used, `/\*?[|<>` are illegal.
*'tabclose'* *'tcl'*
'tabclose' 'tcl' string (default "")
global
This option controls the behavior when closing tab pages (e.g., using
|:tabclose|). When empty Vim goes to the next (right) tab page.
Possible values (comma-separated list):
left If included, go to the previous tab page instead of
the next one.
uselast If included, go to the previously used tab page if
possible. This option takes precedence over the
others.
*'tabline'* *'tal'*
'tabline' 'tal' string (default "")
global

View File

@ -886,6 +886,7 @@ Short explanation of each option: *option-list*
'switchbuf' 'swb' sets behavior when switching to another buffer
'synmaxcol' 'smc' maximum column to find syntax items
'syntax' 'syn' syntax to be loaded for current buffer
'tabclose' 'tcl' which tab page to focus when closing a tab
'tabline' 'tal' custom format for the console tab pages line
'tabpagemax' 'tpm' maximum number of tab pages for |-p| and "tab all"
'tabstop' 'ts' number of spaces that <Tab> in file uses

View File

@ -135,7 +135,8 @@ something else.
:tabclose $ " close the last tab page
:tabclose # " close the last accessed tab page
When a tab is closed the next tab page will become the current one.
When a tab is closed the next tab page will become the current one. This
behaviour can be customized using the 'tabclose' option.
*:tabo* *:tabonly*
:tabo[nly][!] Close all other tab pages.

View File

@ -6837,6 +6837,22 @@ vim.o.syn = vim.o.syntax
vim.bo.syntax = vim.o.syntax
vim.bo.syn = vim.bo.syntax
--- This option controls the behavior when closing tab pages (e.g., using
--- `:tabclose`). When empty Vim goes to the next (right) tab page.
---
--- Possible values (comma-separated list):
--- left If included, go to the previous tab page instead of
--- the next one.
--- uselast If included, go to the previously used tab page if
--- possible. This option takes precedence over the
--- others.
---
--- @type string
vim.o.tabclose = ""
vim.o.tcl = vim.o.tabclose
vim.go.tabclose = vim.o.tabclose
vim.go.tcl = vim.go.tabclose
--- When non-empty, this option determines the content of the tab pages
--- line at the top of the Vim window. When empty Vim will use a default
--- tab pages line. See `setting-tabline` for more info.

View File

@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: The Vim Project <https://github.com/vim/vim>
" Last Change: 2024 Jun 05
" Last Change: 2024 Jul 12
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" If there already is an option window, jump to that one.
@ -507,6 +507,8 @@ endif
call <SID>Header(gettext("multiple tab pages"))
call <SID>AddOption("showtabline", gettext("0, 1 or 2; when to use a tab pages line"))
call append("$", " \tset stal=" . &stal)
call <SID>AddOption("tabclose", gettext("behaviour when closing tab pages: left, uselast or empty"))
call append("$", " \tset tcl=" . &tcl)
call <SID>AddOption("tabpagemax", gettext("maximum number of tab pages to open for -p and \"tab all\""))
call append("$", " \tset tpm=" . &tpm)
call <SID>AddOption("tabline", gettext("custom tab pages line"))

View File

@ -694,7 +694,6 @@ EXTERN unsigned tpf_flags; ///< flags from 'termpastefilter'
EXTERN char *p_tfu; ///< 'tagfunc'
EXTERN char *p_spc; ///< 'spellcapcheck'
EXTERN char *p_spf; ///< 'spellfile'
EXTERN char *p_spk; ///< 'splitkeep'
EXTERN char *p_spl; ///< 'spelllang'
EXTERN char *p_spo; ///< 'spelloptions'
EXTERN unsigned spo_flags;
@ -711,7 +710,12 @@ EXTERN unsigned swb_flags;
#define SWB_NEWTAB 0x008
#define SWB_VSPLIT 0x010
#define SWB_USELAST 0x020
EXTERN char *p_spk; ///< 'splitkeep'
EXTERN char *p_syn; ///< 'syntax'
EXTERN char *p_tcl; ///< 'tabclose'
EXTERN unsigned tcl_flags; ///< flags from 'tabclose'
#define TCL_LEFT 0x001
#define TCL_USELAST 0x002
EXTERN OptInt p_ts; ///< 'tabstop'
EXTERN int p_tbs; ///< 'tagbsearch'
EXTERN char *p_tc; ///< 'tagcase'

View File

@ -8506,6 +8506,30 @@ return {
type = 'string',
varname = 'p_syn',
},
{
abbreviation = 'tcl',
cb = 'did_set_tabclose',
defaults = { if_true = '' },
deny_duplicates = true,
desc = [=[
This option controls the behavior when closing tab pages (e.g., using
|:tabclose|). When empty Vim goes to the next (right) tab page.
Possible values (comma-separated list):
left If included, go to the previous tab page instead of
the next one.
uselast If included, go to the previously used tab page if
possible. This option takes precedence over the
others.
]=],
expand_cb = 'expand_set_tabclose',
full_name = 'tabclose',
list = 'onecomma',
scope = { 'global' },
short_desc = N_('which tab page to focus when closing a tab'),
type = 'string',
varname = 'p_tcl',
},
{
abbreviation = 'tal',
cb = 'did_set_tabline',

View File

@ -98,11 +98,13 @@ static char *(p_ssop_values[]) = { "buffers", "winpos", "resize", "winsize", "lo
"options", "help", "blank", "globals", "slash", "unix", "sesdir",
"curdir", "folds", "cursor", "tabpages", "terminal", "skiprtp",
NULL };
// Keep in sync with SWB_ flags in option_defs.h
// Keep in sync with SWB_ flags in option_vars.h
static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vsplit", "uselast",
NULL };
static char *(p_spk_values[]) = { "cursor", "screen", "topline", NULL };
static char *(p_tc_values[]) = { "followic", "ignore", "match", "followscs", "smart", NULL };
// Keep in sync with TCL_ flags in option_vars.h
static char *(p_tcl_values[]) = { "left", "uselast", NULL };
static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL };
// Note: Keep this in sync with check_opt_wim()
static char *(p_wim_values[]) = { "full", "longest", "list", "lastused", NULL };
@ -169,6 +171,7 @@ void didset_string_options(void)
opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true);
opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
opt_strings_flags(p_swb, p_swb_values, &swb_flags, true);
opt_strings_flags(p_tcl, p_tcl_values, &tcl_flags, true);
opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
}
@ -2207,6 +2210,21 @@ int expand_set_switchbuf(optexpand_T *args, int *numMatches, char ***matches)
matches);
}
/// The 'tabclose' option is changed.
const char *did_set_tabclose(optset_T *args FUNC_ATTR_UNUSED)
{
return did_set_opt_flags(p_tcl, p_tcl_values, &tcl_flags, true);
}
int expand_set_tabclose(optexpand_T *args, int *numMatches, char ***matches)
{
return expand_set_opt_string(args,
p_tcl_values,
ARRAY_SIZE(p_tcl_values) - 1,
numMatches,
matches);
}
/// The 'tabline' option is changed.
const char *did_set_tabline(optset_T *args)
{

View File

@ -3456,14 +3456,22 @@ static frame_T *win_altframe(win_T *win, tabpage_T *tp)
// Return the tabpage that will be used if the current one is closed.
static tabpage_T *alt_tabpage(void)
{
// Use the next tab page if possible.
if (curtab->tp_next != NULL) {
return curtab->tp_next;
// Use the last accessed tab page, if possible.
if ((tcl_flags & TCL_USELAST) && valid_tabpage(lastused_tabpage)) {
return lastused_tabpage;
}
// Find the last but one tab page.
// Use the previous tab page, if possible.
bool forward = curtab->tp_next != NULL
&& ((tcl_flags & TCL_LEFT) == 0 || curtab == first_tabpage);
tabpage_T *tp;
if (forward) {
tp = curtab->tp_next;
} else {
for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {}
}
return tp;
}

View File

@ -558,6 +558,9 @@ func Test_set_completion_string_values()
" call assert_equal('sync', getcompletion('set swapsync=', 'cmdline')[1])
call assert_equal('usetab', getcompletion('set switchbuf=', 'cmdline')[1])
call assert_equal('ignore', getcompletion('set tagcase=', 'cmdline')[1])
if exists('+tabclose')
call assert_equal('left uselast', join(sort(getcompletion('set tabclose=', 'cmdline'))), ' ')
endif
if exists('+termwintype')
call assert_equal('conpty', getcompletion('set termwintype=', 'cmdline')[1])
endif
@ -1377,9 +1380,10 @@ func Test_write()
new
call setline(1, ['L1'])
set nowrite
call assert_fails('write Xfile', 'E142:')
call assert_fails('write Xwrfile', 'E142:')
set write
close!
" close swapfile
bw!
endfunc
" Test for 'buftype' option

View File

@ -967,6 +967,64 @@ func Test_tabpage_alloc_failure()
call assert_equal(1, tabpagenr('$'))
endfunc
func Test_tabpage_tabclose()
" Default behaviour, move to the right.
call s:reconstruct_tabpage_for_test(6)
norm! 4gt
setl tcl=
tabclose
call assert_equal("n3", bufname())
" Move to the left.
call s:reconstruct_tabpage_for_test(6)
norm! 4gt
setl tcl=left
tabclose
call assert_equal("n1", bufname())
" Move to the last used tab page.
call s:reconstruct_tabpage_for_test(6)
norm! 5gt
norm! 2gt
setl tcl=uselast
tabclose
call assert_equal("n3", bufname())
" Same, but the last used tab page is invalid. Move to the right.
call s:reconstruct_tabpage_for_test(6)
norm! 5gt
norm! 3gt
setl tcl=uselast
tabclose 5
tabclose!
call assert_equal("n2", bufname())
" Same, but the last used tab page is invalid. Move to the left.
call s:reconstruct_tabpage_for_test(6)
norm! 5gt
norm! 3gt
setl tcl=uselast,left
tabclose 5
tabclose!
call assert_equal("n0", bufname())
" Move left when moving right is not possible.
call s:reconstruct_tabpage_for_test(6)
setl tcl=
norm! 6gt
tabclose
call assert_equal("n3", bufname())
" Move right when moving left is not possible.
call s:reconstruct_tabpage_for_test(6)
setl tcl=left
norm! 1gt
tabclose
call assert_equal("n0", bufname())
setl tcl&
endfunc
" this was giving ml_get errors
func Test_tabpage_last_line()
enew