diff --git a/.gitignore b/.gitignore index 7b94e27..ab46f26 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ immich/b2-linux # Generated dotfiles - these are created dynamically by bootstrap process dotfiles/my-aliases.zsh + +# Compiled binaries +tui/tui diff --git a/docs/tui-newline-fix-summary.md b/docs/tui-newline-fix-summary.md new file mode 100644 index 0000000..7ce4311 --- /dev/null +++ b/docs/tui-newline-fix-summary.md @@ -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* diff --git a/tui/main.go b/tui/main.go index 29007f8..ea33ca6 100644 --- a/tui/main.go +++ b/tui/main.go @@ -580,8 +580,11 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { 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", - msg.service, duration, summaryText, msg.output)) + msg.service, duration, summaryText, processedOutput)) case backupErrorMsg: 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." } + // 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", - msg.service, duration, errorAnalysis, msg.error)) + msg.service, duration, errorAnalysis, processedError)) case spinner.TickMsg: 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.", - service, progressBar, progress, elapsed.Round(time.Second), etaStr, outputForDisplay)) + service, progressBar, progress, elapsed.Round(time.Second), etaStr, processedOutput)) } func (m Model) View() string { @@ -1257,6 +1266,14 @@ func createProgressBar(progress int) string { 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 func (m Model) startProgressTicker(service string) tea.Cmd { return tea.Tick(time.Second*2, func(t time.Time) tea.Msg {