main 5041353

config_schema.go RawHistoryFolder

1package styles
2
3import (
4	"encoding/json"
5	"fmt"
6	"strings"
7
8	"github.com/charmbracelet/lipgloss"
9
10	"github.com/bnema/dumber/internal/domain/entity"
11)
12
13// ConfigSchemaRenderer renders configuration schema information.
14type ConfigSchemaRenderer struct {
15	theme *Theme
16}
17
18// NewConfigSchemaRenderer creates a new ConfigSchemaRenderer.
19func NewConfigSchemaRenderer(theme *Theme) *ConfigSchemaRenderer {
20	return &ConfigSchemaRenderer{theme: theme}
21}
22
23// Render renders the configuration schema in styled format.
24func (r *ConfigSchemaRenderer) Render(keys []entity.ConfigKeyInfo) string {
25	if len(keys) == 0 {
26		return r.theme.Subtle.Render("No configuration keys found")
27	}
28
29	// Group keys by section
30	sections := groupBySection(keys)
31
32	// Build output
33	var parts []string
34
35	// Header
36	header := r.renderHeader()
37	parts = append(parts, header, "")
38
39	// Render each section
40	sectionOrder := []string{
41		"Appearance",
42		"Logging",
43		"History",
44		"Search",
45		"Dmenu",
46		"Workspace",
47		"Session",
48		"Omnibox",
49		"Content Filtering",
50		"Clipboard",
51		"Rendering",
52		"Media",
53		"Update",
54		"Downloads",
55		"Debug",
56		"Performance",
57		"Runtime",
58		"Database",
59	}
60
61	for _, section := range sectionOrder {
62		if sectionKeys, ok := sections[section]; ok {
63			parts = append(parts, r.renderSection(section, sectionKeys), "")
64		}
65	}
66
67	return strings.Join(parts, "\n")
68}
69
70// RenderJSON renders the configuration schema as JSON.
71func (*ConfigSchemaRenderer) RenderJSON(keys []entity.ConfigKeyInfo) (string, error) {
72	data, err := json.MarshalIndent(keys, "", "  ")
73	if err != nil {
74		return "", fmt.Errorf("marshal schema: %w", err)
75	}
76	return string(data), nil
77}
78
79func (r *ConfigSchemaRenderer) renderHeader() string {
80	iconStyle := lipgloss.NewStyle().Foreground(r.theme.Accent)
81	title := fmt.Sprintf("%s %s", iconStyle.Render(IconConfig), r.theme.Title.Render("Config Schema Reference"))
82	return title
83}
84
85func groupBySection(keys []entity.ConfigKeyInfo) map[string][]entity.ConfigKeyInfo {
86	sections := make(map[string][]entity.ConfigKeyInfo)
87	for _, key := range keys {
88		sections[key.Section] = append(sections[key.Section], key)
89	}
90	return sections
91}
92
93func (r *ConfigSchemaRenderer) renderSection(name string, keys []entity.ConfigKeyInfo) string {
94	var lines []string
95
96	for _, key := range keys {
97		lines = append(lines, r.renderKey(key))
98	}
99
100	body := strings.Join(lines, "\n")
101
102	// Create section header (no extra padding/margin)
103	sectionHeader := r.theme.Highlight.Render(name)
104
105	// Build box content: header directly followed by keys
106	boxContent := sectionHeader + "\n" + body
107
108	// Use box style without top padding
109	boxStyle := r.theme.Box.PaddingTop(0)
110
111	return boxStyle.Render(boxContent)
112}
113
114func (r *ConfigSchemaRenderer) renderKey(key entity.ConfigKeyInfo) string {
115	keyStyle := r.theme.Normal.Bold(true)
116	typeStyle := r.theme.Subtle
117	defaultStyle := lipgloss.NewStyle().Foreground(r.theme.Accent)
118	descStyle := r.theme.Subtle
119	valuesStyle := r.theme.Normal
120
121	// Line 1: key name, type, default
122	line1 := fmt.Sprintf(
123		"%s  %s  %s",
124		keyStyle.Render(key.Key),
125		typeStyle.Render(key.Type),
126		defaultStyle.Render(key.Default),
127	)
128
129	// Line 2: description (indented)
130	line2 := fmt.Sprintf("  %s", descStyle.Render(key.Description))
131
132	result := line1 + "\n" + line2
133
134	// Line 3 (optional): values or range
135	if len(key.Values) > 0 {
136		valuesText := "Values: " + strings.Join(key.Values, ", ")
137		line3 := fmt.Sprintf("  %s", valuesStyle.Render(valuesText))
138		result += "\n" + line3
139	} else if key.Range != "" {
140		rangeText := "Range: " + key.Range
141		line3 := fmt.Sprintf("  %s", valuesStyle.Render(rangeText))
142		result += "\n" + line3
143	}
144
145	return result
146}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close