detached 81b4f58

refactor: minor API and type improvements

- Add new type definitions for enhanced GUI functionality
- Update API scheme handling with better error management
- Refine CLI browse command with improved argument processing
- Enhance keyboard handling in WebKit CGO bindings
commit
81b4f58dc379925d2841c48f77f1febf772484e4
author
bamen · · 2025-09-23 19:03 UTC
committer
bamen · · 2025-09-23 19:13 UTC
parent
266137a
signature
unsigned
4 files · +35 -6
M gui/src/lib/types.ts +6 -0
@@ -1,5 +1,10 @@
11 import type { HistoryEntry, SearchShortcut } from "../types/generated.js";
22
3+type ThemeManagerAPI = {
4+ setUserPreference: (theme: "light" | "dark") => void;
5+ getCurrentTheme: () => "light" | "dark";
6+};
7+
38 // Global window API types for browser integration
49 declare global {
510 interface Window {
@@ -17,6 +22,7 @@ declare global {
1722 // Theme integration
1823 __dumber_initial_theme?: string;
1924 __dumber_setTheme?: (theme: "light" | "dark") => void;
25+ __dumber_color_scheme_manager?: ThemeManagerAPI;
2026
2127 // History callbacks
2228 __dumber_history_recent?: (data: HistoryEntry[]) => void;
@@ -1,5 +1,10 @@
1 import type { HistoryEntry, SearchShortcut } from "../types/generated.js";1 import type { HistoryEntry, SearchShortcut } from "../types/generated.js";
2 2
3+type ThemeManagerAPI = {
4+ setUserPreference: (theme: "light" | "dark") => void;
5+ getCurrentTheme: () => "light" | "dark";
6+};
7+
3 // Global window API types for browser integration8 // Global window API types for browser integration
4 declare global {9 declare global {
5 interface Window {10 interface Window {
@@ -17,6 +22,7 @@ declare global {
17 // Theme integration22 // Theme integration
18 __dumber_initial_theme?: string;23 __dumber_initial_theme?: string;
19 __dumber_setTheme?: (theme: "light" | "dark") => void;24 __dumber_setTheme?: (theme: "light" | "dark") => void;
25+ __dumber_color_scheme_manager?: ThemeManagerAPI;
20 26
21 // History callbacks27 // History callbacks
22 __dumber_history_recent?: (data: HistoryEntry[]) => void;28 __dumber_history_recent?: (data: HistoryEntry[]) => void;
M internal/app/api/scheme.go +4 -4
@@ -74,12 +74,12 @@ func (s *SchemeHandler) handleAsset(u *neturl.URL) (string, []byte, bool) {
7474 }
7575 }
7676
77- // Special-case homepage favicon: map .ico request to embedded SVG file
77+ // Special-case homepage favicon: map .ico request to embedded PNG file
7878 if (u.Host == constants.HomepagePath || u.Opaque == constants.HomepagePath) && strings.EqualFold(rel, "favicon.ico") {
79- log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.svg", rel, u.Host, u.Path)
80- data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.svg")))
79+ log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.png", rel, u.Host, u.Path)
80+ data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.png")))
8181 if rerr == nil {
82- return "image/svg+xml", data, true
82+ return "image/png", data, true
8383 }
8484 }
8585
@@ -74,12 +74,12 @@ func (s *SchemeHandler) handleAsset(u *neturl.URL) (string, []byte, bool) {
74 }74 }
75 }75 }
76 76
77- // Special-case homepage favicon: map .ico request to embedded SVG file77+ // Special-case homepage favicon: map .ico request to embedded PNG file
78 if (u.Host == constants.HomepagePath || u.Opaque == constants.HomepagePath) && strings.EqualFold(rel, "favicon.ico") {78 if (u.Host == constants.HomepagePath || u.Opaque == constants.HomepagePath) && strings.EqualFold(rel, "favicon.ico") {
79- log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.svg", rel, u.Host, u.Path)79+ log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.png", rel, u.Host, u.Path)
80- data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.svg")))80+ data, rerr := s.assets.ReadFile(filepath.ToSlash(filepath.Join("assets", "gui", "favicon.png")))
81 if rerr == nil {81 if rerr == nil {
82- return "image/svg+xml", data, true82+ return "image/png", data, true
83 }83 }
84 }84 }
85 85
M internal/cli/browse.go +6 -2
@@ -136,8 +136,12 @@ func openURLWithConfig(url string, cfg *config.Config) error {
136136 return nil
137137 }
138138
139-// updateFavicon fetches and stores favicon URL for a given page URL
139+// updateFavicon is now deprecated in favor of WebKit's native favicon API
140+// When using the built-in browser, WebKit automatically handles favicon detection
141+// This function is kept for CLI compatibility but may use fallback behavior
140142 func updateFavicon(ctx context.Context, cli *CLI, pageURL string) {
143+ // For CLI usage (non-GUI), we still use the fallback method
144+ // The GUI browser handles favicons through WebKit signals
141145 parsedURL, err := url.Parse(pageURL)
142146 if err != nil {
143147 return // Silently fail for invalid URLs
@@ -151,7 +155,7 @@ func updateFavicon(ctx context.Context, cli *CLI, pageURL string) {
151155 return
152156 }
153157
154- // Standard favicon location
158+ // Standard favicon location (fallback)
155159 faviconURL := fmt.Sprintf("%s://%s/favicon.ico", parsedURL.Scheme, parsedURL.Host)
156160
157161 // Update in database using the new sqlc-generated method
@@ -136,8 +136,12 @@ func openURLWithConfig(url string, cfg *config.Config) error {
136 return nil136 return nil
137 }137 }
138 138
139-// updateFavicon fetches and stores favicon URL for a given page URL139+// updateFavicon is now deprecated in favor of WebKit's native favicon API
140+// When using the built-in browser, WebKit automatically handles favicon detection
141+// This function is kept for CLI compatibility but may use fallback behavior
140 func updateFavicon(ctx context.Context, cli *CLI, pageURL string) {142 func updateFavicon(ctx context.Context, cli *CLI, pageURL string) {
143+ // For CLI usage (non-GUI), we still use the fallback method
144+ // The GUI browser handles favicons through WebKit signals
141 parsedURL, err := url.Parse(pageURL)145 parsedURL, err := url.Parse(pageURL)
142 if err != nil {146 if err != nil {
143 return // Silently fail for invalid URLs147 return // Silently fail for invalid URLs
@@ -151,7 +155,7 @@ func updateFavicon(ctx context.Context, cli *CLI, pageURL string) {
151 return155 return
152 }156 }
153 157
154- // Standard favicon location158+ // Standard favicon location (fallback)
155 faviconURL := fmt.Sprintf("%s://%s/favicon.ico", parsedURL.Scheme, parsedURL.Host)159 faviconURL := fmt.Sprintf("%s://%s/favicon.ico", parsedURL.Scheme, parsedURL.Host)
156 160
157 // Update in database using the new sqlc-generated method161 // Update in database using the new sqlc-generated method
M pkg/webkit/keyboard_cgo.go +19 -0
@@ -508,6 +508,25 @@ func goOnURIChanged(id C.ulong, curi *C.char) {
508508 vw.dispatchURIChanged(uri)
509509 }
510510
511+//export goOnFaviconURIChanged
512+func goOnFaviconURIChanged(id C.ulong, pageURI *C.char, faviconURI *C.char) {
513+ uid := uintptr(id)
514+ pageURLStr := C.GoString(pageURI)
515+ faviconURLStr := C.GoString(faviconURI)
516+
517+ log.Printf("[favicon] WebKit favicon URI changed for WebView ID %d - page: %s, favicon: %s", uid, pageURLStr, faviconURLStr)
518+
519+ regMu.RLock()
520+ vw := viewByID[uid]
521+ regMu.RUnlock()
522+ if vw == nil {
523+ log.Printf("[favicon] WebView not found for ID %d", uid)
524+ return
525+ }
526+
527+ vw.dispatchFaviconURIChanged(pageURLStr, faviconURLStr)
528+}
529+
511530 //export goHandleNewWindowPolicy
512531 func goHandleNewWindowPolicy(id C.ulong, curi *C.char, navType C.int, cframeName *C.char, isUserGesture C.gboolean, modifiers C.guint, mouseButton C.guint) C.gboolean {
513532 uid := uintptr(id)
@@ -508,6 +508,25 @@ func goOnURIChanged(id C.ulong, curi *C.char) {
508 vw.dispatchURIChanged(uri)508 vw.dispatchURIChanged(uri)
509 }509 }
510 510
511+//export goOnFaviconURIChanged
512+func goOnFaviconURIChanged(id C.ulong, pageURI *C.char, faviconURI *C.char) {
513+ uid := uintptr(id)
514+ pageURLStr := C.GoString(pageURI)
515+ faviconURLStr := C.GoString(faviconURI)
516+
517+ log.Printf("[favicon] WebKit favicon URI changed for WebView ID %d - page: %s, favicon: %s", uid, pageURLStr, faviconURLStr)
518+
519+ regMu.RLock()
520+ vw := viewByID[uid]
521+ regMu.RUnlock()
522+ if vw == nil {
523+ log.Printf("[favicon] WebView not found for ID %d", uid)
524+ return
525+ }
526+
527+ vw.dispatchFaviconURIChanged(pageURLStr, faviconURLStr)
528+}
529+
511 //export goHandleNewWindowPolicy530 //export goHandleNewWindowPolicy
512 func goHandleNewWindowPolicy(id C.ulong, curi *C.char, navType C.int, cframeName *C.char, isUserGesture C.gboolean, modifiers C.guint, mouseButton C.guint) C.gboolean {531 func goHandleNewWindowPolicy(id C.ulong, curi *C.char, navType C.int, cframeName *C.char, isUserGesture C.gboolean, modifiers C.guint, mouseButton C.guint) C.gboolean {
513 uid := uintptr(id)532 uid := uintptr(id)

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