mirror of
https://github.com/acedanger/shell.git
synced 2025-12-06 00:00:13 -08:00
Fix TUI newline display issue
- Add processEscapeSequences() function to convert literal \n to actual newlines - Apply fix to backup success, error, and running output displays - Add TUI binary to gitignore - Include comprehensive documentation of the fix Resolves issue where backup output showed literal escape sequences instead of properly formatted text with line breaks.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -38,3 +38,6 @@ immich/b2-linux
|
|||||||
|
|
||||||
# Generated dotfiles - these are created dynamically by bootstrap process
|
# Generated dotfiles - these are created dynamically by bootstrap process
|
||||||
dotfiles/my-aliases.zsh
|
dotfiles/my-aliases.zsh
|
||||||
|
|
||||||
|
# Compiled binaries
|
||||||
|
tui/tui
|
||||||
|
|||||||
64
docs/tui-newline-fix-summary.md
Normal file
64
docs/tui-newline-fix-summary.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# TUI Newline Fix Implementation Summary
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
The TUI application was displaying literal `\n` characters as text strings instead of rendering them as actual line breaks in the right-hand panel when viewing backup output.
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
Backup scripts were outputting literal escape sequences (e.g., `\n`, `\t`, `\r`) as text strings, which were being displayed directly in the TUI viewport without processing.
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
Implemented a `processEscapeSequences()` helper function that converts literal escape sequences to their actual character representations before displaying content in the viewport.
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
|
||||||
|
### 1. Added Helper Function
|
||||||
|
```go
|
||||||
|
// Helper function to process escape sequences in output text
|
||||||
|
func processEscapeSequences(text string) string {
|
||||||
|
processed := strings.ReplaceAll(text, "\\n", "\n")
|
||||||
|
processed = strings.ReplaceAll(processed, "\\t", "\t")
|
||||||
|
processed = strings.ReplaceAll(processed, "\\r", "\r")
|
||||||
|
return processed
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Integration Points
|
||||||
|
The function is called in three key locations where backup output is displayed:
|
||||||
|
|
||||||
|
1. **Backup Success Messages** (line ~584)
|
||||||
|
```go
|
||||||
|
processedOutput := processEscapeSequences(msg.output)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Backup Error Messages** (line ~621)
|
||||||
|
```go
|
||||||
|
processedError := processEscapeSequences(msg.error)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Running Backup Output** (line ~677)
|
||||||
|
```go
|
||||||
|
processedOutput := processEscapeSequences(outputForDisplay)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
- Created test scripts that generate literal escape sequences
|
||||||
|
- Verified the fix converts `\n` to actual newlines
|
||||||
|
- Confirmed TUI compiles and runs successfully
|
||||||
|
- Tested with demonstration scripts
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- `/home/acedanger/shell/tui/main.go` - Main TUI application
|
||||||
|
|
||||||
|
## Files Created for Testing
|
||||||
|
- `/home/acedanger/shell/test-plex-backup.sh` - Test script with literal newlines
|
||||||
|
- `/home/acedanger/shell/test-newline-fix.go` - Standalone test of the fix
|
||||||
|
- `/home/acedanger/shell/demonstrate-newline-fix.sh` - Demonstration script
|
||||||
|
|
||||||
|
## Result
|
||||||
|
✅ **Issue Resolved**: The TUI now properly displays newlines, tabs, and carriage returns in backup output instead of showing them as literal escape sequence characters.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
The fix is automatically applied to all backup output displayed in the TUI. No user action required - the escape sequence processing happens transparently.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Fix implemented on May 30, 2025*
|
||||||
23
tui/main.go
23
tui/main.go
@@ -580,8 +580,11 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
duration = m.backupStatus[msg.service].Duration
|
duration = m.backupStatus[msg.service].Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process output to handle escape sequences properly
|
||||||
|
processedOutput := processEscapeSequences(msg.output)
|
||||||
|
|
||||||
m.viewport.SetContent(fmt.Sprintf("✅ Backup completed successfully for %s!\n\nDuration: %s\n\n%s\n\n📋 Full Output:\n%s",
|
m.viewport.SetContent(fmt.Sprintf("✅ Backup completed successfully for %s!\n\nDuration: %s\n\n%s\n\n📋 Full Output:\n%s",
|
||||||
msg.service, duration, summaryText, msg.output))
|
msg.service, duration, summaryText, processedOutput))
|
||||||
|
|
||||||
case backupErrorMsg:
|
case backupErrorMsg:
|
||||||
if m.backupStatus[msg.service] != nil {
|
if m.backupStatus[msg.service] != nil {
|
||||||
@@ -614,8 +617,11 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
errorAnalysis = "\n💡 This might be a disk space issue. Check available storage."
|
errorAnalysis = "\n💡 This might be a disk space issue. Check available storage."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process error output to handle escape sequences properly
|
||||||
|
processedError := processEscapeSequences(msg.error)
|
||||||
|
|
||||||
m.viewport.SetContent(fmt.Sprintf("❌ Backup failed for %s!\n\nDuration: %s%s\n\n🚨 Error Details:\n%s",
|
m.viewport.SetContent(fmt.Sprintf("❌ Backup failed for %s!\n\nDuration: %s%s\n\n🚨 Error Details:\n%s",
|
||||||
msg.service, duration, errorAnalysis, msg.error))
|
msg.service, duration, errorAnalysis, processedError))
|
||||||
|
|
||||||
case spinner.TickMsg:
|
case spinner.TickMsg:
|
||||||
m.spinner, cmd = m.spinner.Update(msg)
|
m.spinner, cmd = m.spinner.Update(msg)
|
||||||
@@ -667,8 +673,11 @@ func (m *Model) updateViewportForRunningService(service string, outputForDisplay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process output to handle escape sequences properly
|
||||||
|
processedOutput := processEscapeSequences(outputForDisplay)
|
||||||
|
|
||||||
m.viewport.SetContent(fmt.Sprintf("⏳ Backup in progress for %s...\n\n%s %d%%\nElapsed: %s%s\n\n📋 Latest output:\n%s\n\nPress 'x' to stop the backup.",
|
m.viewport.SetContent(fmt.Sprintf("⏳ Backup in progress for %s...\n\n%s %d%%\nElapsed: %s%s\n\n📋 Latest output:\n%s\n\nPress 'x' to stop the backup.",
|
||||||
service, progressBar, progress, elapsed.Round(time.Second), etaStr, outputForDisplay))
|
service, progressBar, progress, elapsed.Round(time.Second), etaStr, processedOutput))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) View() string {
|
func (m Model) View() string {
|
||||||
@@ -1257,6 +1266,14 @@ func createProgressBar(progress int) string {
|
|||||||
return fmt.Sprintf("[%s]", bar)
|
return fmt.Sprintf("[%s]", bar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to process escape sequences in output text
|
||||||
|
func processEscapeSequences(text string) string {
|
||||||
|
processed := strings.ReplaceAll(text, "\\n", "\n")
|
||||||
|
processed = strings.ReplaceAll(processed, "\\t", "\t")
|
||||||
|
processed = strings.ReplaceAll(processed, "\\r", "\r")
|
||||||
|
return processed
|
||||||
|
}
|
||||||
|
|
||||||
// Start a progress ticker for time-based progress estimation
|
// Start a progress ticker for time-based progress estimation
|
||||||
func (m Model) startProgressTicker(service string) tea.Cmd {
|
func (m Model) startProgressTicker(service string) tea.Cmd {
|
||||||
return tea.Tick(time.Second*2, func(t time.Time) tea.Msg {
|
return tea.Tick(time.Second*2, func(t time.Time) tea.Msg {
|
||||||
|
|||||||
Reference in New Issue
Block a user