detached bc09266

refactor(ui-logging): replace unicode symbols with ASCII status codes [OK]/[KO]

commit
bc0926673dfd83856eb0ae71afe6f156c5a47a98
author
bnema · · 2025-10-28 22:53 UTC
committer
bnema · · 2025-10-28 19:15 UTC
parent
cc22049
signature
unsigned
3 files · +7 -12
M internal/ui/styles/theme.go +2 -2
@@ -283,7 +283,7 @@ func HuhTheme() *huh.Theme {
283283 theme.Focused.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
284284 theme.Focused.MultiSelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")
285285 theme.Focused.SelectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
286- theme.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("10")).SetString("✓ ") // Bright green
286+ theme.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("10")).SetString("[OK] ") // Bright green
287287 theme.Focused.UnselectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
288288 theme.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("○ ") // Grey
289289
@@ -317,7 +317,7 @@ func HuhTheme() *huh.Theme {
317317 theme.Focused.TextInput.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
318318
319319 // Error styles
320- theme.Focused.ErrorIndicator = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("✗ ") // Bright red
320+ theme.Focused.ErrorIndicator = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("[KO] ") // Bright red
321321 theme.Focused.ErrorMessage = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Bold(true) // Bright red
322322
323323 return theme
@@ -283,7 +283,7 @@ func HuhTheme() *huh.Theme {
283 theme.Focused.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White283 theme.Focused.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
284 theme.Focused.MultiSelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")284 theme.Focused.MultiSelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")
285 theme.Focused.SelectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan285 theme.Focused.SelectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
286- theme.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("10")).SetString("✓ ") // Bright green286+ theme.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("10")).SetString("[OK] ") // Bright green
287 theme.Focused.UnselectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White287 theme.Focused.UnselectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
288 theme.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("○ ") // Grey288 theme.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("○ ") // Grey
289 289
@@ -317,7 +317,7 @@ func HuhTheme() *huh.Theme {
317 theme.Focused.TextInput.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan317 theme.Focused.TextInput.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
318 318
319 // Error styles319 // Error styles
320- theme.Focused.ErrorIndicator = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("✗ ") // Bright red320+ theme.Focused.ErrorIndicator = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("[KO] ") // Bright red
321 theme.Focused.ErrorMessage = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Bold(true) // Bright red321 theme.Focused.ErrorMessage = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Bold(true) // Bright red
322 322
323 return theme323 return theme
M internal/ui/views/network.go +2 -2
@@ -21,12 +21,12 @@ func RenderNetworkCheck(m model.UI) string {
2121 } else if m.NetworkErr() != nil {
2222 // Network check failed
2323 errorMsg := fmt.Sprintf("Network error: %v", m.NetworkErr())
24- content = CenterText(styles.ErrorStyle.Render("✗ Network Check Failed"), m.Width()) + "\n\n" +
24+ content = CenterText(styles.ErrorStyle.Render("[KO] Network Check Failed"), m.Width()) + "\n\n" +
2525 CenterText(errorMsg, m.Width()) + "\n\n" +
2626 CenterText(styles.HelpStyle.Render("Press ENTER to retry or CTRL+C to exit"), m.Width())
2727 } else {
2828 // Network check passed
29- content = CenterText(styles.SuccessStyle.Render("✓ Network Check Passed"), m.Width()) + "\n\n" +
29+ content = CenterText(styles.SuccessStyle.Render("[OK] Network Check Passed"), m.Width()) + "\n\n" +
3030 CenterText(styles.HelpStyle.Render("Press ENTER to continue"), m.Width())
3131 }
3232
@@ -21,12 +21,12 @@ func RenderNetworkCheck(m model.UI) string {
21 } else if m.NetworkErr() != nil {21 } else if m.NetworkErr() != nil {
22 // Network check failed22 // Network check failed
23 errorMsg := fmt.Sprintf("Network error: %v", m.NetworkErr())23 errorMsg := fmt.Sprintf("Network error: %v", m.NetworkErr())
24- content = CenterText(styles.ErrorStyle.Render("✗ Network Check Failed"), m.Width()) + "\n\n" +24+ content = CenterText(styles.ErrorStyle.Render("[KO] Network Check Failed"), m.Width()) + "\n\n" +
25 CenterText(errorMsg, m.Width()) + "\n\n" +25 CenterText(errorMsg, m.Width()) + "\n\n" +
26 CenterText(styles.HelpStyle.Render("Press ENTER to retry or CTRL+C to exit"), m.Width())26 CenterText(styles.HelpStyle.Render("Press ENTER to retry or CTRL+C to exit"), m.Width())
27 } else {27 } else {
28 // Network check passed28 // Network check passed
29- content = CenterText(styles.SuccessStyle.Render("✓ Network Check Passed"), m.Width()) + "\n\n" +29+ content = CenterText(styles.SuccessStyle.Render("[OK] Network Check Passed"), m.Width()) + "\n\n" +
30 CenterText(styles.HelpStyle.Render("Press ENTER to continue"), m.Width())30 CenterText(styles.HelpStyle.Render("Press ENTER to continue"), m.Width())
31 }31 }
32 32
M internal/ui/views/results.go +3 -8
@@ -12,19 +12,14 @@ import (
1212 func RenderSuccess(m model.UI, duration time.Duration, phaseDurations map[string]time.Duration) string {
1313 cfg := m.Config()
1414
15- s := styles.SuccessStyle.Render("✓ Installation Complete!") + "\n\n"
15+ s := styles.SuccessStyle.Render("[OK] Installation Complete!") + "\n\n"
1616 s += "Installation Summary:\n"
1717 s += fmt.Sprintf(" Hostname: %s\n", cfg.Hostname)
1818 s += fmt.Sprintf(" Disk: %s\n", cfg.TargetDisk)
1919 s += fmt.Sprintf(" Kernel: %s\n", cfg.KernelChoice)
2020 s += fmt.Sprintf(" Total Time: %s\n\n", formatDuration(duration))
2121
22- s += "Phase Breakdown:\n"
23- for phase, dur := range phaseDurations {
24- s += fmt.Sprintf(" %s: %s\n", phase, formatDuration(dur))
25- }
26-
27- s += "\nNext Steps:\n"
22+ s += "Next Steps:\n"
2823 s += " 1. Remove installation media\n"
2924 s += " 2. Reboot the system\n"
3025 s += " 3. First-boot setup will run automatically\n\n"
@@ -35,7 +30,7 @@ func RenderSuccess(m model.UI, duration time.Duration, phaseDurations map[string
3530
3631 // RenderError renders the error screen with log tail (centered)
3732 func RenderError(m model.UI, err error, phaseName string, duration time.Duration) string {
38- s := styles.ErrorStyle.Render("✗ Installation Failed") + "\n\n"
33+ s := styles.ErrorStyle.Render("[KO] Installation Failed") + "\n\n"
3934 s += fmt.Sprintf("Phase: %s\n", phaseName)
4035 s += fmt.Sprintf("Error: %v\n", err)
4136 s += fmt.Sprintf("Duration before failure: %s\n\n", formatDuration(duration))
@@ -12,19 +12,14 @@ import (
12 func RenderSuccess(m model.UI, duration time.Duration, phaseDurations map[string]time.Duration) string {12 func RenderSuccess(m model.UI, duration time.Duration, phaseDurations map[string]time.Duration) string {
13 cfg := m.Config()13 cfg := m.Config()
14 14
15- s := styles.SuccessStyle.Render("✓ Installation Complete!") + "\n\n"15+ s := styles.SuccessStyle.Render("[OK] Installation Complete!") + "\n\n"
16 s += "Installation Summary:\n"16 s += "Installation Summary:\n"
17 s += fmt.Sprintf(" Hostname: %s\n", cfg.Hostname)17 s += fmt.Sprintf(" Hostname: %s\n", cfg.Hostname)
18 s += fmt.Sprintf(" Disk: %s\n", cfg.TargetDisk)18 s += fmt.Sprintf(" Disk: %s\n", cfg.TargetDisk)
19 s += fmt.Sprintf(" Kernel: %s\n", cfg.KernelChoice)19 s += fmt.Sprintf(" Kernel: %s\n", cfg.KernelChoice)
20 s += fmt.Sprintf(" Total Time: %s\n\n", formatDuration(duration))20 s += fmt.Sprintf(" Total Time: %s\n\n", formatDuration(duration))
21 21
22- s += "Phase Breakdown:\n"22+ s += "Next Steps:\n"
23- for phase, dur := range phaseDurations {
24- s += fmt.Sprintf(" %s: %s\n", phase, formatDuration(dur))
25- }
26-
27- s += "\nNext Steps:\n"
28 s += " 1. Remove installation media\n"23 s += " 1. Remove installation media\n"
29 s += " 2. Reboot the system\n"24 s += " 2. Reboot the system\n"
30 s += " 3. First-boot setup will run automatically\n\n"25 s += " 3. First-boot setup will run automatically\n\n"
@@ -35,7 +30,7 @@ func RenderSuccess(m model.UI, duration time.Duration, phaseDurations map[string
35 30
36 // RenderError renders the error screen with log tail (centered)31 // RenderError renders the error screen with log tail (centered)
37 func RenderError(m model.UI, err error, phaseName string, duration time.Duration) string {32 func RenderError(m model.UI, err error, phaseName string, duration time.Duration) string {
38- s := styles.ErrorStyle.Render("✗ Installation Failed") + "\n\n"33+ s := styles.ErrorStyle.Render("[KO] Installation Failed") + "\n\n"
39 s += fmt.Sprintf("Phase: %s\n", phaseName)34 s += fmt.Sprintf("Phase: %s\n", phaseName)
40 s += fmt.Sprintf("Error: %v\n", err)35 s += fmt.Sprintf("Error: %v\n", err)
41 s += fmt.Sprintf("Duration before failure: %s\n\n", formatDuration(duration))36 s += fmt.Sprintf("Duration before failure: %s\n\n", formatDuration(duration))

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 1

Tags 0

    ↑↓ moveenter openesc close