v0.9.0 636c44c

webview.go RawHistoryFolder

1//go:build !webkit_cgo
2
3package webkit
4
5import (
6	"fmt"
7	"log"
8	"strconv"
9	"sync/atomic"
10	"unsafe"
11)
12
13// Package-level ID counter for stub WebViews
14var stubViewIDCounter uint64
15
16// nextStubViewID generates a unique ID for stub WebViews
17func nextStubViewID() uintptr {
18	return uintptr(atomic.AddUint64(&stubViewIDCounter, 1))
19}
20
21// WebView represents a browser view powered by WebKit2GTK.
22// Methods are currently stubs returning ErrNotImplemented to satisfy TDD ordering.
23type WebView struct {
24	config       *Config
25	visible      bool
26	zoom         float64
27	url          string
28	destroyed    bool
29	window       *Window
30	msgHandler   func(payload string)
31	titleHandler func(title string)
32	uriHandler   func(uri string)
33	zoomHandler  func(level float64)
34	popupHandler func(string) *WebView
35	closeHandler func()
36	useDomZoom   bool
37	domZoomSeed  float64
38	container    uintptr
39	id           uintptr // WebView unique identifier
40
41	// Window type fields (no-op in stub)
42	windowType         WindowType
43	windowFeatures     *WindowFeatures
44	windowTypeCallback func(WindowType, *WindowFeatures)
45}
46
47// NewWebView constructs a new WebView instance.
48func NewWebView(cfg *Config) (*WebView, error) {
49	if cfg == nil {
50		cfg = &Config{}
51	}
52	log.Printf("[webkit] NewWebView (non-CGO stub) — UI will not be displayed. Build with -tags=webkit_cgo for native window.")
53	wv := &WebView{config: cfg, useDomZoom: cfg.UseDomZoom}
54	if cfg.ZoomDefault <= 0 {
55		wv.zoom = 1.0
56	} else {
57		wv.zoom = cfg.ZoomDefault
58	}
59	wv.domZoomSeed = wv.zoom
60	wv.id = nextStubViewID() // Assign unique ID
61	// Construction succeeds; create a logical window placeholder.
62	wv.window = &Window{Title: "Dumber Browser"}
63	wv.container = newWidgetHandle()
64	return wv, nil
65}
66
67// NewWebViewWithRelated creates a new WebView related to an existing one (non-CGO stub)
68func NewWebViewWithRelated(cfg *Config, relatedView *WebView) (*WebView, error) {
69	// In non-CGO build, just create a regular WebView
70	return NewWebView(cfg)
71}
72
73// LoadURL navigates the webview to the specified URL.
74func (w *WebView) LoadURL(rawURL string) error {
75	if w == nil || w.destroyed {
76		return ErrNotImplemented
77	}
78	if rawURL == "" {
79		return fmt.Errorf("url cannot be empty")
80	}
81	// Minimal validation; actual navigation handled by CGO bridge later.
82	w.url = rawURL
83	log.Printf("[webkit] LoadURL (non-CGO stub): %s", rawURL)
84	return nil
85}
86
87// Show makes the WebView visible.
88func (w *WebView) Show() error {
89	if w == nil || w.destroyed {
90		return ErrNotImplemented
91	}
92	w.visible = true
93	log.Printf("[webkit] Show (non-CGO stub): no native window will appear")
94	return nil
95}
96
97// Hide hides the WebView window.
98func (w *WebView) Hide() error {
99	if w == nil || w.destroyed {
100		return ErrNotImplemented
101	}
102	w.visible = false
103	return nil
104}
105
106// Destroy releases native resources.
107func (w *WebView) Destroy() error {
108	if w == nil {
109		return ErrNotImplemented
110	}
111	w.destroyed = true
112	return nil
113}
114
115// Window returns the associated native window wrapper (non-nil).
116func (w *WebView) Window() *Window { return w.window }
117
118// GetCurrentURL returns the last requested URL (non-CGO build approximation).
119func (w *WebView) GetCurrentURL() string { return w.url }
120
121// GoBack is not supported in the non-CGO stub.
122func (w *WebView) GoBack() error { return ErrNotImplemented }
123
124// GoForward is not supported in the non-CGO stub.
125func (w *WebView) GoForward() error { return ErrNotImplemented }
126
127// Reload is not supported in the non-CGO stub.
128func (w *WebView) Reload() error { return ErrNotImplemented }
129
130// ReloadBypassCache is not supported in the non-CGO stub.
131func (w *WebView) ReloadBypassCache() error { return ErrNotImplemented }
132
133// ShowDevTools is a no-op in the non-CGO build.
134func (w *WebView) ShowDevTools() error { return nil }
135
136// CloseDevTools is a no-op in the non-CGO build.
137func (w *WebView) CloseDevTools() error { return nil }
138
139// RegisterScriptMessageHandler registers a callback invoked when the content script posts a message.
140func (w *WebView) RegisterScriptMessageHandler(cb func(payload string)) { w.msgHandler = cb }
141
142func (w *WebView) RegisterPopupHandler(cb func(string) *WebView) { w.popupHandler = cb }
143
144func (w *WebView) RegisterCloseHandler(cb func()) { w.closeHandler = cb }
145
146func (w *WebView) dispatchScriptMessage(payload string) { //nolint:unused // Called from CGO WebKit callbacks
147	if w != nil && w.msgHandler != nil {
148		w.msgHandler(payload)
149	}
150}
151
152func (w *WebView) dispatchPopupRequest(uri string) *WebView { //nolint:unused // Called from CGO WebKit callbacks
153	if w != nil && w.popupHandler != nil {
154		return w.popupHandler(uri)
155	}
156	return nil
157}
158
159// GetNativePointer returns nil for non-CGO build (stub implementation)
160func (w *WebView) GetNativePointer() unsafe.Pointer { //nolint:unused // Needed for interface compatibility
161	return nil
162}
163
164// RegisterTitleChangedHandler registers a callback invoked when the page title changes.
165func (w *WebView) RegisterTitleChangedHandler(cb func(title string)) { w.titleHandler = cb }
166
167func (w *WebView) dispatchTitleChanged(title string) { //nolint:unused // Called from CGO WebKit callbacks
168	if w != nil && w.titleHandler != nil {
169		w.titleHandler(title)
170	}
171}
172
173// RegisterURIChangedHandler registers a callback invoked when the current page URI changes.
174func (w *WebView) RegisterURIChangedHandler(cb func(uri string)) { w.uriHandler = cb }
175
176func (w *WebView) dispatchURIChanged(uri string) { //nolint:unused // Called from CGO WebKit callbacks
177	if w != nil && w.uriHandler != nil {
178		w.uriHandler(uri)
179	}
180}
181
182// RegisterZoomChangedHandler registers a callback invoked when zoom level changes.
183func (w *WebView) RegisterZoomChangedHandler(cb func(level float64)) { w.zoomHandler = cb }
184
185func (w *WebView) dispatchZoomChanged(level float64) {
186	if w != nil && w.zoomHandler != nil {
187		w.zoomHandler(level)
188	}
189}
190
191// Widget returns an empty handle in stub builds.
192func (w *WebView) Widget() uintptr { return 0 }
193
194// RootWidget returns the container widget handle in CGO builds. Stub returns 0.
195func (w *WebView) RootWidget() uintptr { return w.container }
196
197// DestroyWindow is a no-op in stub builds.
198func (w *WebView) DestroyWindow() {}
199
200// RunOnMainThread executes fn immediately in non-CGO builds.
201func (w *WebView) RunOnMainThread(fn func()) {
202	if fn != nil {
203		fn()
204	}
205}
206
207// PrepareForReparenting is a no-op in stub builds.
208func (w *WebView) PrepareForReparenting() {}
209
210// RefreshAfterReparenting is a no-op in stub builds.
211func (w *WebView) RefreshAfterReparenting() {}
212
213// UsesDomZoom reports whether DOM-based zoom is enabled in this WebView.
214func (w *WebView) UsesDomZoom() bool {
215	return w != nil && w.useDomZoom
216}
217
218// SeedDomZoom stores the desired DOM zoom level for the next navigation (stub implementation).
219func (w *WebView) SeedDomZoom(level float64) {
220	if w == nil || !w.useDomZoom {
221		return
222	}
223	if level < 0.25 {
224		level = 0.25
225	} else if level > 5.0 {
226		level = 5.0
227	}
228	w.domZoomSeed = level
229}
230
231// CreateRelatedView returns a new WebView (stub creates independent)
232func (w *WebView) CreateRelatedView() *WebView {
233	nw, _ := NewWebView(w.config)
234	return nw
235}
236
237// OnWindowTypeDetected registers a callback (stored but never invoked in stub)
238func (w *WebView) OnWindowTypeDetected(callback func(WindowType, *WindowFeatures)) {
239	if w != nil {
240		w.windowTypeCallback = callback
241	}
242}
243
244// InitializeContentBlocking initializes WebKit content blocking with filter manager (stub)
245func (w *WebView) InitializeContentBlocking(filterManager interface{}) error {
246	return ErrNotImplemented
247}
248
249// OnNavigate sets up domain-specific cosmetic filtering on navigation (stub)
250func (w *WebView) OnNavigate(url string, filterManager interface{}) {
251	// No-op in stub
252}
253
254// UpdateContentFilters updates the content filters dynamically (stub)
255func (w *WebView) UpdateContentFilters(filterManager interface{}) error {
256	return ErrNotImplemented
257}
258
259// SetWindowFeatures sets the window features for this WebView (stub)
260func (w *WebView) SetWindowFeatures(features *WindowFeatures) {
261	w.windowFeatures = features
262}
263
264// SetActive sets whether this WebView is currently active/focused (stub)
265func (w *WebView) SetActive(active bool) {
266	// No-op in stub
267}
268
269// IsActive returns whether this WebView is currently active/focused (stub)
270func (w *WebView) IsActive() bool {
271	return false
272}
273
274// ID returns the unique identifier for this WebView as a string (stub)
275func (w *WebView) ID() string {
276	if w == nil {
277		return ""
278	}
279	return strconv.FormatUint(uint64(w.id), 10)
280}

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