From 6512c66f90c43b8531394c550548e8d231515940 Mon Sep 17 00:00:00 2001 From: jesse23 Date: Sat, 4 Apr 2026 15:04:55 -0400 Subject: [PATCH 1/2] feat: add g:tabs_vim_mode_style enum to control mode display strategy Implements ADR-003: users can now choose between `all` (default), `tabs` (hide mode pill), or `mode` (fixed selected-tab color) via `g:tabs_vim_mode_style`. Co-Authored-By: Claude Sonnet 4.6 --- docs/adrs/003.tabs-vim.mode-style.md | 59 ++++++++++++++++++++++++++++ docs/specs/tabs.vim.md | 27 +++++++++++-- plugin/tabs.vim | 16 +++++++- 3 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 docs/adrs/003.tabs-vim.mode-style.md diff --git a/docs/adrs/003.tabs-vim.mode-style.md b/docs/adrs/003.tabs-vim.mode-style.md new file mode 100644 index 0000000..e42906f --- /dev/null +++ b/docs/adrs/003.tabs-vim.mode-style.md @@ -0,0 +1,59 @@ +# 003. Mode Style Strategy + +**SPEC:** tabs.vim +**Status:** Accepted +**Last Updated:** 2026-04-04 + +--- + +## Decision + +Add a new enum option `g:tabs_vim_mode_style` to control how mode information is presented in the tab bar. + +**Allowed values:** +- `all` *(default)* +- `tabs` +- `mode` + +`mode` is chosen as the concise mode-indicator-only value name. + +### Semantics + +| Value | Selected tab color | Top-right mode pill | +|-------|--------------------|----------------------| +| `all` | Mode-driven (`TabsVim_Sel*`) | Visible | +| `tabs` | Mode-driven (`TabsVim_Sel*`) | Hidden | +| `mode` | Fixed from `tabline_sel` | Visible | + +## Context + +Current behavior couples two signals: +1. selected-tab color changes with mode +2. top-right mode pill is shown + +Some users want only one of those signals depending on visual preference: +- Keep mode-aware selected-tab color but remove pill clutter (`tabs`) +- Keep pill but stabilize selected-tab color to the standard tab selection style (`mode`) + +The option must preserve existing visuals by default and avoid breaking current users. + +## Considered Options + +| Option | Pros | Cons | +|--------|------|------| +| **`all` / `tabs` / `mode` enum** *(chosen)* | Explicit, easy to reason about, backward-compatible default | Adds one more config axis | +| Boolean toggle (`show_mode_pill`) only | Very simple | Cannot express "mode-only" behavior | +| Two independent booleans (`show_mode_pill`, `mode_driven_selected_tab`) | Flexible | Invalid combinations and higher complexity | + +`full/tab/badge` and `notation` were considered, but `all/tabs/mode` are shorter and map directly to behavior. + +## Consequences + +- Backward compatibility: `all` remains the default and preserves current behavior. +- The color contract gains one additional interpretation rule: + - In `mode`, selected-tab color is taken from `tabline_sel`. +- Documentation and examples must show all three modes to reduce ambiguity. +- Fallback rules are explicit: + - Unknown `g:tabs_vim_mode_style` values fall back to `all`. + - Missing `g:tabs_vim_colors` keys use built-in defaults. +- Future extensions can add values without breaking existing configs. diff --git a/docs/specs/tabs.vim.md b/docs/specs/tabs.vim.md index 84d8e2e..99bbf06 100644 --- a/docs/specs/tabs.vim.md +++ b/docs/specs/tabs.vim.md @@ -129,7 +129,7 @@ Tabs plugin plays well with others (fzf, Fern, vim-fugitive). It doesn't reimple All keybindings are configurable. Users can disable features (e.g., if they don't use tabs) without source code changes. **4. Integrated Theming** -Dracula color scheme is the built-in default; tab bar includes mode indicator (Normal/Insert/Visual/Replace/Command/Terminal) with context-aware highlighting. Users may override any or all mode colors via `g:tabs_vim_colors`. +Dracula color scheme is the built-in default; the tab bar can show a mode pill (Normal/Insert/Visual/Replace/Command/Terminal) and can style the selected tab by mode, depending on `g:tabs_vim_mode_style`. Users may override any or all mode colors via `g:tabs_vim_colors`. **5. Vimrc Integration Boundary** The plugin owns all behavior it directly triggers. Integration with third-party plugins (vim-flog, vim-fugitive, diff buffers) — for example, binding `q` to `:tabclose` in their buffer types — is intentionally left to the user's vimrc. These bindings are tab-aware but depend on optional external plugins; pulling them into tabs.vim would introduce undeclared dependencies and couple the plugin to unrelated workflows. @@ -140,13 +140,32 @@ All tab bar colors are configurable via the `g:tabs_vim_colors` global dict. Eac The plugin owns the full tab bar and applies all highlight groups itself — no separate `hi TabLine*` declarations are needed in the user's vimrc. -In the plugin-managed tab bar, the selected tab is styled by the active mode color via mode-specific selected-tab groups (`TabsVim_SelNormal`, `TabsVim_SelInsert`, etc.). Changing `normal`, `insert`, `visual`, `replace`, `command`, or `terminal` therefore changes selected-tab appearance for that mode. +In `all` and `tabs` mode, the selected tab is styled by the active mode color via mode-specific selected-tab groups (`TabsVim_SelNormal`, `TabsVim_SelInsert`, etc.). In `mode`, selected-tab styling comes from `tabline_sel` instead. Changing `normal`, `insert`, `visual`, `replace`, `command`, or `terminal` therefore changes selected-tab appearance in `all` and `tabs` mode. -`tabline`, `tabline_sel`, and `tabline_fill` map to Vim's standard `TabLine`, `TabLineSel`, and `TabLineFill` groups. `tabline_sel` is retained for compatibility/interoperability with non-plugin or default tabline contexts, but it does not control selected-tab styling inside `TabsVim_Line()`. +`tabline`, `tabline_sel`, and `tabline_fill` map to Vim's standard `TabLine`, `TabLineSel`, and `TabLineFill` groups. `tabline_sel` does not control selected-tab styling in `all` or `tabs` mode; in `mode` mode, `tabline_sel` is the selected-tab style source. **Mode color keys:** `normal`, `insert`, `visual`, `replace`, `command`, `terminal` **Tab bar chrome keys:** `tabline`, `tabline_sel`, `tabline_fill` +### Mode Style Contract + +Mode style is controlled by `g:tabs_vim_mode_style`. + +```vim +" default +let g:tabs_vim_mode_style = 'all' +``` + +Allowed values: + +| Value | Behavior | +|-------|----------| +| `all` | Current behavior: selected-tab color is mode-driven and top-right mode pill is shown | +| `tabs` | Mode-driven selected-tab color remains, but top-right mode pill is hidden | +| `mode` | Top-right mode pill is shown; selected-tab color is fixed to `tabline_sel` | + +Unknown values should fall back to `all` for backward compatibility. + **Default (Dracula palette):** ```vim @@ -220,6 +239,7 @@ let g:tabs_vim_colors = { | **Tab Creation** | Create new tab with `wt`, via file picker with `ft` | — | ✅ | | **Tab Closing** | Close current tab or all but current with `x` / `X` | — | ✅ | | **Tab Appearance** | Dracula default theme; user-configurable colors via `g:tabs_vim_colors` | ADR-002 | ✅ | +| **Mode Style Variants** | `g:tabs_vim_mode_style` supports `all` / `tabs` / `mode` display strategies | ADR-003 | ⬜ | | **Terminal in Tabs** | Toggle split terminals and spawn tab terminals (`h/ts/tv/tt`) | — | ✅ | | **File Tree Integration** | Open files in tabs from Fern file browser (`t` key) | — | ⬜ | | **Git Integration** | Open git-related output (diffs, logs) in tabs | — | ⬜ | @@ -248,3 +268,4 @@ None yet. | 2026-04-03 | Initial SPEC: navigation, creation, theming | | 2026-04-04 | Extend color config: plugin now owns TabLine/TabLineSel/TabLineFill via `tabline`, `tabline_sel`, `tabline_fill` keys | | 2026-04-04 | Add Vimrc Integration Boundary pattern; mark completed features; align Features table to template | +| 2026-04-04 | Rename to `g:tabs_vim_mode_style` enum (`all` / `tabs` / `mode`) with `all` as default | diff --git a/plugin/tabs.vim b/plugin/tabs.vim index 1dcf118..e6949e8 100644 --- a/plugin/tabs.vim +++ b/plugin/tabs.vim @@ -243,8 +243,18 @@ function! TabsVim_ModeHl() abort endif endfunction +function! TabsVim_ModeStyle() abort + let l:style = get(g:, 'tabs_vim_mode_style', 'all') + if index(['all', 'tabs', 'mode'], l:style) < 0 + return 'all' + endif + return l:style +endfunction + function! TabsVim_Line() abort let l:hls = TabsVim_ModeHl() " [pill_hl, sel_tab_hl] + let l:style = TabsVim_ModeStyle() + let l:sel_hl = l:style ==# 'mode' ? '%#TabLineSel#' : l:hls[1] " ── Left: tabs (%NT = native Vim click-to-switch + drag) let s = '' for t in range(1, tabpagenr('$')) @@ -253,14 +263,16 @@ function! TabsVim_Line() abort let name = bufname(buf) let name = empty(name) ? '[No Name]' : fnamemodify(name, ':t') let mod = getbufvar(buf, '&modified') ? ' *' : '' - let s .= t == tabpagenr() ? l:hls[1] : '%#TabLine#' + let s .= t == tabpagenr() ? l:sel_hl : '%#TabLine#' let s .= '%' . t . 'T' let s .= ' ' . t . ' ' . name . mod . ' ' if t < tabpagenr('$') | let s .= '%#TabLineFill#│' | endif endfor " ── Right: mode block ─────────────────────────────────────────────────────── - let s .= '%T%=' . l:hls[0] . ' ' . TabsVim_ModeName() . ' ' + if l:style !=# 'tabs' + let s .= '%T%=' . l:hls[0] . ' ' . TabsVim_ModeName() . ' ' + endif return s endfunction From fb6c91e6bdaa395cbd7a111eadd049b13cca4c0e Mon Sep 17 00:00:00 2001 From: jesse23 Date: Sat, 4 Apr 2026 15:23:44 -0400 Subject: [PATCH 2/2] docs: add vim help file and update README with full configuration reference Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/release.yml | 2 +- README.md | 66 ++++++++++---- doc/tabs.vim.txt | 158 ++++++++++++++++++++++++++++++++++ doc/tags | 13 +++ 4 files changed, 223 insertions(+), 16 deletions(-) create mode 100644 doc/tabs.vim.txt create mode 100644 doc/tags diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de76560..6920852 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: git rm -rf . --quiet # Restore plugin files from dev - git checkout dev -- plugin/ README.md LICENSE + git checkout dev -- plugin/ doc/ README.md LICENSE # Only commit if there are changes if git diff --cached --quiet; then diff --git a/README.md b/README.md index e28e8fc..87c6571 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ # tabs.vim -A lightweight Vim plugin that replaces the tabline with a clean mode-aware bar: tabs on the left, current mode pill on the right. Also provides terminal toggles, tab/window management, and file-drop support. +A lightweight Vim plugin that replaces the native tabline with a clean, mode-aware bar: numbered tabs on the left, a color-coded mode pill on the right. Also handles split terminals, tab/window management, and file-drop support. + +## Requirements + +- Vim 8.2+ or Neovim 0.7+ +- Optional: [junegunn/fzf.vim](https://github.com/junegunn/fzf.vim) for file-picker integration ## Installation @@ -8,32 +13,63 @@ A lightweight Vim plugin that replaces the tabline with a clean mode-aware bar: Plug 'jesse23/tabs.vim' ``` -## Features - -**Tabline** — always-visible bar showing open tabs (with modified indicator `*`) and a color-coded mode pill (Normal / Insert / Visual / Replace / Command / Terminal). +## Keybindings **Tab navigation** - `` / `` — next / previous tab - `1`–`9` — jump to tab by number -- `wt` — new tab -- `x` / `X` — close window / close all other tabs -**Split terminals** -- `h` / `ts` — toggle horizontal split terminal (15 lines) -- `tv` — toggle vertical split terminal (80 cols) -- `tt` — open terminal in a new tab -- `` — enter terminal mode; `` or `` — exit terminal mode +**Tab management** +- `wt` — new empty tab +- `ft` — open file in new tab via fzf +- `x` / `X` — close window / close all other tabs +- `gF` — open file under cursor in new tab -**Window & buffer ops** +**Splits & windows** - `ws` / `wv` — horizontal / vertical split - `wm` — maximize (close other windows) + +**Buffer ops** - `wr` — rename current buffer - `fy` — copy file path to clipboard -- `gF` — open file under cursor in new tab -**File drop** — drag a file from Finder onto the terminal; it opens in a new tab (requires bracketed-paste support, e.g. iTerm2). +**Terminals** +- `h` / `ts` — toggle horizontal split terminal (15 lines) +- `tv` — toggle vertical split terminal (80 cols) +- `tt` — open terminal in new tab +- `` — enter terminal mode; `` or `` — exit + +**File drop** — drag a file from Finder onto the terminal to open it in a new tab (requires bracketed-paste, e.g. iTerm2). + +## Configuration + +### Mode style + +Controls what the tabline shows: + +```vim +" all — mode-driven selected tab + mode pill (default) +" tabs — mode-driven selected tab, no pill +" mode — mode pill, fixed selected-tab color +let g:tabs_vim_mode_style = 'all' +``` + +### Colors + +Override any color via `g:tabs_vim_colors`. Each value is `[guifg, guibg, ctermfg, ctermbg]`: + +```vim +" Partial override — unspecified keys keep Dracula defaults +let g:tabs_vim_colors = { + \ 'normal': ['#282828', '#d79921', 235, 172], + \ 'insert': ['#282828', '#b8bb26', 235, 142], +\ } +``` + +Mode keys: `normal`, `insert`, `visual`, `replace`, `command`, `terminal` +Chrome keys: `tabline`, `tabline_sel`, `tabline_fill` -**FZF integration** — `ft` opens a file in a new tab via fzf (requires `junegunn/fzf.vim`). +See `:help tabs.vim` for the full reference. ## License diff --git a/doc/tabs.vim.txt b/doc/tabs.vim.txt new file mode 100644 index 0000000..2001781 --- /dev/null +++ b/doc/tabs.vim.txt @@ -0,0 +1,158 @@ +*tabs.vim.txt* Mode-aware tabline with tab/terminal management + +============================================================================== +CONTENTS *tabs.vim-contents* + + 1. Introduction ......................... |tabs.vim-intro| + 2. Requirements ......................... |tabs.vim-requirements| + 3. Installation ......................... |tabs.vim-installation| + 4. Tabline .............................. |tabs.vim-tabline| + 5. Keybindings .......................... |tabs.vim-keybindings| + 6. Configuration ........................ |tabs.vim-config| + 6.1 Mode Style ....................... |tabs.vim-mode-style| + 6.2 Colors ........................... |tabs.vim-colors| + 7. License .............................. |tabs.vim-license| + +============================================================================== +1. Introduction *tabs.vim-intro* + +tabs.vim replaces Vim's native tabline with a clean, mode-aware bar: open +tabs on the left, a color-coded mode pill on the right. It also provides +keybindings for tab/window management, split terminals, and file-drop support. + +============================================================================== +2. Requirements *tabs.vim-requirements* + +- Vim 8.2+ or Neovim 0.7+ +- Optional: junegunn/fzf.vim (for |ft|) + +============================================================================== +3. Installation *tabs.vim-installation* + +With vim-plug: > + Plug 'jesse23/tabs.vim' +< +With lazy.nvim: > + { 'jesse23/tabs.vim' } +< +============================================================================== +4. Tabline *tabs.vim-tabline* + +The tabline shows: +- Left side: numbered open tabs; active tab highlighted by current mode color; + modified buffers marked with ` *` +- Right side: mode pill showing the current Vim mode (when enabled) + +Mode labels~ + N Normal + I Insert + V Visual / V·LINE / V·BLOCK + R Replace + C Command + T Terminal + +============================================================================== +5. Keybindings *tabs.vim-keybindings* + +Tab navigation~ + Next tab + Previous tab + 1-9 Jump to tab 1–9 + +Tab management~ + wt New empty tab + ft Open file in new tab via fzf (requires fzf.vim) + x Close window (or toggle terminal; quit prompt if last window) + X Close all tabs except current + gF Open file under cursor in new tab + +Window splits~ + ws Horizontal split + wv Vertical split + wm Maximize (close other windows) + +Buffer operations~ + wr Rename current buffer + fy Copy full file path to clipboard + +Terminal~ + h Toggle horizontal split terminal (15 lines) + ts Toggle horizontal split terminal (alias) + tv Toggle vertical split terminal (80 cols) + tt Open terminal in new tab + Enter terminal mode (normal→terminal) + / Exit terminal mode + +File drop~ + Drag a file from Finder/Explorer onto the terminal — it opens in a new tab. + Requires bracketed-paste support (e.g. iTerm2). + +============================================================================== +6. Configuration *tabs.vim-config* + +------------------------------------------------------------------------------ +6.1 Mode Style *tabs.vim-mode-style* + *g:tabs_vim_mode_style* + +Controls how mode information is presented in the tab bar. + +Default: `'all'` > + let g:tabs_vim_mode_style = 'all' +< +Values: + + `all` Selected-tab color is mode-driven; mode pill is shown. (default) + `tabs` Selected-tab color is mode-driven; mode pill is hidden. + `mode` Mode pill is shown; selected-tab color is fixed to |TabLineSel|. + +Unknown values fall back to `'all'`. + +------------------------------------------------------------------------------ +6.2 Colors *tabs.vim-colors* + *g:tabs_vim_colors* + +Override any tab bar color via a dict. Each value is a four-element list: > + [guifg, guibg, ctermfg, ctermbg] +< +Mode color keys (affect mode pill and, in `all`/`tabs` style, selected tab): + `normal` Normal mode + `insert` Insert mode + `visual` Visual mode + `replace` Replace mode + `command` Command mode + `terminal` Terminal mode + +Tab bar chrome keys: + `tabline` Inactive tabs and separators (→ |TabLine|) + `tabline_sel` Standard tab selection; selected-tab in `mode` style (→ |TabLineSel|) + `tabline_fill` Empty tabline fill area (→ |TabLineFill|) + +The plugin owns all TabLine* highlight groups — no separate `hi TabLine*` +declarations are needed in your vimrc. + +Full override example (Dracula defaults): > + let g:tabs_vim_colors = { + \ 'normal': ['#282a36', '#bd93f9', 235, 141], + \ 'insert': ['#282a36', '#50fa7b', 235, 84 ], + \ 'visual': ['#282a36', '#ffb86c', 235, 215], + \ 'replace': ['#282a36', '#ff5555', 235, 203], + \ 'command': ['#282a36', '#bd93f9', 235, 141], + \ 'terminal': ['#282a36', '#8be9fd', 235, 117], + \ 'tabline': ['#6272a4', 'NONE', 61, 'NONE'], + \ 'tabline_sel': ['#bd93f9', 'NONE', 141, 'NONE'], + \ 'tabline_fill': ['#6272a4', 'NONE', 61, 'NONE'], + \ } +< +Partial override (only change some modes; rest keep Dracula defaults): > + let g:tabs_vim_colors = { + \ 'normal': ['#282828', '#d79921', 235, 172], + \ 'insert': ['#282828', '#b8bb26', 235, 142], + \ } +< +============================================================================== +7. License *tabs.vim-license* + +MIT License. See LICENSE in the repository root. + +============================================================================== +vim:tw=78:ts=8:ft=help:norl: diff --git a/doc/tags b/doc/tags new file mode 100644 index 0000000..122f60d --- /dev/null +++ b/doc/tags @@ -0,0 +1,13 @@ +g:tabs_vim_colors tabs.vim.txt /*g:tabs_vim_colors* +g:tabs_vim_mode_style tabs.vim.txt /*g:tabs_vim_mode_style* +tabs.vim-colors tabs.vim.txt /*tabs.vim-colors* +tabs.vim-config tabs.vim.txt /*tabs.vim-config* +tabs.vim-contents tabs.vim.txt /*tabs.vim-contents* +tabs.vim-installation tabs.vim.txt /*tabs.vim-installation* +tabs.vim-intro tabs.vim.txt /*tabs.vim-intro* +tabs.vim-keybindings tabs.vim.txt /*tabs.vim-keybindings* +tabs.vim-license tabs.vim.txt /*tabs.vim-license* +tabs.vim-mode-style tabs.vim.txt /*tabs.vim-mode-style* +tabs.vim-requirements tabs.vim.txt /*tabs.vim-requirements* +tabs.vim-tabline tabs.vim.txt /*tabs.vim-tabline* +tabs.vim.txt tabs.vim.txt /*tabs.vim.txt*