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 { | |||
| 30 | 30 | tabModeTimer *time.Timer | |
| 31 | 31 | ||
| 32 | 32 | // 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 | |
| 35 | 35 | ||
| 36 | 36 | // Synchronization | |
| 37 | 37 | mu sync.RWMutex | |
| @@ -30,8 +30,8 @@ type TabManager struct { | |||||
| 30 | tabModeTimer *time.Timer | 30 | 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 handling | 33 | + | buttonToTab map[uint64]*Tab // Maps button ID to tab for click handling |
| 34 | - | nextButtonID uint64 // Atomic counter for generating unique button IDs | 34 | + | nextButtonID uint64 // Atomic counter for generating unique button IDs |
| 35 | 35 | ||||
| 36 | // Synchronization | 36 | // Synchronization | ||
| 37 | mu sync.RWMutex | 37 | mu sync.RWMutex | ||
M internal/app/browser/workspace_css.go +40 -40
| @@ -127,11 +127,11 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |||
| 127 | 127 | if uiScale <= 0 { | |
| 128 | 128 | uiScale = 1.0 // Fallback to default if invalid | |
| 129 | 129 | } | |
| 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 | |
| 135 | 135 | ||
| 136 | 136 | css := fmt.Sprintf(`window { | |
| 137 | 137 | background-color: %s; | |
| @@ -269,45 +269,45 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |||
| 269 | 269 | 0%%, 100%% { opacity: 1.0; } | |
| 270 | 270 | 50%% { opacity: 0.6; } | |
| 271 | 271 | }`, | |
| 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 | |
| 294 | 294 | // Tab bar styles | |
| 295 | - | windowBackgroundColor, // tab-bar background | |
| 295 | + | windowBackgroundColor, // tab-bar background | |
| 296 | 296 | 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) | |
| 300 | 300 | 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) | |
| 306 | 306 | 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 | |
| 311 | 311 | ) | |
| 312 | 312 | ||
| 313 | 313 | 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 invalid | 128 | uiScale = 1.0 // Fallback to default if invalid | ||
| 129 | } | 129 | } | ||
| 130 | - | titleFontSize := int(12 * uiScale) // Base: 12px | 130 | + | titleFontSize := int(12 * uiScale) // Base: 12px |
| 131 | - | titlePaddingVertical := int(4 * uiScale) // Base: 4px | 131 | + | titlePaddingVertical := int(4 * uiScale) // Base: 4px |
| 132 | - | titlePaddingHorizontal := int(8 * uiScale) // Base: 8px | 132 | + | titlePaddingHorizontal := int(8 * uiScale) // Base: 8px |
| 133 | - | titleMinHeight := int(24 * uiScale) // Base: 24px | 133 | + | titleMinHeight := int(24 * uiScale) // Base: 24px |
| 134 | - | faviconMargin := int(4 * uiScale) // Base: 4px | 134 | + | 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 background | 272 | + | 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 background | 274 | + | 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 radius | 277 | + | styling.BorderRadius, // base pane border radius |
| 278 | - | styling.TransitionDuration, // transition-duration | 278 | + | styling.TransitionDuration, // transition-duration |
| 279 | - | styling.BorderWidth, // workspace-pane-active border-width | 279 | + | styling.BorderWidth, // workspace-pane-active border-width |
| 280 | - | activeBorderColor, // workspace-pane-active border color | 280 | + | activeBorderColor, // workspace-pane-active border color |
| 281 | - | windowBackgroundColor, // stacked-pane-container background | 281 | + | windowBackgroundColor, // stacked-pane-container background |
| 282 | - | styling.InactiveBorderWidth, // stacked-pane-container.active border-width | 282 | + | styling.InactiveBorderWidth, // stacked-pane-container.active border-width |
| 283 | - | inactiveBorderColor, // stacked-pane-container.active border-color | 283 | + | inactiveBorderColor, // stacked-pane-container.active border-color |
| 284 | - | getStackTitleBg(isDark), // stacked-pane-title background | 284 | + | getStackTitleBg(isDark), // stacked-pane-title background |
| 285 | - | stackedTitleBorder, // stacked-pane-title border-bottom | 285 | + | stackedTitleBorder, // stacked-pane-title border-bottom |
| 286 | - | titlePaddingVertical, // stacked-pane-title padding vertical | 286 | + | titlePaddingVertical, // stacked-pane-title padding vertical |
| 287 | - | titlePaddingHorizontal, // stacked-pane-title padding horizontal | 287 | + | titlePaddingHorizontal, // stacked-pane-title padding horizontal |
| 288 | - | titleMinHeight, // stacked-pane-title min-height | 288 | + | titleMinHeight, // stacked-pane-title min-height |
| 289 | - | styling.TransitionDuration, // stacked-pane-title transition | 289 | + | styling.TransitionDuration, // stacked-pane-title transition |
| 290 | - | getStackTitleHoverBg(isDark), // stacked-pane-title:hover background | 290 | + | getStackTitleHoverBg(isDark), // stacked-pane-title:hover background |
| 291 | - | titleFontSize, // stacked-pane-title-text font-size | 291 | + | titleFontSize, // stacked-pane-title-text font-size |
| 292 | - | getStackTitleTextColor(isDark), // stacked-pane-title-text color | 292 | + | getStackTitleTextColor(isDark), // stacked-pane-title-text color |
| 293 | - | faviconMargin, // stacked-pane-favicon margin-right | 293 | + | faviconMargin, // stacked-pane-favicon margin-right |
| 294 | // Tab bar styles | 294 | // Tab bar styles | ||
| 295 | - | windowBackgroundColor, // tab-bar background | 295 | + | windowBackgroundColor, // tab-bar background |
| 296 | getStackTitleBorderColor(isDark), // tab-bar border-top | 296 | getStackTitleBorderColor(isDark), // tab-bar border-top | ||
| 297 | - | int(32 * uiScale), // tab-bar min-height | 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) | 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-right | 300 | getStackTitleBorderColor(isDark), // tab-button border-right | ||
| 301 | - | titlePaddingVertical, // tab-button padding vertical | 301 | + | titlePaddingVertical, // tab-button padding vertical |
| 302 | - | titlePaddingHorizontal, // tab-button padding horizontal | 302 | + | titlePaddingHorizontal, // tab-button padding horizontal |
| 303 | - | styling.TransitionDuration, // tab-button transition | 303 | + | styling.TransitionDuration, // tab-button transition |
| 304 | - | getStackTitleHoverBg(isDark), // tab-button:hover background | 304 | + | 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-right | 306 | getStackTitleBorderColor(isDark), // tab-button-active border-right | ||
| 307 | - | titleFontSize, // tab-title font-size | 307 | + | titleFontSize, // tab-title font-size |
| 308 | - | getStackTitleTextColor(isDark), // tab-title color | 308 | + | getStackTitleTextColor(isDark), // tab-title color |
| 309 | - | windowBackgroundColor, // tab-content-area background | 309 | + | windowBackgroundColor, // tab-content-area background |
| 310 | - | windowBackgroundColor, // tab-workspace-container background | 310 | + | windowBackgroundColor, // tab-workspace-container background |
| 311 | ) | 311 | ) | ||
| 312 | 312 | ||||
| 313 | return css | 313 | return css | ||
M internal/app/browser/workspace_navigation_test.go +4 -3
| @@ -155,9 +155,10 @@ func TestCaseSensitiveDirections(t *testing.T) { | |||
| 155 | 155 | // This causes navigation to fail because we're comparing coordinates in different spaces. | |
| 156 | 156 | // | |
| 157 | 157 | // 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" | |
| 161 | 162 | // | |
| 162 | 163 | // The fix: Always use stack wrapper allocation for panes inside stacks. | |
| 163 | 164 | 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 coords | 158 | + | // |
| 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 { | |||
| 51 | 51 | // GenericCache implements Cache[K, V] using sync.Map for thread-safe storage | |
| 52 | 52 | // and a DatabaseOperations interface for database operations. | |
| 53 | 53 | 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] | |
| 56 | 56 | ||
| 57 | 57 | // Track pending async operations for graceful shutdown | |
| 58 | 58 | 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 storage | 51 | // 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.Map | 54 | + | cache sync.Map |
| 55 | - | dbOps DatabaseOperations[K, V] | 55 | + | dbOps DatabaseOperations[K, V] |
| 56 | 56 | ||||
| 57 | // Track pending async operations for graceful shutdown | 57 | // Track pending async operations for graceful shutdown | ||
| 58 | pendingWrites sync.WaitGroup | 58 | pendingWrites sync.WaitGroup | ||
M internal/config/config.go +10 -10
| @@ -23,17 +23,17 @@ const ( | |||
| 23 | 23 | ||
| 24 | 24 | // Config represents the complete configuration for dumber. | |
| 25 | 25 | 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"` | |
| 29 | 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"` | |
| 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"` | |
| 37 | 37 | // RenderingMode controls GPU/CPU rendering selection for WebKit | |
| 38 | 38 | RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"` | |
| 39 | 39 | // 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 WebKit | 37 | // 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 ( | |||
| 29 | 29 | // Workspace styling defaults | |
| 30 | 30 | defaultBorderWidth = 1 | |
| 31 | 31 | 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) | |
| 37 | 37 | defaultTransitionDuration = 120 | |
| 38 | 38 | defaultBorderRadius = 0 | |
| 39 | 39 | defaultUIScale = 1.0 // UI scale multiplier (1.0 = 100%, 1.2 = 120%) | |
| @@ -130,8 +130,8 @@ func DefaultConfig() *Config { | |||
| 130 | 130 | VideoBufferSizeMB: 16, // Larger buffer for AV1 streams | |
| 131 | 131 | QueueBufferTimeSec: 10, // More buffering time for smooth playback | |
| 132 | 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 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) | |
| 135 | 135 | }, | |
| 136 | 136 | Debug: DebugConfig{ | |
| 137 | 137 | EnableWebKitDebug: false, | |
| @@ -190,8 +190,8 @@ func DefaultConfig() *Config { | |||
| 190 | 190 | OpenInNewPane: true, | |
| 191 | 191 | FollowPaneContext: true, | |
| 192 | 192 | 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 | |
| 195 | 195 | }, | |
| 196 | 196 | Styling: WorkspaceStylingConfig{ | |
| 197 | 197 | BorderWidth: defaultBorderWidth, | |
| @@ -29,11 +29,11 @@ const ( | |||||
| 29 | // Workspace styling defaults | 29 | // Workspace styling defaults | ||
| 30 | defaultBorderWidth = 1 | 30 | defaultBorderWidth = 1 | ||
| 31 | defaultBorderColor = "@theme_selected_bg_color" | 31 | defaultBorderColor = "@theme_selected_bg_color" | ||
| 32 | - | defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift | 32 | + | defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift |
| 33 | - | defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable | 33 | + | defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable |
| 34 | - | defaultShowStackedTitleBorder = false // Hidden by default | 34 | + | defaultShowStackedTitleBorder = false // Hidden by default |
| 35 | - | defaultPaneModeBorderColor = "#4A90E2" // Blue for pane mode indicator | 35 | + | 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 = 120 | 37 | defaultTransitionDuration = 120 | ||
| 38 | defaultBorderRadius = 0 | 38 | 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 streams | 130 | VideoBufferSizeMB: 16, // Larger buffer for AV1 streams | ||
| 131 | QueueBufferTimeSec: 10, // More buffering time for smooth playback | 131 | 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 res | 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) | 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 mode | 192 | BlankTargetBehavior: "stacked", // Default: open _blank links in stacked mode | ||
| 193 | - | EnableSmartDetection: true, // Use WindowProperties to detect popup vs tab | 193 | + | EnableSmartDetection: true, // Use WindowProperties to detect popup vs tab |
| 194 | - | OAuthAutoClose: true, // Auto-close OAuth popups on success | 194 | + | 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 | |||
| 85 | 85 | func (fm *FilterManager) updateWhitelistCache(whitelist []string) { | |
| 86 | 86 | // Create a hash of the whitelist to detect changes | |
| 87 | 87 | currentHash := strings.Join(whitelist, "|") | |
| 88 | - | ||
| 88 | + | ||
| 89 | 89 | // Only rebuild if whitelist changed | |
| 90 | 90 | if fm.cachedWhitelistHash == currentHash && fm.cachedWhitelistRules != nil { | |
| 91 | 91 | return | |
| 92 | 92 | } | |
| 93 | - | ||
| 93 | + | ||
| 94 | 94 | // Rebuild cache with pre-allocation | |
| 95 | 95 | rules := make([]converter.WebKitRule, 0, len(whitelist)) | |
| 96 | 96 | 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 changes | 86 | // 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 changed | 89 | // Only rebuild if whitelist changed | ||
| 90 | if fm.cachedWhitelistHash == currentHash && fm.cachedWhitelistRules != nil { | 90 | if fm.cachedWhitelistHash == currentHash && fm.cachedWhitelistRules != nil { | ||
| 91 | return | 91 | return | ||
| 92 | } | 92 | } | ||
| 93 | - | 93 | + | ||
| 94 | // Rebuild cache with pre-allocation | 94 | // 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) { | |||
| 44 | 44 | resultType = InputTypeFallbackSearch | |
| 45 | 45 | confidence = 0.1 | |
| 46 | 46 | 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://"): | |
| 50 | 50 | resultType = InputTypeDirectURL | |
| 51 | 51 | confidence = 1.0 | |
| 52 | 52 | default: | |
| @@ -44,9 +44,9 @@ func (p *Parser) ParseInput(input string) (*ParseResult, error) { | |||||
| 44 | resultType = InputTypeFallbackSearch | 44 | resultType = InputTypeFallbackSearch | ||
| 45 | confidence = 0.1 | 45 | 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 = InputTypeDirectURL | 50 | resultType = InputTypeDirectURL | ||
| 51 | confidence = 1.0 | 51 | confidence = 1.0 | ||
| 52 | default: | 52 | default: | ||
M internal/services/browser.go +9 -9
| @@ -48,13 +48,13 @@ type BrowserService struct { | |||
| 48 | 48 | webView *webkit.WebView | |
| 49 | 49 | initialURL string | |
| 50 | 50 | 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 | |
| 58 | 58 | ||
| 59 | 59 | // Fuzzy cache refresh tracking | |
| 60 | 60 | historySinceRefresh int // Count of history entries added since last cache refresh | |
| @@ -440,8 +440,8 @@ func (s *BrowserService) processHistoryQueue() { | |||
| 440 | 440 | batch = batch[:0] // Clear batch | |
| 441 | 441 | ||
| 442 | 442 | // 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 | |
| 445 | 445 | ||
| 446 | 446 | s.historySinceRefresh += batchSize | |
| 447 | 447 | timeSinceRefresh := time.Since(s.lastCacheRefresh) | |
| @@ -48,13 +48,13 @@ type BrowserService struct { | |||||
| 48 | webView *webkit.WebView | 48 | webView *webkit.WebView | ||
| 49 | initialURL string | 49 | initialURL string | ||
| 50 | guiBundle string | 50 | guiBundle string | ||
| 51 | - | zoomCache *cache.ZoomCache // In-memory cache for zoom levels | 51 | + | zoomCache *cache.ZoomCache // In-memory cache for zoom levels |
| 52 | - | certCache *cache.CertValidationsCache // In-memory cache for certificate validations | 52 | + | certCache *cache.CertValidationsCache // In-memory cache for certificate validations |
| 53 | - | favoritesCache *cache.FavoritesCache // In-memory cache for favorites | 53 | + | favoritesCache *cache.FavoritesCache // In-memory cache for favorites |
| 54 | - | fuzzyCache *cache.CacheManager // Async fuzzy search cache for dmenu | 54 | + | fuzzyCache *cache.CacheManager // Async fuzzy search cache for dmenu |
| 55 | - | historyQueue chan historyUpdate // Queue for batched history writes | 55 | + | 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 once | 57 | + | flushOnce sync.Once // Ensures FlushHistoryQueue only runs once |
| 58 | 58 | ||||
| 59 | // Fuzzy cache refresh tracking | 59 | // Fuzzy cache refresh tracking | ||
| 60 | historySinceRefresh int // Count of history entries added since last cache refresh | 60 | historySinceRefresh int // Count of history entries added since last cache refresh | ||
| @@ -440,8 +440,8 @@ func (s *BrowserService) processHistoryQueue() { | |||||
| 440 | batch = batch[:0] // Clear batch | 440 | batch = batch[:0] // Clear batch | ||
| 441 | 441 | ||||
| 442 | // Smart fuzzy cache refresh: rebuild after N entries AND M minutes | 442 | // Smart fuzzy cache refresh: rebuild after N entries AND M minutes | ||
| 443 | - | const minEntries = 10 // Minimum new entries before refresh | 443 | + | const minEntries = 10 // Minimum new entries before refresh |
| 444 | - | const minInterval = 5 * time.Minute // Minimum time between refreshes | 444 | + | const minInterval = 5 * time.Minute // Minimum time between refreshes |
| 445 | 445 | ||||
| 446 | s.historySinceRefresh += batchSize | 446 | 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 { | |||
| 29 | 29 | exportDir string // Directory for exporting favicons for CLI access | |
| 30 | 30 | dataDir string // WebKit data directory | |
| 31 | 31 | enableExport bool // Whether to export favicons for CLI tools | |
| 32 | - | ||
| 32 | + | ||
| 33 | 33 | // Deduplication: tracks recently processed (pageURL, faviconURI) pairs | |
| 34 | 34 | // Key: pageURL, Value: struct{faviconURI string, timestamp time.Time} | |
| 35 | 35 | recentChanges sync.Map | |
| 36 | - | ||
| 36 | + | ||
| 37 | 37 | // Debouncing: tracks ongoing preload operations to prevent duplicates | |
| 38 | 38 | // Key: pageURL, Value: bool (true if preload is in progress) | |
| 39 | 39 | ongoingPreloads sync.Map | |
| @@ -115,7 +115,7 @@ func (fs *FaviconService) OnFaviconChanged(pageURL, faviconURI string) error { | |||
| 115 | 115 | faviconURI string | |
| 116 | 116 | timestamp time.Time | |
| 117 | 117 | } | |
| 118 | - | ||
| 118 | + | ||
| 119 | 119 | if cached, ok := fs.recentChanges.Load(pageURL); ok { | |
| 120 | 120 | if rc, ok := cached.(recentChange); ok { | |
| 121 | 121 | if time.Since(rc.timestamp) < DeduplicationWindow { | |
| @@ -29,11 +29,11 @@ type FaviconService struct { | |||||
| 29 | exportDir string // Directory for exporting favicons for CLI access | 29 | exportDir string // Directory for exporting favicons for CLI access | ||
| 30 | dataDir string // WebKit data directory | 30 | dataDir string // WebKit data directory | ||
| 31 | enableExport bool // Whether to export favicons for CLI tools | 31 | enableExport bool // Whether to export favicons for CLI tools | ||
| 32 | - | 32 | + | ||
| 33 | // Deduplication: tracks recently processed (pageURL, faviconURI) pairs | 33 | // 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.Map | 35 | recentChanges sync.Map | ||
| 36 | - | 36 | + | ||
| 37 | // Debouncing: tracks ongoing preload operations to prevent duplicates | 37 | // 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.Map | 39 | ongoingPreloads sync.Map | ||
| @@ -115,7 +115,7 @@ func (fs *FaviconService) OnFaviconChanged(pageURL, faviconURI string) error { | |||||
| 115 | faviconURI string | 115 | faviconURI string | ||
| 116 | timestamp time.Time | 116 | 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 { | ||