patch 9.1.0572: cannot specify tab page closing behaviour

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

fixes: #5967
closes: #15204

Signed-off-by: LemonBoy <thatlemon@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
index 8cca2b9..7674714 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -144,6 +144,7 @@
       \ 'splitkeep': [['cursor', 'screen', 'topline'], ['xxx']],
       \ 'swapsync': [['', 'sync', 'fsync'], ['xxx']],
       \ 'switchbuf': [['', 'useopen', 'split,newtab'], ['xxx']],
+      \ 'tabclose': [['', 'left', 'left,uselast'], ['xxx']],
       \ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']],
       \ 'term': [[], []],
       \ 'termguicolors': [[], []],
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index fbfbaae..02f5d7e 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -548,6 +548,9 @@
   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
@@ -1407,7 +1410,8 @@
   set nowrite
   call assert_fails('write Xwrfile', 'E142:')
   set write
-  close!
+  " close swapfile
+  bw!
 endfunc
 
 " Test for 'buftype' option
diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim
index 3624790..1a40567 100644
--- a/src/testdir/test_tabpage.vim
+++ b/src/testdir/test_tabpage.vim
@@ -965,6 +965,64 @@
   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