summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2015-07-22 14:19:45 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2015-07-22 14:19:45 +0900
commit5e3cb3a4eaa557b03d0d18a36f983cc6acec6ad1 (patch)
tree3205662fa6d6616d036996864ebff7b5623ac599
parentf71ea5f3ea469489fc979ee3c0cd2622d011befd (diff)
Fix ANSI processor to handle multi-line regions
-rw-r--r--src/ansi.go10
-rw-r--r--src/ansi_test.go71
-rw-r--r--src/core.go7
-rw-r--r--src/terminal.go4
4 files changed, 72 insertions, 20 deletions
diff --git a/src/ansi.go b/src/ansi.go
index 116282c1..a80de478 100644
--- a/src/ansi.go
+++ b/src/ansi.go
@@ -36,11 +36,13 @@ func init() {
ansiRegex = regexp.MustCompile("\x1b\\[[0-9;]*[mK]")
}
-func extractColor(str *string) (*string, []ansiOffset) {
+func extractColor(str *string, state *ansiState) (*string, []ansiOffset, *ansiState) {
var offsets []ansiOffset
-
var output bytes.Buffer
- var state *ansiState
+
+ if state != nil {
+ offsets = append(offsets, ansiOffset{[2]int32{0, 0}, *state})
+ }
idx := 0
for _, offset := range ansiRegex.FindAllStringIndex(*str, -1) {
@@ -76,7 +78,7 @@ func extractColor(str *string) (*string, []ansiOffset) {
}
}
outputStr := output.String()
- return &outputStr, offsets
+ return &outputStr, offsets, state
}
func interpretCode(ansiCode string, prevState *ansiState) *ansiState {
diff --git a/src/ansi_test.go b/src/ansi_test.go
index 9f628409..d4d3ca1e 100644
--- a/src/ansi_test.go
+++ b/src/ansi_test.go
@@ -14,79 +14,89 @@ func TestExtractColor(t *testing.T) {
}
src := "hello world"
+ var state *ansiState
clean := "\x1b[0m"
- check := func(assertion func(ansiOffsets []ansiOffset)) {
- output, ansiOffsets := extractColor(&src)
+ check := func(assertion func(ansiOffsets []ansiOffset, state *ansiState)) {
+ output, ansiOffsets, newState := extractColor(&src, state)
+ state = newState
if *output != "hello world" {
t.Errorf("Invalid output: {}", output)
}
fmt.Println(src, ansiOffsets, clean)
- assertion(ansiOffsets)
+ assertion(ansiOffsets, state)
}
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) > 0 {
t.Fail()
}
})
+ state = nil
src = "\x1b[0mhello world"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) > 0 {
t.Fail()
}
})
+ state = nil
src = "\x1b[1mhello world"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 1 {
t.Fail()
}
assert(offsets[0], 0, 11, -1, -1, true)
})
+ state = nil
src = "\x1b[1mhello \x1b[mworld"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 1 {
t.Fail()
}
assert(offsets[0], 0, 6, -1, -1, true)
})
+ state = nil
src = "\x1b[1mhello \x1b[Kworld"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 1 {
t.Fail()
}
assert(offsets[0], 0, 11, -1, -1, true)
})
+ state = nil
src = "hello \x1b[34;45;1mworld"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 1 {
t.Fail()
}
assert(offsets[0], 6, 11, 4, 5, true)
})
+ state = nil
src = "hello \x1b[34;45;1mwor\x1b[34;45;1mld"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 1 {
t.Fail()
}
assert(offsets[0], 6, 11, 4, 5, true)
})
+ state = nil
src = "hello \x1b[34;45;1mwor\x1b[0mld"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 1 {
t.Fail()
}
assert(offsets[0], 6, 9, 4, 5, true)
})
+ state = nil
src = "hello \x1b[34;48;5;233;1mwo\x1b[38;5;161mr\x1b[0ml\x1b[38;5;161md"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 3 {
t.Fail()
}
@@ -96,12 +106,47 @@ func TestExtractColor(t *testing.T) {
})
// {38,48};5;{38,48}
+ state = nil
src = "hello \x1b[38;5;38;48;5;48;1mwor\x1b[38;5;48;48;5;38ml\x1b[0md"
- check(func(offsets []ansiOffset) {
+ check(func(offsets []ansiOffset, state *ansiState) {
if len(offsets) != 2 {
t.Fail()
}
assert(offsets[0], 6, 9, 38, 48, true)
assert(offsets[1], 9, 10, 48, 38, true)
})
+
+ src = "hello \x1b[32;1mworld"
+ check(func(offsets []ansiOffset, state *ansiState) {
+ if len(offsets) != 1 {
+ t.Fail()
+ }
+ if state.fg != 2 || state.bg != -1 || !state.bold {
+ t.Fail()
+ }
+ assert(offsets[0], 6, 11, 2, -1, true)
+ })
+
+ src = "hello world"
+ check(func(offsets []ansiOffset, state *ansiState) {
+ if len(offsets) != 1 {
+ t.Fail()
+ }
+ if state.fg != 2 || state.bg != -1 || !state.bold {
+ t.Fail()
+ }
+ assert(offsets[0], 0, 11, 2, -1, true)
+ })
+
+ src = "hello \x1b[0;38;5;200;48;5;100mworld"
+ check(func(offsets []ansiOffset, state *ansiState) {
+ if len(offsets) != 2 {
+ t.Fail()
+ }
+ if state.fg != 200 || state.bg != 100 || state.bold {
+ t.Fail()
+ }
+ assert(offsets[0], 0, 6, 2, -1, true)
+ assert(offsets[1], 6, 11, 200, 100, false)
+ })
}
diff --git a/src/core.go b/src/core.go
index e38908a8..7a0f1199 100644
--- a/src/core.go
+++ b/src/core.go
@@ -69,14 +69,17 @@ func Run(opts *Options) {
}
if opts.Ansi {
if opts.Theme != nil {
+ var state *ansiState
ansiProcessor = func(data *string) (*string, []ansiOffset) {
- return extractColor(data)
+ trimmed, offsets, newState := extractColor(data, state)
+ state = newState
+ return trimmed, offsets
}
} else {
// When color is disabled but ansi option is given,
// we simply strip out ANSI codes from the input
ansiProcessor = func(data *string) (*string, []ansiOffset) {
- trimmed, _ := extractColor(data)
+ trimmed, _, _ := extractColor(data, nil)
return trimmed, nil
}
}
diff --git a/src/terminal.go b/src/terminal.go
index 52c36cf9..a5ac33cc 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -378,6 +378,7 @@ func (t *Terminal) printHeader() {
return
}
max := C.MaxY()
+ var state *ansiState
for idx, lineStr := range t.header {
if !t.reverse {
idx = len(t.header) - idx - 1
@@ -389,7 +390,8 @@ func (t *Terminal) printHeader() {
if line >= max {
break
}
- trimmed, colors := extractColor(&lineStr)
+ trimmed, colors, newState := extractColor(&lineStr, state)
+ state = newState
item := &Item{
text: trimmed,
index: 0,