v0.28.0 3cb3770

engine.go RawHistoryFolder

1package webkit
2
3import (
4	"context"
5	"fmt"
6
7	"github.com/bnema/dumber/internal/application/port"
8	"github.com/bnema/dumber/internal/infrastructure/config"
9	"github.com/bnema/dumber/internal/infrastructure/filtering"
10	"github.com/rs/zerolog"
11)
12
13// Engine implements port.Engine for the WebKit browser engine.
14type Engine struct {
15	ctx           context.Context
16	wkCtx         *WebKitContext
17	settings      *SettingsManager
18	injector      *ContentInjector
19	messageRouter *MessageRouter
20	pool          *WebViewPool
21	factory       *WebViewFactory
22	filterManager *filtering.Manager
23	schemeHandler *DumbSchemeHandler
24	schemePath    string
25	logger        zerolog.Logger
26
27	// Handler registrars - injected at construction to avoid import cycles.
28	handlerRegistrar       func(ctx context.Context, router *MessageRouter, deps port.HandlerDependencies) error
29	accentHandlerRegistrar func(ctx context.Context, router *MessageRouter, handler port.AccentKeyHandler) error
30}
31
32// Compile-time check that Engine implements port.Engine.
33var _ port.Engine = (*Engine)(nil)
34
35// Factory returns the WebViewFactory wrapped as a port.WebViewFactory.
36func (e *Engine) Factory() port.WebViewFactory {
37	return &webViewFactoryAdapter{factory: e.factory}
38}
39
40// Pool returns the WebViewPool wrapped as a port.WebViewPool.
41func (e *Engine) Pool() port.WebViewPool {
42	return &webViewPoolAdapter{pool: e.pool, ctx: e.ctx}
43}
44
45// ContentInjector returns the ContentInjector implementing port.ContentInjector.
46func (e *Engine) ContentInjector() port.ContentInjector {
47	return e.injector
48}
49
50// InternalSchemePath returns the URI scheme used for internal app resources.
51func (e *Engine) InternalSchemePath() string {
52	return e.schemePath
53}
54
55// Close releases all resources held by the engine.
56func (e *Engine) Close() error {
57	if e.pool != nil {
58		e.pool.Close(e.ctx)
59	}
60	return nil
61}
62
63// SettingsApplier returns a port.SettingsApplier adapter for the SettingsManager.
64func (e *Engine) SettingsApplier() port.SettingsApplier {
65	return &settingsApplierAdapter{settings: e.settings}
66}
67
68// FilterApplier returns a port.FilterApplier adapter, or nil if filtering is disabled.
69func (e *Engine) FilterApplier() port.FilterApplier {
70	if e.filterManager == nil {
71		return nil
72	}
73	return &filterApplierAdapter{manager: e.filterManager}
74}
75
76// FaviconDatabase returns a port.FaviconDatabase adapter for async favicon lookups.
77func (e *Engine) FaviconDatabase() port.FaviconDatabase {
78	return &faviconDatabaseAdapter{wkCtx: e.wkCtx}
79}
80
81// InternalFilterManager returns the FilterManager for content filter lifecycle.
82// This is on the concrete *Engine type (not the port.Engine interface) because
83// FilterManager is a webkit-specific concern used only during dependency wiring.
84func (e *Engine) InternalFilterManager() port.FilterManager { return e.filterManager }
85
86// SetHandlerContext sets the base context for message handler dispatch.
87func (e *Engine) SetHandlerContext(ctx context.Context) {
88	if e.messageRouter != nil {
89		e.messageRouter.SetBaseContext(ctx)
90	}
91}
92
93// RegisterHandlers registers all WebUI message bridge handlers.
94func (e *Engine) RegisterHandlers(ctx context.Context, deps port.HandlerDependencies) error {
95	if e.messageRouter == nil {
96		return fmt.Errorf("message router not initialized")
97	}
98	if e.handlerRegistrar == nil {
99		return fmt.Errorf("handler registrar not configured")
100	}
101	return e.handlerRegistrar(ctx, e.messageRouter, deps)
102}
103
104// RegisterAccentHandlers registers accent/dead-key input handlers.
105func (e *Engine) RegisterAccentHandlers(ctx context.Context, handler port.AccentKeyHandler) error {
106	if e.messageRouter == nil {
107		return fmt.Errorf("message router not initialized")
108	}
109	if e.accentHandlerRegistrar == nil {
110		return fmt.Errorf("accent handler registrar not configured")
111	}
112	return e.accentHandlerRegistrar(ctx, e.messageRouter, handler)
113}
114
115// ConfigureDownloads sets up download handling.
116func (e *Engine) ConfigureDownloads(
117	ctx context.Context, downloadPath string,
118	eventHandler port.DownloadEventHandler, preparer port.DownloadPreparer,
119) error {
120	if e.wkCtx == nil {
121		return fmt.Errorf("webkit context not initialized")
122	}
123	handler := NewDownloadHandler(downloadPath, eventHandler, preparer)
124	e.wkCtx.SetDownloadHandler(ctx, handler)
125	return nil
126}
127
128// OnToolkitReady refreshes pooled WebViews after toolkit init.
129func (e *Engine) OnToolkitReady(ctx context.Context) error {
130	if e.pool != nil {
131		e.pool.RefreshScripts(ctx)
132	}
133	return nil
134}
135
136// UpdateAppearance updates default background color for pool and factory.
137func (e *Engine) UpdateAppearance(_ context.Context, r, g, b, alpha float64) error {
138	if e.pool != nil {
139		e.pool.SetBackgroundColor(float32(r), float32(g), float32(b), float32(alpha))
140	}
141	if e.factory != nil {
142		e.factory.SetBackgroundColor(float32(r), float32(g), float32(b), float32(alpha))
143	}
144	return nil
145}
146
147// UpdateSettings applies runtime config changes to engine settings.
148func (e *Engine) UpdateSettings(ctx context.Context, update port.EngineSettingsUpdate) error {
149	cfg, ok := update.Raw.(*config.Config)
150	if !ok {
151		return fmt.Errorf("UpdateSettings: expected *config.Config, got %T", update.Raw)
152	}
153	if e.settings != nil {
154		e.settings.UpdateFromConfig(ctx, cfg)
155	}
156	return nil
157}

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