Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(tui): pin tab + auto-follow new downloads#438

Merged
SuperCoolPencil merged 7 commits into
mainfrom
fix/issue-431-tab-switching
May 10, 2026
Merged

feat(tui): pin tab + auto-follow new downloads#438
SuperCoolPencil merged 7 commits into
mainfrom
fix/issue-431-tab-switching

Conversation

@SuperCoolPencil
Copy link
Copy Markdown
Member

@SuperCoolPencil SuperCoolPencil commented May 10, 2026

Closes #431

Summary

Adds a pin tab feature to the TUI and implements auto-follow for new downloads initiated from the browser extension.

Pin Tab

  • Press ctrl+tab to pin/unpin the currently active tab
  • A 📌 icon appears in the tab bar to indicate the pinned state
  • While a tab is pinned, the TUI will not automatically switch away — even when downloads complete or new ones arrive
  • Pressing ctrl+tabagain on the same tab unpins it; a log entry confirms the action

Auto-follow New Downloads (when unpinned)

UX Design Rationale

Automatic switching alone would be disruptive to users browsing history or other tabs. The pin feature gives users explicit control: pin a tab to stay there, unpin to let the TUI follow activity.

Greptile Summary

Adds a pin tab feature (t to toggle) and auto-follow for downloads started or queued from the browser extension. When unpinned, the TUI automatically navigates to the newly active tab by setting SelectedDownloadID before calling UpdateListItems; a new started bool field on DownloadModel ensures downloads appear in TabActive immediately after the engine confirms start, before any progress events arrive.

  • pinnedTab int (-1 = none) is added to RootModel; all tab-switch paths and auto-follow logic check this field before redirecting.
  • renderTabs is promoted from a package-level function to a RootModel method so it can read pinnedTab to decorate the label with a indicator.
  • Four new tests in follow_test.go cover brand-new download auto-follow, existing-download restart, pin suppression, and Queued→Active transition; the DownloadQueuedMsg auto-follow path remains untested.

Confidence Score: 5/5

Safe to merge; the pin and auto-follow logic is straightforward and well-contained within the TUI layer.

All tab-switch paths consistently gate on pinnedTab, started is correctly initialised for every server-status case, and the core auto-follow flow is exercised by the new tests. The one open item — pinnedGuard logging a spurious message when the user presses the shortcut for a tab they are already on — is cosmetic and does not affect correctness or data.

No files require special attention beyond the minor guard-log behaviour in update_dashboard.go.

Important Files Changed

Filename Overview
internal/tui/components/tab_bar.go Adds Pinned bool to Tab and prepends when set; applied to both RenderTabBar and RenderNumberedTabBar. Safe change.
internal/tui/follow_test.go New test file covering auto-follow for brand-new downloads, existing restarts, pin suppression, and Queued→Active transitions. The DownloadQueuedMsg auto-follow path (update_events.go:280) has no coverage here.
internal/tui/keys.go Adds PinTab (t) and PrevTab (left) bindings; removes j/k vim shortcuts (intentional per thread reply, closes #430). Full-help rows updated.
internal/tui/list.go Auto-follow tab switch now gated on m.pinnedTab == -1; adds d.started to tab-classification conditions.
internal/tui/model.go Introduces started bool on DownloadModel and pinnedTab int (default -1) on RootModel; started correctly initialised for all server-status cases.
internal/tui/process.go Wraps the optimistic tab switch to TabQueued in a pinnedTab == -1 guard so pinned users are not redirected when they add a download.
internal/tui/update_dashboard.go Adds pinnedGuard closure and PinTab / PrevTab handlers. Guard fires a log entry even when the user presses the shortcut for the already-active pinned tab, producing spurious noise.
internal/tui/update_events.go Sets d.started = true and m.SelectedDownloadID before UpdateListItems for DownloadStartedMsg (both existing and new). Also adds SelectedDownloadID for DownloadQueuedMsg. The queued-path auto-follow is untested.
internal/tui/update_test.go Existing test updated to initialise pinnedTab: -1 so the optimistic-ID merge test continues to pass.
internal/tui/view.go Converts renderTabs from a package-level function to a RootModel method so it can access m.pinnedTab for the tab label; clean refactor.
internal/tui/view_dashboard_list.go Single call-site update from renderTabs(...) to m.renderTabs(...) following the view.go refactor.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
internal/tui/update_dashboard.go:58-65
**Spurious pin-guard log when already on the pinned tab**

`pinnedGuard` fires unconditionally before each `switchTab` call, including when the user presses the shortcut for the tab they are *already on*. If TabQueued is pinned and the user presses `q`, the guard logs "Tab is pinned — press t to unpin" even though the tab would not have changed anyway. With repeated key presses the log fills up with noise, and the message is misleading since nothing was actually blocked. The guard should only fire when the requested tab differs from `m.activeTab`.

Reviews (4): Last reviewed commit: "fix(tui): address auto-follow edge cases..." | Re-trigger Greptile

- Add pinnedTab field to RootModel to track which tab is pinned (-1 = none)
- Press ctrl+tab to toggle pin on the active tab; a 📌 icon appears in the tab bar
- When a tab is pinned, automatic tab switching is suppressed — the UI stays put
- When no tab is pinned, the TUI now auto-follows new downloads started from
  the browser extension (sets SelectedDownloadID on DownloadStarted/Queued events)
- Update Tab component to accept a Pinned field and render the pin icon
- Add PinTab key binding to dashboard help view

Closes #431
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 10, 2026

Binary Size Analysis

⚠️ Size Increased

Version Human Readable Raw Bytes
Main 19.77 MB 20726052
PR 19.91 MB 20881700
Difference 152.00 KB 155648

ctrl+tab is consumed by the terminal emulator and never reaches the TUI.
Use 't' (toggle) as the pin key instead — consistent with single-key
binding style used throughout the dashboard (q/w/e, p, r, x, etc.).
- Left/right arrows now switch tabs (prev/next); tab key retained for next
- Remove vim j/k navigation bindings (closes #430)
- Fix: pin tab now fully overrides ALL tab switches including:
  - Downloads started via 'a' key (startDownload in process.go)
  - Browser extension downloads (update_events.go)
  - Download completion follow-through (list.go)
Comment thread internal/tui/keys.go
Comment thread internal/tui/update_dashboard.go
Comment thread internal/tui/update_events.go
Comment thread internal/tui/list.go
Comment thread internal/tui/keys.go
Comment on lines 238 to 253
Up: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("\u2191/k", "up"),
key.WithKeys("up"),
key.WithHelp("\u2191", "up"),
),
Down: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("\u2193/j", "down"),
key.WithKeys("down"),
key.WithHelp("\u2193", "down"),
),
LogUp: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("\u2191/k", "scroll up"),
key.WithKeys("up"),
key.WithHelp("", "scroll up"),
),
LogDown: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("\u2193/j", "scroll down"),
key.WithKeys("down"),
key.WithHelp("", "scroll down"),
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Vim-style j/k navigation was removed from four key maps (Dashboard Up/Down, LogUp/LogDown, Settings Up/Down, CategoryManager Up/Down) with no replacement. Neither PinTab ("t") nor PrevTab ("left") conflicts with these keys, so the removal is unrelated to this feature and silently breaks navigation for users who rely on vim-style keys. This change should either be reverted or shipped in a separate PR.

