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 SectionContentFiltering = "Content Filtering"
18 SectionRendering = "Rendering"
19 SectionMedia = "Media"
20 SectionUpdate = "Update"
21 SectionDmenu = "Dmenu"
22 SectionDebug = "Debug"
23 SectionPerformance = "Performance"
24 SectionRuntime = "Runtime"
25 SectionDatabase = "Database"
26 SectionSearch = "Search"
27)
28
29// SchemaProvider implements port.ConfigSchemaProvider.
30type SchemaProvider struct{}
31
32// NewSchemaProvider creates a new SchemaProvider.
33func NewSchemaProvider() *SchemaProvider {
34 return &SchemaProvider{}
35}
36
37// GetSchema returns all configuration keys with their metadata.
38func (p *SchemaProvider) GetSchema() []entity.ConfigKeyInfo {
39 defaults := DefaultConfig()
40
41 keys := make([]entity.ConfigKeyInfo, 0, 100)
42
43 // Appearance section
44 keys = append(keys, p.getAppearanceKeys(defaults)...)
45
46 // Logging section
47 keys = append(keys, p.getLoggingKeys(defaults)...)
48
49 // History section
50 keys = append(keys, p.getHistoryKeys(defaults)...)
51
52 // Search section
53 keys = append(keys, p.getSearchKeys(defaults)...)
54
55 // Dmenu section
56 keys = append(keys, p.getDmenuKeys(defaults)...)
57
58 // Workspace section
59 keys = append(keys, p.getWorkspaceKeys(defaults)...)
60
61 // Session section
62 keys = append(keys, p.getSessionKeys(defaults)...)
63
64 // Omnibox section
65 keys = append(keys, p.getOmniboxKeys(defaults)...)
66
67 // Content Filtering section
68 keys = append(keys, p.getContentFilteringKeys(defaults)...)
69
70 // Rendering section
71 keys = append(keys, p.getRenderingKeys(defaults)...)
72
73 // Media section
74 keys = append(keys, p.getMediaKeys(defaults)...)
75
76 // Update section
77 keys = append(keys, p.getUpdateKeys(defaults)...)
78
79 // Debug section
80 keys = append(keys, p.getDebugKeys(defaults)...)
81
82 // Performance section
83 keys = append(keys, p.getPerformanceKeys(defaults)...)
84
85 // Runtime section
86 keys = append(keys, p.getRuntimeKeys(defaults)...)
87
88 // Database section
89 keys = append(keys, p.getDatabaseKeys()...)
90
91 return keys
92}
93
94func (*SchemaProvider) getAppearanceKeys(defaults *Config) []entity.ConfigKeyInfo {
95 return []entity.ConfigKeyInfo{
96 {
97 Key: "appearance.color_scheme",
98 Type: "string",
99 Default: defaults.Appearance.ColorScheme,
100 Description: "Theme preference (follows system by default)",
101 Values: []string{"default", "prefer-dark", "prefer-light"},
102 Section: SectionAppearance,
103 },
104 {
105 Key: "appearance.default_font_size",
106 Type: "int",
107 Default: fmt.Sprintf("%d", defaults.Appearance.DefaultFontSize),
108 Description: "Default font size in CSS pixels",
109 Range: "1-72",
110 Section: SectionAppearance,
111 },
112 {
113 Key: "appearance.sans_font",
114 Type: "string",
115 Default: defaults.Appearance.SansFont,
116 Description: "Sans-serif font family for web pages",
117 Section: SectionAppearance,
118 },
119 {
120 Key: "appearance.serif_font",
121 Type: "string",
122 Default: defaults.Appearance.SerifFont,
123 Description: "Serif font family for web pages",
124 Section: SectionAppearance,
125 },
126 {
127 Key: "appearance.monospace_font",
128 Type: "string",
129 Default: defaults.Appearance.MonospaceFont,
130 Description: "Monospace font family for code",
131 Section: SectionAppearance,
132 },
133 {
134 Key: "default_webpage_zoom",
135 Type: "float64",
136 Default: fmt.Sprintf("%.1f", defaults.DefaultWebpageZoom),
137 Description: "Default zoom level for web pages (1.0 = 100%%)",
138 Range: "0.1-5.0",
139 Section: SectionAppearance,
140 },
141 {
142 Key: "default_ui_scale",
143 Type: "float64",
144 Default: fmt.Sprintf("%.1f", defaults.DefaultUIScale),
145 Description: "UI scale multiplier for GTK widgets",
146 Range: "0.5-3.0",
147 Section: SectionAppearance,
148 },
149 {
150 Key: "appearance.light_palette.*",
151 Type: "string",
152 Default: "(hex colors)",
153 Description: "Light theme color palette (background, surface, surface_variant, text, muted, accent, border)",
154 Section: SectionAppearance,
155 },
156 {
157 Key: "appearance.dark_palette.*",
158 Type: "string",
159 Default: "(hex colors)",
160 Description: "Dark theme color palette (background, surface, surface_variant, text, muted, accent, border)",
161 Section: SectionAppearance,
162 },
163 }
164}
165
166func (*SchemaProvider) getLoggingKeys(defaults *Config) []entity.ConfigKeyInfo {
167 return []entity.ConfigKeyInfo{
168 {
169 Key: "logging.level",
170 Type: "string",
171 Default: defaults.Logging.Level,
172 Description: "Log verbosity level",
173 Values: []string{"trace", "debug", "info", "warn", "error", "fatal"},
174 Section: SectionLogging,
175 },
176 {
177 Key: "logging.format",
178 Type: "string",
179 Default: defaults.Logging.Format,
180 Description: "Log output format",
181 Values: []string{"text", "json", "console"},
182 Section: SectionLogging,
183 },
184 {
185 Key: "logging.max_age",
186 Type: "int",
187 Default: fmt.Sprintf("%d", defaults.Logging.MaxAge),
188 Description: "Maximum age of log files in days",
189 Range: ">=0",
190 Section: SectionLogging,
191 },
192 {
193 Key: "logging.log_dir",
194 Type: "string",
195 Default: defaults.Logging.LogDir,
196 Description: "Directory for log files",
197 Section: SectionLogging,
198 },
199 {
200 Key: "logging.enable_file_log",
201 Type: "bool",
202 Default: fmt.Sprintf("%t", defaults.Logging.EnableFileLog),
203 Description: "Enable logging to file",
204 Section: SectionLogging,
205 },
206 {
207 Key: "logging.capture_console",
208 Type: "bool",
209 Default: fmt.Sprintf("%t", defaults.Logging.CaptureConsole),
210 Description: "Capture browser console messages to log",
211 Section: SectionLogging,
212 },
213 }
214}
215
216func (*SchemaProvider) getHistoryKeys(defaults *Config) []entity.ConfigKeyInfo {
217 return []entity.ConfigKeyInfo{
218 {
219 Key: "history.max_entries",
220 Type: "int",
221 Default: fmt.Sprintf("%d", defaults.History.MaxEntries),
222 Description: "Maximum number of history entries to keep",
223 Range: ">=0",
224 Section: SectionHistory,
225 },
226 {
227 Key: "history.retention_period_days",
228 Type: "int",
229 Default: fmt.Sprintf("%d", defaults.History.RetentionPeriodDays),
230 Description: "Number of days to retain history",
231 Range: ">=0",
232 Section: SectionHistory,
233 },
234 {
235 Key: "history.cleanup_interval_days",
236 Type: "int",
237 Default: fmt.Sprintf("%d", defaults.History.CleanupIntervalDays),
238 Description: "Days between automatic history cleanup",
239 Range: ">=0",
240 Section: SectionHistory,
241 },
242 }
243}
244
245func (*SchemaProvider) getSearchKeys(defaults *Config) []entity.ConfigKeyInfo {
246 return []entity.ConfigKeyInfo{
247 {
248 Key: "default_search_engine",
249 Type: "string",
250 Default: defaults.DefaultSearchEngine,
251 Description: "Default search engine URL (must contain %s placeholder)",
252 Section: SectionSearch,
253 },
254 {
255 Key: "search_shortcuts.<key>",
256 Type: "object",
257 Default: "(see defaults)",
258 Description: "Search shortcuts map with url and description fields",
259 Section: SectionSearch,
260 },
261 }
262}
263
264func (*SchemaProvider) getDmenuKeys(defaults *Config) []entity.ConfigKeyInfo {
265 return []entity.ConfigKeyInfo{
266 {
267 Key: "dmenu.max_history_days",
268 Type: "int",
269 Default: fmt.Sprintf("%d", defaults.Dmenu.MaxHistoryDays),
270 Description: "Number of days of history to show in dmenu (0 = all)",
271 Range: ">=0",
272 Section: SectionDmenu,
273 },
274 {
275 Key: "dmenu.show_visit_count",
276 Type: "bool",
277 Default: fmt.Sprintf("%t", defaults.Dmenu.ShowVisitCount),
278 Description: "Show visit count in dmenu entries",
279 Section: SectionDmenu,
280 },
281 {
282 Key: "dmenu.show_last_visited",
283 Type: "bool",
284 Default: fmt.Sprintf("%t", defaults.Dmenu.ShowLastVisited),
285 Description: "Show last visited date in dmenu entries",
286 Section: SectionDmenu,
287 },
288 {
289 Key: "dmenu.history_prefix",
290 Type: "string",
291 Default: defaults.Dmenu.HistoryPrefix,
292 Description: "Prefix for history entries in dmenu",
293 Section: SectionDmenu,
294 },
295 {
296 Key: "dmenu.shortcut_prefix",
297 Type: "string",
298 Default: defaults.Dmenu.ShortcutPrefix,
299 Description: "Prefix for search shortcuts in dmenu",
300 Section: SectionDmenu,
301 },
302 {
303 Key: "dmenu.url_prefix",
304 Type: "string",
305 Default: defaults.Dmenu.URLPrefix,
306 Description: "Prefix for URL entries in dmenu",
307 Section: SectionDmenu,
308 },
309 {
310 Key: "dmenu.date_format",
311 Type: "string",
312 Default: defaults.Dmenu.DateFormat,
313 Description: "Go time format for dates in dmenu",
314 Section: SectionDmenu,
315 },
316 {
317 Key: "dmenu.sort_by_visit_count",
318 Type: "bool",
319 Default: fmt.Sprintf("%t", defaults.Dmenu.SortByVisitCount),
320 Description: "Sort dmenu entries by visit count",
321 Section: SectionDmenu,
322 },
323 }
324}
325
326func (*SchemaProvider) getWorkspaceKeys(defaults *Config) []entity.ConfigKeyInfo {
327 return []entity.ConfigKeyInfo{
328 {
329 Key: "workspace.new_pane_url",
330 Type: "string",
331 Default: defaults.Workspace.NewPaneURL,
332 Description: "URL loaded when creating a new pane",
333 Section: SectionWorkspace,
334 },
335 {
336 Key: "workspace.tab_bar_position",
337 Type: "string",
338 Default: defaults.Workspace.TabBarPosition,
339 Description: "Position of the tab bar",
340 Values: []string{"top", "bottom"},
341 Section: SectionWorkspace,
342 },
343 {
344 Key: "workspace.hide_tab_bar_when_single_tab",
345 Type: "bool",
346 Default: fmt.Sprintf("%t", defaults.Workspace.HideTabBarWhenSingleTab),
347 Description: "Hide tab bar when only one tab exists",
348 Section: SectionWorkspace,
349 },
350 {
351 Key: "workspace.switch_to_tab_on_move",
352 Type: "bool",
353 Default: fmt.Sprintf("%t", defaults.Workspace.SwitchToTabOnMove),
354 Description: "Switch focus to tab when moving pane to it",
355 Section: SectionWorkspace,
356 },
357 // Pane mode
358 {
359 Key: "workspace.pane_mode.activation_shortcut",
360 Type: "string",
361 Default: defaults.Workspace.PaneMode.ActivationShortcut,
362 Description: "Shortcut to enter pane mode",
363 Section: SectionWorkspace,
364 },
365 {
366 Key: "workspace.pane_mode.timeout_ms",
367 Type: "int",
368 Default: fmt.Sprintf("%d", defaults.Workspace.PaneMode.TimeoutMilliseconds),
369 Description: "Pane mode timeout in milliseconds (0 = no timeout)",
370 Range: ">=0",
371 Section: SectionWorkspace,
372 },
373 {
374 Key: "workspace.pane_mode.actions.<action>",
375 Type: "[]string",
376 Default: "(see defaults)",
377 Description: "Key bindings for pane mode actions",
378 Section: SectionWorkspace,
379 },
380 // Tab mode
381 {
382 Key: "workspace.tab_mode.activation_shortcut",
383 Type: "string",
384 Default: defaults.Workspace.TabMode.ActivationShortcut,
385 Description: "Shortcut to enter tab mode",
386 Section: SectionWorkspace,
387 },
388 {
389 Key: "workspace.tab_mode.timeout_ms",
390 Type: "int",
391 Default: fmt.Sprintf("%d", defaults.Workspace.TabMode.TimeoutMilliseconds),
392 Description: "Tab mode timeout in milliseconds (0 = no timeout)",
393 Range: ">=0",
394 Section: SectionWorkspace,
395 },
396 {
397 Key: "workspace.tab_mode.actions.<action>",
398 Type: "[]string",
399 Default: "(see defaults)",
400 Description: "Key bindings for tab mode actions",
401 Section: SectionWorkspace,
402 },
403 // Resize mode
404 {
405 Key: "workspace.resize_mode.activation_shortcut",
406 Type: "string",
407 Default: defaults.Workspace.ResizeMode.ActivationShortcut,
408 Description: "Shortcut to enter resize mode",
409 Section: SectionWorkspace,
410 },
411 {
412 Key: "workspace.resize_mode.timeout_ms",
413 Type: "int",
414 Default: fmt.Sprintf("%d", defaults.Workspace.ResizeMode.TimeoutMilliseconds),
415 Description: "Resize mode timeout in milliseconds (0 = no timeout)",
416 Range: ">=0",
417 Section: SectionWorkspace,
418 },
419 {
420 Key: "workspace.resize_mode.step_percent",
421 Type: "float64",
422 Default: fmt.Sprintf("%.1f", defaults.Workspace.ResizeMode.StepPercent),
423 Description: "Percentage to resize panes per step",
424 Section: SectionWorkspace,
425 },
426 {
427 Key: "workspace.resize_mode.min_pane_percent",
428 Type: "float64",
429 Default: fmt.Sprintf("%.1f", defaults.Workspace.ResizeMode.MinPanePercent),
430 Description: "Minimum pane size as percentage",
431 Section: SectionWorkspace,
432 },
433 {
434 Key: "workspace.resize_mode.actions.<action>",
435 Type: "[]string",
436 Default: "(see defaults)",
437 Description: "Key bindings for resize mode actions",
438 Section: SectionWorkspace,
439 },
440 // Global shortcuts
441 {
442 Key: "workspace.shortcuts.close_pane",
443 Type: "string",
444 Default: defaults.Workspace.Shortcuts.ClosePane,
445 Description: "Global shortcut to close current pane",
446 Section: SectionWorkspace,
447 },
448 {
449 Key: "workspace.shortcuts.next_tab",
450 Type: "string",
451 Default: defaults.Workspace.Shortcuts.NextTab,
452 Description: "Global shortcut to switch to next tab",
453 Section: SectionWorkspace,
454 },
455 {
456 Key: "workspace.shortcuts.previous_tab",
457 Type: "string",
458 Default: defaults.Workspace.Shortcuts.PreviousTab,
459 Description: "Global shortcut to switch to previous tab",
460 Section: SectionWorkspace,
461 },
462 // Popups
463 {
464 Key: "workspace.popups.behavior",
465 Type: "string",
466 Default: string(defaults.Workspace.Popups.Behavior),
467 Description: "How to handle JavaScript popup windows",
468 Values: []string{"split", "stacked", "tabbed", "windowed"},
469 Section: SectionWorkspace,
470 },
471 {
472 Key: "workspace.popups.placement",
473 Type: "string",
474 Default: defaults.Workspace.Popups.Placement,
475 Description: "Placement direction for split popups",
476 Values: []string{"right", "left", "top", "bottom"},
477 Section: SectionWorkspace,
478 },
479 {
480 Key: "workspace.popups.blank_target_behavior",
481 Type: "string",
482 Default: defaults.Workspace.Popups.BlankTargetBehavior,
483 Description: "How to handle target=\"_blank\" links",
484 Values: []string{"split", "stacked", "tabbed"},
485 Section: SectionWorkspace,
486 },
487 {
488 Key: "workspace.popups.open_in_new_pane",
489 Type: "bool",
490 Default: fmt.Sprintf("%t", defaults.Workspace.Popups.OpenInNewPane),
491 Description: "Open popups in workspace instead of blocking",
492 Section: SectionWorkspace,
493 },
494 {
495 Key: "workspace.popups.follow_pane_context",
496 Type: "bool",
497 Default: fmt.Sprintf("%t", defaults.Workspace.Popups.FollowPaneContext),
498 Description: "Popup placement follows parent pane context",
499 Section: SectionWorkspace,
500 },
501 {
502 Key: "workspace.popups.enable_smart_detection",
503 Type: "bool",
504 Default: fmt.Sprintf("%t", defaults.Workspace.Popups.EnableSmartDetection),
505 Description: "Use window properties to detect popup intent",
506 Section: SectionWorkspace,
507 },
508 {
509 Key: "workspace.popups.oauth_auto_close",
510 Type: "bool",
511 Default: fmt.Sprintf("%t", defaults.Workspace.Popups.OAuthAutoClose),
512 Description: "Auto-close OAuth popups after success",
513 Section: SectionWorkspace,
514 },
515 // Styling
516 {
517 Key: "workspace.styling.border_width",
518 Type: "int",
519 Default: fmt.Sprintf("%d", defaults.Workspace.Styling.BorderWidth),
520 Description: "Active pane border width in pixels",
521 Range: ">=0",
522 Section: SectionWorkspace,
523 },
524 {
525 Key: "workspace.styling.border_color",
526 Type: "string",
527 Default: defaults.Workspace.Styling.BorderColor,
528 Description: "Active pane border color (CSS or @theme variable)",
529 Section: SectionWorkspace,
530 },
531 {
532 Key: "workspace.styling.mode_border_width",
533 Type: "int",
534 Default: fmt.Sprintf("%d", defaults.Workspace.Styling.ModeBorderWidth),
535 Description: "Border width for modal mode indicators",
536 Range: ">=0",
537 Section: SectionWorkspace,
538 },
539 {
540 Key: "workspace.styling.pane_mode_color",
541 Type: "string",
542 Default: defaults.Workspace.Styling.PaneModeColor,
543 Description: "Color for pane mode indicator",
544 Section: SectionWorkspace,
545 },
546 {
547 Key: "workspace.styling.tab_mode_color",
548 Type: "string",
549 Default: defaults.Workspace.Styling.TabModeColor,
550 Description: "Color for tab mode indicator",
551 Section: SectionWorkspace,
552 },
553 {
554 Key: "workspace.styling.session_mode_color",
555 Type: "string",
556 Default: defaults.Workspace.Styling.SessionModeColor,
557 Description: "Color for session mode indicator",
558 Section: SectionWorkspace,
559 },
560 {
561 Key: "workspace.styling.resize_mode_color",
562 Type: "string",
563 Default: defaults.Workspace.Styling.ResizeModeColor,
564 Description: "Color for resize mode indicator",
565 Section: SectionWorkspace,
566 },
567 {
568 Key: "workspace.styling.mode_indicator_toaster_enabled",
569 Type: "bool",
570 Default: fmt.Sprintf("%t", defaults.Workspace.Styling.ModeIndicatorToasterEnabled),
571 Description: "Show toaster notification for modal modes",
572 Section: SectionWorkspace,
573 },
574 {
575 Key: "workspace.styling.transition_duration",
576 Type: "int",
577 Default: fmt.Sprintf("%d", defaults.Workspace.Styling.TransitionDuration),
578 Description: "Border animation duration in milliseconds",
579 Range: ">=0",
580 Section: SectionWorkspace,
581 },
582 }
583}
584
585func (*SchemaProvider) getSessionKeys(defaults *Config) []entity.ConfigKeyInfo {
586 return []entity.ConfigKeyInfo{
587 {
588 Key: "session.auto_restore",
589 Type: "bool",
590 Default: fmt.Sprintf("%t", defaults.Session.AutoRestore),
591 Description: "Automatically restore last session on startup",
592 Section: SectionSession,
593 },
594 {
595 Key: "session.snapshot_interval_ms",
596 Type: "int",
597 Default: fmt.Sprintf("%d", defaults.Session.SnapshotIntervalMs),
598 Description: "Minimum interval between session snapshots",
599 Range: ">=0",
600 Section: SectionSession,
601 },
602 {
603 Key: "session.max_exited_sessions",
604 Type: "int",
605 Default: fmt.Sprintf("%d", defaults.Session.MaxExitedSessions),
606 Description: "Maximum number of exited sessions to keep",
607 Range: ">=0",
608 Section: SectionSession,
609 },
610 {
611 Key: "session.max_exited_session_age_days",
612 Type: "int",
613 Default: fmt.Sprintf("%d", defaults.Session.MaxExitedSessionAgeDays),
614 Description: "Maximum age of exited sessions in days",
615 Range: ">=0",
616 Section: SectionSession,
617 },
618 {
619 Key: "session.session_mode.activation_shortcut",
620 Type: "string",
621 Default: defaults.Session.SessionMode.ActivationShortcut,
622 Description: "Shortcut to enter session mode",
623 Section: SectionSession,
624 },
625 {
626 Key: "session.session_mode.timeout_ms",
627 Type: "int",
628 Default: fmt.Sprintf("%d", defaults.Session.SessionMode.TimeoutMilliseconds),
629 Description: "Session mode timeout in milliseconds",
630 Range: ">=0",
631 Section: SectionSession,
632 },
633 {
634 Key: "session.session_mode.actions.<action>",
635 Type: "[]string",
636 Default: "(see defaults)",
637 Description: "Key bindings for session mode actions",
638 Section: SectionSession,
639 },
640 }
641}
642
643func (*SchemaProvider) getOmniboxKeys(defaults *Config) []entity.ConfigKeyInfo {
644 return []entity.ConfigKeyInfo{
645 {
646 Key: "omnibox.initial_behavior",
647 Type: "string",
648 Default: defaults.Omnibox.InitialBehavior,
649 Description: "What to show when omnibox opens with empty input",
650 Values: []string{"recent", "most_visited", "none"},
651 Section: SectionOmnibox,
652 },
653 {
654 Key: "omnibox.auto_open_on_new_pane",
655 Type: "bool",
656 Default: fmt.Sprintf("%t", defaults.Omnibox.AutoOpenOnNewPane),
657 Description: "Auto-open omnibox when creating new pane",
658 Section: SectionOmnibox,
659 },
660 }
661}
662
663func (*SchemaProvider) getContentFilteringKeys(defaults *Config) []entity.ConfigKeyInfo {
664 return []entity.ConfigKeyInfo{
665 {
666 Key: "content_filtering.enabled",
667 Type: "bool",
668 Default: fmt.Sprintf("%t", defaults.ContentFiltering.Enabled),
669 Description: "Enable ad blocking and content filtering",
670 Section: SectionContentFiltering,
671 },
672 {
673 Key: "content_filtering.auto_update",
674 Type: "bool",
675 Default: fmt.Sprintf("%t", defaults.ContentFiltering.AutoUpdate),
676 Description: "Auto-update filter lists from GitHub",
677 Section: SectionContentFiltering,
678 },
679 }
680}
681
682func (*SchemaProvider) getRenderingKeys(defaults *Config) []entity.ConfigKeyInfo {
683 return []entity.ConfigKeyInfo{
684 {
685 Key: "rendering.mode",
686 Type: "string",
687 Default: string(defaults.Rendering.Mode),
688 Description: "GPU/CPU rendering selection for WebKit",
689 Values: []string{"auto", "gpu", "cpu"},
690 Section: SectionRendering,
691 },
692 {
693 Key: "rendering.gsk_renderer",
694 Type: "string",
695 Default: string(defaults.Rendering.GSKRenderer),
696 Description: "GTK Scene Kit renderer selection",
697 Values: []string{"auto", "opengl", "vulkan", "cairo"},
698 Section: SectionRendering,
699 },
700 {
701 Key: "rendering.disable_dmabuf_renderer",
702 Type: "bool",
703 Default: fmt.Sprintf("%t", defaults.Rendering.DisableDMABufRenderer),
704 Description: "Disable DMA-BUF accelerated renderer",
705 Section: SectionRendering,
706 },
707 {
708 Key: "rendering.force_compositing_mode",
709 Type: "bool",
710 Default: fmt.Sprintf("%t", defaults.Rendering.ForceCompositingMode),
711 Description: "Force accelerated compositing",
712 Section: SectionRendering,
713 },
714 {
715 Key: "rendering.disable_compositing_mode",
716 Type: "bool",
717 Default: fmt.Sprintf("%t", defaults.Rendering.DisableCompositingMode),
718 Description: "Disable accelerated compositing",
719 Section: SectionRendering,
720 },
721 {
722 Key: "rendering.disable_mipmaps",
723 Type: "bool",
724 Default: fmt.Sprintf("%t", defaults.Rendering.DisableMipmaps),
725 Description: "Disable mipmap generation",
726 Section: SectionRendering,
727 },
728 {
729 Key: "rendering.prefer_gl",
730 Type: "bool",
731 Default: fmt.Sprintf("%t", defaults.Rendering.PreferGL),
732 Description: "Force OpenGL over GLES",
733 Section: SectionRendering,
734 },
735 {
736 Key: "rendering.draw_compositing_indicators",
737 Type: "bool",
738 Default: fmt.Sprintf("%t", defaults.Rendering.DrawCompositingIndicators),
739 Description: "Show compositing layer borders",
740 Section: SectionRendering,
741 },
742 {
743 Key: "rendering.show_fps",
744 Type: "bool",
745 Default: fmt.Sprintf("%t", defaults.Rendering.ShowFPS),
746 Description: "Display WebKit FPS counter",
747 Section: SectionRendering,
748 },
749 {
750 Key: "rendering.sample_memory",
751 Type: "bool",
752 Default: fmt.Sprintf("%t", defaults.Rendering.SampleMemory),
753 Description: "Enable memory sampling",
754 Section: SectionRendering,
755 },
756 {
757 Key: "rendering.debug_frames",
758 Type: "bool",
759 Default: fmt.Sprintf("%t", defaults.Rendering.DebugFrames),
760 Description: "Enable frame timing debug output",
761 Section: SectionRendering,
762 },
763 }
764}
765
766func (*SchemaProvider) getMediaKeys(defaults *Config) []entity.ConfigKeyInfo {
767 return []entity.ConfigKeyInfo{
768 {
769 Key: "media.hardware_decoding",
770 Type: "string",
771 Default: string(defaults.Media.HardwareDecodingMode),
772 Description: "Hardware vs software video decoding",
773 Values: []string{"auto", "force", "disable"},
774 Section: SectionMedia,
775 },
776 {
777 Key: "media.gl_rendering_mode",
778 Type: "string",
779 Default: string(defaults.Media.GLRenderingMode),
780 Description: "OpenGL API selection for video rendering",
781 Values: []string{"auto", "gles2", "gl3", "none"},
782 Section: SectionMedia,
783 },
784 {
785 Key: "media.prefer_av1",
786 Type: "bool",
787 Default: fmt.Sprintf("%t", defaults.Media.PreferAV1),
788 Description: "Prioritize AV1 codec when available",
789 Section: SectionMedia,
790 },
791 {
792 Key: "media.show_diagnostics",
793 Type: "bool",
794 Default: fmt.Sprintf("%t", defaults.Media.ShowDiagnosticsOnStartup),
795 Description: "Show media capability warnings at startup",
796 Section: SectionMedia,
797 },
798 {
799 Key: "media.force_vsync",
800 Type: "bool",
801 Default: fmt.Sprintf("%t", defaults.Media.ForceVSync),
802 Description: "Force vertical sync for video playback",
803 Section: SectionMedia,
804 },
805 {
806 Key: "media.gstreamer_debug_level",
807 Type: "int",
808 Default: fmt.Sprintf("%d", defaults.Media.GStreamerDebugLevel),
809 Description: "GStreamer debug verbosity (0=off, 1-5)",
810 Range: "0-5",
811 Section: SectionMedia,
812 },
813 }
814}
815
816func (*SchemaProvider) getUpdateKeys(defaults *Config) []entity.ConfigKeyInfo {
817 return []entity.ConfigKeyInfo{
818 {
819 Key: "update.enable_on_startup",
820 Type: "bool",
821 Default: fmt.Sprintf("%t", defaults.Update.EnableOnStartup),
822 Description: "Check for updates on browser startup",
823 Section: SectionUpdate,
824 },
825 {
826 Key: "update.auto_download",
827 Type: "bool",
828 Default: fmt.Sprintf("%t", defaults.Update.AutoDownload),
829 Description: "Auto-download updates in background",
830 Section: SectionUpdate,
831 },
832 {
833 Key: "update.notify_on_new_settings",
834 Type: "bool",
835 Default: fmt.Sprintf("%t", defaults.Update.NotifyOnNewSettings),
836 Description: "Show toast when new config settings available",
837 Section: SectionUpdate,
838 },
839 }
840}
841
842func (*SchemaProvider) getDebugKeys(defaults *Config) []entity.ConfigKeyInfo {
843 return []entity.ConfigKeyInfo{
844 {
845 Key: "debug.enable_devtools",
846 Type: "bool",
847 Default: fmt.Sprintf("%t", defaults.Debug.EnableDevTools),
848 Description: "Enable browser developer tools (F12)",
849 Section: SectionDebug,
850 },
851 }
852}
853
854func (*SchemaProvider) getPerformanceKeys(defaults *Config) []entity.ConfigKeyInfo {
855 return []entity.ConfigKeyInfo{
856 {
857 Key: "performance.zoom_cache_size",
858 Type: "int",
859 Default: fmt.Sprintf("%d", defaults.Performance.ZoomCacheSize),
860 Description: "Number of domain zoom levels to cache",
861 Range: ">=0",
862 Section: SectionPerformance,
863 },
864 {
865 Key: "performance.webview_pool_prewarm_count",
866 Type: "int",
867 Default: fmt.Sprintf("%d", defaults.Performance.WebViewPoolPrewarmCount),
868 Description: "WebViews to pre-create at startup",
869 Range: ">=0",
870 Section: SectionPerformance,
871 },
872 }
873}
874
875func (*SchemaProvider) getRuntimeKeys(_ *Config) []entity.ConfigKeyInfo {
876 return []entity.ConfigKeyInfo{
877 {
878 Key: "runtime.prefix",
879 Type: "string",
880 Default: "(empty)",
881 Description: "Custom runtime prefix for WebKitGTK/GTK",
882 Section: SectionRuntime,
883 },
884 }
885}
886
887func (*SchemaProvider) getDatabaseKeys() []entity.ConfigKeyInfo {
888 // Get actual default path for display
889 dbPath := "$XDG_DATA_HOME/" + appName + "/" + databaseName
890 if path, err := GetDatabaseFile(); err == nil {
891 dbPath = path
892 }
893
894 return []entity.ConfigKeyInfo{
895 {
896 Key: "database.path",
897 Type: "string",
898 Default: dbPath,
899 Description: "Path to SQLite database file",
900 Section: SectionDatabase,
901 },
902 }
903}