@@ -12,6 +12,8 @@ import (
1212 "strings"
1313 "time"
1414
15+ "github.com/charmbracelet/x/ansi"
16+
1517 "charm.land/fantasy"
1618 "github.com/charmbracelet/crush/internal/config"
1719 "github.com/charmbracelet/crush/internal/fsext"
@@ -423,15 +425,15 @@ func formatOutput(stdout, stderr string, execErr error) string {
423425}
424426
425427func TruncateOutput(content string) string {
426− if len(content) <= MaxOutputLength {
428+ if ansi.StringWidth(content) <= MaxOutputLength {
427429 return content
428430 }
429431
430432 halfLength := MaxOutputLength / 2
431− start := content[:halfLength]
432− end := content[len(content)-halfLength:]
433+ start := ansi.Truncate(content, halfLength, "")
434+ end := ansi.TruncateLeft(content, ansi.StringWidth(content)-halfLength, "")
433435
434− truncatedLinesCount := countLines(content[halfLength : len(content)-halfLength])
436+ truncatedLinesCount := max(strings.Count(content, "\n")-strings.Count(start, "\n")-strings.Count(end, "\n"), 0)
435437 return fmt.Sprintf("%s\n\n... [%d lines truncated] ...\n\n%s", start, truncatedLinesCount, end)
436438}
437439
@@ -439,13 +441,6 @@ func truncateOutput(content string) string {
439441 return TruncateOutput(content)
440442}
441443
442−func countLines(s string) int {
443− if s == "" {
444− return 0
445− }
446− return len(strings.Split(s, "\n"))
447−}
448−
449444func normalizeWorkingDir(path string) string {
450445 if runtime.GOOS == "windows" {
451446 path = strings.ReplaceAll(path, fsext.WindowsWorkingDirDrive(), "")