detached b3a6cbe

chore: run go fmt on all packages

Apply standard Go formatting across the codebase.
commit
b3a6cbeb4ed5a8869c2ed07f80add72c1d3c7b91
author
bnema · · 2025-11-17 17:25 UTC
committer
bnema · · 2025-11-17 21:46 UTC
parent
61536e8
signature
unsigned
10 files · +84 -83
M internal/app/browser/tab_manager.go +2 -2
@@ -30,8 +30,8 @@ type TabManager struct {
3030 tabModeTimer *time.Timer
3131
3232 // Tab button click handling (pattern from StackedPaneManager)
33- buttonToTab map[uint64]*Tab // Maps button ID to tab for click handling
34- nextButtonID uint64 // Atomic counter for generating unique button IDs
33+ buttonToTab map[uint64]*Tab // Maps button ID to tab for click handling
34+ nextButtonID uint64 // Atomic counter for generating unique button IDs
3535
3636 // Synchronization
3737 mu sync.RWMutex
@@ -30,8 +30,8 @@ type TabManager struct {
30 tabModeTimer *time.Timer30 tabModeTimer *time.Timer
31 31
32 // Tab button click handling (pattern from StackedPaneManager)32 // Tab button click handling (pattern from StackedPaneManager)
33- buttonToTab map[uint64]*Tab // Maps button ID to tab for click handling33+ buttonToTab map[uint64]*Tab // Maps button ID to tab for click handling
34- nextButtonID uint64 // Atomic counter for generating unique button IDs34+ nextButtonID uint64 // Atomic counter for generating unique button IDs
35 35
36 // Synchronization36 // Synchronization
37 mu sync.RWMutex37 mu sync.RWMutex
M internal/app/browser/workspace_css.go +40 -40
@@ -127,11 +127,11 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
127127 if uiScale <= 0 {
128128 uiScale = 1.0 // Fallback to default if invalid
129129 }
130- titleFontSize := int(12 * uiScale) // Base: 12px
131- titlePaddingVertical := int(4 * uiScale) // Base: 4px
132- titlePaddingHorizontal := int(8 * uiScale) // Base: 8px
133- titleMinHeight := int(24 * uiScale) // Base: 24px
134- faviconMargin := int(4 * uiScale) // Base: 4px
130+ titleFontSize := int(12 * uiScale) // Base: 12px
131+ titlePaddingVertical := int(4 * uiScale) // Base: 4px
132+ titlePaddingHorizontal := int(8 * uiScale) // Base: 8px
133+ titleMinHeight := int(24 * uiScale) // Base: 24px
134+ faviconMargin := int(4 * uiScale) // Base: 4px
135135
136136 css := fmt.Sprintf(`window {
137137 background-color: %s;
@@ -269,45 +269,45 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
269269 0%%, 100%% { opacity: 1.0; }
270270 50%% { opacity: 0.6; }
271271 }`,
272- windowBackgroundColor, // window background
273- paneModeColor, // window.pane-mode-active background (border color)
274- windowBackgroundColor, // paned, box background
275- styling.InactiveBorderWidth, // base pane border-width (inactive)
276- inactiveBorderColor, // base pane border-color (inactive)
277- styling.BorderRadius, // base pane border radius
278- styling.TransitionDuration, // transition-duration
279- styling.BorderWidth, // workspace-pane-active border-width
280- activeBorderColor, // workspace-pane-active border color
281- windowBackgroundColor, // stacked-pane-container background
282- styling.InactiveBorderWidth, // stacked-pane-container.active border-width
283- inactiveBorderColor, // stacked-pane-container.active border-color
284- getStackTitleBg(isDark), // stacked-pane-title background
285- stackedTitleBorder, // stacked-pane-title border-bottom
286- titlePaddingVertical, // stacked-pane-title padding vertical
287- titlePaddingHorizontal, // stacked-pane-title padding horizontal
288- titleMinHeight, // stacked-pane-title min-height
289- styling.TransitionDuration, // stacked-pane-title transition
290- getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
291- titleFontSize, // stacked-pane-title-text font-size
292- getStackTitleTextColor(isDark), // stacked-pane-title-text color
293- faviconMargin, // stacked-pane-favicon margin-right
272+ windowBackgroundColor, // window background
273+ paneModeColor, // window.pane-mode-active background (border color)
274+ windowBackgroundColor, // paned, box background
275+ styling.InactiveBorderWidth, // base pane border-width (inactive)
276+ inactiveBorderColor, // base pane border-color (inactive)
277+ styling.BorderRadius, // base pane border radius
278+ styling.TransitionDuration, // transition-duration
279+ styling.BorderWidth, // workspace-pane-active border-width
280+ activeBorderColor, // workspace-pane-active border color
281+ windowBackgroundColor, // stacked-pane-container background
282+ styling.InactiveBorderWidth, // stacked-pane-container.active border-width
283+ inactiveBorderColor, // stacked-pane-container.active border-color
284+ getStackTitleBg(isDark), // stacked-pane-title background
285+ stackedTitleBorder, // stacked-pane-title border-bottom
286+ titlePaddingVertical, // stacked-pane-title padding vertical
287+ titlePaddingHorizontal, // stacked-pane-title padding horizontal
288+ titleMinHeight, // stacked-pane-title min-height
289+ styling.TransitionDuration, // stacked-pane-title transition
290+ getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
291+ titleFontSize, // stacked-pane-title-text font-size
292+ getStackTitleTextColor(isDark), // stacked-pane-title-text color
293+ faviconMargin, // stacked-pane-favicon margin-right
294294 // Tab bar styles
295- windowBackgroundColor, // tab-bar background
295+ windowBackgroundColor, // tab-bar background
296296 getStackTitleBorderColor(isDark), // tab-bar border-top
297- int(32 * uiScale), // tab-bar min-height
298- tabModeColor, // window.tab-mode-active .tab-bar border-top-color (orange, distinct from pane mode blue)
299- getStackTitleBg(isDark), // tab-button background (same as stacked title)
297+ int(32*uiScale), // tab-bar min-height
298+ tabModeColor, // window.tab-mode-active .tab-bar border-top-color (orange, distinct from pane mode blue)
299+ getStackTitleBg(isDark), // tab-button background (same as stacked title)
300300 getStackTitleBorderColor(isDark), // tab-button border-right
301- titlePaddingVertical, // tab-button padding vertical
302- titlePaddingHorizontal, // tab-button padding horizontal
303- styling.TransitionDuration, // tab-button transition
304- getStackTitleHoverBg(isDark), // tab-button:hover background
305- getActiveTabBg(isDark), // tab-button-active background (much more visible)
301+ titlePaddingVertical, // tab-button padding vertical
302+ titlePaddingHorizontal, // tab-button padding horizontal
303+ styling.TransitionDuration, // tab-button transition
304+ getStackTitleHoverBg(isDark), // tab-button:hover background
305+ getActiveTabBg(isDark), // tab-button-active background (much more visible)
306306 getStackTitleBorderColor(isDark), // tab-button-active border-right
307- titleFontSize, // tab-title font-size
308- getStackTitleTextColor(isDark), // tab-title color
309- windowBackgroundColor, // tab-content-area background
310- windowBackgroundColor, // tab-workspace-container background
307+ titleFontSize, // tab-title font-size
308+ getStackTitleTextColor(isDark), // tab-title color
309+ windowBackgroundColor, // tab-content-area background
310+ windowBackgroundColor, // tab-workspace-container background
311311 )
312312
313313 return css
@@ -127,11 +127,11 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
127 if uiScale <= 0 {127 if uiScale <= 0 {
128 uiScale = 1.0 // Fallback to default if invalid128 uiScale = 1.0 // Fallback to default if invalid
129 }129 }
130- titleFontSize := int(12 * uiScale) // Base: 12px130+ titleFontSize := int(12 * uiScale) // Base: 12px
131- titlePaddingVertical := int(4 * uiScale) // Base: 4px131+ titlePaddingVertical := int(4 * uiScale) // Base: 4px
132- titlePaddingHorizontal := int(8 * uiScale) // Base: 8px132+ titlePaddingHorizontal := int(8 * uiScale) // Base: 8px
133- titleMinHeight := int(24 * uiScale) // Base: 24px133+ titleMinHeight := int(24 * uiScale) // Base: 24px
134- faviconMargin := int(4 * uiScale) // Base: 4px134+ faviconMargin := int(4 * uiScale) // Base: 4px
135 135
136 css := fmt.Sprintf(`window {136 css := fmt.Sprintf(`window {
137 background-color: %s;137 background-color: %s;
@@ -269,45 +269,45 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
269 0%%, 100%% { opacity: 1.0; }269 0%%, 100%% { opacity: 1.0; }
270 50%% { opacity: 0.6; }270 50%% { opacity: 0.6; }
271 }`,271 }`,
272- windowBackgroundColor, // window background272+ windowBackgroundColor, // window background
273- paneModeColor, // window.pane-mode-active background (border color)273+ paneModeColor, // window.pane-mode-active background (border color)
274- windowBackgroundColor, // paned, box background274+ windowBackgroundColor, // paned, box background
275- styling.InactiveBorderWidth, // base pane border-width (inactive)275+ styling.InactiveBorderWidth, // base pane border-width (inactive)
276- inactiveBorderColor, // base pane border-color (inactive)276+ inactiveBorderColor, // base pane border-color (inactive)
277- styling.BorderRadius, // base pane border radius277+ styling.BorderRadius, // base pane border radius
278- styling.TransitionDuration, // transition-duration278+ styling.TransitionDuration, // transition-duration
279- styling.BorderWidth, // workspace-pane-active border-width279+ styling.BorderWidth, // workspace-pane-active border-width
280- activeBorderColor, // workspace-pane-active border color280+ activeBorderColor, // workspace-pane-active border color
281- windowBackgroundColor, // stacked-pane-container background281+ windowBackgroundColor, // stacked-pane-container background
282- styling.InactiveBorderWidth, // stacked-pane-container.active border-width282+ styling.InactiveBorderWidth, // stacked-pane-container.active border-width
283- inactiveBorderColor, // stacked-pane-container.active border-color283+ inactiveBorderColor, // stacked-pane-container.active border-color
284- getStackTitleBg(isDark), // stacked-pane-title background284+ getStackTitleBg(isDark), // stacked-pane-title background
285- stackedTitleBorder, // stacked-pane-title border-bottom285+ stackedTitleBorder, // stacked-pane-title border-bottom
286- titlePaddingVertical, // stacked-pane-title padding vertical286+ titlePaddingVertical, // stacked-pane-title padding vertical
287- titlePaddingHorizontal, // stacked-pane-title padding horizontal287+ titlePaddingHorizontal, // stacked-pane-title padding horizontal
288- titleMinHeight, // stacked-pane-title min-height288+ titleMinHeight, // stacked-pane-title min-height
289- styling.TransitionDuration, // stacked-pane-title transition289+ styling.TransitionDuration, // stacked-pane-title transition
290- getStackTitleHoverBg(isDark), // stacked-pane-title:hover background290+ getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
291- titleFontSize, // stacked-pane-title-text font-size291+ titleFontSize, // stacked-pane-title-text font-size
292- getStackTitleTextColor(isDark), // stacked-pane-title-text color292+ getStackTitleTextColor(isDark), // stacked-pane-title-text color
293- faviconMargin, // stacked-pane-favicon margin-right293+ faviconMargin, // stacked-pane-favicon margin-right
294 // Tab bar styles294 // Tab bar styles
295- windowBackgroundColor, // tab-bar background295+ windowBackgroundColor, // tab-bar background
296 getStackTitleBorderColor(isDark), // tab-bar border-top296 getStackTitleBorderColor(isDark), // tab-bar border-top
297- int(32 * uiScale), // tab-bar min-height297+ int(32*uiScale), // tab-bar min-height
298- tabModeColor, // window.tab-mode-active .tab-bar border-top-color (orange, distinct from pane mode blue)298+ tabModeColor, // window.tab-mode-active .tab-bar border-top-color (orange, distinct from pane mode blue)
299- getStackTitleBg(isDark), // tab-button background (same as stacked title)299+ getStackTitleBg(isDark), // tab-button background (same as stacked title)
300 getStackTitleBorderColor(isDark), // tab-button border-right300 getStackTitleBorderColor(isDark), // tab-button border-right
301- titlePaddingVertical, // tab-button padding vertical301+ titlePaddingVertical, // tab-button padding vertical
302- titlePaddingHorizontal, // tab-button padding horizontal302+ titlePaddingHorizontal, // tab-button padding horizontal
303- styling.TransitionDuration, // tab-button transition303+ styling.TransitionDuration, // tab-button transition
304- getStackTitleHoverBg(isDark), // tab-button:hover background304+ getStackTitleHoverBg(isDark), // tab-button:hover background
305- getActiveTabBg(isDark), // tab-button-active background (much more visible)305+ getActiveTabBg(isDark), // tab-button-active background (much more visible)
306 getStackTitleBorderColor(isDark), // tab-button-active border-right306 getStackTitleBorderColor(isDark), // tab-button-active border-right
307- titleFontSize, // tab-title font-size307+ titleFontSize, // tab-title font-size
308- getStackTitleTextColor(isDark), // tab-title color308+ getStackTitleTextColor(isDark), // tab-title color
309- windowBackgroundColor, // tab-content-area background309+ windowBackgroundColor, // tab-content-area background
310- windowBackgroundColor, // tab-workspace-container background310+ windowBackgroundColor, // tab-workspace-container background
311 )311 )
312 312
313 return css313 return css
M internal/app/browser/workspace_navigation_test.go +4 -3
@@ -155,9 +155,10 @@ func TestCaseSensitiveDirections(t *testing.T) {
155155 // This causes navigation to fail because we're comparing coordinates in different spaces.
156156 //
157157 // Real-world example from logs:
158-// Normal pane (top half): center=(957, 532) - window coords
159-// Stack pane (bottom): center=(955, 511) - relative to stack box!
160-// Result: dy=-21 → SKIPPED as "not below"
158+//
159+// Normal pane (top half): center=(957, 532) - window coords
160+// Stack pane (bottom): center=(955, 511) - relative to stack box!
161+// Result: dy=-21 → SKIPPED as "not below"
161162 //
162163 // The fix: Always use stack wrapper allocation for panes inside stacks.
163164 func TestNavigationCoordinateBug(t *testing.T) {
@@ -155,9 +155,10 @@ func TestCaseSensitiveDirections(t *testing.T) {
155 // This causes navigation to fail because we're comparing coordinates in different spaces.155 // This causes navigation to fail because we're comparing coordinates in different spaces.
156 //156 //
157 // Real-world example from logs:157 // Real-world example from logs:
158-// Normal pane (top half): center=(957, 532) - window coords158+//
159-// Stack pane (bottom): center=(955, 511) - relative to stack box!159+// Normal pane (top half): center=(957, 532) - window coords
160-// Result: dy=-21 → SKIPPED as "not below"160+// Stack pane (bottom): center=(955, 511) - relative to stack box!
161+// Result: dy=-21 → SKIPPED as "not below"
161 //162 //
162 // The fix: Always use stack wrapper allocation for panes inside stacks.163 // The fix: Always use stack wrapper allocation for panes inside stacks.
163 func TestNavigationCoordinateBug(t *testing.T) {164 func TestNavigationCoordinateBug(t *testing.T) {
M internal/cache/generic/cache.go +2 -2
@@ -51,8 +51,8 @@ type DatabaseOperations[K comparable, V any] interface {
5151 // GenericCache implements Cache[K, V] using sync.Map for thread-safe storage
5252 // and a DatabaseOperations interface for database operations.
5353 type GenericCache[K comparable, V any] struct {
54- cache sync.Map
55- dbOps DatabaseOperations[K, V]
54+ cache sync.Map
55+ dbOps DatabaseOperations[K, V]
5656
5757 // Track pending async operations for graceful shutdown
5858 pendingWrites sync.WaitGroup
@@ -51,8 +51,8 @@ type DatabaseOperations[K comparable, V any] interface {
51 // GenericCache implements Cache[K, V] using sync.Map for thread-safe storage51 // GenericCache implements Cache[K, V] using sync.Map for thread-safe storage
52 // and a DatabaseOperations interface for database operations.52 // and a DatabaseOperations interface for database operations.
53 type GenericCache[K comparable, V any] struct {53 type GenericCache[K comparable, V any] struct {
54- cache sync.Map54+ cache sync.Map
55- dbOps DatabaseOperations[K, V]55+ dbOps DatabaseOperations[K, V]
56 56
57 // Track pending async operations for graceful shutdown57 // Track pending async operations for graceful shutdown
58 pendingWrites sync.WaitGroup58 pendingWrites sync.WaitGroup
M internal/config/config.go +10 -10
@@ -23,17 +23,17 @@ const (
2323
2424 // Config represents the complete configuration for dumber.
2525 type Config struct {
26- Database DatabaseConfig `mapstructure:"database" yaml:"database"`
27- History HistoryConfig `mapstructure:"history" yaml:"history"`
28- SearchShortcuts map[string]SearchShortcut `mapstructure:"search_shortcuts" yaml:"search_shortcuts"`
26+ Database DatabaseConfig `mapstructure:"database" yaml:"database"`
27+ History HistoryConfig `mapstructure:"history" yaml:"history"`
28+ SearchShortcuts map[string]SearchShortcut `mapstructure:"search_shortcuts" yaml:"search_shortcuts"`
2929 // DefaultSearchEngine is the URL template for the default search engine (must contain %s placeholder)
30- DefaultSearchEngine string `mapstructure:"default_search_engine" yaml:"default_search_engine"`
31- Dmenu DmenuConfig `mapstructure:"dmenu" yaml:"dmenu"`
32- Logging LoggingConfig `mapstructure:"logging" yaml:"logging"`
33- Appearance AppearanceConfig `mapstructure:"appearance" yaml:"appearance"`
34- VideoAcceleration VideoAccelerationConfig `mapstructure:"video_acceleration" yaml:"video_acceleration"`
35- CodecPreferences CodecConfig `mapstructure:"codec_preferences" yaml:"codec_preferences"`
36- Debug DebugConfig `mapstructure:"debug" yaml:"debug"`
30+ DefaultSearchEngine string `mapstructure:"default_search_engine" yaml:"default_search_engine"`
31+ Dmenu DmenuConfig `mapstructure:"dmenu" yaml:"dmenu"`
32+ Logging LoggingConfig `mapstructure:"logging" yaml:"logging"`
33+ Appearance AppearanceConfig `mapstructure:"appearance" yaml:"appearance"`
34+ VideoAcceleration VideoAccelerationConfig `mapstructure:"video_acceleration" yaml:"video_acceleration"`
35+ CodecPreferences CodecConfig `mapstructure:"codec_preferences" yaml:"codec_preferences"`
36+ Debug DebugConfig `mapstructure:"debug" yaml:"debug"`
3737 // RenderingMode controls GPU/CPU rendering selection for WebKit
3838 RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"`
3939 // UseDomZoom toggles DOM-based zoom instead of native WebKit zoom.
@@ -23,17 +23,17 @@ const (
23 23
24 // Config represents the complete configuration for dumber.24 // Config represents the complete configuration for dumber.
25 type Config struct {25 type Config struct {
26- Database DatabaseConfig `mapstructure:"database" yaml:"database"`26+ Database DatabaseConfig `mapstructure:"database" yaml:"database"`
27- History HistoryConfig `mapstructure:"history" yaml:"history"`27+ History HistoryConfig `mapstructure:"history" yaml:"history"`
28- SearchShortcuts map[string]SearchShortcut `mapstructure:"search_shortcuts" yaml:"search_shortcuts"`28+ SearchShortcuts map[string]SearchShortcut `mapstructure:"search_shortcuts" yaml:"search_shortcuts"`
29 // DefaultSearchEngine is the URL template for the default search engine (must contain %s placeholder)29 // DefaultSearchEngine is the URL template for the default search engine (must contain %s placeholder)
30- DefaultSearchEngine string `mapstructure:"default_search_engine" yaml:"default_search_engine"`30+ DefaultSearchEngine string `mapstructure:"default_search_engine" yaml:"default_search_engine"`
31- Dmenu DmenuConfig `mapstructure:"dmenu" yaml:"dmenu"`31+ Dmenu DmenuConfig `mapstructure:"dmenu" yaml:"dmenu"`
32- Logging LoggingConfig `mapstructure:"logging" yaml:"logging"`32+ Logging LoggingConfig `mapstructure:"logging" yaml:"logging"`
33- Appearance AppearanceConfig `mapstructure:"appearance" yaml:"appearance"`33+ Appearance AppearanceConfig `mapstructure:"appearance" yaml:"appearance"`
34- VideoAcceleration VideoAccelerationConfig `mapstructure:"video_acceleration" yaml:"video_acceleration"`34+ VideoAcceleration VideoAccelerationConfig `mapstructure:"video_acceleration" yaml:"video_acceleration"`
35- CodecPreferences CodecConfig `mapstructure:"codec_preferences" yaml:"codec_preferences"`35+ CodecPreferences CodecConfig `mapstructure:"codec_preferences" yaml:"codec_preferences"`
36- Debug DebugConfig `mapstructure:"debug" yaml:"debug"`36+ Debug DebugConfig `mapstructure:"debug" yaml:"debug"`
37 // RenderingMode controls GPU/CPU rendering selection for WebKit37 // RenderingMode controls GPU/CPU rendering selection for WebKit
38 RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"`38 RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"`
39 // UseDomZoom toggles DOM-based zoom instead of native WebKit zoom.39 // UseDomZoom toggles DOM-based zoom instead of native WebKit zoom.
M internal/config/defaults.go +9 -9
@@ -29,11 +29,11 @@ const (
2929 // Workspace styling defaults
3030 defaultBorderWidth = 1
3131 defaultBorderColor = "@theme_selected_bg_color"
32- defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift
33- defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable
34- defaultShowStackedTitleBorder = false // Hidden by default
35- defaultPaneModeBorderColor = "#4A90E2" // Blue for pane mode indicator
36- defaultTabModeBorderColor = "#FFA500" // Orange for tab mode indicator (distinct from pane mode)
32+ defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift
33+ defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable
34+ defaultShowStackedTitleBorder = false // Hidden by default
35+ defaultPaneModeBorderColor = "#4A90E2" // Blue for pane mode indicator
36+ defaultTabModeBorderColor = "#FFA500" // Orange for tab mode indicator (distinct from pane mode)
3737 defaultTransitionDuration = 120
3838 defaultBorderRadius = 0
3939 defaultUIScale = 1.0 // UI scale multiplier (1.0 = 100%, 1.2 = 120%)
@@ -130,8 +130,8 @@ func DefaultConfig() *Config {
130130 VideoBufferSizeMB: 16, // Larger buffer for AV1 streams
131131 QueueBufferTimeSec: 10, // More buffering time for smooth playback
132132 CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15", // WebKitGTK default (same as Epiphany)
133- AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res
134- DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing)
133+ AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res
134+ DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing)
135135 },
136136 Debug: DebugConfig{
137137 EnableWebKitDebug: false,
@@ -190,8 +190,8 @@ func DefaultConfig() *Config {
190190 OpenInNewPane: true,
191191 FollowPaneContext: true,
192192 BlankTargetBehavior: "stacked", // Default: open _blank links in stacked mode
193- EnableSmartDetection: true, // Use WindowProperties to detect popup vs tab
194- OAuthAutoClose: true, // Auto-close OAuth popups on success
193+ EnableSmartDetection: true, // Use WindowProperties to detect popup vs tab
194+ OAuthAutoClose: true, // Auto-close OAuth popups on success
195195 },
196196 Styling: WorkspaceStylingConfig{
197197 BorderWidth: defaultBorderWidth,
@@ -29,11 +29,11 @@ const (
29 // Workspace styling defaults29 // Workspace styling defaults
30 defaultBorderWidth = 130 defaultBorderWidth = 1
31 defaultBorderColor = "@theme_selected_bg_color"31 defaultBorderColor = "@theme_selected_bg_color"
32- defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift32+ defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift
33- defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable33+ defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable
34- defaultShowStackedTitleBorder = false // Hidden by default34+ defaultShowStackedTitleBorder = false // Hidden by default
35- defaultPaneModeBorderColor = "#4A90E2" // Blue for pane mode indicator35+ defaultPaneModeBorderColor = "#4A90E2" // Blue for pane mode indicator
36- defaultTabModeBorderColor = "#FFA500" // Orange for tab mode indicator (distinct from pane mode)36+ defaultTabModeBorderColor = "#FFA500" // Orange for tab mode indicator (distinct from pane mode)
37 defaultTransitionDuration = 12037 defaultTransitionDuration = 120
38 defaultBorderRadius = 038 defaultBorderRadius = 0
39 defaultUIScale = 1.0 // UI scale multiplier (1.0 = 100%, 1.2 = 120%)39 defaultUIScale = 1.0 // UI scale multiplier (1.0 = 100%, 1.2 = 120%)
@@ -130,8 +130,8 @@ func DefaultConfig() *Config {
130 VideoBufferSizeMB: 16, // Larger buffer for AV1 streams130 VideoBufferSizeMB: 16, // Larger buffer for AV1 streams
131 QueueBufferTimeSec: 10, // More buffering time for smooth playback131 QueueBufferTimeSec: 10, // More buffering time for smooth playback
132 CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15", // WebKitGTK default (same as Epiphany)132 CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15", // WebKitGTK default (same as Epiphany)
133- AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res133+ AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res
134- DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing)134+ DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing)
135 },135 },
136 Debug: DebugConfig{136 Debug: DebugConfig{
137 EnableWebKitDebug: false,137 EnableWebKitDebug: false,
@@ -190,8 +190,8 @@ func DefaultConfig() *Config {
190 OpenInNewPane: true,190 OpenInNewPane: true,
191 FollowPaneContext: true,191 FollowPaneContext: true,
192 BlankTargetBehavior: "stacked", // Default: open _blank links in stacked mode192 BlankTargetBehavior: "stacked", // Default: open _blank links in stacked mode
193- EnableSmartDetection: true, // Use WindowProperties to detect popup vs tab193+ EnableSmartDetection: true, // Use WindowProperties to detect popup vs tab
194- OAuthAutoClose: true, // Auto-close OAuth popups on success194+ OAuthAutoClose: true, // Auto-close OAuth popups on success
195 },195 },
196 Styling: WorkspaceStylingConfig{196 Styling: WorkspaceStylingConfig{
197 BorderWidth: defaultBorderWidth,197 BorderWidth: defaultBorderWidth,
M internal/filtering/manager.go +2 -2
@@ -85,12 +85,12 @@ func NewFilterManager(store FilterStore, compiler FilterCompiler) *FilterManager
8585 func (fm *FilterManager) updateWhitelistCache(whitelist []string) {
8686 // Create a hash of the whitelist to detect changes
8787 currentHash := strings.Join(whitelist, "|")
88-
88+
8989 // Only rebuild if whitelist changed
9090 if fm.cachedWhitelistHash == currentHash && fm.cachedWhitelistRules != nil {
9191 return
9292 }
93-
93+
9494 // Rebuild cache with pre-allocation
9595 rules := make([]converter.WebKitRule, 0, len(whitelist))
9696 for _, domain := range whitelist {
@@ -85,12 +85,12 @@ func NewFilterManager(store FilterStore, compiler FilterCompiler) *FilterManager
85 func (fm *FilterManager) updateWhitelistCache(whitelist []string) {85 func (fm *FilterManager) updateWhitelistCache(whitelist []string) {
86 // Create a hash of the whitelist to detect changes86 // Create a hash of the whitelist to detect changes
87 currentHash := strings.Join(whitelist, "|")87 currentHash := strings.Join(whitelist, "|")
88- 88+
89 // Only rebuild if whitelist changed89 // Only rebuild if whitelist changed
90 if fm.cachedWhitelistHash == currentHash && fm.cachedWhitelistRules != nil {90 if fm.cachedWhitelistHash == currentHash && fm.cachedWhitelistRules != nil {
91 return91 return
92 }92 }
93- 93+
94 // Rebuild cache with pre-allocation94 // Rebuild cache with pre-allocation
95 rules := make([]converter.WebKitRule, 0, len(whitelist))95 rules := make([]converter.WebKitRule, 0, len(whitelist))
96 for _, domain := range whitelist {96 for _, domain := range whitelist {
M internal/parser/parser.go +3 -3
@@ -44,9 +44,9 @@ func (p *Parser) ParseInput(input string) (*ParseResult, error) {
4444 resultType = InputTypeFallbackSearch
4545 confidence = 0.1
4646 case strings.HasPrefix(finalURL, "http://"),
47- strings.HasPrefix(finalURL, "https://"),
48- strings.HasPrefix(finalURL, "dumb://"),
49- strings.HasPrefix(finalURL, "file://"):
47+ strings.HasPrefix(finalURL, "https://"),
48+ strings.HasPrefix(finalURL, "dumb://"),
49+ strings.HasPrefix(finalURL, "file://"):
5050 resultType = InputTypeDirectURL
5151 confidence = 1.0
5252 default:
@@ -44,9 +44,9 @@ func (p *Parser) ParseInput(input string) (*ParseResult, error) {
44 resultType = InputTypeFallbackSearch44 resultType = InputTypeFallbackSearch
45 confidence = 0.145 confidence = 0.1
46 case strings.HasPrefix(finalURL, "http://"),46 case strings.HasPrefix(finalURL, "http://"),
47- strings.HasPrefix(finalURL, "https://"),47+ strings.HasPrefix(finalURL, "https://"),
48- strings.HasPrefix(finalURL, "dumb://"),48+ strings.HasPrefix(finalURL, "dumb://"),
49- strings.HasPrefix(finalURL, "file://"):49+ strings.HasPrefix(finalURL, "file://"):
50 resultType = InputTypeDirectURL50 resultType = InputTypeDirectURL
51 confidence = 1.051 confidence = 1.0
52 default:52 default:
M internal/services/browser.go +9 -9
@@ -48,13 +48,13 @@ type BrowserService struct {
4848 webView *webkit.WebView
4949 initialURL string
5050 guiBundle string
51- zoomCache *cache.ZoomCache // In-memory cache for zoom levels
52- certCache *cache.CertValidationsCache // In-memory cache for certificate validations
53- favoritesCache *cache.FavoritesCache // In-memory cache for favorites
54- fuzzyCache *cache.CacheManager // Async fuzzy search cache for dmenu
55- historyQueue chan historyUpdate // Queue for batched history writes
56- historyFlushDone chan bool // Signal when history flush is complete (buffered)
57- flushOnce sync.Once // Ensures FlushHistoryQueue only runs once
51+ zoomCache *cache.ZoomCache // In-memory cache for zoom levels
52+ certCache *cache.CertValidationsCache // In-memory cache for certificate validations
53+ favoritesCache *cache.FavoritesCache // In-memory cache for favorites
54+ fuzzyCache *cache.CacheManager // Async fuzzy search cache for dmenu
55+ historyQueue chan historyUpdate // Queue for batched history writes
56+ historyFlushDone chan bool // Signal when history flush is complete (buffered)
57+ flushOnce sync.Once // Ensures FlushHistoryQueue only runs once
5858
5959 // Fuzzy cache refresh tracking
6060 historySinceRefresh int // Count of history entries added since last cache refresh
@@ -440,8 +440,8 @@ func (s *BrowserService) processHistoryQueue() {
440440 batch = batch[:0] // Clear batch
441441
442442 // Smart fuzzy cache refresh: rebuild after N entries AND M minutes
443- const minEntries = 10 // Minimum new entries before refresh
444- const minInterval = 5 * time.Minute // Minimum time between refreshes
443+ const minEntries = 10 // Minimum new entries before refresh
444+ const minInterval = 5 * time.Minute // Minimum time between refreshes
445445
446446 s.historySinceRefresh += batchSize
447447 timeSinceRefresh := time.Since(s.lastCacheRefresh)
@@ -48,13 +48,13 @@ type BrowserService struct {
48 webView *webkit.WebView48 webView *webkit.WebView
49 initialURL string49 initialURL string
50 guiBundle string50 guiBundle string
51- zoomCache *cache.ZoomCache // In-memory cache for zoom levels51+ zoomCache *cache.ZoomCache // In-memory cache for zoom levels
52- certCache *cache.CertValidationsCache // In-memory cache for certificate validations52+ certCache *cache.CertValidationsCache // In-memory cache for certificate validations
53- favoritesCache *cache.FavoritesCache // In-memory cache for favorites53+ favoritesCache *cache.FavoritesCache // In-memory cache for favorites
54- fuzzyCache *cache.CacheManager // Async fuzzy search cache for dmenu54+ fuzzyCache *cache.CacheManager // Async fuzzy search cache for dmenu
55- historyQueue chan historyUpdate // Queue for batched history writes55+ historyQueue chan historyUpdate // Queue for batched history writes
56- historyFlushDone chan bool // Signal when history flush is complete (buffered)56+ historyFlushDone chan bool // Signal when history flush is complete (buffered)
57- flushOnce sync.Once // Ensures FlushHistoryQueue only runs once57+ flushOnce sync.Once // Ensures FlushHistoryQueue only runs once
58 58
59 // Fuzzy cache refresh tracking59 // Fuzzy cache refresh tracking
60 historySinceRefresh int // Count of history entries added since last cache refresh60 historySinceRefresh int // Count of history entries added since last cache refresh
@@ -440,8 +440,8 @@ func (s *BrowserService) processHistoryQueue() {
440 batch = batch[:0] // Clear batch440 batch = batch[:0] // Clear batch
441 441
442 // Smart fuzzy cache refresh: rebuild after N entries AND M minutes442 // Smart fuzzy cache refresh: rebuild after N entries AND M minutes
443- const minEntries = 10 // Minimum new entries before refresh443+ const minEntries = 10 // Minimum new entries before refresh
444- const minInterval = 5 * time.Minute // Minimum time between refreshes444+ const minInterval = 5 * time.Minute // Minimum time between refreshes
445 445
446 s.historySinceRefresh += batchSize446 s.historySinceRefresh += batchSize
447 timeSinceRefresh := time.Since(s.lastCacheRefresh)447 timeSinceRefresh := time.Since(s.lastCacheRefresh)
M internal/services/favicon_service.go +3 -3
@@ -29,11 +29,11 @@ type FaviconService struct {
2929 exportDir string // Directory for exporting favicons for CLI access
3030 dataDir string // WebKit data directory
3131 enableExport bool // Whether to export favicons for CLI tools
32-
32+
3333 // Deduplication: tracks recently processed (pageURL, faviconURI) pairs
3434 // Key: pageURL, Value: struct{faviconURI string, timestamp time.Time}
3535 recentChanges sync.Map
36-
36+
3737 // Debouncing: tracks ongoing preload operations to prevent duplicates
3838 // Key: pageURL, Value: bool (true if preload is in progress)
3939 ongoingPreloads sync.Map
@@ -115,7 +115,7 @@ func (fs *FaviconService) OnFaviconChanged(pageURL, faviconURI string) error {
115115 faviconURI string
116116 timestamp time.Time
117117 }
118-
118+
119119 if cached, ok := fs.recentChanges.Load(pageURL); ok {
120120 if rc, ok := cached.(recentChange); ok {
121121 if time.Since(rc.timestamp) < DeduplicationWindow {
@@ -29,11 +29,11 @@ type FaviconService struct {
29 exportDir string // Directory for exporting favicons for CLI access29 exportDir string // Directory for exporting favicons for CLI access
30 dataDir string // WebKit data directory30 dataDir string // WebKit data directory
31 enableExport bool // Whether to export favicons for CLI tools31 enableExport bool // Whether to export favicons for CLI tools
32- 32+
33 // Deduplication: tracks recently processed (pageURL, faviconURI) pairs33 // Deduplication: tracks recently processed (pageURL, faviconURI) pairs
34 // Key: pageURL, Value: struct{faviconURI string, timestamp time.Time}34 // Key: pageURL, Value: struct{faviconURI string, timestamp time.Time}
35 recentChanges sync.Map35 recentChanges sync.Map
36- 36+
37 // Debouncing: tracks ongoing preload operations to prevent duplicates37 // Debouncing: tracks ongoing preload operations to prevent duplicates
38 // Key: pageURL, Value: bool (true if preload is in progress)38 // Key: pageURL, Value: bool (true if preload is in progress)
39 ongoingPreloads sync.Map39 ongoingPreloads sync.Map
@@ -115,7 +115,7 @@ func (fs *FaviconService) OnFaviconChanged(pageURL, faviconURI string) error {
115 faviconURI string115 faviconURI string
116 timestamp time.Time116 timestamp time.Time
117 }117 }
118- 118+
119 if cached, ok := fs.recentChanges.Load(pageURL); ok {119 if cached, ok := fs.recentChanges.Load(pageURL); ok {
120 if rc, ok := cached.(recentChange); ok {120 if rc, ok := cached.(recentChange); ok {
121 if time.Since(rc.timestamp) < DeduplicationWindow {121 if time.Since(rc.timestamp) < DeduplicationWindow {

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