1package config
2
3import (
4 "fmt"
5
6 "github.com/bnema/dumber/internal/domain/entity"
7)
8
9// Section names for grouping config keys.
10const (
11 SectionAppearance = "Appearance"
12 SectionLogging = "Logging"
13 SectionHistory = "History"
14 SectionWorkspace = "Workspace"
15 SectionSession = "Session"
16 SectionOmnibox = "Omnibox"
17 SectionClipboard = "Clipboard"
18 SectionContentFiltering = "Content Filtering"
19 SectionRendering = "Rendering"
20 SectionMedia = "Media"
21 SectionPrivacy = "Privacy"
22 SectionUpdate = "Update"
23 SectionDmenu = "Dmenu"
24 SectionDebug = "Debug"
25 SectionPerformance = "Performance"
26 SectionRuntime = "Runtime"
27 SectionDatabase = "Database"
28 SectionSearch = "Search"
29 SectionDownloads = "Downloads"
30)
31
32// SchemaProvider implements port.ConfigSchemaProvider.
33type SchemaProvider struct{}
34
35// NewSchemaProvider creates a new SchemaProvider.
36func NewSchemaProvider() *SchemaProvider {
37 return &SchemaProvider{}
38}
39
40// GetSchema returns all configuration keys with their metadata.
41func (p *SchemaProvider) GetSchema() []entity.ConfigKeyInfo {
42 defaults := DefaultConfig()
43
44 keys := make([]entity.ConfigKeyInfo, 0, 100)
45
46 // Appearance section
47 keys = append(keys, p.getAppearanceKeys(defaults)...)
48
49 // Logging section
50 keys = append(keys, p.getLoggingKeys(defaults)...)
51
52 // History section
53 keys = append(keys, p.getHistoryKeys(defaults)...)
54
55 // Search section
56 keys = append(keys, p.getSearchKeys(defaults)...)
57
58 // Dmenu section
59 keys = append(keys, p.getDmenuKeys(defaults)...)
60
61 // Workspace section
62 keys = append(keys, p.getWorkspaceKeys(defaults)...)
63
64 // Session section
65 keys = append(keys, p.getSessionKeys(defaults)...)
66
67 // Omnibox section
68 keys = append(keys, p.getOmniboxKeys(defaults)...)
69
70 // Clipboard section
71 keys = append(keys, p.getClipboardKeys(defaults)...)
72
73 // Content Filtering section
74 keys = append(keys, p.getContentFilteringKeys(defaults)...)
75
76 // Rendering section
77 keys = append(keys, p.getRenderingKeys(defaults)...)
78
79 // Media section
80 keys = append(keys, p.getMediaKeys(defaults)...)
81
82 // Privacy section
83 keys = append(keys, p.getPrivacyKeys(defaults)...)
84
85 // Update section
86 keys = append(keys, p.getUpdateKeys(defaults)...)
87
88 // Debug section
89 keys = append(keys, p.getDebugKeys(defaults)...)
90
91 // Performance section
92 keys = append(keys, p.getPerformanceKeys(defaults)...)
93
94 // Runtime section
95 keys = append(keys, p.getRuntimeKeys(defaults)...)
96
97 // Database section
98 keys = append(keys, p.getDatabaseKeys()...)
99
100 // Downloads section
101 keys = append(keys, p.getDownloadsKeys(defaults)...)
102
103 return keys
104}
105
106func (*SchemaProvider) getAppearanceKeys(defaults *Config) []entity.ConfigKeyInfo {
107 return []entity.ConfigKeyInfo{
108 {
109 Key: "appearance.color_scheme",
110 Type: "string",
111 Default: defaults.Appearance.ColorScheme,
112 Description: "Theme preference (follows system by default)",
113 Values: []string{"default", "prefer-dark", "prefer-light"},
114 Section: SectionAppearance,
115 },
116 {
117 Key: "appearance.default_font_size",
118 Type: "int",
119 Default: fmt.Sprintf("%d", defaults.Appearance.DefaultFontSize),
120 Description: "Default font size in CSS pixels",
121 Range: "1-72",
122 Section: SectionAppearance,
123 },
124 {
125 Key: "appearance.sans_font",
126 Type: "string",
127 Default: defaults.Appearance.SansFont,
128 Description: "Sans-serif font family for web pages",
129 Section: SectionAppearance,
130 },
131 {
132 Key: "appearance.serif_font",
133 Type: "string",
134 Default: defaults.Appearance.SerifFont,
135 Description: "Serif font family for web pages",
136 Section: SectionAppearance,
137 },
138 {
139 Key: "appearance.monospace_font",
140 Type: "string",
141 Default: defaults.Appearance.MonospaceFont,
142 Description: "Monospace font family for code",
143 Section: SectionAppearance,
144 },
145 {
146 Key: "appearance.gtk_font",
147 Type: "string",
148 Default: defaults.Appearance.GtkFont,
149 Description: "Native GTK UI font family for app chrome",
150 Section: SectionAppearance,
151 },
152 {
153 Key: "default_webpage_zoom",
154 Type: "float64",
155 Default: fmt.Sprintf("%.1f", defaults.DefaultWebpageZoom),
156 Description: "Default zoom level for web pages (1.0 = 100%%)",
157 Range: "0.1-5.0",
158 Section: SectionAppearance,
159 },
160 {
161 Key: "default_ui_scale",
162 Type: "float64",
163 Default: fmt.Sprintf("%.1f", defaults.DefaultUIScale),
164 Description: "UI scale multiplier for GTK widgets",
165 Range: "0.5-3.0",
166 Section: SectionAppearance,
167 },
168 {
169 Key: "sidebar_width",
170 Type: "int",
171 Default: fmt.Sprintf("%d", defaults.SidebarWidth),
172 Description: "Preferred width (px) for the history sidebar. 0 = default",
173 Range: "0 or 280-380",
174 Section: SectionAppearance,
175 },
176 {
177 Key: "appearance.light_palette.*",
178 Type: "string",
179 Default: "(hex colors)",
180 Description: "Light theme color palette (background, surface, surface_variant, text, muted, accent, border)",
181 Section: SectionAppearance,
182 },
183 {
184 Key: "appearance.dark_palette.*",
185 Type: "string",
186 Default: "(hex colors)",
187 Description: "Dark theme color palette (background, surface, surface_variant, text, muted, accent, border)",
188 Section: SectionAppearance,
189 },
190 {
191 Key: "appearance.external_theme.enabled",
192 Type: "bool",
193 Default: fmt.Sprintf("%t", defaults.Appearance.ExternalTheme.Enabled),
194 Description: "Enable loading theme settings from an external provider",
195 Section: SectionAppearance,
196 },
197 {
198 Key: "appearance.external_theme.provider",
199 Type: "string",
200 Default: defaults.Appearance.ExternalTheme.Provider,
201 Description: "External theme provider",
202 Values: []string{"noctalia"},
203 Section: SectionAppearance,
204 },
205 {
206 Key: "appearance.external_theme.format",
207 Type: "string",
208 Default: defaults.Appearance.ExternalTheme.Format,
209 Description: "External theme file format",
210 Values: []string{"colors-json", "dumber-json"},
211 Section: SectionAppearance,
212 },
213 {
214 Key: "appearance.external_theme.path",
215 Type: "string",
216 Default: defaults.Appearance.ExternalTheme.Path,
217 Description: "Path to the external theme file",
218 Section: SectionAppearance,
219 },
220 }
221}
222
223func (*SchemaProvider) getLoggingKeys(defaults *Config) []entity.ConfigKeyInfo {
224 return []entity.ConfigKeyInfo{
225 {
226 Key: "logging.level",
227 Type: "string",
228 Default: defaults.Logging.Level,
229 Description: "Log verbosity level",
230 Values: []string{"trace", "debug", "info", "warn", "error", "fatal"},
231 Section: SectionLogging,
232 },
233 {
234 Key: "logging.format",
235 Type: "string",
236 Default: defaults.Logging.Format,
237 Description: "Log output format",
238 Values: []string{"text", "json", "console"},
239 Section: SectionLogging,
240 },
241 {
242 Key: "logging.max_age",
243 Type: "int",
244 Default: fmt.Sprintf("%d", defaults.Logging.MaxAge),
245 Description: "Maximum age of log files in days",
246 Range: ">=0",
247 Section: SectionLogging,
248 },
249 {
250 Key: "logging.max_files",
251 Type: "int",
252 Default: fmt.Sprintf("%d", defaults.Logging.MaxFiles),
253 Description: "Maximum number of session log files to keep (0 disables count-based cleanup)",
254 Range: ">=0",
255 Section: SectionLogging,
256 },
257 {
258 Key: "logging.log_dir",
259 Type: "string",
260 Default: defaults.Logging.LogDir,
261 Description: "Directory for log files",
262 Section: SectionLogging,
263 },
264 {
265 Key: "logging.enable_file_log",
266 Type: "bool",
267 Default: fmt.Sprintf("%t", defaults.Logging.EnableFileLog),
268 Description: "Enable logging to file",
269 Section: SectionLogging,
270 },
271 {
272 Key: "logging.capture_console",
273 Type: "bool",
274 Default: fmt.Sprintf("%t", defaults.Logging.CaptureConsole),
275 Description: "Capture browser console messages to log",
276 Section: SectionLogging,
277 },
278 {
279 Key: "logging.capture_gtk_logs",
280 Type: "bool",
281 Default: fmt.Sprintf("%t", defaults.Logging.CaptureGTKLogs),
282 Description: "Capture GTK and GLib log messages",
283 Section: SectionLogging,
284 },
285 }
286}
287
288func (*SchemaProvider) getHistoryKeys(defaults *Config) []entity.ConfigKeyInfo {
289 return []entity.ConfigKeyInfo{
290 {
291 Key: "history.max_entries",
292 Type: "int",
293 Default: fmt.Sprintf("%d", defaults.History.MaxEntries),
294 Description: "Maximum number of history entries to keep",
295 Range: ">=0",
296 Section: SectionHistory,
297 },
298 {
299 Key: "history.retention_period_days",
300 Type: "int",
301 Default: fmt.Sprintf("%d", defaults.History.RetentionPeriodDays),
302 Description: "Number of days to retain history",
303 Range: ">=0",
304 Section: SectionHistory,
305 },
306 {
307 Key: "history.cleanup_interval_days",
308 Type: "int",
309 Default: fmt.Sprintf("%d", defaults.History.CleanupIntervalDays),
310 Description: "Days between automatic history cleanup",
311 Range: ">=0",
312 Section: SectionHistory,
313 },
314 }
315}
316
317func (*SchemaProvider) getSearchKeys(defaults *Config) []entity.ConfigKeyInfo {
318 return []entity.ConfigKeyInfo{
319 {
320 Key: "default_search_engine",
321 Type: "string",
322 Default: defaults.DefaultSearchEngine,
323 Description: "Default search engine URL (must contain %s placeholder)",
324 Section: SectionSearch,
325 },
326 {
327 Key: "search_shortcuts.<key>",
328 Type: "object",
329 Default: "(see defaults)",
330 Description: "Search shortcuts map with url and description fields",
331 Section: SectionSearch,
332 },
333 }
334}
335
336func (*SchemaProvider) getDmenuKeys(defaults *Config) []entity.ConfigKeyInfo {
337 return []entity.ConfigKeyInfo{
338 {
339 Key: "dmenu.max_history_days",
340 Type: "int",
341 Default: fmt.Sprintf("%d", defaults.Dmenu.MaxHistoryDays),
342 Description: "Number of days of history to show in dmenu (0 = all)",
343 Range: ">=0",
344 Section: SectionDmenu,
345 },
346 {
347 Key: "dmenu.show_visit_count",
348 Type: "bool",
349 Default: fmt.Sprintf("%t", defaults.Dmenu.ShowVisitCount),
350 Description: "Show visit count in dmenu entries",
351 Section: SectionDmenu,
352 },
353 {
354 Key: "dmenu.show_last_visited",
355 Type: "bool",
356 Default: fmt.Sprintf("%t", defaults.Dmenu.ShowLastVisited),
357 Description: "Show last visited date in dmenu entries",
358 Section: SectionDmenu,
359 },
360 {
361 Key: "dmenu.history_prefix",
362 Type: "string",
363 Default: defaults.Dmenu.HistoryPrefix,
364 Description: "Prefix for history entries in dmenu",
365 Section: SectionDmenu,
366 },
367 {
368 Key: "dmenu.shortcut_prefix",
369 Type: "string",
370 Default: defaults.Dmenu.ShortcutPrefix,
371 Description: "Prefix for search shortcuts in dmenu",
372 Section: SectionDmenu,
373 },
374 {
375 Key: "dmenu.url_prefix",
376 Type: "string",
377 Default: defaults.Dmenu.URLPrefix,
378 Description: "Prefix for URL entries in dmenu",
379 Section: SectionDmenu,
380 },
381 {
382 Key: "dmenu.date_format",
383 Type: "string",
384 Default: defaults.Dmenu.DateFormat,
385 Description: "Go time format for dates in dmenu",
386 Section: SectionDmenu,
387 },
388 {
389 Key: "dmenu.sort_by_visit_count",
390 Type: "bool",
391 Default: fmt.Sprintf("%t", defaults.Dmenu.SortByVisitCount),
392 Description: "Sort dmenu entries by visit count",
393 Section: SectionDmenu,
394 },
395 }
396}
397
398func (*SchemaProvider) getWorkspaceKeys(defaults *Config) []entity.ConfigKeyInfo {
399 return []entity.ConfigKeyInfo{
400 {
401 Key: "workspace.new_pane_url",
402 Type: "string",
403 Default: defaults.Workspace.NewPaneURL,
404 Description: "URL loaded when creating a new pane",
405 Section: SectionWorkspace,
406 },
407 {
408 Key: "workspace.tab_bar_position",
409 Type: "string",
410 Default: defaults.Workspace.TabBarPosition,
411 Description: "Position of the tab bar",
412 Values: []string{"top", "bottom"},
413 Section: SectionWorkspace,
414 },
415 {
416 Key: "workspace.hide_tab_bar_when_single_tab",
417 Type: "bool",
418 Default: fmt.Sprintf("%t", defaults.Workspace.HideTabBarWhenSingleTab),
419 Description: "Hide tab bar when only one tab exists",
420 Section: SectionWorkspace,
421 },
422 {
423 Key: "workspace.switch_to_tab_on_move",
424 Type: "bool",
425 Default: fmt.Sprintf("%t", defaults.Workspace.SwitchToTabOnMove),
426 Description: "Switch focus to tab when moving pane to it",
427 Section: SectionWorkspace,
428 },
429 // Keymap preset
430 {
431 Key: "workspace.keymap",
432 Type: "string",
433 Default: string(defaults.Workspace.Keymap),
434 Description: "Mode activation style: zellij (one shortcut per mode) or tmux (single prefix key)",
435 Values: []string{string(KeymapZellij), string(KeymapTmux)},
436 Section: SectionWorkspace,
437 },
438 {
439 Key: "workspace.prefix_mode.activation_shortcut",
440 Type: "string",
441 Default: defaults.Workspace.PrefixMode.ActivationShortcut,
442 Description: "Prefix key used when workspace.keymap is tmux",
443 Section: SectionWorkspace,
444 },
445 {
446 Key: "workspace.prefix_mode.timeout_ms",
447 Type: "int",
448 Default: fmt.Sprintf("%d", defaults.Workspace.PrefixMode.TimeoutMilliseconds),
449 Description: "Prefix timeout in milliseconds (0 = no timeout)",
450 Range: ">=0",
451 Section: SectionWorkspace,
452 },
453 {
454 Key: "workspace.prefix_mode.actions.<action>",
455 Type: "object",
456 Default: "(see defaults)",
457 Description: "One-shot actions available after the prefix key",
458 Section: SectionWorkspace,
459 },
460 // Pane mode
461 {
462 Key: "workspace.pane_mode.activation_shortcut",
463 Type: "string",
464 Default: defaults.Workspace.PaneMode.ActivationShortcut,
465 Description: "Shortcut to enter pane mode",
466 Section: SectionWorkspace,
467 },
468 {
469 Key: "workspace.pane_mode.timeout_ms",
470 Type: "int",
471 Default: fmt.Sprintf("%d", defaults.Workspace.PaneMode.TimeoutMilliseconds),
472 Description: "Pane mode timeout in milliseconds (0 = no timeout)",
473 Range: ">=0",
474 Section: SectionWorkspace,
475 },
476 {
477 Key: "workspace.pane_mode.actions.<action>",
478 Type: "[]string",
479 Default: "(see defaults)",
480 Description: "Key bindings for pane mode actions",
481 Section: SectionWorkspace,
482 },
483 // Tab mode
484 {
485 Key: "workspace.tab_mode.activation_shortcut",
486 Type: "string",
487 Default: defaults.Workspace.TabMode.ActivationShortcut,
488 Description: "Shortcut to enter tab mode",
489 Section: SectionWorkspace,
490 },
491 {
492 Key: "workspace.tab_mode.timeout_ms",
493 Type: "int",
494 Default: fmt.Sprintf("%d", defaults.Workspace.TabMode.TimeoutMilliseconds),
495 Description: "Tab mode timeout in milliseconds (0 = no timeout)",
496 Range: ">=0",
497 Section: SectionWorkspace,
498 },
499 {
500 Key: "workspace.tab_mode.actions.<action>",
501 Type: "[]string",
502 Default: "(see defaults)",
503 Description: "Key bindings for tab mode actions",
504 Section: SectionWorkspace,
505 },
506 // Vim mode
507 {
508 Key: "workspace.vim_mode.activation_shortcut",
509 Type: "string",
510 Default: defaults.Workspace.VimMode.ActivationShortcut,
511 Description: "Shortcut to enter vim scroll mode",
512 Section: SectionWorkspace,
513 },
514 {
515 Key: "workspace.vim_mode.timeout_ms",
516 Type: "int",
517 Default: fmt.Sprintf("%d", defaults.Workspace.VimMode.TimeoutMilliseconds),
518 Description: "Vim mode timeout in milliseconds (0 = no timeout)",
519 Range: ">=0",
520 Section: SectionWorkspace,
521 },
522 {
523 Key: "workspace.vim_mode.sequence_timeout_ms",
524 Type: "int",
525 Default: fmt.Sprintf("%d", defaults.Workspace.VimMode.SequenceTimeoutMilliseconds),
526 Description: "Vim mode multi-key sequence timeout in milliseconds (0 = immediate ambiguity resolution)",
527 Range: ">=0",
528 Section: SectionWorkspace,
529 },
530 {
531 Key: "workspace.vim_mode.preload_accessibility",
532 Type: "bool",
533 Default: fmt.Sprintf("%t", defaults.Workspace.VimMode.PreloadAccessibility),
534 Description: "Pre-enable browser accessibility when a WebView is shown (default false; enable on Vim Mode enter otherwise)",
535 Section: SectionWorkspace,
536 },
537 {
538 Key: "workspace.vim_mode.actions.<action>",
539 Type: "object",
540 Default: "(see defaults)",
541 Description: "Vim mode action object with keys ([]string) and desc (string)",
542 Section: SectionWorkspace,
543 },
544 // Resize mode
545 {
546 Key: "workspace.resize_mode.activation_shortcut",
547 Type: "string",
548 Default: defaults.Workspace.ResizeMode.ActivationShortcut,
549 Description: "Shortcut to enter resize mode",
550 Section: SectionWorkspace,
551 },
552 {
553 Key: "workspace.resize_mode.timeout_ms",
554 Type: "int",
555 Default: fmt.Sprintf("%d", defaults.Workspace.ResizeMode.TimeoutMilliseconds),
556 Description: "Resize mode timeout in milliseconds (0 = no timeout)",
557 Range: ">=0",
558 Section: SectionWorkspace,
559 },
560 {
561 Key: "workspace.resize_mode.step_percent",
562 Type: "float64",
563 Default: fmt.Sprintf("%.1f", defaults.Workspace.ResizeMode.StepPercent),
564 Description: "Percentage to resize panes per step",
565 Section: SectionWorkspace,
566 },
567 {
568 Key: "workspace.resize_mode.min_pane_percent",
569 Type: "float64",
570 Default: fmt.Sprintf("%.1f", defaults.Workspace.ResizeMode.MinPanePercent),
571 Description: "Minimum pane size as percentage",
572 Section: SectionWorkspace,
573 },
574 {
575 Key: "workspace.resize_mode.actions.<action>",
576 Type: "[]string",
577 Default: "(see defaults)",
578 Description: "Key bindings for resize mode actions",
579 Section: SectionWorkspace,
580 },
581 // Global shortcuts - managed via dedicated keybindings UI
582 {
583 Key: "workspace.shortcuts.actions",
584 Type: "object",
585 Default: "(see defaults)",
586 Description: "Global keyboard shortcuts (use Keybindings tab to edit)",
587 Section: SectionWorkspace,
588 },
589 // Floating pane
590 {
591 Key: "workspace.floating_pane.width_pct",
592 Type: "float64",
593 Default: fmt.Sprintf("%.2f", defaults.Workspace.FloatingPane.WidthPct),
594 Description: "Floating pane width as a fraction of workspace width",
595 Range: "(0,1]",
596 Section: SectionWorkspace,
597 },
598 {
599 Key: "workspace.floating_pane.height_pct",
600 Type: "float64",
601 Default: fmt.Sprintf("%.2f", defaults.Workspace.FloatingPane.HeightPct),
602 Description: "Floating pane height as a fraction of workspace height",
603 Range: "(0,1]",
604 Section: SectionWorkspace,
605 },
606 {
607 Key: "workspace.floating_pane.profiles.<name>",
608 Type: "object",
609 Default: "(empty)",
610 Description: "Named floating pane URL profiles with keys, url, and optional desc",
611 Section: SectionWorkspace,
612 },
613 // External links
614 {
615 Key: "workspace.external_links.behavior",
616 Type: "string",
617 Default: string(defaults.Workspace.ExternalLinks.Behavior),
618 Description: "How URLs opened from external applications are placed",
619 Values: []string{"windowed", "tabbed", "split", "stacked"},
620 Section: SectionWorkspace,
621 },
622 {
623 Key: "workspace.external_links.placement",
624 Type: "string",
625 Default: string(defaults.Workspace.ExternalLinks.Placement),
626 Description: "Placement direction for split external links",
627 Values: []string{"right", "left", "top", "bottom"},
628 Section: SectionWorkspace,
629 },
630 // Browsing contexts
631 {
632 Key: "workspace.browsing_contexts.behavior",
633 Type: "string",
634 Default: string(defaults.Workspace.BrowsingContexts.Behavior),
635 Description: "How to handle JavaScript popup windows",
636 Values: []string{"split", "stacked", "tabbed", "windowed"},
637 Section: SectionWorkspace,
638 },
639 {
640 Key: "workspace.browsing_contexts.placement",
641 Type: "string",
642 Default: defaults.Workspace.BrowsingContexts.Placement,
643 Description: "Placement direction for split popups",
644 Values: []string{"right", "left", "top", "bottom"},
645 Section: SectionWorkspace,
646 },
647 {
648 Key: "workspace.browsing_contexts.blank_target_behavior",
649 Type: "string",
650 Default: defaults.Workspace.BrowsingContexts.BlankTargetBehavior,
651 Description: "How to handle target=\"_blank\" links",
652 Values: []string{"split", "stacked", "tabbed"},
653 Section: SectionWorkspace,
654 },
655 {
656 Key: "workspace.browsing_contexts.open_in_new_pane",
657 Type: "bool",
658 Default: fmt.Sprintf("%t", defaults.Workspace.BrowsingContexts.OpenInNewPane),
659 Description: "Open popups in workspace instead of blocking",
660 Section: SectionWorkspace,
661 },
662 {
663 Key: "workspace.browsing_contexts.follow_pane_context",
664 Type: "bool",
665 Default: fmt.Sprintf("%t", defaults.Workspace.BrowsingContexts.FollowPaneContext),
666 Description: "Popup placement follows parent pane context",
667 Section: SectionWorkspace,
668 },
669 {
670 Key: "workspace.browsing_contexts.enable_smart_detection",
671 Type: "bool",
672 Default: fmt.Sprintf("%t", defaults.Workspace.BrowsingContexts.EnableSmartDetection),
673 Description: "Use window properties to detect popup intent",
674 Section: SectionWorkspace,
675 },
676 {
677 Key: "workspace.browsing_contexts.oauth_auto_close",
678 Type: "bool",
679 Default: fmt.Sprintf("%t", defaults.Workspace.BrowsingContexts.OAuthAutoClose),
680 Description: "Auto-close OAuth popups after success",
681 Section: SectionWorkspace,
682 },
683 // Styling
684 {
685 Key: "workspace.styling.border_width",
686 Type: "int",
687 Default: fmt.Sprintf("%d", defaults.Workspace.Styling.BorderWidth),
688 Description: "Active pane border width in pixels",
689 Range: ">=0",
690 Section: SectionWorkspace,
691 },
692 {
693 Key: "workspace.styling.border_color",
694 Type: "string",
695 Default: defaults.Workspace.Styling.BorderColor,
696 Description: "Active pane border color (CSS or @theme variable)",
697 Section: SectionWorkspace,
698 },
699 {
700 Key: "workspace.styling.mode_border_width",
701 Type: "int",
702 Default: fmt.Sprintf("%d", defaults.Workspace.Styling.ModeBorderWidth),
703 Description: "Reserved; mode frame borders currently use fixed widths",
704 Range: ">=0",
705 Section: SectionWorkspace,
706 },
707 {
708 Key: "workspace.styling.pane_mode_color",
709 Type: "string",
710 Default: defaults.Workspace.Styling.PaneModeColor,
711 Description: "Color for pane mode indicator",
712 Section: SectionWorkspace,
713 },
714 {
715 Key: "workspace.styling.tab_mode_color",
716 Type: "string",
717 Default: defaults.Workspace.Styling.TabModeColor,
718 Description: "Color for tab mode indicator",
719 Section: SectionWorkspace,
720 },
721 {
722 Key: "workspace.styling.session_mode_color",
723 Type: "string",
724 Default: defaults.Workspace.Styling.SessionModeColor,
725 Description: "Color for session mode indicator",
726 Section: SectionWorkspace,
727 },
728 {
729 Key: "workspace.styling.vim_mode_color", Type: "string", Default: defaults.Workspace.Styling.VimModeColor,
730 Description: "Color for Vim mode indicator", Section: SectionWorkspace,
731 },
732 {
733 Key: "workspace.styling.resize_mode_color",
734 Type: "string",
735 Default: defaults.Workspace.Styling.ResizeModeColor,
736 Description: "Color for resize mode indicator",
737 Section: SectionWorkspace,
738 },
739 {
740 Key: "workspace.styling.mode_indicator_toaster_enabled",
741 Type: "bool",
742 Default: fmt.Sprintf("%t", defaults.Workspace.Styling.ModeIndicatorToasterEnabled),
743 Description: "Show the bottom-left mode toaster while a mode is active (kept as the legend header while the legend is not off)",
744 Section: SectionWorkspace,
745 },
746 {
747 Key: "workspace.styling.mode_legend",
748 Type: "string",
749 Default: defaults.Workspace.Styling.ModeLegend,
750 Description: "Mode legend visibility",
751 Values: []string{"always", "delay", "off"},
752 Section: SectionWorkspace,
753 },
754 {
755 Key: "workspace.styling.mode_legend_delay_ms",
756 Type: "int",
757 Default: fmt.Sprintf("%d", defaults.Workspace.Styling.ModeLegendDelayMs),
758 Description: "Delay before showing the mode legend in milliseconds",
759 Range: ">=0",
760 Section: SectionWorkspace,
761 },
762 {
763 Key: "workspace.styling.mode_legend_linger", Type: "bool", Default: fmt.Sprintf("%t", defaults.Workspace.Styling.ModeLegendLinger),
764 Description: "Keep the legend visible, read-only, after its mode ends while the pointer is over it, until the next key press or click.",
765 Section: SectionWorkspace,
766 },
767 {
768 Key: "workspace.styling.mode_legend_animations",
769 Type: "bool",
770 Default: fmt.Sprintf("%t", defaults.Workspace.Styling.ModeLegendAnimations),
771 Description: "Animate the mode legend and pressed keycaps",
772 Section: SectionWorkspace,
773 },
774 {
775 Key: "workspace.styling.mode_legend_collapsed",
776 Type: "bool",
777 Default: fmt.Sprintf("%t", defaults.Workspace.Styling.ModeLegendCollapsed),
778 Description: "Collapse the mode legend to its header; toggled by clicking the mode toaster and shared by all modes and windows",
779 Section: SectionWorkspace,
780 },
781 {
782 Key: "workspace.styling.transition_duration",
783 Type: "int",
784 Default: fmt.Sprintf("%d", defaults.Workspace.Styling.TransitionDuration),
785 Description: "Border animation duration in milliseconds",
786 Range: ">=0",
787 Section: SectionWorkspace,
788 },
789 }
790}
791
792func (*SchemaProvider) getSessionKeys(defaults *Config) []entity.ConfigKeyInfo {
793 return []entity.ConfigKeyInfo{
794 {
795 Key: "session.auto_restore",
796 Type: "bool",
797 Default: fmt.Sprintf("%t", defaults.Session.AutoRestore),
798 Description: "Automatically restore last session on startup",
799 Section: SectionSession,
800 },
801 {
802 Key: "session.snapshot_interval_ms",
803 Type: "int",
804 Default: fmt.Sprintf("%d", defaults.Session.SnapshotIntervalMs),
805 Description: "Minimum interval between session snapshots",
806 Range: ">=0",
807 Section: SectionSession,
808 },
809 {
810 Key: "session.max_exited_sessions",
811 Type: "int",
812 Default: fmt.Sprintf("%d", defaults.Session.MaxExitedSessions),
813 Description: "Maximum number of exited sessions to keep",
814 Range: ">=0",
815 Section: SectionSession,
816 },
817 {
818 Key: "session.max_exited_session_age_days",
819 Type: "int",
820 Default: fmt.Sprintf("%d", defaults.Session.MaxExitedSessionAgeDays),
821 Description: "Maximum age of exited sessions in days",
822 Range: ">=0",
823 Section: SectionSession,
824 },
825 {
826 Key: "session.session_mode.activation_shortcut",
827 Type: "string",
828 Default: defaults.Session.SessionMode.ActivationShortcut,
829 Description: "Shortcut to enter session mode",
830 Section: SectionSession,
831 },
832 {
833 Key: "session.session_mode.timeout_ms",
834 Type: "int",
835 Default: fmt.Sprintf("%d", defaults.Session.SessionMode.TimeoutMilliseconds),
836 Description: "Session mode timeout in milliseconds",
837 Range: ">=0",
838 Section: SectionSession,
839 },
840 {
841 Key: "session.session_mode.actions.<action>",
842 Type: "[]string",
843 Default: "(see defaults)",
844 Description: "Key bindings for session mode actions",
845 Section: SectionSession,
846 },
847 }
848}
849
850func (*SchemaProvider) getOmniboxKeys(defaults *Config) []entity.ConfigKeyInfo {
851 return []entity.ConfigKeyInfo{
852 {
853 Key: "omnibox.style",
854 Type: "string",
855 Default: defaults.Omnibox.Style,
856 Description: "Visual treatment for the omnibox",
857 Values: []string{"multiplexer", "command", "minimal"},
858 Section: SectionOmnibox,
859 },
860 {
861 Key: "omnibox.initial_behavior",
862 Type: "string",
863 Default: string(defaults.Omnibox.InitialBehavior),
864 Description: "What to show when omnibox opens with empty input",
865 Values: []string{
866 string(OmniboxInitialBehaviorRecent),
867 string(OmniboxInitialBehaviorMostVisited),
868 string(OmniboxInitialBehaviorNone),
869 },
870 Section: SectionOmnibox,
871 },
872 {
873 Key: "omnibox.max_history_days",
874 Type: "int",
875 Default: fmt.Sprintf("%d", defaults.Omnibox.MaxHistoryDays),
876 Description: "Days of omnibox suggestion history (typed and initial); 0 = all history, never deletes",
877 Range: ">=0",
878 Section: SectionOmnibox,
879 },
880 {
881 Key: "omnibox.auto_open_on_new_pane",
882 Type: "bool",
883 Default: fmt.Sprintf("%t", defaults.Omnibox.AutoOpenOnNewPane),
884 Description: "Auto-open omnibox when creating new pane",
885 Section: SectionOmnibox,
886 },
887 }
888}
889
890func (*SchemaProvider) getContentFilteringKeys(defaults *Config) []entity.ConfigKeyInfo {
891 return []entity.ConfigKeyInfo{
892 {
893 Key: "content_filtering.enabled",
894 Type: "bool",
895 Default: fmt.Sprintf("%t", defaults.ContentFiltering.Enabled),
896 Description: "Enable ad blocking and content filtering",
897 Section: SectionContentFiltering,
898 },
899 {
900 Key: "content_filtering.auto_update",
901 Type: "bool",
902 Default: fmt.Sprintf("%t", defaults.ContentFiltering.AutoUpdate),
903 Description: "Auto-update filter lists from GitHub",
904 Section: SectionContentFiltering,
905 },
906 }
907}
908
909func (*SchemaProvider) getClipboardKeys(defaults *Config) []entity.ConfigKeyInfo {
910 return []entity.ConfigKeyInfo{
911 {
912 Key: "clipboard.auto_copy_on_selection",
913 Type: "bool",
914 Default: fmt.Sprintf("%t", defaults.Clipboard.AutoCopyOnSelection),
915 Description: "Auto-copy selected text to clipboard (zellij-style)",
916 Section: SectionClipboard,
917 },
918 }
919}
920
921func (*SchemaProvider) getRenderingKeys(defaults *Config) []entity.ConfigKeyInfo {
922 return []entity.ConfigKeyInfo{
923 {
924 Key: "engine.type",
925 Type: "string",
926 Default: defaults.Engine.Type,
927 Description: "Browser engine selection; CEF is the default and WebKitGTK is the fallback",
928 Values: []string{"cef", "webkit"},
929 Section: SectionRendering,
930 },
931 {
932 Key: "engine.webkit.gsk_renderer",
933 Type: "string",
934 Default: string(defaults.Engine.WebKit.GSKRenderer),
935 Description: "GTK Scene Kit renderer selection",
936 Values: []string{"auto", "opengl", "vulkan", "cairo"},
937 Section: SectionRendering,
938 },
939 {
940 Key: "engine.webkit.disable_dmabuf_renderer",
941 Type: "bool",
942 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.DisableDMABufRenderer),
943 Description: "Disable DMA-BUF accelerated renderer",
944 Section: SectionRendering,
945 },
946 {
947 Key: "engine.webkit.force_compositing_mode",
948 Type: "bool",
949 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.ForceCompositingMode),
950 Description: "Force accelerated compositing",
951 Section: SectionRendering,
952 },
953 {
954 Key: "engine.webkit.disable_compositing_mode",
955 Type: "bool",
956 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.DisableCompositingMode),
957 Description: "Disable accelerated compositing",
958 Section: SectionRendering,
959 },
960 {
961 Key: "engine.webkit.disable_mipmaps",
962 Type: "bool",
963 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.DisableMipmaps),
964 Description: "Disable mipmap generation",
965 Section: SectionRendering,
966 },
967 {
968 Key: "engine.webkit.prefer_gl",
969 Type: "bool",
970 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.PreferGL),
971 Description: "Force OpenGL over GLES",
972 Section: SectionRendering,
973 },
974 {
975 Key: "engine.webkit.draw_compositing_indicators",
976 Type: "bool",
977 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.DrawCompositingIndicators),
978 Description: "Show compositing layer borders",
979 Section: SectionRendering,
980 },
981 {
982 Key: "engine.webkit.show_fps",
983 Type: "bool",
984 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.ShowFPS),
985 Description: "Display WebKit FPS counter",
986 Section: SectionRendering,
987 },
988 {
989 Key: "engine.webkit.sample_memory",
990 Type: "bool",
991 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.SampleMemory),
992 Description: "Enable memory sampling",
993 Section: SectionRendering,
994 },
995 {
996 Key: "engine.webkit.debug_frames",
997 Type: "bool",
998 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.DebugFrames),
999 Description: "Enable frame timing debug output",
1000 Section: SectionRendering,
1001 },
1002 }
1003}
1004
1005func (*SchemaProvider) getMediaKeys(defaults *Config) []entity.ConfigKeyInfo {
1006 return []entity.ConfigKeyInfo{
1007 {
1008 Key: "media.hardware_decoding",
1009 Type: "string",
1010 Default: string(defaults.Media.HardwareDecodingMode),
1011 Description: "Hardware vs software video decoding",
1012 Values: []string{"auto", "force", "disable"},
1013 Section: SectionMedia,
1014 },
1015 {
1016 Key: "media.prefer_av1",
1017 Type: "bool",
1018 Default: fmt.Sprintf("%t", defaults.Media.PreferAV1),
1019 Description: "Prioritize AV1 codec when available",
1020 Section: SectionMedia,
1021 },
1022 {
1023 Key: "media.show_diagnostics",
1024 Type: "bool",
1025 Default: fmt.Sprintf("%t", defaults.Media.ShowDiagnosticsOnStartup),
1026 Description: "Show media capability warnings at startup",
1027 Section: SectionMedia,
1028 },
1029 {
1030 Key: "engine.webkit.force_vsync",
1031 Type: "bool",
1032 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.ForceVSync),
1033 Description: "Force VSync for WebKit fallback video playback",
1034 Section: SectionMedia,
1035 },
1036 {
1037 Key: "engine.webkit.gl_rendering_mode",
1038 Type: "string",
1039 Default: string(defaults.Engine.WebKit.GLRenderingMode),
1040 Description: "WebKit fallback GStreamer/OpenGL API selection",
1041 Values: []string{"auto", "gles2", "gl3", "none"},
1042 Section: SectionMedia,
1043 },
1044 {
1045 Key: "engine.webkit.gstreamer_debug_level",
1046 Type: "int",
1047 Default: fmt.Sprintf("%d", defaults.Engine.WebKit.GStreamerDebugLevel),
1048 Description: "WebKit fallback GStreamer debug verbosity",
1049 Range: "0-5",
1050 Section: SectionMedia,
1051 },
1052 }
1053}
1054
1055func (*SchemaProvider) getPrivacyKeys(defaults *Config) []entity.ConfigKeyInfo {
1056 return []entity.ConfigKeyInfo{
1057 {
1058 Key: "engine.cookie_policy",
1059 Type: "string",
1060 Default: string(defaults.Engine.CookiePolicy),
1061 Description: "Cookie acceptance policy",
1062 Values: []string{"always", "no_third_party", "never"},
1063 Section: SectionPrivacy,
1064 },
1065 {
1066 Key: "engine.webkit.itp_enabled",
1067 Type: "bool",
1068 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.ITPEnabled),
1069 Description: "Enable WebKit fallback Intelligent Tracking Prevention",
1070 Section: SectionPrivacy,
1071 },
1072 }
1073}
1074
1075func (*SchemaProvider) getUpdateKeys(defaults *Config) []entity.ConfigKeyInfo {
1076 return []entity.ConfigKeyInfo{
1077 {
1078 Key: "update.enable_on_startup",
1079 Type: "bool",
1080 Default: fmt.Sprintf("%t", defaults.Update.EnableOnStartup),
1081 Description: "Check for updates on browser startup",
1082 Section: SectionUpdate,
1083 },
1084 {
1085 Key: "update.auto_download",
1086 Type: "bool",
1087 Default: fmt.Sprintf("%t", defaults.Update.AutoDownload),
1088 Description: "Auto-download updates in background",
1089 Section: SectionUpdate,
1090 },
1091 {
1092 Key: "update.notify_on_new_settings",
1093 Type: "bool",
1094 Default: fmt.Sprintf("%t", defaults.Update.NotifyOnNewSettings),
1095 Description: "Show toast when new config settings available",
1096 Section: SectionUpdate,
1097 },
1098 }
1099}
1100
1101func (*SchemaProvider) getDebugKeys(defaults *Config) []entity.ConfigKeyInfo {
1102 return []entity.ConfigKeyInfo{
1103 {
1104 Key: "debug.enable_devtools",
1105 Type: "bool",
1106 Default: fmt.Sprintf("%t", defaults.Debug.EnableDevTools),
1107 Description: "Enable browser developer tools (F12)",
1108 Section: SectionDebug,
1109 },
1110 {
1111 Key: "engine.cef.log_file",
1112 Type: "string",
1113 Default: defaults.Engine.CEF.LogFile,
1114 Description: "Path to the CEF runtime log file written during startup and browser process execution",
1115 Section: SectionDebug,
1116 },
1117 {
1118 Key: "engine.cef.log_severity",
1119 Type: "int32",
1120 Default: fmt.Sprintf("%d", defaults.Engine.CEF.LogSeverity),
1121 Description: "CEF internal log verbosity (0=default, 1=verbose, 2=info, 3=warning, 4=error, 99=disable)",
1122 Section: SectionDebug,
1123 },
1124 {
1125 Key: "engine.cef.trace_handlers",
1126 Type: "bool",
1127 Default: fmt.Sprintf("%t", defaults.Engine.CEF.TraceHandlers),
1128 Description: "Trace purego-cef handler wrapping and refcount activity",
1129 Section: SectionDebug,
1130 },
1131 {
1132 Key: "engine.cef.enable_audio_handler",
1133 Type: "bool",
1134 Default: fmt.Sprintf("%t", defaults.Engine.CEF.EnableAudioHandler),
1135 Description: "Enable the experimental CEF audio handler bridge",
1136 Section: SectionDebug,
1137 },
1138 }
1139}
1140
1141func (*SchemaProvider) getPerformanceKeys(defaults *Config) []entity.ConfigKeyInfo {
1142 return []entity.ConfigKeyInfo{
1143 {
1144 Key: "engine.profile",
1145 Type: "string",
1146 Default: string(defaults.Engine.Profile),
1147 Description: "Performance profile preset (custom enables manual tuning)",
1148 Values: []string{"default", "lite", "balanced", "max", "custom"},
1149 Section: SectionPerformance,
1150 },
1151 {
1152 Key: "engine.zoom_cache_size",
1153 Type: "int",
1154 Default: fmt.Sprintf("%d", defaults.Engine.ZoomCacheSize),
1155 Description: "Number of domain zoom levels to cache",
1156 Range: ">=0",
1157 Section: SectionPerformance,
1158 },
1159 {
1160 Key: "engine.pool_prewarm_count",
1161 Type: "int",
1162 Default: fmt.Sprintf("%d", defaults.Engine.PoolPrewarmCount),
1163 Description: "WebViews to pre-create at startup",
1164 Range: ">=0",
1165 Section: SectionPerformance,
1166 },
1167 {
1168 Key: "engine.cef.render_stack",
1169 Type: "string",
1170 Default: string(defaults.Engine.CEF.CEFRenderStack()),
1171 Description: "CEF GPU render stack",
1172 Values: []string{"vulkan", "egl"},
1173 Section: SectionPerformance,
1174 },
1175 {
1176 Key: "engine.cef.adaptive_windowless_frame_rate",
1177 Type: "bool",
1178 Default: fmt.Sprintf("%t", defaults.Engine.CEF.AdaptiveWindowlessFrameRate),
1179 Description: "Adapt CEF OSR frame rate to the active Wayland monitor refresh rate when no explicit windowless_frame_rate is set",
1180 Section: SectionPerformance,
1181 },
1182 {
1183 Key: "engine.cef.windowless_frame_rate",
1184 Type: "int32",
1185 Default: fmt.Sprintf("%d", defaults.Engine.CEF.WindowlessFrameRate),
1186 Description: "Explicit maximum off-screen frame rate for the CEF engine; 0 enables adaptive mode when configured",
1187 Range: ">=0",
1188 Section: SectionPerformance,
1189 },
1190 {
1191 Key: "engine.cef.windowless_frame_rate_max",
1192 Type: "int32",
1193 Default: fmt.Sprintf("%d", defaults.Engine.CEF.CEFWindowlessFrameRateMax()),
1194 Description: "Hard cap for adaptive CEF OSR frame rate; 0 uses the built-in default cap",
1195 Range: ">=0",
1196 Section: SectionPerformance,
1197 },
1198 {
1199 Key: "engine.cef.idle_runtime_timeout_ms",
1200 Type: "int",
1201 Default: fmt.Sprintf("%d", defaults.Engine.CEF.IdleRuntimeTimeoutMs),
1202 Description: "Bounded opt-in CEF runtime residency in milliseconds after the last window closes; 0 disables, changes require restart",
1203 Range: "0..300000",
1204 Section: SectionPerformance,
1205 },
1206 {
1207 Key: "engine.cef.input.scroll_wheel_multiplier",
1208 Type: "float64",
1209 Default: fmt.Sprintf("%.2f", defaults.Engine.CEF.Input.ScrollWheelMultiplier),
1210 Description: "CEF mouse wheel scroll delta multiplier",
1211 Range: ">0",
1212 Section: SectionPerformance,
1213 },
1214 {
1215 Key: "engine.cef.input.scroll_precise_multiplier",
1216 Type: "float64",
1217 Default: fmt.Sprintf("%.2f", defaults.Engine.CEF.Input.ScrollPreciseMultiplier),
1218 Description: "CEF precise/surface scroll delta multiplier for touchpads and high-resolution wheels",
1219 Range: ">0",
1220 Section: SectionPerformance,
1221 },
1222 {
1223 Key: "engine.cef.input.scroll_horizontal_multiplier",
1224 Type: "float64",
1225 Default: fmt.Sprintf("%.2f", defaults.Engine.CEF.Input.ScrollHorizontalMultiplier),
1226 Description: "CEF horizontal scroll delta multiplier",
1227 Range: ">0",
1228 Section: SectionPerformance,
1229 },
1230 {
1231 Key: "engine.cef.input.scroll_vertical_multiplier",
1232 Type: "float64",
1233 Default: fmt.Sprintf("%.2f", defaults.Engine.CEF.Input.ScrollVerticalMultiplier),
1234 Description: "CEF vertical scroll delta multiplier; touchpad vertical speed uses this together with scroll_precise_multiplier",
1235 Range: ">0",
1236 Section: SectionPerformance,
1237 },
1238 {
1239 Key: "engine.cef.input.scroll_max_delta",
1240 Type: "int32",
1241 Default: fmt.Sprintf("%d", defaults.Engine.CEF.Input.ScrollMaxDelta),
1242 Description: "CEF maximum absolute scroll delta after scaling; 0 disables clamping",
1243 Range: ">=0",
1244 Section: SectionPerformance,
1245 },
1246 {
1247 Key: "engine.cef.input.scroll_touchpad_inertia",
1248 Type: "bool",
1249 Default: fmt.Sprintf("%t", defaults.Engine.CEF.Input.ScrollTouchpadInertia),
1250 Description: "Enable direct touchpad tracking with exponential release decay for CEF views",
1251 Section: SectionPerformance,
1252 },
1253 {
1254 Key: "engine.cef.input.scroll_wheel_smoothing",
1255 Type: "bool",
1256 Default: fmt.Sprintf("%t", defaults.Engine.CEF.Input.ScrollWheelSmoothing),
1257 Description: "Interpolate accepted CEF wheel impulses across frames without a long coast",
1258 Section: SectionPerformance,
1259 },
1260 {
1261 Key: "engine.cef.input.touchpad_navigation_enabled",
1262 Type: "bool",
1263 Default: fmt.Sprintf("%t", defaults.Engine.CEF.Input.TouchpadNavigationEnabled),
1264 Description: "Enable deliberate two-finger touchpad swipe back/forward navigation for CEF views",
1265 Section: SectionPerformance,
1266 },
1267 {
1268 Key: "engine.cef.input.touchpad_navigation_min_delta",
1269 Type: "float64",
1270 Default: fmt.Sprintf("%.2f", defaults.Engine.CEF.Input.TouchpadNavigationMinDelta),
1271 Description: "Minimum accumulated horizontal touchpad swipe delta required before release triggers CEF back/forward navigation",
1272 Range: ">0",
1273 Section: SectionPerformance,
1274 },
1275 {
1276 Key: "engine.cef.input.touchpad_navigation_max_vertical_ratio",
1277 Type: "float64",
1278 Default: fmt.Sprintf("%.2f", defaults.Engine.CEF.Input.TouchpadNavigationMaxVerticalRatio),
1279 Description: "Maximum vertical-to-horizontal delta ratio allowed for CEF touchpad back/forward swipes; " +
1280 "does not affect vertical scroll speed",
1281 Range: ">0",
1282 Section: SectionPerformance,
1283 },
1284 {
1285 Key: "engine.webkit.skia_cpu_painting_threads",
1286 Type: "int",
1287 Default: fmt.Sprintf("%d", defaults.Engine.WebKit.SkiaCPUPaintingThreads),
1288 Description: "Skia CPU rendering threads (0=unset, custom profile only)",
1289 Range: ">=0",
1290 Section: SectionPerformance,
1291 },
1292 {
1293 Key: "engine.webkit.skia_gpu_painting_threads",
1294 Type: "int",
1295 Default: fmt.Sprintf("%d", defaults.Engine.WebKit.SkiaGPUPaintingThreads),
1296 Description: "Skia GPU rendering threads (-1=unset, 0=disable, custom profile only)",
1297 Range: ">=-1",
1298 Section: SectionPerformance,
1299 },
1300 {
1301 Key: "engine.webkit.skia_enable_cpu_rendering",
1302 Type: "bool",
1303 Default: fmt.Sprintf("%t", defaults.Engine.WebKit.SkiaEnableCPURendering),
1304 Description: "Force CPU rendering (custom profile only)",
1305 Section: SectionPerformance,
1306 },
1307 {
1308 Key: "engine.webkit.web_process_memory_limit_mb",
1309 Type: "int",
1310 Default: fmt.Sprintf("%d", defaults.Engine.WebKit.WebProcessMemoryLimitMB),
1311 Description: "Web process memory limit in MB (0=unset, custom profile only)",
1312 Range: ">=0",
1313 Section: SectionPerformance,
1314 },
1315 {
1316 Key: "engine.webkit.web_process_memory_poll_interval_sec",
1317 Type: "float64",
1318 Default: fmt.Sprintf("%.1f", defaults.Engine.WebKit.WebProcessMemoryPollIntervalSec),
1319 Description: "Memory check interval in seconds (0=default 30s, custom profile only)",
1320 Range: ">=0",
1321 Section: SectionPerformance,
1322 },
1323 {
1324 Key: "engine.webkit.web_process_memory_conservative_threshold",
1325 Type: "float64",
1326 Default: fmt.Sprintf("%.2f", defaults.Engine.WebKit.WebProcessMemoryConservativeThreshold),
1327 Description: "Conservative memory cleanup threshold (0-1, custom profile only)",
1328 Range: "0-1",
1329 Section: SectionPerformance,
1330 },
1331 {
1332 Key: "engine.webkit.web_process_memory_strict_threshold",
1333 Type: "float64",
1334 Default: fmt.Sprintf("%.2f", defaults.Engine.WebKit.WebProcessMemoryStrictThreshold),
1335 Description: "Strict memory cleanup threshold (0-1, custom profile only)",
1336 Range: "0-1",
1337 Section: SectionPerformance,
1338 },
1339 {
1340 Key: "engine.webkit.network_process_memory_limit_mb",
1341 Type: "int",
1342 Default: fmt.Sprintf("%d", defaults.Engine.WebKit.NetworkProcessMemoryLimitMB),
1343 Description: "Network process memory limit in MB (0=unset, custom profile only)",
1344 Range: ">=0",
1345 Section: SectionPerformance,
1346 },
1347 {
1348 Key: "engine.webkit.network_process_memory_poll_interval_sec",
1349 Type: "float64",
1350 Default: fmt.Sprintf("%.1f", defaults.Engine.WebKit.NetworkProcessMemoryPollIntervalSec),
1351 Description: "Network memory check interval in seconds (custom profile only)",
1352 Range: ">=0",
1353 Section: SectionPerformance,
1354 },
1355 {
1356 Key: "engine.webkit.network_process_memory_conservative_threshold",
1357 Type: "float64",
1358 Default: fmt.Sprintf("%.2f", defaults.Engine.WebKit.NetworkProcessMemoryConservativeThreshold),
1359 Description: "Network conservative memory threshold (0-1, custom profile only)",
1360 Range: "0-1",
1361 Section: SectionPerformance,
1362 },
1363 {
1364 Key: "engine.webkit.network_process_memory_strict_threshold",
1365 Type: "float64",
1366 Default: fmt.Sprintf("%.2f", defaults.Engine.WebKit.NetworkProcessMemoryStrictThreshold),
1367 Description: "Network strict memory threshold (0-1, custom profile only)",
1368 Range: "0-1",
1369 Section: SectionPerformance,
1370 },
1371 }
1372}
1373
1374func (*SchemaProvider) getRuntimeKeys(defaults *Config) []entity.ConfigKeyInfo {
1375 return []entity.ConfigKeyInfo{
1376 {
1377 Key: "engine.cef.cef_dir",
1378 Type: "string",
1379 Default: defaults.Engine.CEF.CEFDir,
1380 Description: "Optional CEF runtime directory containing libcef.so and Resources; overrides the default " +
1381 "runtime discovery order (CEF_DIR env, /usr/lib/cef, ~/.local/share/cef)",
1382 Section: SectionRuntime,
1383 },
1384 {
1385 Key: "engine.webkit.prefix",
1386 Type: "string",
1387 Default: defaults.Engine.WebKit.Prefix,
1388 Description: "Custom runtime prefix for WebKitGTK/GTK",
1389 Section: SectionRuntime,
1390 },
1391 }
1392}
1393
1394func (*SchemaProvider) getDatabaseKeys() []entity.ConfigKeyInfo {
1395 // Get actual default path for display
1396 dbPath := "$XDG_DATA_HOME/" + appName + "/" + databaseName
1397 if path, err := GetDatabaseFile(); err == nil {
1398 dbPath = path
1399 }
1400
1401 return []entity.ConfigKeyInfo{
1402 {
1403 Key: "database.path",
1404 Type: "string",
1405 Default: dbPath,
1406 Description: "Path to SQLite database file",
1407 Section: SectionDatabase,
1408 },
1409 }
1410}
1411
1412func (*SchemaProvider) getDownloadsKeys(_ *Config) []entity.ConfigKeyInfo {
1413 return []entity.ConfigKeyInfo{
1414 {
1415 Key: "downloads.path",
1416 Type: "string",
1417 Default: "(empty = $XDG_DOWNLOAD_DIR or ~/Downloads)",
1418 Description: "Directory where downloads are saved",
1419 Section: SectionDownloads,
1420 },
1421 }
1422}