-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
4 changed files
with
176 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package text | ||
|
||
import ( | ||
"fmt" | ||
"sort" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type escSeqParser struct { | ||
openSeq map[int]bool | ||
} | ||
|
||
func (s *escSeqParser) Codes() []int { | ||
codes := make([]int, 0) | ||
for code, val := range s.openSeq { | ||
if val { | ||
codes = append(codes, code) | ||
} | ||
} | ||
sort.Ints(codes) | ||
return codes | ||
} | ||
|
||
func (s *escSeqParser) Extract(str string) string { | ||
escapeSeq, inEscSeq := "", false | ||
for _, char := range str { | ||
if char == EscapeStartRune { | ||
inEscSeq = true | ||
escapeSeq = "" | ||
} | ||
if inEscSeq { | ||
escapeSeq += string(char) | ||
} | ||
if char == EscapeStopRune { | ||
inEscSeq = false | ||
s.Parse(escapeSeq) | ||
} | ||
} | ||
return s.Sequence() | ||
} | ||
|
||
func (s *escSeqParser) IsOpen() bool { | ||
return len(s.openSeq) > 0 | ||
} | ||
|
||
func (s *escSeqParser) Sequence() string { | ||
out := strings.Builder{} | ||
if s.IsOpen() { | ||
out.WriteString(EscapeStart) | ||
for idx, code := range s.Codes() { | ||
if idx > 0 { | ||
out.WriteRune(';') | ||
} | ||
out.WriteString(fmt.Sprint(code)) | ||
} | ||
out.WriteString(EscapeStop) | ||
} | ||
|
||
return out.String() | ||
} | ||
|
||
func (s *escSeqParser) Parse(seq string) { | ||
if s.openSeq == nil { | ||
s.openSeq = make(map[int]bool) | ||
} | ||
|
||
seq = strings.Replace(seq, EscapeStart, "", 1) | ||
seq = strings.Replace(seq, EscapeStop, "", 1) | ||
codes := strings.Split(seq, ";") | ||
for _, code := range codes { | ||
code = strings.TrimSpace(code) | ||
if codeNum, err := strconv.Atoi(code); err == nil { | ||
switch codeNum { | ||
case 0: // reset | ||
s.openSeq = make(map[int]bool) // clear everything | ||
case 22: // reset intensity | ||
delete(s.openSeq, 1) // remove bold | ||
delete(s.openSeq, 2) // remove faint | ||
case 23: // not italic | ||
delete(s.openSeq, 3) // remove italic | ||
case 24: // not underlined | ||
delete(s.openSeq, 4) // remove underline | ||
case 25: // not blinking | ||
delete(s.openSeq, 5) // remove slow blink | ||
delete(s.openSeq, 6) // remove rapid blink | ||
case 27: // not reversed | ||
delete(s.openSeq, 7) // remove reverse | ||
case 29: // not crossed-out | ||
delete(s.openSeq, 9) // remove crossed-out | ||
default: | ||
s.openSeq[codeNum] = true | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package text | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func Test_escSeqParser(t *testing.T) { | ||
t.Run("extract", func(t *testing.T) { | ||
es := escSeqParser{} | ||
|
||
assert.Equal(t, "\x1b[1;3;4;5;7;9;91m", es.Extract("\x1b[91m\x1b[1m\x1b[3m\x1b[4m\x1b[5m\x1b[7m\x1b[9m Spicy")) | ||
assert.Equal(t, "\x1b[3;4;5;7;9;91m", es.Extract("\x1b[22m No Bold")) | ||
assert.Equal(t, "\x1b[4;5;7;9;91m", es.Extract("\x1b[23m No Italic")) | ||
assert.Equal(t, "\x1b[5;7;9;91m", es.Extract("\x1b[24m No Underline")) | ||
assert.Equal(t, "\x1b[7;9;91m", es.Extract("\x1b[25m No Blink")) | ||
assert.Equal(t, "\x1b[9;91m", es.Extract("\x1b[27m No Reverse")) | ||
assert.Equal(t, "\x1b[91m", es.Extract("\x1b[29m No Crossed-Out")) | ||
assert.Equal(t, "", es.Extract("\x1b[0m Resetted")) | ||
}) | ||
|
||
t.Run("parse", func(t *testing.T) { | ||
es := escSeqParser{} | ||
|
||
es.Parse("\x1b[91m") // color | ||
es.Parse("\x1b[1m") // bold | ||
assert.Len(t, es.Codes(), 2) | ||
assert.True(t, es.IsOpen()) | ||
assert.Equal(t, "\x1b[1;91m", es.Sequence()) | ||
|
||
es.Parse("\x1b[22m") // un-bold | ||
assert.Len(t, es.Codes(), 1) | ||
assert.True(t, es.IsOpen()) | ||
assert.Equal(t, "\x1b[91m", es.Sequence()) | ||
|
||
es.Parse("\x1b[0m") // reset | ||
assert.Empty(t, es.Codes()) | ||
assert.False(t, es.IsOpen()) | ||
assert.Empty(t, es.Sequence()) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters