From 06a9ff12ab7b2b83f11f3b74a7a812c775cf225c Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 25 Jan 2026 15:18:29 +0100 Subject: [PATCH] Bump gocui This brings in https://github.com/jesseduffield/gocui/pull/98 with the following fix: Fix rendering of CRLF sequence ('\r\n') The FirstGraphemeCluster call returns this as a single character; we want to treat it the same way as a single \n. This would be a problem if e.g. a progress bar used \r repeatedly to paint over the same line, and then printed a \n to move on to the next line; the last pair of \r and \n was swallowed. Another scenario where this was a problem was if you stream output of a command to the log, and the command used \r\n as line feeds. This happens for example for a background fetch that fails with an error; in that case we print the combined output (stdout plus stderr) to the log after the command finished, and for some reason it uses \r\n in that case (I can't actually explain why; when I do `git fetch --all | xxd` I see only bare \n characters). All output would appear on one line then. Also, filter out escape sequences for character set designation; there's nothing useful we can do with them. In practice, the only one that you are likely to see is `ESC ( B`, which is sent as part of tput sgr0, which is sometimes used in scripts to reset all graphics attributes to defaults. --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/gui/views.go | 1 - vendor/github.com/gdamore/tcell/v2/tscreen.go | 9 +++++++-- vendor/github.com/jesseduffield/gocui/escape.go | 11 +++++++++++ vendor/github.com/jesseduffield/gocui/view.go | 9 +++++---- vendor/modules.txt | 4 ++-- 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 6634cd544..4b4f1a6cc 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,13 @@ require ( github.com/aybabtme/humanlog v0.4.1 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/creack/pty v1.1.11 - github.com/gdamore/tcell/v2 v2.13.7 + github.com/gdamore/tcell/v2 v2.13.8 github.com/go-errors/errors v1.5.1 github.com/gookit/color v1.4.2 github.com/integrii/flaggy v1.4.0 github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd - github.com/jesseduffield/gocui v0.3.1-0.20260125102045-dd3e33362e7b + github.com/jesseduffield/gocui v0.3.1-0.20260128194906-9d8c3cdfac18 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3 diff --git a/go.sum b/go.sum index 4022e75a2..224984b0d 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= -github.com/gdamore/tcell/v2 v2.13.7 h1:yfHdeC7ODIYCc6dgRos8L1VujQtXHmUpU6UZotzD6os= -github.com/gdamore/tcell/v2 v2.13.7/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= +github.com/gdamore/tcell/v2 v2.13.8 h1:Mys/Kl5wfC/GcC5Cx4C2BIQH9dbnhnkPgS9/wF3RlfU= +github.com/gdamore/tcell/v2 v2.13.8/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= @@ -189,8 +189,8 @@ github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c h1:tC2Paiis github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c/go.mod h1:F2fEBk0ddf6ixrBrJjY7phfQ3hL9rXG0uSjvwYe50bE= github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd h1:ViKj6qth8FgcIWizn9KiACWwPemWSymx62OPN0tHT+Q= github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd/go.mod h1:lRhCiBr6XjQrvcQVa+UYsy/99d3wMXn/a0nSQlhnhlA= -github.com/jesseduffield/gocui v0.3.1-0.20260125102045-dd3e33362e7b h1:FYDdvzbNDatJQ81+n2kKrzk74/dltP8sUySFm52CVIM= -github.com/jesseduffield/gocui v0.3.1-0.20260125102045-dd3e33362e7b/go.mod h1:lQCd2TvvNXVKFBowy4A7xxZbUp+1KEiGs4j0Q5Zt9gQ= +github.com/jesseduffield/gocui v0.3.1-0.20260128194906-9d8c3cdfac18 h1:+Q17GqvNaGzuvIR1JCdIS0khVjMzdwrhXBBDxnsdN8Y= +github.com/jesseduffield/gocui v0.3.1-0.20260128194906-9d8c3cdfac18/go.mod h1:lQCd2TvvNXVKFBowy4A7xxZbUp+1KEiGs4j0Q5Zt9gQ= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 629f5e396..ba4b4373f 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -102,7 +102,6 @@ func (gui *Gui) createAllViews() error { for _, view := range []*gocui.View{gui.Views.Main, gui.Views.Secondary, gui.Views.Staging, gui.Views.StagingSecondary, gui.Views.PatchBuilding, gui.Views.PatchBuildingSecondary, gui.Views.MergeConflicts} { view.Wrap = true - view.IgnoreCarriageReturns = true view.UnderlineHyperLinksOnlyOnHover = true view.AutoRenderHyperLinks = true } diff --git a/vendor/github.com/gdamore/tcell/v2/tscreen.go b/vendor/github.com/gdamore/tcell/v2/tscreen.go index b4dfdf960..7dc7cdf81 100644 --- a/vendor/github.com/gdamore/tcell/v2/tscreen.go +++ b/vendor/github.com/gdamore/tcell/v2/tscreen.go @@ -622,7 +622,7 @@ func (t *tScreen) drawCell(x, y int) int { width = 1 str = " " } - if width > 1 { + if width > 1 && x+width < t.w { // Clobber over any content in the next cell. // This fixes a problem with some terminals where overwriting two // adjacent single cells with a wide rune would leave an image @@ -997,9 +997,14 @@ func (t *tScreen) buildAcsMap() { } func (t *tScreen) scanInput(buf *bytes.Buffer) { + // The end of the buffer isn't necessarily the end of the input, because + // large inputs are chunked. Set atEOF to false so the UTF-8 validating decoder + // returns ErrShortSrc instead of ErrInvalidUTF8 for incomplete multi-byte codepoints. + const atEOF = false + for buf.Len() > 0 { utf := make([]byte, min(8, max(buf.Len()*2, 128))) - nOut, nIn, e := t.decoder.Transform(utf, buf.Bytes(), true) + nOut, nIn, e := t.decoder.Transform(utf, buf.Bytes(), atEOF) _ = buf.Next(nIn) t.input.ScanUTF8(utf[:nOut]) if e == transform.ErrShortSrc { diff --git a/vendor/github.com/jesseduffield/gocui/escape.go b/vendor/github.com/jesseduffield/gocui/escape.go index 7c500d9a4..cb557f088 100644 --- a/vendor/github.com/jesseduffield/gocui/escape.go +++ b/vendor/github.com/jesseduffield/gocui/escape.go @@ -39,6 +39,7 @@ func (self noInstruction) isInstruction() {} const ( stateNone escapeState = iota stateEscape + stateCharacterSetDesignation stateCSI stateParams stateOSC @@ -144,9 +145,19 @@ func (ei *escapeInterpreter) parseOne(ch []byte) (isEscape bool, err error) { case characterEquals(ch, ']'): ei.state = stateOSC return true, nil + case characterEquals(ch, '('), + characterEquals(ch, ')'), + characterEquals(ch, '*'), + characterEquals(ch, '+'): + ei.state = stateCharacterSetDesignation + return true, nil default: return false, errNotCSI } + case stateCharacterSetDesignation: + // Not supported, so just skip it + ei.state = stateNone + return true, nil case stateCSI: switch { case len(ch) == 1 && ch[0] >= '0' && ch[0] <= '9': diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index ead9aa984..9ba8b7efc 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -167,9 +167,6 @@ type View struct { // If HasLoader is true, the message will be appended with a spinning loader animation HasLoader bool - // IgnoreCarriageReturns tells us whether to ignore '\r' characters - IgnoreCarriageReturns bool - // ParentView is the view which catches events bubbled up from the given view if there's no matching handler ParentView *View @@ -465,6 +462,10 @@ func characterEquals(chr []byte, b byte) bool { return len(chr) == 1 && chr[0] == b } +func isCRLF(chr []byte) bool { + return len(chr) == 2 && chr[0] == '\r' && chr[1] == '\n' +} + // String returns a string from a given cell slice. func (l lineType) String() string { var str strings.Builder @@ -840,7 +841,7 @@ func (v *View) write(p []byte) { chr, remaining, width, state = uniseg.FirstGraphemeCluster(remaining, state) switch { - case characterEquals(chr, '\n'): + case characterEquals(chr, '\n') || isCRLF(chr): finishLine() advanceToNextLine() case characterEquals(chr, '\r'): diff --git a/vendor/modules.txt b/vendor/modules.txt index e26f7b667..a33021dd3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -88,7 +88,7 @@ github.com/fatih/color # github.com/gdamore/encoding v1.0.1 ## explicit; go 1.9 github.com/gdamore/encoding -# github.com/gdamore/tcell/v2 v2.13.7 +# github.com/gdamore/tcell/v2 v2.13.8 ## explicit; go 1.24.0 github.com/gdamore/tcell/v2 github.com/gdamore/tcell/v2/terminfo @@ -211,7 +211,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder github.com/jesseduffield/go-git/v5/utils/sync github.com/jesseduffield/go-git/v5/utils/trace -# github.com/jesseduffield/gocui v0.3.1-0.20260125102045-dd3e33362e7b +# github.com/jesseduffield/gocui v0.3.1-0.20260128194906-9d8c3cdfac18 ## explicit; go 1.25 github.com/jesseduffield/gocui # github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5