1package config
2
3import (
4 "maps"
5 "os"
6 "path/filepath"
7
8 "github.com/bnema/dumber/internal/domain/entity"
9)
10
11// Default configuration constants
12const (
13 // History defaults
14 defaultMaxHistoryEntries = 10000 // entries
15 defaultRetentionDays = 365 // 1 year
16
17 // Dmenu defaults
18 defaultMaxHistoryDays = 30 // days
19
20 // Logging defaults
21 defaultMaxLogAgeDays = 7 // days
22 defaultMaxLogFiles = 100 // session log files
23
24 // Appearance defaults
25 defaultSidebarWidth = 320 // px, clamped to [280, 380]
26 defaultFontSize = 16 // points
27 defaultExternalThemeProvider = "noctalia"
28 defaultExternalThemeFormat = "colors-json"
29 defaultExternalThemeColorsFilename = "colors.json"
30 defaultExternalThemeTemplateFormat = "dumber-json"
31 defaultExternalThemeTemplateFilename = "noctalia-theme.json"
32
33 // Workspace defaults
34 defaultNewPaneURL = "about:blank"
35
36 // Omnibox defaults
37 defaultOmniboxStyle = "command"
38 defaultOmniboxInitialBehavior = OmniboxInitialBehaviorRecent
39 defaultOmniboxMaxHistoryDays = 30
40 defaultOmniboxAutoOpenOnNewPane = false
41
42 // Workspace defaults
43 defaultKeymap = KeymapZellij
44 defaultPrefixActivationShortcut = "ctrl+space"
45 defaultPrefixTimeoutMilliseconds = 2000
46 defaultPaneActivationShortcut = "ctrl+p"
47 defaultPaneTimeoutMilliseconds = 3000
48 defaultTabActivationShortcut = "ctrl+t"
49 defaultTabTimeoutMilliseconds = 3000
50 defaultResizeActivationShortcut = "ctrl+n"
51 defaultResizeTimeoutMilliseconds = 3000
52 defaultPageActivationShortcut = "ctrl+y"
53 defaultPageTimeoutMilliseconds = 0
54 defaultPageSequenceTimeoutMilliseconds = 500
55 defaultResizeStepPercent = 5.0
56 defaultResizeMinPanePercent = 10.0
57 defaultTabBarPosition = "bottom"
58 defaultPopupPlacement = "right"
59 defaultExternalLinkBehavior = ExternalLinkBehaviorWindowed
60 defaultExternalLinkPlacement = ExternalLinkPlacementRight
61 defaultFloatingPaneWidthPct = 0.82
62 defaultFloatingPaneHeightPct = 0.72
63
64 // Session defaults
65 defaultSessionActivationShortcut = "ctrl+o"
66 defaultSessionTimeoutMilliseconds = 3000
67 defaultSnapshotIntervalMs = 5000
68 defaultMaxExitedSessions = 50
69 defaultMaxExitedSessionAgeDays = 7
70
71 // Workspace styling defaults
72 // Active pane border (overlay)
73 defaultBorderWidth = 1
74 defaultBorderColor = "@theme_selected_bg_color"
75
76 // Mode border width (consolidated for all modes)
77 defaultModeBorderWidth = 4
78
79 // Mode colors (used for both borders and toaster)
80 defaultPaneModeColor = "#4A90E2" // Blue for pane mode
81 defaultTabModeColor = "#FFA500" // Orange for tab mode
82 defaultSessionModeColor = "#9B59B6" // Purple for session mode
83 defaultVimModeColor = "#F7768E"
84 defaultResizeModeColor = "#00D4AA" // Cyan/teal for resize mode
85
86 // Mode indicator toaster
87 defaultModeIndicatorToasterEnabled = true
88
89 // Other styling
90 defaultTransitionDuration = 120
91 defaultUIScale = 1.0 // UI scale multiplier (1.0 = 100%, 1.2 = 120%)
92
93 // Performance defaults
94 defaultZoomCacheSize = 256 // domains to cache (~20KB memory)
95 defaultWebViewPoolPrewarmCount = 4 // WebViews to pre-create at startup
96 defaultCEFWindowlessFrameRate = 60 // static OSR frame rate when adaptive CEF pacing is disabled
97 defaultCEFWindowlessFrameRateMax = 240 // adaptive OSR frame-rate hard cap
98 defaultCEFScrollMultiplier = 1.0
99 defaultCEFScrollPreciseMultiplier = 2.5
100 defaultCEFScrollMaxDelta = 0
101 defaultCEFScrollTouchpadInertia = true
102 defaultCEFScrollWheelSmoothing = true
103 defaultCEFTouchpadNavigation = true
104 // Require a deliberate swipe before history navigation so ordinary
105 // horizontal scrolling is unlikely to cross the commit threshold.
106 defaultCEFTouchpadNavigationDelta = 320.0
107 defaultCEFTouchpadNavigationRatio = 0.5
108
109 // Skia threading defaults (0 = unset, -1 = unset for GPU threads)
110 defaultSkiaCPUPaintingThreads = 0
111 defaultSkiaGPUPaintingThreads = -1 // -1 means unset; 0 would disable GPU tile painting
112)
113
114func defaultBrowsingContextConfig() BrowsingContextConfig {
115 return BrowsingContextConfig{
116 Behavior: PopupBehaviorSplit,
117 Placement: defaultPopupPlacement,
118 OpenInNewPane: true,
119 FollowPaneContext: true,
120 BlankTargetBehavior: "stacked",
121 EnableSmartDetection: true,
122 OAuthAutoClose: true,
123 }
124}
125
126// getDefaultLogDir returns the default log directory, falls back to empty string on error
127func getDefaultLogDir() string {
128 logDir, err := GetLogDir()
129 if err != nil {
130 return ""
131 }
132 return logDir
133}
134
135// getDefaultExternalThemePath returns Noctalia's native colors.json path.
136func getDefaultExternalThemePath() string {
137 return getDefaultExternalThemePathForFormat(defaultExternalThemeFormat)
138}
139
140func getDefaultExternalThemePathForFormat(format string) string {
141 switch format {
142 case defaultExternalThemeTemplateFormat:
143 return getDefaultExternalThemeTemplatePath()
144 default:
145 return getDefaultNoctaliaColorsPath()
146 }
147}
148
149func getDefaultNoctaliaColorsPath() string {
150 configHome, err := os.UserConfigDir()
151 if err != nil {
152 return ""
153 }
154 return filepath.Join(configHome, defaultExternalThemeProvider, defaultExternalThemeColorsFilename)
155}
156
157func getDefaultExternalThemeTemplatePath() string {
158 configDir, err := GetConfigDir()
159 if err != nil {
160 return ""
161 }
162 return filepath.Join(configDir, defaultExternalThemeTemplateFilename)
163}
164
165// withBuiltinGlobalShortcuts adds the preset-independent browser shortcuts
166// to the configured global shortcut defaults.
167func withBuiltinGlobalShortcuts(actions map[string]ActionBinding) map[string]ActionBinding {
168 maps.Copy(actions, entity.BuiltinGlobalShortcuts())
169 return actions
170}
171
172// DefaultConfig returns the default configuration values for dumber.
173func DefaultConfig() *Config {
174 browsingContextDefaults := defaultBrowsingContextConfig()
175
176 return &Config{
177 Database: DatabaseConfig{
178 // Path is set dynamically in config.Load()
179 },
180 History: HistoryConfig{
181 MaxEntries: defaultMaxHistoryEntries,
182 RetentionPeriodDays: defaultRetentionDays, // 1 year
183 CleanupIntervalDays: 1, // daily cleanup
184 },
185 SearchShortcuts: GetDefaultSearchShortcuts(),
186 DefaultSearchEngine: "https://duckduckgo.com/?q=%s",
187 Dmenu: DmenuConfig{
188 MaxHistoryDays: defaultMaxHistoryDays,
189 ShowVisitCount: true,
190 ShowLastVisited: true,
191 HistoryPrefix: "🕒",
192 ShortcutPrefix: "🔍",
193 URLPrefix: "🌐",
194 DateFormat: "2006-01-02 15:04",
195 SortByVisitCount: true,
196 },
197 Logging: LoggingConfig{
198 Level: "info",
199 Format: "text", // text or json
200 MaxAge: defaultMaxLogAgeDays,
201 MaxFiles: defaultMaxLogFiles,
202 LogDir: getDefaultLogDir(),
203 EnableFileLog: true,
204 CaptureConsole: false, // Disabled by default
205 CaptureGTKLogs: false, // Disabled by default
206 },
207 Appearance: AppearanceConfig{
208 SansFont: "Fira Sans",
209 SerifFont: "Fira Sans",
210 MonospaceFont: "Fira Code",
211 GtkFont: "Adwaita Sans",
212 DefaultFontSize: defaultFontSize,
213 LightPalette: ColorPalette{
214 Background: "#fafafa",
215 Surface: "#f4f4f5",
216 SurfaceVariant: "#e4e4e7",
217 Text: "#18181b",
218 Muted: "#71717a",
219 Accent: "#22c55e", // Green-500 - vibrant primary
220 Border: "#d4d4d8",
221 },
222 DarkPalette: ColorPalette{
223 Background: "#0a0a0b",
224 Surface: "#18181b",
225 SurfaceVariant: "#27272a",
226 Text: "#fafafa",
227 Muted: "#a1a1aa",
228 Accent: "#4ade80", // Green-400 - vibrant primary
229 Border: "#3f3f46",
230 },
231 ColorScheme: "default", // default follows system theme
232 ExternalTheme: entity.ExternalThemeConfig{
233 Enabled: false,
234 Provider: defaultExternalThemeProvider,
235 Format: defaultExternalThemeFormat,
236 Path: getDefaultExternalThemePath(),
237 },
238 },
239 Debug: DebugConfig{
240 EnableDevTools: true,
241 },
242 Engine: EngineConfig{
243 Type: EngineTypeCEF,
244 Profile: ProfileDefault,
245 PoolPrewarmCount: defaultWebViewPoolPrewarmCount,
246 ZoomCacheSize: defaultZoomCacheSize,
247 // With ITP enabled, WebKit ignores ACCEPT_NO_THIRD_PARTY — ITP handles
248 // third-party cookie isolation more intelligently. Using Always + ITP
249 // matches Epiphany's model and avoids a misleading setting.
250 CookiePolicy: CookiePolicyAlways,
251 CEF: CEFEngineConfig{
252 RenderStack: CEFRenderStackVulkan,
253 AdaptiveWindowlessFrameRate: true,
254 WindowlessFrameRate: 0,
255 WindowlessFrameRateMax: defaultCEFWindowlessFrameRateMax,
256 LogFile: "",
257 EnableAudioHandler: true,
258 Input: CEFInputConfig{
259 ScrollWheelMultiplier: defaultCEFScrollMultiplier,
260 ScrollPreciseMultiplier: defaultCEFScrollPreciseMultiplier,
261 ScrollHorizontalMultiplier: defaultCEFScrollMultiplier,
262 ScrollVerticalMultiplier: defaultCEFScrollMultiplier,
263 ScrollMaxDelta: defaultCEFScrollMaxDelta,
264 ScrollTouchpadInertia: defaultCEFScrollTouchpadInertia,
265 ScrollWheelSmoothing: defaultCEFScrollWheelSmoothing,
266 TouchpadNavigationEnabled: defaultCEFTouchpadNavigation,
267 TouchpadNavigationMinDelta: defaultCEFTouchpadNavigationDelta,
268 TouchpadNavigationMaxVerticalRatio: defaultCEFTouchpadNavigationRatio,
269 },
270 },
271 WebKit: WebKitEngineConfig{
272 ITPEnabled: true,
273 SkiaCPUPaintingThreads: defaultSkiaCPUPaintingThreads,
274 SkiaGPUPaintingThreads: defaultSkiaGPUPaintingThreads,
275 GSKRenderer: GSKRendererAuto,
276 GLRenderingMode: GLRenderingModeAuto,
277 },
278 },
279 DefaultWebpageZoom: 1.2, // 120% default zoom for better readability
280 DefaultUIScale: defaultUIScale, // 1.0 = 100%, 2.0 = 200%
281 SidebarWidth: defaultSidebarWidth, // 320px, clamped to [280, 380]
282 Workspace: WorkspaceConfig{
283 NewPaneURL: defaultNewPaneURL,
284 SwitchToTabOnMove: true,
285 Keymap: defaultKeymap,
286 PrefixMode: PrefixModeConfig{
287 ActivationShortcut: defaultPrefixActivationShortcut,
288 TimeoutMilliseconds: defaultPrefixTimeoutMilliseconds,
289 Actions: map[string]ActionBinding{
290 "split-right": {Keys: []string{"%"}, Desc: "Split pane to the right"},
291 "split-down": {Keys: []string{"\""}, Desc: "Split pane downward"},
292 "close-pane": {Keys: []string{"x"}, Desc: "Close current pane"},
293 "stack-pane": {Keys: []string{"shift+s"}, Desc: "Stack pane with sibling"},
294 "move-pane-to-tab": {Keys: []string{"!"}, Desc: "Move pane to different tab"},
295 "focus-left": {Keys: []string{"arrowleft"}, Desc: "Focus pane to the left"},
296 "focus-right": {Keys: []string{"arrowright"}, Desc: "Focus pane to the right"},
297 "focus-up": {Keys: []string{"arrowup"}, Desc: "Focus pane above"},
298 "focus-down": {Keys: []string{"arrowdown"}, Desc: "Focus pane below"},
299 "new-tab": {Keys: []string{"c"}, Desc: "Create new tab"},
300 "close-tab": {Keys: []string{"&"}, Desc: "Close current tab"},
301 "next-tab": {Keys: []string{"n"}, Desc: "Switch to next tab"},
302 "previous-tab": {Keys: []string{"p"}, Desc: "Switch to previous tab"},
303 "rename-tab": {Keys: []string{","}, Desc: "Rename current tab"},
304 "session-manager": {Keys: []string{"s"}, Desc: "Open session manager"},
305 "enter-resize-mode": {Keys: []string{"r"}, Desc: "Enter resize mode"},
306 "enter-vim-mode": {Keys: []string{"["}, Desc: "Enter Vim mode"},
307 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit prefix"},
308 },
309 },
310 PaneMode: PaneModeConfig{
311 ActivationShortcut: defaultPaneActivationShortcut,
312 TimeoutMilliseconds: defaultPaneTimeoutMilliseconds,
313 Actions: map[string]ActionBinding{
314 "split-right": {Keys: []string{"arrowright", "r"}, Desc: "Split pane to the right"},
315 "split-left": {Keys: []string{"arrowleft", "l"}, Desc: "Split pane to the left"},
316 "split-up": {Keys: []string{"arrowup", "u"}, Desc: "Split pane upward"},
317 "split-down": {Keys: []string{"arrowdown", "d"}, Desc: "Split pane downward"},
318 "stack-pane": {Keys: []string{"s"}, Desc: "Stack pane with sibling"},
319 "close-pane": {Keys: []string{"x"}, Desc: "Close current pane"},
320 "move-pane-to-tab": {Keys: []string{"m"}, Desc: "Move pane to different tab"},
321 "move-pane-to-next-tab": {Keys: []string{"M", "shift+m"}, Desc: "Move pane to next tab"},
322 "eject-pane-to-window": {Keys: []string{"w"}, Desc: "Eject active pane to a new window"},
323
324 "consume-or-expel-left": {Keys: []string{"["}, Desc: "Consume/expel pane left"},
325 "consume-or-expel-right": {Keys: []string{"]"}, Desc: "Consume/expel pane right"},
326 "consume-or-expel-up": {Keys: []string{"{"}, Desc: "Consume/expel pane up"},
327 "consume-or-expel-down": {Keys: []string{"}"}, Desc: "Consume/expel pane down"},
328
329 "focus-right": {Keys: []string{"shift+arrowright", "shift+l"}, Desc: "Focus pane to the right"},
330 "focus-left": {Keys: []string{"shift+arrowleft", "shift+h"}, Desc: "Focus pane to the left"},
331 "focus-up": {Keys: []string{"shift+arrowup", "shift+k"}, Desc: "Focus pane above"},
332 "focus-down": {Keys: []string{"shift+arrowdown", "shift+j"}, Desc: "Focus pane below"},
333 "confirm": {Keys: []string{"enter"}, Desc: "Confirm action"},
334 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit mode"},
335 },
336 },
337 TabMode: TabModeConfig{
338 ActivationShortcut: defaultTabActivationShortcut,
339 TimeoutMilliseconds: defaultTabTimeoutMilliseconds,
340 Actions: map[string]ActionBinding{
341 "new-tab": {Keys: []string{"n", "c"}, Desc: "Create new tab"},
342 "close-tab": {Keys: []string{"x"}, Desc: "Close current tab"},
343 "next-tab": {Keys: []string{"l", "tab"}, Desc: "Switch to next tab"},
344 "previous-tab": {Keys: []string{"h", "shift+tab"}, Desc: "Switch to previous tab"},
345 "rename-tab": {Keys: []string{"r"}, Desc: "Rename current tab"},
346 "confirm": {Keys: []string{"enter"}, Desc: "Confirm action"},
347 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit mode"},
348 },
349 },
350 VimMode: VimModeConfig{
351 ActivationShortcut: defaultPageActivationShortcut,
352 TimeoutMilliseconds: defaultPageTimeoutMilliseconds,
353 SequenceTimeoutMilliseconds: defaultPageSequenceTimeoutMilliseconds,
354 Actions: map[string]ActionBinding{
355 "vim-scroll-left": {Keys: []string{"h"}, Desc: "Scroll page left"},
356 "vim-scroll-down": {Keys: []string{"j"}, Desc: "Scroll page down"},
357 "vim-scroll-up": {Keys: []string{"k"}, Desc: "Scroll page up"},
358 "vim-scroll-right": {Keys: []string{"l"}, Desc: "Scroll page right"},
359 "vim-scroll-down-fast": {Keys: []string{"shift+j"}, Desc: "Scroll page down fast"},
360 "vim-scroll-up-fast": {Keys: []string{"shift+k"}, Desc: "Scroll page up fast"},
361 "confirm": {Keys: []string{"enter"}, Desc: "Open selected heading link and exit mode"},
362 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit mode"},
363 "heading-next": {Keys: []string{"]]"}, Desc: "Jump to next heading"},
364 "heading-prev": {Keys: []string{"[["}, Desc: "Jump to previous heading"},
365 "focus-input": {Keys: []string{"gi"}, Desc: "Focus next page input"},
366 "code-next": {Keys: []string{"]c"}, Desc: "Jump to next code block"},
367 "code-prev": {Keys: []string{"[c"}, Desc: "Jump to previous code block"},
368 "table-next": {Keys: []string{"]t"}, Desc: "Jump to next table"},
369 "image-next": {Keys: []string{"]i"}, Desc: "Jump to next image"},
370 "list-next": {Keys: []string{"]l"}, Desc: "Jump to next list"},
371 "outline": {Keys: []string{"gO"}, Desc: "Show page outline"},
372 "yank-section": {Keys: []string{"yah"}, Desc: "Yank current section"},
373 "half-page-down": {Keys: []string{"<C-d>"}, Desc: "Scroll half page down"},
374 "half-page-up": {Keys: []string{"<C-u>"}, Desc: "Scroll half page up"},
375 },
376 },
377 ResizeMode: ResizeModeConfig{
378 ActivationShortcut: defaultResizeActivationShortcut,
379 TimeoutMilliseconds: defaultResizeTimeoutMilliseconds,
380 StepPercent: defaultResizeStepPercent,
381 MinPanePercent: defaultResizeMinPanePercent,
382 Actions: map[string]ActionBinding{
383 "resize-increase-left": {Keys: []string{"h", "arrowleft"}, Desc: "Increase size leftward"},
384 "resize-increase-down": {Keys: []string{"j", "arrowdown"}, Desc: "Increase size downward"},
385 "resize-increase-up": {Keys: []string{"k", "arrowup"}, Desc: "Increase size upward"},
386 "resize-increase-right": {Keys: []string{"l", "arrowright"}, Desc: "Increase size rightward"},
387 "resize-decrease-left": {Keys: []string{"H"}, Desc: "Decrease size leftward"},
388 "resize-decrease-down": {Keys: []string{"J"}, Desc: "Decrease size downward"},
389 "resize-decrease-up": {Keys: []string{"K"}, Desc: "Decrease size upward"},
390 "resize-decrease-right": {Keys: []string{"L"}, Desc: "Decrease size rightward"},
391 "resize-increase": {Keys: []string{"+", "="}, Desc: "Increase pane size"},
392 "resize-decrease": {Keys: []string{"-"}, Desc: "Decrease pane size"},
393 "confirm": {Keys: []string{"enter"}, Desc: "Confirm action"},
394 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit mode"},
395 },
396 },
397 Shortcuts: GlobalShortcutsConfig{
398 Actions: withBuiltinGlobalShortcuts(map[string]ActionBinding{
399 "toggle-floating-pane": {Keys: []string{"alt+f"}, Desc: "Toggle floating pane"},
400 "toggle-history-systemview": {Keys: []string{"ctrl+h"}, Desc: "Toggle History in right split"},
401 "toggle-favorites-sidebar": {Keys: []string{"ctrl+b"}, Desc: "Toggle Favorites sidebar"},
402 "toggle-current-page-favorite": {Keys: []string{"ctrl+d"}, Desc: "Add/remove current page favorite"},
403 "toggle-config-systemview": {Keys: []string{}, Desc: "Toggle Config in right split"},
404 "close-pane": {Keys: []string{"ctrl+w"}, Desc: "Close active pane"},
405 "next-tab": {Keys: []string{"ctrl+tab"}, Desc: "Switch to next tab"},
406 "previous-tab": {Keys: []string{"ctrl+shift+tab"}, Desc: "Switch to previous tab"},
407 "consume-or-expel-left": {Keys: []string{"alt+["}, Desc: "Consume/expel pane left"},
408 "consume-or-expel-right": {Keys: []string{"alt+]"}, Desc: "Consume/expel pane right"},
409 "consume-or-expel-up": {Keys: []string{"alt+{"}, Desc: "Consume/expel pane up"},
410 "consume-or-expel-down": {Keys: []string{"alt+}"}, Desc: "Consume/expel pane down"},
411 }),
412 },
413 FloatingPane: FloatingPaneConfig{
414 WidthPct: defaultFloatingPaneWidthPct,
415 HeightPct: defaultFloatingPaneHeightPct,
416 Profiles: map[string]FloatingPaneProfile{},
417 },
418 ExternalLinks: ExternalLinksConfig{
419 Behavior: defaultExternalLinkBehavior,
420 Placement: defaultExternalLinkPlacement,
421 },
422 TabBarPosition: defaultTabBarPosition,
423 HideTabBarWhenSingleTab: true,
424 BrowsingContexts: browsingContextDefaults,
425 Popups: browsingContextDefaults,
426 Styling: WorkspaceStylingConfig{
427 BorderWidth: defaultBorderWidth,
428 BorderColor: defaultBorderColor,
429 ModeBorderWidth: defaultModeBorderWidth,
430 PaneModeColor: defaultPaneModeColor,
431 TabModeColor: defaultTabModeColor,
432 SessionModeColor: defaultSessionModeColor,
433 ResizeModeColor: defaultResizeModeColor,
434 VimModeColor: defaultVimModeColor,
435 ModeLegendLinger: true,
436 ModeIndicatorToasterEnabled: defaultModeIndicatorToasterEnabled,
437 ModeLegend: "delay",
438 ModeLegendDelayMs: 500,
439 ModeLegendAnimations: true,
440 TransitionDuration: defaultTransitionDuration,
441 },
442 },
443 ContentFiltering: ContentFilteringConfig{
444 Enabled: true, // Ad blocking enabled by default
445 AutoUpdate: true, // Auto-update filters from GitHub releases
446 },
447 Clipboard: ClipboardConfig{
448 AutoCopyOnSelection: true, // Enabled by default (zellij-style)
449 },
450 Omnibox: OmniboxConfig{
451 Style: defaultOmniboxStyle,
452 InitialBehavior: defaultOmniboxInitialBehavior,
453 MaxHistoryDays: defaultOmniboxMaxHistoryDays,
454 AutoOpenOnNewPane: defaultOmniboxAutoOpenOnNewPane,
455 },
456 Session: SessionConfig{
457 AutoRestore: false,
458 SnapshotIntervalMs: defaultSnapshotIntervalMs,
459 MaxExitedSessions: defaultMaxExitedSessions,
460 MaxExitedSessionAgeDays: defaultMaxExitedSessionAgeDays,
461 SessionMode: SessionModeConfig{
462 ActivationShortcut: defaultSessionActivationShortcut,
463 TimeoutMilliseconds: defaultSessionTimeoutMilliseconds,
464 Actions: map[string]ActionBinding{
465 "session-manager": {Keys: []string{"s", "w"}, Desc: "Open session manager"},
466 "confirm": {Keys: []string{"enter"}, Desc: "Confirm action"},
467 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit mode"},
468 },
469 },
470 },
471 Media: MediaConfig{
472 HardwareDecodingMode: HardwareDecodingAuto, // auto allows sw fallback
473 PreferAV1: false, // Don't force codec preference, let site choose
474 ShowDiagnosticsOnStartup: false, // Disabled - diagnostics can be noisy
475 // GStreamer fields (ForceVSync, GLRenderingMode, GStreamerDebugLevel)
476 // moved to [engine.webkit] — zero values here prevent them from being
477 // written back when marshaling the Config struct.
478 },
479 Update: UpdateConfig{
480 EnableOnStartup: true, // Check for updates on startup by default
481 AutoDownload: false, // Conservative: don't auto-download by default
482 NotifyOnNewSettings: true, // Show toast when new config settings available
483 },
484 Downloads: DownloadsConfig{
485 Path: "", // Empty = use XDG_DOWNLOAD_DIR or ~/Downloads
486 },
487 }
488}
489
490// GetDefaultSearchShortcuts returns the default search shortcuts.
491func GetDefaultSearchShortcuts() map[string]SearchShortcut {
492 return map[string]SearchShortcut{
493 "ddg": {
494 URL: "https://duckduckgo.com/?q=%s",
495 Description: "DuckDuckGo search",
496 },
497 "g": {
498 URL: "https://www.google.com/search?q=%s",
499 Description: "Google search",
500 },
501 "gi": {
502 URL: "https://www.google.com/search?tbm=isch&q=%s",
503 Description: "Google Images search",
504 },
505 "gh": {
506 URL: "https://github.com/search?q=%s",
507 Description: "GitHub search",
508 },
509 "go": {
510 URL: "https://pkg.go.dev/search?q=%s",
511 Description: "Go package search",
512 },
513 "mdn": {
514 URL: "https://developer.mozilla.org/en-US/search?q=%s",
515 Description: "MDN Web Docs search",
516 },
517 "npm": {
518 URL: "https://www.npmjs.com/search?q=%s",
519 Description: "npm package search",
520 },
521 "r": {
522 URL: "https://www.reddit.com/search?q=%s",
523 Description: "Reddit search",
524 },
525 "so": {
526 URL: "https://stackoverflow.com/search?q=%s",
527 Description: "Stack Overflow search",
528 },
529 "w": {
530 URL: "https://en.wikipedia.org/wiki/%s",
531 Description: "Wikipedia search",
532 },
533 "yt": {
534 URL: "https://www.youtube.com/results?search_query=%s",
535 Description: "YouTube search",
536 },
537 }
538}