From 331597b9f8a7942cbcb233a328301e4d5bf94fb0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 11 Jan 2019 23:28:47 +0200 Subject: Switch to Go modules and make other changes --- vendor/maunium.net/go/tcell/terminfo/terminfo.go | 881 ----------------------- 1 file changed, 881 deletions(-) delete mode 100644 vendor/maunium.net/go/tcell/terminfo/terminfo.go (limited to 'vendor/maunium.net/go/tcell/terminfo/terminfo.go') 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 = ¶msBuffer{} - -// 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 -} -- cgit v1.2.3