aboutsummaryrefslogtreecommitdiff
path: root/vendor/maunium.net/go/tcell/terminfo/terminfo.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/maunium.net/go/tcell/terminfo/terminfo.go')
-rw-r--r--vendor/maunium.net/go/tcell/terminfo/terminfo.go881
1 files changed, 0 insertions, 881 deletions
diff --git a/vendor/maunium.net/go/tcell/terminfo/terminfo.go b/vendor/maunium.net/go/tcell/terminfo/terminfo.go
deleted file mode 100644
index 045a372..0000000
--- a/vendor/maunium.net/go/tcell/terminfo/terminfo.go
+++ /dev/null
@@ -1,881 +0,0 @@
-// Copyright 2018 The TCell Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use file except in compliance with the License.
-// You may obtain a copy of the license at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package terminfo
-
-import (
- "bytes"
- "compress/gzip"
- "crypto/sha1"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "os"
- "path"
- "path/filepath"
- "strconv"
- "strings"
- "sync"
-)
-
-var (
- // ErrTermNotFound indicates that a suitable terminal entry could
- // not be found. This can result from either not having TERM set,
- // or from the TERM failing to support certain minimal functionality,
- // in particular absolute cursor addressability (the cup capability)
- // is required. For example, legacy "adm3" lacks this capability,
- // whereas the slightly newer "adm3a" supports it. This failure
- // occurs most often with "dumb".
- ErrTermNotFound = errors.New("terminal entry not found")
-)
-
-// Terminfo represents a terminfo entry. Note that we use friendly names
-// in Go, but when we write out JSON, we use the same names as terminfo.
-// The name, aliases and smous, rmous fields do not come from terminfo directly.
-type Terminfo struct {
- Name string `json:"name"`
- Aliases []string `json:"aliases,omitempty"`
- Columns int `json:"cols,omitempty"` // cols
- Lines int `json:"lines,omitempty"` // lines
- Colors int `json:"colors,omitempty"` // colors
- Bell string `json:"bell,omitempty"` // bell
- Clear string `json:"clear,omitempty"` // clear
- EnterCA string `json:"smcup,omitempty"` // smcup
- ExitCA string `json:"rmcup,omitempty"` // rmcup
- ShowCursor string `json:"cnorm,omitempty"` // cnorm
- HideCursor string `json:"civis,omitempty"` // civis
- AttrOff string `json:"sgr0,omitempty"` // sgr0
- Underline string `json:"smul,omitempty"` // smul
- Bold string `json:"bold,omitempty"` // bold
- Italic string `json:"sitm,omitempty"` // sitm
- Strikethrough string `json:"strikethrough,omitempty"` // strikethrough
- Blink string `json:"blink,omitempty"` // blink
- Reverse string `json:"rev,omitempty"` // rev
- Dim string `json:"dim,omitempty"` // dim
- EnterKeypad string `json:"smkx,omitempty"` // smkx
- ExitKeypad string `json:"rmkx,omitempty"` // rmkx
- SetFg string `json:"setaf,omitempty"` // setaf
- SetBg string `json:"setbg,omitempty"` // setab
- SetCursor string `json:"cup,omitempty"` // cup
- CursorBack1 string `json:"cub1,omitempty"` // cub1
- CursorUp1 string `json:"cuu1,omitempty"` // cuu1
- PadChar string `json:"pad,omitempty"` // pad
- KeyBackspace string `json:"kbs,omitempty"` // kbs
- KeyF1 string `json:"kf1,omitempty"` // kf1
- KeyF2 string `json:"kf2,omitempty"` // kf2
- KeyF3 string `json:"kf3,omitempty"` // kf3
- KeyF4 string `json:"kf4,omitempty"` // kf4
- KeyF5 string `json:"kf5,omitempty"` // kf5
- KeyF6 string `json:"kf6,omitempty"` // kf6
- KeyF7 string `json:"kf7,omitempty"` // kf7
- KeyF8 string `json:"kf8,omitempty"` // kf8
- KeyF9 string `json:"kf9,omitempty"` // kf9
- KeyF10 string `json:"kf10,omitempty"` // kf10
- KeyF11 string `json:"kf11,omitempty"` // kf11
- KeyF12 string `json:"kf12,omitempty"` // kf12
- KeyF13 string `json:"kf13,omitempty"` // kf13
- KeyF14 string `json:"kf14,omitempty"` // kf14
- KeyF15 string `json:"kf15,omitempty"` // kf15
- KeyF16 string `json:"kf16,omitempty"` // kf16
- KeyF17 string `json:"kf17,omitempty"` // kf17
- KeyF18 string `json:"kf18,omitempty"` // kf18
- KeyF19 string `json:"kf19,omitempty"` // kf19
- KeyF20 string `json:"kf20,omitempty"` // kf20
- KeyF21 string `json:"kf21,omitempty"` // kf21
- KeyF22 string `json:"kf22,omitempty"` // kf22
- KeyF23 string `json:"kf23,omitempty"` // kf23
- KeyF24 string `json:"kf24,omitempty"` // kf24
- KeyF25 string `json:"kf25,omitempty"` // kf25
- KeyF26 string `json:"kf26,omitempty"` // kf26
- KeyF27 string `json:"kf27,omitempty"` // kf27
- KeyF28 string `json:"kf28,omitempty"` // kf28
- KeyF29 string `json:"kf29,omitempty"` // kf29
- KeyF30 string `json:"kf30,omitempty"` // kf30
- KeyF31 string `json:"kf31,omitempty"` // kf31
- KeyF32 string `json:"kf32,omitempty"` // kf32
- KeyF33 string `json:"kf33,omitempty"` // kf33
- KeyF34 string `json:"kf34,omitempty"` // kf34
- KeyF35 string `json:"kf35,omitempty"` // kf35
- KeyF36 string `json:"kf36,omitempty"` // kf36
- KeyF37 string `json:"kf37,omitempty"` // kf37
- KeyF38 string `json:"kf38,omitempty"` // kf38
- KeyF39 string `json:"kf39,omitempty"` // kf39
- KeyF40 string `json:"kf40,omitempty"` // kf40
- KeyF41 string `json:"kf41,omitempty"` // kf41
- KeyF42 string `json:"kf42,omitempty"` // kf42
- KeyF43 string `json:"kf43,omitempty"` // kf43
- KeyF44 string `json:"kf44,omitempty"` // kf44
- KeyF45 string `json:"kf45,omitempty"` // kf45
- KeyF46 string `json:"kf46,omitempty"` // kf46
- KeyF47 string `json:"kf47,omitempty"` // kf47
- KeyF48 string `json:"kf48,omitempty"` // kf48
- KeyF49 string `json:"kf49,omitempty"` // kf49
- KeyF50 string `json:"kf50,omitempty"` // kf50
- KeyF51 string `json:"kf51,omitempty"` // kf51
- KeyF52 string `json:"kf52,omitempty"` // kf52
- KeyF53 string `json:"kf53,omitempty"` // kf53
- KeyF54 string `json:"kf54,omitempty"` // kf54
- KeyF55 string `json:"kf55,omitempty"` // kf55
- KeyF56 string `json:"kf56,omitempty"` // kf56
- KeyF57 string `json:"kf57,omitempty"` // kf57
- KeyF58 string `json:"kf58,omitempty"` // kf58
- KeyF59 string `json:"kf59,omitempty"` // kf59
- KeyF60 string `json:"kf60,omitempty"` // kf60
- KeyF61 string `json:"kf61,omitempty"` // kf61
- KeyF62 string `json:"kf62,omitempty"` // kf62
- KeyF63 string `json:"kf63,omitempty"` // kf63
- KeyF64 string `json:"kf64,omitempty"` // kf64
- KeyInsert string `json:"kich,omitempty"` // kich1
- KeyDelete string `json:"kdch,omitempty"` // kdch1
- KeyHome string `json:"khome,omitempty"` // khome
- KeyEnd string `json:"kend,omitempty"` // kend
- KeyHelp string `json:"khlp,omitempty"` // khlp
- KeyPgUp string `json:"kpp,omitempty"` // kpp
- KeyPgDn string `json:"knp,omitempty"` // knp
- KeyUp string `json:"kcuu1,omitempty"` // kcuu1
- KeyDown string `json:"kcud1,omitempty"` // kcud1
- KeyLeft string `json:"kcub1,omitempty"` // kcub1
- KeyRight string `json:"kcuf1,omitempty"` // kcuf1
- KeyBacktab string `json:"kcbt,omitempty"` // kcbt
- KeyExit string `json:"kext,omitempty"` // kext
- KeyClear string `json:"kclr,omitempty"` // kclr
- KeyPrint string `json:"kprt,omitempty"` // kprt
- KeyCancel string `json:"kcan,omitempty"` // kcan
- Mouse string `json:"kmous,omitempty"` // kmous
- MouseMode string `json:"XM,omitempty"` // XM
- AltChars string `json:"acsc,omitempty"` // acsc
- EnterAcs string `json:"smacs,omitempty"` // smacs
- ExitAcs string `json:"rmacs,omitempty"` // rmacs
- EnableAcs string `json:"enacs,omitempty"` // enacs
- KeyShfRight string `json:"kRIT,omitempty"` // kRIT
- KeyShfLeft string `json:"kLFT,omitempty"` // kLFT
- KeyShfHome string `json:"kHOM,omitempty"` // kHOM
- KeyShfEnd string `json:"kEND,omitempty"` // kEND
-
- // These are non-standard extensions to terminfo. This includes
- // true color support, and some additional keys. Its kind of bizarre
- // that shifted variants of left and right exist, but not up and down.
- // Terminal support for these are going to vary amongst XTerm
- // emulations, so don't depend too much on them in your application.
-
- SetFgBg string `json:"_setfgbg,omitempty"` // setfgbg
- SetFgBgRGB string `json:"_setfgbgrgb,omitempty"` // setfgbgrgb
- SetFgRGB string `json:"_setfrgb,omitempty"` // setfrgb
- SetBgRGB string `json:"_setbrgb,omitempty"` // setbrgb
- KeyShfUp string `json:"_kscu1,omitempty"` // shift-up
- KeyShfDown string `json:"_kscud1,omitempty"` // shift-down
- KeyCtrlUp string `json:"_kccu1,omitempty"` // ctrl-up
- KeyCtrlDown string `json:"_kccud1,omitempty"` // ctrl-left
- KeyCtrlRight string `json:"_kccuf1,omitempty"` // ctrl-right
- KeyCtrlLeft string `json:"_kccub1,omitempty"` // ctrl-left
- KeyMetaUp string `json:"_kmcu1,omitempty"` // meta-up
- KeyMetaDown string `json:"_kmcud1,omitempty"` // meta-left
- KeyMetaRight string `json:"_kmcuf1,omitempty"` // meta-right
- KeyMetaLeft string `json:"_kmcub1,omitempty"` // meta-left
- KeyAltUp string `json:"_kacu1,omitempty"` // alt-up
- KeyAltDown string `json:"_kacud1,omitempty"` // alt-left
- KeyAltRight string `json:"_kacuf1,omitempty"` // alt-right
- KeyAltLeft string `json:"_kacub1,omitempty"` // alt-left
- KeyCtrlHome string `json:"_kchome,omitempty"`
- KeyCtrlEnd string `json:"_kcend,omitempty"`
- KeyMetaHome string `json:"_kmhome,omitempty"`
- KeyMetaEnd string `json:"_kmend,omitempty"`
- KeyAltHome string `json:"_kahome,omitempty"`
- KeyAltEnd string `json:"_kaend,omitempty"`
- KeyAltShfUp string `json:"_kascu1,omitempty"`
- KeyAltShfDown string `json:"_kascud1,omitempty"`
- KeyAltShfLeft string `json:"_kascub1,omitempty"`
- KeyAltShfRight string `json:"_kascuf1,omitempty"`
- KeyMetaShfUp string `json:"_kmscu1,omitempty"`
- KeyMetaShfDown string `json:"_kmscud1,omitempty"`
- KeyMetaShfLeft string `json:"_kmscub1,omitempty"`
- KeyMetaShfRight string `json:"_kmscuf1,omitempty"`
- KeyCtrlShfUp string `json:"_kcscu1,omitempty"`
- KeyCtrlShfDown string `json:"_kcscud1,omitempty"`
- KeyCtrlShfLeft string `json:"_kcscub1,omitempty"`
- KeyCtrlShfRight string `json:"_kcscuf1,omitempty"`
- KeyCtrlShfHome string `json:"_kcHOME,omitempty"`
- KeyCtrlShfEnd string `json:"_kcEND,omitempty"`
- KeyAltShfHome string `json:"_kaHOME,omitempty"`
- KeyAltShfEnd string `json:"_kaEND,omitempty"`
- KeyMetaShfHome string `json:"_kmHOME,omitempty"`
- KeyMetaShfEnd string `json:"_kmEND,omitempty"`
- KeyCtrlPgUp string
- KeyCtrlPgDn string
-}
-
-type stackElem struct {
- s string
- i int
- isStr bool
- isInt bool
-}
-
-type stack []stackElem
-
-func (st stack) Push(v string) stack {
- e := stackElem{
- s: v,
- isStr: true,
- }
- return append(st, e)
-}
-
-func (st stack) Pop() (string, stack) {
- v := ""
- if len(st) > 0 {
- e := st[len(st)-1]
- st = st[:len(st)-1]
- if e.isStr {
- v = e.s
- } else {
- v = strconv.Itoa(e.i)
- }
- }
- return v, st
-}
-
-func (st stack) PopInt() (int, stack) {
- if len(st) > 0 {
- e := st[len(st)-1]
- st = st[:len(st)-1]
- if e.isInt {
- return e.i, st
- } else if e.isStr {
- i, _ := strconv.Atoi(e.s)
- return i, st
- }
- }
- return 0, st
-}
-
-func (st stack) PopBool() (bool, stack) {
- if len(st) > 0 {
- e := st[len(st)-1]
- st = st[:len(st)-1]
- if e.isStr {
- if e.s == "1" {
- return true, st
- }
- return false, st
- } else if e.i == 1 {
- return true, st
- } else {
- return false, st
- }
- }
- return false, st
-}
-
-func (st stack) PushInt(i int) stack {
- e := stackElem{
- i: i,
- isInt: true,
- }
- return append(st, e)
-}
-
-func (st stack) PushBool(i bool) stack {
- if i {
- return st.PushInt(1)
- }
- return st.PushInt(0)
-}
-
-func nextch(s string, index int) (byte, int) {
- if index < len(s) {
- return s[index], index + 1
- }
- return 0, index
-}
-
-// static vars
-var svars [26]string
-
-// paramsBuffer handles some persistent state for TParam. Technically we
-// could probably dispense with this, but caching buffer arrays gives us
-// a nice little performance boost. Furthermore, we know that TParam is
-// rarely (never?) called re-entrantly, so we can just reuse the same
-// buffers, making it thread-safe by stashing a lock.
-type paramsBuffer struct {
- out bytes.Buffer
- buf bytes.Buffer
- lk sync.Mutex
-}
-
-// Start initializes the params buffer with the initial string data.
-// It also locks the paramsBuffer. The caller must call End() when
-// finished.
-func (pb *paramsBuffer) Start(s string) {
- pb.lk.Lock()
- pb.out.Reset()
- pb.buf.Reset()
- pb.buf.WriteString(s)
-}
-
-// End returns the final output from TParam, but it also releases the lock.
-func (pb *paramsBuffer) End() string {
- s := pb.out.String()
- pb.lk.Unlock()
- return s
-}
-
-// NextCh returns the next input character to the expander.
-func (pb *paramsBuffer) NextCh() (byte, error) {
- return pb.buf.ReadByte()
-}
-
-// PutCh "emits" (rather schedules for output) a single byte character.
-func (pb *paramsBuffer) PutCh(ch byte) {
- pb.out.WriteByte(ch)
-}
-
-// PutString schedules a string for output.
-func (pb *paramsBuffer) PutString(s string) {
- pb.out.WriteString(s)
-}
-
-var pb = &paramsBuffer{}
-
-// TParm takes a terminfo parameterized string, such as setaf or cup, and
-// evaluates the string, and returns the result with the parameter
-// applied.
-func (t *Terminfo) TParm(s string, p ...int) string {
- var stk stack
- var a, b string
- var ai, bi int
- var ab bool
- var dvars [26]string
- var params [9]int
-
- pb.Start(s)
-
- // make sure we always have 9 parameters -- makes it easier
- // later to skip checks
- for i := 0; i < len(params) && i < len(p); i++ {
- params[i] = p[i]
- }
-
- nest := 0
-
- for {
-
- ch, err := pb.NextCh()
- if err != nil {
- break
- }
-
- if ch != '%' {
- pb.PutCh(ch)
- continue
- }
-
- ch, err = pb.NextCh()
- if err != nil {
- // XXX Error
- break
- }
-
- switch ch {
- case '%': // quoted %
- pb.PutCh(ch)
-
- case 'i': // increment both parameters (ANSI cup support)
- params[0]++
- params[1]++
-
- case 'c', 's':
- // NB: these, and 'd' below are special cased for
- // efficiency. They could be handled by the richer
- // format support below, less efficiently.
- a, stk = stk.Pop()
- pb.PutString(a)
-
- case 'd':
- ai, stk = stk.PopInt()
- pb.PutString(strconv.Itoa(ai))
-
- case '0', '1', '2', '3', '4', 'x', 'X', 'o', ':':
- // This is pretty suboptimal, but this is rarely used.
- // None of the mainstream terminals use any of this,
- // and it would surprise me if this code is ever
- // executed outside of test cases.
- f := "%"
- if ch == ':' {
- ch, _ = pb.NextCh()
- }
- f += string(ch)
- for ch == '+' || ch == '-' || ch == '#' || ch == ' ' {
- ch, _ = pb.NextCh()
- f += string(ch)
- }
- for (ch >= '0' && ch <= '9') || ch == '.' {
- ch, _ = pb.NextCh()
- f += string(ch)
- }
- switch ch {
- case 'd', 'x', 'X', 'o':
- ai, stk = stk.PopInt()
- pb.PutString(fmt.Sprintf(f, ai))
- case 'c', 's':
- a, stk = stk.Pop()
- pb.PutString(fmt.Sprintf(f, a))
- }
-
- case 'p': // push parameter
- ch, _ = pb.NextCh()
- ai = int(ch - '1')
- if ai >= 0 && ai < len(params) {
- stk = stk.PushInt(params[ai])
- } else {
- stk = stk.PushInt(0)
- }
-
- case 'P': // pop & store variable
- ch, _ = pb.NextCh()
- if ch >= 'A' && ch <= 'Z' {
- svars[int(ch-'A')], stk = stk.Pop()
- } else if ch >= 'a' && ch <= 'z' {
- dvars[int(ch-'a')], stk = stk.Pop()
- }
-
- case 'g': // recall & push variable
- ch, _ = pb.NextCh()
- if ch >= 'A' && ch <= 'Z' {
- stk = stk.Push(svars[int(ch-'A')])
- } else if ch >= 'a' && ch <= 'z' {
- stk = stk.Push(dvars[int(ch-'a')])
- }
-
- case '\'': // push(char)
- ch, _ = pb.NextCh()
- pb.NextCh() // must be ' but we don't check
- stk = stk.Push(string(ch))
-
- case '{': // push(int)
- ai = 0
- ch, _ = pb.NextCh()
- for ch >= '0' && ch <= '9' {
- ai *= 10
- ai += int(ch - '0')
- ch, _ = pb.NextCh()
- }
- // ch must be '}' but no verification
- stk = stk.PushInt(ai)
-
- case 'l': // push(strlen(pop))
- a, stk = stk.Pop()
- stk = stk.PushInt(len(a))
-
- case '+':
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushInt(ai + bi)
-
- case '-':
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushInt(ai - bi)
-
- case '*':
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushInt(ai * bi)
-
- case '/':
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- if bi != 0 {
- stk = stk.PushInt(ai / bi)
- } else {
- stk = stk.PushInt(0)
- }
-
- case 'm': // push(pop mod pop)
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- if bi != 0 {
- stk = stk.PushInt(ai % bi)
- } else {
- stk = stk.PushInt(0)
- }
-
- case '&': // AND
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushInt(ai & bi)
-
- case '|': // OR
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushInt(ai | bi)
-
- case '^': // XOR
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushInt(ai ^ bi)
-
- case '~': // bit complement
- ai, stk = stk.PopInt()
- stk = stk.PushInt(ai ^ -1)
-
- case '!': // logical NOT
- ai, stk = stk.PopInt()
- stk = stk.PushBool(ai != 0)
-
- case '=': // numeric compare or string compare
- b, stk = stk.Pop()
- a, stk = stk.Pop()
- stk = stk.PushBool(a == b)
-
- case '>': // greater than, numeric
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushBool(ai > bi)
-
- case '<': // less than, numeric
- bi, stk = stk.PopInt()
- ai, stk = stk.PopInt()
- stk = stk.PushBool(ai < bi)
-
- case '?': // start conditional
-
- case 't':
- ab, stk = stk.PopBool()
- if ab {
- // just keep going
- break
- }
- nest = 0
- ifloop:
- // this loop consumes everything until we hit our else,
- // or the end of the conditional
- for {
- ch, err = pb.NextCh()
- if err != nil {
- break
- }
- if ch != '%' {
- continue
- }
- ch, _ = pb.NextCh()
- switch ch {
- case ';':
- if nest == 0 {
- break ifloop
- }
- nest--
- case '?':
- nest++
- case 'e':
- if nest == 0 {
- break ifloop
- }
- }
- }
-
- case 'e':
- // if we got here, it means we didn't use the else
- // in the 't' case above, and we should skip until
- // the end of the conditional
- nest = 0
- elloop:
- for {
- ch, err = pb.NextCh()
- if err != nil {
- break
- }
- if ch != '%' {
- continue
- }
- ch, _ = pb.NextCh()
- switch ch {
- case ';':
- if nest == 0 {
- break elloop
- }
- nest--
- case '?':
- nest++
- }
- }
-
- case ';': // endif
-
- }
- }
-
- return pb.End()
-}
-
-// TPuts emits the string to the writer, but expands inline padding
-// indications (of the form $<[delay]> where [delay] is msec) to
-// a suitable number of padding characters (usually null bytes) based
-// upon the supplied baud. At high baud rates, more padding characters
-// will be inserted. All Terminfo based strings should be emitted using
-// this function.
-func (t *Terminfo) TPuts(w io.Writer, s string, baud int) {
- for {
- beg := strings.Index(s, "$<")
- if beg < 0 {
- // Most strings don't need padding, which is good news!
- io.WriteString(w, s)
- return
- }
- io.WriteString(w, s[:beg])
- s = s[beg+2:]
- end := strings.Index(s, ">")
- if end < 0 {
- // unterminated.. just emit bytes unadulterated
- io.WriteString(w, "$<"+s)
- return
- }
- val := s[:end]
- s = s[end+1:]
- padus := 0
- unit := 1000
- dot := false
- loop:
- for i := range val {
- switch val[i] {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- padus *= 10
- padus += int(val[i] - '0')
- if dot {
- unit *= 10
- }
- case '.':
- if !dot {
- dot = true
- } else {
- break loop
- }
- default:
- break loop
- }
- }
- cnt := int(((baud / 8) * padus) / unit)
- for cnt > 0 {
- io.WriteString(w, t.PadChar)
- cnt--
- }
- }
-}
-
-// TGoto returns a string suitable for addressing the cursor at the given
-// row and column. The origin 0, 0 is in the upper left corner of the screen.
-func (t *Terminfo) TGoto(col, row int) string {
- return t.TParm(t.SetCursor, row, col)
-}
-
-// TColor returns a string corresponding to the given foreground and background
-// colors. Either fg or bg can be set to -1 to elide.
-func (t *Terminfo) TColor(fi, bi int) string {
- rv := ""
- // As a special case, we map bright colors to lower versions if the
- // color table only holds 8. For the remaining 240 colors, the user
- // is out of luck. Someday we could create a mapping table, but its
- // not worth it.
- if t.Colors == 8 {
- if fi > 7 && fi < 16 {
- fi -= 8
- }
- if bi > 7 && bi < 16 {
- bi -= 8
- }
- }
- if t.Colors > fi && fi >= 0 {
- rv += t.TParm(t.SetFg, fi)
- }
- if t.Colors > bi && bi >= 0 {
- rv += t.TParm(t.SetBg, bi)
- }
- return rv
-}
-
-var (
- dblock sync.Mutex
- terminfos = make(map[string]*Terminfo)
- aliases = make(map[string]string)
-)
-
-// AddTerminfo can be called to register a new Terminfo entry.
-func AddTerminfo(t *Terminfo) {
- dblock.Lock()
- terminfos[t.Name] = t
- for _, x := range t.Aliases {
- terminfos[x] = t
- }
- dblock.Unlock()
-}
-
-func loadFromFile(fname string, term string) (*Terminfo, error) {
- var e error
- var f io.Reader
- if f, e = os.Open(fname); e != nil {
- return nil, e
- }
- if strings.HasSuffix(fname, ".gz") {
- if f, e = gzip.NewReader(f); e != nil {
- return nil, e
- }
- }
- d := json.NewDecoder(f)
- for {
- t := &Terminfo{}
- if e := d.Decode(t); e != nil {
- if e == io.EOF {
- return nil, ErrTermNotFound
- }
- return nil, e
- }
- if t.SetCursor == "" {
- // This must be an alias record, return it.
- return t, nil
- }
- if t.Name == term {
- return t, nil
- }
- for _, a := range t.Aliases {
- if a == term {
- return t, nil
- }
- }
- }
-}
-
-// LookupTerminfo attempts to find a definition for the named $TERM.
-// It first looks in the builtin database, which should cover just about
-// everyone. If it can't find one there, then it will attempt to read
-// one from the JSON file located in either $TCELLDB, $HOME/.tcelldb,
-// or as a database file.
-//
-// The database files are named by taking terminal name, hashing it through
-// sha1, and then a subdirectory of the form database/hash[0:2]/hash[0:8]
-// (with an optional .gz extension).
-//
-// For other local database files, we will look for the database file using
-// the terminal name, so database/term[0:2]/term[0:8], again with optional
-// .gz extension.
-func LookupTerminfo(name string) (*Terminfo, error) {
- if name == "" {
- // else on windows: index out of bounds
- // on the name[0] reference below
- return nil, ErrTermNotFound
- }
-
- dblock.Lock()
- t := terminfos[name]
- dblock.Unlock()
-
- if t == nil {
-
- var files []string
- letter := fmt.Sprintf("%02x", name[0])
- gzfile := path.Join(letter, name+".gz")
- jsfile := path.Join(letter, name)
- hash := fmt.Sprintf("%x", sha1.Sum([]byte(name)))
- gzhfile := path.Join(hash[0:2], hash[0:8]+".gz")
- jshfile := path.Join(hash[0:2], hash[0:8])
-
- // Build up the search path. Old versions of tcell used a
- // single database file, whereas the new ones locate them
- // in JSON (optionally compressed) files.
- //
- // The search path for "xterm" (SHA1 sig e2e28a8e...) looks
- // like this:
- //
- // $TCELLDB/78/xterm.gz
- // $TCELLDB/78/xterm
- // $TCELLDB
- // $HOME/.tcelldb/e2/e2e28a8e.gz
- // $HOME/.tcelldb/e2/e2e28a8e
- // $HOME/.tcelldb/78/xterm.gz
- // $HOME/.tcelldb/78/xterm
- // $HOME/.tcelldb
- // $GOPATH/terminfo/database/e2/e2e28a8e.gz
- // $GOPATH/terminfo/database/e2/e2e28a8e
- // $GOPATH/terminfo/database/78/xterm.gz
- // $GOPATH/terminfo/database/78/xterm
- //
- // Note that the legacy name lookups (78/xterm etc.) are
- // provided for compatibility. We do not actually deliver
- // any files with this style of naming, to avoid collisions
- // on case insensitive filesystems. (*cough* mac *cough*).
-
- // If $GOPATH set, honor it, else assume $HOME/go just like
- // modern golang does.
- gopath := os.Getenv("GOPATH")
- if gopath == "" {
- gopath = path.Join(os.Getenv("HOME"), "go")
- }
- if pth := os.Getenv("TCELLDB"); pth != "" {
- files = append(files,
- path.Join(pth, gzfile),
- path.Join(pth, jsfile),
- pth)
- }
- if pth := os.Getenv("HOME"); pth != "" {
- pth = path.Join(pth, ".tcelldb")
- files = append(files,
- path.Join(pth, gzhfile),
- path.Join(pth, jshfile),
- path.Join(pth, gzfile),
- path.Join(pth, jsfile),
- pth)
- }
-
- for _, pth := range filepath.SplitList(gopath) {
- pth = path.Join(pth, "src", "github.com",
- "gdamore", "tcell", "terminfo", "database")
- files = append(files,
- path.Join(pth, gzhfile),
- path.Join(pth, jshfile),
- path.Join(pth, gzfile),
- path.Join(pth, jsfile))
- }
-
- for _, fname := range files {
- t, _ = loadFromFile(fname, name)
- if t != nil {
- break
- }
- }
- if t != nil {
- if t.Name != name {
- // Check for a database loop (no infinite
- // recursion).
- dblock.Lock()
- if aliases[name] != "" {
- dblock.Unlock()
- return nil, ErrTermNotFound
- }
- aliases[name] = t.Name
- dblock.Unlock()
- return LookupTerminfo(t.Name)
- }
- dblock.Lock()
- terminfos[name] = t
- dblock.Unlock()
- }
- }
- if t == nil {
- t, _ = GetDynamic()
- }
- if t == nil {
- return nil, ErrTermNotFound
- }
- return t, nil
-}