detached 751112c

feat(history): persist page titles via ContentCoordinator callback

commit
751112c6e8f0f10d7d1eb7538604d08985ac837c
author
brice · · 2025-12-16 18:24 UTC
parent
6a3405f
signature
unsigned
2 files · +23 -0
M internal/ui/app.go +5 -0
@@ -294,6 +294,11 @@ func (a *App) initCoordinators(ctx context.Context) {
294294 a.contentCoord,
295295 )
296296
297+ // Wire title updates to history persistence
298+ a.contentCoord.SetOnTitleUpdated(func(ctx context.Context, paneID entity.PaneID, url, title string) {
299+ a.navCoord.UpdateHistoryTitle(ctx, paneID, url, title)
300+ })
301+
297302 // 5. Keyboard Dispatcher
298303 a.kbDispatcher = dispatcher.NewKeyboardDispatcher(
299304 ctx,
@@ -294,6 +294,11 @@ func (a *App) initCoordinators(ctx context.Context) {
294 a.contentCoord,294 a.contentCoord,
295 )295 )
296 296
297+ // Wire title updates to history persistence
298+ a.contentCoord.SetOnTitleUpdated(func(ctx context.Context, paneID entity.PaneID, url, title string) {
299+ a.navCoord.UpdateHistoryTitle(ctx, paneID, url, title)
300+ })
301+
297 // 5. Keyboard Dispatcher302 // 5. Keyboard Dispatcher
298 a.kbDispatcher = dispatcher.NewKeyboardDispatcher(303 a.kbDispatcher = dispatcher.NewKeyboardDispatcher(
299 ctx,304 ctx,
M internal/ui/coordinator/content.go +18 -0
@@ -31,6 +31,9 @@ type ContentCoordinator struct {
3131
3232 // Callback to get active workspace state (avoids circular dependency)
3333 getActiveWS func() (*entity.Workspace, *component.WorkspaceView)
34+
35+ // Callback when title changes (for history persistence)
36+ onTitleUpdated func(ctx context.Context, paneID entity.PaneID, url, title string)
3437 }
3538
3639 // NewContentCoordinator creates a new ContentCoordinator.
@@ -55,6 +58,11 @@ func NewContentCoordinator(
5558 }
5659 }
5760
61+// SetOnTitleUpdated sets the callback for title changes (for history persistence).
62+func (c *ContentCoordinator) SetOnTitleUpdated(fn func(ctx context.Context, paneID entity.PaneID, url, title string)) {
63+ c.onTitleUpdated = fn
64+}
65+
5866 // EnsureWebView acquires or reuses a WebView for the given pane.
5967 func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.PaneID) (*webkit.WebView, error) {
6068 log := logging.FromContext(ctx)
@@ -231,6 +239,16 @@ func (c *ContentCoordinator) onTitleChanged(ctx context.Context, paneID entity.P
231239 }
232240 }
233241
242+ // Notify history persistence (get URL from WebView)
243+ if c.onTitleUpdated != nil {
244+ if wv := c.webViews[paneID]; wv != nil {
245+ url := wv.URI()
246+ if url != "" && title != "" {
247+ c.onTitleUpdated(ctx, paneID, url, title)
248+ }
249+ }
250+ }
251+
234252 log.Debug().
235253 Str("pane_id", string(paneID)).
236254 Str("title", title).
@@ -31,6 +31,9 @@ type ContentCoordinator struct {
31 31
32 // Callback to get active workspace state (avoids circular dependency)32 // Callback to get active workspace state (avoids circular dependency)
33 getActiveWS func() (*entity.Workspace, *component.WorkspaceView)33 getActiveWS func() (*entity.Workspace, *component.WorkspaceView)
34+
35+ // Callback when title changes (for history persistence)
36+ onTitleUpdated func(ctx context.Context, paneID entity.PaneID, url, title string)
34 }37 }
35 38
36 // NewContentCoordinator creates a new ContentCoordinator.39 // NewContentCoordinator creates a new ContentCoordinator.
@@ -55,6 +58,11 @@ func NewContentCoordinator(
55 }58 }
56 }59 }
57 60
61+// SetOnTitleUpdated sets the callback for title changes (for history persistence).
62+func (c *ContentCoordinator) SetOnTitleUpdated(fn func(ctx context.Context, paneID entity.PaneID, url, title string)) {
63+ c.onTitleUpdated = fn
64+}
65+
58 // EnsureWebView acquires or reuses a WebView for the given pane.66 // EnsureWebView acquires or reuses a WebView for the given pane.
59 func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.PaneID) (*webkit.WebView, error) {67 func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.PaneID) (*webkit.WebView, error) {
60 log := logging.FromContext(ctx)68 log := logging.FromContext(ctx)
@@ -231,6 +239,16 @@ func (c *ContentCoordinator) onTitleChanged(ctx context.Context, paneID entity.P
231 }239 }
232 }240 }
233 241
242+ // Notify history persistence (get URL from WebView)
243+ if c.onTitleUpdated != nil {
244+ if wv := c.webViews[paneID]; wv != nil {
245+ url := wv.URI()
246+ if url != "" && title != "" {
247+ c.onTitleUpdated(ctx, paneID, url, title)
248+ }
249+ }
250+ }
251+
234 log.Debug().252 log.Debug().
235 Str("pane_id", string(paneID)).253 Str("pane_id", string(paneID)).
236 Str("title", title).254 Str("title", title).

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