diff --git a/go.mod b/go.mod index 0b253c7052b9813f10b721d763ade79aba356624..6a856d069637b09e324a090dd0c3a5cac4d62ff4 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/charmbracelet/colorprofile v0.4.1 github.com/charmbracelet/fang v0.4.4 github.com/charmbracelet/ultraviolet v0.0.0-20251212194010-b927aa605560 - github.com/charmbracelet/x/ansi v0.11.3 + github.com/charmbracelet/x/ansi v0.11.4 github.com/charmbracelet/x/editor v0.2.0 github.com/charmbracelet/x/etag v0.2.0 github.com/charmbracelet/x/exp/charmtone v0.0.0-20260109001716-2fbdffcb221f @@ -104,7 +104,7 @@ require ( github.com/charmbracelet/x/json v0.2.0 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect - github.com/clipperhouse/displaywidth v0.6.2 // indirect + github.com/clipperhouse/displaywidth v0.7.0 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/uax29/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 6346b736a83815afe4daff8390a03b941539ad6d..3a9f73bdd233aea6d5f449a8e0e27234bb519c9d 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/charmbracelet/fang v0.4.4 h1:G4qKxF6or/eTPgmAolwPuRNyuci3hTUGGX1rj1Yk github.com/charmbracelet/fang v0.4.4/go.mod h1:P5/DNb9DddQ0Z0dbc0P3ol4/ix5Po7Ofr2KMBfAqoCo= github.com/charmbracelet/ultraviolet v0.0.0-20251212194010-b927aa605560 h1:j3PW2hypGoPKBy3ooKzW0TFxaxhyHK3NbkLLn4KeRFc= github.com/charmbracelet/ultraviolet v0.0.0-20251212194010-b927aa605560/go.mod h1:VWATWLRwYP06VYCEur7FsNR2B1xAo7Y+xl1PTbd1ePc= -github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI= -github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI= +github.com/charmbracelet/x/ansi v0.11.4 h1:6G65PLu6HjmE858CnTUQY1LXT3ZUWwfvqEROLF8vqHI= +github.com/charmbracelet/x/ansi v0.11.4/go.mod h1:/5AZ+UfWExW3int5H5ugnsG/PWjNcSQcwYsHBlPFQN4= github.com/charmbracelet/x/editor v0.2.0 h1:7XLUKtaRaB8jN7bWU2p2UChiySyaAuIfYiIRg8gGWwk= github.com/charmbracelet/x/editor v0.2.0/go.mod h1:p3oQ28TSL3YPd+GKJ1fHWcp+7bVGpedHpXmo0D6t1dY= github.com/charmbracelet/x/etag v0.2.0 h1:Euj1VkheoHfTYA9y+TCwkeXF/hN8Fb9l4LqZl79pt04= @@ -130,8 +130,8 @@ github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8 github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= -github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo= -github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= +github.com/clipperhouse/displaywidth v0.7.0 h1:QNv1GYsnLX9QBrcWUtMlogpTXuM5FVnBwKWp1O5NwmE= +github.com/clipperhouse/displaywidth v0.7.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= diff --git a/internal/ui/image/image.go b/internal/ui/image/image.go index e04a781c767c5677e0165cb3e191c60532dac0e6..06183ae8142b6d7f2e4ff932cdfa07273f1a16c8 100644 --- a/internal/ui/image/image.go +++ b/internal/ui/image/image.go @@ -2,7 +2,6 @@ package image import ( "bytes" - "errors" "fmt" "hash/fnv" "image" @@ -195,50 +194,12 @@ func (e Encoding) Transmit(id string, img image.Image, cs CellSize, cols, rows i } var buf bytes.Buffer - rp, wp := io.Pipe() - go func() { - for { - // Read single Kitty graphic chunks from the pipe and wrap them - // for tmux if needed. - var out bytes.Buffer - seenEsc := false - for { - var p [1]byte - n, err := rp.Read(p[:]) - if n > 0 { - out.WriteByte(p[0]) - if p[0] == ansi.ESC { - seenEsc = true - } else if seenEsc && p[0] == '\\' { - // End of Kitty graphics sequence - break - } else { - seenEsc = false - } - } - if err != nil { - if !errors.Is(err, io.EOF) { - slog.Error("error reading from pipe", "err", err) - } - return - } - } - - seq := out.String() - if tmux { - seq = ansi.TmuxPassthrough(seq) - } - - buf.WriteString(seq) - } - }() - img := fitImage(id, img, cs, cols, rows) bounds := img.Bounds() imgWidth := bounds.Dx() imgHeight := bounds.Dy() imgID := int(key.Hash()) - if err := kitty.EncodeGraphics(wp, img, &kitty.Options{ + if err := kitty.EncodeGraphics(&buf, img, &kitty.Options{ ID: imgID, Action: kitty.TransmitAndPut, Transmission: kitty.Direct, @@ -250,9 +211,18 @@ func (e Encoding) Transmit(id string, img image.Image, cs CellSize, cols, rows i VirtualPlacement: true, Quite: 1, Chunk: true, + ChunkFormatter: func(chunk string) string { + if tmux { + return ansi.TmuxPassthrough(chunk) + } + return chunk + }, }); err != nil { slog.Error("failed to encode image for kitty graphics", "err", err) - return uiutil.ReportError(fmt.Errorf("failed to encode image")) + return uiutil.InfoMsg{ + Type: uiutil.InfoTypeError, + Msg: "failed to encode image", + } } return tea.RawMsg{Msg: buf.String()}