aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/jroimartin/gocui/escape.go
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2018-07-30 18:11:53 +0200
committerMichael Muré <batolettre@gmail.com>2018-07-30 18:11:53 +0200
commitbb9168f98a9dd50a7215652ab77a1c46615064cd (patch)
tree8ee16c1b5c6078cd48427c799375b78c95749bcd /vendor/github.com/jroimartin/gocui/escape.go
parent29bb7364c8e873c72a386f4f6fa26248e5355cb2 (diff)
downloadgit-bug-bb9168f98a9dd50a7215652ab77a1c46615064cd.tar.gz
vendor gocui
Diffstat (limited to 'vendor/github.com/jroimartin/gocui/escape.go')
-rw-r--r--vendor/github.com/jroimartin/gocui/escape.go168
1 files changed, 168 insertions, 0 deletions
diff --git a/vendor/github.com/jroimartin/gocui/escape.go b/vendor/github.com/jroimartin/gocui/escape.go
new file mode 100644
index 00000000..07871d52
--- /dev/null
+++ b/vendor/github.com/jroimartin/gocui/escape.go
@@ -0,0 +1,168 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+ "errors"
+ "strconv"
+)
+
+type escapeInterpreter struct {
+ state escapeState
+ curch rune
+ csiParam []string
+ curFgColor, curBgColor Attribute
+}
+
+type escapeState int
+
+const (
+ stateNone escapeState = iota
+ stateEscape
+ stateCSI
+ stateParams
+)
+
+var (
+ errNotCSI = errors.New("Not a CSI escape sequence")
+ errCSINotANumber = errors.New("CSI escape sequence was expecting a number or a ;")
+ errCSIParseError = errors.New("CSI escape sequence parsing error")
+ errCSITooLong = errors.New("CSI escape sequence is too long")
+)
+
+// runes in case of error will output the non-parsed runes as a string.
+func (ei *escapeInterpreter) runes() []rune {
+ switch ei.state {
+ case stateNone:
+ return []rune{0x1b}
+ case stateEscape:
+ return []rune{0x1b, ei.curch}
+ case stateCSI:
+ return []rune{0x1b, '[', ei.curch}
+ case stateParams:
+ ret := []rune{0x1b, '['}
+ for _, s := range ei.csiParam {
+ ret = append(ret, []rune(s)...)
+ ret = append(ret, ';')
+ }
+ return append(ret, ei.curch)
+ }
+ return nil
+}
+
+// newEscapeInterpreter returns an escapeInterpreter that will be able to parse
+// terminal escape sequences.
+func newEscapeInterpreter() *escapeInterpreter {
+ ei := &escapeInterpreter{
+ state: stateNone,
+ curFgColor: ColorDefault,
+ curBgColor: ColorDefault,
+ }
+ return ei
+}
+
+// reset sets the escapeInterpreter in initial state.
+func (ei *escapeInterpreter) reset() {
+ ei.state = stateNone
+ ei.curFgColor = ColorDefault
+ ei.curBgColor = ColorDefault
+ ei.csiParam = nil
+}
+
+// paramToColor returns an attribute given a terminfo coloring.
+func paramToColor(p int) Attribute {
+ switch p {
+ case 0:
+ return ColorBlack
+ case 1:
+ return ColorRed
+ case 2:
+ return ColorGreen
+ case 3:
+ return ColorYellow
+ case 4:
+ return ColorBlue
+ case 5:
+ return ColorMagenta
+ case 6:
+ return ColorCyan
+ case 7:
+ return ColorWhite
+ }
+ return ColorDefault
+}
+
+// parseOne parses a rune. If isEscape is true, it means that the rune is part
+// of an escape sequence, and as such should not be printed verbatim. Otherwise,
+// it's not an escape sequence.
+func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) {
+ // Sanity checks to make sure we're not parsing something totally bogus.
+ if len(ei.csiParam) > 20 {
+ return false, errCSITooLong
+ }
+ if len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 {
+ return false, errCSITooLong
+ }
+ ei.curch = ch
+ switch ei.state {
+ case stateNone:
+ if ch == 0x1b {
+ ei.state = stateEscape
+ return true, nil
+ }
+ return false, nil
+ case stateEscape:
+ if ch == '[' {
+ ei.state = stateCSI
+ return true, nil
+ }
+ return false, errNotCSI
+ case stateCSI:
+ if ch >= '0' && ch <= '9' {
+ ei.state = stateParams
+ ei.csiParam = append(ei.csiParam, string(ch))
+ return true, nil
+ }
+ return false, errCSINotANumber
+ case stateParams:
+ switch {
+ case ch >= '0' && ch <= '9':
+ ei.csiParam[len(ei.csiParam)-1] += string(ch)
+ return true, nil
+ case ch == ';':
+ ei.csiParam = append(ei.csiParam, "")
+ return true, nil
+ case ch == 'm':
+ if len(ei.csiParam) < 1 {
+ return false, errCSIParseError
+ }
+ for _, param := range ei.csiParam {
+ p, err := strconv.Atoi(param)
+ if err != nil {
+ return false, errCSIParseError
+ }
+ switch {
+ case p >= 30 && p <= 37:
+ ei.curFgColor = paramToColor(p - 30)
+ case p >= 40 && p <= 47:
+ ei.curBgColor = paramToColor(p - 40)
+ case p == 1:
+ ei.curFgColor |= AttrBold
+ case p == 4:
+ ei.curFgColor |= AttrUnderline
+ case p == 7:
+ ei.curFgColor |= AttrReverse
+ case p == 0 || p == 39:
+ ei.curFgColor = ColorDefault
+ ei.curBgColor = ColorDefault
+ }
+ }
+ ei.state = stateNone
+ ei.csiParam = nil
+ return true, nil
+ }
+ }
+ return false, nil
+}