Align the TUI help legend into a fixed-width column grid.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+49
-31
@@ -152,42 +152,60 @@ func (m Model) helpSep() string {
|
|||||||
return sep
|
return sep
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrapHelpParts packs styled help snippets into lines that fit within width.
|
// padHelpCell pads a styled help snippet to cellW visible columns.
|
||||||
func wrapHelpParts(parts []string, width int, sep string) []string {
|
func padHelpCell(part string, cellW int) string {
|
||||||
|
pad := cellW - lipgloss.Width(part)
|
||||||
|
if pad < 0 {
|
||||||
|
pad = 0
|
||||||
|
}
|
||||||
|
return part + strings.Repeat(" ", pad)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tableHelpParts lays out styled help snippets as a fixed-width column grid.
|
||||||
|
func tableHelpParts(parts []string, width int, sep string) []string {
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
if width < 1 {
|
if width < 1 {
|
||||||
width = 1
|
width = 1
|
||||||
}
|
}
|
||||||
sepW := lipgloss.Width(sep)
|
|
||||||
var lines []string
|
|
||||||
var cur string
|
|
||||||
|
|
||||||
|
cellW := 0
|
||||||
for _, p := range parts {
|
for _, p := range parts {
|
||||||
pw := lipgloss.Width(p)
|
if w := lipgloss.Width(p); w > cellW {
|
||||||
if cur == "" {
|
cellW = w
|
||||||
cur = p
|
}
|
||||||
// Oversized single entry still gets its own line so nothing is dropped.
|
}
|
||||||
if pw > width {
|
if cellW < 1 {
|
||||||
lines = append(lines, cur)
|
cellW = 1
|
||||||
cur = ""
|
}
|
||||||
|
|
||||||
|
sepW := lipgloss.Width(sep)
|
||||||
|
cols := 1
|
||||||
|
if cellW <= width {
|
||||||
|
cols = (width + sepW) / (cellW + sepW)
|
||||||
|
if cols < 1 {
|
||||||
|
cols = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines []string
|
||||||
|
for i := 0; i < len(parts); i += cols {
|
||||||
|
end := i + cols
|
||||||
|
if end > len(parts) {
|
||||||
|
end = len(parts)
|
||||||
|
}
|
||||||
|
row := parts[i:end]
|
||||||
|
cells := make([]string, len(row))
|
||||||
|
for j, p := range row {
|
||||||
|
// Pad every cell except a lone oversized entry on its own row.
|
||||||
|
if len(row) == 1 && lipgloss.Width(p) > width {
|
||||||
|
cells[j] = p
|
||||||
|
} else {
|
||||||
|
cells[j] = padHelpCell(p, cellW)
|
||||||
}
|
}
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if lipgloss.Width(cur)+sepW+pw <= width {
|
lines = append(lines, strings.Join(cells, sep))
|
||||||
cur = cur + sep + p
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
lines = append(lines, cur)
|
|
||||||
cur = p
|
|
||||||
if pw > width {
|
|
||||||
lines = append(lines, cur)
|
|
||||||
cur = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cur != "" {
|
|
||||||
lines = append(lines, cur)
|
|
||||||
}
|
|
||||||
if len(lines) == 0 {
|
|
||||||
return []string{""}
|
|
||||||
}
|
}
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
@@ -203,8 +221,8 @@ func (m Model) renderFooter() string {
|
|||||||
sep := m.helpSep()
|
sep := m.helpSep()
|
||||||
parts := m.helpParts()
|
parts := m.helpParts()
|
||||||
|
|
||||||
// Wrap help across the full width so all bindings stay visible.
|
// Table layout so key/desc columns stay aligned across rows.
|
||||||
lines := wrapHelpParts(parts, width, sep)
|
lines := tableHelpParts(parts, width, sep)
|
||||||
|
|
||||||
// Place version on the last line to the right when it fits; otherwise
|
// Place version on the last line to the right when it fits; otherwise
|
||||||
// put it on an extra right-aligned line.
|
// put it on an extra right-aligned line.
|
||||||
|
|||||||
Reference in New Issue
Block a user