mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-11-20 03:51:02 +00:00
0ea66329b8
> wc -l /tmp/list2 2594098 /tmp/list2 > time cat /tmp/list2 | fzf-0.10.1-darwin_amd64 -fqwerty > /dev/null real 0m5.418s user 0m10.990s sys 0m1.302s > time cat /tmp/list2 | fzf-head -fqwerty > /dev/null real 0m4.862s user 0m6.619s sys 0m0.982s
150 lines
2.7 KiB
Go
150 lines
2.7 KiB
Go
package fzf
|
|
|
|
import (
|
|
"bytes"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type ansiOffset struct {
|
|
offset [2]int32
|
|
color ansiState
|
|
}
|
|
|
|
type ansiState struct {
|
|
fg int
|
|
bg int
|
|
bold bool
|
|
}
|
|
|
|
func (s *ansiState) colored() bool {
|
|
return s.fg != -1 || s.bg != -1 || s.bold
|
|
}
|
|
|
|
func (s *ansiState) equals(t *ansiState) bool {
|
|
if t == nil {
|
|
return !s.colored()
|
|
}
|
|
return s.fg == t.fg && s.bg == t.bg && s.bold == t.bold
|
|
}
|
|
|
|
var ansiRegex *regexp.Regexp
|
|
|
|
func init() {
|
|
ansiRegex = regexp.MustCompile("\x1b\\[[0-9;]*[mK]")
|
|
}
|
|
|
|
func extractColor(str string, state *ansiState) (string, []ansiOffset, *ansiState) {
|
|
var offsets []ansiOffset
|
|
var output bytes.Buffer
|
|
|
|
if state != nil {
|
|
offsets = append(offsets, ansiOffset{[2]int32{0, 0}, *state})
|
|
}
|
|
|
|
idx := 0
|
|
for _, offset := range ansiRegex.FindAllStringIndex(str, -1) {
|
|
output.WriteString(str[idx:offset[0]])
|
|
newState := interpretCode(str[offset[0]:offset[1]], state)
|
|
|
|
if !newState.equals(state) {
|
|
if state != nil {
|
|
// Update last offset
|
|
(&offsets[len(offsets)-1]).offset[1] = int32(utf8.RuneCount(output.Bytes()))
|
|
}
|
|
|
|
if newState.colored() {
|
|
// Append new offset
|
|
state = newState
|
|
newLen := int32(utf8.RuneCount(output.Bytes()))
|
|
offsets = append(offsets, ansiOffset{[2]int32{newLen, newLen}, *state})
|
|
} else {
|
|
// Discard state
|
|
state = nil
|
|
}
|
|
}
|
|
|
|
idx = offset[1]
|
|
}
|
|
|
|
rest := str[idx:]
|
|
if len(rest) > 0 {
|
|
output.WriteString(rest)
|
|
if state != nil {
|
|
// Update last offset
|
|
(&offsets[len(offsets)-1]).offset[1] = int32(utf8.RuneCount(output.Bytes()))
|
|
}
|
|
}
|
|
return output.String(), offsets, state
|
|
}
|
|
|
|
func interpretCode(ansiCode string, prevState *ansiState) *ansiState {
|
|
// State
|
|
var state *ansiState
|
|
if prevState == nil {
|
|
state = &ansiState{-1, -1, false}
|
|
} else {
|
|
state = &ansiState{prevState.fg, prevState.bg, prevState.bold}
|
|
}
|
|
if ansiCode[len(ansiCode)-1] == 'K' {
|
|
return state
|
|
}
|
|
|
|
ptr := &state.fg
|
|
state256 := 0
|
|
|
|
init := func() {
|
|
state.fg = -1
|
|
state.bg = -1
|
|
state.bold = false
|
|
state256 = 0
|
|
}
|
|
|
|
ansiCode = ansiCode[2 : len(ansiCode)-1]
|
|
if len(ansiCode) == 0 {
|
|
init()
|
|
}
|
|
for _, code := range strings.Split(ansiCode, ";") {
|
|
if num, err := strconv.Atoi(code); err == nil {
|
|
switch state256 {
|
|
case 0:
|
|
switch num {
|
|
case 38:
|
|
ptr = &state.fg
|
|
state256++
|
|
case 48:
|
|
ptr = &state.bg
|
|
state256++
|
|
case 39:
|
|
state.fg = -1
|
|
case 49:
|
|
state.bg = -1
|
|
case 1:
|
|
state.bold = true
|
|
case 0:
|
|
init()
|
|
default:
|
|
if num >= 30 && num <= 37 {
|
|
state.fg = num - 30
|
|
} else if num >= 40 && num <= 47 {
|
|
state.bg = num - 40
|
|
}
|
|
}
|
|
case 1:
|
|
switch num {
|
|
case 5:
|
|
state256++
|
|
default:
|
|
state256 = 0
|
|
}
|
|
case 2:
|
|
*ptr = num
|
|
state256 = 0
|
|
}
|
|
}
|
|
}
|
|
return state
|
|
}
|