From 763d69890c79cfdb7981c0d1837e15cedf60cb77 Mon Sep 17 00:00:00 2001 From: Nathan Rijksen Date: Fri, 8 Sep 2023 15:13:59 -0700 Subject: [PATCH] Update termtest --- go.mod | 2 +- go.sum | 4 +- .../ActiveState/termtest/helpers_windows.go | 38 ++++++++++++------- .../ActiveState/termtest/outputproducer.go | 28 +++++++------- .../ActiveState/termtest/termtest.go | 4 +- vendor/modules.txt | 2 +- 6 files changed, 46 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 7ac453726b..9f65df5e70 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace cloud.google.com/go => cloud.google.com/go v0.110.0 require ( github.com/99designs/gqlgen v0.17.19 github.com/ActiveState/go-ogle-analytics v0.0.0-20170510030904-9b3f14901527 - github.com/ActiveState/termtest v0.7.3-0.20230908163501-7dbf9b0e4aa9 + github.com/ActiveState/termtest v0.7.3-0.20230908221236-4a478533c7a9 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/andygrunwald/go-jira v1.15.1 diff --git a/go.sum b/go.sum index 3ca8a663cb..ff9a86fcb5 100644 --- a/go.sum +++ b/go.sum @@ -345,8 +345,8 @@ github.com/ActiveState/graphql v0.0.0-20230719154233-6949037a6e48 h1:UCx/ObpVRgC github.com/ActiveState/graphql v0.0.0-20230719154233-6949037a6e48/go.mod h1:NhUbNQ8UpfnC6nZvZ8oThqYSCE/G8FQp9JUrK9jXJs0= github.com/ActiveState/pty v0.0.0-20230628221854-6fb90eb08a14 h1:RdhhSiwmgyUaaF2GBNrbqTwE5SM+MaVjwf91Ua+CK8c= github.com/ActiveState/pty v0.0.0-20230628221854-6fb90eb08a14/go.mod h1:5mM6vNRQwshCjlkOnVpwC//4ZpkiC6nmZr8lPOxJdXs= -github.com/ActiveState/termtest v0.7.3-0.20230908163501-7dbf9b0e4aa9 h1:n4fVV71e5FRLTgqLZiKf3YeU/tsI4OdDFZaqFQHOM+I= -github.com/ActiveState/termtest v0.7.3-0.20230908163501-7dbf9b0e4aa9/go.mod h1:RyWp2NaaTrVAa+XjMHpKAqwBFWbL6wE12HQxiZNGAqU= +github.com/ActiveState/termtest v0.7.3-0.20230908221236-4a478533c7a9 h1:5Duq9BzYcauTtXpbzAD852pgVOJ0ISqvGi2FIcgKZVQ= +github.com/ActiveState/termtest v0.7.3-0.20230908221236-4a478533c7a9/go.mod h1:RyWp2NaaTrVAa+XjMHpKAqwBFWbL6wE12HQxiZNGAqU= github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= diff --git a/vendor/github.com/ActiveState/termtest/helpers_windows.go b/vendor/github.com/ActiveState/termtest/helpers_windows.go index 4febeb9129..c501a4dc4d 100644 --- a/vendor/github.com/ActiveState/termtest/helpers_windows.go +++ b/vendor/github.com/ActiveState/termtest/helpers_windows.go @@ -16,9 +16,9 @@ const UnicodeBackspaceRune = '\u0008' // Note in the docs this is \u007f, but in // Ultimately we want to emulate the windows console here, just like we're doing for v10x on posix. // The current implementation is geared towards our needs, and won't be able to handle all escape sequences as a result. // For details on escape sequences see https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences -func cleanPtySnapshot(snapshot []byte, isPosix bool) []byte { +func cleanPtySnapshot(snapshot []byte, cursorPos int, isPosix bool) ([]byte, int) { if isPosix { - return snapshot + return snapshot, cursorPos } // Most escape sequences appear to end on `A-Za-z@` @@ -33,9 +33,16 @@ func cleanPtySnapshot(snapshot []byte, isPosix bool) []byte { inEscapeSequence := false inTitleEscapeSequence := false + newCursorPos := cursorPos + dropPos := func(pos int) { + if pos <= cursorPos { + newCursorPos-- + } + } + var result []rune runes := bytes.Runes(snapshot) - for _, r := range runes { + for pos, r := range runes { // Reset code recording outside of escape sequence, so we don't have to manually handle this throughout if !inEscapeSequence { recordingCode = false @@ -48,12 +55,14 @@ func cleanPtySnapshot(snapshot []byte, isPosix bool) []byte { case !inEscapeSequence && r == UnicodeEscapeRune: inEscapeSequence = true recordingCode = true + dropPos(pos) continue // Detect start of complex escape sequence case inEscapeSequence && !inTitleEscapeSequence && (escapeSequenceCode == "0" || escapeSequenceCode == "2"): inTitleEscapeSequence = true recordingCode = false + dropPos(pos) continue // SEQUENCE END @@ -61,39 +70,42 @@ func cleanPtySnapshot(snapshot []byte, isPosix bool) []byte { // Detect end of escape sequence case inEscapeSequence && !inTitleEscapeSequence && bytes.ContainsRune(plainVirtualEscapeSeqEndValues, r): inEscapeSequence = false + dropPos(pos) continue // Detect end of complex escape sequence case inTitleEscapeSequence && r == UnicodeBellRune: inEscapeSequence = false inTitleEscapeSequence = false + dropPos(pos) continue // SEQUENCE CONTINUATION - case inEscapeSequence && recordingCode: - if r == ']' { - continue - } - if !bytes.ContainsRune(numbers, r) { - recordingCode = false - continue - } + case inEscapeSequence && recordingCode && bytes.ContainsRune(numbers, r): escapeSequenceCode += string(r) + dropPos(pos) + continue // Detect continuation of escape sequence case inEscapeSequence: - recordingCode = false + if r != ']' { + recordingCode = false + } + dropPos(pos) continue // OUTSIDE OF ESCAPE SEQUENCE case r == UnicodeBackspaceRune && len(result) > 0: + dropPos(pos - 1) + dropPos(pos) result = result[:len(result)-1] + continue default: result = append(result, r) } } - return []byte(string(result)) + return []byte(string(result)), cursorPos } diff --git a/vendor/github.com/ActiveState/termtest/outputproducer.go b/vendor/github.com/ActiveState/termtest/outputproducer.go index 000af7f602..5c40bd4050 100644 --- a/vendor/github.com/ActiveState/termtest/outputproducer.go +++ b/vendor/github.com/ActiveState/termtest/outputproducer.go @@ -21,8 +21,8 @@ const producerBufferSize = 1024 // outputProducer is responsible for keeping track of the output and notifying consumers when new output is produced type outputProducer struct { output []byte - snapshotPos int - cleanUptoPos int + cursorPos int // The position of our virtual cursor, which is the position up to where we've satisfied consumers + cleanUptoPos int // Up to which position we've cleaned the output, because incomplete output cannot be cleaned consumers []*outputConsumer opts *Opts mutex *sync.Mutex @@ -111,13 +111,13 @@ func (o *outputProducer) appendBuffer(value []byte, isFinal bool) error { // Clean output var err error - o.output, o.cleanUptoPos, err = o.processDirtyOutput(output, o.cleanUptoPos, isFinal, func(output []byte) ([]byte, error) { + o.output, o.cursorPos, o.cleanUptoPos, err = o.processDirtyOutput(output, o.cursorPos, o.cleanUptoPos, isFinal, func(output []byte, cursorPos int) ([]byte, int, error) { var err error - output = cleanPtySnapshot(output, o.opts.Posix) + output, cursorPos = cleanPtySnapshot(output, cursorPos, o.opts.Posix) if o.opts.OutputSanitizer != nil { - output, err = o.opts.OutputSanitizer(output) + output, cursorPos, err = o.opts.OutputSanitizer(output, cursorPos) } - return output, err + return output, cursorPos, err }) if err != nil { return fmt.Errorf("cleaning output failed: %w", err) @@ -133,11 +133,13 @@ func (o *outputProducer) appendBuffer(value []byte, isFinal bool) error { return nil } +type cleanerFunc func([]byte, int) ([]byte, int, error) + // processDirtyOutput will sanitize the output received, but we have to be careful not to clean output that hasn't fully arrived // For example we may be inside an escape sequence and the escape sequence hasn't finished // So instead we only process new output up to the most recent line break // In order for this to work properly the invoker must ensure the output and cleanUptoPos are consistent with each other. -func (o *outputProducer) processDirtyOutput(output []byte, cleanUptoPos int, isFinal bool, cleaner func([]byte) ([]byte, error)) ([]byte, int, error) { +func (o *outputProducer) processDirtyOutput(output []byte, cursorPos int, cleanUptoPos int, isFinal bool, cleaner cleanerFunc) ([]byte, int, int, error) { alreadyCleanedOutput := copyBytes(output[:cleanUptoPos]) processedOutput := []byte{} unprocessedOutput := copyBytes(output[cleanUptoPos:]) @@ -161,9 +163,9 @@ func (o *outputProducer) processDirtyOutput(output []byte, cleanUptoPos int, isF // Invoke the cleaner now that we have output that can be cleaned if len(processedOutput) > 0 { var err error - processedOutput, err = cleaner(processedOutput) + processedOutput, cursorPos, err = cleaner(processedOutput, cursorPos) if err != nil { - return processedOutput, cleanUptoPos, fmt.Errorf("cleaner failed: %w", err) + return processedOutput, cursorPos, cleanUptoPos, fmt.Errorf("cleaner failed: %w", err) } } @@ -171,7 +173,7 @@ func (o *outputProducer) processDirtyOutput(output []byte, cleanUptoPos int, isF cleanUptoPos = cleanUptoPos + len(processedOutput) // Stitch everything back together - return append(append(alreadyCleanedOutput, processedOutput...), unprocessedOutput...), cleanUptoPos, nil + return append(append(alreadyCleanedOutput, processedOutput...), unprocessedOutput...), cursorPos, cleanUptoPos, nil } func (o *outputProducer) flushConsumers() error { @@ -183,7 +185,7 @@ func (o *outputProducer) flushConsumers() error { for n := 0; n < len(o.consumers); n++ { consumer := o.consumers[n] - snapshot := o.PendingOutput() // o.PendingOutput() considers the snapshotPos + snapshot := o.PendingOutput() // o.PendingOutput() considers the cursorPos if len(snapshot) == 0 { o.opts.Logger.Println("no snapshot to flush") return nil @@ -206,7 +208,7 @@ func (o *outputProducer) flushConsumers() error { if endPos > len(snapshot) { return fmt.Errorf("consumer reported end position %d greater than snapshot length %d", endPos, len(o.output)) } - o.snapshotPos += endPos + o.cursorPos += endPos // Drop consumer o.opts.Logger.Printf("dropping consumer %d out of %d", n+1, len(o.consumers)) @@ -234,7 +236,7 @@ func (o *outputProducer) addConsumer(consume consumer, opts ...SetConsOpt) (*out } func (o *outputProducer) PendingOutput() []byte { - return o.output[o.snapshotPos:] + return o.output[o.cursorPos:] } func (o *outputProducer) Output() []byte { diff --git a/vendor/github.com/ActiveState/termtest/termtest.go b/vendor/github.com/ActiveState/termtest/termtest.go index af93bfd02e..68699d3518 100644 --- a/vendor/github.com/ActiveState/termtest/termtest.go +++ b/vendor/github.com/ActiveState/termtest/termtest.go @@ -35,7 +35,7 @@ type Opts struct { Rows int Posix bool DefaultTimeout time.Duration - OutputSanitizer func([]byte) ([]byte, error) + OutputSanitizer cleanerFunc NormalizedLineEnds bool } @@ -165,7 +165,7 @@ func OptDefaultTimeout(duration time.Duration) SetOpt { } } -func OptOutputSanitizer(f func([]byte) ([]byte, error)) SetOpt { +func OptOutputSanitizer(f cleanerFunc) SetOpt { return func(o *Opts) error { o.OutputSanitizer = f return nil diff --git a/vendor/modules.txt b/vendor/modules.txt index 76f98e9603..1493d2d83f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -19,7 +19,7 @@ github.com/ActiveState/graphql # github.com/ActiveState/pty v0.0.0-20230628221854-6fb90eb08a14 ## explicit; go 1.13 github.com/ActiveState/pty -# github.com/ActiveState/termtest v0.7.3-0.20230908163501-7dbf9b0e4aa9 +# github.com/ActiveState/termtest v0.7.3-0.20230908221236-4a478533c7a9 ## explicit; go 1.18 github.com/ActiveState/termtest # github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78