summaryrefslogtreecommitdiffstats
path: root/src/ansi.go
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2022-08-12 22:18:10 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2022-08-13 22:30:50 +0900
commitaa10dccf900b5f0bdad475663f5dfe70757ea29d (patch)
tree08fe0b2e6273792362de6ce897f5b5eef4cb993d /src/ansi.go
parentf4fd53211a9e3964818c2069aeff5464a679079f (diff)
Support colon delimiter in ANSI escape sequences
# Both should work printf "\e[38;5;208mOption 1\e[m\nOption 2" | fzf --ansi printf "\e[38:5:208mOption 1\e[m\nOption 2" | fzf --ansi This change makes ANSI parsing slightly slower. cpu: Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz Before: BenchmarkNextAnsiEscapeSequence-12 992.22 MB/s BenchmarkExtractColor-12 174.35 MB/s After: BenchmarkNextAnsiEscapeSequence-12 925.05 MB/s BenchmarkExtractColor-12 163.33 MB/s Fix #2913
Diffstat (limited to 'src/ansi.go')
-rw-r--r--src/ansi.go40
1 files changed, 26 insertions, 14 deletions
diff --git a/src/ansi.go b/src/ansi.go
index 543dabf3..f7910d7a 100644
--- a/src/ansi.go
+++ b/src/ansi.go
@@ -85,7 +85,7 @@ func isPrint(c uint8) bool {
}
func matchOperatingSystemCommand(s string) int {
- // `\x1b][0-9];[[:print:]]+(?:\x1b\\\\|\x07)`
+ // `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
// ^ match starting here
//
i := 5 // prefix matched in nextAnsiEscapeSequence()
@@ -103,11 +103,11 @@ func matchOperatingSystemCommand(s string) int {
}
func matchControlSequence(s string) int {
- // `\x1b[\\[()][0-9;?]*[a-zA-Z@]`
- // ^ match starting here
+ // `\x1b[\\[()][0-9;:?]*[a-zA-Z@]`
+ // ^ match starting here
//
i := 2 // prefix matched in nextAnsiEscapeSequence()
- for ; i < len(s) && (isNumeric(s[i]) || s[i] == ';' || s[i] == '?'); i++ {
+ for ; i < len(s) && (isNumeric(s[i]) || s[i] == ';' || s[i] == ':' || s[i] == '?'); i++ {
}
if i < len(s) {
c := s[i]
@@ -125,7 +125,7 @@ func isCtrlSeqStart(c uint8) bool {
// nextAnsiEscapeSequence returns the ANSI escape sequence and is equivalent to
// calling FindStringIndex() on the below regex (which was originally used):
//
-// "(?:\x1b[\\[()][0-9;?]*[a-zA-Z@]|\x1b][0-9];[[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)"
+// "(?:\x1b[\\[()][0-9;:?]*[a-zA-Z@]|\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)"
func nextAnsiEscapeSequence(s string) (int, int) {
// fast check for ANSI escape sequences
i := 0
@@ -153,16 +153,16 @@ Loop:
return i - n, i + 1
}
case '\x1b':
- // match: `\x1b[\\[()][0-9;?]*[a-zA-Z@]`
+ // match: `\x1b[\\[()][0-9;:?]*[a-zA-Z@]`
if i+2 < len(s) && isCtrlSeqStart(s[i+1]) {
if j := matchControlSequence(s[i:]); j != -1 {
return i, i + j
}
}
- // match: `\x1b][0-9];[[:print:]]+(?:\x1b\\\\|\x07)`
+ // match: `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
if i+5 < len(s) && s[i+1] == ']' && isNumeric(s[i+2]) &&
- s[i+3] == ';' && isPrint(s[i+4]) {
+ (s[i+3] == ';' || s[i+3] == ':') && isPrint(s[i+4]) {
if j := matchOperatingSystemCommand(s[i:]); j != -1 {
return i, i + j
@@ -279,9 +279,20 @@ func extractColor(str string, state *ansiState, proc func(string, *ansiState) bo
return trimmed, nil, state
}
-func parseAnsiCode(s string) (int, string) {
+func parseAnsiCode(s string, delimiter byte) (int, byte, string) {
var remaining string
- if i := strings.IndexByte(s, ';'); i >= 0 {
+ i := -1
+ if delimiter == 0 {
+ // Faster than strings.IndexAny(";:")
+ i = strings.IndexByte(s, ';')
+ if i < 0 {
+ i = strings.IndexByte(s, ':')
+ }
+ } else {
+ i = strings.IndexByte(s, delimiter)
+ }
+ if i >= 0 {
+ delimiter = s[i]
remaining = s[i+1:]
s = s[:i]
}
@@ -293,14 +304,14 @@ func parseAnsiCode(s string) (int, string) {
for _, ch := range []byte(s) {
ch -= '0'
if ch > 9 {
- return -1, remaining
+ return -1, delimiter, remaining
}
code = code*10 + int(ch)
}
- return code, remaining
+ return code, delimiter, remaining
}
- return -1, remaining
+ return -1, delimiter, remaining
}
func interpretCode(ansiCode string, prevState *ansiState) ansiState {
@@ -328,9 +339,10 @@ func interpretCode(ansiCode string, prevState *ansiState) ansiState {
state256 := 0
ptr := &state.fg
+ var delimiter byte = 0
for len(ansiCode) != 0 {
var num int
- if num, ansiCode = parseAnsiCode(ansiCode); num != -1 {
+ if num, delimiter, ansiCode = parseAnsiCode(ansiCode, delimiter); num != -1 {
switch state256 {
case 0:
switch num {