diff --git a/parse.go b/parse.go index 69b873c..f8fcbd6 100644 --- a/parse.go +++ b/parse.go @@ -31,6 +31,11 @@ import ( "strings" ) +const ( + bel = '\a' // bel (Bell) + st = '\\' // st (String Terminator) +) + var ( escapeSeqRegExp = regexp.MustCompile(`\x1b\[(\d+(;\d+)*)m`) boldMarker = regexp.MustCompile(`\*([^*]+?)\*`) @@ -93,15 +98,17 @@ func ParseStream(in io.Reader, opts ...ParseOption) (*String, error) { panic("failed to parse ANSI sequence") } - var skipUntil = func(end rune) { + var skipUntil = func(ends ...rune) { for { r, _, err := input.ReadRune() if err == io.EOF { panic("reached end of file before reaching end identifier") } - if r == end { - return + for _, end := range ends { + if r == end { + return + } } } } @@ -169,7 +176,7 @@ func ParseStream(in io.Reader, opts ...ParseOption) (*String, error) { } case ']': - skipUntil('\a') + skipUntil(bel, st) } } diff --git a/parse_test.go b/parse_test.go index 0ba8e55..3997489 100644 --- a/parse_test.go +++ b/parse_test.go @@ -54,6 +54,18 @@ var _ = Describe("parse input string", func() { Expect(err).ToNot(HaveOccurred()) Expect(result.String()).To(Equal("Hello, \x1b[1mWorld\x1b[0m!")) }) + + It("should process Operating System Command sequences that terminate on bell", func() { + result, err := ParseStream(strings.NewReader("\x1b]2;title\a")) + Expect(err).ToNot(HaveOccurred()) + Expect(result).ToNot(BeNil()) + }) + + It("should process Operating System Command sequences that terminate string terminator", func() { + result, err := ParseStream(strings.NewReader("\x1b]7;file://host/home/foobar/dir\x1b\\")) + Expect(err).ToNot(HaveOccurred()) + Expect(result).ToNot(BeNil()) + }) }) Context("parse Select Graphic Rendition (SGR) based input", func() {