detached 7db7973

fix: improve CLI routes list display

- Convert all icon constants to Unicode escape sequences for portability
- Add new container status icons (running, stopped, paused, restarting, exited)
- Render status badges with icons instead of text labels
- Fix gray/faded alternating table rows (use same color for all rows)
- Use container icon prefix for attachment tree display
commit
7db79736234ce027759e7187b256cd19b3375271
author
brice · · 2026-01-17 14:17 UTC
parent
50a9654
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
4 files · +120 -69
M internal/adapters/in/cli/routes.go +3 -6
@@ -169,12 +169,9 @@ func runRoutesListRemote(ctx context.Context, client *remote.Client) error {
169169 displayNetwork := truncateNetwork(route.Network, networkColWidth)
170170 rows = append(rows, []string{route.Domain, displayImage, displayNetwork, containerBadge, httpStatus})
171171
172- for i, attachment := range route.Attachments {
173- prefix := "|-"
174- if i == len(route.Attachments)-1 {
175- prefix = "`-"
176- }
177- attachmentName := prefix + " " + attachment.Name
172+ for _, attachment := range route.Attachments {
173+ // Use container icon with indent for attachment tree display
174+ attachmentName := " " + styles.IconContainer + " " + attachment.Name
178175 if len(attachmentName) > 25 {
179176 attachmentName = attachmentName[:22] + "..."
180177 }
@@ -169,12 +169,9 @@ func runRoutesListRemote(ctx context.Context, client *remote.Client) error {
169 displayNetwork := truncateNetwork(route.Network, networkColWidth)169 displayNetwork := truncateNetwork(route.Network, networkColWidth)
170 rows = append(rows, []string{route.Domain, displayImage, displayNetwork, containerBadge, httpStatus})170 rows = append(rows, []string{route.Domain, displayImage, displayNetwork, containerBadge, httpStatus})
171 171
172- for i, attachment := range route.Attachments {172+ for _, attachment := range route.Attachments {
173- prefix := "|-"173+ // Use container icon with indent for attachment tree display
174- if i == len(route.Attachments)-1 {174+ attachmentName := " " + styles.IconContainer + " " + attachment.Name
175- prefix = "`-"
176- }
177- attachmentName := prefix + " " + attachment.Name
178 if len(attachmentName) > 25 {175 if len(attachmentName) > 25 {
179 attachmentName = attachmentName[:22] + "..."176 attachmentName = attachmentName[:22] + "..."
180 }177 }
M internal/adapters/in/cli/ui/components/status.go +41 -10
@@ -19,6 +19,10 @@ const (
1919 StatusPending
2020 StatusRunning
2121 StatusStopped
22+ StatusPaused
23+ StatusRestarting
24+ StatusExited
25+ StatusUnknown
2226 )
2327
2428 // StatusConfig holds configuration for status rendering.
@@ -54,13 +58,29 @@ var DefaultStatusConfigs = map[Status]StatusConfig{
5458 Style: styles.Theme.Muted,
5559 },
5660 StatusRunning: {
57- Icon: styles.IconSuccess,
61+ Icon: styles.IconRunning,
5862 Style: styles.Theme.Success,
5963 },
6064 StatusStopped: {
61- Icon: styles.IconError,
65+ Icon: styles.IconStopped,
66+ Style: styles.Theme.Error,
67+ },
68+ StatusPaused: {
69+ Icon: styles.IconPaused,
70+ Style: styles.Theme.Warning,
71+ },
72+ StatusRestarting: {
73+ Icon: styles.IconRestarting,
74+ Style: styles.Theme.Warning,
75+ },
76+ StatusExited: {
77+ Icon: styles.IconExited,
6278 Style: styles.Theme.Error,
6379 },
80+ StatusUnknown: {
81+ Icon: styles.IconUnknown,
82+ Style: styles.Theme.Muted,
83+ },
6484 }
6585
6686 // RenderStatus renders a status with icon and optional label.
@@ -72,22 +92,25 @@ func RenderStatus(status Status, label string) string {
7292 return config.Style.Render(config.Icon + " " + label)
7393 }
7494
75-// RenderStatusBadge renders a status as a badge with background.
76-func RenderStatusBadge(status Status, label string) string {
95+// RenderStatusBadge renders a status as a badge with background and icon.
96+func RenderStatusBadge(status Status, _ string) string {
97+ config := DefaultStatusConfigs[status]
7798 var badgeStyle lipgloss.Style
7899 switch status {
79100 case StatusSuccess, StatusRunning:
80101 badgeStyle = styles.Theme.BadgeSuccess
81- case StatusError, StatusStopped:
102+ case StatusError, StatusStopped, StatusExited:
82103 badgeStyle = styles.Theme.BadgeError
83- case StatusWarning:
104+ case StatusWarning, StatusPaused, StatusRestarting:
84105 badgeStyle = styles.Theme.BadgeWarning
85106 case StatusPending:
86107 badgeStyle = styles.Theme.BadgePending
108+ case StatusUnknown:
109+ badgeStyle = styles.Theme.Muted
87110 default:
88111 badgeStyle = styles.Theme.BadgeInfo
89112 }
90- return badgeStyle.Render(label)
113+ return badgeStyle.Render(config.Icon)
91114 }
92115
93116 // ParseStatus converts a string status to Status type.
@@ -101,14 +124,22 @@ func ParseStatus(s string) Status {
101124 return StatusWarning
102125 case "info":
103126 return StatusInfo
104- case "pending", "starting", "waiting":
127+ case "pending", "starting", "waiting", "created":
105128 return StatusPending
106129 case "running", "up":
107130 return StatusRunning
108- case "stopped", "down", "exited":
131+ case "stopped", "down":
109132 return StatusStopped
133+ case "paused":
134+ return StatusPaused
135+ case "restarting":
136+ return StatusRestarting
137+ case "exited", "dead":
138+ return StatusExited
139+ case "unknown":
140+ return StatusUnknown
110141 default:
111- return StatusInfo
142+ return StatusUnknown
112143 }
113144 }
114145
@@ -19,6 +19,10 @@ const (
19 StatusPending19 StatusPending
20 StatusRunning20 StatusRunning
21 StatusStopped21 StatusStopped
22+ StatusPaused
23+ StatusRestarting
24+ StatusExited
25+ StatusUnknown
22 )26 )
23 27
24 // StatusConfig holds configuration for status rendering.28 // StatusConfig holds configuration for status rendering.
@@ -54,13 +58,29 @@ var DefaultStatusConfigs = map[Status]StatusConfig{
54 Style: styles.Theme.Muted,58 Style: styles.Theme.Muted,
55 },59 },
56 StatusRunning: {60 StatusRunning: {
57- Icon: styles.IconSuccess,61+ Icon: styles.IconRunning,
58 Style: styles.Theme.Success,62 Style: styles.Theme.Success,
59 },63 },
60 StatusStopped: {64 StatusStopped: {
61- Icon: styles.IconError,65+ Icon: styles.IconStopped,
66+ Style: styles.Theme.Error,
67+ },
68+ StatusPaused: {
69+ Icon: styles.IconPaused,
70+ Style: styles.Theme.Warning,
71+ },
72+ StatusRestarting: {
73+ Icon: styles.IconRestarting,
74+ Style: styles.Theme.Warning,
75+ },
76+ StatusExited: {
77+ Icon: styles.IconExited,
62 Style: styles.Theme.Error,78 Style: styles.Theme.Error,
63 },79 },
80+ StatusUnknown: {
81+ Icon: styles.IconUnknown,
82+ Style: styles.Theme.Muted,
83+ },
64 }84 }
65 85
66 // RenderStatus renders a status with icon and optional label.86 // RenderStatus renders a status with icon and optional label.
@@ -72,22 +92,25 @@ func RenderStatus(status Status, label string) string {
72 return config.Style.Render(config.Icon + " " + label)92 return config.Style.Render(config.Icon + " " + label)
73 }93 }
74 94
75-// RenderStatusBadge renders a status as a badge with background.95+// RenderStatusBadge renders a status as a badge with background and icon.
76-func RenderStatusBadge(status Status, label string) string {96+func RenderStatusBadge(status Status, _ string) string {
97+ config := DefaultStatusConfigs[status]
77 var badgeStyle lipgloss.Style98 var badgeStyle lipgloss.Style
78 switch status {99 switch status {
79 case StatusSuccess, StatusRunning:100 case StatusSuccess, StatusRunning:
80 badgeStyle = styles.Theme.BadgeSuccess101 badgeStyle = styles.Theme.BadgeSuccess
81- case StatusError, StatusStopped:102+ case StatusError, StatusStopped, StatusExited:
82 badgeStyle = styles.Theme.BadgeError103 badgeStyle = styles.Theme.BadgeError
83- case StatusWarning:104+ case StatusWarning, StatusPaused, StatusRestarting:
84 badgeStyle = styles.Theme.BadgeWarning105 badgeStyle = styles.Theme.BadgeWarning
85 case StatusPending:106 case StatusPending:
86 badgeStyle = styles.Theme.BadgePending107 badgeStyle = styles.Theme.BadgePending
108+ case StatusUnknown:
109+ badgeStyle = styles.Theme.Muted
87 default:110 default:
88 badgeStyle = styles.Theme.BadgeInfo111 badgeStyle = styles.Theme.BadgeInfo
89 }112 }
90- return badgeStyle.Render(label)113+ return badgeStyle.Render(config.Icon)
91 }114 }
92 115
93 // ParseStatus converts a string status to Status type.116 // ParseStatus converts a string status to Status type.
@@ -101,14 +124,22 @@ func ParseStatus(s string) Status {
101 return StatusWarning124 return StatusWarning
102 case "info":125 case "info":
103 return StatusInfo126 return StatusInfo
104- case "pending", "starting", "waiting":127+ case "pending", "starting", "waiting", "created":
105 return StatusPending128 return StatusPending
106 case "running", "up":129 case "running", "up":
107 return StatusRunning130 return StatusRunning
108- case "stopped", "down", "exited":131+ case "stopped", "down":
109 return StatusStopped132 return StatusStopped
133+ case "paused":
134+ return StatusPaused
135+ case "restarting":
136+ return StatusRestarting
137+ case "exited", "dead":
138+ return StatusExited
139+ case "unknown":
140+ return StatusUnknown
110 default:141 default:
111- return StatusInfo142+ return StatusUnknown
112 }143 }
113 }144 }
114 145
M internal/adapters/in/cli/ui/components/table.go +1 -1
@@ -45,7 +45,7 @@ func NewTable(opts ...TableOption) *TableModel {
4545 Foreground(styles.ColorText).
4646 Padding(0, 1),
4747 evenStyle: lipgloss.NewStyle().
48- Foreground(styles.ColorTextMuted).
48+ Foreground(styles.ColorText).
4949 Padding(0, 1),
5050 }
5151
@@ -45,7 +45,7 @@ func NewTable(opts ...TableOption) *TableModel {
45 Foreground(styles.ColorText).45 Foreground(styles.ColorText).
46 Padding(0, 1),46 Padding(0, 1),
47 evenStyle: lipgloss.NewStyle().47 evenStyle: lipgloss.NewStyle().
48- Foreground(styles.ColorTextMuted).48+ Foreground(styles.ColorText).
49 Padding(0, 1),49 Padding(0, 1),
50 }50 }
51 51
M internal/adapters/in/cli/ui/styles/icons.go +75 -52
@@ -2,78 +2,101 @@ package styles
22
33 // Nerd Font icons for terminal UI.
44 // These icons require a Nerd Font compatible terminal font.
5+// All icons are defined using Unicode escape sequences for portability.
56 // Fallback ASCII alternatives are provided where practical.
67 const (
78 // Status indicators
8- IconSuccess = "" // nf-fa-check (U+F00C)
9- IconError = "" // nf-fa-times (U+F00D)
10- IconWarning = "" // nf-fa-exclamation_triangle (U+F071)
11- IconInfo = "" // nf-fa-info_circle (U+F05A)
12- IconPending = "" // nf-fa-clock_o (U+F017)
9+ IconSuccess = "\uf00c" // nf-fa-check
10+ IconError = "\uf00d" // nf-fa-times
11+ IconWarning = "\uf071" // nf-fa-exclamation_triangle
12+ IconInfo = "\uf05a" // nf-fa-info_circle
13+ IconPending = "\uf017" // nf-fa-clock
14+
15+ // Container status icons
16+ IconRunning = "\uf00c" // nf-fa-check (green)
17+ IconStopped = "\uf04d" // nf-fa-stop
18+ IconExited = "\uf00d" // nf-fa-times
19+ IconPaused = "\uf04c" // nf-fa-pause
20+ IconRestarting = "\uf021" // nf-fa-refresh
21+ IconUnknown = "\uf071" // nf-fa-exclamation_triangle
1322
1423 // Objects
15- IconRoute = "" // nf-fa-sitemap (U+F0E8)
16- IconSecret = "" // nf-fa-lock (U+F023)
17- IconToken = "" // nf-fa-key (U+F084)
18- IconContainer = "" // nf-oct-container (U+F489)
19- IconServer = "" // nf-fa-server (U+F233)
20- IconNetwork = "󰛳" // nf-md-lan (U+F06F3)
21- IconVolume = "" // nf-fa-database (U+F1C0)
22- IconImage = "" // nf-fa-archive (U+F187)
24+ IconRoute = "\uf0e8" // nf-fa-sitemap
25+ IconSecret = "\uf023" // nf-fa-lock
26+ IconToken = "\uf084" // nf-fa-key
27+ IconContainer = "\uf4b7" // nf-oct-container
28+ IconServer = "\uf233" // nf-fa-server
29+ IconNetwork = "\U000f0317" // nf-md-lan
30+ IconVolume = "\uf1c0" // nf-fa-database
31+ IconImage = "\uf187" // nf-fa-archive
32+ IconDocker = "\ue7b0" // nf-dev-docker
2333
2434 // Actions
25- IconAdd = "" // nf-fa-plus (U+F067)
26- IconRemove = "" // nf-fa-minus (U+F068)
27- IconEdit = "" // nf-fa-pencil (U+F040)
28- IconRefresh = "" // nf-fa-refresh (U+F021)
29- IconUpload = "" // nf-fa-cloud_upload (U+F0EE)
30- IconDelete = "" // nf-fa-trash (U+F1F8)
35+ IconAdd = "\uf067" // nf-fa-plus
36+ IconRemove = "\uf068" // nf-fa-minus
37+ IconEdit = "\uf040" // nf-fa-pencil
38+ IconRefresh = "\uf021" // nf-fa-refresh
39+ IconUpload = "\uf0ee" // nf-fa-cloud_upload
40+ IconDelete = "\uf1f8" // nf-fa-trash
3141
3242 // Navigation
33- IconArrowRight = "" // nf-fa-arrow_right (U+F061)
34- IconArrowLeft = "" // nf-fa-arrow_left (U+F060)
35- IconArrowUp = "" // nf-fa-arrow_up (U+F062)
36- IconArrowDown = "" // nf-fa-arrow_down (U+F063)
37- IconChevron = "" // nf-fa-chevron_right (U+F054)
43+ IconArrowRight = "\uf061" // nf-fa-arrow_right
44+ IconArrowLeft = "\uf060" // nf-fa-arrow_left
45+ IconArrowUp = "\uf062" // nf-fa-arrow_up
46+ IconArrowDown = "\uf063" // nf-fa-arrow_down
47+ IconChevron = "\uf054" // nf-fa-chevron_right
3848
3949 // UI elements
40- IconBullet = "▸" // Simple triangle bullet
41- IconDot = "●" // Filled circle
42- IconDotEmpty = "○" // Empty circle
43- IconCheckbox = "" // nf-fa-square_o (U+F096)
44- IconChecked = "" // nf-fa-check_square_o (U+F046)
45- IconRadio = "" // nf-fa-circle_o (U+F10C)
46- IconRadioCheck = "" // nf-fa-dot_circle_o (U+F192)
50+ IconBullet = "\u25b8" // ▸ Simple triangle bullet
51+ IconDot = "\u25cf" // ● Filled circle
52+ IconDotEmpty = "\u25cb" // ○ Empty circle
53+ IconCheckbox = "\uf096" // nf-fa-square_o
54+ IconChecked = "\uf046" // nf-fa-check_square_o
55+ IconRadio = "\uf10c" // nf-fa-circle_o
56+ IconRadioCheck = "\uf192" // nf-fa-dot_circle_o
57+ IconPlay = "\uf04b" // nf-fa-play
58+ IconStop = "\uf04d" // nf-fa-stop
59+ IconPause = "\uf04c" // nf-fa-pause
60+
61+ // Tree structure
62+ IconTreeBranch = "\u251c" // ├
63+ IconTreeLast = "\u2514" // └
64+ IconTreeLine = "\u2500" // ─
65+ IconTreeVert = "\u2502" // │
4766
4867 // Spinners (individual frames)
49- SpinnerDot = "⣾⣽⣻⢿⡿⣟⣯⣷"
68+ SpinnerDot = "\u28fe\u28fd\u28fb\u28bf\u287f\u28df\u28ef\u28f7"
5069 SpinnerLine = "|/-\\"
51- SpinnerCircle = "◐◓◑◒"
52- SpinnerBrail = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
70+ SpinnerCircle = "\u25d0\u25d3\u25d1\u25d2"
71+ SpinnerBrail = "\u280b\u2819\u2839\u2838\u283c\u2834\u2826\u2827\u2807\u280f"
5372
5473 // Borders and decorations
55- BorderHorizontal = "─"
56- BorderVertical = "│"
57- BorderCornerTL = "┌"
58- BorderCornerTR = "┐"
59- BorderCornerBL = "└"
60- BorderCornerBR = "┘"
61- BorderT = "┬"
62- BorderB = "┴"
63- BorderL = "├"
64- BorderR = "┤"
65- BorderCross = "┼"
74+ BorderHorizontal = "\u2500" // ─
75+ BorderVertical = "\u2502" // │
76+ BorderCornerTL = "\u250c" // ┌
77+ BorderCornerTR = "\u2510" // ┐
78+ BorderCornerBL = "\u2514" // └
79+ BorderCornerBR = "\u2518" // ┘
80+ BorderT = "\u252c" // ┬
81+ BorderB = "\u2534" // ┴
82+ BorderL = "\u251c" // ├
83+ BorderR = "\u2524" // ┤
84+ BorderCross = "\u253c" // ┼
6685
6786 // Gordon branding
68- IconGordon = "" // nf-fa-cube (U+F1B2)
87+ IconGordon = "\uf1b2" // nf-fa-cube
6988 )
7089
7190 // ASCII fallback alternatives for terminals without Nerd Fonts.
7291 const (
73- AsciiSuccess = "[OK]"
74- AsciiError = "[X]"
75- AsciiWarning = "[!]"
76- AsciiInfo = "[i]"
77- AsciiBullet = ">"
78- AsciiDot = "*"
92+ AsciiSuccess = "[OK]"
93+ AsciiError = "[X]"
94+ AsciiWarning = "[!]"
95+ AsciiInfo = "[i]"
96+ AsciiBullet = ">"
97+ AsciiDot = "*"
98+ AsciiRunning = "[R]"
99+ AsciiStopped = "[S]"
100+ AsciiTreeBranch = "|-"
101+ AsciiTreeLast = "`-"
79102 )
@@ -2,78 +2,101 @@ package styles
2 2
3 // Nerd Font icons for terminal UI.3 // Nerd Font icons for terminal UI.
4 // These icons require a Nerd Font compatible terminal font.4 // These icons require a Nerd Font compatible terminal font.
5+// All icons are defined using Unicode escape sequences for portability.
5 // Fallback ASCII alternatives are provided where practical.6 // Fallback ASCII alternatives are provided where practical.
6 const (7 const (
7 // Status indicators8 // Status indicators
8- IconSuccess = "" // nf-fa-check (U+F00C)9+ IconSuccess = "\uf00c" // nf-fa-check
9- IconError = "" // nf-fa-times (U+F00D)10+ IconError = "\uf00d" // nf-fa-times
10- IconWarning = "" // nf-fa-exclamation_triangle (U+F071)11+ IconWarning = "\uf071" // nf-fa-exclamation_triangle
11- IconInfo = "" // nf-fa-info_circle (U+F05A)12+ IconInfo = "\uf05a" // nf-fa-info_circle
12- IconPending = "" // nf-fa-clock_o (U+F017)13+ IconPending = "\uf017" // nf-fa-clock
14+
15+ // Container status icons
16+ IconRunning = "\uf00c" // nf-fa-check (green)
17+ IconStopped = "\uf04d" // nf-fa-stop
18+ IconExited = "\uf00d" // nf-fa-times
19+ IconPaused = "\uf04c" // nf-fa-pause
20+ IconRestarting = "\uf021" // nf-fa-refresh
21+ IconUnknown = "\uf071" // nf-fa-exclamation_triangle
13 22
14 // Objects23 // Objects
15- IconRoute = "" // nf-fa-sitemap (U+F0E8)24+ IconRoute = "\uf0e8" // nf-fa-sitemap
16- IconSecret = "" // nf-fa-lock (U+F023)25+ IconSecret = "\uf023" // nf-fa-lock
17- IconToken = "" // nf-fa-key (U+F084)26+ IconToken = "\uf084" // nf-fa-key
18- IconContainer = "" // nf-oct-container (U+F489)27+ IconContainer = "\uf4b7" // nf-oct-container
19- IconServer = "" // nf-fa-server (U+F233)28+ IconServer = "\uf233" // nf-fa-server
20- IconNetwork = "󰛳" // nf-md-lan (U+F06F3)29+ IconNetwork = "\U000f0317" // nf-md-lan
21- IconVolume = "" // nf-fa-database (U+F1C0)30+ IconVolume = "\uf1c0" // nf-fa-database
22- IconImage = "" // nf-fa-archive (U+F187)31+ IconImage = "\uf187" // nf-fa-archive
32+ IconDocker = "\ue7b0" // nf-dev-docker
23 33
24 // Actions34 // Actions
25- IconAdd = "" // nf-fa-plus (U+F067)35+ IconAdd = "\uf067" // nf-fa-plus
26- IconRemove = "" // nf-fa-minus (U+F068)36+ IconRemove = "\uf068" // nf-fa-minus
27- IconEdit = "" // nf-fa-pencil (U+F040)37+ IconEdit = "\uf040" // nf-fa-pencil
28- IconRefresh = "" // nf-fa-refresh (U+F021)38+ IconRefresh = "\uf021" // nf-fa-refresh
29- IconUpload = "" // nf-fa-cloud_upload (U+F0EE)39+ IconUpload = "\uf0ee" // nf-fa-cloud_upload
30- IconDelete = "" // nf-fa-trash (U+F1F8)40+ IconDelete = "\uf1f8" // nf-fa-trash
31 41
32 // Navigation42 // Navigation
33- IconArrowRight = "" // nf-fa-arrow_right (U+F061)43+ IconArrowRight = "\uf061" // nf-fa-arrow_right
34- IconArrowLeft = "" // nf-fa-arrow_left (U+F060)44+ IconArrowLeft = "\uf060" // nf-fa-arrow_left
35- IconArrowUp = "" // nf-fa-arrow_up (U+F062)45+ IconArrowUp = "\uf062" // nf-fa-arrow_up
36- IconArrowDown = "" // nf-fa-arrow_down (U+F063)46+ IconArrowDown = "\uf063" // nf-fa-arrow_down
37- IconChevron = "" // nf-fa-chevron_right (U+F054)47+ IconChevron = "\uf054" // nf-fa-chevron_right
38 48
39 // UI elements49 // UI elements
40- IconBullet = "▸" // Simple triangle bullet50+ IconBullet = "\u25b8" // ▸ Simple triangle bullet
41- IconDot = "●" // Filled circle51+ IconDot = "\u25cf" // ● Filled circle
42- IconDotEmpty = "○" // Empty circle52+ IconDotEmpty = "\u25cb" // ○ Empty circle
43- IconCheckbox = "" // nf-fa-square_o (U+F096)53+ IconCheckbox = "\uf096" // nf-fa-square_o
44- IconChecked = "" // nf-fa-check_square_o (U+F046)54+ IconChecked = "\uf046" // nf-fa-check_square_o
45- IconRadio = "" // nf-fa-circle_o (U+F10C)55+ IconRadio = "\uf10c" // nf-fa-circle_o
46- IconRadioCheck = "" // nf-fa-dot_circle_o (U+F192)56+ IconRadioCheck = "\uf192" // nf-fa-dot_circle_o
57+ IconPlay = "\uf04b" // nf-fa-play
58+ IconStop = "\uf04d" // nf-fa-stop
59+ IconPause = "\uf04c" // nf-fa-pause
60+
61+ // Tree structure
62+ IconTreeBranch = "\u251c" // ├
63+ IconTreeLast = "\u2514" // └
64+ IconTreeLine = "\u2500" // ─
65+ IconTreeVert = "\u2502" // │
47 66
48 // Spinners (individual frames)67 // Spinners (individual frames)
49- SpinnerDot = "⣾⣽⣻⢿⡿⣟⣯⣷"68+ SpinnerDot = "\u28fe\u28fd\u28fb\u28bf\u287f\u28df\u28ef\u28f7"
50 SpinnerLine = "|/-\\"69 SpinnerLine = "|/-\\"
51- SpinnerCircle = "◐◓◑◒"70+ SpinnerCircle = "\u25d0\u25d3\u25d1\u25d2"
52- SpinnerBrail = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"71+ SpinnerBrail = "\u280b\u2819\u2839\u2838\u283c\u2834\u2826\u2827\u2807\u280f"
53 72
54 // Borders and decorations73 // Borders and decorations
55- BorderHorizontal = "─"74+ BorderHorizontal = "\u2500" // ─
56- BorderVertical = "│"75+ BorderVertical = "\u2502" // │
57- BorderCornerTL = "┌"76+ BorderCornerTL = "\u250c" // ┌
58- BorderCornerTR = "┐"77+ BorderCornerTR = "\u2510" // ┐
59- BorderCornerBL = "└"78+ BorderCornerBL = "\u2514" // └
60- BorderCornerBR = "┘"79+ BorderCornerBR = "\u2518" // ┘
61- BorderT = "┬"80+ BorderT = "\u252c" // ┬
62- BorderB = "┴"81+ BorderB = "\u2534" // ┴
63- BorderL = "├"82+ BorderL = "\u251c" // ├
64- BorderR = "┤"83+ BorderR = "\u2524" // ┤
65- BorderCross = "┼"84+ BorderCross = "\u253c" // ┼
66 85
67 // Gordon branding86 // Gordon branding
68- IconGordon = "" // nf-fa-cube (U+F1B2)87+ IconGordon = "\uf1b2" // nf-fa-cube
69 )88 )
70 89
71 // ASCII fallback alternatives for terminals without Nerd Fonts.90 // ASCII fallback alternatives for terminals without Nerd Fonts.
72 const (91 const (
73- AsciiSuccess = "[OK]"92+ AsciiSuccess = "[OK]"
74- AsciiError = "[X]"93+ AsciiError = "[X]"
75- AsciiWarning = "[!]"94+ AsciiWarning = "[!]"
76- AsciiInfo = "[i]"95+ AsciiInfo = "[i]"
77- AsciiBullet = ">"96+ AsciiBullet = ">"
78- AsciiDot = "*"97+ AsciiDot = "*"
98+ AsciiRunning = "[R]"
99+ AsciiStopped = "[S]"
100+ AsciiTreeBranch = "|-"
101+ AsciiTreeLast = "`-"
79 )102 )

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 7

Tags 106

↑↓ moveenter openesc close