detached bfd66cc

refactor(content): trim named popup cache state

Drop cached popup IDs that are already available from the stored WebView. Keep the named popup reuse test aligned with the extra ID lookup in the reuse path.
commit
bfd66cc38db4713c89c23726efc213236896e114
author
brice · · 2026-04-11 10:25 UTC
parent
5dc11a5
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +5 -9
M internal/ui/coordinator/content/popup.go +4 -8
@@ -85,8 +85,6 @@ type namedPopupKey struct {
8585 }
8686
8787 type namedPopupState struct {
88- PaneID entity.PaneID
89- PopupID port.WebViewID
9088 WebView port.WebView
9189 }
9290
@@ -123,8 +121,6 @@ func (c *Coordinator) lookupReusableNamedPopup(parentPaneID entity.PaneID, frame
123121 func (c *Coordinator) storeReusableNamedPopup(
124122 parentPaneID entity.PaneID,
125123 frameName string,
126- paneID entity.PaneID,
127- popupID port.WebViewID,
128124 wv port.WebView,
129125 ) {
130126 if !isReusableNamedPopupFrame(frameName) || wv == nil {
@@ -137,7 +133,7 @@ func (c *Coordinator) storeReusableNamedPopup(
137133 if c.namedPopups == nil {
138134 c.namedPopups = make(map[namedPopupKey]*namedPopupState)
139135 }
140- c.namedPopups[key] = &namedPopupState{PaneID: paneID, PopupID: popupID, WebView: wv}
136+ c.namedPopups[key] = &namedPopupState{WebView: wv}
141137 c.popupMu.Unlock()
142138 }
143139
@@ -152,7 +148,7 @@ func (c *Coordinator) updatePendingPopupTarget(popupID port.WebViewID, targetURI
152148 func (c *Coordinator) clearReusableNamedPopupByWebViewID(popupID port.WebViewID) {
153149 c.popupMu.Lock()
154150 for key, state := range c.namedPopups {
155- if state != nil && state.PopupID == popupID {
151+ if state != nil && state.WebView != nil && state.WebView.ID() == popupID {
156152 delete(c.namedPopups, key)
157153 }
158154 }
@@ -306,7 +302,7 @@ func (c *Coordinator) handlePopupCreate(
306302
307303 parentID := parentWV.ID()
308304 if existing, ok := c.lookupReusableNamedPopup(parentPaneID, req.FrameName); ok {
309- c.updatePendingPopupTarget(existing.PopupID, req.TargetURI)
305+ c.updatePendingPopupTarget(existing.WebView.ID(), req.TargetURI)
310306 if err := existing.WebView.LoadURI(ctx, req.TargetURI); err != nil {
311307 log.Warn().Err(err).
312308 Str("target_uri", logging.TruncateURL(req.TargetURI, logURLMaxLen)).
@@ -374,7 +370,7 @@ func (c *Coordinator) handlePopupCreate(
374370
375371 // Register WebView in our map (after successful insertion)
376372 c.setWebViewLocked(paneID, popupWV)
377- c.storeReusableNamedPopup(parentPaneID, req.FrameName, paneID, popupID, popupWV)
373+ c.storeReusableNamedPopup(parentPaneID, req.FrameName, popupWV)
378374
379375 // Setup standard callbacks (after successful insertion to avoid leak)
380376 c.setupWebViewCallbacks(ctx, paneID, popupWV)
@@ -85,8 +85,6 @@ type namedPopupKey struct {
85 }85 }
86 86
87 type namedPopupState struct {87 type namedPopupState struct {
88- PaneID entity.PaneID
89- PopupID port.WebViewID
90 WebView port.WebView88 WebView port.WebView
91 }89 }
92 90
@@ -123,8 +121,6 @@ func (c *Coordinator) lookupReusableNamedPopup(parentPaneID entity.PaneID, frame
123 func (c *Coordinator) storeReusableNamedPopup(121 func (c *Coordinator) storeReusableNamedPopup(
124 parentPaneID entity.PaneID,122 parentPaneID entity.PaneID,
125 frameName string,123 frameName string,
126- paneID entity.PaneID,
127- popupID port.WebViewID,
128 wv port.WebView,124 wv port.WebView,
129 ) {125 ) {
130 if !isReusableNamedPopupFrame(frameName) || wv == nil {126 if !isReusableNamedPopupFrame(frameName) || wv == nil {
@@ -137,7 +133,7 @@ func (c *Coordinator) storeReusableNamedPopup(
137 if c.namedPopups == nil {133 if c.namedPopups == nil {
138 c.namedPopups = make(map[namedPopupKey]*namedPopupState)134 c.namedPopups = make(map[namedPopupKey]*namedPopupState)
139 }135 }
140- c.namedPopups[key] = &namedPopupState{PaneID: paneID, PopupID: popupID, WebView: wv}136+ c.namedPopups[key] = &namedPopupState{WebView: wv}
141 c.popupMu.Unlock()137 c.popupMu.Unlock()
142 }138 }
143 139
@@ -152,7 +148,7 @@ func (c *Coordinator) updatePendingPopupTarget(popupID port.WebViewID, targetURI
152 func (c *Coordinator) clearReusableNamedPopupByWebViewID(popupID port.WebViewID) {148 func (c *Coordinator) clearReusableNamedPopupByWebViewID(popupID port.WebViewID) {
153 c.popupMu.Lock()149 c.popupMu.Lock()
154 for key, state := range c.namedPopups {150 for key, state := range c.namedPopups {
155- if state != nil && state.PopupID == popupID {151+ if state != nil && state.WebView != nil && state.WebView.ID() == popupID {
156 delete(c.namedPopups, key)152 delete(c.namedPopups, key)
157 }153 }
158 }154 }
@@ -306,7 +302,7 @@ func (c *Coordinator) handlePopupCreate(
306 302
307 parentID := parentWV.ID()303 parentID := parentWV.ID()
308 if existing, ok := c.lookupReusableNamedPopup(parentPaneID, req.FrameName); ok {304 if existing, ok := c.lookupReusableNamedPopup(parentPaneID, req.FrameName); ok {
309- c.updatePendingPopupTarget(existing.PopupID, req.TargetURI)305+ c.updatePendingPopupTarget(existing.WebView.ID(), req.TargetURI)
310 if err := existing.WebView.LoadURI(ctx, req.TargetURI); err != nil {306 if err := existing.WebView.LoadURI(ctx, req.TargetURI); err != nil {
311 log.Warn().Err(err).307 log.Warn().Err(err).
312 Str("target_uri", logging.TruncateURL(req.TargetURI, logURLMaxLen)).308 Str("target_uri", logging.TruncateURL(req.TargetURI, logURLMaxLen)).
@@ -374,7 +370,7 @@ func (c *Coordinator) handlePopupCreate(
374 370
375 // Register WebView in our map (after successful insertion)371 // Register WebView in our map (after successful insertion)
376 c.setWebViewLocked(paneID, popupWV)372 c.setWebViewLocked(paneID, popupWV)
377- c.storeReusableNamedPopup(parentPaneID, req.FrameName, paneID, popupID, popupWV)373+ c.storeReusableNamedPopup(parentPaneID, req.FrameName, popupWV)
378 374
379 // Setup standard callbacks (after successful insertion to avoid leak)375 // Setup standard callbacks (after successful insertion to avoid leak)
380 c.setupWebViewCallbacks(ctx, paneID, popupWV)376 c.setupWebViewCallbacks(ctx, paneID, popupWV)
M internal/ui/coordinator/content/popup_test.go +1 -1
@@ -132,7 +132,7 @@ func TestHandlePopupCreate_ReusesNamedPopup(t *testing.T) {
132132 parentWV.EXPECT().ID().Return(port.WebViewID(101)).Twice()
133133
134134 popupWV := mocks.NewMockWebView(t)
135- popupWV.EXPECT().ID().Return(port.WebViewID(202)).Once()
135+ popupWV.EXPECT().ID().Return(port.WebViewID(202)).Twice()
136136 popupWV.EXPECT().Generation().Return(uint64(1)).Maybe()
137137 popupWV.EXPECT().SetCallbacks(mock.Anything).Maybe()
138138 popupWV.EXPECT().IsLoading().Return(false).Maybe()
@@ -132,7 +132,7 @@ func TestHandlePopupCreate_ReusesNamedPopup(t *testing.T) {
132 parentWV.EXPECT().ID().Return(port.WebViewID(101)).Twice()132 parentWV.EXPECT().ID().Return(port.WebViewID(101)).Twice()
133 133
134 popupWV := mocks.NewMockWebView(t)134 popupWV := mocks.NewMockWebView(t)
135- popupWV.EXPECT().ID().Return(port.WebViewID(202)).Once()135+ popupWV.EXPECT().ID().Return(port.WebViewID(202)).Twice()
136 popupWV.EXPECT().Generation().Return(uint64(1)).Maybe()136 popupWV.EXPECT().Generation().Return(uint64(1)).Maybe()
137 popupWV.EXPECT().SetCallbacks(mock.Anything).Maybe()137 popupWV.EXPECT().SetCallbacks(mock.Anything).Maybe()
138 popupWV.EXPECT().IsLoading().Return(false).Maybe()138 popupWV.EXPECT().IsLoading().Return(false).Maybe()

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