Skip to content

kis9a/tabset

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tabset

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.

Quick Start

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.

Demo

When Is This Useful?

  • Tabs multiply during multi-task work (issues, PRs, debugging, ...) -- :TabKeep auth to keep only auth-related tabs and close the rest.
  • Same file opened in multiple tabs -- :TabDeduplicate removes the duplicates automatically.
  • Jumping across many tabs -- :TabJump api shows interactive candidates with single-key selection. :TabRestoreLast returns you to the previous tab (MRU history).
  • Reorganizing tab order -- :TabSortByName alphabetizes. :TabMoveMatch README 0 moves a specific tab to the first position.

Installation

Install with your preferred plugin manager.

" vim-plug
Plug 'kis9a/tabset'

Commands

Filtering

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.

Sorting

Command Description
:TabSortByName[!] Sort tabs by label. ! = descending (Z-A).

Navigation

Command Description
:TabJump {pattern} [key] Jump to tab matching pattern. Multiple matches show interactive key selection.
:TabRestoreLast Jump back to last visited tab (MRU).

Movement

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.

Pattern Matching

All commands use Vim regular expressions to match against buffer names in each tab.

What Gets Matched

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.

Pattern Examples

: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/

Configuration

Mappings

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>

Options

  • 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 selection
  • g: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 when 1
  • g:tabset_confirm_bulk_close (default: 1) -- Show confirmation dialog before bulk close
  • g:tabset_confirm_threshold (default: 3) -- Number of tabs that triggers the bulk close confirmation
  • g: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) -> string
  • g:tabset_include_buftype (default: []) -- Additional buffer types to include (eg, ['help', 'quickfix'])
  • g:tabset_include_unlisted (default: 0) -- Include unlisted buffers in matching
  • g:tabset_include_nameless (default: 0) -- Include nameless buffers in matching

Functions

  • tabset#keep(pattern, bang) -- TabKeep
  • tabset#reject(pattern, bang) -- TabReject
  • tabset#deduplicate(bang) -- TabDeduplicate
  • tabset#sort(desc) -- TabSortByName
  • tabset#jump(pattern, key) -- TabJump
  • tabset#restore_last() -- TabRestoreLast
  • tabset#move(spec) -- TabMove
  • tabset#move_match(pattern, spec, key) -- TabMoveMatch
  • tabset#label(tabnr) -- Get label for tab number

FAQ

The last character of my :TabJump pattern is being eaten as a selection key

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 word

Can :TabRestoreLast restore a closed tab?

No. :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.

How does bulk close confirmation work?

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 entirely

Does this plugin require external dependencies?

No. Tabset has zero external dependencies (no fzf, rg, etc.). It works with Vim 8+ and Neovim 0.6+.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Tab page workspace manager for Vim/Neovim

Resources

License

Stars

Watchers

Forks

Contributors