detached 1e06425

fix: clear stale previous tab ids per window

Validate per-window previous tab ids before Alt+Tab uses them.
commit
1e06425d829aec6dc90c1b3c780317d756fc994f
author
brice · · 2026-04-28 18:38 UTC
parent
cccb5fe
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +22 -3
M internal/ui/app.go +22 -3
@@ -511,6 +511,19 @@ func (a *App) browserWindowForTab(tabID entity.TabID) *browserWindow {
511511 return a.browserWindowForMainWindow(a.mainWindow)
512512 }
513513
514+func (a *App) browserWindowHasLiveTab(bw *browserWindow, tabID entity.TabID) bool {
515+ if a == nil || a.tabs == nil || bw == nil || tabID == "" {
516+ return false
517+ }
518+ if a.tabs.Find(tabID) == nil {
519+ return false
520+ }
521+ if a.windowForTab[tabID] != bw {
522+ return false
523+ }
524+ return true
525+}
526+
514527 func (a *App) tabCountForBrowserWindow(bw *browserWindow) int {
515528 if a.tabs == nil || bw == nil {
516529 return 0
@@ -2168,10 +2181,16 @@ func (a *App) initTabCoordinator(ctx context.Context) {
21682181 })
21692182 // Wire per-window previous active tab ID provider for scoped Alt+Tab switching
21702183 a.tabCoord.SetPreviousActiveTabIDProvider(func(mainWindow *window.MainWindow) entity.TabID {
2171- if bw := a.browserWindowForMainWindow(mainWindow); bw != nil {
2172- return bw.prevActiveTabID
2184+ bw := a.browserWindowForMainWindow(mainWindow)
2185+ if bw == nil {
2186+ return ""
21732187 }
2174- return ""
2188+ prevID := bw.prevActiveTabID
2189+ if !a.browserWindowHasLiveTab(bw, prevID) {
2190+ bw.prevActiveTabID = ""
2191+ return ""
2192+ }
2193+ return prevID
21752194 })
21762195 a.tabCoord.SetOnCurrentWindowEmpty(func(ctx context.Context, mainWindow *window.MainWindow) {
21772196 bw := a.browserWindowForMainWindow(mainWindow)
@@ -511,6 +511,19 @@ func (a *App) browserWindowForTab(tabID entity.TabID) *browserWindow {
511 return a.browserWindowForMainWindow(a.mainWindow)511 return a.browserWindowForMainWindow(a.mainWindow)
512 }512 }
513 513
514+func (a *App) browserWindowHasLiveTab(bw *browserWindow, tabID entity.TabID) bool {
515+ if a == nil || a.tabs == nil || bw == nil || tabID == "" {
516+ return false
517+ }
518+ if a.tabs.Find(tabID) == nil {
519+ return false
520+ }
521+ if a.windowForTab[tabID] != bw {
522+ return false
523+ }
524+ return true
525+}
526+
514 func (a *App) tabCountForBrowserWindow(bw *browserWindow) int {527 func (a *App) tabCountForBrowserWindow(bw *browserWindow) int {
515 if a.tabs == nil || bw == nil {528 if a.tabs == nil || bw == nil {
516 return 0529 return 0
@@ -2168,10 +2181,16 @@ func (a *App) initTabCoordinator(ctx context.Context) {
2168 })2181 })
2169 // Wire per-window previous active tab ID provider for scoped Alt+Tab switching2182 // Wire per-window previous active tab ID provider for scoped Alt+Tab switching
2170 a.tabCoord.SetPreviousActiveTabIDProvider(func(mainWindow *window.MainWindow) entity.TabID {2183 a.tabCoord.SetPreviousActiveTabIDProvider(func(mainWindow *window.MainWindow) entity.TabID {
2171- if bw := a.browserWindowForMainWindow(mainWindow); bw != nil {2184+ bw := a.browserWindowForMainWindow(mainWindow)
2172- return bw.prevActiveTabID2185+ if bw == nil {
2186+ return ""
2173 }2187 }
2174- return ""2188+ prevID := bw.prevActiveTabID
2189+ if !a.browserWindowHasLiveTab(bw, prevID) {
2190+ bw.prevActiveTabID = ""
2191+ return ""
2192+ }
2193+ return prevID
2175 })2194 })
2176 a.tabCoord.SetOnCurrentWindowEmpty(func(ctx context.Context, mainWindow *window.MainWindow) {2195 a.tabCoord.SetOnCurrentWindowEmpty(func(ctx context.Context, mainWindow *window.MainWindow) {
2177 bw := a.browserWindowForMainWindow(mainWindow)2196 bw := a.browserWindowForMainWindow(mainWindow)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close