mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-15 01:34:26 +02:00
Bump gocui
... and switch back from stefanhaller's tcell fork to the official tcell. This
basically reverts 7ccb871a45
.
This commit is contained in:
767
vendor/github.com/gdamore/tcell/v2/terminfo/terminfo.go
generated
vendored
Normal file
767
vendor/github.com/gdamore/tcell/v2/terminfo/terminfo.go
generated
vendored
Normal file
@ -0,0 +1,767 @@
|
||||
// Copyright 2022 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
Aliases []string
|
||||
Columns int // cols
|
||||
Lines int // lines
|
||||
Colors int // colors
|
||||
Bell string // bell
|
||||
Clear string // clear
|
||||
EnterCA string // smcup
|
||||
ExitCA string // rmcup
|
||||
ShowCursor string // cnorm
|
||||
HideCursor string // civis
|
||||
AttrOff string // sgr0
|
||||
Underline string // smul
|
||||
Bold string // bold
|
||||
Blink string // blink
|
||||
Reverse string // rev
|
||||
Dim string // dim
|
||||
Italic string // sitm
|
||||
EnterKeypad string // smkx
|
||||
ExitKeypad string // rmkx
|
||||
SetFg string // setaf
|
||||
SetBg string // setab
|
||||
ResetFgBg string // op
|
||||
SetCursor string // cup
|
||||
CursorBack1 string // cub1
|
||||
CursorUp1 string // cuu1
|
||||
PadChar string // pad
|
||||
KeyBackspace string // kbs
|
||||
KeyF1 string // kf1
|
||||
KeyF2 string // kf2
|
||||
KeyF3 string // kf3
|
||||
KeyF4 string // kf4
|
||||
KeyF5 string // kf5
|
||||
KeyF6 string // kf6
|
||||
KeyF7 string // kf7
|
||||
KeyF8 string // kf8
|
||||
KeyF9 string // kf9
|
||||
KeyF10 string // kf10
|
||||
KeyF11 string // kf11
|
||||
KeyF12 string // kf12
|
||||
KeyF13 string // kf13
|
||||
KeyF14 string // kf14
|
||||
KeyF15 string // kf15
|
||||
KeyF16 string // kf16
|
||||
KeyF17 string // kf17
|
||||
KeyF18 string // kf18
|
||||
KeyF19 string // kf19
|
||||
KeyF20 string // kf20
|
||||
KeyF21 string // kf21
|
||||
KeyF22 string // kf22
|
||||
KeyF23 string // kf23
|
||||
KeyF24 string // kf24
|
||||
KeyF25 string // kf25
|
||||
KeyF26 string // kf26
|
||||
KeyF27 string // kf27
|
||||
KeyF28 string // kf28
|
||||
KeyF29 string // kf29
|
||||
KeyF30 string // kf30
|
||||
KeyF31 string // kf31
|
||||
KeyF32 string // kf32
|
||||
KeyF33 string // kf33
|
||||
KeyF34 string // kf34
|
||||
KeyF35 string // kf35
|
||||
KeyF36 string // kf36
|
||||
KeyF37 string // kf37
|
||||
KeyF38 string // kf38
|
||||
KeyF39 string // kf39
|
||||
KeyF40 string // kf40
|
||||
KeyF41 string // kf41
|
||||
KeyF42 string // kf42
|
||||
KeyF43 string // kf43
|
||||
KeyF44 string // kf44
|
||||
KeyF45 string // kf45
|
||||
KeyF46 string // kf46
|
||||
KeyF47 string // kf47
|
||||
KeyF48 string // kf48
|
||||
KeyF49 string // kf49
|
||||
KeyF50 string // kf50
|
||||
KeyF51 string // kf51
|
||||
KeyF52 string // kf52
|
||||
KeyF53 string // kf53
|
||||
KeyF54 string // kf54
|
||||
KeyF55 string // kf55
|
||||
KeyF56 string // kf56
|
||||
KeyF57 string // kf57
|
||||
KeyF58 string // kf58
|
||||
KeyF59 string // kf59
|
||||
KeyF60 string // kf60
|
||||
KeyF61 string // kf61
|
||||
KeyF62 string // kf62
|
||||
KeyF63 string // kf63
|
||||
KeyF64 string // kf64
|
||||
KeyInsert string // kich1
|
||||
KeyDelete string // kdch1
|
||||
KeyHome string // khome
|
||||
KeyEnd string // kend
|
||||
KeyHelp string // khlp
|
||||
KeyPgUp string // kpp
|
||||
KeyPgDn string // knp
|
||||
KeyUp string // kcuu1
|
||||
KeyDown string // kcud1
|
||||
KeyLeft string // kcub1
|
||||
KeyRight string // kcuf1
|
||||
KeyBacktab string // kcbt
|
||||
KeyExit string // kext
|
||||
KeyClear string // kclr
|
||||
KeyPrint string // kprt
|
||||
KeyCancel string // kcan
|
||||
Mouse string // kmous
|
||||
AltChars string // acsc
|
||||
EnterAcs string // smacs
|
||||
ExitAcs string // rmacs
|
||||
EnableAcs string // enacs
|
||||
KeyShfRight string // kRIT
|
||||
KeyShfLeft string // kLFT
|
||||
KeyShfHome string // kHOM
|
||||
KeyShfEnd string // kEND
|
||||
KeyShfInsert string // kIC
|
||||
KeyShfDelete string // kDC
|
||||
|
||||
// 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.
|
||||
|
||||
StrikeThrough string // smxx
|
||||
SetFgBg string // setfgbg
|
||||
SetFgBgRGB string // setfgbgrgb
|
||||
SetFgRGB string // setfrgb
|
||||
SetBgRGB string // setbrgb
|
||||
KeyShfUp string // shift-up
|
||||
KeyShfDown string // shift-down
|
||||
KeyShfPgUp string // shift-kpp
|
||||
KeyShfPgDn string // shift-knp
|
||||
KeyCtrlUp string // ctrl-up
|
||||
KeyCtrlDown string // ctrl-left
|
||||
KeyCtrlRight string // ctrl-right
|
||||
KeyCtrlLeft string // ctrl-left
|
||||
KeyMetaUp string // meta-up
|
||||
KeyMetaDown string // meta-left
|
||||
KeyMetaRight string // meta-right
|
||||
KeyMetaLeft string // meta-left
|
||||
KeyAltUp string // alt-up
|
||||
KeyAltDown string // alt-left
|
||||
KeyAltRight string // alt-right
|
||||
KeyAltLeft string // alt-left
|
||||
KeyCtrlHome string
|
||||
KeyCtrlEnd string
|
||||
KeyMetaHome string
|
||||
KeyMetaEnd string
|
||||
KeyAltHome string
|
||||
KeyAltEnd string
|
||||
KeyAltShfUp string
|
||||
KeyAltShfDown string
|
||||
KeyAltShfLeft string
|
||||
KeyAltShfRight string
|
||||
KeyMetaShfUp string
|
||||
KeyMetaShfDown string
|
||||
KeyMetaShfLeft string
|
||||
KeyMetaShfRight string
|
||||
KeyCtrlShfUp string
|
||||
KeyCtrlShfDown string
|
||||
KeyCtrlShfLeft string
|
||||
KeyCtrlShfRight string
|
||||
KeyCtrlShfHome string
|
||||
KeyCtrlShfEnd string
|
||||
KeyAltShfHome string
|
||||
KeyAltShfEnd string
|
||||
KeyMetaShfHome string
|
||||
KeyMetaShfEnd string
|
||||
EnablePaste string // bracketed paste mode
|
||||
DisablePaste string
|
||||
PasteStart string
|
||||
PasteEnd string
|
||||
Modifiers int
|
||||
InsertChar string // string to insert a character (ich1)
|
||||
AutoMargin bool // true if writing to last cell in line advances
|
||||
TrueColor bool // true if the terminal supports direct color
|
||||
CursorDefault string
|
||||
CursorBlinkingBlock string
|
||||
CursorSteadyBlock string
|
||||
CursorBlinkingUnderline string
|
||||
CursorSteadyUnderline string
|
||||
CursorBlinkingBar string
|
||||
CursorSteadyBar string
|
||||
EnterUrl string
|
||||
ExitUrl string
|
||||
SetWindowSize string
|
||||
EnableFocusReporting string
|
||||
DisableFocusReporting string
|
||||
}
|
||||
|
||||
const (
|
||||
ModifiersNone = 0
|
||||
ModifiersXTerm = 1
|
||||
)
|
||||
|
||||
type stack []interface{}
|
||||
|
||||
func (st stack) Push(v interface{}) stack {
|
||||
if b, ok := v.(bool); ok {
|
||||
if b {
|
||||
return append(st, 1)
|
||||
} else {
|
||||
return append(st, 0)
|
||||
}
|
||||
}
|
||||
return append(st, v)
|
||||
}
|
||||
|
||||
func (st stack) PopString() (string, stack) {
|
||||
if len(st) > 0 {
|
||||
e := st[len(st)-1]
|
||||
var s string
|
||||
switch v := e.(type) {
|
||||
case int:
|
||||
s = strconv.Itoa(v)
|
||||
case string:
|
||||
s = v
|
||||
}
|
||||
return s, st[:len(st)-1]
|
||||
}
|
||||
return "", st
|
||||
|
||||
}
|
||||
func (st stack) PopInt() (int, stack) {
|
||||
if len(st) > 0 {
|
||||
e := st[len(st)-1]
|
||||
var i int
|
||||
switch v := e.(type) {
|
||||
case int:
|
||||
i = v
|
||||
case string:
|
||||
i, _ = strconv.Atoi(v)
|
||||
}
|
||||
return i, st[:len(st)-1]
|
||||
}
|
||||
return 0, st
|
||||
}
|
||||
|
||||
// static vars
|
||||
var svars [26]string
|
||||
|
||||
type paramsBuffer struct {
|
||||
out bytes.Buffer
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
// 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.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()
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 ...interface{}) string {
|
||||
var stk stack
|
||||
var a string
|
||||
var ai, bi int
|
||||
var dvars [26]string
|
||||
var params [9]interface{}
|
||||
var pb = ¶msBuffer{}
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
const (
|
||||
emit = iota
|
||||
toEnd
|
||||
toElse
|
||||
)
|
||||
|
||||
skip := emit
|
||||
|
||||
for {
|
||||
|
||||
ch, err := pb.NextCh()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if ch != '%' {
|
||||
if skip == emit {
|
||||
pb.PutCh(ch)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
ch, err = pb.NextCh()
|
||||
if err != nil {
|
||||
// XXX Error
|
||||
break
|
||||
}
|
||||
if skip == toEnd {
|
||||
if ch == ';' {
|
||||
skip = emit
|
||||
}
|
||||
continue
|
||||
} else if skip == toElse {
|
||||
if ch == 'e' || ch == ';' {
|
||||
skip = emit
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch ch {
|
||||
case '%': // quoted %
|
||||
pb.PutCh(ch)
|
||||
|
||||
case 'i': // increment both parameters (ANSI cup support)
|
||||
if i, ok := params[0].(int); ok {
|
||||
params[0] = i + 1
|
||||
}
|
||||
if i, ok := params[1].(int); ok {
|
||||
params[1] = i + 1
|
||||
}
|
||||
|
||||
case 's':
|
||||
// NB: 's', 'c', and 'd' below are special cased for
|
||||
// efficiency. They could be handled by the richer
|
||||
// format support below, less efficiently.
|
||||
a, stk = stk.PopString()
|
||||
pb.PutString(a)
|
||||
|
||||
case 'c':
|
||||
// Integer as special character.
|
||||
ai, stk = stk.PopInt()
|
||||
pb.PutCh(byte(ai))
|
||||
|
||||
case 'd':
|
||||
ai, stk = stk.PopInt()
|
||||
pb.PutString(strconv.Itoa(ai))
|
||||
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '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 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 's':
|
||||
a, stk = stk.PopString()
|
||||
pb.PutString(fmt.Sprintf(f, a))
|
||||
case 'c':
|
||||
ai, stk = stk.PopInt()
|
||||
pb.PutString(fmt.Sprintf(f, ai))
|
||||
}
|
||||
|
||||
case 'p': // push parameter
|
||||
ch, _ = pb.NextCh()
|
||||
ai = int(ch - '1')
|
||||
if ai >= 0 && ai < len(params) {
|
||||
stk = stk.Push(params[ai])
|
||||
} else {
|
||||
stk = stk.Push(0)
|
||||
}
|
||||
|
||||
case 'P': // pop & store variable
|
||||
ch, _ = pb.NextCh()
|
||||
if ch >= 'A' && ch <= 'Z' {
|
||||
svars[int(ch-'A')], stk = stk.PopString()
|
||||
} else if ch >= 'a' && ch <= 'z' {
|
||||
dvars[int(ch-'a')], stk = stk.PopString()
|
||||
}
|
||||
|
||||
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) - the integer value of it
|
||||
ch, _ = pb.NextCh()
|
||||
_, _ = pb.NextCh() // must be ' but we don't check
|
||||
stk = stk.Push(int(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.Push(ai)
|
||||
|
||||
case 'l': // push(strlen(pop))
|
||||
a, stk = stk.PopString()
|
||||
stk = stk.Push(len(a))
|
||||
|
||||
case '+':
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai + bi)
|
||||
|
||||
case '-':
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai - bi)
|
||||
|
||||
case '*':
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai * bi)
|
||||
|
||||
case '/':
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
if bi != 0 {
|
||||
stk = stk.Push(ai / bi)
|
||||
} else {
|
||||
stk = stk.Push(0)
|
||||
}
|
||||
|
||||
case 'm': // push(pop mod pop)
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
if bi != 0 {
|
||||
stk = stk.Push(ai % bi)
|
||||
} else {
|
||||
stk = stk.Push(0)
|
||||
}
|
||||
|
||||
case '&': // AND
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai & bi)
|
||||
|
||||
case '|': // OR
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai | bi)
|
||||
|
||||
case '^': // XOR
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai ^ bi)
|
||||
|
||||
case '~': // bit complement
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai ^ -1)
|
||||
|
||||
case '!': // logical NOT
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai == 0)
|
||||
|
||||
case '=': // numeric compare
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai == bi)
|
||||
|
||||
case '>': // greater than, numeric
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai > bi)
|
||||
|
||||
case '<': // less than, numeric
|
||||
bi, stk = stk.PopInt()
|
||||
ai, stk = stk.PopInt()
|
||||
stk = stk.Push(ai < bi)
|
||||
|
||||
case '?': // start conditional
|
||||
|
||||
case ';':
|
||||
skip = emit
|
||||
|
||||
case 't':
|
||||
ai, stk = stk.PopInt()
|
||||
if ai == 0 {
|
||||
skip = toElse
|
||||
}
|
||||
|
||||
case 'e':
|
||||
skip = toEnd
|
||||
|
||||
default:
|
||||
pb.PutString("%" + string(ch))
|
||||
}
|
||||
}
|
||||
|
||||
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 time (unless the terminfo string indicates this isn't needed
|
||||
// by specifying npc - no padding). All Terminfo based strings should be
|
||||
// emitted using this function.
|
||||
func (t *Terminfo) TPuts(w io.Writer, s string) {
|
||||
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 := time.Millisecond
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// Curses historically uses padding to achieve "fine grained"
|
||||
// delays. We have much better clocks these days, and so we
|
||||
// do not rely on padding but simply sleep a bit.
|
||||
if len(t.PadChar) > 0 {
|
||||
time.Sleep(unit * time.Duration(padus))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
)
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// LookupTerminfo attempts to find a definition for the named $TERM.
|
||||
func LookupTerminfo(name string) (*Terminfo, error) {
|
||||
if name == "" {
|
||||
// else on windows: index out of bounds
|
||||
// on the name[0] reference below
|
||||
return nil, ErrTermNotFound
|
||||
}
|
||||
|
||||
addtruecolor := false
|
||||
add256color := false
|
||||
switch os.Getenv("COLORTERM") {
|
||||
case "truecolor", "24bit", "24-bit":
|
||||
addtruecolor = true
|
||||
}
|
||||
dblock.Lock()
|
||||
t := terminfos[name]
|
||||
dblock.Unlock()
|
||||
|
||||
// If the name ends in -truecolor, then fabricate an entry
|
||||
// from the corresponding -256color, -color, or bare terminal.
|
||||
if t != nil && t.TrueColor {
|
||||
addtruecolor = true
|
||||
} else if t == nil && strings.HasSuffix(name, "-truecolor") {
|
||||
|
||||
suffixes := []string{
|
||||
"-256color",
|
||||
"-88color",
|
||||
"-color",
|
||||
"",
|
||||
}
|
||||
base := name[:len(name)-len("-truecolor")]
|
||||
for _, s := range suffixes {
|
||||
if t, _ = LookupTerminfo(base + s); t != nil {
|
||||
addtruecolor = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the name ends in -256color, maybe fabricate using the xterm 256 color sequences
|
||||
if t == nil && strings.HasSuffix(name, "-256color") {
|
||||
suffixes := []string{
|
||||
"-88color",
|
||||
"-color",
|
||||
}
|
||||
base := name[:len(name)-len("-256color")]
|
||||
for _, s := range suffixes {
|
||||
if t, _ = LookupTerminfo(base + s); t != nil {
|
||||
add256color = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if t == nil {
|
||||
return nil, ErrTermNotFound
|
||||
}
|
||||
|
||||
switch os.Getenv("TCELL_TRUECOLOR") {
|
||||
case "":
|
||||
case "disable":
|
||||
addtruecolor = false
|
||||
default:
|
||||
addtruecolor = true
|
||||
}
|
||||
|
||||
// If the user has requested 24-bit color with $COLORTERM, then
|
||||
// amend the value (unless already present). This means we don't
|
||||
// need to have a value present.
|
||||
if addtruecolor &&
|
||||
t.SetFgBgRGB == "" &&
|
||||
t.SetFgRGB == "" &&
|
||||
t.SetBgRGB == "" {
|
||||
|
||||
// Supply vanilla ISO 8613-6:1994 24-bit color sequences.
|
||||
t.SetFgRGB = "\x1b[38;2;%p1%d;%p2%d;%p3%dm"
|
||||
t.SetBgRGB = "\x1b[48;2;%p1%d;%p2%d;%p3%dm"
|
||||
t.SetFgBgRGB = "\x1b[38;2;%p1%d;%p2%d;%p3%d;" +
|
||||
"48;2;%p4%d;%p5%d;%p6%dm"
|
||||
}
|
||||
|
||||
if add256color {
|
||||
t.Colors = 256
|
||||
t.SetFg = "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"
|
||||
t.SetBg = "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m"
|
||||
t.SetFgBg = "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;;%?%p2%{8}%<%t4%p2%d%e%p2%{16}%<%t10%p2%{8}%-%d%e48;5;%p2%d%;m"
|
||||
t.ResetFgBg = "\x1b[39;49m"
|
||||
}
|
||||
return t, nil
|
||||
}
|
Reference in New Issue
Block a user