Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions docs/adrs/002.tabs-vim.themes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@

## Decision

Expose mode colors via a single `g:tabs_vim_colors` dict. Each key is a lowercase mode name (`normal`, `insert`, `visual`, `replace`, `command`, `terminal`); each value is a four-element list `[guifg, guibg, ctermfg, ctermbg]`. Users may override any subset; omitted modes fall back to the built-in Dracula defaults. The dict is read once at plugin load after `colorscheme` is applied.
Expose all tab bar colors via a single `g:tabs_vim_colors` dict. Each key is a lowercase name; each value is a four-element list `[guifg, guibg, ctermfg, ctermbg]`. Users may override any subset; omitted keys fall back to the built-in Dracula defaults. The dict is read once at plugin load after `colorscheme` is applied.

**Mode color keys:** `normal`, `insert`, `visual`, `replace`, `command`, `terminal`
**Tab bar chrome keys:** `tabline` (`TabLine`), `tabline_sel` (`TabLineSel`), `tabline_fill` (`TabLineFill`)

The plugin applies all highlight groups — both its own `TabsVim_*` groups and the standard Vim `TabLine*` groups — so users need no separate `hi` declarations in their vimrc.
Comment thread
jesse23 marked this conversation as resolved.

## Context

Expand Down Expand Up @@ -42,7 +47,7 @@ tabs.vim sits between lightline (full palette control, many modes) and buftablin

## Consequences

- `g:tabs_vim_colors` is the single configuration point for all mode colors
- The plugin applies `hi` statements from the merged dict (user overrides + defaults) at load time
- If a user sets `TabsVim_*` highlight groups themselves *after* the plugin loads, those are respected as-is (plugin does not re-apply on colorscheme change in this phase)
- `g:tabs_vim_colors` is the single configuration point for all tab bar colors (mode pills and chrome)
- The plugin applies all `hi` statements from the merged dict (user overrides + defaults) at load time — no separate `hi TabLine*` declarations needed in the user's vimrc
- If a user sets `TabsVim_*` or `TabLine*` highlight groups themselves *after* the plugin loads, those are respected as-is (plugin does not re-apply on colorscheme change in this phase)
- Phase 4 (Polish) may add `ColorScheme` autocmd re-application, but that is out of scope here
51 changes: 31 additions & 20 deletions docs/specs/tabs.vim.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# tabs.vim

**Version:** 0.1.0
**Last Updated:** 2026-04-03
**Last Updated:** 2026-04-04
**Status:** Active Development

