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 "yank-paragraph": {Keys: []string{"yap"}, Desc: "Yank first visible paragraph"},
374 "yank-code": {Keys: []string{"yac"}, Desc: "Yank first visible code block"},
375 "yank-table": {Keys: []string{"yat"}, Desc: "Yank first visible table"},
376 "yank-list": {Keys: []string{"yal"}, Desc: "Yank first visible list"},
377 "hint-follow": {Keys: []string{"f"}, Desc: "Show hints and follow a link or control"},
378 "hint-follow-new": {Keys: []string{"F"}, Desc: "Show hints and open a link in a new pane"},
379 "hint-yank-url": {Keys: []string{"yf"}, Desc: "Show hints and yank a link URL"},
380 "visual": {Keys: []string{"v"}, Desc: "Start visual selection (motions extend, y yanks)"},
381 "half-page-down": {Keys: []string{"<C-d>"}, Desc: "Scroll half page down"},
382 "half-page-up": {Keys: []string{"<C-u>"}, Desc: "Scroll half page up"},
383 },
384 },
385 ResizeMode: ResizeModeConfig{
386 ActivationShortcut: defaultResizeActivationShortcut,
387 TimeoutMilliseconds: defaultResizeTimeoutMilliseconds,
388 StepPercent: defaultResizeStepPercent,
389 MinPanePercent: defaultResizeMinPanePercent,
390 Actions: map[string]ActionBinding{
391 "resize-increase-left": {Keys: []string{"h", "arrowleft"}, Desc: "Increase size leftward"},
392 "resize-increase-down": {Keys: []string{"j", "arrowdown"}, Desc: "Increase size downward"},
393 "resize-increase-up": {Keys: []string{"k", "arrowup"}, Desc: "Increase size upward"},
394 "resize-increase-right": {Keys: []string{"l", "arrowright"}, Desc: "Increase size rightward"},
395 "resize-decrease-left": {Keys: []string{"H"}, Desc: "Decrease size leftward"},
396 "resize-decrease-down": {Keys: []string{"J"}, Desc: "Decrease size downward"},
397 "resize-decrease-up": {Keys: []string{"K"}, Desc: "Decrease size upward"},
398 "resize-decrease-right": {Keys: []string{"L"}, Desc: "Decrease size rightward"},
399 "resize-increase": {Keys: []string{"+", "="}, Desc: "Increase pane size"},
400 "resize-decrease": {Keys: []string{"-"}, Desc: "Decrease pane size"},
401 "confirm": {Keys: []string{"enter"}, Desc: "Confirm action"},
402 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit mode"},
403 },
404 },
405 Shortcuts: GlobalShortcutsConfig{
406 Actions: withBuiltinGlobalShortcuts(map[string]ActionBinding{
407 "toggle-floating-pane": {Keys: []string{"alt+f"}, Desc: "Toggle floating pane"},
408 "toggle-history-systemview": {Keys: []string{"ctrl+h"}, Desc: "Toggle History in right split"},
409 "toggle-favorites-sidebar": {Keys: []string{"ctrl+b"}, Desc: "Toggle Favorites sidebar"},
410 "toggle-current-page-favorite": {Keys: []string{"ctrl+d"}, Desc: "Add/remove current page favorite"},
411 "toggle-config-systemview": {Keys: []string{}, Desc: "Toggle Config in right split"},
412 "close-pane": {Keys: []string{"ctrl+w"}, Desc: "Close active pane"},
413 "next-tab": {Keys: []string{"ctrl+tab"}, Desc: "Switch to next tab"},
414 "previous-tab": {Keys: []string{"ctrl+shift+tab"}, Desc: "Switch to previous tab"},
415 "consume-or-expel-left": {Keys: []string{"alt+["}, Desc: "Consume/expel pane left"},
416 "consume-or-expel-right": {Keys: []string{"alt+]"}, Desc: "Consume/expel pane right"},
417 "consume-or-expel-up": {Keys: []string{"alt+{"}, Desc: "Consume/expel pane up"},
418 "consume-or-expel-down": {Keys: []string{"alt+}"}, Desc: "Consume/expel pane down"},
419 }),
420 },
421 FloatingPane: FloatingPaneConfig{
422 WidthPct: defaultFloatingPaneWidthPct,
423 HeightPct: defaultFloatingPaneHeightPct,
424 Profiles: map[string]FloatingPaneProfile{},
425 },
426 ExternalLinks: ExternalLinksConfig{
427 Behavior: defaultExternalLinkBehavior,
428 Placement: defaultExternalLinkPlacement,
429 },
430 TabBarPosition: defaultTabBarPosition,
431 HideTabBarWhenSingleTab: true,
432 BrowsingContexts: browsingContextDefaults,
433 Popups: browsingContextDefaults,
434 Styling: WorkspaceStylingConfig{
435 BorderWidth: defaultBorderWidth,
436 BorderColor: defaultBorderColor,
437 ModeBorderWidth: defaultModeBorderWidth,
438 PaneModeColor: defaultPaneModeColor,
439 TabModeColor: defaultTabModeColor,
440 SessionModeColor: defaultSessionModeColor,
441 ResizeModeColor: defaultResizeModeColor,
442 VimModeColor: defaultVimModeColor,
443 ModeLegendLinger: true,
444 ModeIndicatorToasterEnabled: defaultModeIndicatorToasterEnabled,
445 ModeLegend: "delay",
446 ModeLegendDelayMs: 500,
447 ModeLegendAnimations: true,
448 ModeLegendCollapsed: false,
449 TransitionDuration: defaultTransitionDuration,
450 },
451 },
452 ContentFiltering: ContentFilteringConfig{
453 Enabled: true, // Ad blocking enabled by default
454 AutoUpdate: true, // Auto-update filters from GitHub releases
455 },
456 Clipboard: ClipboardConfig{
457 AutoCopyOnSelection: true, // Enabled by default (zellij-style)
458 },
459 Omnibox: OmniboxConfig{
460 Style: defaultOmniboxStyle,
461 InitialBehavior: defaultOmniboxInitialBehavior,
462 MaxHistoryDays: defaultOmniboxMaxHistoryDays,
463 AutoOpenOnNewPane: defaultOmniboxAutoOpenOnNewPane,
464 },
465 Session: SessionConfig{
466 AutoRestore: false,
467 SnapshotIntervalMs: defaultSnapshotIntervalMs,
468 MaxExitedSessions: defaultMaxExitedSessions,
469 MaxExitedSessionAgeDays: defaultMaxExitedSessionAgeDays,
470 SessionMode: SessionModeConfig{
471 ActivationShortcut: defaultSessionActivationShortcut,
472 TimeoutMilliseconds: defaultSessionTimeoutMilliseconds,
473 Actions: map[string]ActionBinding{
474 "session-manager": {Keys: []string{"s", "w"}, Desc: "Open session manager"},
475 "confirm": {Keys: []string{"enter"}, Desc: "Confirm action"},
476 "cancel": {Keys: []string{"escape"}, Desc: "Cancel/exit mode"},
477 },
478 },
479 },
480 Media: MediaConfig{
481 HardwareDecodingMode: HardwareDecodingAuto, // auto allows sw fallback
482 PreferAV1: false, // Don't force codec preference, let site choose
483 ShowDiagnosticsOnStartup: false, // Disabled - diagnostics can be noisy
484 // GStreamer fields (ForceVSync, GLRenderingMode, GStreamerDebugLevel)
485 // moved to [engine.webkit] — zero values here prevent them from being
486 // written back when marshaling the Config struct.
487 },
488 Update: UpdateConfig{
489 EnableOnStartup: true, // Check for updates on startup by default
490 AutoDownload: false, // Conservative: don't auto-download by default
491 NotifyOnNewSettings: true, // Show toast when new config settings available
492 },
493 Downloads: DownloadsConfig{
494 Path: "", // Empty = use XDG_DOWNLOAD_DIR or ~/Downloads
495 },
496 }
497}
498
499// GetDefaultSearchShortcuts returns the default search shortcuts.
500func GetDefaultSearchShortcuts() map[string]SearchShortcut {
501 return map[string]SearchShortcut{
502 "ddg": {
503 URL: "https://duckduckgo.com/?q=%s",
504 Description: "DuckDuckGo search",
505 },
506 "g": {
507 URL: "https://www.google.com/search?q=%s",
508 Description: "Google search",
509 },
510 "gi": {
511 URL: "https://www.google.com/search?tbm=isch&q=%s",
512 Description: "Google Images search",
513 },
514 "gh": {
515 URL: "https://github.com/search?q=%s",
516 Description: "GitHub search",
517 },
518 "go": {
519 URL: "https://pkg.go.dev/search?q=%s",
520 Description: "Go package search",
521 },
522 "mdn": {
523 URL: "https://developer.mozilla.org/en-US/search?q=%s",
524 Description: "MDN Web Docs search",
525 },
526 "npm": {
527 URL: "https://www.npmjs.com/search?q=%s",
528 Description: "npm package search",
529 },
530 "r": {
531 URL: "https://www.reddit.com/search?q=%s",
532 Description: "Reddit search",
533 },
534 "so": {
535 URL: "https://stackoverflow.com/search?q=%s",
536 Description: "Stack Overflow search",
537 },
538 "w": {
539 URL: "https://en.wikipedia.org/wiki/%s",
540 Description: "Wikipedia search",
541 },
542 "yt": {
543 URL: "https://www.youtube.com/results?search_query=%s",
544 Description: "YouTube search",
545 },
546 }
547}