Suggested change
Up: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("\u2191/k", "up"),
key.WithKeys("up"),
key.WithHelp("\u2191", "up"),
),
Down: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("\u2193/j", "down"),
key.WithKeys("down"),
key.WithHelp("\u2193", "down"),
),
LogUp: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("\u2191/k", "scroll up"),
key.WithKeys("up"),
key.WithHelp("↑", "scroll up"),
),
LogDown: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("\u2193/j", "scroll down"),
key.WithKeys("down"),
key.WithHelp("↓", "scroll down"),
),
Up: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("↑/k", "up"),
),
Down: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("↓/j", "down"),
),
LogUp: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("↑/k", "scroll up"),
),
LogDown: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("↓/j", "scroll down"),
),

Rule Used: What: Flag commits that bundle unnecessary changes... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/tui/keys.go
Line: 238-253

Comment:
Vim-style `j`/`k` navigation was removed from four key maps (Dashboard Up/Down, LogUp/LogDown, Settings Up/Down, CategoryManager Up/Down) with no replacement. Neither `PinTab` (`"t"`) nor `PrevTab` (`"left"`) conflicts with these keys, so the removal is unrelated to this feature and silently breaks navigation for users who rely on vim-style keys. This change should either be reverted or shipped in a separate PR.

```suggestion
		Up: key.NewBinding(
			key.WithKeys("up", "k"),
			key.WithHelp("↑/k", "up"),
		),
		Down: key.NewBinding(
			key.WithKeys("down", "j"),
			key.WithHelp("↓/j", "down"),
		),
		LogUp: key.NewBinding(
			key.WithKeys("up", "k"),
			key.WithHelp("↑/k", "scroll up"),
		),
		LogDown: key.NewBinding(
			key.WithKeys("down", "j"),
			key.WithHelp("↓/j", "scroll down"),
		),
```

**Rule Used:** What: Flag commits that bundle unnecessary changes... ([source](https://app.greptile.com/review/custom-context?memory=74a28159-60fc-4201-a661-331594ebaf90))

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is intentional.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

closes #430

When a tab is pinned, pressing q/w/e, left/right, or tab now logs
'◆ Tab is pinned — press t to unpin' instead of switching tabs.
@SuperCoolPencil SuperCoolPencil merged commit 4061deb into main May 10, 2026
16 checks passed
@SuperCoolPencil SuperCoolPencil deleted the fix/issue-431-tab-switching branch May 10, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Set "Active" tab to selected when a download starts J and K trigger navigation rather than typing when in Categories editor

1 participant