mirror of
https://github.com/lukaszraczylo/lolcathost.git
synced 2026-06-05 23:29:18 +00:00
Add automatic wrapping of the content based on terminal width
This commit is contained in:
+71
-16
@@ -920,8 +920,15 @@ func (m *Model) View() string {
|
||||
currentContent := sb.String()
|
||||
currentLines := strings.Count(currentContent, "\n") + 1
|
||||
|
||||
// Fill space to push footer to bottom (reserve 3 lines for footer)
|
||||
footerHeight := 3
|
||||
// Calculate footer height dynamically (help bar lines + status bar + spacing)
|
||||
footerHeight := 2 // status bar + newline before it
|
||||
var helpBarContent string
|
||||
if m.mode == ViewList {
|
||||
helpBarContent = m.helpBar()
|
||||
helpBarLines := strings.Count(helpBarContent, "\n") + 1
|
||||
footerHeight += helpBarLines + 1 // +1 for newline before help bar
|
||||
}
|
||||
|
||||
remainingLines := m.height - currentLines - footerHeight
|
||||
if remainingLines > 0 {
|
||||
sb.WriteString(strings.Repeat("\n", remainingLines))
|
||||
@@ -930,7 +937,7 @@ func (m *Model) View() string {
|
||||
// Footer (help bar + status bar)
|
||||
if m.mode == ViewList {
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(m.helpBar())
|
||||
sb.WriteString(helpBarContent)
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(m.statusBar())
|
||||
@@ -939,19 +946,67 @@ func (m *Model) View() string {
|
||||
}
|
||||
|
||||
func (m *Model) helpBar() string {
|
||||
return helpBarStyle.Render(fmt.Sprintf("%s/%s: Navigate %s: Toggle %s: New %s: Edit %s: Delete %s: Presets %s: Groups %s: Backups %s: Search %s: Help %s: Quit",
|
||||
helpKeyStyle.Render("↑↓"),
|
||||
helpKeyStyle.Render("jk"),
|
||||
helpKeyStyle.Render("Space"),
|
||||
helpKeyStyle.Render("n"),
|
||||
helpKeyStyle.Render("e"),
|
||||
helpKeyStyle.Render("d"),
|
||||
helpKeyStyle.Render("p"),
|
||||
helpKeyStyle.Render("g"),
|
||||
helpKeyStyle.Render("b"),
|
||||
helpKeyStyle.Render("/"),
|
||||
helpKeyStyle.Render("?"),
|
||||
helpKeyStyle.Render("q")))
|
||||
// Define help items with their display widths (without ANSI codes)
|
||||
type helpItem struct {
|
||||
key string
|
||||
desc string
|
||||
rawWidth int // width without ANSI escape codes
|
||||
}
|
||||
|
||||
items := []helpItem{
|
||||
{"↑↓/jk", "Navigate", 13},
|
||||
{"Space", "Toggle", 13},
|
||||
{"n", "New", 6},
|
||||
{"e", "Edit", 7},
|
||||
{"d", "Delete", 9},
|
||||
{"p", "Presets", 10},
|
||||
{"g", "Groups", 9},
|
||||
{"b", "Backups", 10},
|
||||
{"/", "Search", 9},
|
||||
{"?", "Help", 7},
|
||||
{"q", "Quit", 7},
|
||||
}
|
||||
|
||||
separator := " "
|
||||
sepWidth := 2
|
||||
|
||||
var lines []string
|
||||
var currentLine string
|
||||
var currentWidth int
|
||||
|
||||
for i, item := range items {
|
||||
rendered := helpKeyStyle.Render(item.key) + ": " + item.desc
|
||||
|
||||
// Check if adding this item would exceed width
|
||||
newWidth := currentWidth + item.rawWidth
|
||||
if currentWidth > 0 {
|
||||
newWidth += sepWidth
|
||||
}
|
||||
|
||||
if m.width > 0 && newWidth > m.width && currentWidth > 0 {
|
||||
// Start a new line
|
||||
lines = append(lines, currentLine)
|
||||
currentLine = rendered
|
||||
currentWidth = item.rawWidth
|
||||
} else {
|
||||
// Add to current line
|
||||
if currentWidth > 0 {
|
||||
currentLine += separator
|
||||
}
|
||||
currentLine += rendered
|
||||
currentWidth = newWidth
|
||||
if i == 0 {
|
||||
currentWidth = item.rawWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last line
|
||||
if currentLine != "" {
|
||||
lines = append(lines, currentLine)
|
||||
}
|
||||
|
||||
return helpBarStyle.Render(strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
func (m *Model) statusBar() string {
|
||||
|
||||
@@ -174,7 +174,7 @@ func (b *BackupPicker) selectView() string {
|
||||
}
|
||||
|
||||
leftSb.WriteString("\n")
|
||||
leftSb.WriteString(helpDescStyle.Render("↑↓ navigate • Enter restore • Esc cancel"))
|
||||
leftSb.WriteString(WrapHelpText("↑↓ navigate • Enter restore • Esc cancel", 40))
|
||||
|
||||
// Build right panel (preview)
|
||||
var rightSb strings.Builder
|
||||
@@ -219,7 +219,8 @@ func (b *BackupPicker) selectView() string {
|
||||
// Show scroll indicator
|
||||
if len(lines) > previewHeight {
|
||||
rightSb.WriteString("\n")
|
||||
rightSb.WriteString(helpDescStyle.Render(fmt.Sprintf("Lines %d-%d of %d (Shift+↑↓ scroll)", b.previewScroll+1, endLine, len(lines))))
|
||||
scrollText := fmt.Sprintf("%d-%d of %d (↑↓ scroll)", b.previewScroll+1, endLine, len(lines))
|
||||
rightSb.WriteString(helpDescStyle.Render(scrollText))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ func (f *Form) View() string {
|
||||
sb.WriteString("\n\n")
|
||||
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(helpDescStyle.Render("Tab/↓ next • Shift+Tab/↑ prev • ←→ select group • Enter save • Esc cancel"))
|
||||
sb.WriteString(WrapHelpText("Tab/↓ next • Shift+Tab/↑ prev • ←→ select group • Enter save • Esc cancel", f.width-6))
|
||||
|
||||
return dialogStyle.Render(sb.String())
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ func (g *GroupPicker) selectView() string {
|
||||
}
|
||||
|
||||
sb.WriteString("\n\n")
|
||||
sb.WriteString(helpDescStyle.Render("↑↓ navigate • n new • r rename • d delete • Esc back"))
|
||||
sb.WriteString(WrapHelpText("↑↓ navigate • n new • r rename • d delete • Esc back", g.width-6))
|
||||
|
||||
return dialogStyle.Render(sb.String())
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ func (p *PresetPicker) selectView() string {
|
||||
}
|
||||
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(helpDescStyle.Render("↑↓ navigate • Enter apply • n new • e edit • d delete • Esc cancel"))
|
||||
sb.WriteString(WrapHelpText("↑↓ navigate • Enter apply • n new • e edit • d delete • Esc cancel", p.width-6))
|
||||
|
||||
return dialogStyle.Render(sb.String())
|
||||
}
|
||||
@@ -483,7 +483,7 @@ func (p *PresetPicker) formView() string {
|
||||
}
|
||||
sb.WriteString("\n\n")
|
||||
|
||||
sb.WriteString(helpDescStyle.Render("Tab/↓ next • Enter select/save • Esc cancel"))
|
||||
sb.WriteString(WrapHelpText("Tab/↓ next • Enter select/save • Esc cancel", p.width-6))
|
||||
|
||||
return dialogStyle.Render(sb.String())
|
||||
}
|
||||
@@ -536,7 +536,7 @@ func (p *PresetPicker) pickerView() string {
|
||||
|
||||
sb.WriteString(titleStyle.Render(title))
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(helpDescStyle.Render("Space to toggle • Enter to confirm • Esc to cancel"))
|
||||
sb.WriteString(WrapHelpText("Space to toggle • Enter to confirm • Esc to cancel", p.width-6))
|
||||
sb.WriteString("\n\n")
|
||||
|
||||
filtered := p.getFilteredAliases()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
@@ -148,3 +150,71 @@ func StatusText(enabled bool, pending bool, hasError bool) string {
|
||||
func HelpItem(key, desc string) string {
|
||||
return helpKeyStyle.Render(key) + " " + helpDescStyle.Render(desc)
|
||||
}
|
||||
|
||||
// WrapHelpText wraps help text to fit within maxWidth, splitting on bullet separators.
|
||||
// If maxWidth is 0 or negative, returns the original text.
|
||||
func WrapHelpText(text string, maxWidth int) string {
|
||||
if maxWidth <= 0 {
|
||||
return helpDescStyle.Render(text)
|
||||
}
|
||||
|
||||
separator := " • "
|
||||
parts := splitOnSeparator(text, separator)
|
||||
|
||||
var lines []string
|
||||
var currentLine string
|
||||
var currentWidth int
|
||||
|
||||
for i, part := range parts {
|
||||
partWidth := len(part)
|
||||
sepWidth := 3 // len(" • ")
|
||||
|
||||
newWidth := currentWidth + partWidth
|
||||
if currentWidth > 0 {
|
||||
newWidth += sepWidth
|
||||
}
|
||||
|
||||
if newWidth > maxWidth && currentWidth > 0 {
|
||||
lines = append(lines, currentLine)
|
||||
currentLine = part
|
||||
currentWidth = partWidth
|
||||
} else {
|
||||
if currentWidth > 0 {
|
||||
currentLine += separator
|
||||
}
|
||||
currentLine += part
|
||||
if i == 0 {
|
||||
currentWidth = partWidth
|
||||
} else {
|
||||
currentWidth = newWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentLine != "" {
|
||||
lines = append(lines, currentLine)
|
||||
}
|
||||
|
||||
// Apply style to each line and join
|
||||
var result []string
|
||||
for _, line := range lines {
|
||||
result = append(result, helpDescStyle.Render(line))
|
||||
}
|
||||
|
||||
return strings.Join(result, "\n")
|
||||
}
|
||||
|
||||
// splitOnSeparator splits a string on the given separator.
|
||||
func splitOnSeparator(s, sep string) []string {
|
||||
var parts []string
|
||||
for {
|
||||
idx := strings.Index(s, sep)
|
||||
if idx == -1 {
|
||||
parts = append(parts, s)
|
||||
break
|
||||
}
|
||||
parts = append(parts, s[:idx])
|
||||
s = s[idx+len(sep):]
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user