v0.28.0 3cb3770

webview.go RawHistoryFolder

1// Package port defines application-layer interfaces for external capabilities.
2// Ports abstract infrastructure concerns, allowing the application layer to
3// remain independent of specific implementations (WebKit, GTK, etc.).
4package port
5
6import (
7	"context"
8)
9
10// WebViewID uniquely identifies a WebView instance.
11type WebViewID uint64
12
13// LoadEvent represents page load state transitions.
14type LoadEvent int
15
16const (
17	// LoadStarted indicates navigation has begun.
18	LoadStarted LoadEvent = iota
19	// LoadRedirected indicates a redirect occurred.
20	LoadRedirected
21	// LoadCommitted indicates content is being received.
22	LoadCommitted
23	// LoadFinished indicates the page has fully loaded.
24	LoadFinished
25)
26
27// String returns a human-readable representation of the load event.
28func (e LoadEvent) String() string {
29	switch e {
30	case LoadStarted:
31		return "started"
32	case LoadRedirected:
33		return "redirected"
34	case LoadCommitted:
35		return "committed"
36	case LoadFinished:
37		return "finished"
38	default:
39		return "unknown"
40	}
41}
42
43// WebViewState represents a snapshot of the current WebView state.
44// This is an immutable struct that can be safely passed between components.
45type WebViewState struct {
46	URI       string
47	Title     string
48	IsLoading bool
49	Progress  float64 // 0.0 to 1.0
50	CanGoBack bool
51	CanGoFwd  bool
52	ZoomLevel float64
53}
54
55// WebProcessTerminationReason describes why the web process terminated.
56type WebProcessTerminationReason int
57
58const (
59	WebProcessTerminationUnknown WebProcessTerminationReason = iota
60	WebProcessTerminationCrashed
61	WebProcessTerminationExceededMemory
62	WebProcessTerminationByAPI
63)
64
65// PopupRequest contains metadata about a popup window request.
66type PopupRequest struct {
67	TargetURI     string
68	FrameName     string // e.g., "_blank", custom name, or empty
69	IsUserGesture bool
70	ParentViewID  WebViewID
71}
72
73// Texture represents a graphics texture returned by the engine.
74// GoPointer returns a native toolkit pointer (e.g. *gdk.Texture in GTK engines).
75// Engine implementations are responsible for the concrete type.
76type Texture interface {
77	GoPointer() uintptr
78}
79
80// WebViewCallbacks defines callback handlers for WebView events.
81// Implementations should invoke these on the main thread/goroutine.
82type WebViewCallbacks struct {
83	// OnLoadChanged is called when load state changes.
84	OnLoadChanged func(event LoadEvent)
85	// OnTitleChanged is called when the page title changes.
86	OnTitleChanged func(title string)
87	// OnURIChanged is called when the URI changes.
88	OnURIChanged func(uri string)
89	// OnProgressChanged is called during page load with progress 0.0-1.0.
90	OnProgressChanged func(progress float64)
91	// OnFaviconChanged is called when the page favicon changes.
92	// The parameter is a *gdk.Texture (passed as Texture interface to avoid GTK import in port layer).
93	OnFaviconChanged func(favicon Texture)
94	// OnClose is called when the WebView requests to close.
95	OnClose func()
96	// OnCreate is called when a popup window is requested.
97	// Return a WebView to allow the popup, or nil to block it.
98	OnCreate func(request PopupRequest) WebView
99	// OnReadyToShow is called when a popup WebView is ready to display.
100	OnReadyToShow func()
101	// OnLinkHover is called when hovering over a link, image, or media element.
102	// The uri parameter contains the target URL, or empty string when leaving.
103	OnLinkHover func(uri string)
104	// OnWebProcessTerminated is called when the web process exits unexpectedly.
105	OnWebProcessTerminated func(reason WebProcessTerminationReason, reasonLabel string, uri string)
106
107	// OnPermissionRequest is called when a site requests permission (mic, camera, screen sharing).
108	// Return true to indicate the request was handled. Call allow()/deny() to respond.
109	// The permission types are passed as strings ("microphone", "camera", "display", etc.).
110	// The metadata map carries permission-type-specific context; for website_data_access both
111	// entity.PermissionMetadataKeyRequestingDomain and entity.PermissionMetadataKeyCurrentDomain must be populated.
112	OnPermissionRequest func(origin string, permTypes []string, metadata map[string]string, allow, deny func()) bool
113
114	// OnLinkMiddleClick is called when a link is middle-clicked.
115	// Return true if handled (blocks default navigation).
116	OnLinkMiddleClick func(uri string) bool
117
118	// OnEnterFullscreen is called when the WebView requests fullscreen mode.
119	// Return true to prevent fullscreen.
120	OnEnterFullscreen func() bool
121
122	// OnLeaveFullscreen is called when the WebView exits fullscreen mode.
123	// Return true to prevent leaving fullscreen.
124	OnLeaveFullscreen func() bool
125
126	// OnAudioStateChanged is called when audio playback starts or stops.
127	OnAudioStateChanged func(playing bool)
128}
129
130// FindOptions configures search behavior.
131type FindOptions struct {
132	CaseInsensitive bool
133	AtWordStarts    bool
134	WrapAround      bool
135}
136
137// FindController abstracts WebKit's FindController for clean architecture.
138type FindController interface {
139	Search(text string, options FindOptions, maxMatches uint)
140	CountMatches(text string, options FindOptions, maxMatches uint)
141	SearchNext()
142	SearchPrevious()
143	SearchFinish()
144	GetSearchText() string
145
146	// Signal connections
147	OnFoundText(callback func(matchCount uint)) uint
148	OnFailedToFindText(callback func()) uint
149	OnCountedMatches(callback func(matchCount uint)) uint
150	DisconnectSignal(id uint)
151}
152
153// WebView defines the port interface for browser view operations.
154// This interface abstracts the underlying browser engine (WebKit, etc.)
155// and exposes only the navigation and state capabilities needed by
156// the application layer.
157type WebView interface {
158	// ID returns the unique identifier for this WebView.
159	ID() WebViewID
160
161	// --- Navigation ---
162
163	// LoadURI navigates to the specified URI.
164	LoadURI(ctx context.Context, uri string) error
165
166	// LoadHTML loads HTML content with an optional base URI for relative links.
167	LoadHTML(ctx context.Context, content, baseURI string) error
168
169	// Reload reloads the current page.
170	Reload(ctx context.Context) error
171
172	// ReloadBypassCache reloads the current page, bypassing cache.
173	ReloadBypassCache(ctx context.Context) error
174
175	// Stop stops the current page load.
176	Stop(ctx context.Context) error
177
178	// GoBack navigates back in history.
179	// Uses WebKit native navigation if available, falls back to JavaScript history.back() for SPA compatibility.
180	GoBack(ctx context.Context) error
181
182	// GoForward navigates forward in history.
183	// Uses WebKit native navigation if available, falls back to JavaScript history.forward() for SPA compatibility.
184	GoForward(ctx context.Context) error
185
186	// --- State Queries ---
187
188	// State returns the current WebView state as a snapshot.
189	State() WebViewState
190
191	// URI returns the current URI.
192	URI() string
193
194	// Title returns the current page title.
195	Title() string
196
197	// IsLoading returns true if a page is currently loading.
198	IsLoading() bool
199
200	// EstimatedProgress returns the load progress (0.0 to 1.0).
201	EstimatedProgress() float64
202
203	// CanGoBack returns true if back navigation is available.
204	CanGoBack() bool
205
206	// CanGoForward returns true if forward navigation is available.
207	CanGoForward() bool
208
209	// --- Zoom ---
210
211	// SetZoomLevel sets the zoom level (1.0 = 100%).
212	SetZoomLevel(ctx context.Context, level float64) error
213
214	// GetZoomLevel returns the current zoom level.
215	GetZoomLevel() float64
216
217	// --- Find ---
218
219	// GetFindController returns the find controller for text search.
220	// Returns nil if find is not supported.
221	GetFindController() FindController
222
223	// --- Callbacks ---
224
225	// SetCallbacks registers callback handlers for WebView events.
226	// Pass nil to clear all callbacks.
227	SetCallbacks(callbacks *WebViewCallbacks)
228
229	// --- Appearance ---
230
231	// RunJavaScript executes a script in the main world. Fire-and-forget.
232	RunJavaScript(ctx context.Context, script string)
233
234	// SetBackgroundColor sets the background color shown before content paints (0.0-1.0 RGBA).
235	SetBackgroundColor(r, g, b, a float64)
236
237	// ResetBackgroundToDefault resets the background to white (browser default).
238	ResetBackgroundToDefault()
239
240	// --- Favicon ---
241
242	// Favicon returns the current page favicon, or nil if unavailable.
243	Favicon() Texture
244
245	// Generation returns a monotonic counter incremented on pool reuse.
246	// Used to detect stale callbacks after a WebView is recycled.
247	Generation() uint64
248
249	// --- Media/Fullscreen State ---
250
251	// IsFullscreen returns true if the WebView is currently in fullscreen mode.
252	IsFullscreen() bool
253
254	// IsPlayingAudio returns true if the WebView is currently playing audio.
255	IsPlayingAudio() bool
256
257	// --- Lifecycle ---
258
259	// IsDestroyed returns true if the WebView has been destroyed.
260	IsDestroyed() bool
261
262	// Destroy releases all resources associated with this WebView.
263	// After calling Destroy, the WebView should not be used.
264	Destroy()
265}
266
267// WebViewPool defines the port interface for WebView pooling.
268// Pools maintain pre-created WebViews for fast tab creation.
269type WebViewPool interface {
270	// Acquire obtains a WebView from the pool or creates a new one.
271	// The context can be used for cancellation.
272	Acquire(ctx context.Context) (WebView, error)
273
274	// Release returns a WebView to the pool for reuse.
275	// The WebView will be reset to a blank state.
276	// If the pool is full, the WebView will be destroyed.
277	Release(wv WebView)
278
279	// Prewarm creates WebViews synchronously to populate the pool.
280	// Pass count <= 0 to use the default prewarm count.
281	Prewarm(count int)
282
283	// PrewarmAsync schedules WebView creation on the toolkit idle loop,
284	// avoiding blocking startup while still warming up WebViews.
285	// Pass count <= 0 to use the default prewarm count.
286	PrewarmAsync(ctx context.Context, count int)
287
288	// Size returns the current number of available WebViews in the pool.
289	Size() int
290
291	// Close shuts down the pool and destroys all pooled WebViews.
292	Close()
293}
294
295// WebViewFactory creates new WebView instances.
296// This is used when direct WebView creation is needed without pooling.
297type WebViewFactory interface {
298	// Create creates a new WebView instance.
299	Create(ctx context.Context) (WebView, error)
300
301	// CreateRelated creates a WebView that shares session/cookies with parent.
302	// This is required for popup windows to maintain authentication state.
303	// Popup WebViews bypass the pool since they must be related to a specific parent.
304	CreateRelated(ctx context.Context, parentID WebViewID) (WebView, error)
305}
306
307// DevToolsOpener is an optional capability for WebViews that support developer tools.
308type DevToolsOpener interface {
309	OpenDevTools()
310}
311
312// Printer is an optional capability for WebViews that support printing.
313type Printer interface {
314	PrintPage()
315}
316
317// PopupCapable is implemented by WebViews that support popup lifecycle callbacks.
318// SetOnClose composes the provided function with any existing close handler so
319// that multiple callers can each register a close callback without overwriting
320// one another.
321type PopupCapable interface {
322	SetOnReadyToShow(fn func())
323	SetOnClose(fn func())
324	Show()
325}
326
327// OAuthCallbackCapable is implemented by WebViews that support OAuth auto-close callbacks.
328// It is an optional capability; callers should type-assert port.WebView to this interface
329// before use and degrade gracefully when it is absent.
330type OAuthCallbackCapable interface {
331	// AddCloseCallback registers fn to be called when the WebView is programmatically closed.
332	// Multiple callbacks may be registered; each will be called in registration order.
333	AddCloseCallback(fn func())
334	// AddNavigationCallback registers fn to be called whenever the URI changes or a
335	// committed load is detected. The uri parameter contains the new URL.
336	// Multiple callbacks may be registered; each will be called in registration order.
337	AddNavigationCallback(fn func(uri string))
338	// Close triggers a programmatic close of the WebView (equivalent to window.close()).
339	Close()
340}
341
342// TextInputTargetProvider is an optional capability for WebViews that support
343// text input method integration.
344type TextInputTargetProvider interface {
345	TextInputTarget() TextInputTarget
346}

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