detached 71664a3

fix: init missing maps in NewCoordinator, log GoBack error, safe test assertion

- Initialize pendingScriptRefresh and pendingThemePanes maps in
  NewCoordinator to prevent nil-map panics on write
- Log error from wv.GoBack() in external URL handler instead of discarding
- Use checked type assertion in migrate_engine_test.go to avoid panic
commit
71664a35b35cabdd1932787641924505b2eb4563
author
brice · · 2026-03-15 19:40 UTC
parent
ac967b8
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +22 -15
M internal/infrastructure/config/migrate_engine_test.go +4 -1
@@ -276,6 +276,9 @@ show_fps = true
276276 err = toml.Unmarshal(data, &raw)
277277 require.NoError(t, err)
278278
279- engine := raw["engine"].(map[string]any)
279+ engineAny, ok := raw["engine"]
280+ require.True(t, ok, "raw[\"engine\"] should exist")
281+ engine, ok := engineAny.(map[string]any)
282+ require.True(t, ok, "raw[\"engine\"] should be map[string]any, got %T", engineAny)
280283 assert.Equal(t, "webkit", engine["type"], "engine.type should default to webkit")
281284 }
@@ -276,6 +276,9 @@ show_fps = true
276 err = toml.Unmarshal(data, &raw)276 err = toml.Unmarshal(data, &raw)
277 require.NoError(t, err)277 require.NoError(t, err)
278 278
279- engine := raw["engine"].(map[string]any)279+ engineAny, ok := raw["engine"]
280+ require.True(t, ok, "raw[\"engine\"] should exist")
281+ engine, ok := engineAny.(map[string]any)
282+ require.True(t, ok, "raw[\"engine\"] should be map[string]any, got %T", engineAny)
280 assert.Equal(t, "webkit", engine["type"], "engine.type should default to webkit")283 assert.Equal(t, "webkit", engine["type"], "engine.type should default to webkit")
281 }284 }
M internal/ui/coordinator/content/coordinator.go +15 -13
@@ -144,19 +144,21 @@ func NewCoordinator(
144144 log.Debug().Msg("creating content coordinator")
145145
146146 return &Coordinator{
147- pool: pool,
148- widgetFactory: widgetFactory,
149- faviconAdapter: faviconAdapter,
150- zoomUC: zoomUC,
151- permissionUC: permissionUC,
152- webViews: make(map[entity.PaneID]port.WebView),
153- paneTitles: make(map[entity.PaneID]string),
154- navOrigins: make(map[entity.PaneID]string),
155- pendingReveal: make(map[entity.PaneID]bool),
156- getActiveWS: getActiveWS,
157- pendingPopups: make(map[port.WebViewID]*PendingPopup),
158- popupOAuth: make(map[port.WebViewID]*popupOAuthState),
159- popupRefresh: make(map[entity.PaneID]*time.Timer),
147+ pool: pool,
148+ widgetFactory: widgetFactory,
149+ faviconAdapter: faviconAdapter,
150+ zoomUC: zoomUC,
151+ permissionUC: permissionUC,
152+ webViews: make(map[entity.PaneID]port.WebView),
153+ paneTitles: make(map[entity.PaneID]string),
154+ navOrigins: make(map[entity.PaneID]string),
155+ pendingReveal: make(map[entity.PaneID]bool),
156+ pendingScriptRefresh: make(map[entity.PaneID]bool),
157+ pendingThemePanes: make(map[entity.PaneID]bool),
158+ getActiveWS: getActiveWS,
159+ pendingPopups: make(map[port.WebViewID]*PendingPopup),
160+ popupOAuth: make(map[port.WebViewID]*popupOAuthState),
161+ popupRefresh: make(map[entity.PaneID]*time.Timer),
160162 }
161163 }
162164
@@ -144,19 +144,21 @@ func NewCoordinator(
144 log.Debug().Msg("creating content coordinator")144 log.Debug().Msg("creating content coordinator")
145 145
146 return &Coordinator{146 return &Coordinator{
147- pool: pool,147+ pool: pool,
148- widgetFactory: widgetFactory,148+ widgetFactory: widgetFactory,
149- faviconAdapter: faviconAdapter,149+ faviconAdapter: faviconAdapter,
150- zoomUC: zoomUC,150+ zoomUC: zoomUC,
151- permissionUC: permissionUC,151+ permissionUC: permissionUC,
152- webViews: make(map[entity.PaneID]port.WebView),152+ webViews: make(map[entity.PaneID]port.WebView),
153- paneTitles: make(map[entity.PaneID]string),153+ paneTitles: make(map[entity.PaneID]string),
154- navOrigins: make(map[entity.PaneID]string),154+ navOrigins: make(map[entity.PaneID]string),
155- pendingReveal: make(map[entity.PaneID]bool),155+ pendingReveal: make(map[entity.PaneID]bool),
156- getActiveWS: getActiveWS,156+ pendingScriptRefresh: make(map[entity.PaneID]bool),
157- pendingPopups: make(map[port.WebViewID]*PendingPopup),157+ pendingThemePanes: make(map[entity.PaneID]bool),
158- popupOAuth: make(map[port.WebViewID]*popupOAuthState),158+ getActiveWS: getActiveWS,
159- popupRefresh: make(map[entity.PaneID]*time.Timer),159+ pendingPopups: make(map[port.WebViewID]*PendingPopup),
160+ popupOAuth: make(map[port.WebViewID]*popupOAuthState),
161+ popupRefresh: make(map[entity.PaneID]*time.Timer),
160 }162 }
161 }163 }
162 164
M internal/ui/coordinator/content/navigation.go +3 -1
@@ -327,7 +327,9 @@ func (c *Coordinator) handleURIChanged(ctx context.Context, paneID entity.PaneID
327327
328328 // Navigate back to avoid stale URI in omnibox/history
329329 if wv.CanGoBack() {
330- _ = wv.GoBack(ctx)
330+ if err := wv.GoBack(ctx); err != nil {
331+ log.Warn().Str("pane_id", string(paneID)).Err(err).Msg("GoBack after external URL")
332+ }
331333 }
332334 return
333335 }
@@ -327,7 +327,9 @@ func (c *Coordinator) handleURIChanged(ctx context.Context, paneID entity.PaneID
327 327
328 // Navigate back to avoid stale URI in omnibox/history328 // Navigate back to avoid stale URI in omnibox/history
329 if wv.CanGoBack() {329 if wv.CanGoBack() {
330- _ = wv.GoBack(ctx)330+ if err := wv.GoBack(ctx); err != nil {
331+ log.Warn().Str("pane_id", string(paneID)).Err(err).Msg("GoBack after external URL")
332+ }
331 }333 }
332 return334 return
333 }335 }

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