---
Expand Down Expand Up @@ -131,22 +131,31 @@ All keybindings are configurable. Users can disable features (e.g., if they don'
**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`.

**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.

### Color Configuration Contract

Mode colors are configurable via the `g:tabs_vim_colors` global dict. Each key is a lowercase mode name; each value is a four-element list `[guifg, guibg, ctermfg, ctermbg]`. Unspecified modes fall back to the built-in Dracula defaults. The dict is read once at plugin load time (after `colorscheme` is applied).
All tab bar colors are configurable via the `g:tabs_vim_colors` global dict. Each key is a lowercase name; each value is a four-element list `[guifg, guibg, ctermfg, ctermbg]`. Unspecified keys fall back to the built-in Dracula defaults. The dict is read once at plugin load time (after `colorscheme` is applied).

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.

Comment thread
jesse23 marked this conversation as resolved.
**Supported keys:** `normal`, `insert`, `visual`, `replace`, `command`, `terminal`
**Mode color keys:** `normal`, `insert`, `visual`, `replace`, `command`, `terminal`
**Tab bar chrome keys:** `tabline`, `tabline_sel`, `tabline_fill`

**Default (Dracula palette):**

```vim
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],
\ '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'],
\ }
```

Expand Down Expand Up @@ -200,17 +209,17 @@ let g:tabs_vim_colors = {

## Features

| Feature | Description | Status | ADR |
|---------|-------------|--------|-----|
| **Tab Navigation** | Switch to next/prev tab with `<Tab>` / `<S-Tab>` | | |
| **Direct Tab Jump** | Jump to tab 1-9 with `<leader>[1-9]` | | |
| **Tab Creation** | Create new tab with `<leader>wt`, via file picker with `<leader>ft` | | |
| **Tab Closing** | Close current tab or all but current with `<leader>x` / `<leader>X` | | |
| **Tab Appearance** | Dracula default theme; user-configurable colors via `g:tabs_vim_colors` | ⬜ | ADR-002 |
| **File Tree Integration** | Open files in tabs from Fern file browser (`t` key) | | |
| **Git Integration** | Open git-related output (diffs, logs) in tabs | ⬜ | — |
| **Terminal in Tabs** | Spawn terminal windows in new tabs (separate from splits) | ⬜ | — |
| **Which-Key Support** | Tab commands exposed in `<Space>` menu hierarchy | | |
| Feature | Description | ADR | Done? |
|---------|-------------|-----|-------|
| **Tab Navigation** | Switch to next/prev tab with `<Tab>` / `<S-Tab>` | | |
| **Direct Tab Jump** | Jump to tab 1-9 with `<leader>[1-9]` | | |
| **Tab Creation** | Create new tab with `<leader>wt`, via file picker with `<leader>ft` | | |
| **Tab Closing** | Close current tab or all but current with `<leader>x` / `<leader>X` | | |
| **Tab Appearance** | Dracula default theme; user-configurable colors via `g:tabs_vim_colors` | ADR-002 | ✅ |
| **Terminal in Tabs** | Toggle split terminals and spawn tab terminals (`<leader>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 | — | ⬜ |
| **Which-Key Support** | Tab commands exposed in `<Space>` menu hierarchy | | |

---

Expand All @@ -233,3 +242,5 @@ None yet.
| Date | Change |
|------|--------|
| 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 |
24 changes: 18 additions & 6 deletions plugin/tabs.vim
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,15 @@ endif
" MODE COLORS — override any mode via g:tabs_vim_colors (see docs/specs/tabs.vim.md)
" Each entry: [guifg, guibg, ctermfg, ctermbg]
let s:tabs_vim_defaults = {
\ '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],
\ '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'],
\ }

function! s:ApplyColors() abort
Expand All @@ -201,6 +204,15 @@ function! s:ApplyColors() abort
let l:n = (type(l:ov) == type([]) && len(l:ov) == 4) ? l:ov : s:tabs_vim_defaults['normal']
execute printf('hi TabsVim_Accent guifg=%s guibg=%s ctermfg=%s ctermbg=%s gui=bold cterm=bold',
\ l:n[0], l:n[1], l:n[2], l:n[3])
for [l:key, l:Group, l:bold] in [
\ ['tabline', 'TabLine', 'NONE'],
\ ['tabline_sel', 'TabLineSel', 'bold'],
\ ['tabline_fill', 'TabLineFill', 'NONE']]
Comment thread
jesse23 marked this conversation as resolved.
let l:ov = get(l:user, l:key, [])
let l:col = (type(l:ov) == type([]) && len(l:ov) == 4) ? l:ov : s:tabs_vim_defaults[l:key]
execute printf('hi %s guifg=%s guibg=%s ctermfg=%s ctermbg=%s gui=%s cterm=%s',
\ l:Group, l:col[0], l:col[1], l:col[2], l:col[3], l:bold, l:bold)
endfor
endfunction

call s:ApplyColors()
Expand Down
2 changes: 1 addition & 1 deletion skills-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"create-live-spec": {
"source": "./docs/skills/create-live-spec",
"sourceType": "local",
"computedHash": "9c83b94d12109ef8823e227b0e9e5d58a48eab636cee7da11a1b446098dcb474"
"computedHash": "36acce4b9f9e55a4427f547d151cf11705ccf011fb5ecb164b9b2327c73a8f54"
}
}
}
Loading