Tab page workspace manager for Vim/Neovim.
Treat each tab page as a workspace and manage them by name. Filter, jump, sort, deduplicate, and move tabs — all with Vim regex pattern matching against buffer names.
Plug 'kis9a/tabset':TabKeep docs " Close everything except docs-related tabs
:TabJump api " Jump to a tab matching 'api' (interactive selection if multiple)
:TabSortByName " Sort all tabs alphabetically by label
:TabReject \.test\. " Close all test file tabs
:TabRestoreLast " Jump back to the tab you were just on (MRU)Every :Tab* command uses Vim regex to match against buffer names in each tab. The current tab is always protected from closure.
- Tabs multiply during multi-task work (issues, PRs, debugging, ...) --
:TabKeep authto keep only auth-related tabs and close the rest. - Same file opened in multiple tabs --
:TabDeduplicateremoves the duplicates automatically. - Jumping across many tabs --
:TabJump apishows interactive candidates with single-key selection.:TabRestoreLastreturns you to the previous tab (MRU history). - Reorganizing tab order --
:TabSortByNamealphabetizes.:TabMoveMatch README 0moves a specific tab to the first position.
Install with your preferred plugin manager.
" vim-plug
Plug 'kis9a/tabset'| Command | Description |
|---|---|
:TabKeep[!] {pattern} |
Close tabs NOT matching pattern. |
:TabReject[!] {pattern} |
Close tabs matching pattern. |
:TabDeduplicate[!] |
Remove duplicate tabs. |
! forces close even for unsaved buffers (:tabclose!). The current tab is never closed.
| Command | Description |
|---|---|
:TabSortByName[!] |
Sort tabs by label. ! = descending (Z-A). |
| Command | Description |
|---|---|
:TabJump {pattern} [key] |
Jump to tab matching pattern. Multiple matches show interactive key selection. |
:TabRestoreLast |
Jump back to last visited tab (MRU). |
| Command | Description |
|---|---|
:TabMove [{spec}] |
Move current tab. Spec: N (position), +N/-N (relative), +/- (by 1), empty (end). |
:TabMoveLeft [{count}] |
Move current tab left (default: 1). |
:TabMoveRight [{count}] |
Move current tab right (default: 1). |
:TabMoveMatch {pattern} {spec} [{key}] |
Move matching tab to position. |
All commands use Vim regular expressions to match against buffer names in each tab.
Two options control what the pattern is tested against:
Scope (g:tabset_match_scope) -- which buffers in a tab to consider:
| Value | Behavior |
|---|---|
'label' |
Match only the tab label (filename tail). |
'main' |
Match only the focused buffer. |
'any' (default) |
Match if any eligible buffer or the label matches. |
'all' |
Match only if all eligible buffers match. |
Target (g:tabset_match_target) -- which part of the buffer name to match:
| Value | Behavior |
|---|---|
'tail' |
Filename only (e.g., file.vim). |
'path' |
Full absolute path. |
'both' (default) |
Both tail and full path. |
:TabKeep ^docs/ " Keep tabs whose path starts with docs/
:TabReject \.test\. " Close tabs containing .test. in the name
:TabJump (api|client) " Jump to a tab matching api or client
:TabKeep \.vue$ " Keep only Vue component tabs
:TabReject ^__ " Close tabs starting with __ (e.g., __init__.py)Matching with scope and target:
" Match only the focused buffer's filename (ignore path)
let g:tabset_match_scope = 'main'
let g:tabset_match_target = 'tail'
:TabKeep config " Keeps tabs where the focused buffer name contains 'config'
" Match full path of any buffer in the tab
let g:tabset_match_scope = 'any'
let g:tabset_match_target = 'path'
:TabKeep /src/components/ " Keeps tabs that have any buffer under src/components/nnoremap <Leader>tk :TabKeep<Space>
nnoremap <Leader>tr :TabReject<Space>
nnoremap <Leader>td :TabDeduplicate<CR>
nnoremap <Leader>ts :TabSortByName<CR>
nnoremap <Leader>tj :TabJump<Space>
nnoremap <Leader>tl :TabRestoreLast<CR>
nnoremap <Leader>th :TabMoveLeft<CR>
nnoremap <Leader>tn :TabMoveRight<CR>g:tabset_enabled(default:1) -- Enable/disable plugin (commands become no-op when 0)g:tabset_match_scope(default:'any') -- Match scope:'label','main','any','all'g:tabset_match_target(default:'both') -- Match target:'tail','path','both'g:tabset_jump_keys(default:'asdfghjklqwertyuiopzxcvbnm') -- Keys for interactive jump selectiong:tabset_dedupe_mode(default:'main') -- Dedup key:'main'(focused buffer),'set'(all buffer paths),'visible'(visible buffers)g:tabset_dedupe_keep(default:'current') -- Which duplicate to keep:'current'or'leftmost'g:tabset_sort_case_sensitive(default:0) -- Case-sensitive sort when1g:tabset_confirm_bulk_close(default:1) -- Show confirmation dialog before bulk closeg:tabset_confirm_threshold(default:3) -- Number of tabs that triggers the bulk close confirmationg:tabset_close_error_policy(default:'stop') -- On close error:'stop'(halt) or'continue'(warn and proceed)g:tabset_label_func(default: built-in) -- Custom label function(tabnr) -> stringg:tabset_include_buftype(default:[]) -- Additional buffer types to include (eg,['help', 'quickfix'])g:tabset_include_unlisted(default:0) -- Include unlisted buffers in matchingg:tabset_include_nameless(default:0) -- Include nameless buffers in matching
tabset#keep(pattern, bang)-- TabKeeptabset#reject(pattern, bang)-- TabRejecttabset#deduplicate(bang)-- TabDeduplicatetabset#sort(desc)-- TabSortByNametabset#jump(pattern, key)-- TabJumptabset#restore_last()-- TabRestoreLasttabset#move(spec)-- TabMovetabset#move_match(pattern, spec, key)-- TabMoveMatchtabset#label(tabnr)-- Get label for tab number
If the pattern's last word is a single character, it is interpreted as a direct selection key, not part of the pattern.
:TabJump my project a " pattern='my project', key='a' (NOT pattern='my project a')Workarounds:
:TabJump my project a\> " Anchor makes 'a\>' a multi-char word
:TabJump my project [a] " Character class makes '[a]' a multi-char wordNo. :TabRestoreLast is an MRU history jump -- it switches to the tab you visited most recently, not a closed-tab restore. Once a tab is closed, it cannot be recovered by this plugin.
When g:tabset_confirm_bulk_close is 1 (default), closing 3 or more tabs at once (via :TabKeep, :TabReject, or :TabDeduplicate) triggers a confirmation dialog. Adjust the threshold with g:tabset_confirm_threshold:
let g:tabset_confirm_threshold = 5 " Confirm only when closing 5+ tabs
let g:tabset_confirm_bulk_close = 0 " Disable confirmation entirelyNo. Tabset has zero external dependencies (no fzf, rg, etc.). It works with Vim 8+ and Neovim 0.6+.
This project is licensed under the MIT License - see the LICENSE file for details.