diff --git a/go.mod b/go.mod index 37b26b83f..615155332 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/cli/go-gh/v2 v2.13.0 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/creack/pty v1.1.24 - github.com/gdamore/tcell/v2 v2.13.8 + github.com/gdamore/tcell/v3 v3.3.0 github.com/go-errors/errors v1.5.1 github.com/gookit/color v1.6.0 github.com/integrii/flaggy v1.8.0 @@ -47,6 +47,8 @@ require ( github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.2 // indirect github.com/cli/safeexec v1.0.1 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.9.0 // indirect github.com/gdamore/encoding v1.0.1 // indirect @@ -67,7 +69,7 @@ require ( github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect golang.org/x/net v0.47.0 // indirect - golang.org/x/term v0.41.0 // indirect + golang.org/x/term v0.42.0 // indirect golang.org/x/text v0.36.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect diff --git a/go.sum b/go.sum index e108704c1..8ac21030f 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,10 @@ github.com/cli/go-gh/v2 v2.13.0 h1:jEHZu/VPVoIJkciK3pzZd3rbT8J90swsK5Ui4ewH1ys= github.com/cli/go-gh/v2 v2.13.0/go.mod h1:Us/NbQ8VNM0fdaILgoXSz6PKkV5PWaEzkJdc9vR2geM= github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -29,8 +33,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= -github.com/gdamore/tcell/v2 v2.13.8 h1:Mys/Kl5wfC/GcC5Cx4C2BIQH9dbnhnkPgS9/wF3RlfU= -github.com/gdamore/tcell/v2 v2.13.8/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= +github.com/gdamore/tcell/v3 v3.3.0 h1:lGo3VwiV8iYMH4TdwBDwEOoDctnOLns6QfrXvZkKNe8= +github.com/gdamore/tcell/v3 v3.3.0/go.mod h1:8CJpEjUiAlFIrs7jUhzobiZsSLBAtXo8Dq9mCTrVnqo= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -163,8 +167,8 @@ golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/pkg/config/keynames.go b/pkg/config/keynames.go index d1fda527c..075e8006e 100644 --- a/pkg/config/keynames.go +++ b/pkg/config/keynames.go @@ -42,8 +42,6 @@ var LabelByKey = map[gocui.KeyName]string{ gocui.KeyAltEnter: "", gocui.KeyEsc: "", // , gocui.KeyBackspace: "", // - gocui.KeyCtrlSpace: "", // , - gocui.KeyCtrlSlash: "", // gocui.KeySpace: "", gocui.KeyCtrlA: "", gocui.KeyCtrlB: "", @@ -68,9 +66,6 @@ var LabelByKey = map[gocui.KeyName]string{ gocui.KeyCtrlX: "", gocui.KeyCtrlY: "", gocui.KeyCtrlZ: "", - gocui.KeyCtrl4: "", // - gocui.KeyCtrl5: "", // - gocui.KeyCtrl6: "", gocui.KeyCtrl8: "", gocui.MouseWheelUp: "mouse wheel up", gocui.MouseWheelDown: "mouse wheel down", diff --git a/pkg/gocui/attribute.go b/pkg/gocui/attribute.go index b6cbf39d0..bfa4ad854 100644 --- a/pkg/gocui/attribute.go +++ b/pkg/gocui/attribute.go @@ -4,7 +4,7 @@ package gocui -import "github.com/gdamore/tcell/v2" +import "github.com/gdamore/tcell/v3" // Attribute affects the presentation of characters, such as color, boldness, etc. type Attribute uint64 diff --git a/pkg/gocui/edit.go b/pkg/gocui/edit.go index d941cd477..a11993a48 100644 --- a/pkg/gocui/edit.go +++ b/pkg/gocui/edit.go @@ -62,8 +62,8 @@ func SimpleEditor(v *View, key Key, mod Modifier) bool { v.TextArea.BackSpaceWord() case key.KeyName() == KeyCtrlY: v.TextArea.Yank() - case key.Ch() != 0: - v.TextArea.TypeCharacter(string(key.Ch())) + case key.Str() != "": + v.TextArea.TypeCharacter(key.Str()) default: return false } diff --git a/pkg/gocui/gui.go b/pkg/gocui/gui.go index 7b3d4dd7c..e4320231e 100644 --- a/pkg/gocui/gui.go +++ b/pkg/gocui/gui.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v3" "github.com/go-errors/errors" "github.com/rivo/uniseg" ) @@ -558,7 +558,7 @@ func (g *Gui) SetKeybinding(viewname string, key Key, mod Modifier, handler func // DeleteKeybinding deletes a keybinding. func (g *Gui) DeleteKeybinding(viewname string, key Key, mod Modifier) error { for i, kb := range g.keybindings { - if kb.viewName == viewname && kb.key.keyName == key.KeyName() && kb.key.ch == key.ch && kb.mod == mod { + if kb.viewName == viewname && kb.key.keyName == key.KeyName() && kb.key.str == key.str && kb.mod == mod { g.keybindings = append(g.keybindings[:i], g.keybindings[i+1:]...) return nil } @@ -1595,7 +1595,7 @@ func (g *Gui) matchView(v *View, kb *keybinding) bool { if v == nil { return false } - if v.Editable && kb.key.ch != 0 { + if v.Editable && kb.key.Str() != "" { return false } if kb.viewName != v.name { diff --git a/pkg/gocui/key.go b/pkg/gocui/key.go index f5e787a22..2a2091696 100644 --- a/pkg/gocui/key.go +++ b/pkg/gocui/key.go @@ -4,31 +4,31 @@ package gocui -import "github.com/gdamore/tcell/v2" +import "github.com/gdamore/tcell/v3" type Key struct { keyName KeyName - ch rune + str string } -func NewKey(keyName KeyName, ch rune) Key { +func NewKey(keyName KeyName, str string) Key { return Key{ keyName: keyName, - ch: ch, + str: str, } } func NewKeyName(keyName KeyName) Key { return Key{ keyName: keyName, - ch: 0, + str: "", } } func NewKeyRune(ch rune) Key { return Key{ keyName: KeyName(tcell.KeyRune), - ch: ch, + str: string(ch), } } @@ -36,8 +36,8 @@ func (k Key) KeyName() KeyName { return k.keyName } -func (k Key) Ch() rune { - return k.ch +func (k Key) Str() string { + return k.str } func (k Key) IsSet() bool { @@ -45,5 +45,5 @@ func (k Key) IsSet() bool { } func (k Key) Equals(otherKey Key) bool { - return k.keyName == otherKey.keyName && k.ch == otherKey.ch + return k.keyName == otherKey.keyName && k.str == otherKey.str } diff --git a/pkg/gocui/keybinding.go b/pkg/gocui/keybinding.go index e05f7ce08..cdd2f0c0a 100644 --- a/pkg/gocui/keybinding.go +++ b/pkg/gocui/keybinding.go @@ -5,7 +5,7 @@ package gocui import ( - "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v3" ) // KeyName represents special keys or keys combinations. @@ -69,67 +69,55 @@ const ( // Keys combinations. const ( - KeyCtrlTilde = KeyName(tcell.KeyF64) // arbitrary assignment - KeyCtrlSpace = KeyName(tcell.KeyCtrlSpace) - KeyCtrlA = KeyName(tcell.KeyCtrlA) - KeyCtrlB = KeyName(tcell.KeyCtrlB) - KeyCtrlC = KeyName(tcell.KeyCtrlC) - KeyCtrlD = KeyName(tcell.KeyCtrlD) - KeyCtrlE = KeyName(tcell.KeyCtrlE) - KeyCtrlF = KeyName(tcell.KeyCtrlF) - KeyCtrlG = KeyName(tcell.KeyCtrlG) - KeyBackspace = KeyName(tcell.KeyBackspace) - KeyCtrlH = KeyName(tcell.KeyCtrlH) - KeyTab = KeyName(tcell.KeyTab) - KeyBacktab = KeyName(tcell.KeyBacktab) - KeyCtrlI = KeyName(tcell.KeyCtrlI) - KeyCtrlJ = KeyName(tcell.KeyCtrlJ) - KeyCtrlK = KeyName(tcell.KeyCtrlK) - KeyCtrlL = KeyName(tcell.KeyCtrlL) - KeyEnter = KeyName(tcell.KeyEnter) - KeyCtrlM = KeyName(tcell.KeyCtrlM) - KeyCtrlN = KeyName(tcell.KeyCtrlN) - KeyCtrlO = KeyName(tcell.KeyCtrlO) - KeyCtrlP = KeyName(tcell.KeyCtrlP) - KeyCtrlQ = KeyName(tcell.KeyCtrlQ) - KeyCtrlR = KeyName(tcell.KeyCtrlR) - KeyCtrlS = KeyName(tcell.KeyCtrlS) - KeyCtrlT = KeyName(tcell.KeyCtrlT) - KeyCtrlU = KeyName(tcell.KeyCtrlU) - KeyCtrlV = KeyName(tcell.KeyCtrlV) - KeyCtrlW = KeyName(tcell.KeyCtrlW) - KeyCtrlX = KeyName(tcell.KeyCtrlX) - KeyCtrlY = KeyName(tcell.KeyCtrlY) - KeyCtrlZ = KeyName(tcell.KeyCtrlZ) - KeyEsc = KeyName(tcell.KeyEscape) - KeyCtrlUnderscore = KeyName(tcell.KeyCtrlUnderscore) - KeySpace = KeyName(32) - KeyBackspace2 = KeyName(tcell.KeyBackspace2) - KeyCtrl8 = KeyName(tcell.KeyBackspace2) // same key as in termbox-go + KeyCtrlTilde = KeyName(tcell.KeyF64) // arbitrary assignment + KeyCtrlA = KeyName(tcell.KeyCtrlA) + KeyCtrlB = KeyName(tcell.KeyCtrlB) + KeyCtrlC = KeyName(tcell.KeyCtrlC) + KeyCtrlD = KeyName(tcell.KeyCtrlD) + KeyCtrlE = KeyName(tcell.KeyCtrlE) + KeyCtrlF = KeyName(tcell.KeyCtrlF) + KeyCtrlG = KeyName(tcell.KeyCtrlG) + KeyBackspace = KeyName(tcell.KeyBackspace) + KeyCtrlH = KeyName(tcell.KeyCtrlH) + KeyTab = KeyName(tcell.KeyTab) + KeyBacktab = KeyName(tcell.KeyBacktab) + KeyCtrlI = KeyName(tcell.KeyCtrlI) + KeyCtrlJ = KeyName(tcell.KeyCtrlJ) + KeyCtrlK = KeyName(tcell.KeyCtrlK) + KeyCtrlL = KeyName(tcell.KeyCtrlL) + KeyEnter = KeyName(tcell.KeyEnter) + KeyCtrlM = KeyName(tcell.KeyCtrlM) + KeyCtrlN = KeyName(tcell.KeyCtrlN) + KeyCtrlO = KeyName(tcell.KeyCtrlO) + KeyCtrlP = KeyName(tcell.KeyCtrlP) + KeyCtrlQ = KeyName(tcell.KeyCtrlQ) + KeyCtrlR = KeyName(tcell.KeyCtrlR) + KeyCtrlS = KeyName(tcell.KeyCtrlS) + KeyCtrlT = KeyName(tcell.KeyCtrlT) + KeyCtrlU = KeyName(tcell.KeyCtrlU) + KeyCtrlV = KeyName(tcell.KeyCtrlV) + KeyCtrlW = KeyName(tcell.KeyCtrlW) + KeyCtrlX = KeyName(tcell.KeyCtrlX) + KeyCtrlY = KeyName(tcell.KeyCtrlY) + KeyCtrlZ = KeyName(tcell.KeyCtrlZ) + KeyEsc = KeyName(tcell.KeyEscape) + KeySpace = KeyName(32) + KeyBackspace2 = KeyName(tcell.KeyBackspace2) + KeyCtrl8 = KeyName(tcell.KeyBackspace2) // same key as in termbox-go // The following assignments were used in termbox implementation. // In tcell, these are not keys per se. But in gocui we have them // mapped to the keys so we have to use placeholder keys. - KeyAltEnter = KeyName(tcell.KeyF64) // arbitrary assignments - MouseLeft = KeyName(tcell.KeyF63) - MouseRight = KeyName(tcell.KeyF62) - MouseMiddle = KeyName(tcell.KeyF61) - MouseRelease = KeyName(tcell.KeyF60) - MouseWheelUp = KeyName(tcell.KeyF59) - MouseWheelDown = KeyName(tcell.KeyF58) - MouseWheelLeft = KeyName(tcell.KeyF57) - MouseWheelRight = KeyName(tcell.KeyF56) - KeyCtrl2 = KeyName(tcell.KeyNUL) // termbox defines theses - KeyCtrl3 = KeyName(tcell.KeyEscape) - KeyCtrl4 = KeyName(tcell.KeyCtrlBackslash) - KeyCtrl5 = KeyName(tcell.KeyCtrlRightSq) - KeyCtrl6 = KeyName(tcell.KeyCtrlCarat) - KeyCtrl7 = KeyName(tcell.KeyCtrlUnderscore) - KeyCtrlSlash = KeyName(tcell.KeyCtrlUnderscore) - KeyCtrlRsqBracket = KeyName(tcell.KeyCtrlRightSq) - KeyCtrlBackslash = KeyName(tcell.KeyCtrlBackslash) - KeyCtrlLsqBracket = KeyName(tcell.KeyCtrlLeftSq) + KeyAltEnter = KeyName(tcell.KeyF64) // arbitrary assignments + MouseLeft = KeyName(tcell.KeyF63) + MouseRight = KeyName(tcell.KeyF62) + MouseMiddle = KeyName(tcell.KeyF61) + MouseRelease = KeyName(tcell.KeyF60) + MouseWheelUp = KeyName(tcell.KeyF59) + MouseWheelDown = KeyName(tcell.KeyF58) + MouseWheelLeft = KeyName(tcell.KeyF57) + MouseWheelRight = KeyName(tcell.KeyF56) ) // Modifiers. diff --git a/pkg/gocui/tcell_driver.go b/pkg/gocui/tcell_driver.go index 333e7b9e9..2e5278a37 100644 --- a/pkg/gocui/tcell_driver.go +++ b/pkg/gocui/tcell_driver.go @@ -5,7 +5,8 @@ package gocui import ( - "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v3" + "github.com/gdamore/tcell/v3/vt" ) // We probably don't want this being a global variable for YOLO for now @@ -83,16 +84,17 @@ func registerRuneFallbacks(s tcell.Screen, additional map[rune]string) { // tcellInitSimulation initializes tcell screen for use. func (g *Gui) tcellInitSimulation(width int, height int) error { - s := tcell.NewSimulationScreen("") - if e := s.Init(); e != nil { + mt := vt.NewMockTerm(vt.MockOptSize{X: vt.Col(width), Y: vt.Row(height)}) + s, e := tcell.NewTerminfoScreenFromTty(mt) + if e != nil { + return e + } + if e = s.Init(); e != nil { return e } g.screen = s Screen = s - // setting to a larger value than the typical terminal size - // so that during a test we're more likely to see an item to select in a view. - s.SetSize(width, height) s.Sync() return nil } @@ -206,7 +208,7 @@ type TcellKeyEventWrapper struct { Timestamp int64 Mod tcell.ModMask Key tcell.Key - Ch rune + Ch string } func NewTcellKeyEventWrapper(event *tcell.EventKey, timestamp int64) *TcellKeyEventWrapper { @@ -214,7 +216,7 @@ func NewTcellKeyEventWrapper(event *tcell.EventKey, timestamp int64) *TcellKeyEv Timestamp: timestamp, Mod: event.Modifiers(), Key: event.Key(), - Ch: event.Rune(), + Ch: event.Str(), } } @@ -278,7 +280,7 @@ func (g *Gui) pollEvent() GocuiEvent { tev = (ev).toTcellEvent() } } else { - tev = Screen.PollEvent() + tev = <-Screen.EventQ() } switch tev := tev.(type) { @@ -289,28 +291,27 @@ func (g *Gui) pollEvent() GocuiEvent { return GocuiEvent{Type: eventResize, Width: w, Height: h} case *tcell.EventKey: k := tev.Key() - ch := rune(0) + ch := "" if k == tcell.KeyRune { - ch = tev.Rune() - if ch == ' ' { + ch = tev.Str() + if ch == " " { // special handling for spacebar k = tcell.Key(KeySpace) - ch = rune(0) + ch = "" } } mod := tev.Modifiers() // remove control modifier and setup special handling of ctrl+spacebar, etc. if mod == tcell.ModCtrl && k == 32 { - mod = 0 - ch = rune(0) - k = tcell.KeyCtrlSpace + ch = " " + k = tcell.KeyRune } else if mod == tcell.ModShift && k == tcell.KeyUp { mod = 0 - ch = rune(0) + ch = "" k = tcell.KeyF62 } else if mod == tcell.ModShift && k == tcell.KeyDown { mod = 0 - ch = rune(0) + ch = "" k = tcell.KeyF63 } else if mod == tcell.ModCtrl || mod == tcell.ModShift { // remove Ctrl or Shift if specified diff --git a/pkg/gocui/view.go b/pkg/gocui/view.go index 697ca2029..166cb0e2c 100644 --- a/pkg/gocui/view.go +++ b/pkg/gocui/view.go @@ -12,7 +12,7 @@ import ( "unicode" "unicode/utf8" - "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v3" "github.com/rivo/uniseg" ) diff --git a/pkg/gui/gui_driver.go b/pkg/gui/gui_driver.go index 01d4c99a7..18f59152b 100644 --- a/pkg/gui/gui_driver.go +++ b/pkg/gui/gui_driver.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v3" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gocui" @@ -32,7 +32,7 @@ func (self *GuiDriver) PressKey(keyStr string) { key := keybindings.GetKey(keyStr) self.gui.g.ReplayedEvents.Keys <- gocui.NewTcellKeyEventWrapper( - tcell.NewEventKey(tcell.Key(key.KeyName()), key.Ch(), tcell.ModNone), + tcell.NewEventKey(tcell.Key(key.KeyName()), key.Str(), tcell.ModNone), 0, ) diff --git a/pkg/gui/keybindings/keybindings.go b/pkg/gui/keybindings/keybindings.go index 4bd2f4e75..4b67e23fe 100644 --- a/pkg/gui/keybindings/keybindings.go +++ b/pkg/gui/keybindings/keybindings.go @@ -5,7 +5,7 @@ import ( "strings" "unicode/utf8" - "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v3" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/constants" "github.com/jesseduffield/lazygit/pkg/gocui" @@ -17,7 +17,7 @@ func LabelFromKey(key gocui.Key) string { } if key.KeyName() == gocui.KeyName(tcell.KeyRune) { - return string(key.Ch()) + return key.Str() } value, ok := config.LabelByKey[key.KeyName()] diff --git a/vendor/github.com/clipperhouse/displaywidth/.gitignore b/vendor/github.com/clipperhouse/displaywidth/.gitignore new file mode 100644 index 000000000..b356d43c6 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*.out +*.test diff --git a/vendor/github.com/clipperhouse/displaywidth/AGENTS.md b/vendor/github.com/clipperhouse/displaywidth/AGENTS.md new file mode 100644 index 000000000..9ae951b25 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/AGENTS.md @@ -0,0 +1,51 @@ +The goals and overview of this package can be found in the README.md file, +start by reading that. + +The goal of this package is to determine the display (column) width of a +string, UTF-8 bytes, or runes, as would happen in a monospace font, especially +in a terminal. + +When troubleshooting, write Go unit tests instead of executing debug scripts. +The tests can return whatever logs or output you need. If those tests are +only for temporary troubleshooting, clean up the tests after the debugging is +done. + +(Separate executable debugging scripts are messy, tend to have conflicting +dependencies and are hard to cleanup.) + +If you make changes to the trie generation in internal/gen, it can be invoked +by running `go generate` from the top package directory. + +## Pull Requests and branches + +For PRs (pull requests), you can use the gh CLI tool. Compare the current branch with main. Reviewing a PR and reviewing a branch are about the same, but the PR may add context. + +Understand the goals of the PR. Note any API changes, especially breaking changes. + +Look for thoroughness of tests, as well as GoDoc comments. + +Retrieve and consider the comments on the PR, which may have come from GitHub Copilot or Cursor BugBot. Think like GitHub Copilot or Cursor BugBot. + +Offer to optionally post a brief summary of the review to the PR, via the gh CLI tool. + +## Tagged Go releases + +If I ask you whether we are ready to release, this means a tagged Go release on the main branch. Go releases are git tagged with a version number. + +Review the changes since the last release, i.e. the previous git tag. Ensure that the changes are complete and correct. Identify new features, bug fixes, and performance improvements. + +Identify breaking changes, especially API changes. + +Ensure good test coverage. Look for performance changes, especially performance regressions, by running benchmarks against the previous release. + +Ensure that the documentation in READMEs and GoDocs are complete, correct and consistent. + +## Comparisons to go-runewidth + +We originally attempted to make this package compatible with go-runewidth. +However, we found that there were too many differences in the handling of +certain characters and properties. + +We believe, preliminarily, that our choices are more correct and complete, +by using more complete categories such as Unicode Cf (format) for zero-width +and Mn (Nonspacing_Mark) for combining marks. diff --git a/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md b/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md new file mode 100644 index 000000000..8c6efc10d --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md @@ -0,0 +1,129 @@ +# Changelog + +## [0.11.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.10.0...v0.11.0) + +### Added +- New `ControlSequences8Bit` option to treat 8-bit ECMA-48 (C1) escape sequences as zero-width. (#22) + +### Changed +- Upgraded uax29 dependency to v2.7.0 for 8-bit escape sequence support in the grapheme iterator. +- Truncation now validates that preserved trailing escape sequences are zero-width, preventing edge cases where non-zero-width sequences could leak into output. + +### Note +- `ControlSequences8Bit` is deliberately ignored by `TruncateString` and `TruncateBytes`, because C1 byte values (0x80–0x9F) overlap with UTF-8 multi-byte encoding. + +## [0.10.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.9.0...v0.10.0) + +### Added +- New `ControlSequences` option to treat ECMA-48/ANSI escape sequences as zero-width. (#20) +- `TruncateString` and `TruncateBytes` now preserve trailing ANSI escape sequences (such as SGR resets) when `ControlSequences` is true, preventing color bleed in terminal output. + +### Changed +- Removed `stringish` dependency; generic type constraints are now inline `~string | []byte`. +- Upgraded uax29 dependency to v2.6.0 for ANSI escape sequence support in the grapheme iterator. + +## [0.9.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.8.0...v0.9.0) + +### Changed +- Unicode 17 support: East Asian Width and emoji data updated to Unicode 17.0.0. (#18) +- Upgraded uax29 dependency to v2.5.0 (Unicode 17 grapheme segmentation). + +## [0.8.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.7.0...v0.8.0) + +### Changed +- Performance: ASCII fast path that applies to any run of printable + ASCII. 2x-10x faster for ASCII text vs v0.7.0. (#16) +- Upgraded uax29 dependency to v2.4.0 for Unicode 16 support. Text that includes + Indic_Conjunct_Break may segment differently (and more correctly). (#15) + +## [0.7.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.2...v0.7.0) + +### Added +- New `TruncateString` and `TruncateBytes` methods to truncate strings to a + maximum display width, with optional tail (like an ellipsis). (#13) + +## [0.6.2] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.1...v0.6.2) + +### Changed +- Internal: reduced property categories for simpler trie. + +## [0.6.1] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.0...v0.6.1) + +### Changed +- Perf improvements: replaced the ASCII lookup table with a simple + function. A bit more cache-friendly. More inlining. +- Bug fix: single regional indicators are now treated as width 2, since that + is what actual terminals do. + +## [0.6.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.5.0...v0.6.0) + +### Added +- New `StringGraphemes` and `BytesGraphemes` methods, for iterating over the +widths of grapheme clusters. + +### Changed +- Fast ASCII lookups + +## [0.5.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.4.1...v0.5.0) + +### Added +- Unicode 16 support +- Improved emoji presentation handling per Unicode TR51 + +### Changed +- Corrected VS15 (U+FE0E) handling: now preserves base character width (no-op) per Unicode TR51 +- Performance optimizations: reduced property lookups + +### Fixed +- VS15 variation selector now correctly preserves base character width instead of forcing width 1 + +## [0.4.1] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.4.0...v0.4.1) + +### Changed +- Updated uax29 dependency +- Improved flag handling + +## [0.4.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.3.1...v0.4.0) + +### Added +- Support for variation selectors (VS15, VS16) and regional indicator pairs (flags) + +## [0.3.1] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.3.0...v0.3.1) + +### Added +- Fuzz testing support + +### Changed +- Updated stringish dependency + +## [0.3.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.2.0...v0.3.0) + +### Changed +- Dropped compatibility with go-runewidth +- Trie implementation cleanup diff --git a/vendor/github.com/clipperhouse/displaywidth/LICENSE b/vendor/github.com/clipperhouse/displaywidth/LICENSE new file mode 100644 index 000000000..4b8064eb3 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Matt Sherman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/clipperhouse/displaywidth/README.md b/vendor/github.com/clipperhouse/displaywidth/README.md new file mode 100644 index 000000000..506822b02 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/README.md @@ -0,0 +1,190 @@ +# displaywidth + +A high-performance Go package for measuring the monospace display width of strings, UTF-8 bytes, and runes. + +[![Documentation](https://pkg.go.dev/badge/github.com/clipperhouse/displaywidth.svg)](https://pkg.go.dev/github.com/clipperhouse/displaywidth) +[![Test](https://github.com/clipperhouse/displaywidth/actions/workflows/gotest.yml/badge.svg)](https://github.com/clipperhouse/displaywidth/actions/workflows/gotest.yml) +[![Fuzz](https://github.com/clipperhouse/displaywidth/actions/workflows/gofuzz.yml/badge.svg)](https://github.com/clipperhouse/displaywidth/actions/workflows/gofuzz.yml) + +## Install +```bash +go get github.com/clipperhouse/displaywidth +``` + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/clipperhouse/displaywidth" +) + +func main() { + width := displaywidth.String("Hello, δΈ–η•Œ!") + fmt.Println(width) + + width = displaywidth.Bytes([]byte("🌍")) + fmt.Println(width) + + width = displaywidth.Rune('🌍') + fmt.Println(width) +} +``` + +For most purposes, you should use the `String` or `Bytes` methods. They sum +the widths of grapheme clusters in the string or byte slice. + +> Note: in your application, iterating over runes to measure width is likely incorrect; +the smallest unit of display is a grapheme, not a rune. + +### Iterating over graphemes + +If you need the individual graphemes: + +```go +import ( + "fmt" + "github.com/clipperhouse/displaywidth" +) + +func main() { + g := displaywidth.StringGraphemes("Hello, δΈ–η•Œ!") + for g.Next() { + width := g.Width() + value := g.Value() + // do something with the width or value + } +} +``` + +### Options + +Create the options you need, and then use methods on the options struct. + +```go +var myOptions = displaywidth.Options{ + EastAsianWidth: true, + ControlSequences: true, +} + +width := myOptions.String("Hello, δΈ–η•Œ!") +``` + +#### ControlSequences + +`ControlSequences` specifies whether to ignore ECMA-48 escape sequences +when calculating the display width. When `false` (default), ANSI escape +sequences are treated as just a series of characters. When `true`, they are +treated as a single zero-width unit. + +#### ControlSequences8Bit + +`ControlSequences8Bit` specifies whether to ignore 8-bit ECMA-48 escape sequences +when calculating the display width. When `false` (default), these are treated +as just a series of characters. When `true`, they are treated as a single +zero-width unit. + +Note: this option is ignored by the `Truncate` methods, as the concatenation +can lead to unintended UTF-8 semantics. + +#### EastAsianWidth + +`EastAsianWidth` defines how +[East Asian Ambiguous characters](https://www.unicode.org/reports/tr11/#Ambiguous) +are treated. + +When `false` (default), East Asian Ambiguous characters are treated as width 1. +When `true`, they are treated as width 2. + +You may wish to configure this based on environment variables or locale. + `go-runewidth`, for example, does so + [during package initialization](https://github.com/mattn/go-runewidth/blob/master/runewidth.go#L26C1-L45C2). `displaywidth` does not do this automatically, we prefer to leave it to you. + + +## Technical standards and compatibility + +This package implements the Unicode East Asian Width standard +([UAX #11](https://www.unicode.org/reports/tr11/tr11-43.html)), and handles +[version selectors](https://en.wikipedia.org/wiki/Variation_Selectors_(Unicode_block)), +and [regional indicator pairs](https://en.wikipedia.org/wiki/Regional_indicator_symbol) +(flags). We implement [Unicode TR51](https://www.unicode.org/reports/tr51/tr51-27.html) +for emojis. We are keeping an eye on +[emerging standards](https://www.jeffquast.com/post/state-of-terminal-emulation-2025/). + +For control sequences, we implement the [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/) standard for 7-bit and 8-bit control sequences. + +`clipperhouse/displaywidth`, `mattn/go-runewidth`, and `rivo/uniseg` will +give the same outputs for most real-world text. Extensive details are in the +[compatibility analysis](comparison/COMPATIBILITY_ANALYSIS.md). + +## Invalid UTF-8 + +This package does not validate UTF-8. If you pass invalid UTF-8, the results +are undefined. We fuzz against invalid UTF-8 to ensure we don't panic or +loop indefinitely. + +The `ControlSequences8Bit` option means that we will segment valid 8-bit +control sequences, which are typically _not_ valid UTF-8. 8-bit control bytes +happen to also be UTF-8 continuation bytes. Use with caution. + +## Prior Art + +[mattn/go-runewidth](https://github.com/mattn/go-runewidth) + +[rivo/uniseg](https://github.com/rivo/uniseg) + +[x/text/width](https://pkg.go.dev/golang.org/x/text/width) + +[x/text/internal/triegen](https://pkg.go.dev/golang.org/x/text/internal/triegen) + +## Benchmarks + +```bash +cd comparison +go test -bench=. -benchmem +``` + +``` +goos: darwin +goarch: arm64 +pkg: github.com/clipperhouse/displaywidth/comparison +cpu: Apple M2 + +BenchmarkString_Mixed/clipperhouse/displaywidth-8 5784 ns/op 291.69 MB/s 0 B/op 0 allocs/op +BenchmarkString_Mixed/mattn/go-runewidth-8 14751 ns/op 114.36 MB/s 0 B/op 0 allocs/op +BenchmarkString_Mixed/rivo/uniseg-8 19360 ns/op 87.14 MB/s 0 B/op 0 allocs/op + +BenchmarkString_ASCII/clipperhouse/displaywidth-8 54.60 ns/op 2344.32 MB/s 0 B/op 0 allocs/op +BenchmarkString_ASCII/mattn/go-runewidth-8 1195 ns/op 107.08 MB/s 0 B/op 0 allocs/op +BenchmarkString_ASCII/rivo/uniseg-8 1578 ns/op 81.13 MB/s 0 B/op 0 allocs/op + +BenchmarkString_EastAsian/clipperhouse/displaywidth-8 5837 ns/op 289.01 MB/s 0 B/op 0 allocs/op +BenchmarkString_EastAsian/mattn/go-runewidth-8 24418 ns/op 69.09 MB/s 0 B/op 0 allocs/op +BenchmarkString_EastAsian/rivo/uniseg-8 19339 ns/op 87.23 MB/s 0 B/op 0 allocs/op + +BenchmarkString_Emoji/clipperhouse/displaywidth-8 3225 ns/op 224.51 MB/s 0 B/op 0 allocs/op +BenchmarkString_Emoji/mattn/go-runewidth-8 4851 ns/op 149.25 MB/s 0 B/op 0 allocs/op +BenchmarkString_Emoji/rivo/uniseg-8 6591 ns/op 109.85 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3385 ns/op 498.34 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Mixed/mattn/go-runewidth-8 5354 ns/op 315.07 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3397 ns/op 496.56 MB/s 0 B/op 0 allocs/op +BenchmarkRune_EastAsian/mattn/go-runewidth-8 15673 ns/op 107.64 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_ASCII/clipperhouse/displaywidth-8 255.7 ns/op 500.53 MB/s 0 B/op 0 allocs/op +BenchmarkRune_ASCII/mattn/go-runewidth-8 261.5 ns/op 489.55 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1371 ns/op 528.22 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Emoji/mattn/go-runewidth-8 2267 ns/op 319.43 MB/s 0 B/op 0 allocs/op + +BenchmarkTruncateWithTail/clipperhouse/displaywidth-8 3229 ns/op 54.82 MB/s 192 B/op 14 allocs/op +BenchmarkTruncateWithTail/mattn/go-runewidth-8 8408 ns/op 21.05 MB/s 192 B/op 14 allocs/op + +BenchmarkTruncateWithoutTail/clipperhouse/displaywidth-8 3554 ns/op 64.43 MB/s 0 B/op 0 allocs/op +BenchmarkTruncateWithoutTail/mattn/go-runewidth-8 11189 ns/op 20.47 MB/s 0 B/op 0 allocs/op +``` + +Here are some notes on [how to make Unicode things fast](https://clipperhouse.com/go-unicode/). diff --git a/vendor/github.com/clipperhouse/displaywidth/gen.go b/vendor/github.com/clipperhouse/displaywidth/gen.go new file mode 100644 index 000000000..52e1085bc --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/gen.go @@ -0,0 +1,3 @@ +package displaywidth + +//go:generate go run -C internal/gen . diff --git a/vendor/github.com/clipperhouse/displaywidth/graphemes.go b/vendor/github.com/clipperhouse/displaywidth/graphemes.go new file mode 100644 index 000000000..14a52788b --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/graphemes.go @@ -0,0 +1,73 @@ +package displaywidth + +import ( + "github.com/clipperhouse/uax29/v2/graphemes" +) + +// Graphemes is an iterator over grapheme clusters. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +type Graphemes[T ~string | []byte] struct { + iter *graphemes.Iterator[T] + options Options +} + +// Next advances the iterator to the next grapheme cluster. +func (g *Graphemes[T]) Next() bool { + return g.iter.Next() +} + +// Value returns the current grapheme cluster. +func (g *Graphemes[T]) Value() T { + return g.iter.Value() +} + +// Width returns the display width of the current grapheme cluster. +func (g *Graphemes[T]) Width() int { + return graphemeWidth(g.Value(), g.options) +} + +// StringGraphemes returns an iterator over grapheme clusters for the given +// string. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func StringGraphemes(s string) Graphemes[string] { + return DefaultOptions.StringGraphemes(s) +} + +// StringGraphemes returns an iterator over grapheme clusters for the given +// string, with the given options. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func (options Options) StringGraphemes(s string) Graphemes[string] { + g := graphemes.FromString(s) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + return Graphemes[string]{iter: g, options: options} +} + +// BytesGraphemes returns an iterator over grapheme clusters for the given +// []byte. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func BytesGraphemes(s []byte) Graphemes[[]byte] { + return DefaultOptions.BytesGraphemes(s) +} + +// BytesGraphemes returns an iterator over grapheme clusters for the given +// []byte, with the given options. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func (options Options) BytesGraphemes(s []byte) Graphemes[[]byte] { + g := graphemes.FromBytes(s) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + return Graphemes[[]byte]{iter: g, options: options} +} diff --git a/vendor/github.com/clipperhouse/displaywidth/options.go b/vendor/github.com/clipperhouse/displaywidth/options.go new file mode 100644 index 000000000..b63b585aa --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/options.go @@ -0,0 +1,30 @@ +package displaywidth + +// Options allows you to specify the treatment of ambiguous East Asian +// characters and ANSI escape sequences. +type Options struct { + // EastAsianWidth specifies whether to treat ambiguous East Asian characters + // as width 1 or 2. When false (default), ambiguous East Asian characters + // are treated as width 1. When true, they are width 2. + EastAsianWidth bool + + // ControlSequences specifies whether to ignore 7-bit ECMA-48 escape sequences + // when calculating the display width. When false (default), ANSI escape + // sequences are treated as just a series of characters. When true, they are + // treated as a single zero-width unit. + ControlSequences bool + // ControlSequences8Bit specifies whether to ignore 8-bit ECMA-48 escape sequences + // when calculating the display width. When false (default), these are treated + // as just a series of characters. When true, they are treated as a single + // zero-width unit. + ControlSequences8Bit bool +} + +// DefaultOptions is the default options for the display width +// calculation, which is EastAsianWidth false, ControlSequences false, and +// ControlSequences8Bit false. +var DefaultOptions = Options{ + EastAsianWidth: false, + ControlSequences: false, + ControlSequences8Bit: false, +} diff --git a/vendor/github.com/clipperhouse/displaywidth/trie.go b/vendor/github.com/clipperhouse/displaywidth/trie.go new file mode 100644 index 000000000..1d3a98300 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/trie.go @@ -0,0 +1,1699 @@ +// Code generated by internal/gen/main.go. DO NOT EDIT. + +package displaywidth + +// property is an enum representing the properties of a character +type property uint8 + +const ( + // Always 0 width, includes combining marks, control characters, non-printable, etc + _Zero_Width property = iota + 1 + // Always 2 wide (East Asian Wide F/W, Emoji, Regional Indicator) + _Wide + // Width depends on EastAsianWidth option + _East_Asian_Ambiguous +) + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func lookup[T ~string | []byte](s T) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return stringWidthValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := stringWidthIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := stringWidthIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = stringWidthIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := stringWidthIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = stringWidthIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = stringWidthIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// stringWidthTrie. Total size: 17664 bytes (17.25 KiB). Checksum: 220983462f26d765. +// type stringWidthTrie struct { } + +// func newStringWidthTrie(i int) *stringWidthTrie { +// return &stringWidthTrie{} +// } + +// lookupValue determines the type of block n and looks up the value for b. +func lookupValue(n uint32, b byte) uint8 { + switch { + default: + return uint8(stringWidthValues[n<<6+uint32(b)]) + } +} + +// stringWidthValues: 246 blocks, 15744 entries, 15744 bytes +// The third block is the zero block. +var stringWidthValues = [15744]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x0001, 0xc1: 0x0001, 0xc2: 0x0001, 0xc3: 0x0001, 0xc4: 0x0001, 0xc5: 0x0001, + 0xc6: 0x0001, 0xc7: 0x0001, 0xc8: 0x0001, 0xc9: 0x0001, 0xca: 0x0001, 0xcb: 0x0001, + 0xcc: 0x0001, 0xcd: 0x0001, 0xce: 0x0001, 0xcf: 0x0001, 0xd0: 0x0001, 0xd1: 0x0001, + 0xd2: 0x0001, 0xd3: 0x0001, 0xd4: 0x0001, 0xd5: 0x0001, 0xd6: 0x0001, 0xd7: 0x0001, + 0xd8: 0x0001, 0xd9: 0x0001, 0xda: 0x0001, 0xdb: 0x0001, 0xdc: 0x0001, 0xdd: 0x0001, + 0xde: 0x0001, 0xdf: 0x0001, 0xe1: 0x0003, + 0xe4: 0x0003, 0xe7: 0x0003, 0xe8: 0x0003, + 0xea: 0x0003, 0xed: 0x0001, 0xee: 0x0003, + 0xf0: 0x0003, 0xf1: 0x0003, 0xf2: 0x0003, 0xf3: 0x0003, 0xf4: 0x0003, + 0xf6: 0x0003, 0xf7: 0x0003, 0xf8: 0x0003, 0xf9: 0x0003, 0xfa: 0x0003, + 0xfc: 0x0003, 0xfd: 0x0003, 0xfe: 0x0003, 0xff: 0x0003, + // Block 0x4, offset 0x100 + 0x106: 0x0003, + 0x110: 0x0003, + 0x117: 0x0003, + 0x118: 0x0003, + 0x11e: 0x0003, 0x11f: 0x0003, 0x120: 0x0003, 0x121: 0x0003, + 0x126: 0x0003, 0x128: 0x0003, 0x129: 0x0003, + 0x12a: 0x0003, 0x12c: 0x0003, 0x12d: 0x0003, + 0x130: 0x0003, 0x132: 0x0003, 0x133: 0x0003, + 0x137: 0x0003, 0x138: 0x0003, 0x139: 0x0003, 0x13a: 0x0003, + 0x13c: 0x0003, 0x13e: 0x0003, + // Block 0x5, offset 0x140 + 0x141: 0x0003, + 0x151: 0x0003, + 0x153: 0x0003, + 0x15b: 0x0003, + 0x166: 0x0003, 0x167: 0x0003, + 0x16b: 0x0003, + 0x171: 0x0003, 0x172: 0x0003, 0x173: 0x0003, + 0x178: 0x0003, + 0x17f: 0x0003, + // Block 0x6, offset 0x180 + 0x180: 0x0003, 0x181: 0x0003, 0x182: 0x0003, 0x184: 0x0003, + 0x188: 0x0003, 0x189: 0x0003, 0x18a: 0x0003, 0x18b: 0x0003, + 0x18d: 0x0003, + 0x192: 0x0003, 0x193: 0x0003, + 0x1a6: 0x0003, 0x1a7: 0x0003, + 0x1ab: 0x0003, + // Block 0x7, offset 0x1c0 + 0x1ce: 0x0003, 0x1d0: 0x0003, + 0x1d2: 0x0003, 0x1d4: 0x0003, 0x1d6: 0x0003, + 0x1d8: 0x0003, 0x1da: 0x0003, 0x1dc: 0x0003, + // Block 0x8, offset 0x200 + 0x211: 0x0003, + 0x221: 0x0003, + // Block 0x9, offset 0x240 + 0x244: 0x0003, + 0x247: 0x0003, 0x249: 0x0003, 0x24a: 0x0003, 0x24b: 0x0003, + 0x24d: 0x0003, 0x250: 0x0003, + 0x258: 0x0003, 0x259: 0x0003, 0x25a: 0x0003, 0x25b: 0x0003, 0x25d: 0x0003, + 0x25f: 0x0003, + // Block 0xa, offset 0x280 + 0x280: 0x0001, 0x281: 0x0001, 0x282: 0x0001, 0x283: 0x0001, 0x284: 0x0001, 0x285: 0x0001, + 0x286: 0x0001, 0x287: 0x0001, 0x288: 0x0001, 0x289: 0x0001, 0x28a: 0x0001, 0x28b: 0x0001, + 0x28c: 0x0001, 0x28d: 0x0001, 0x28e: 0x0001, 0x28f: 0x0001, 0x290: 0x0001, 0x291: 0x0001, + 0x292: 0x0001, 0x293: 0x0001, 0x294: 0x0001, 0x295: 0x0001, 0x296: 0x0001, 0x297: 0x0001, + 0x298: 0x0001, 0x299: 0x0001, 0x29a: 0x0001, 0x29b: 0x0001, 0x29c: 0x0001, 0x29d: 0x0001, + 0x29e: 0x0001, 0x29f: 0x0001, 0x2a0: 0x0001, 0x2a1: 0x0001, 0x2a2: 0x0001, 0x2a3: 0x0001, + 0x2a4: 0x0001, 0x2a5: 0x0001, 0x2a6: 0x0001, 0x2a7: 0x0001, 0x2a8: 0x0001, 0x2a9: 0x0001, + 0x2aa: 0x0001, 0x2ab: 0x0001, 0x2ac: 0x0001, 0x2ad: 0x0001, 0x2ae: 0x0001, 0x2af: 0x0001, + 0x2b0: 0x0001, 0x2b1: 0x0001, 0x2b2: 0x0001, 0x2b3: 0x0001, 0x2b4: 0x0001, 0x2b5: 0x0001, + 0x2b6: 0x0001, 0x2b7: 0x0001, 0x2b8: 0x0001, 0x2b9: 0x0001, 0x2ba: 0x0001, 0x2bb: 0x0001, + 0x2bc: 0x0001, 0x2bd: 0x0001, 0x2be: 0x0001, 0x2bf: 0x0001, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x0001, 0x2c1: 0x0001, 0x2c2: 0x0001, 0x2c3: 0x0001, 0x2c4: 0x0001, 0x2c5: 0x0001, + 0x2c6: 0x0001, 0x2c7: 0x0001, 0x2c8: 0x0001, 0x2c9: 0x0001, 0x2ca: 0x0001, 0x2cb: 0x0001, + 0x2cc: 0x0001, 0x2cd: 0x0001, 0x2ce: 0x0001, 0x2cf: 0x0001, 0x2d0: 0x0001, 0x2d1: 0x0001, + 0x2d2: 0x0001, 0x2d3: 0x0001, 0x2d4: 0x0001, 0x2d5: 0x0001, 0x2d6: 0x0001, 0x2d7: 0x0001, + 0x2d8: 0x0001, 0x2d9: 0x0001, 0x2da: 0x0001, 0x2db: 0x0001, 0x2dc: 0x0001, 0x2dd: 0x0001, + 0x2de: 0x0001, 0x2df: 0x0001, 0x2e0: 0x0001, 0x2e1: 0x0001, 0x2e2: 0x0001, 0x2e3: 0x0001, + 0x2e4: 0x0001, 0x2e5: 0x0001, 0x2e6: 0x0001, 0x2e7: 0x0001, 0x2e8: 0x0001, 0x2e9: 0x0001, + 0x2ea: 0x0001, 0x2eb: 0x0001, 0x2ec: 0x0001, 0x2ed: 0x0001, 0x2ee: 0x0001, 0x2ef: 0x0001, + // Block 0xc, offset 0x300 + 0x311: 0x0003, + 0x312: 0x0003, 0x313: 0x0003, 0x314: 0x0003, 0x315: 0x0003, 0x316: 0x0003, 0x317: 0x0003, + 0x318: 0x0003, 0x319: 0x0003, 0x31a: 0x0003, 0x31b: 0x0003, 0x31c: 0x0003, 0x31d: 0x0003, + 0x31e: 0x0003, 0x31f: 0x0003, 0x320: 0x0003, 0x321: 0x0003, 0x323: 0x0003, + 0x324: 0x0003, 0x325: 0x0003, 0x326: 0x0003, 0x327: 0x0003, 0x328: 0x0003, 0x329: 0x0003, + 0x331: 0x0003, 0x332: 0x0003, 0x333: 0x0003, 0x334: 0x0003, 0x335: 0x0003, + 0x336: 0x0003, 0x337: 0x0003, 0x338: 0x0003, 0x339: 0x0003, 0x33a: 0x0003, 0x33b: 0x0003, + 0x33c: 0x0003, 0x33d: 0x0003, 0x33e: 0x0003, 0x33f: 0x0003, + // Block 0xd, offset 0x340 + 0x340: 0x0003, 0x341: 0x0003, 0x343: 0x0003, 0x344: 0x0003, 0x345: 0x0003, + 0x346: 0x0003, 0x347: 0x0003, 0x348: 0x0003, 0x349: 0x0003, + // Block 0xe, offset 0x380 + 0x381: 0x0003, + 0x390: 0x0003, 0x391: 0x0003, + 0x392: 0x0003, 0x393: 0x0003, 0x394: 0x0003, 0x395: 0x0003, 0x396: 0x0003, 0x397: 0x0003, + 0x398: 0x0003, 0x399: 0x0003, 0x39a: 0x0003, 0x39b: 0x0003, 0x39c: 0x0003, 0x39d: 0x0003, + 0x39e: 0x0003, 0x39f: 0x0003, 0x3a0: 0x0003, 0x3a1: 0x0003, 0x3a2: 0x0003, 0x3a3: 0x0003, + 0x3a4: 0x0003, 0x3a5: 0x0003, 0x3a6: 0x0003, 0x3a7: 0x0003, 0x3a8: 0x0003, 0x3a9: 0x0003, + 0x3aa: 0x0003, 0x3ab: 0x0003, 0x3ac: 0x0003, 0x3ad: 0x0003, 0x3ae: 0x0003, 0x3af: 0x0003, + 0x3b0: 0x0003, 0x3b1: 0x0003, 0x3b2: 0x0003, 0x3b3: 0x0003, 0x3b4: 0x0003, 0x3b5: 0x0003, + 0x3b6: 0x0003, 0x3b7: 0x0003, 0x3b8: 0x0003, 0x3b9: 0x0003, 0x3ba: 0x0003, 0x3bb: 0x0003, + 0x3bc: 0x0003, 0x3bd: 0x0003, 0x3be: 0x0003, 0x3bf: 0x0003, + // Block 0xf, offset 0x3c0 + 0x3c0: 0x0003, 0x3c1: 0x0003, 0x3c2: 0x0003, 0x3c3: 0x0003, 0x3c4: 0x0003, 0x3c5: 0x0003, + 0x3c6: 0x0003, 0x3c7: 0x0003, 0x3c8: 0x0003, 0x3c9: 0x0003, 0x3ca: 0x0003, 0x3cb: 0x0003, + 0x3cc: 0x0003, 0x3cd: 0x0003, 0x3ce: 0x0003, 0x3cf: 0x0003, 0x3d1: 0x0003, + // Block 0x10, offset 0x400 + 0x403: 0x0001, 0x404: 0x0001, 0x405: 0x0001, + 0x406: 0x0001, 0x407: 0x0001, 0x408: 0x0001, 0x409: 0x0001, + // Block 0x11, offset 0x440 + 0x451: 0x0001, + 0x452: 0x0001, 0x453: 0x0001, 0x454: 0x0001, 0x455: 0x0001, 0x456: 0x0001, 0x457: 0x0001, + 0x458: 0x0001, 0x459: 0x0001, 0x45a: 0x0001, 0x45b: 0x0001, 0x45c: 0x0001, 0x45d: 0x0001, + 0x45e: 0x0001, 0x45f: 0x0001, 0x460: 0x0001, 0x461: 0x0001, 0x462: 0x0001, 0x463: 0x0001, + 0x464: 0x0001, 0x465: 0x0001, 0x466: 0x0001, 0x467: 0x0001, 0x468: 0x0001, 0x469: 0x0001, + 0x46a: 0x0001, 0x46b: 0x0001, 0x46c: 0x0001, 0x46d: 0x0001, 0x46e: 0x0001, 0x46f: 0x0001, + 0x470: 0x0001, 0x471: 0x0001, 0x472: 0x0001, 0x473: 0x0001, 0x474: 0x0001, 0x475: 0x0001, + 0x476: 0x0001, 0x477: 0x0001, 0x478: 0x0001, 0x479: 0x0001, 0x47a: 0x0001, 0x47b: 0x0001, + 0x47c: 0x0001, 0x47d: 0x0001, 0x47f: 0x0001, + // Block 0x12, offset 0x480 + 0x481: 0x0001, 0x482: 0x0001, 0x484: 0x0001, 0x485: 0x0001, + 0x487: 0x0001, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x0001, 0x4c1: 0x0001, 0x4c2: 0x0001, 0x4c3: 0x0001, 0x4c4: 0x0001, 0x4c5: 0x0001, + 0x4d0: 0x0001, 0x4d1: 0x0001, + 0x4d2: 0x0001, 0x4d3: 0x0001, 0x4d4: 0x0001, 0x4d5: 0x0001, 0x4d6: 0x0001, 0x4d7: 0x0001, + 0x4d8: 0x0001, 0x4d9: 0x0001, 0x4da: 0x0001, 0x4dc: 0x0001, + // Block 0x14, offset 0x500 + 0x50b: 0x0001, + 0x50c: 0x0001, 0x50d: 0x0001, 0x50e: 0x0001, 0x50f: 0x0001, 0x510: 0x0001, 0x511: 0x0001, + 0x512: 0x0001, 0x513: 0x0001, 0x514: 0x0001, 0x515: 0x0001, 0x516: 0x0001, 0x517: 0x0001, + 0x518: 0x0001, 0x519: 0x0001, 0x51a: 0x0001, 0x51b: 0x0001, 0x51c: 0x0001, 0x51d: 0x0001, + 0x51e: 0x0001, 0x51f: 0x0001, + 0x530: 0x0001, + // Block 0x15, offset 0x540 + 0x556: 0x0001, 0x557: 0x0001, + 0x558: 0x0001, 0x559: 0x0001, 0x55a: 0x0001, 0x55b: 0x0001, 0x55c: 0x0001, 0x55d: 0x0001, + 0x55f: 0x0001, 0x560: 0x0001, 0x561: 0x0001, 0x562: 0x0001, 0x563: 0x0001, + 0x564: 0x0001, 0x567: 0x0001, 0x568: 0x0001, + 0x56a: 0x0001, 0x56b: 0x0001, 0x56c: 0x0001, 0x56d: 0x0001, + // Block 0x16, offset 0x580 + 0x58f: 0x0001, 0x591: 0x0001, + 0x5b0: 0x0001, 0x5b1: 0x0001, 0x5b2: 0x0001, 0x5b3: 0x0001, 0x5b4: 0x0001, 0x5b5: 0x0001, + 0x5b6: 0x0001, 0x5b7: 0x0001, 0x5b8: 0x0001, 0x5b9: 0x0001, 0x5ba: 0x0001, 0x5bb: 0x0001, + 0x5bc: 0x0001, 0x5bd: 0x0001, 0x5be: 0x0001, 0x5bf: 0x0001, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x0001, 0x5c1: 0x0001, 0x5c2: 0x0001, 0x5c3: 0x0001, 0x5c4: 0x0001, 0x5c5: 0x0001, + 0x5c6: 0x0001, 0x5c7: 0x0001, 0x5c8: 0x0001, 0x5c9: 0x0001, 0x5ca: 0x0001, + // Block 0x18, offset 0x600 + 0x626: 0x0001, 0x627: 0x0001, 0x628: 0x0001, 0x629: 0x0001, + 0x62a: 0x0001, 0x62b: 0x0001, 0x62c: 0x0001, 0x62d: 0x0001, 0x62e: 0x0001, 0x62f: 0x0001, + 0x630: 0x0001, + // Block 0x19, offset 0x640 + 0x66b: 0x0001, 0x66c: 0x0001, 0x66d: 0x0001, 0x66e: 0x0001, 0x66f: 0x0001, + 0x670: 0x0001, 0x671: 0x0001, 0x672: 0x0001, 0x673: 0x0001, + 0x67d: 0x0001, + // Block 0x1a, offset 0x680 + 0x696: 0x0001, 0x697: 0x0001, + 0x698: 0x0001, 0x699: 0x0001, 0x69b: 0x0001, 0x69c: 0x0001, 0x69d: 0x0001, + 0x69e: 0x0001, 0x69f: 0x0001, 0x6a0: 0x0001, 0x6a1: 0x0001, 0x6a2: 0x0001, 0x6a3: 0x0001, + 0x6a5: 0x0001, 0x6a6: 0x0001, 0x6a7: 0x0001, 0x6a9: 0x0001, + 0x6aa: 0x0001, 0x6ab: 0x0001, 0x6ac: 0x0001, 0x6ad: 0x0001, + // Block 0x1b, offset 0x6c0 + 0x6d9: 0x0001, 0x6da: 0x0001, 0x6db: 0x0001, + // Block 0x1c, offset 0x700 + 0x710: 0x0001, 0x711: 0x0001, + 0x718: 0x0001, 0x719: 0x0001, 0x71a: 0x0001, 0x71b: 0x0001, 0x71c: 0x0001, 0x71d: 0x0001, + 0x71e: 0x0001, 0x71f: 0x0001, + // Block 0x1d, offset 0x740 + 0x74a: 0x0001, 0x74b: 0x0001, + 0x74c: 0x0001, 0x74d: 0x0001, 0x74e: 0x0001, 0x74f: 0x0001, 0x750: 0x0001, 0x751: 0x0001, + 0x752: 0x0001, 0x753: 0x0001, 0x754: 0x0001, 0x755: 0x0001, 0x756: 0x0001, 0x757: 0x0001, + 0x758: 0x0001, 0x759: 0x0001, 0x75a: 0x0001, 0x75b: 0x0001, 0x75c: 0x0001, 0x75d: 0x0001, + 0x75e: 0x0001, 0x75f: 0x0001, 0x760: 0x0001, 0x761: 0x0001, 0x762: 0x0001, 0x763: 0x0001, + 0x764: 0x0001, 0x765: 0x0001, 0x766: 0x0001, 0x767: 0x0001, 0x768: 0x0001, 0x769: 0x0001, + 0x76a: 0x0001, 0x76b: 0x0001, 0x76c: 0x0001, 0x76d: 0x0001, 0x76e: 0x0001, 0x76f: 0x0001, + 0x770: 0x0001, 0x771: 0x0001, 0x772: 0x0001, 0x773: 0x0001, 0x774: 0x0001, 0x775: 0x0001, + 0x776: 0x0001, 0x777: 0x0001, 0x778: 0x0001, 0x779: 0x0001, 0x77a: 0x0001, 0x77b: 0x0001, + 0x77c: 0x0001, 0x77d: 0x0001, 0x77e: 0x0001, 0x77f: 0x0001, + // Block 0x1e, offset 0x780 + 0x780: 0x0001, 0x781: 0x0001, 0x782: 0x0001, + 0x7ba: 0x0001, + 0x7bc: 0x0001, + // Block 0x1f, offset 0x7c0 + 0x7c1: 0x0001, 0x7c2: 0x0001, 0x7c3: 0x0001, 0x7c4: 0x0001, 0x7c5: 0x0001, + 0x7c6: 0x0001, 0x7c7: 0x0001, 0x7c8: 0x0001, + 0x7cd: 0x0001, 0x7d1: 0x0001, + 0x7d2: 0x0001, 0x7d3: 0x0001, 0x7d4: 0x0001, 0x7d5: 0x0001, 0x7d6: 0x0001, 0x7d7: 0x0001, + 0x7e2: 0x0001, 0x7e3: 0x0001, + // Block 0x20, offset 0x800 + 0x801: 0x0001, + 0x83c: 0x0001, + // Block 0x21, offset 0x840 + 0x841: 0x0001, 0x842: 0x0001, 0x843: 0x0001, 0x844: 0x0001, + 0x84d: 0x0001, + 0x862: 0x0001, 0x863: 0x0001, + 0x87e: 0x0001, + // Block 0x22, offset 0x880 + 0x881: 0x0001, 0x882: 0x0001, + 0x8bc: 0x0001, + // Block 0x23, offset 0x8c0 + 0x8c1: 0x0001, 0x8c2: 0x0001, + 0x8c7: 0x0001, 0x8c8: 0x0001, 0x8cb: 0x0001, + 0x8cc: 0x0001, 0x8cd: 0x0001, 0x8d1: 0x0001, + 0x8f0: 0x0001, 0x8f1: 0x0001, 0x8f5: 0x0001, + // Block 0x24, offset 0x900 + 0x901: 0x0001, 0x902: 0x0001, 0x903: 0x0001, 0x904: 0x0001, 0x905: 0x0001, + 0x907: 0x0001, 0x908: 0x0001, + 0x90d: 0x0001, + 0x922: 0x0001, 0x923: 0x0001, + 0x93a: 0x0001, 0x93b: 0x0001, + 0x93c: 0x0001, 0x93d: 0x0001, 0x93e: 0x0001, 0x93f: 0x0001, + // Block 0x25, offset 0x940 + 0x941: 0x0001, + 0x97c: 0x0001, 0x97f: 0x0001, + // Block 0x26, offset 0x980 + 0x981: 0x0001, 0x982: 0x0001, 0x983: 0x0001, 0x984: 0x0001, + 0x98d: 0x0001, + 0x995: 0x0001, 0x996: 0x0001, + 0x9a2: 0x0001, 0x9a3: 0x0001, + // Block 0x27, offset 0x9c0 + 0x9c2: 0x0001, + // Block 0x28, offset 0xa00 + 0xa00: 0x0001, + 0xa0d: 0x0001, + // Block 0x29, offset 0xa40 + 0xa40: 0x0001, 0xa44: 0x0001, + 0xa7c: 0x0001, 0xa7e: 0x0001, 0xa7f: 0x0001, + // Block 0x2a, offset 0xa80 + 0xa80: 0x0001, + 0xa86: 0x0001, 0xa87: 0x0001, 0xa88: 0x0001, 0xa8a: 0x0001, 0xa8b: 0x0001, + 0xa8c: 0x0001, 0xa8d: 0x0001, + 0xa95: 0x0001, 0xa96: 0x0001, + 0xaa2: 0x0001, 0xaa3: 0x0001, + // Block 0x2b, offset 0xac0 + 0xac6: 0x0001, + 0xacc: 0x0001, 0xacd: 0x0001, + 0xae2: 0x0001, 0xae3: 0x0001, + // Block 0x2c, offset 0xb00 + 0xb00: 0x0001, 0xb01: 0x0001, + 0xb3b: 0x0001, + 0xb3c: 0x0001, + // Block 0x2d, offset 0xb40 + 0xb41: 0x0001, 0xb42: 0x0001, 0xb43: 0x0001, 0xb44: 0x0001, + 0xb4d: 0x0001, + 0xb62: 0x0001, 0xb63: 0x0001, + // Block 0x2e, offset 0xb80 + 0xb81: 0x0001, + // Block 0x2f, offset 0xbc0 + 0xbca: 0x0001, + 0xbd2: 0x0001, 0xbd3: 0x0001, 0xbd4: 0x0001, 0xbd6: 0x0001, + // Block 0x30, offset 0xc00 + 0xc31: 0x0001, 0xc34: 0x0001, 0xc35: 0x0001, + 0xc36: 0x0001, 0xc37: 0x0001, 0xc38: 0x0001, 0xc39: 0x0001, 0xc3a: 0x0001, + // Block 0x31, offset 0xc40 + 0xc47: 0x0001, 0xc48: 0x0001, 0xc49: 0x0001, 0xc4a: 0x0001, 0xc4b: 0x0001, + 0xc4c: 0x0001, 0xc4d: 0x0001, 0xc4e: 0x0001, + // Block 0x32, offset 0xc80 + 0xcb1: 0x0001, 0xcb4: 0x0001, 0xcb5: 0x0001, + 0xcb6: 0x0001, 0xcb7: 0x0001, 0xcb8: 0x0001, 0xcb9: 0x0001, 0xcba: 0x0001, 0xcbb: 0x0001, + 0xcbc: 0x0001, + // Block 0x33, offset 0xcc0 + 0xcc8: 0x0001, 0xcc9: 0x0001, 0xcca: 0x0001, 0xccb: 0x0001, + 0xccc: 0x0001, 0xccd: 0x0001, 0xcce: 0x0001, + // Block 0x34, offset 0xd00 + 0xd18: 0x0001, 0xd19: 0x0001, + 0xd35: 0x0001, + 0xd37: 0x0001, 0xd39: 0x0001, + // Block 0x35, offset 0xd40 + 0xd71: 0x0001, 0xd72: 0x0001, 0xd73: 0x0001, 0xd74: 0x0001, 0xd75: 0x0001, + 0xd76: 0x0001, 0xd77: 0x0001, 0xd78: 0x0001, 0xd79: 0x0001, 0xd7a: 0x0001, 0xd7b: 0x0001, + 0xd7c: 0x0001, 0xd7d: 0x0001, 0xd7e: 0x0001, + // Block 0x36, offset 0xd80 + 0xd80: 0x0001, 0xd81: 0x0001, 0xd82: 0x0001, 0xd83: 0x0001, 0xd84: 0x0001, + 0xd86: 0x0001, 0xd87: 0x0001, + 0xd8d: 0x0001, 0xd8e: 0x0001, 0xd8f: 0x0001, 0xd90: 0x0001, 0xd91: 0x0001, + 0xd92: 0x0001, 0xd93: 0x0001, 0xd94: 0x0001, 0xd95: 0x0001, 0xd96: 0x0001, 0xd97: 0x0001, + 0xd99: 0x0001, 0xd9a: 0x0001, 0xd9b: 0x0001, 0xd9c: 0x0001, 0xd9d: 0x0001, + 0xd9e: 0x0001, 0xd9f: 0x0001, 0xda0: 0x0001, 0xda1: 0x0001, 0xda2: 0x0001, 0xda3: 0x0001, + 0xda4: 0x0001, 0xda5: 0x0001, 0xda6: 0x0001, 0xda7: 0x0001, 0xda8: 0x0001, 0xda9: 0x0001, + 0xdaa: 0x0001, 0xdab: 0x0001, 0xdac: 0x0001, 0xdad: 0x0001, 0xdae: 0x0001, 0xdaf: 0x0001, + 0xdb0: 0x0001, 0xdb1: 0x0001, 0xdb2: 0x0001, 0xdb3: 0x0001, 0xdb4: 0x0001, 0xdb5: 0x0001, + 0xdb6: 0x0001, 0xdb7: 0x0001, 0xdb8: 0x0001, 0xdb9: 0x0001, 0xdba: 0x0001, 0xdbb: 0x0001, + 0xdbc: 0x0001, + // Block 0x37, offset 0xdc0 + 0xdc6: 0x0001, + // Block 0x38, offset 0xe00 + 0xe2d: 0x0001, 0xe2e: 0x0001, 0xe2f: 0x0001, + 0xe30: 0x0001, 0xe32: 0x0001, 0xe33: 0x0001, 0xe34: 0x0001, 0xe35: 0x0001, + 0xe36: 0x0001, 0xe37: 0x0001, 0xe39: 0x0001, 0xe3a: 0x0001, + 0xe3d: 0x0001, 0xe3e: 0x0001, + // Block 0x39, offset 0xe40 + 0xe58: 0x0001, 0xe59: 0x0001, + 0xe5e: 0x0001, 0xe5f: 0x0001, 0xe60: 0x0001, + 0xe71: 0x0001, 0xe72: 0x0001, 0xe73: 0x0001, 0xe74: 0x0001, + // Block 0x3a, offset 0xe80 + 0xe82: 0x0001, 0xe85: 0x0001, + 0xe86: 0x0001, + 0xe8d: 0x0001, + 0xe9d: 0x0001, + // Block 0x3b, offset 0xec0 + 0xec0: 0x0002, 0xec1: 0x0002, 0xec2: 0x0002, 0xec3: 0x0002, 0xec4: 0x0002, 0xec5: 0x0002, + 0xec6: 0x0002, 0xec7: 0x0002, 0xec8: 0x0002, 0xec9: 0x0002, 0xeca: 0x0002, 0xecb: 0x0002, + 0xecc: 0x0002, 0xecd: 0x0002, 0xece: 0x0002, 0xecf: 0x0002, 0xed0: 0x0002, 0xed1: 0x0002, + 0xed2: 0x0002, 0xed3: 0x0002, 0xed4: 0x0002, 0xed5: 0x0002, 0xed6: 0x0002, 0xed7: 0x0002, + 0xed8: 0x0002, 0xed9: 0x0002, 0xeda: 0x0002, 0xedb: 0x0002, 0xedc: 0x0002, 0xedd: 0x0002, + 0xede: 0x0002, 0xedf: 0x0002, 0xee0: 0x0002, 0xee1: 0x0002, 0xee2: 0x0002, 0xee3: 0x0002, + 0xee4: 0x0002, 0xee5: 0x0002, 0xee6: 0x0002, 0xee7: 0x0002, 0xee8: 0x0002, 0xee9: 0x0002, + 0xeea: 0x0002, 0xeeb: 0x0002, 0xeec: 0x0002, 0xeed: 0x0002, 0xeee: 0x0002, 0xeef: 0x0002, + 0xef0: 0x0002, 0xef1: 0x0002, 0xef2: 0x0002, 0xef3: 0x0002, 0xef4: 0x0002, 0xef5: 0x0002, + 0xef6: 0x0002, 0xef7: 0x0002, 0xef8: 0x0002, 0xef9: 0x0002, 0xefa: 0x0002, 0xefb: 0x0002, + 0xefc: 0x0002, 0xefd: 0x0002, 0xefe: 0x0002, 0xeff: 0x0002, + // Block 0x3c, offset 0xf00 + 0xf00: 0x0002, 0xf01: 0x0002, 0xf02: 0x0002, 0xf03: 0x0002, 0xf04: 0x0002, 0xf05: 0x0002, + 0xf06: 0x0002, 0xf07: 0x0002, 0xf08: 0x0002, 0xf09: 0x0002, 0xf0a: 0x0002, 0xf0b: 0x0002, + 0xf0c: 0x0002, 0xf0d: 0x0002, 0xf0e: 0x0002, 0xf0f: 0x0002, 0xf10: 0x0002, 0xf11: 0x0002, + 0xf12: 0x0002, 0xf13: 0x0002, 0xf14: 0x0002, 0xf15: 0x0002, 0xf16: 0x0002, 0xf17: 0x0002, + 0xf18: 0x0002, 0xf19: 0x0002, 0xf1a: 0x0002, 0xf1b: 0x0002, 0xf1c: 0x0002, 0xf1d: 0x0002, + 0xf1e: 0x0002, 0xf1f: 0x0002, + // Block 0x3d, offset 0xf40 + 0xf5d: 0x0001, + 0xf5e: 0x0001, 0xf5f: 0x0001, + // Block 0x3e, offset 0xf80 + 0xf92: 0x0001, 0xf93: 0x0001, 0xf94: 0x0001, + 0xfb2: 0x0001, 0xfb3: 0x0001, + // Block 0x3f, offset 0xfc0 + 0xfd2: 0x0001, 0xfd3: 0x0001, + 0xff2: 0x0001, 0xff3: 0x0001, + // Block 0x40, offset 0x1000 + 0x1034: 0x0001, 0x1035: 0x0001, + 0x1037: 0x0001, 0x1038: 0x0001, 0x1039: 0x0001, 0x103a: 0x0001, 0x103b: 0x0001, + 0x103c: 0x0001, 0x103d: 0x0001, + // Block 0x41, offset 0x1040 + 0x1046: 0x0001, 0x1049: 0x0001, 0x104a: 0x0001, 0x104b: 0x0001, + 0x104c: 0x0001, 0x104d: 0x0001, 0x104e: 0x0001, 0x104f: 0x0001, 0x1050: 0x0001, 0x1051: 0x0001, + 0x1052: 0x0001, 0x1053: 0x0001, + 0x105d: 0x0001, + // Block 0x42, offset 0x1080 + 0x108b: 0x0001, + 0x108c: 0x0001, 0x108d: 0x0001, 0x108e: 0x0001, 0x108f: 0x0001, + // Block 0x43, offset 0x10c0 + 0x10c5: 0x0001, + 0x10c6: 0x0001, + 0x10e9: 0x0001, + // Block 0x44, offset 0x1100 + 0x1120: 0x0001, 0x1121: 0x0001, 0x1122: 0x0001, + 0x1127: 0x0001, 0x1128: 0x0001, + 0x1132: 0x0001, + 0x1139: 0x0001, 0x113a: 0x0001, 0x113b: 0x0001, + // Block 0x45, offset 0x1140 + 0x1157: 0x0001, + 0x1158: 0x0001, 0x115b: 0x0001, + // Block 0x46, offset 0x1180 + 0x1196: 0x0001, + 0x1198: 0x0001, 0x1199: 0x0001, 0x119a: 0x0001, 0x119b: 0x0001, 0x119c: 0x0001, 0x119d: 0x0001, + 0x119e: 0x0001, 0x11a0: 0x0001, 0x11a2: 0x0001, + 0x11a5: 0x0001, 0x11a6: 0x0001, 0x11a7: 0x0001, 0x11a8: 0x0001, 0x11a9: 0x0001, + 0x11aa: 0x0001, 0x11ab: 0x0001, 0x11ac: 0x0001, + 0x11b3: 0x0001, 0x11b4: 0x0001, 0x11b5: 0x0001, + 0x11b6: 0x0001, 0x11b7: 0x0001, 0x11b8: 0x0001, 0x11b9: 0x0001, 0x11ba: 0x0001, 0x11bb: 0x0001, + 0x11bc: 0x0001, 0x11bf: 0x0001, + // Block 0x47, offset 0x11c0 + 0x11f0: 0x0001, 0x11f1: 0x0001, 0x11f2: 0x0001, 0x11f3: 0x0001, 0x11f4: 0x0001, 0x11f5: 0x0001, + 0x11f6: 0x0001, 0x11f7: 0x0001, 0x11f8: 0x0001, 0x11f9: 0x0001, 0x11fa: 0x0001, 0x11fb: 0x0001, + 0x11fc: 0x0001, 0x11fd: 0x0001, 0x11fe: 0x0001, 0x11ff: 0x0001, + // Block 0x48, offset 0x1200 + 0x1200: 0x0001, 0x1201: 0x0001, 0x1202: 0x0001, 0x1203: 0x0001, 0x1204: 0x0001, 0x1205: 0x0001, + 0x1206: 0x0001, 0x1207: 0x0001, 0x1208: 0x0001, 0x1209: 0x0001, 0x120a: 0x0001, 0x120b: 0x0001, + 0x120c: 0x0001, 0x120d: 0x0001, 0x120e: 0x0001, + // Block 0x49, offset 0x1240 + 0x1240: 0x0001, 0x1241: 0x0001, 0x1242: 0x0001, 0x1243: 0x0001, + 0x1274: 0x0001, + 0x1276: 0x0001, 0x1277: 0x0001, 0x1278: 0x0001, 0x1279: 0x0001, 0x127a: 0x0001, + 0x127c: 0x0001, + // Block 0x4a, offset 0x1280 + 0x1282: 0x0001, + 0x12ab: 0x0001, 0x12ac: 0x0001, 0x12ad: 0x0001, 0x12ae: 0x0001, 0x12af: 0x0001, + 0x12b0: 0x0001, 0x12b1: 0x0001, 0x12b2: 0x0001, 0x12b3: 0x0001, + // Block 0x4b, offset 0x12c0 + 0x12c0: 0x0001, 0x12c1: 0x0001, + 0x12e2: 0x0001, 0x12e3: 0x0001, + 0x12e4: 0x0001, 0x12e5: 0x0001, 0x12e8: 0x0001, 0x12e9: 0x0001, + 0x12eb: 0x0001, 0x12ec: 0x0001, 0x12ed: 0x0001, + // Block 0x4c, offset 0x1300 + 0x1326: 0x0001, 0x1328: 0x0001, 0x1329: 0x0001, + 0x132d: 0x0001, 0x132f: 0x0001, + 0x1330: 0x0001, 0x1331: 0x0001, + // Block 0x4d, offset 0x1340 + 0x136c: 0x0001, 0x136d: 0x0001, 0x136e: 0x0001, 0x136f: 0x0001, + 0x1370: 0x0001, 0x1371: 0x0001, 0x1372: 0x0001, 0x1373: 0x0001, + 0x1376: 0x0001, 0x1377: 0x0001, + // Block 0x4e, offset 0x1380 + 0x1390: 0x0001, 0x1391: 0x0001, + 0x1392: 0x0001, 0x1394: 0x0001, 0x1395: 0x0001, 0x1396: 0x0001, 0x1397: 0x0001, + 0x1398: 0x0001, 0x1399: 0x0001, 0x139a: 0x0001, 0x139b: 0x0001, 0x139c: 0x0001, 0x139d: 0x0001, + 0x139e: 0x0001, 0x139f: 0x0001, 0x13a0: 0x0001, 0x13a2: 0x0001, 0x13a3: 0x0001, + 0x13a4: 0x0001, 0x13a5: 0x0001, 0x13a6: 0x0001, 0x13a7: 0x0001, 0x13a8: 0x0001, + 0x13ad: 0x0001, + 0x13b4: 0x0001, + 0x13b8: 0x0001, 0x13b9: 0x0001, + // Block 0x4f, offset 0x13c0 + 0x13cb: 0x0001, + 0x13cc: 0x0001, 0x13cd: 0x0001, 0x13ce: 0x0001, 0x13cf: 0x0001, 0x13d0: 0x0003, + 0x13d3: 0x0003, 0x13d4: 0x0003, 0x13d5: 0x0003, 0x13d6: 0x0003, + 0x13d8: 0x0003, 0x13d9: 0x0003, 0x13dc: 0x0003, 0x13dd: 0x0003, + 0x13e0: 0x0003, 0x13e1: 0x0003, 0x13e2: 0x0003, + 0x13e4: 0x0003, 0x13e5: 0x0003, 0x13e6: 0x0003, 0x13e7: 0x0003, 0x13e8: 0x0001, 0x13e9: 0x0001, + 0x13ea: 0x0001, 0x13eb: 0x0001, 0x13ec: 0x0001, 0x13ed: 0x0001, 0x13ee: 0x0001, + 0x13f0: 0x0003, 0x13f2: 0x0003, 0x13f3: 0x0003, 0x13f5: 0x0003, + 0x13fb: 0x0003, + 0x13fe: 0x0003, + // Block 0x50, offset 0x1400 + 0x1420: 0x0001, 0x1421: 0x0001, 0x1422: 0x0001, 0x1423: 0x0001, + 0x1424: 0x0001, 0x1426: 0x0001, 0x1427: 0x0001, 0x1428: 0x0001, 0x1429: 0x0001, + 0x142a: 0x0001, 0x142b: 0x0001, 0x142c: 0x0001, 0x142d: 0x0001, 0x142e: 0x0001, 0x142f: 0x0001, + 0x1434: 0x0003, + 0x143f: 0x0003, + // Block 0x51, offset 0x1440 + 0x1441: 0x0003, 0x1442: 0x0003, 0x1443: 0x0003, 0x1444: 0x0003, + 0x146c: 0x0003, + // Block 0x52, offset 0x1480 + 0x1490: 0x0001, 0x1491: 0x0001, + 0x1492: 0x0001, 0x1493: 0x0001, 0x1494: 0x0001, 0x1495: 0x0001, 0x1496: 0x0001, 0x1497: 0x0001, + 0x1498: 0x0001, 0x1499: 0x0001, 0x149a: 0x0001, 0x149b: 0x0001, 0x149c: 0x0001, 0x149d: 0x0001, + 0x149e: 0x0001, 0x149f: 0x0001, 0x14a0: 0x0001, 0x14a1: 0x0001, 0x14a2: 0x0001, 0x14a3: 0x0001, + 0x14a4: 0x0001, 0x14a5: 0x0001, 0x14a6: 0x0001, 0x14a7: 0x0001, 0x14a8: 0x0001, 0x14a9: 0x0001, + 0x14aa: 0x0001, 0x14ab: 0x0001, 0x14ac: 0x0001, 0x14ad: 0x0001, 0x14ae: 0x0001, 0x14af: 0x0001, + 0x14b0: 0x0001, + // Block 0x53, offset 0x14c0 + 0x14c3: 0x0003, 0x14c5: 0x0003, + 0x14c9: 0x0003, + 0x14d3: 0x0003, 0x14d6: 0x0003, + 0x14e1: 0x0003, 0x14e2: 0x0003, + 0x14e6: 0x0003, + 0x14eb: 0x0003, + // Block 0x54, offset 0x1500 + 0x1513: 0x0003, 0x1514: 0x0003, + 0x151b: 0x0003, 0x151c: 0x0003, 0x151d: 0x0003, + 0x151e: 0x0003, 0x1520: 0x0003, 0x1521: 0x0003, 0x1522: 0x0003, 0x1523: 0x0003, + 0x1524: 0x0003, 0x1525: 0x0003, 0x1526: 0x0003, 0x1527: 0x0003, 0x1528: 0x0003, 0x1529: 0x0003, + 0x152a: 0x0003, 0x152b: 0x0003, + 0x1530: 0x0003, 0x1531: 0x0003, 0x1532: 0x0003, 0x1533: 0x0003, 0x1534: 0x0003, 0x1535: 0x0003, + 0x1536: 0x0003, 0x1537: 0x0003, 0x1538: 0x0003, 0x1539: 0x0003, + // Block 0x55, offset 0x1540 + 0x1549: 0x0003, + 0x1550: 0x0003, 0x1551: 0x0003, + 0x1552: 0x0003, 0x1553: 0x0003, 0x1554: 0x0003, 0x1555: 0x0003, 0x1556: 0x0003, 0x1557: 0x0003, + 0x1558: 0x0003, 0x1559: 0x0003, + 0x1578: 0x0003, 0x1579: 0x0003, + // Block 0x56, offset 0x1580 + 0x1592: 0x0003, 0x1594: 0x0003, + 0x15a7: 0x0003, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x0003, 0x15c2: 0x0003, 0x15c3: 0x0003, + 0x15c7: 0x0003, 0x15c8: 0x0003, 0x15cb: 0x0003, + 0x15cf: 0x0003, 0x15d1: 0x0003, + 0x15d5: 0x0003, + 0x15da: 0x0003, 0x15dd: 0x0003, + 0x15de: 0x0003, 0x15df: 0x0003, 0x15e0: 0x0003, 0x15e3: 0x0003, + 0x15e5: 0x0003, 0x15e7: 0x0003, 0x15e8: 0x0003, 0x15e9: 0x0003, + 0x15ea: 0x0003, 0x15eb: 0x0003, 0x15ec: 0x0003, 0x15ee: 0x0003, + 0x15f4: 0x0003, 0x15f5: 0x0003, + 0x15f6: 0x0003, 0x15f7: 0x0003, + 0x15fc: 0x0003, 0x15fd: 0x0003, + // Block 0x58, offset 0x1600 + 0x1608: 0x0003, + 0x160c: 0x0003, + 0x1612: 0x0003, + 0x1620: 0x0003, 0x1621: 0x0003, + 0x1624: 0x0003, 0x1625: 0x0003, 0x1626: 0x0003, 0x1627: 0x0003, + 0x162a: 0x0003, 0x162b: 0x0003, 0x162e: 0x0003, 0x162f: 0x0003, + // Block 0x59, offset 0x1640 + 0x1642: 0x0003, 0x1643: 0x0003, + 0x1646: 0x0003, 0x1647: 0x0003, + 0x1655: 0x0003, + 0x1659: 0x0003, + 0x1665: 0x0003, + 0x167f: 0x0003, + // Block 0x5a, offset 0x1680 + 0x1692: 0x0003, + 0x169a: 0x0002, 0x169b: 0x0002, + 0x16a9: 0x0002, + 0x16aa: 0x0002, + // Block 0x5b, offset 0x16c0 + 0x16e9: 0x0002, + 0x16ea: 0x0002, 0x16eb: 0x0002, 0x16ec: 0x0002, + 0x16f0: 0x0002, 0x16f3: 0x0002, + // Block 0x5c, offset 0x1700 + 0x1720: 0x0003, 0x1721: 0x0003, 0x1722: 0x0003, 0x1723: 0x0003, + 0x1724: 0x0003, 0x1725: 0x0003, 0x1726: 0x0003, 0x1727: 0x0003, 0x1728: 0x0003, 0x1729: 0x0003, + 0x172a: 0x0003, 0x172b: 0x0003, 0x172c: 0x0003, 0x172d: 0x0003, 0x172e: 0x0003, 0x172f: 0x0003, + 0x1730: 0x0003, 0x1731: 0x0003, 0x1732: 0x0003, 0x1733: 0x0003, 0x1734: 0x0003, 0x1735: 0x0003, + 0x1736: 0x0003, 0x1737: 0x0003, 0x1738: 0x0003, 0x1739: 0x0003, 0x173a: 0x0003, 0x173b: 0x0003, + 0x173c: 0x0003, 0x173d: 0x0003, 0x173e: 0x0003, 0x173f: 0x0003, + // Block 0x5d, offset 0x1740 + 0x1740: 0x0003, 0x1741: 0x0003, 0x1742: 0x0003, 0x1743: 0x0003, 0x1744: 0x0003, 0x1745: 0x0003, + 0x1746: 0x0003, 0x1747: 0x0003, 0x1748: 0x0003, 0x1749: 0x0003, 0x174a: 0x0003, 0x174b: 0x0003, + 0x174c: 0x0003, 0x174d: 0x0003, 0x174e: 0x0003, 0x174f: 0x0003, 0x1750: 0x0003, 0x1751: 0x0003, + 0x1752: 0x0003, 0x1753: 0x0003, 0x1754: 0x0003, 0x1755: 0x0003, 0x1756: 0x0003, 0x1757: 0x0003, + 0x1758: 0x0003, 0x1759: 0x0003, 0x175a: 0x0003, 0x175b: 0x0003, 0x175c: 0x0003, 0x175d: 0x0003, + 0x175e: 0x0003, 0x175f: 0x0003, 0x1760: 0x0003, 0x1761: 0x0003, 0x1762: 0x0003, 0x1763: 0x0003, + 0x1764: 0x0003, 0x1765: 0x0003, 0x1766: 0x0003, 0x1767: 0x0003, 0x1768: 0x0003, 0x1769: 0x0003, + 0x176a: 0x0003, 0x176b: 0x0003, 0x176c: 0x0003, 0x176d: 0x0003, 0x176e: 0x0003, 0x176f: 0x0003, + 0x1770: 0x0003, 0x1771: 0x0003, 0x1772: 0x0003, 0x1773: 0x0003, 0x1774: 0x0003, 0x1775: 0x0003, + 0x1776: 0x0003, 0x1777: 0x0003, 0x1778: 0x0003, 0x1779: 0x0003, 0x177a: 0x0003, 0x177b: 0x0003, + 0x177c: 0x0003, 0x177d: 0x0003, 0x177e: 0x0003, 0x177f: 0x0003, + // Block 0x5e, offset 0x1780 + 0x1780: 0x0003, 0x1781: 0x0003, 0x1782: 0x0003, 0x1783: 0x0003, 0x1784: 0x0003, 0x1785: 0x0003, + 0x1786: 0x0003, 0x1787: 0x0003, 0x1788: 0x0003, 0x1789: 0x0003, 0x178a: 0x0003, 0x178b: 0x0003, + 0x178c: 0x0003, 0x178d: 0x0003, 0x178e: 0x0003, 0x178f: 0x0003, 0x1790: 0x0003, 0x1791: 0x0003, + 0x1792: 0x0003, 0x1793: 0x0003, 0x1794: 0x0003, 0x1795: 0x0003, 0x1796: 0x0003, 0x1797: 0x0003, + 0x1798: 0x0003, 0x1799: 0x0003, 0x179a: 0x0003, 0x179b: 0x0003, 0x179c: 0x0003, 0x179d: 0x0003, + 0x179e: 0x0003, 0x179f: 0x0003, 0x17a0: 0x0003, 0x17a1: 0x0003, 0x17a2: 0x0003, 0x17a3: 0x0003, + 0x17a4: 0x0003, 0x17a5: 0x0003, 0x17a6: 0x0003, 0x17a7: 0x0003, 0x17a8: 0x0003, 0x17a9: 0x0003, + 0x17ab: 0x0003, 0x17ac: 0x0003, 0x17ad: 0x0003, 0x17ae: 0x0003, 0x17af: 0x0003, + 0x17b0: 0x0003, 0x17b1: 0x0003, 0x17b2: 0x0003, 0x17b3: 0x0003, 0x17b4: 0x0003, 0x17b5: 0x0003, + 0x17b6: 0x0003, 0x17b7: 0x0003, 0x17b8: 0x0003, 0x17b9: 0x0003, 0x17ba: 0x0003, 0x17bb: 0x0003, + 0x17bc: 0x0003, 0x17bd: 0x0003, 0x17be: 0x0003, 0x17bf: 0x0003, + // Block 0x5f, offset 0x17c0 + 0x17c0: 0x0003, 0x17c1: 0x0003, 0x17c2: 0x0003, 0x17c3: 0x0003, 0x17c4: 0x0003, 0x17c5: 0x0003, + 0x17c6: 0x0003, 0x17c7: 0x0003, 0x17c8: 0x0003, 0x17c9: 0x0003, 0x17ca: 0x0003, 0x17cb: 0x0003, + 0x17d0: 0x0003, 0x17d1: 0x0003, + 0x17d2: 0x0003, 0x17d3: 0x0003, 0x17d4: 0x0003, 0x17d5: 0x0003, 0x17d6: 0x0003, 0x17d7: 0x0003, + 0x17d8: 0x0003, 0x17d9: 0x0003, 0x17da: 0x0003, 0x17db: 0x0003, 0x17dc: 0x0003, 0x17dd: 0x0003, + 0x17de: 0x0003, 0x17df: 0x0003, 0x17e0: 0x0003, 0x17e1: 0x0003, 0x17e2: 0x0003, 0x17e3: 0x0003, + 0x17e4: 0x0003, 0x17e5: 0x0003, 0x17e6: 0x0003, 0x17e7: 0x0003, 0x17e8: 0x0003, 0x17e9: 0x0003, + 0x17ea: 0x0003, 0x17eb: 0x0003, 0x17ec: 0x0003, 0x17ed: 0x0003, 0x17ee: 0x0003, 0x17ef: 0x0003, + 0x17f0: 0x0003, 0x17f1: 0x0003, 0x17f2: 0x0003, 0x17f3: 0x0003, + // Block 0x60, offset 0x1800 + 0x1800: 0x0003, 0x1801: 0x0003, 0x1802: 0x0003, 0x1803: 0x0003, 0x1804: 0x0003, 0x1805: 0x0003, + 0x1806: 0x0003, 0x1807: 0x0003, 0x1808: 0x0003, 0x1809: 0x0003, 0x180a: 0x0003, 0x180b: 0x0003, + 0x180c: 0x0003, 0x180d: 0x0003, 0x180e: 0x0003, 0x180f: 0x0003, + 0x1812: 0x0003, 0x1813: 0x0003, 0x1814: 0x0003, 0x1815: 0x0003, + 0x1820: 0x0003, 0x1821: 0x0003, 0x1823: 0x0003, + 0x1824: 0x0003, 0x1825: 0x0003, 0x1826: 0x0003, 0x1827: 0x0003, 0x1828: 0x0003, 0x1829: 0x0003, + 0x1832: 0x0003, 0x1833: 0x0003, + 0x1836: 0x0003, 0x1837: 0x0003, + 0x183c: 0x0003, 0x183d: 0x0003, + // Block 0x61, offset 0x1840 + 0x1840: 0x0003, 0x1841: 0x0003, + 0x1846: 0x0003, 0x1847: 0x0003, 0x1848: 0x0003, 0x184b: 0x0003, + 0x184e: 0x0003, 0x184f: 0x0003, 0x1850: 0x0003, 0x1851: 0x0003, + 0x1862: 0x0003, 0x1863: 0x0003, + 0x1864: 0x0003, 0x1865: 0x0003, + 0x186f: 0x0003, + 0x187d: 0x0002, 0x187e: 0x0002, + // Block 0x62, offset 0x1880 + 0x1885: 0x0003, + 0x1886: 0x0003, 0x1889: 0x0003, + 0x188e: 0x0003, 0x188f: 0x0003, + 0x1894: 0x0002, 0x1895: 0x0002, + 0x189c: 0x0003, + 0x189e: 0x0003, + 0x18b0: 0x0002, 0x18b1: 0x0002, 0x18b2: 0x0002, 0x18b3: 0x0002, 0x18b4: 0x0002, 0x18b5: 0x0002, + 0x18b6: 0x0002, 0x18b7: 0x0002, + // Block 0x63, offset 0x18c0 + 0x18c0: 0x0003, 0x18c2: 0x0003, + 0x18c8: 0x0002, 0x18c9: 0x0002, 0x18ca: 0x0002, 0x18cb: 0x0002, + 0x18cc: 0x0002, 0x18cd: 0x0002, 0x18ce: 0x0002, 0x18cf: 0x0002, 0x18d0: 0x0002, 0x18d1: 0x0002, + 0x18d2: 0x0002, 0x18d3: 0x0002, + 0x18e0: 0x0003, 0x18e1: 0x0003, 0x18e3: 0x0003, + 0x18e4: 0x0003, 0x18e5: 0x0003, 0x18e7: 0x0003, 0x18e8: 0x0003, 0x18e9: 0x0003, + 0x18ea: 0x0003, 0x18ec: 0x0003, 0x18ed: 0x0003, 0x18ef: 0x0003, + 0x18ff: 0x0002, + // Block 0x64, offset 0x1900 + 0x190a: 0x0002, 0x190b: 0x0002, + 0x190c: 0x0002, 0x190d: 0x0002, 0x190e: 0x0002, 0x190f: 0x0002, + 0x1913: 0x0002, + 0x191e: 0x0003, 0x191f: 0x0003, 0x1921: 0x0002, + 0x192a: 0x0002, 0x192b: 0x0002, + 0x193d: 0x0002, 0x193e: 0x0002, 0x193f: 0x0003, + // Block 0x65, offset 0x1940 + 0x1944: 0x0002, 0x1945: 0x0002, + 0x1946: 0x0003, 0x1947: 0x0003, 0x1948: 0x0003, 0x1949: 0x0003, 0x194a: 0x0003, 0x194b: 0x0003, + 0x194c: 0x0003, 0x194d: 0x0003, 0x194e: 0x0002, 0x194f: 0x0003, 0x1950: 0x0003, 0x1951: 0x0003, + 0x1952: 0x0003, 0x1953: 0x0003, 0x1954: 0x0002, 0x1955: 0x0003, 0x1956: 0x0003, 0x1957: 0x0003, + 0x1958: 0x0003, 0x1959: 0x0003, 0x195a: 0x0003, 0x195b: 0x0003, 0x195c: 0x0003, 0x195d: 0x0003, + 0x195e: 0x0003, 0x195f: 0x0003, 0x1960: 0x0003, 0x1961: 0x0003, 0x1963: 0x0003, + 0x1968: 0x0003, 0x1969: 0x0003, + 0x196a: 0x0002, 0x196b: 0x0003, 0x196c: 0x0003, 0x196d: 0x0003, 0x196e: 0x0003, 0x196f: 0x0003, + 0x1970: 0x0003, 0x1971: 0x0003, 0x1972: 0x0002, 0x1973: 0x0002, 0x1974: 0x0003, 0x1975: 0x0002, + 0x1976: 0x0003, 0x1977: 0x0003, 0x1978: 0x0003, 0x1979: 0x0003, 0x197a: 0x0002, 0x197b: 0x0003, + 0x197c: 0x0003, 0x197d: 0x0002, 0x197e: 0x0003, 0x197f: 0x0003, + // Block 0x66, offset 0x1980 + 0x1985: 0x0002, + 0x198a: 0x0002, 0x198b: 0x0002, + 0x19a8: 0x0002, + 0x19bd: 0x0003, + // Block 0x67, offset 0x19c0 + 0x19cc: 0x0002, 0x19ce: 0x0002, + 0x19d3: 0x0002, 0x19d4: 0x0002, 0x19d5: 0x0002, 0x19d7: 0x0002, + 0x19f6: 0x0003, 0x19f7: 0x0003, 0x19f8: 0x0003, 0x19f9: 0x0003, 0x19fa: 0x0003, 0x19fb: 0x0003, + 0x19fc: 0x0003, 0x19fd: 0x0003, 0x19fe: 0x0003, 0x19ff: 0x0003, + // Block 0x68, offset 0x1a00 + 0x1a15: 0x0002, 0x1a16: 0x0002, 0x1a17: 0x0002, + 0x1a30: 0x0002, + 0x1a3f: 0x0002, + // Block 0x69, offset 0x1a40 + 0x1a5b: 0x0002, 0x1a5c: 0x0002, + // Block 0x6a, offset 0x1a80 + 0x1a90: 0x0002, + 0x1a95: 0x0002, 0x1a96: 0x0003, 0x1a97: 0x0003, + 0x1a98: 0x0003, 0x1a99: 0x0003, + // Block 0x6b, offset 0x1ac0 + 0x1aef: 0x0001, + 0x1af0: 0x0001, 0x1af1: 0x0001, + // Block 0x6c, offset 0x1b00 + 0x1b3f: 0x0001, + // Block 0x6d, offset 0x1b40 + 0x1b60: 0x0001, 0x1b61: 0x0001, 0x1b62: 0x0001, 0x1b63: 0x0001, + 0x1b64: 0x0001, 0x1b65: 0x0001, 0x1b66: 0x0001, 0x1b67: 0x0001, 0x1b68: 0x0001, 0x1b69: 0x0001, + 0x1b6a: 0x0001, 0x1b6b: 0x0001, 0x1b6c: 0x0001, 0x1b6d: 0x0001, 0x1b6e: 0x0001, 0x1b6f: 0x0001, + 0x1b70: 0x0001, 0x1b71: 0x0001, 0x1b72: 0x0001, 0x1b73: 0x0001, 0x1b74: 0x0001, 0x1b75: 0x0001, + 0x1b76: 0x0001, 0x1b77: 0x0001, 0x1b78: 0x0001, 0x1b79: 0x0001, 0x1b7a: 0x0001, 0x1b7b: 0x0001, + 0x1b7c: 0x0001, 0x1b7d: 0x0001, 0x1b7e: 0x0001, 0x1b7f: 0x0001, + // Block 0x6e, offset 0x1b80 + 0x1b80: 0x0002, 0x1b81: 0x0002, 0x1b82: 0x0002, 0x1b83: 0x0002, 0x1b84: 0x0002, 0x1b85: 0x0002, + 0x1b86: 0x0002, 0x1b87: 0x0002, 0x1b88: 0x0002, 0x1b89: 0x0002, 0x1b8a: 0x0002, 0x1b8b: 0x0002, + 0x1b8c: 0x0002, 0x1b8d: 0x0002, 0x1b8e: 0x0002, 0x1b8f: 0x0002, 0x1b90: 0x0002, 0x1b91: 0x0002, + 0x1b92: 0x0002, 0x1b93: 0x0002, 0x1b94: 0x0002, 0x1b95: 0x0002, 0x1b96: 0x0002, 0x1b97: 0x0002, + 0x1b98: 0x0002, 0x1b99: 0x0002, 0x1b9b: 0x0002, 0x1b9c: 0x0002, 0x1b9d: 0x0002, + 0x1b9e: 0x0002, 0x1b9f: 0x0002, 0x1ba0: 0x0002, 0x1ba1: 0x0002, 0x1ba2: 0x0002, 0x1ba3: 0x0002, + 0x1ba4: 0x0002, 0x1ba5: 0x0002, 0x1ba6: 0x0002, 0x1ba7: 0x0002, 0x1ba8: 0x0002, 0x1ba9: 0x0002, + 0x1baa: 0x0002, 0x1bab: 0x0002, 0x1bac: 0x0002, 0x1bad: 0x0002, 0x1bae: 0x0002, 0x1baf: 0x0002, + 0x1bb0: 0x0002, 0x1bb1: 0x0002, 0x1bb2: 0x0002, 0x1bb3: 0x0002, 0x1bb4: 0x0002, 0x1bb5: 0x0002, + 0x1bb6: 0x0002, 0x1bb7: 0x0002, 0x1bb8: 0x0002, 0x1bb9: 0x0002, 0x1bba: 0x0002, 0x1bbb: 0x0002, + 0x1bbc: 0x0002, 0x1bbd: 0x0002, 0x1bbe: 0x0002, 0x1bbf: 0x0002, + // Block 0x6f, offset 0x1bc0 + 0x1bc0: 0x0002, 0x1bc1: 0x0002, 0x1bc2: 0x0002, 0x1bc3: 0x0002, 0x1bc4: 0x0002, 0x1bc5: 0x0002, + 0x1bc6: 0x0002, 0x1bc7: 0x0002, 0x1bc8: 0x0002, 0x1bc9: 0x0002, 0x1bca: 0x0002, 0x1bcb: 0x0002, + 0x1bcc: 0x0002, 0x1bcd: 0x0002, 0x1bce: 0x0002, 0x1bcf: 0x0002, 0x1bd0: 0x0002, 0x1bd1: 0x0002, + 0x1bd2: 0x0002, 0x1bd3: 0x0002, 0x1bd4: 0x0002, 0x1bd5: 0x0002, 0x1bd6: 0x0002, 0x1bd7: 0x0002, + 0x1bd8: 0x0002, 0x1bd9: 0x0002, 0x1bda: 0x0002, 0x1bdb: 0x0002, 0x1bdc: 0x0002, 0x1bdd: 0x0002, + 0x1bde: 0x0002, 0x1bdf: 0x0002, 0x1be0: 0x0002, 0x1be1: 0x0002, 0x1be2: 0x0002, 0x1be3: 0x0002, + 0x1be4: 0x0002, 0x1be5: 0x0002, 0x1be6: 0x0002, 0x1be7: 0x0002, 0x1be8: 0x0002, 0x1be9: 0x0002, + 0x1bea: 0x0002, 0x1beb: 0x0002, 0x1bec: 0x0002, 0x1bed: 0x0002, 0x1bee: 0x0002, 0x1bef: 0x0002, + 0x1bf0: 0x0002, 0x1bf1: 0x0002, 0x1bf2: 0x0002, 0x1bf3: 0x0002, + // Block 0x70, offset 0x1c00 + 0x1c00: 0x0002, 0x1c01: 0x0002, 0x1c02: 0x0002, 0x1c03: 0x0002, 0x1c04: 0x0002, 0x1c05: 0x0002, + 0x1c06: 0x0002, 0x1c07: 0x0002, 0x1c08: 0x0002, 0x1c09: 0x0002, 0x1c0a: 0x0002, 0x1c0b: 0x0002, + 0x1c0c: 0x0002, 0x1c0d: 0x0002, 0x1c0e: 0x0002, 0x1c0f: 0x0002, 0x1c10: 0x0002, 0x1c11: 0x0002, + 0x1c12: 0x0002, 0x1c13: 0x0002, 0x1c14: 0x0002, 0x1c15: 0x0002, + 0x1c30: 0x0002, 0x1c31: 0x0002, 0x1c32: 0x0002, 0x1c33: 0x0002, 0x1c34: 0x0002, 0x1c35: 0x0002, + 0x1c36: 0x0002, 0x1c37: 0x0002, 0x1c38: 0x0002, 0x1c39: 0x0002, 0x1c3a: 0x0002, 0x1c3b: 0x0002, + 0x1c3c: 0x0002, 0x1c3d: 0x0002, 0x1c3e: 0x0002, 0x1c3f: 0x0002, + // Block 0x71, offset 0x1c40 + 0x1c40: 0x0002, 0x1c41: 0x0002, 0x1c42: 0x0002, 0x1c43: 0x0002, 0x1c44: 0x0002, 0x1c45: 0x0002, + 0x1c46: 0x0002, 0x1c47: 0x0002, 0x1c48: 0x0002, 0x1c49: 0x0002, 0x1c4a: 0x0002, 0x1c4b: 0x0002, + 0x1c4c: 0x0002, 0x1c4d: 0x0002, 0x1c4e: 0x0002, 0x1c4f: 0x0002, 0x1c50: 0x0002, 0x1c51: 0x0002, + 0x1c52: 0x0002, 0x1c53: 0x0002, 0x1c54: 0x0002, 0x1c55: 0x0002, 0x1c56: 0x0002, 0x1c57: 0x0002, + 0x1c58: 0x0002, 0x1c59: 0x0002, 0x1c5a: 0x0002, 0x1c5b: 0x0002, 0x1c5c: 0x0002, 0x1c5d: 0x0002, + 0x1c5e: 0x0002, 0x1c5f: 0x0002, 0x1c60: 0x0002, 0x1c61: 0x0002, 0x1c62: 0x0002, 0x1c63: 0x0002, + 0x1c64: 0x0002, 0x1c65: 0x0002, 0x1c66: 0x0002, 0x1c67: 0x0002, 0x1c68: 0x0002, 0x1c69: 0x0002, + 0x1c6a: 0x0001, 0x1c6b: 0x0001, 0x1c6c: 0x0001, 0x1c6d: 0x0001, 0x1c6e: 0x0002, 0x1c6f: 0x0002, + 0x1c70: 0x0002, 0x1c71: 0x0002, 0x1c72: 0x0002, 0x1c73: 0x0002, 0x1c74: 0x0002, 0x1c75: 0x0002, + 0x1c76: 0x0002, 0x1c77: 0x0002, 0x1c78: 0x0002, 0x1c79: 0x0002, 0x1c7a: 0x0002, 0x1c7b: 0x0002, + 0x1c7c: 0x0002, 0x1c7d: 0x0002, 0x1c7e: 0x0002, + // Block 0x72, offset 0x1c80 + 0x1c81: 0x0002, 0x1c82: 0x0002, 0x1c83: 0x0002, 0x1c84: 0x0002, 0x1c85: 0x0002, + 0x1c86: 0x0002, 0x1c87: 0x0002, 0x1c88: 0x0002, 0x1c89: 0x0002, 0x1c8a: 0x0002, 0x1c8b: 0x0002, + 0x1c8c: 0x0002, 0x1c8d: 0x0002, 0x1c8e: 0x0002, 0x1c8f: 0x0002, 0x1c90: 0x0002, 0x1c91: 0x0002, + 0x1c92: 0x0002, 0x1c93: 0x0002, 0x1c94: 0x0002, 0x1c95: 0x0002, 0x1c96: 0x0002, 0x1c97: 0x0002, + 0x1c98: 0x0002, 0x1c99: 0x0002, 0x1c9a: 0x0002, 0x1c9b: 0x0002, 0x1c9c: 0x0002, 0x1c9d: 0x0002, + 0x1c9e: 0x0002, 0x1c9f: 0x0002, 0x1ca0: 0x0002, 0x1ca1: 0x0002, 0x1ca2: 0x0002, 0x1ca3: 0x0002, + 0x1ca4: 0x0002, 0x1ca5: 0x0002, 0x1ca6: 0x0002, 0x1ca7: 0x0002, 0x1ca8: 0x0002, 0x1ca9: 0x0002, + 0x1caa: 0x0002, 0x1cab: 0x0002, 0x1cac: 0x0002, 0x1cad: 0x0002, 0x1cae: 0x0002, 0x1caf: 0x0002, + 0x1cb0: 0x0002, 0x1cb1: 0x0002, 0x1cb2: 0x0002, 0x1cb3: 0x0002, 0x1cb4: 0x0002, 0x1cb5: 0x0002, + 0x1cb6: 0x0002, 0x1cb7: 0x0002, 0x1cb8: 0x0002, 0x1cb9: 0x0002, 0x1cba: 0x0002, 0x1cbb: 0x0002, + 0x1cbc: 0x0002, 0x1cbd: 0x0002, 0x1cbe: 0x0002, 0x1cbf: 0x0002, + // Block 0x73, offset 0x1cc0 + 0x1cc0: 0x0002, 0x1cc1: 0x0002, 0x1cc2: 0x0002, 0x1cc3: 0x0002, 0x1cc4: 0x0002, 0x1cc5: 0x0002, + 0x1cc6: 0x0002, 0x1cc7: 0x0002, 0x1cc8: 0x0002, 0x1cc9: 0x0002, 0x1cca: 0x0002, 0x1ccb: 0x0002, + 0x1ccc: 0x0002, 0x1ccd: 0x0002, 0x1cce: 0x0002, 0x1ccf: 0x0002, 0x1cd0: 0x0002, 0x1cd1: 0x0002, + 0x1cd2: 0x0002, 0x1cd3: 0x0002, 0x1cd4: 0x0002, 0x1cd5: 0x0002, 0x1cd6: 0x0002, + 0x1cd9: 0x0001, 0x1cda: 0x0001, 0x1cdb: 0x0002, 0x1cdc: 0x0002, 0x1cdd: 0x0002, + 0x1cde: 0x0002, 0x1cdf: 0x0002, 0x1ce0: 0x0002, 0x1ce1: 0x0002, 0x1ce2: 0x0002, 0x1ce3: 0x0002, + 0x1ce4: 0x0002, 0x1ce5: 0x0002, 0x1ce6: 0x0002, 0x1ce7: 0x0002, 0x1ce8: 0x0002, 0x1ce9: 0x0002, + 0x1cea: 0x0002, 0x1ceb: 0x0002, 0x1cec: 0x0002, 0x1ced: 0x0002, 0x1cee: 0x0002, 0x1cef: 0x0002, + 0x1cf0: 0x0002, 0x1cf1: 0x0002, 0x1cf2: 0x0002, 0x1cf3: 0x0002, 0x1cf4: 0x0002, 0x1cf5: 0x0002, + 0x1cf6: 0x0002, 0x1cf7: 0x0002, 0x1cf8: 0x0002, 0x1cf9: 0x0002, 0x1cfa: 0x0002, 0x1cfb: 0x0002, + 0x1cfc: 0x0002, 0x1cfd: 0x0002, 0x1cfe: 0x0002, 0x1cff: 0x0002, + // Block 0x74, offset 0x1d00 + 0x1d05: 0x0002, + 0x1d06: 0x0002, 0x1d07: 0x0002, 0x1d08: 0x0002, 0x1d09: 0x0002, 0x1d0a: 0x0002, 0x1d0b: 0x0002, + 0x1d0c: 0x0002, 0x1d0d: 0x0002, 0x1d0e: 0x0002, 0x1d0f: 0x0002, 0x1d10: 0x0002, 0x1d11: 0x0002, + 0x1d12: 0x0002, 0x1d13: 0x0002, 0x1d14: 0x0002, 0x1d15: 0x0002, 0x1d16: 0x0002, 0x1d17: 0x0002, + 0x1d18: 0x0002, 0x1d19: 0x0002, 0x1d1a: 0x0002, 0x1d1b: 0x0002, 0x1d1c: 0x0002, 0x1d1d: 0x0002, + 0x1d1e: 0x0002, 0x1d1f: 0x0002, 0x1d20: 0x0002, 0x1d21: 0x0002, 0x1d22: 0x0002, 0x1d23: 0x0002, + 0x1d24: 0x0002, 0x1d25: 0x0002, 0x1d26: 0x0002, 0x1d27: 0x0002, 0x1d28: 0x0002, 0x1d29: 0x0002, + 0x1d2a: 0x0002, 0x1d2b: 0x0002, 0x1d2c: 0x0002, 0x1d2d: 0x0002, 0x1d2e: 0x0002, 0x1d2f: 0x0002, + 0x1d31: 0x0002, 0x1d32: 0x0002, 0x1d33: 0x0002, 0x1d34: 0x0002, 0x1d35: 0x0002, + 0x1d36: 0x0002, 0x1d37: 0x0002, 0x1d38: 0x0002, 0x1d39: 0x0002, 0x1d3a: 0x0002, 0x1d3b: 0x0002, + 0x1d3c: 0x0002, 0x1d3d: 0x0002, 0x1d3e: 0x0002, 0x1d3f: 0x0002, + // Block 0x75, offset 0x1d40 + 0x1d40: 0x0002, 0x1d41: 0x0002, 0x1d42: 0x0002, 0x1d43: 0x0002, 0x1d44: 0x0002, 0x1d45: 0x0002, + 0x1d46: 0x0002, 0x1d47: 0x0002, 0x1d48: 0x0002, 0x1d49: 0x0002, 0x1d4a: 0x0002, 0x1d4b: 0x0002, + 0x1d4c: 0x0002, 0x1d4d: 0x0002, 0x1d4e: 0x0002, 0x1d50: 0x0002, 0x1d51: 0x0002, + 0x1d52: 0x0002, 0x1d53: 0x0002, 0x1d54: 0x0002, 0x1d55: 0x0002, 0x1d56: 0x0002, 0x1d57: 0x0002, + 0x1d58: 0x0002, 0x1d59: 0x0002, 0x1d5a: 0x0002, 0x1d5b: 0x0002, 0x1d5c: 0x0002, 0x1d5d: 0x0002, + 0x1d5e: 0x0002, 0x1d5f: 0x0002, 0x1d60: 0x0002, 0x1d61: 0x0002, 0x1d62: 0x0002, 0x1d63: 0x0002, + 0x1d64: 0x0002, 0x1d65: 0x0002, 0x1d66: 0x0002, 0x1d67: 0x0002, 0x1d68: 0x0002, 0x1d69: 0x0002, + 0x1d6a: 0x0002, 0x1d6b: 0x0002, 0x1d6c: 0x0002, 0x1d6d: 0x0002, 0x1d6e: 0x0002, 0x1d6f: 0x0002, + 0x1d70: 0x0002, 0x1d71: 0x0002, 0x1d72: 0x0002, 0x1d73: 0x0002, 0x1d74: 0x0002, 0x1d75: 0x0002, + 0x1d76: 0x0002, 0x1d77: 0x0002, 0x1d78: 0x0002, 0x1d79: 0x0002, 0x1d7a: 0x0002, 0x1d7b: 0x0002, + 0x1d7c: 0x0002, 0x1d7d: 0x0002, 0x1d7e: 0x0002, 0x1d7f: 0x0002, + // Block 0x76, offset 0x1d80 + 0x1d80: 0x0002, 0x1d81: 0x0002, 0x1d82: 0x0002, 0x1d83: 0x0002, 0x1d84: 0x0002, 0x1d85: 0x0002, + 0x1d86: 0x0002, 0x1d87: 0x0002, 0x1d88: 0x0002, 0x1d89: 0x0002, 0x1d8a: 0x0002, 0x1d8b: 0x0002, + 0x1d8c: 0x0002, 0x1d8d: 0x0002, 0x1d8e: 0x0002, 0x1d8f: 0x0002, 0x1d90: 0x0002, 0x1d91: 0x0002, + 0x1d92: 0x0002, 0x1d93: 0x0002, 0x1d94: 0x0002, 0x1d95: 0x0002, 0x1d96: 0x0002, 0x1d97: 0x0002, + 0x1d98: 0x0002, 0x1d99: 0x0002, 0x1d9a: 0x0002, 0x1d9b: 0x0002, 0x1d9c: 0x0002, 0x1d9d: 0x0002, + 0x1d9e: 0x0002, 0x1d9f: 0x0002, 0x1da0: 0x0002, 0x1da1: 0x0002, 0x1da2: 0x0002, 0x1da3: 0x0002, + 0x1da4: 0x0002, 0x1da5: 0x0002, + 0x1daf: 0x0002, + 0x1db0: 0x0002, 0x1db1: 0x0002, 0x1db2: 0x0002, 0x1db3: 0x0002, 0x1db4: 0x0002, 0x1db5: 0x0002, + 0x1db6: 0x0002, 0x1db7: 0x0002, 0x1db8: 0x0002, 0x1db9: 0x0002, 0x1dba: 0x0002, 0x1dbb: 0x0002, + 0x1dbc: 0x0002, 0x1dbd: 0x0002, 0x1dbe: 0x0002, 0x1dbf: 0x0002, + // Block 0x77, offset 0x1dc0 + 0x1dc0: 0x0002, 0x1dc1: 0x0002, 0x1dc2: 0x0002, 0x1dc3: 0x0002, 0x1dc4: 0x0002, 0x1dc5: 0x0002, + 0x1dc6: 0x0002, 0x1dc7: 0x0002, 0x1dc8: 0x0002, 0x1dc9: 0x0002, 0x1dca: 0x0002, 0x1dcb: 0x0002, + 0x1dcc: 0x0002, 0x1dcd: 0x0002, 0x1dce: 0x0002, 0x1dcf: 0x0002, 0x1dd0: 0x0002, 0x1dd1: 0x0002, + 0x1dd2: 0x0002, 0x1dd3: 0x0002, 0x1dd4: 0x0002, 0x1dd5: 0x0002, 0x1dd6: 0x0002, 0x1dd7: 0x0002, + 0x1dd8: 0x0002, 0x1dd9: 0x0002, 0x1dda: 0x0002, 0x1ddb: 0x0002, 0x1ddc: 0x0002, 0x1ddd: 0x0002, + 0x1dde: 0x0002, 0x1de0: 0x0002, 0x1de1: 0x0002, 0x1de2: 0x0002, 0x1de3: 0x0002, + 0x1de4: 0x0002, 0x1de5: 0x0002, 0x1de6: 0x0002, 0x1de7: 0x0002, 0x1de8: 0x0002, 0x1de9: 0x0002, + 0x1dea: 0x0002, 0x1deb: 0x0002, 0x1dec: 0x0002, 0x1ded: 0x0002, 0x1dee: 0x0002, 0x1def: 0x0002, + 0x1df0: 0x0002, 0x1df1: 0x0002, 0x1df2: 0x0002, 0x1df3: 0x0002, 0x1df4: 0x0002, 0x1df5: 0x0002, + 0x1df6: 0x0002, 0x1df7: 0x0002, 0x1df8: 0x0002, 0x1df9: 0x0002, 0x1dfa: 0x0002, 0x1dfb: 0x0002, + 0x1dfc: 0x0002, 0x1dfd: 0x0002, 0x1dfe: 0x0002, 0x1dff: 0x0002, + // Block 0x78, offset 0x1e00 + 0x1e00: 0x0002, 0x1e01: 0x0002, 0x1e02: 0x0002, 0x1e03: 0x0002, 0x1e04: 0x0002, 0x1e05: 0x0002, + 0x1e06: 0x0002, 0x1e07: 0x0002, 0x1e08: 0x0003, 0x1e09: 0x0003, 0x1e0a: 0x0003, 0x1e0b: 0x0003, + 0x1e0c: 0x0003, 0x1e0d: 0x0003, 0x1e0e: 0x0003, 0x1e0f: 0x0003, 0x1e10: 0x0002, 0x1e11: 0x0002, + 0x1e12: 0x0002, 0x1e13: 0x0002, 0x1e14: 0x0002, 0x1e15: 0x0002, 0x1e16: 0x0002, 0x1e17: 0x0002, + 0x1e18: 0x0002, 0x1e19: 0x0002, 0x1e1a: 0x0002, 0x1e1b: 0x0002, 0x1e1c: 0x0002, 0x1e1d: 0x0002, + 0x1e1e: 0x0002, 0x1e1f: 0x0002, 0x1e20: 0x0002, 0x1e21: 0x0002, 0x1e22: 0x0002, 0x1e23: 0x0002, + 0x1e24: 0x0002, 0x1e25: 0x0002, 0x1e26: 0x0002, 0x1e27: 0x0002, 0x1e28: 0x0002, 0x1e29: 0x0002, + 0x1e2a: 0x0002, 0x1e2b: 0x0002, 0x1e2c: 0x0002, 0x1e2d: 0x0002, 0x1e2e: 0x0002, 0x1e2f: 0x0002, + 0x1e30: 0x0002, 0x1e31: 0x0002, 0x1e32: 0x0002, 0x1e33: 0x0002, 0x1e34: 0x0002, 0x1e35: 0x0002, + 0x1e36: 0x0002, 0x1e37: 0x0002, 0x1e38: 0x0002, 0x1e39: 0x0002, 0x1e3a: 0x0002, 0x1e3b: 0x0002, + 0x1e3c: 0x0002, 0x1e3d: 0x0002, 0x1e3e: 0x0002, 0x1e3f: 0x0002, + // Block 0x79, offset 0x1e40 + 0x1e40: 0x0002, 0x1e41: 0x0002, 0x1e42: 0x0002, 0x1e43: 0x0002, 0x1e44: 0x0002, 0x1e45: 0x0002, + 0x1e46: 0x0002, 0x1e47: 0x0002, 0x1e48: 0x0002, 0x1e49: 0x0002, 0x1e4a: 0x0002, 0x1e4b: 0x0002, + 0x1e4c: 0x0002, 0x1e50: 0x0002, 0x1e51: 0x0002, + 0x1e52: 0x0002, 0x1e53: 0x0002, 0x1e54: 0x0002, 0x1e55: 0x0002, 0x1e56: 0x0002, 0x1e57: 0x0002, + 0x1e58: 0x0002, 0x1e59: 0x0002, 0x1e5a: 0x0002, 0x1e5b: 0x0002, 0x1e5c: 0x0002, 0x1e5d: 0x0002, + 0x1e5e: 0x0002, 0x1e5f: 0x0002, 0x1e60: 0x0002, 0x1e61: 0x0002, 0x1e62: 0x0002, 0x1e63: 0x0002, + 0x1e64: 0x0002, 0x1e65: 0x0002, 0x1e66: 0x0002, 0x1e67: 0x0002, 0x1e68: 0x0002, 0x1e69: 0x0002, + 0x1e6a: 0x0002, 0x1e6b: 0x0002, 0x1e6c: 0x0002, 0x1e6d: 0x0002, 0x1e6e: 0x0002, 0x1e6f: 0x0002, + 0x1e70: 0x0002, 0x1e71: 0x0002, 0x1e72: 0x0002, 0x1e73: 0x0002, 0x1e74: 0x0002, 0x1e75: 0x0002, + 0x1e76: 0x0002, 0x1e77: 0x0002, 0x1e78: 0x0002, 0x1e79: 0x0002, 0x1e7a: 0x0002, 0x1e7b: 0x0002, + 0x1e7c: 0x0002, 0x1e7d: 0x0002, 0x1e7e: 0x0002, 0x1e7f: 0x0002, + // Block 0x7a, offset 0x1e80 + 0x1e80: 0x0002, 0x1e81: 0x0002, 0x1e82: 0x0002, 0x1e83: 0x0002, 0x1e84: 0x0002, 0x1e85: 0x0002, + 0x1e86: 0x0002, + // Block 0x7b, offset 0x1ec0 + 0x1eef: 0x0001, + 0x1ef0: 0x0001, 0x1ef1: 0x0001, 0x1ef2: 0x0001, 0x1ef4: 0x0001, 0x1ef5: 0x0001, + 0x1ef6: 0x0001, 0x1ef7: 0x0001, 0x1ef8: 0x0001, 0x1ef9: 0x0001, 0x1efa: 0x0001, 0x1efb: 0x0001, + 0x1efc: 0x0001, 0x1efd: 0x0001, + // Block 0x7c, offset 0x1f00 + 0x1f1e: 0x0001, 0x1f1f: 0x0001, + // Block 0x7d, offset 0x1f40 + 0x1f70: 0x0001, 0x1f71: 0x0001, + // Block 0x7e, offset 0x1f80 + 0x1f82: 0x0001, + 0x1f86: 0x0001, 0x1f8b: 0x0001, + 0x1fa5: 0x0001, 0x1fa6: 0x0001, + 0x1fac: 0x0001, + // Block 0x7f, offset 0x1fc0 + 0x1fc4: 0x0001, 0x1fc5: 0x0001, + 0x1fe0: 0x0001, 0x1fe1: 0x0001, 0x1fe2: 0x0001, 0x1fe3: 0x0001, + 0x1fe4: 0x0001, 0x1fe5: 0x0001, 0x1fe6: 0x0001, 0x1fe7: 0x0001, 0x1fe8: 0x0001, 0x1fe9: 0x0001, + 0x1fea: 0x0001, 0x1feb: 0x0001, 0x1fec: 0x0001, 0x1fed: 0x0001, 0x1fee: 0x0001, 0x1fef: 0x0001, + 0x1ff0: 0x0001, 0x1ff1: 0x0001, + 0x1fff: 0x0001, + // Block 0x80, offset 0x2000 + 0x2026: 0x0001, 0x2027: 0x0001, 0x2028: 0x0001, 0x2029: 0x0001, + 0x202a: 0x0001, 0x202b: 0x0001, 0x202c: 0x0001, 0x202d: 0x0001, + // Block 0x81, offset 0x2040 + 0x2047: 0x0001, 0x2048: 0x0001, 0x2049: 0x0001, 0x204a: 0x0001, 0x204b: 0x0001, + 0x204c: 0x0001, 0x204d: 0x0001, 0x204e: 0x0001, 0x204f: 0x0001, 0x2050: 0x0001, 0x2051: 0x0001, + 0x2060: 0x0002, 0x2061: 0x0002, 0x2062: 0x0002, 0x2063: 0x0002, + 0x2064: 0x0002, 0x2065: 0x0002, 0x2066: 0x0002, 0x2067: 0x0002, 0x2068: 0x0002, 0x2069: 0x0002, + 0x206a: 0x0002, 0x206b: 0x0002, 0x206c: 0x0002, 0x206d: 0x0002, 0x206e: 0x0002, 0x206f: 0x0002, + 0x2070: 0x0002, 0x2071: 0x0002, 0x2072: 0x0002, 0x2073: 0x0002, 0x2074: 0x0002, 0x2075: 0x0002, + 0x2076: 0x0002, 0x2077: 0x0002, 0x2078: 0x0002, 0x2079: 0x0002, 0x207a: 0x0002, 0x207b: 0x0002, + 0x207c: 0x0002, + // Block 0x82, offset 0x2080 + 0x2080: 0x0001, 0x2081: 0x0001, 0x2082: 0x0001, + 0x20b3: 0x0001, + 0x20b6: 0x0001, 0x20b7: 0x0001, 0x20b8: 0x0001, 0x20b9: 0x0001, + 0x20bc: 0x0001, 0x20bd: 0x0001, + // Block 0x83, offset 0x20c0 + 0x20e5: 0x0001, + // Block 0x84, offset 0x2100 + 0x2129: 0x0001, + 0x212a: 0x0001, 0x212b: 0x0001, 0x212c: 0x0001, 0x212d: 0x0001, 0x212e: 0x0001, + 0x2131: 0x0001, 0x2132: 0x0001, 0x2135: 0x0001, + 0x2136: 0x0001, + // Block 0x85, offset 0x2140 + 0x2143: 0x0001, + 0x214c: 0x0001, + 0x217c: 0x0001, + // Block 0x86, offset 0x2180 + 0x21b0: 0x0001, 0x21b2: 0x0001, 0x21b3: 0x0001, 0x21b4: 0x0001, + 0x21b7: 0x0001, 0x21b8: 0x0001, + 0x21be: 0x0001, 0x21bf: 0x0001, + // Block 0x87, offset 0x21c0 + 0x21c1: 0x0001, + 0x21ec: 0x0001, 0x21ed: 0x0001, + 0x21f6: 0x0001, + // Block 0x88, offset 0x2200 + 0x2225: 0x0001, 0x2228: 0x0001, + 0x222d: 0x0001, + // Block 0x89, offset 0x2240 + 0x2240: 0x0002, 0x2241: 0x0002, 0x2242: 0x0002, 0x2243: 0x0002, 0x2244: 0x0002, 0x2245: 0x0002, + 0x2246: 0x0002, 0x2247: 0x0002, 0x2248: 0x0002, 0x2249: 0x0002, 0x224a: 0x0002, 0x224b: 0x0002, + 0x224c: 0x0002, 0x224d: 0x0002, 0x224e: 0x0002, 0x224f: 0x0002, 0x2250: 0x0002, 0x2251: 0x0002, + 0x2252: 0x0002, 0x2253: 0x0002, 0x2254: 0x0002, 0x2255: 0x0002, 0x2256: 0x0002, 0x2257: 0x0002, + 0x2258: 0x0002, 0x2259: 0x0002, 0x225a: 0x0002, 0x225b: 0x0002, 0x225c: 0x0002, 0x225d: 0x0002, + 0x225e: 0x0002, 0x225f: 0x0002, 0x2260: 0x0002, 0x2261: 0x0002, 0x2262: 0x0002, 0x2263: 0x0002, + // Block 0x8a, offset 0x2280 + 0x229e: 0x0001, + // Block 0x8b, offset 0x22c0 + 0x22c0: 0x0001, 0x22c1: 0x0001, 0x22c2: 0x0001, 0x22c3: 0x0001, 0x22c4: 0x0001, 0x22c5: 0x0001, + 0x22c6: 0x0001, 0x22c7: 0x0001, 0x22c8: 0x0001, 0x22c9: 0x0001, 0x22ca: 0x0001, 0x22cb: 0x0001, + 0x22cc: 0x0001, 0x22cd: 0x0001, 0x22ce: 0x0001, 0x22cf: 0x0001, 0x22d0: 0x0002, 0x22d1: 0x0002, + 0x22d2: 0x0002, 0x22d3: 0x0002, 0x22d4: 0x0002, 0x22d5: 0x0002, 0x22d6: 0x0002, 0x22d7: 0x0002, + 0x22d8: 0x0002, 0x22d9: 0x0002, + 0x22e0: 0x0001, 0x22e1: 0x0001, 0x22e2: 0x0001, 0x22e3: 0x0001, + 0x22e4: 0x0001, 0x22e5: 0x0001, 0x22e6: 0x0001, 0x22e7: 0x0001, 0x22e8: 0x0001, 0x22e9: 0x0001, + 0x22ea: 0x0001, 0x22eb: 0x0001, 0x22ec: 0x0001, 0x22ed: 0x0001, 0x22ee: 0x0001, 0x22ef: 0x0001, + 0x22f0: 0x0002, 0x22f1: 0x0002, 0x22f2: 0x0002, 0x22f3: 0x0002, 0x22f4: 0x0002, 0x22f5: 0x0002, + 0x22f6: 0x0002, 0x22f7: 0x0002, 0x22f8: 0x0002, 0x22f9: 0x0002, 0x22fa: 0x0002, 0x22fb: 0x0002, + 0x22fc: 0x0002, 0x22fd: 0x0002, 0x22fe: 0x0002, 0x22ff: 0x0002, + // Block 0x8c, offset 0x2300 + 0x2300: 0x0002, 0x2301: 0x0002, 0x2302: 0x0002, 0x2303: 0x0002, 0x2304: 0x0002, 0x2305: 0x0002, + 0x2306: 0x0002, 0x2307: 0x0002, 0x2308: 0x0002, 0x2309: 0x0002, 0x230a: 0x0002, 0x230b: 0x0002, + 0x230c: 0x0002, 0x230d: 0x0002, 0x230e: 0x0002, 0x230f: 0x0002, 0x2310: 0x0002, 0x2311: 0x0002, + 0x2312: 0x0002, 0x2314: 0x0002, 0x2315: 0x0002, 0x2316: 0x0002, 0x2317: 0x0002, + 0x2318: 0x0002, 0x2319: 0x0002, 0x231a: 0x0002, 0x231b: 0x0002, 0x231c: 0x0002, 0x231d: 0x0002, + 0x231e: 0x0002, 0x231f: 0x0002, 0x2320: 0x0002, 0x2321: 0x0002, 0x2322: 0x0002, 0x2323: 0x0002, + 0x2324: 0x0002, 0x2325: 0x0002, 0x2326: 0x0002, 0x2328: 0x0002, 0x2329: 0x0002, + 0x232a: 0x0002, 0x232b: 0x0002, + // Block 0x8d, offset 0x2340 + 0x2340: 0x0002, 0x2341: 0x0002, 0x2342: 0x0002, 0x2343: 0x0002, 0x2344: 0x0002, 0x2345: 0x0002, + 0x2346: 0x0002, 0x2347: 0x0002, 0x2348: 0x0002, 0x2349: 0x0002, 0x234a: 0x0002, 0x234b: 0x0002, + 0x234c: 0x0002, 0x234d: 0x0002, 0x234e: 0x0002, 0x234f: 0x0002, 0x2350: 0x0002, 0x2351: 0x0002, + 0x2352: 0x0002, 0x2353: 0x0002, 0x2354: 0x0002, 0x2355: 0x0002, 0x2356: 0x0002, 0x2357: 0x0002, + 0x2358: 0x0002, 0x2359: 0x0002, 0x235a: 0x0002, 0x235b: 0x0002, 0x235c: 0x0002, 0x235d: 0x0002, + 0x235e: 0x0002, 0x235f: 0x0002, 0x2360: 0x0002, + // Block 0x8e, offset 0x2380 + 0x23a0: 0x0002, 0x23a1: 0x0002, 0x23a2: 0x0002, 0x23a3: 0x0002, + 0x23a4: 0x0002, 0x23a5: 0x0002, 0x23a6: 0x0002, + 0x23b9: 0x0001, 0x23ba: 0x0001, 0x23bb: 0x0001, + 0x23be: 0x0001, 0x23bf: 0x0001, + // Block 0x8f, offset 0x23c0 + 0x23fd: 0x0001, + // Block 0x90, offset 0x2400 + 0x2420: 0x0001, + // Block 0x91, offset 0x2440 + 0x2476: 0x0001, 0x2477: 0x0001, 0x2478: 0x0001, 0x2479: 0x0001, 0x247a: 0x0001, + // Block 0x92, offset 0x2480 + 0x2481: 0x0001, 0x2482: 0x0001, 0x2483: 0x0001, 0x2485: 0x0001, + 0x2486: 0x0001, + 0x248c: 0x0001, 0x248d: 0x0001, 0x248e: 0x0001, 0x248f: 0x0001, + 0x24b8: 0x0001, 0x24b9: 0x0001, 0x24ba: 0x0001, + 0x24bf: 0x0001, + // Block 0x93, offset 0x24c0 + 0x24e5: 0x0001, 0x24e6: 0x0001, + // Block 0x94, offset 0x2500 + 0x2524: 0x0001, 0x2525: 0x0001, 0x2526: 0x0001, 0x2527: 0x0001, + // Block 0x95, offset 0x2540 + 0x256b: 0x0001, 0x256c: 0x0001, + // Block 0x96, offset 0x2580 + 0x25bd: 0x0001, 0x25be: 0x0001, 0x25bf: 0x0001, + // Block 0x97, offset 0x25c0 + 0x25c6: 0x0001, 0x25c7: 0x0001, 0x25c8: 0x0001, 0x25c9: 0x0001, 0x25ca: 0x0001, 0x25cb: 0x0001, + 0x25cc: 0x0001, 0x25cd: 0x0001, 0x25ce: 0x0001, 0x25cf: 0x0001, 0x25d0: 0x0001, + // Block 0x98, offset 0x2600 + 0x2602: 0x0001, 0x2603: 0x0001, 0x2604: 0x0001, 0x2605: 0x0001, + // Block 0x99, offset 0x2640 + 0x2641: 0x0001, + 0x2678: 0x0001, 0x2679: 0x0001, 0x267a: 0x0001, 0x267b: 0x0001, + 0x267c: 0x0001, 0x267d: 0x0001, 0x267e: 0x0001, 0x267f: 0x0001, + // Block 0x9a, offset 0x2680 + 0x2680: 0x0001, 0x2681: 0x0001, 0x2682: 0x0001, 0x2683: 0x0001, 0x2684: 0x0001, 0x2685: 0x0001, + 0x2686: 0x0001, + 0x26b0: 0x0001, 0x26b3: 0x0001, 0x26b4: 0x0001, + 0x26bf: 0x0001, + // Block 0x9b, offset 0x26c0 + 0x26c0: 0x0001, 0x26c1: 0x0001, + 0x26f3: 0x0001, 0x26f4: 0x0001, 0x26f5: 0x0001, + 0x26f6: 0x0001, 0x26f9: 0x0001, 0x26fa: 0x0001, + 0x26fd: 0x0001, + // Block 0x9c, offset 0x2700 + 0x2702: 0x0001, + 0x270d: 0x0001, + // Block 0x9d, offset 0x2740 + 0x2740: 0x0001, 0x2741: 0x0001, 0x2742: 0x0001, + 0x2767: 0x0001, 0x2768: 0x0001, 0x2769: 0x0001, + 0x276a: 0x0001, 0x276b: 0x0001, 0x276d: 0x0001, 0x276e: 0x0001, 0x276f: 0x0001, + 0x2770: 0x0001, 0x2771: 0x0001, 0x2772: 0x0001, 0x2773: 0x0001, 0x2774: 0x0001, + // Block 0x9e, offset 0x2780 + 0x27b3: 0x0001, + // Block 0x9f, offset 0x27c0 + 0x27c0: 0x0001, 0x27c1: 0x0001, + 0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x0001, 0x27f9: 0x0001, 0x27fa: 0x0001, 0x27fb: 0x0001, + 0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, + // Block 0xa0, offset 0x2800 + 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001, + 0x280c: 0x0001, 0x280f: 0x0001, + // Block 0xa1, offset 0x2840 + 0x286f: 0x0001, + 0x2870: 0x0001, 0x2871: 0x0001, 0x2874: 0x0001, + 0x2876: 0x0001, 0x2877: 0x0001, + 0x287e: 0x0001, + // Block 0xa2, offset 0x2880 + 0x289f: 0x0001, 0x28a3: 0x0001, + 0x28a4: 0x0001, 0x28a5: 0x0001, 0x28a6: 0x0001, 0x28a7: 0x0001, 0x28a8: 0x0001, 0x28a9: 0x0001, + 0x28aa: 0x0001, + // Block 0xa3, offset 0x28c0 + 0x28c0: 0x0001, + 0x28e6: 0x0001, 0x28e7: 0x0001, 0x28e8: 0x0001, 0x28e9: 0x0001, + 0x28ea: 0x0001, 0x28eb: 0x0001, 0x28ec: 0x0001, + 0x28f0: 0x0001, 0x28f1: 0x0001, 0x28f2: 0x0001, 0x28f3: 0x0001, 0x28f4: 0x0001, + // Block 0xa4, offset 0x2900 + 0x2938: 0x0001, 0x2939: 0x0001, 0x293a: 0x0001, 0x293b: 0x0001, + 0x293c: 0x0001, 0x293d: 0x0001, 0x293e: 0x0001, 0x293f: 0x0001, + // Block 0xa5, offset 0x2940 + 0x2942: 0x0001, 0x2943: 0x0001, 0x2944: 0x0001, + 0x2946: 0x0001, + 0x295e: 0x0001, + // Block 0xa6, offset 0x2980 + 0x29b3: 0x0001, 0x29b4: 0x0001, 0x29b5: 0x0001, + 0x29b6: 0x0001, 0x29b7: 0x0001, 0x29b8: 0x0001, 0x29ba: 0x0001, + 0x29bf: 0x0001, + // Block 0xa7, offset 0x29c0 + 0x29c0: 0x0001, 0x29c2: 0x0001, 0x29c3: 0x0001, + // Block 0xa8, offset 0x2a00 + 0x2a32: 0x0001, 0x2a33: 0x0001, 0x2a34: 0x0001, 0x2a35: 0x0001, + 0x2a3c: 0x0001, 0x2a3d: 0x0001, 0x2a3f: 0x0001, + // Block 0xa9, offset 0x2a40 + 0x2a40: 0x0001, + 0x2a5c: 0x0001, 0x2a5d: 0x0001, + // Block 0xaa, offset 0x2a80 + 0x2ab3: 0x0001, 0x2ab4: 0x0001, 0x2ab5: 0x0001, + 0x2ab6: 0x0001, 0x2ab7: 0x0001, 0x2ab8: 0x0001, 0x2ab9: 0x0001, 0x2aba: 0x0001, + 0x2abd: 0x0001, 0x2abf: 0x0001, + // Block 0xab, offset 0x2ac0 + 0x2ac0: 0x0001, + // Block 0xac, offset 0x2b00 + 0x2b2b: 0x0001, 0x2b2d: 0x0001, + 0x2b30: 0x0001, 0x2b31: 0x0001, 0x2b32: 0x0001, 0x2b33: 0x0001, 0x2b34: 0x0001, 0x2b35: 0x0001, + 0x2b37: 0x0001, + // Block 0xad, offset 0x2b40 + 0x2b5d: 0x0001, + 0x2b5e: 0x0001, 0x2b5f: 0x0001, 0x2b62: 0x0001, 0x2b63: 0x0001, + 0x2b64: 0x0001, 0x2b65: 0x0001, 0x2b67: 0x0001, 0x2b68: 0x0001, 0x2b69: 0x0001, + 0x2b6a: 0x0001, 0x2b6b: 0x0001, + // Block 0xae, offset 0x2b80 + 0x2baf: 0x0001, + 0x2bb0: 0x0001, 0x2bb1: 0x0001, 0x2bb2: 0x0001, 0x2bb3: 0x0001, 0x2bb4: 0x0001, 0x2bb5: 0x0001, + 0x2bb6: 0x0001, 0x2bb7: 0x0001, 0x2bb9: 0x0001, 0x2bba: 0x0001, + // Block 0xaf, offset 0x2bc0 + 0x2bfb: 0x0001, + 0x2bfc: 0x0001, 0x2bfe: 0x0001, + // Block 0xb0, offset 0x2c00 + 0x2c03: 0x0001, + // Block 0xb1, offset 0x2c40 + 0x2c54: 0x0001, 0x2c55: 0x0001, 0x2c56: 0x0001, 0x2c57: 0x0001, + 0x2c5a: 0x0001, 0x2c5b: 0x0001, + 0x2c60: 0x0001, + // Block 0xb2, offset 0x2c80 + 0x2c81: 0x0001, 0x2c82: 0x0001, 0x2c83: 0x0001, 0x2c84: 0x0001, 0x2c85: 0x0001, + 0x2c86: 0x0001, 0x2c87: 0x0001, 0x2c88: 0x0001, 0x2c89: 0x0001, 0x2c8a: 0x0001, + 0x2cb3: 0x0001, 0x2cb4: 0x0001, 0x2cb5: 0x0001, + 0x2cb6: 0x0001, 0x2cb7: 0x0001, 0x2cb8: 0x0001, 0x2cbb: 0x0001, + 0x2cbc: 0x0001, 0x2cbd: 0x0001, 0x2cbe: 0x0001, + // Block 0xb3, offset 0x2cc0 + 0x2cc7: 0x0001, + 0x2cd1: 0x0001, + 0x2cd2: 0x0001, 0x2cd3: 0x0001, 0x2cd4: 0x0001, 0x2cd5: 0x0001, 0x2cd6: 0x0001, + 0x2cd9: 0x0001, 0x2cda: 0x0001, 0x2cdb: 0x0001, + // Block 0xb4, offset 0x2d00 + 0x2d0a: 0x0001, 0x2d0b: 0x0001, + 0x2d0c: 0x0001, 0x2d0d: 0x0001, 0x2d0e: 0x0001, 0x2d0f: 0x0001, 0x2d10: 0x0001, 0x2d11: 0x0001, + 0x2d12: 0x0001, 0x2d13: 0x0001, 0x2d14: 0x0001, 0x2d15: 0x0001, 0x2d16: 0x0001, + 0x2d18: 0x0001, 0x2d19: 0x0001, + // Block 0xb5, offset 0x2d40 + 0x2d70: 0x0001, 0x2d71: 0x0001, 0x2d72: 0x0001, 0x2d73: 0x0001, 0x2d74: 0x0001, 0x2d75: 0x0001, + 0x2d76: 0x0001, 0x2d78: 0x0001, 0x2d79: 0x0001, 0x2d7a: 0x0001, 0x2d7b: 0x0001, + 0x2d7c: 0x0001, 0x2d7d: 0x0001, 0x2d7f: 0x0001, + // Block 0xb6, offset 0x2d80 + 0x2d92: 0x0001, 0x2d93: 0x0001, 0x2d94: 0x0001, 0x2d95: 0x0001, 0x2d96: 0x0001, 0x2d97: 0x0001, + 0x2d98: 0x0001, 0x2d99: 0x0001, 0x2d9a: 0x0001, 0x2d9b: 0x0001, 0x2d9c: 0x0001, 0x2d9d: 0x0001, + 0x2d9e: 0x0001, 0x2d9f: 0x0001, 0x2da0: 0x0001, 0x2da1: 0x0001, 0x2da2: 0x0001, 0x2da3: 0x0001, + 0x2da4: 0x0001, 0x2da5: 0x0001, 0x2da6: 0x0001, 0x2da7: 0x0001, + 0x2daa: 0x0001, 0x2dab: 0x0001, 0x2dac: 0x0001, 0x2dad: 0x0001, 0x2dae: 0x0001, 0x2daf: 0x0001, + 0x2db0: 0x0001, 0x2db2: 0x0001, 0x2db3: 0x0001, 0x2db5: 0x0001, + 0x2db6: 0x0001, + // Block 0xb7, offset 0x2dc0 + 0x2df1: 0x0001, 0x2df2: 0x0001, 0x2df3: 0x0001, 0x2df4: 0x0001, 0x2df5: 0x0001, + 0x2df6: 0x0001, 0x2dfa: 0x0001, + 0x2dfc: 0x0001, 0x2dfd: 0x0001, 0x2dff: 0x0001, + // Block 0xb8, offset 0x2e00 + 0x2e00: 0x0001, 0x2e01: 0x0001, 0x2e02: 0x0001, 0x2e03: 0x0001, 0x2e04: 0x0001, 0x2e05: 0x0001, + 0x2e07: 0x0001, + // Block 0xb9, offset 0x2e40 + 0x2e50: 0x0001, 0x2e51: 0x0001, + 0x2e55: 0x0001, 0x2e57: 0x0001, + // Block 0xba, offset 0x2e80 + 0x2eb3: 0x0001, 0x2eb4: 0x0001, + // Block 0xbb, offset 0x2ec0 + 0x2ec0: 0x0001, 0x2ec1: 0x0001, + 0x2ef6: 0x0001, 0x2ef7: 0x0001, 0x2ef8: 0x0001, 0x2ef9: 0x0001, 0x2efa: 0x0001, + // Block 0xbc, offset 0x2f00 + 0x2f00: 0x0001, 0x2f02: 0x0001, + // Block 0xbd, offset 0x2f40 + 0x2f40: 0x0001, + 0x2f47: 0x0001, 0x2f48: 0x0001, 0x2f49: 0x0001, 0x2f4a: 0x0001, 0x2f4b: 0x0001, + 0x2f4c: 0x0001, 0x2f4d: 0x0001, 0x2f4e: 0x0001, 0x2f4f: 0x0001, 0x2f50: 0x0001, 0x2f51: 0x0001, + 0x2f52: 0x0001, 0x2f53: 0x0001, 0x2f54: 0x0001, 0x2f55: 0x0001, + // Block 0xbe, offset 0x2f80 + 0x2fb0: 0x0001, 0x2fb1: 0x0001, 0x2fb2: 0x0001, 0x2fb3: 0x0001, 0x2fb4: 0x0001, + // Block 0xbf, offset 0x2fc0 + 0x2ff0: 0x0001, 0x2ff1: 0x0001, 0x2ff2: 0x0001, 0x2ff3: 0x0001, 0x2ff4: 0x0001, 0x2ff5: 0x0001, + 0x2ff6: 0x0001, + // Block 0xc0, offset 0x3000 + 0x300f: 0x0001, + // Block 0xc1, offset 0x3040 + 0x304f: 0x0001, 0x3050: 0x0001, 0x3051: 0x0001, + 0x3052: 0x0001, + // Block 0xc2, offset 0x3080 + 0x30a0: 0x0002, 0x30a1: 0x0002, 0x30a2: 0x0002, 0x30a3: 0x0002, + 0x30a4: 0x0001, + 0x30b0: 0x0002, 0x30b1: 0x0002, 0x30b2: 0x0002, 0x30b3: 0x0002, 0x30b4: 0x0002, 0x30b5: 0x0002, + 0x30b6: 0x0002, + // Block 0xc3, offset 0x30c0 + 0x30c0: 0x0002, 0x30c1: 0x0002, 0x30c2: 0x0002, 0x30c3: 0x0002, 0x30c4: 0x0002, 0x30c5: 0x0002, + 0x30c6: 0x0002, 0x30c7: 0x0002, 0x30c8: 0x0002, 0x30c9: 0x0002, 0x30ca: 0x0002, 0x30cb: 0x0002, + 0x30cc: 0x0002, 0x30cd: 0x0002, 0x30ce: 0x0002, 0x30cf: 0x0002, 0x30d0: 0x0002, 0x30d1: 0x0002, + 0x30d2: 0x0002, 0x30d3: 0x0002, 0x30d4: 0x0002, 0x30d5: 0x0002, + 0x30ff: 0x0002, + // Block 0xc4, offset 0x3100 + 0x3100: 0x0002, 0x3101: 0x0002, 0x3102: 0x0002, 0x3103: 0x0002, 0x3104: 0x0002, 0x3105: 0x0002, + 0x3106: 0x0002, 0x3107: 0x0002, 0x3108: 0x0002, 0x3109: 0x0002, 0x310a: 0x0002, 0x310b: 0x0002, + 0x310c: 0x0002, 0x310d: 0x0002, 0x310e: 0x0002, 0x310f: 0x0002, 0x3110: 0x0002, 0x3111: 0x0002, + 0x3112: 0x0002, 0x3113: 0x0002, 0x3114: 0x0002, 0x3115: 0x0002, 0x3116: 0x0002, 0x3117: 0x0002, + 0x3118: 0x0002, 0x3119: 0x0002, 0x311a: 0x0002, 0x311b: 0x0002, 0x311c: 0x0002, 0x311d: 0x0002, + 0x311e: 0x0002, + // Block 0xc5, offset 0x3140 + 0x3140: 0x0002, 0x3141: 0x0002, 0x3142: 0x0002, 0x3143: 0x0002, 0x3144: 0x0002, 0x3145: 0x0002, + 0x3146: 0x0002, 0x3147: 0x0002, 0x3148: 0x0002, 0x3149: 0x0002, 0x314a: 0x0002, 0x314b: 0x0002, + 0x314c: 0x0002, 0x314d: 0x0002, 0x314e: 0x0002, 0x314f: 0x0002, 0x3150: 0x0002, 0x3151: 0x0002, + 0x3152: 0x0002, 0x3153: 0x0002, 0x3154: 0x0002, 0x3155: 0x0002, 0x3156: 0x0002, 0x3157: 0x0002, + 0x3158: 0x0002, 0x3159: 0x0002, 0x315a: 0x0002, 0x315b: 0x0002, 0x315c: 0x0002, 0x315d: 0x0002, + 0x315e: 0x0002, 0x315f: 0x0002, 0x3160: 0x0002, 0x3161: 0x0002, 0x3162: 0x0002, 0x3163: 0x0002, + 0x3164: 0x0002, 0x3165: 0x0002, 0x3166: 0x0002, 0x3167: 0x0002, 0x3168: 0x0002, 0x3169: 0x0002, + 0x316a: 0x0002, 0x316b: 0x0002, 0x316c: 0x0002, 0x316d: 0x0002, 0x316e: 0x0002, 0x316f: 0x0002, + 0x3170: 0x0002, 0x3171: 0x0002, 0x3172: 0x0002, + // Block 0xc6, offset 0x3180 + 0x31b0: 0x0002, 0x31b1: 0x0002, 0x31b2: 0x0002, 0x31b3: 0x0002, 0x31b5: 0x0002, + 0x31b6: 0x0002, 0x31b7: 0x0002, 0x31b8: 0x0002, 0x31b9: 0x0002, 0x31ba: 0x0002, 0x31bb: 0x0002, + 0x31bd: 0x0002, 0x31be: 0x0002, + // Block 0xc7, offset 0x31c0 + 0x31c0: 0x0002, 0x31c1: 0x0002, 0x31c2: 0x0002, 0x31c3: 0x0002, 0x31c4: 0x0002, 0x31c5: 0x0002, + 0x31c6: 0x0002, 0x31c7: 0x0002, 0x31c8: 0x0002, 0x31c9: 0x0002, 0x31ca: 0x0002, 0x31cb: 0x0002, + 0x31cc: 0x0002, 0x31cd: 0x0002, 0x31ce: 0x0002, 0x31cf: 0x0002, 0x31d0: 0x0002, 0x31d1: 0x0002, + 0x31d2: 0x0002, 0x31d3: 0x0002, 0x31d4: 0x0002, 0x31d5: 0x0002, 0x31d6: 0x0002, 0x31d7: 0x0002, + 0x31d8: 0x0002, 0x31d9: 0x0002, 0x31da: 0x0002, 0x31db: 0x0002, 0x31dc: 0x0002, 0x31dd: 0x0002, + 0x31de: 0x0002, 0x31df: 0x0002, 0x31e0: 0x0002, 0x31e1: 0x0002, 0x31e2: 0x0002, + 0x31f2: 0x0002, + // Block 0xc8, offset 0x3200 + 0x3210: 0x0002, 0x3211: 0x0002, + 0x3212: 0x0002, 0x3215: 0x0002, + 0x3224: 0x0002, 0x3225: 0x0002, 0x3226: 0x0002, 0x3227: 0x0002, + 0x3230: 0x0002, 0x3231: 0x0002, 0x3232: 0x0002, 0x3233: 0x0002, 0x3234: 0x0002, 0x3235: 0x0002, + 0x3236: 0x0002, 0x3237: 0x0002, 0x3238: 0x0002, 0x3239: 0x0002, 0x323a: 0x0002, 0x323b: 0x0002, + 0x323c: 0x0002, 0x323d: 0x0002, 0x323e: 0x0002, 0x323f: 0x0002, + // Block 0xc9, offset 0x3240 + 0x3240: 0x0002, 0x3241: 0x0002, 0x3242: 0x0002, 0x3243: 0x0002, 0x3244: 0x0002, 0x3245: 0x0002, + 0x3246: 0x0002, 0x3247: 0x0002, 0x3248: 0x0002, 0x3249: 0x0002, 0x324a: 0x0002, 0x324b: 0x0002, + 0x324c: 0x0002, 0x324d: 0x0002, 0x324e: 0x0002, 0x324f: 0x0002, 0x3250: 0x0002, 0x3251: 0x0002, + 0x3252: 0x0002, 0x3253: 0x0002, 0x3254: 0x0002, 0x3255: 0x0002, 0x3256: 0x0002, 0x3257: 0x0002, + 0x3258: 0x0002, 0x3259: 0x0002, 0x325a: 0x0002, 0x325b: 0x0002, 0x325c: 0x0002, 0x325d: 0x0002, + 0x325e: 0x0002, 0x325f: 0x0002, 0x3260: 0x0002, 0x3261: 0x0002, 0x3262: 0x0002, 0x3263: 0x0002, + 0x3264: 0x0002, 0x3265: 0x0002, 0x3266: 0x0002, 0x3267: 0x0002, 0x3268: 0x0002, 0x3269: 0x0002, + 0x326a: 0x0002, 0x326b: 0x0002, 0x326c: 0x0002, 0x326d: 0x0002, 0x326e: 0x0002, 0x326f: 0x0002, + 0x3270: 0x0002, 0x3271: 0x0002, 0x3272: 0x0002, 0x3273: 0x0002, 0x3274: 0x0002, 0x3275: 0x0002, + 0x3276: 0x0002, 0x3277: 0x0002, 0x3278: 0x0002, 0x3279: 0x0002, 0x327a: 0x0002, 0x327b: 0x0002, + // Block 0xca, offset 0x3280 + 0x329d: 0x0001, + 0x329e: 0x0001, 0x32a0: 0x0001, 0x32a1: 0x0001, 0x32a2: 0x0001, 0x32a3: 0x0001, + // Block 0xcb, offset 0x32c0 + 0x32c0: 0x0001, 0x32c1: 0x0001, 0x32c2: 0x0001, 0x32c3: 0x0001, 0x32c4: 0x0001, 0x32c5: 0x0001, + 0x32c6: 0x0001, 0x32c7: 0x0001, 0x32c8: 0x0001, 0x32c9: 0x0001, 0x32ca: 0x0001, 0x32cb: 0x0001, + 0x32cc: 0x0001, 0x32cd: 0x0001, 0x32ce: 0x0001, 0x32cf: 0x0001, 0x32d0: 0x0001, 0x32d1: 0x0001, + 0x32d2: 0x0001, 0x32d3: 0x0001, 0x32d4: 0x0001, 0x32d5: 0x0001, 0x32d6: 0x0001, 0x32d7: 0x0001, + 0x32d8: 0x0001, 0x32d9: 0x0001, 0x32da: 0x0001, 0x32db: 0x0001, 0x32dc: 0x0001, 0x32dd: 0x0001, + 0x32de: 0x0001, 0x32df: 0x0001, 0x32e0: 0x0001, 0x32e1: 0x0001, 0x32e2: 0x0001, 0x32e3: 0x0001, + 0x32e4: 0x0001, 0x32e5: 0x0001, 0x32e6: 0x0001, 0x32e7: 0x0001, 0x32e8: 0x0001, 0x32e9: 0x0001, + 0x32ea: 0x0001, 0x32eb: 0x0001, 0x32ec: 0x0001, 0x32ed: 0x0001, + 0x32f0: 0x0001, 0x32f1: 0x0001, 0x32f2: 0x0001, 0x32f3: 0x0001, 0x32f4: 0x0001, 0x32f5: 0x0001, + 0x32f6: 0x0001, 0x32f7: 0x0001, 0x32f8: 0x0001, 0x32f9: 0x0001, 0x32fa: 0x0001, 0x32fb: 0x0001, + 0x32fc: 0x0001, 0x32fd: 0x0001, 0x32fe: 0x0001, 0x32ff: 0x0001, + // Block 0xcc, offset 0x3300 + 0x3300: 0x0001, 0x3301: 0x0001, 0x3302: 0x0001, 0x3303: 0x0001, 0x3304: 0x0001, 0x3305: 0x0001, + 0x3306: 0x0001, + // Block 0xcd, offset 0x3340 + 0x3367: 0x0001, 0x3368: 0x0001, 0x3369: 0x0001, + 0x3373: 0x0001, 0x3374: 0x0001, 0x3375: 0x0001, + 0x3376: 0x0001, 0x3377: 0x0001, 0x3378: 0x0001, 0x3379: 0x0001, 0x337a: 0x0001, 0x337b: 0x0001, + 0x337c: 0x0001, 0x337d: 0x0001, 0x337e: 0x0001, 0x337f: 0x0001, + // Block 0xce, offset 0x3380 + 0x3380: 0x0001, 0x3381: 0x0001, 0x3382: 0x0001, 0x3385: 0x0001, + 0x3386: 0x0001, 0x3387: 0x0001, 0x3388: 0x0001, 0x3389: 0x0001, 0x338a: 0x0001, 0x338b: 0x0001, + 0x33aa: 0x0001, 0x33ab: 0x0001, 0x33ac: 0x0001, 0x33ad: 0x0001, + // Block 0xcf, offset 0x33c0 + 0x33c2: 0x0001, 0x33c3: 0x0001, 0x33c4: 0x0001, + // Block 0xd0, offset 0x3400 + 0x3400: 0x0002, 0x3401: 0x0002, 0x3402: 0x0002, 0x3403: 0x0002, 0x3404: 0x0002, 0x3405: 0x0002, + 0x3406: 0x0002, 0x3407: 0x0002, 0x3408: 0x0002, 0x3409: 0x0002, 0x340a: 0x0002, 0x340b: 0x0002, + 0x340c: 0x0002, 0x340d: 0x0002, 0x340e: 0x0002, 0x340f: 0x0002, 0x3410: 0x0002, 0x3411: 0x0002, + 0x3412: 0x0002, 0x3413: 0x0002, 0x3414: 0x0002, 0x3415: 0x0002, 0x3416: 0x0002, + 0x3420: 0x0002, 0x3421: 0x0002, 0x3422: 0x0002, 0x3423: 0x0002, + 0x3424: 0x0002, 0x3425: 0x0002, 0x3426: 0x0002, 0x3427: 0x0002, 0x3428: 0x0002, 0x3429: 0x0002, + 0x342a: 0x0002, 0x342b: 0x0002, 0x342c: 0x0002, 0x342d: 0x0002, 0x342e: 0x0002, 0x342f: 0x0002, + 0x3430: 0x0002, 0x3431: 0x0002, 0x3432: 0x0002, 0x3433: 0x0002, 0x3434: 0x0002, 0x3435: 0x0002, + 0x3436: 0x0002, + // Block 0xd1, offset 0x3440 + 0x3440: 0x0001, 0x3441: 0x0001, 0x3442: 0x0001, 0x3443: 0x0001, 0x3444: 0x0001, 0x3445: 0x0001, + 0x3446: 0x0001, 0x3447: 0x0001, 0x3448: 0x0001, 0x3449: 0x0001, 0x344a: 0x0001, 0x344b: 0x0001, + 0x344c: 0x0001, 0x344d: 0x0001, 0x344e: 0x0001, 0x344f: 0x0001, 0x3450: 0x0001, 0x3451: 0x0001, + 0x3452: 0x0001, 0x3453: 0x0001, 0x3454: 0x0001, 0x3455: 0x0001, 0x3456: 0x0001, 0x3457: 0x0001, + 0x3458: 0x0001, 0x3459: 0x0001, 0x345a: 0x0001, 0x345b: 0x0001, 0x345c: 0x0001, 0x345d: 0x0001, + 0x345e: 0x0001, 0x345f: 0x0001, 0x3460: 0x0001, 0x3461: 0x0001, 0x3462: 0x0001, 0x3463: 0x0001, + 0x3464: 0x0001, 0x3465: 0x0001, 0x3466: 0x0001, 0x3467: 0x0001, 0x3468: 0x0001, 0x3469: 0x0001, + 0x346a: 0x0001, 0x346b: 0x0001, 0x346c: 0x0001, 0x346d: 0x0001, 0x346e: 0x0001, 0x346f: 0x0001, + 0x3470: 0x0001, 0x3471: 0x0001, 0x3472: 0x0001, 0x3473: 0x0001, 0x3474: 0x0001, 0x3475: 0x0001, + 0x3476: 0x0001, 0x347b: 0x0001, + 0x347c: 0x0001, 0x347d: 0x0001, 0x347e: 0x0001, 0x347f: 0x0001, + // Block 0xd2, offset 0x3480 + 0x3480: 0x0001, 0x3481: 0x0001, 0x3482: 0x0001, 0x3483: 0x0001, 0x3484: 0x0001, 0x3485: 0x0001, + 0x3486: 0x0001, 0x3487: 0x0001, 0x3488: 0x0001, 0x3489: 0x0001, 0x348a: 0x0001, 0x348b: 0x0001, + 0x348c: 0x0001, 0x348d: 0x0001, 0x348e: 0x0001, 0x348f: 0x0001, 0x3490: 0x0001, 0x3491: 0x0001, + 0x3492: 0x0001, 0x3493: 0x0001, 0x3494: 0x0001, 0x3495: 0x0001, 0x3496: 0x0001, 0x3497: 0x0001, + 0x3498: 0x0001, 0x3499: 0x0001, 0x349a: 0x0001, 0x349b: 0x0001, 0x349c: 0x0001, 0x349d: 0x0001, + 0x349e: 0x0001, 0x349f: 0x0001, 0x34a0: 0x0001, 0x34a1: 0x0001, 0x34a2: 0x0001, 0x34a3: 0x0001, + 0x34a4: 0x0001, 0x34a5: 0x0001, 0x34a6: 0x0001, 0x34a7: 0x0001, 0x34a8: 0x0001, 0x34a9: 0x0001, + 0x34aa: 0x0001, 0x34ab: 0x0001, 0x34ac: 0x0001, + 0x34b5: 0x0001, + // Block 0xd3, offset 0x34c0 + 0x34c4: 0x0001, + 0x34db: 0x0001, 0x34dc: 0x0001, 0x34dd: 0x0001, + 0x34de: 0x0001, 0x34df: 0x0001, 0x34e1: 0x0001, 0x34e2: 0x0001, 0x34e3: 0x0001, + 0x34e4: 0x0001, 0x34e5: 0x0001, 0x34e6: 0x0001, 0x34e7: 0x0001, 0x34e8: 0x0001, 0x34e9: 0x0001, + 0x34ea: 0x0001, 0x34eb: 0x0001, 0x34ec: 0x0001, 0x34ed: 0x0001, 0x34ee: 0x0001, 0x34ef: 0x0001, + // Block 0xd4, offset 0x3500 + 0x3500: 0x0001, 0x3501: 0x0001, 0x3502: 0x0001, 0x3503: 0x0001, 0x3504: 0x0001, 0x3505: 0x0001, + 0x3506: 0x0001, 0x3508: 0x0001, 0x3509: 0x0001, 0x350a: 0x0001, 0x350b: 0x0001, + 0x350c: 0x0001, 0x350d: 0x0001, 0x350e: 0x0001, 0x350f: 0x0001, 0x3510: 0x0001, 0x3511: 0x0001, + 0x3512: 0x0001, 0x3513: 0x0001, 0x3514: 0x0001, 0x3515: 0x0001, 0x3516: 0x0001, 0x3517: 0x0001, + 0x3518: 0x0001, 0x351b: 0x0001, 0x351c: 0x0001, 0x351d: 0x0001, + 0x351e: 0x0001, 0x351f: 0x0001, 0x3520: 0x0001, 0x3521: 0x0001, 0x3523: 0x0001, + 0x3524: 0x0001, 0x3526: 0x0001, 0x3527: 0x0001, 0x3528: 0x0001, 0x3529: 0x0001, + 0x352a: 0x0001, + // Block 0xd5, offset 0x3540 + 0x356e: 0x0001, + // Block 0xd6, offset 0x3580 + 0x35ac: 0x0001, 0x35ad: 0x0001, 0x35ae: 0x0001, 0x35af: 0x0001, + // Block 0xd7, offset 0x35c0 + 0x35d0: 0x0001, 0x35d1: 0x0001, + 0x35d2: 0x0001, 0x35d3: 0x0001, 0x35d4: 0x0001, 0x35d5: 0x0001, 0x35d6: 0x0001, + // Block 0xd8, offset 0x3600 + 0x3604: 0x0001, 0x3605: 0x0001, + 0x3606: 0x0001, 0x3607: 0x0001, 0x3608: 0x0001, 0x3609: 0x0001, 0x360a: 0x0001, + // Block 0xd9, offset 0x3640 + 0x3644: 0x0002, + // Block 0xda, offset 0x3680 + 0x368f: 0x0002, + // Block 0xdb, offset 0x36c0 + 0x36c0: 0x0003, 0x36c1: 0x0003, 0x36c2: 0x0003, 0x36c3: 0x0003, 0x36c4: 0x0003, 0x36c5: 0x0003, + 0x36c6: 0x0003, 0x36c7: 0x0003, 0x36c8: 0x0003, 0x36c9: 0x0003, 0x36ca: 0x0003, + 0x36d0: 0x0003, 0x36d1: 0x0003, + 0x36d2: 0x0003, 0x36d3: 0x0003, 0x36d4: 0x0003, 0x36d5: 0x0003, 0x36d6: 0x0003, 0x36d7: 0x0003, + 0x36d8: 0x0003, 0x36d9: 0x0003, 0x36da: 0x0003, 0x36db: 0x0003, 0x36dc: 0x0003, 0x36dd: 0x0003, + 0x36de: 0x0003, 0x36df: 0x0003, 0x36e0: 0x0003, 0x36e1: 0x0003, 0x36e2: 0x0003, 0x36e3: 0x0003, + 0x36e4: 0x0003, 0x36e5: 0x0003, 0x36e6: 0x0003, 0x36e7: 0x0003, 0x36e8: 0x0003, 0x36e9: 0x0003, + 0x36ea: 0x0003, 0x36eb: 0x0003, 0x36ec: 0x0003, 0x36ed: 0x0003, + 0x36f0: 0x0003, 0x36f1: 0x0003, 0x36f2: 0x0003, 0x36f3: 0x0003, 0x36f4: 0x0003, 0x36f5: 0x0003, + 0x36f6: 0x0003, 0x36f7: 0x0003, 0x36f8: 0x0003, 0x36f9: 0x0003, 0x36fa: 0x0003, 0x36fb: 0x0003, + 0x36fc: 0x0003, 0x36fd: 0x0003, 0x36fe: 0x0003, 0x36ff: 0x0003, + // Block 0xdc, offset 0x3700 + 0x3700: 0x0003, 0x3701: 0x0003, 0x3702: 0x0003, 0x3703: 0x0003, 0x3704: 0x0003, 0x3705: 0x0003, + 0x3706: 0x0003, 0x3707: 0x0003, 0x3708: 0x0003, 0x3709: 0x0003, 0x370a: 0x0003, 0x370b: 0x0003, + 0x370c: 0x0003, 0x370d: 0x0003, 0x370e: 0x0003, 0x370f: 0x0003, 0x3710: 0x0003, 0x3711: 0x0003, + 0x3712: 0x0003, 0x3713: 0x0003, 0x3714: 0x0003, 0x3715: 0x0003, 0x3716: 0x0003, 0x3717: 0x0003, + 0x3718: 0x0003, 0x3719: 0x0003, 0x371a: 0x0003, 0x371b: 0x0003, 0x371c: 0x0003, 0x371d: 0x0003, + 0x371e: 0x0003, 0x371f: 0x0003, 0x3720: 0x0003, 0x3721: 0x0003, 0x3722: 0x0003, 0x3723: 0x0003, + 0x3724: 0x0003, 0x3725: 0x0003, 0x3726: 0x0003, 0x3727: 0x0003, 0x3728: 0x0003, 0x3729: 0x0003, + 0x3730: 0x0003, 0x3731: 0x0003, 0x3732: 0x0003, 0x3733: 0x0003, 0x3734: 0x0003, 0x3735: 0x0003, + 0x3736: 0x0003, 0x3737: 0x0003, 0x3738: 0x0003, 0x3739: 0x0003, 0x373a: 0x0003, 0x373b: 0x0003, + 0x373c: 0x0003, 0x373d: 0x0003, 0x373e: 0x0003, 0x373f: 0x0003, + // Block 0xdd, offset 0x3740 + 0x3740: 0x0003, 0x3741: 0x0003, 0x3742: 0x0003, 0x3743: 0x0003, 0x3744: 0x0003, 0x3745: 0x0003, + 0x3746: 0x0003, 0x3747: 0x0003, 0x3748: 0x0003, 0x3749: 0x0003, 0x374a: 0x0003, 0x374b: 0x0003, + 0x374c: 0x0003, 0x374d: 0x0003, 0x374e: 0x0002, 0x374f: 0x0003, 0x3750: 0x0003, 0x3751: 0x0002, + 0x3752: 0x0002, 0x3753: 0x0002, 0x3754: 0x0002, 0x3755: 0x0002, 0x3756: 0x0002, 0x3757: 0x0002, + 0x3758: 0x0002, 0x3759: 0x0002, 0x375a: 0x0002, 0x375b: 0x0003, 0x375c: 0x0003, 0x375d: 0x0003, + 0x375e: 0x0003, 0x375f: 0x0003, 0x3760: 0x0003, 0x3761: 0x0003, 0x3762: 0x0003, 0x3763: 0x0003, + 0x3764: 0x0003, 0x3765: 0x0003, 0x3766: 0x0003, 0x3767: 0x0003, 0x3768: 0x0003, 0x3769: 0x0003, + 0x376a: 0x0003, 0x376b: 0x0003, 0x376c: 0x0003, + // Block 0xde, offset 0x3780 + 0x37a6: 0x0002, 0x37a7: 0x0002, 0x37a8: 0x0002, 0x37a9: 0x0002, + 0x37aa: 0x0002, 0x37ab: 0x0002, 0x37ac: 0x0002, 0x37ad: 0x0002, 0x37ae: 0x0002, 0x37af: 0x0002, + 0x37b0: 0x0002, 0x37b1: 0x0002, 0x37b2: 0x0002, 0x37b3: 0x0002, 0x37b4: 0x0002, 0x37b5: 0x0002, + 0x37b6: 0x0002, 0x37b7: 0x0002, 0x37b8: 0x0002, 0x37b9: 0x0002, 0x37ba: 0x0002, 0x37bb: 0x0002, + 0x37bc: 0x0002, 0x37bd: 0x0002, 0x37be: 0x0002, 0x37bf: 0x0002, + // Block 0xdf, offset 0x37c0 + 0x37c0: 0x0002, 0x37c1: 0x0002, 0x37c2: 0x0002, + 0x37d0: 0x0002, 0x37d1: 0x0002, + 0x37d2: 0x0002, 0x37d3: 0x0002, 0x37d4: 0x0002, 0x37d5: 0x0002, 0x37d6: 0x0002, 0x37d7: 0x0002, + 0x37d8: 0x0002, 0x37d9: 0x0002, 0x37da: 0x0002, 0x37db: 0x0002, 0x37dc: 0x0002, 0x37dd: 0x0002, + 0x37de: 0x0002, 0x37df: 0x0002, 0x37e0: 0x0002, 0x37e1: 0x0002, 0x37e2: 0x0002, 0x37e3: 0x0002, + 0x37e4: 0x0002, 0x37e5: 0x0002, 0x37e6: 0x0002, 0x37e7: 0x0002, 0x37e8: 0x0002, 0x37e9: 0x0002, + 0x37ea: 0x0002, 0x37eb: 0x0002, 0x37ec: 0x0002, 0x37ed: 0x0002, 0x37ee: 0x0002, 0x37ef: 0x0002, + 0x37f0: 0x0002, 0x37f1: 0x0002, 0x37f2: 0x0002, 0x37f3: 0x0002, 0x37f4: 0x0002, 0x37f5: 0x0002, + 0x37f6: 0x0002, 0x37f7: 0x0002, 0x37f8: 0x0002, 0x37f9: 0x0002, 0x37fa: 0x0002, 0x37fb: 0x0002, + // Block 0xe0, offset 0x3800 + 0x3800: 0x0002, 0x3801: 0x0002, 0x3802: 0x0002, 0x3803: 0x0002, 0x3804: 0x0002, 0x3805: 0x0002, + 0x3806: 0x0002, 0x3807: 0x0002, 0x3808: 0x0002, + 0x3810: 0x0002, 0x3811: 0x0002, + 0x3820: 0x0002, 0x3821: 0x0002, 0x3822: 0x0002, 0x3823: 0x0002, + 0x3824: 0x0002, 0x3825: 0x0002, + // Block 0xe1, offset 0x3840 + 0x3840: 0x0002, 0x3841: 0x0002, 0x3842: 0x0002, 0x3843: 0x0002, 0x3844: 0x0002, 0x3845: 0x0002, + 0x3846: 0x0002, 0x3847: 0x0002, 0x3848: 0x0002, 0x3849: 0x0002, 0x384a: 0x0002, 0x384b: 0x0002, + 0x384c: 0x0002, 0x384d: 0x0002, 0x384e: 0x0002, 0x384f: 0x0002, 0x3850: 0x0002, 0x3851: 0x0002, + 0x3852: 0x0002, 0x3853: 0x0002, 0x3854: 0x0002, 0x3855: 0x0002, 0x3856: 0x0002, 0x3857: 0x0002, + 0x3858: 0x0002, 0x3859: 0x0002, 0x385a: 0x0002, 0x385b: 0x0002, 0x385c: 0x0002, 0x385d: 0x0002, + 0x385e: 0x0002, 0x385f: 0x0002, 0x3860: 0x0002, + 0x386d: 0x0002, 0x386e: 0x0002, 0x386f: 0x0002, + 0x3870: 0x0002, 0x3871: 0x0002, 0x3872: 0x0002, 0x3873: 0x0002, 0x3874: 0x0002, 0x3875: 0x0002, + 0x3877: 0x0002, 0x3878: 0x0002, 0x3879: 0x0002, 0x387a: 0x0002, 0x387b: 0x0002, + 0x387c: 0x0002, 0x387d: 0x0002, 0x387e: 0x0002, 0x387f: 0x0002, + // Block 0xe2, offset 0x3880 + 0x3880: 0x0002, 0x3881: 0x0002, 0x3882: 0x0002, 0x3883: 0x0002, 0x3884: 0x0002, 0x3885: 0x0002, + 0x3886: 0x0002, 0x3887: 0x0002, 0x3888: 0x0002, 0x3889: 0x0002, 0x388a: 0x0002, 0x388b: 0x0002, + 0x388c: 0x0002, 0x388d: 0x0002, 0x388e: 0x0002, 0x388f: 0x0002, 0x3890: 0x0002, 0x3891: 0x0002, + 0x3892: 0x0002, 0x3893: 0x0002, 0x3894: 0x0002, 0x3895: 0x0002, 0x3896: 0x0002, 0x3897: 0x0002, + 0x3898: 0x0002, 0x3899: 0x0002, 0x389a: 0x0002, 0x389b: 0x0002, 0x389c: 0x0002, 0x389d: 0x0002, + 0x389e: 0x0002, 0x389f: 0x0002, 0x38a0: 0x0002, 0x38a1: 0x0002, 0x38a2: 0x0002, 0x38a3: 0x0002, + 0x38a4: 0x0002, 0x38a5: 0x0002, 0x38a6: 0x0002, 0x38a7: 0x0002, 0x38a8: 0x0002, 0x38a9: 0x0002, + 0x38aa: 0x0002, 0x38ab: 0x0002, 0x38ac: 0x0002, 0x38ad: 0x0002, 0x38ae: 0x0002, 0x38af: 0x0002, + 0x38b0: 0x0002, 0x38b1: 0x0002, 0x38b2: 0x0002, 0x38b3: 0x0002, 0x38b4: 0x0002, 0x38b5: 0x0002, + 0x38b6: 0x0002, 0x38b7: 0x0002, 0x38b8: 0x0002, 0x38b9: 0x0002, 0x38ba: 0x0002, 0x38bb: 0x0002, + 0x38bc: 0x0002, 0x38be: 0x0002, 0x38bf: 0x0002, + // Block 0xe3, offset 0x38c0 + 0x38c0: 0x0002, 0x38c1: 0x0002, 0x38c2: 0x0002, 0x38c3: 0x0002, 0x38c4: 0x0002, 0x38c5: 0x0002, + 0x38c6: 0x0002, 0x38c7: 0x0002, 0x38c8: 0x0002, 0x38c9: 0x0002, 0x38ca: 0x0002, 0x38cb: 0x0002, + 0x38cc: 0x0002, 0x38cd: 0x0002, 0x38ce: 0x0002, 0x38cf: 0x0002, 0x38d0: 0x0002, 0x38d1: 0x0002, + 0x38d2: 0x0002, 0x38d3: 0x0002, + 0x38e0: 0x0002, 0x38e1: 0x0002, 0x38e2: 0x0002, 0x38e3: 0x0002, + 0x38e4: 0x0002, 0x38e5: 0x0002, 0x38e6: 0x0002, 0x38e7: 0x0002, 0x38e8: 0x0002, 0x38e9: 0x0002, + 0x38ea: 0x0002, 0x38eb: 0x0002, 0x38ec: 0x0002, 0x38ed: 0x0002, 0x38ee: 0x0002, 0x38ef: 0x0002, + 0x38f0: 0x0002, 0x38f1: 0x0002, 0x38f2: 0x0002, 0x38f3: 0x0002, 0x38f4: 0x0002, 0x38f5: 0x0002, + 0x38f6: 0x0002, 0x38f7: 0x0002, 0x38f8: 0x0002, 0x38f9: 0x0002, 0x38fa: 0x0002, 0x38fb: 0x0002, + 0x38fc: 0x0002, 0x38fd: 0x0002, 0x38fe: 0x0002, 0x38ff: 0x0002, + // Block 0xe4, offset 0x3900 + 0x3900: 0x0002, 0x3901: 0x0002, 0x3902: 0x0002, 0x3903: 0x0002, 0x3904: 0x0002, 0x3905: 0x0002, + 0x3906: 0x0002, 0x3907: 0x0002, 0x3908: 0x0002, 0x3909: 0x0002, 0x390a: 0x0002, + 0x390f: 0x0002, 0x3910: 0x0002, 0x3911: 0x0002, + 0x3912: 0x0002, 0x3913: 0x0002, + 0x3920: 0x0002, 0x3921: 0x0002, 0x3922: 0x0002, 0x3923: 0x0002, + 0x3924: 0x0002, 0x3925: 0x0002, 0x3926: 0x0002, 0x3927: 0x0002, 0x3928: 0x0002, 0x3929: 0x0002, + 0x392a: 0x0002, 0x392b: 0x0002, 0x392c: 0x0002, 0x392d: 0x0002, 0x392e: 0x0002, 0x392f: 0x0002, + 0x3930: 0x0002, 0x3934: 0x0002, + 0x3938: 0x0002, 0x3939: 0x0002, 0x393a: 0x0002, 0x393b: 0x0002, + 0x393c: 0x0002, 0x393d: 0x0002, 0x393e: 0x0002, 0x393f: 0x0002, + // Block 0xe5, offset 0x3940 + 0x3940: 0x0002, 0x3941: 0x0002, 0x3942: 0x0002, 0x3943: 0x0002, 0x3944: 0x0002, 0x3945: 0x0002, + 0x3946: 0x0002, 0x3947: 0x0002, 0x3948: 0x0002, 0x3949: 0x0002, 0x394a: 0x0002, 0x394b: 0x0002, + 0x394c: 0x0002, 0x394d: 0x0002, 0x394e: 0x0002, 0x394f: 0x0002, 0x3950: 0x0002, 0x3951: 0x0002, + 0x3952: 0x0002, 0x3953: 0x0002, 0x3954: 0x0002, 0x3955: 0x0002, 0x3956: 0x0002, 0x3957: 0x0002, + 0x3958: 0x0002, 0x3959: 0x0002, 0x395a: 0x0002, 0x395b: 0x0002, 0x395c: 0x0002, 0x395d: 0x0002, + 0x395e: 0x0002, 0x395f: 0x0002, 0x3960: 0x0002, 0x3961: 0x0002, 0x3962: 0x0002, 0x3963: 0x0002, + 0x3964: 0x0002, 0x3965: 0x0002, 0x3966: 0x0002, 0x3967: 0x0002, 0x3968: 0x0002, 0x3969: 0x0002, + 0x396a: 0x0002, 0x396b: 0x0002, 0x396c: 0x0002, 0x396d: 0x0002, 0x396e: 0x0002, 0x396f: 0x0002, + 0x3970: 0x0002, 0x3971: 0x0002, 0x3972: 0x0002, 0x3973: 0x0002, 0x3974: 0x0002, 0x3975: 0x0002, + 0x3976: 0x0002, 0x3977: 0x0002, 0x3978: 0x0002, 0x3979: 0x0002, 0x397a: 0x0002, 0x397b: 0x0002, + 0x397c: 0x0002, 0x397d: 0x0002, 0x397e: 0x0002, + // Block 0xe6, offset 0x3980 + 0x3980: 0x0002, 0x3982: 0x0002, 0x3983: 0x0002, 0x3984: 0x0002, 0x3985: 0x0002, + 0x3986: 0x0002, 0x3987: 0x0002, 0x3988: 0x0002, 0x3989: 0x0002, 0x398a: 0x0002, 0x398b: 0x0002, + 0x398c: 0x0002, 0x398d: 0x0002, 0x398e: 0x0002, 0x398f: 0x0002, 0x3990: 0x0002, 0x3991: 0x0002, + 0x3992: 0x0002, 0x3993: 0x0002, 0x3994: 0x0002, 0x3995: 0x0002, 0x3996: 0x0002, 0x3997: 0x0002, + 0x3998: 0x0002, 0x3999: 0x0002, 0x399a: 0x0002, 0x399b: 0x0002, 0x399c: 0x0002, 0x399d: 0x0002, + 0x399e: 0x0002, 0x399f: 0x0002, 0x39a0: 0x0002, 0x39a1: 0x0002, 0x39a2: 0x0002, 0x39a3: 0x0002, + 0x39a4: 0x0002, 0x39a5: 0x0002, 0x39a6: 0x0002, 0x39a7: 0x0002, 0x39a8: 0x0002, 0x39a9: 0x0002, + 0x39aa: 0x0002, 0x39ab: 0x0002, 0x39ac: 0x0002, 0x39ad: 0x0002, 0x39ae: 0x0002, 0x39af: 0x0002, + 0x39b0: 0x0002, 0x39b1: 0x0002, 0x39b2: 0x0002, 0x39b3: 0x0002, 0x39b4: 0x0002, 0x39b5: 0x0002, + 0x39b6: 0x0002, 0x39b7: 0x0002, 0x39b8: 0x0002, 0x39b9: 0x0002, 0x39ba: 0x0002, 0x39bb: 0x0002, + 0x39bc: 0x0002, 0x39bd: 0x0002, 0x39be: 0x0002, 0x39bf: 0x0002, + // Block 0xe7, offset 0x39c0 + 0x39c0: 0x0002, 0x39c1: 0x0002, 0x39c2: 0x0002, 0x39c3: 0x0002, 0x39c4: 0x0002, 0x39c5: 0x0002, + 0x39c6: 0x0002, 0x39c7: 0x0002, 0x39c8: 0x0002, 0x39c9: 0x0002, 0x39ca: 0x0002, 0x39cb: 0x0002, + 0x39cc: 0x0002, 0x39cd: 0x0002, 0x39ce: 0x0002, 0x39cf: 0x0002, 0x39d0: 0x0002, 0x39d1: 0x0002, + 0x39d2: 0x0002, 0x39d3: 0x0002, 0x39d4: 0x0002, 0x39d5: 0x0002, 0x39d6: 0x0002, 0x39d7: 0x0002, + 0x39d8: 0x0002, 0x39d9: 0x0002, 0x39da: 0x0002, 0x39db: 0x0002, 0x39dc: 0x0002, 0x39dd: 0x0002, + 0x39de: 0x0002, 0x39df: 0x0002, 0x39e0: 0x0002, 0x39e1: 0x0002, 0x39e2: 0x0002, 0x39e3: 0x0002, + 0x39e4: 0x0002, 0x39e5: 0x0002, 0x39e6: 0x0002, 0x39e7: 0x0002, 0x39e8: 0x0002, 0x39e9: 0x0002, + 0x39ea: 0x0002, 0x39eb: 0x0002, 0x39ec: 0x0002, 0x39ed: 0x0002, 0x39ee: 0x0002, 0x39ef: 0x0002, + 0x39f0: 0x0002, 0x39f1: 0x0002, 0x39f2: 0x0002, 0x39f3: 0x0002, 0x39f4: 0x0002, 0x39f5: 0x0002, + 0x39f6: 0x0002, 0x39f7: 0x0002, 0x39f8: 0x0002, 0x39f9: 0x0002, 0x39fa: 0x0002, 0x39fb: 0x0002, + 0x39fc: 0x0002, 0x39ff: 0x0002, + // Block 0xe8, offset 0x3a00 + 0x3a00: 0x0002, 0x3a01: 0x0002, 0x3a02: 0x0002, 0x3a03: 0x0002, 0x3a04: 0x0002, 0x3a05: 0x0002, + 0x3a06: 0x0002, 0x3a07: 0x0002, 0x3a08: 0x0002, 0x3a09: 0x0002, 0x3a0a: 0x0002, 0x3a0b: 0x0002, + 0x3a0c: 0x0002, 0x3a0d: 0x0002, 0x3a0e: 0x0002, 0x3a0f: 0x0002, 0x3a10: 0x0002, 0x3a11: 0x0002, + 0x3a12: 0x0002, 0x3a13: 0x0002, 0x3a14: 0x0002, 0x3a15: 0x0002, 0x3a16: 0x0002, 0x3a17: 0x0002, + 0x3a18: 0x0002, 0x3a19: 0x0002, 0x3a1a: 0x0002, 0x3a1b: 0x0002, 0x3a1c: 0x0002, 0x3a1d: 0x0002, + 0x3a1e: 0x0002, 0x3a1f: 0x0002, 0x3a20: 0x0002, 0x3a21: 0x0002, 0x3a22: 0x0002, 0x3a23: 0x0002, + 0x3a24: 0x0002, 0x3a25: 0x0002, 0x3a26: 0x0002, 0x3a27: 0x0002, 0x3a28: 0x0002, 0x3a29: 0x0002, + 0x3a2a: 0x0002, 0x3a2b: 0x0002, 0x3a2c: 0x0002, 0x3a2d: 0x0002, 0x3a2e: 0x0002, 0x3a2f: 0x0002, + 0x3a30: 0x0002, 0x3a31: 0x0002, 0x3a32: 0x0002, 0x3a33: 0x0002, 0x3a34: 0x0002, 0x3a35: 0x0002, + 0x3a36: 0x0002, 0x3a37: 0x0002, 0x3a38: 0x0002, 0x3a39: 0x0002, 0x3a3a: 0x0002, 0x3a3b: 0x0002, + 0x3a3c: 0x0002, 0x3a3d: 0x0002, + // Block 0xe9, offset 0x3a40 + 0x3a4b: 0x0002, + 0x3a4c: 0x0002, 0x3a4d: 0x0002, 0x3a4e: 0x0002, 0x3a50: 0x0002, 0x3a51: 0x0002, + 0x3a52: 0x0002, 0x3a53: 0x0002, 0x3a54: 0x0002, 0x3a55: 0x0002, 0x3a56: 0x0002, 0x3a57: 0x0002, + 0x3a58: 0x0002, 0x3a59: 0x0002, 0x3a5a: 0x0002, 0x3a5b: 0x0002, 0x3a5c: 0x0002, 0x3a5d: 0x0002, + 0x3a5e: 0x0002, 0x3a5f: 0x0002, 0x3a60: 0x0002, 0x3a61: 0x0002, 0x3a62: 0x0002, 0x3a63: 0x0002, + 0x3a64: 0x0002, 0x3a65: 0x0002, 0x3a66: 0x0002, 0x3a67: 0x0002, + 0x3a7a: 0x0002, + // Block 0xea, offset 0x3a80 + 0x3a95: 0x0002, 0x3a96: 0x0002, + 0x3aa4: 0x0002, + // Block 0xeb, offset 0x3ac0 + 0x3afb: 0x0002, + 0x3afc: 0x0002, 0x3afd: 0x0002, 0x3afe: 0x0002, 0x3aff: 0x0002, + // Block 0xec, offset 0x3b00 + 0x3b00: 0x0002, 0x3b01: 0x0002, 0x3b02: 0x0002, 0x3b03: 0x0002, 0x3b04: 0x0002, 0x3b05: 0x0002, + 0x3b06: 0x0002, 0x3b07: 0x0002, 0x3b08: 0x0002, 0x3b09: 0x0002, 0x3b0a: 0x0002, 0x3b0b: 0x0002, + 0x3b0c: 0x0002, 0x3b0d: 0x0002, 0x3b0e: 0x0002, 0x3b0f: 0x0002, + // Block 0xed, offset 0x3b40 + 0x3b40: 0x0002, 0x3b41: 0x0002, 0x3b42: 0x0002, 0x3b43: 0x0002, 0x3b44: 0x0002, 0x3b45: 0x0002, + 0x3b4c: 0x0002, 0x3b50: 0x0002, 0x3b51: 0x0002, + 0x3b52: 0x0002, 0x3b55: 0x0002, 0x3b56: 0x0002, 0x3b57: 0x0002, + 0x3b58: 0x0002, 0x3b5c: 0x0002, 0x3b5d: 0x0002, + 0x3b5e: 0x0002, 0x3b5f: 0x0002, + 0x3b6b: 0x0002, 0x3b6c: 0x0002, + 0x3b74: 0x0002, 0x3b75: 0x0002, + 0x3b76: 0x0002, 0x3b77: 0x0002, 0x3b78: 0x0002, 0x3b79: 0x0002, 0x3b7a: 0x0002, 0x3b7b: 0x0002, + 0x3b7c: 0x0002, + // Block 0xee, offset 0x3b80 + 0x3ba0: 0x0002, 0x3ba1: 0x0002, 0x3ba2: 0x0002, 0x3ba3: 0x0002, + 0x3ba4: 0x0002, 0x3ba5: 0x0002, 0x3ba6: 0x0002, 0x3ba7: 0x0002, 0x3ba8: 0x0002, 0x3ba9: 0x0002, + 0x3baa: 0x0002, 0x3bab: 0x0002, + 0x3bb0: 0x0002, + // Block 0xef, offset 0x3bc0 + 0x3bcc: 0x0002, 0x3bcd: 0x0002, 0x3bce: 0x0002, 0x3bcf: 0x0002, 0x3bd0: 0x0002, 0x3bd1: 0x0002, + 0x3bd2: 0x0002, 0x3bd3: 0x0002, 0x3bd4: 0x0002, 0x3bd5: 0x0002, 0x3bd6: 0x0002, 0x3bd7: 0x0002, + 0x3bd8: 0x0002, 0x3bd9: 0x0002, 0x3bda: 0x0002, 0x3bdb: 0x0002, 0x3bdc: 0x0002, 0x3bdd: 0x0002, + 0x3bde: 0x0002, 0x3bdf: 0x0002, 0x3be0: 0x0002, 0x3be1: 0x0002, 0x3be2: 0x0002, 0x3be3: 0x0002, + 0x3be4: 0x0002, 0x3be5: 0x0002, 0x3be6: 0x0002, 0x3be7: 0x0002, 0x3be8: 0x0002, 0x3be9: 0x0002, + 0x3bea: 0x0002, 0x3beb: 0x0002, 0x3bec: 0x0002, 0x3bed: 0x0002, 0x3bee: 0x0002, 0x3bef: 0x0002, + 0x3bf0: 0x0002, 0x3bf1: 0x0002, 0x3bf2: 0x0002, 0x3bf3: 0x0002, 0x3bf4: 0x0002, 0x3bf5: 0x0002, + 0x3bf6: 0x0002, 0x3bf7: 0x0002, 0x3bf8: 0x0002, 0x3bf9: 0x0002, 0x3bfa: 0x0002, + 0x3bfc: 0x0002, 0x3bfd: 0x0002, 0x3bfe: 0x0002, 0x3bff: 0x0002, + // Block 0xf0, offset 0x3c00 + 0x3c00: 0x0002, 0x3c01: 0x0002, 0x3c02: 0x0002, 0x3c03: 0x0002, 0x3c04: 0x0002, 0x3c05: 0x0002, + 0x3c07: 0x0002, 0x3c08: 0x0002, 0x3c09: 0x0002, 0x3c0a: 0x0002, 0x3c0b: 0x0002, + 0x3c0c: 0x0002, 0x3c0d: 0x0002, 0x3c0e: 0x0002, 0x3c0f: 0x0002, 0x3c10: 0x0002, 0x3c11: 0x0002, + 0x3c12: 0x0002, 0x3c13: 0x0002, 0x3c14: 0x0002, 0x3c15: 0x0002, 0x3c16: 0x0002, 0x3c17: 0x0002, + 0x3c18: 0x0002, 0x3c19: 0x0002, 0x3c1a: 0x0002, 0x3c1b: 0x0002, 0x3c1c: 0x0002, 0x3c1d: 0x0002, + 0x3c1e: 0x0002, 0x3c1f: 0x0002, 0x3c20: 0x0002, 0x3c21: 0x0002, 0x3c22: 0x0002, 0x3c23: 0x0002, + 0x3c24: 0x0002, 0x3c25: 0x0002, 0x3c26: 0x0002, 0x3c27: 0x0002, 0x3c28: 0x0002, 0x3c29: 0x0002, + 0x3c2a: 0x0002, 0x3c2b: 0x0002, 0x3c2c: 0x0002, 0x3c2d: 0x0002, 0x3c2e: 0x0002, 0x3c2f: 0x0002, + 0x3c30: 0x0002, 0x3c31: 0x0002, 0x3c32: 0x0002, 0x3c33: 0x0002, 0x3c34: 0x0002, 0x3c35: 0x0002, + 0x3c36: 0x0002, 0x3c37: 0x0002, 0x3c38: 0x0002, 0x3c39: 0x0002, 0x3c3a: 0x0002, 0x3c3b: 0x0002, + 0x3c3c: 0x0002, 0x3c3d: 0x0002, 0x3c3e: 0x0002, 0x3c3f: 0x0002, + // Block 0xf1, offset 0x3c40 + 0x3c70: 0x0002, 0x3c71: 0x0002, 0x3c72: 0x0002, 0x3c73: 0x0002, 0x3c74: 0x0002, 0x3c75: 0x0002, + 0x3c76: 0x0002, 0x3c77: 0x0002, 0x3c78: 0x0002, 0x3c79: 0x0002, 0x3c7a: 0x0002, 0x3c7b: 0x0002, + 0x3c7c: 0x0002, + // Block 0xf2, offset 0x3c80 + 0x3c80: 0x0002, 0x3c81: 0x0002, 0x3c82: 0x0002, 0x3c83: 0x0002, 0x3c84: 0x0002, 0x3c85: 0x0002, + 0x3c86: 0x0002, 0x3c87: 0x0002, 0x3c88: 0x0002, 0x3c89: 0x0002, 0x3c8a: 0x0002, + 0x3c8e: 0x0002, 0x3c8f: 0x0002, 0x3c90: 0x0002, 0x3c91: 0x0002, + 0x3c92: 0x0002, 0x3c93: 0x0002, 0x3c94: 0x0002, 0x3c95: 0x0002, 0x3c96: 0x0002, 0x3c97: 0x0002, + 0x3c98: 0x0002, 0x3c99: 0x0002, 0x3c9a: 0x0002, 0x3c9b: 0x0002, 0x3c9c: 0x0002, 0x3c9d: 0x0002, + 0x3c9e: 0x0002, 0x3c9f: 0x0002, 0x3ca0: 0x0002, 0x3ca1: 0x0002, 0x3ca2: 0x0002, 0x3ca3: 0x0002, + 0x3ca4: 0x0002, 0x3ca5: 0x0002, 0x3ca6: 0x0002, 0x3ca7: 0x0002, 0x3ca8: 0x0002, 0x3ca9: 0x0002, + 0x3caa: 0x0002, 0x3cab: 0x0002, 0x3cac: 0x0002, 0x3cad: 0x0002, 0x3cae: 0x0002, 0x3caf: 0x0002, + 0x3cb0: 0x0002, 0x3cb1: 0x0002, 0x3cb2: 0x0002, 0x3cb3: 0x0002, 0x3cb4: 0x0002, 0x3cb5: 0x0002, + 0x3cb6: 0x0002, 0x3cb7: 0x0002, 0x3cb8: 0x0002, 0x3cb9: 0x0002, 0x3cba: 0x0002, 0x3cbb: 0x0002, + 0x3cbc: 0x0002, 0x3cbd: 0x0002, 0x3cbe: 0x0002, 0x3cbf: 0x0002, + // Block 0xf3, offset 0x3cc0 + 0x3cc0: 0x0002, 0x3cc1: 0x0002, 0x3cc2: 0x0002, 0x3cc3: 0x0002, 0x3cc4: 0x0002, 0x3cc5: 0x0002, + 0x3cc6: 0x0002, 0x3cc8: 0x0002, + 0x3ccd: 0x0002, 0x3cce: 0x0002, 0x3ccf: 0x0002, 0x3cd0: 0x0002, 0x3cd1: 0x0002, + 0x3cd2: 0x0002, 0x3cd3: 0x0002, 0x3cd4: 0x0002, 0x3cd5: 0x0002, 0x3cd6: 0x0002, 0x3cd7: 0x0002, + 0x3cd8: 0x0002, 0x3cd9: 0x0002, 0x3cda: 0x0002, 0x3cdb: 0x0002, 0x3cdc: 0x0002, + 0x3cdf: 0x0002, 0x3ce0: 0x0002, 0x3ce1: 0x0002, 0x3ce2: 0x0002, 0x3ce3: 0x0002, + 0x3ce4: 0x0002, 0x3ce5: 0x0002, 0x3ce6: 0x0002, 0x3ce7: 0x0002, 0x3ce8: 0x0002, 0x3ce9: 0x0002, + 0x3cea: 0x0002, 0x3cef: 0x0002, + 0x3cf0: 0x0002, 0x3cf1: 0x0002, 0x3cf2: 0x0002, 0x3cf3: 0x0002, 0x3cf4: 0x0002, 0x3cf5: 0x0002, + 0x3cf6: 0x0002, 0x3cf7: 0x0002, 0x3cf8: 0x0002, + // Block 0xf4, offset 0x3d00 + 0x3d01: 0x0001, + 0x3d20: 0x0001, 0x3d21: 0x0001, 0x3d22: 0x0001, 0x3d23: 0x0001, + 0x3d24: 0x0001, 0x3d25: 0x0001, 0x3d26: 0x0001, 0x3d27: 0x0001, 0x3d28: 0x0001, 0x3d29: 0x0001, + 0x3d2a: 0x0001, 0x3d2b: 0x0001, 0x3d2c: 0x0001, 0x3d2d: 0x0001, 0x3d2e: 0x0001, 0x3d2f: 0x0001, + 0x3d30: 0x0001, 0x3d31: 0x0001, 0x3d32: 0x0001, 0x3d33: 0x0001, 0x3d34: 0x0001, 0x3d35: 0x0001, + 0x3d36: 0x0001, 0x3d37: 0x0001, 0x3d38: 0x0001, 0x3d39: 0x0001, 0x3d3a: 0x0001, 0x3d3b: 0x0001, + 0x3d3c: 0x0001, 0x3d3d: 0x0001, 0x3d3e: 0x0001, 0x3d3f: 0x0001, + // Block 0xf5, offset 0x3d40 + 0x3d40: 0x0003, 0x3d41: 0x0003, 0x3d42: 0x0003, 0x3d43: 0x0003, 0x3d44: 0x0003, 0x3d45: 0x0003, + 0x3d46: 0x0003, 0x3d47: 0x0003, 0x3d48: 0x0003, 0x3d49: 0x0003, 0x3d4a: 0x0003, 0x3d4b: 0x0003, + 0x3d4c: 0x0003, 0x3d4d: 0x0003, 0x3d4e: 0x0003, 0x3d4f: 0x0003, 0x3d50: 0x0003, 0x3d51: 0x0003, + 0x3d52: 0x0003, 0x3d53: 0x0003, 0x3d54: 0x0003, 0x3d55: 0x0003, 0x3d56: 0x0003, 0x3d57: 0x0003, + 0x3d58: 0x0003, 0x3d59: 0x0003, 0x3d5a: 0x0003, 0x3d5b: 0x0003, 0x3d5c: 0x0003, 0x3d5d: 0x0003, + 0x3d5e: 0x0003, 0x3d5f: 0x0003, 0x3d60: 0x0003, 0x3d61: 0x0003, 0x3d62: 0x0003, 0x3d63: 0x0003, + 0x3d64: 0x0003, 0x3d65: 0x0003, 0x3d66: 0x0003, 0x3d67: 0x0003, 0x3d68: 0x0003, 0x3d69: 0x0003, + 0x3d6a: 0x0003, 0x3d6b: 0x0003, 0x3d6c: 0x0003, 0x3d6d: 0x0003, 0x3d6e: 0x0003, 0x3d6f: 0x0003, + 0x3d70: 0x0003, 0x3d71: 0x0003, 0x3d72: 0x0003, 0x3d73: 0x0003, 0x3d74: 0x0003, 0x3d75: 0x0003, + 0x3d76: 0x0003, 0x3d77: 0x0003, 0x3d78: 0x0003, 0x3d79: 0x0003, 0x3d7a: 0x0003, 0x3d7b: 0x0003, + 0x3d7c: 0x0003, 0x3d7d: 0x0003, +} + +// stringWidthIndex: 30 blocks, 1920 entries, 1920 bytes +// Block 0 is the zero block. +var stringWidthIndex = [1920]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc7: 0x05, + 0xc9: 0x06, 0xcb: 0x07, 0xcc: 0x08, 0xcd: 0x09, 0xce: 0x0a, 0xcf: 0x0b, + 0xd0: 0x0c, 0xd1: 0x0d, 0xd2: 0x0e, 0xd6: 0x0f, 0xd7: 0x10, + 0xd8: 0x11, 0xd9: 0x12, 0xdb: 0x13, 0xdc: 0x14, 0xdd: 0x15, 0xde: 0x16, 0xdf: 0x17, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x06, 0xe6: 0x06, 0xe7: 0x06, + 0xe8: 0x06, 0xe9: 0x06, 0xea: 0x07, 0xeb: 0x06, 0xec: 0x06, 0xed: 0x08, 0xee: 0x09, 0xef: 0x0a, + 0xf0: 0x17, 0xf3: 0x1a, 0xf4: 0x1b, + // Block 0x4, offset 0x100 + 0x120: 0x18, 0x121: 0x19, 0x122: 0x1a, 0x123: 0x1b, 0x124: 0x1c, 0x125: 0x1d, 0x126: 0x1e, 0x127: 0x1f, + 0x128: 0x20, 0x129: 0x21, 0x12a: 0x20, 0x12b: 0x22, 0x12c: 0x23, 0x12d: 0x24, 0x12e: 0x25, 0x12f: 0x26, + 0x130: 0x27, 0x131: 0x28, 0x132: 0x23, 0x133: 0x29, 0x134: 0x2a, 0x135: 0x2b, 0x136: 0x2c, 0x137: 0x2d, + 0x138: 0x2e, 0x139: 0x2f, 0x13a: 0x30, 0x13b: 0x31, 0x13c: 0x32, 0x13d: 0x33, 0x13e: 0x34, 0x13f: 0x35, + // Block 0x5, offset 0x140 + 0x140: 0x36, 0x141: 0x37, 0x142: 0x38, 0x144: 0x39, 0x145: 0x3a, + 0x14d: 0x3b, + 0x15c: 0x3c, 0x15d: 0x3d, 0x15e: 0x3e, 0x15f: 0x3f, + 0x160: 0x40, 0x162: 0x41, 0x164: 0x42, + 0x168: 0x43, 0x169: 0x44, 0x16a: 0x45, 0x16b: 0x46, 0x16c: 0x47, 0x16d: 0x48, 0x16e: 0x49, 0x16f: 0x4a, + 0x170: 0x4b, 0x173: 0x4c, 0x177: 0x08, + // Block 0x6, offset 0x180 + 0x180: 0x4d, 0x181: 0x4e, 0x182: 0x4f, 0x183: 0x50, 0x184: 0x51, 0x185: 0x52, 0x186: 0x53, 0x187: 0x54, + 0x188: 0x55, 0x189: 0x56, 0x18a: 0x57, 0x18c: 0x58, 0x18f: 0x59, + 0x191: 0x5a, 0x192: 0x5b, 0x193: 0x5c, 0x194: 0x5b, 0x195: 0x5d, 0x196: 0x5e, 0x197: 0x5f, + 0x198: 0x60, 0x199: 0x61, 0x19a: 0x62, 0x19b: 0x63, 0x19c: 0x64, 0x19d: 0x65, 0x19e: 0x66, + 0x1ac: 0x67, 0x1ad: 0x68, + 0x1b3: 0x69, 0x1b5: 0x6a, 0x1b7: 0x6b, + 0x1ba: 0x6c, 0x1bb: 0x6d, 0x1bc: 0x39, 0x1bd: 0x39, 0x1be: 0x39, 0x1bf: 0x6e, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x6f, 0x1c1: 0x70, 0x1c2: 0x71, 0x1c3: 0x39, 0x1c4: 0x72, 0x1c5: 0x39, 0x1c6: 0x73, 0x1c7: 0x74, + 0x1c8: 0x75, 0x1c9: 0x76, 0x1ca: 0x39, 0x1cb: 0x39, 0x1cc: 0x39, 0x1cd: 0x39, 0x1ce: 0x39, 0x1cf: 0x39, + 0x1d0: 0x39, 0x1d1: 0x39, 0x1d2: 0x39, 0x1d3: 0x39, 0x1d4: 0x39, 0x1d5: 0x39, 0x1d6: 0x39, 0x1d7: 0x39, + 0x1d8: 0x39, 0x1d9: 0x39, 0x1da: 0x39, 0x1db: 0x39, 0x1dc: 0x39, 0x1dd: 0x39, 0x1de: 0x39, 0x1df: 0x39, + 0x1e0: 0x39, 0x1e1: 0x39, 0x1e2: 0x39, 0x1e3: 0x39, 0x1e4: 0x39, 0x1e5: 0x39, 0x1e6: 0x39, 0x1e7: 0x39, + 0x1e8: 0x39, 0x1e9: 0x39, 0x1ea: 0x39, 0x1eb: 0x39, 0x1ec: 0x39, 0x1ed: 0x39, 0x1ee: 0x39, 0x1ef: 0x39, + 0x1f0: 0x39, 0x1f1: 0x39, 0x1f2: 0x39, 0x1f3: 0x39, 0x1f4: 0x39, 0x1f5: 0x39, 0x1f6: 0x39, 0x1f7: 0x39, + 0x1f8: 0x39, 0x1f9: 0x39, 0x1fa: 0x39, 0x1fb: 0x39, 0x1fc: 0x39, 0x1fd: 0x39, 0x1fe: 0x39, 0x1ff: 0x39, + // Block 0x8, offset 0x200 + 0x200: 0x39, 0x201: 0x39, 0x202: 0x39, 0x203: 0x39, 0x204: 0x39, 0x205: 0x39, 0x206: 0x39, 0x207: 0x39, + 0x208: 0x39, 0x209: 0x39, 0x20a: 0x39, 0x20b: 0x39, 0x20c: 0x39, 0x20d: 0x39, 0x20e: 0x39, 0x20f: 0x39, + 0x210: 0x39, 0x211: 0x39, 0x212: 0x39, 0x213: 0x39, 0x214: 0x39, 0x215: 0x39, 0x216: 0x39, 0x217: 0x39, + 0x218: 0x39, 0x219: 0x39, 0x21a: 0x39, 0x21b: 0x39, 0x21c: 0x39, 0x21d: 0x39, 0x21e: 0x39, 0x21f: 0x39, + 0x220: 0x39, 0x221: 0x39, 0x222: 0x39, 0x223: 0x39, 0x224: 0x39, 0x225: 0x39, 0x226: 0x39, 0x227: 0x39, + 0x228: 0x39, 0x229: 0x39, 0x22a: 0x39, 0x22b: 0x39, 0x22c: 0x39, 0x22d: 0x39, 0x22e: 0x39, 0x22f: 0x39, + 0x230: 0x39, 0x231: 0x39, 0x232: 0x39, 0x233: 0x39, 0x234: 0x39, 0x235: 0x39, 0x236: 0x39, 0x237: 0x39, + 0x238: 0x39, 0x239: 0x39, 0x23a: 0x39, 0x23b: 0x39, 0x23c: 0x39, 0x23d: 0x39, 0x23e: 0x39, 0x23f: 0x39, + // Block 0x9, offset 0x240 + 0x240: 0x39, 0x241: 0x39, 0x242: 0x39, 0x243: 0x39, 0x244: 0x39, 0x245: 0x39, 0x246: 0x39, 0x247: 0x39, + 0x248: 0x39, 0x249: 0x39, 0x24a: 0x39, 0x24b: 0x39, 0x24c: 0x39, 0x24d: 0x39, 0x24e: 0x39, 0x24f: 0x39, + 0x250: 0x39, 0x251: 0x39, 0x252: 0x77, 0x253: 0x78, + 0x259: 0x79, 0x25a: 0x7a, 0x25b: 0x7b, + 0x260: 0x7c, 0x263: 0x7d, 0x264: 0x7e, 0x265: 0x7f, 0x266: 0x80, 0x267: 0x81, + 0x268: 0x82, 0x269: 0x83, 0x26a: 0x84, 0x26b: 0x85, 0x26f: 0x86, + 0x270: 0x39, 0x271: 0x39, 0x272: 0x39, 0x273: 0x39, 0x274: 0x39, 0x275: 0x39, 0x276: 0x39, 0x277: 0x39, + 0x278: 0x39, 0x279: 0x39, 0x27a: 0x39, 0x27b: 0x39, 0x27c: 0x39, 0x27d: 0x39, 0x27e: 0x39, 0x27f: 0x39, + // Block 0xa, offset 0x280 + 0x280: 0x39, 0x281: 0x39, 0x282: 0x39, 0x283: 0x39, 0x284: 0x39, 0x285: 0x39, 0x286: 0x39, 0x287: 0x39, + 0x288: 0x39, 0x289: 0x39, 0x28a: 0x39, 0x28b: 0x39, 0x28c: 0x39, 0x28d: 0x39, 0x28e: 0x39, 0x28f: 0x39, + 0x290: 0x39, 0x291: 0x39, 0x292: 0x39, 0x293: 0x39, 0x294: 0x39, 0x295: 0x39, 0x296: 0x39, 0x297: 0x39, + 0x298: 0x39, 0x299: 0x39, 0x29a: 0x39, 0x29b: 0x39, 0x29c: 0x39, 0x29d: 0x39, 0x29e: 0x87, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x5b, 0x2c1: 0x5b, 0x2c2: 0x5b, 0x2c3: 0x5b, 0x2c4: 0x5b, 0x2c5: 0x5b, 0x2c6: 0x5b, 0x2c7: 0x5b, + 0x2c8: 0x5b, 0x2c9: 0x5b, 0x2ca: 0x5b, 0x2cb: 0x5b, 0x2cc: 0x5b, 0x2cd: 0x5b, 0x2ce: 0x5b, 0x2cf: 0x5b, + 0x2d0: 0x5b, 0x2d1: 0x5b, 0x2d2: 0x5b, 0x2d3: 0x5b, 0x2d4: 0x5b, 0x2d5: 0x5b, 0x2d6: 0x5b, 0x2d7: 0x5b, + 0x2d8: 0x5b, 0x2d9: 0x5b, 0x2da: 0x5b, 0x2db: 0x5b, 0x2dc: 0x5b, 0x2dd: 0x5b, 0x2de: 0x5b, 0x2df: 0x5b, + 0x2e0: 0x5b, 0x2e1: 0x5b, 0x2e2: 0x5b, 0x2e3: 0x5b, 0x2e4: 0x5b, 0x2e5: 0x5b, 0x2e6: 0x5b, 0x2e7: 0x5b, + 0x2e8: 0x5b, 0x2e9: 0x5b, 0x2ea: 0x5b, 0x2eb: 0x5b, 0x2ec: 0x5b, 0x2ed: 0x5b, 0x2ee: 0x5b, 0x2ef: 0x5b, + 0x2f0: 0x5b, 0x2f1: 0x5b, 0x2f2: 0x5b, 0x2f3: 0x5b, 0x2f4: 0x5b, 0x2f5: 0x5b, 0x2f6: 0x5b, 0x2f7: 0x5b, + 0x2f8: 0x5b, 0x2f9: 0x5b, 0x2fa: 0x5b, 0x2fb: 0x5b, 0x2fc: 0x5b, 0x2fd: 0x5b, 0x2fe: 0x5b, 0x2ff: 0x5b, + // Block 0xc, offset 0x300 + 0x300: 0x5b, 0x301: 0x5b, 0x302: 0x5b, 0x303: 0x5b, 0x304: 0x5b, 0x305: 0x5b, 0x306: 0x5b, 0x307: 0x5b, + 0x308: 0x5b, 0x309: 0x5b, 0x30a: 0x5b, 0x30b: 0x5b, 0x30c: 0x5b, 0x30d: 0x5b, 0x30e: 0x5b, 0x30f: 0x5b, + 0x310: 0x5b, 0x311: 0x5b, 0x312: 0x5b, 0x313: 0x5b, 0x314: 0x5b, 0x315: 0x5b, 0x316: 0x5b, 0x317: 0x5b, + 0x318: 0x5b, 0x319: 0x5b, 0x31a: 0x5b, 0x31b: 0x5b, 0x31c: 0x5b, 0x31d: 0x5b, 0x31e: 0x5b, 0x31f: 0x5b, + 0x320: 0x5b, 0x321: 0x5b, 0x322: 0x5b, 0x323: 0x5b, 0x324: 0x39, 0x325: 0x39, 0x326: 0x39, 0x327: 0x39, + 0x328: 0x39, 0x329: 0x39, 0x32a: 0x39, 0x32b: 0x39, 0x32c: 0x88, + 0x338: 0x89, 0x339: 0x8a, 0x33b: 0x6a, 0x33c: 0x70, 0x33d: 0x8b, 0x33f: 0x8c, + // Block 0xd, offset 0x340 + 0x347: 0x8d, + 0x34b: 0x8e, 0x34d: 0x8f, + 0x368: 0x90, 0x36b: 0x91, + 0x374: 0x92, + 0x37a: 0x93, 0x37b: 0x94, 0x37d: 0x95, 0x37e: 0x96, + // Block 0xe, offset 0x380 + 0x380: 0x97, 0x381: 0x98, 0x382: 0x99, 0x383: 0x9a, 0x384: 0x9b, 0x385: 0x9c, 0x386: 0x9d, 0x387: 0x9e, + 0x388: 0x9f, 0x389: 0x2c, 0x38b: 0xa0, 0x38c: 0x2a, 0x38d: 0xa1, + 0x390: 0xa2, 0x391: 0xa3, 0x392: 0xa4, 0x393: 0xa5, 0x396: 0xa6, 0x397: 0xa7, + 0x398: 0xa8, 0x399: 0xa9, 0x39a: 0xaa, 0x39c: 0xab, + 0x3a0: 0xac, 0x3a4: 0xad, 0x3a5: 0xae, 0x3a7: 0xaf, + 0x3a8: 0xb0, 0x3a9: 0xb1, 0x3aa: 0xb2, + 0x3b0: 0xb3, 0x3b2: 0xb4, 0x3b4: 0xb5, 0x3b5: 0xb6, 0x3b6: 0xb7, + 0x3bb: 0xb8, 0x3bc: 0xb9, 0x3bd: 0xba, + // Block 0xf, offset 0x3c0 + 0x3d0: 0x45, 0x3d1: 0xbb, + // Block 0x10, offset 0x400 + 0x42b: 0xbc, 0x42c: 0xbd, + 0x43d: 0xbe, 0x43e: 0xbf, 0x43f: 0xc0, + // Block 0x11, offset 0x440 + 0x440: 0x39, 0x441: 0x39, 0x442: 0x39, 0x443: 0x39, 0x444: 0x39, 0x445: 0x39, 0x446: 0x39, 0x447: 0x39, + 0x448: 0x39, 0x449: 0x39, 0x44a: 0x39, 0x44b: 0x39, 0x44c: 0x39, 0x44d: 0x39, 0x44e: 0x39, 0x44f: 0x39, + 0x450: 0x39, 0x451: 0x39, 0x452: 0x39, 0x453: 0x39, 0x454: 0x39, 0x455: 0x39, 0x456: 0x39, 0x457: 0x39, + 0x458: 0x39, 0x459: 0x39, 0x45a: 0x39, 0x45b: 0x39, 0x45c: 0x39, 0x45d: 0x39, 0x45e: 0x39, 0x45f: 0x39, + 0x460: 0x39, 0x461: 0x39, 0x462: 0x39, 0x463: 0x39, 0x464: 0x39, 0x465: 0x39, 0x466: 0x39, 0x467: 0x39, + 0x468: 0x39, 0x469: 0x39, 0x46a: 0x39, 0x46b: 0x39, 0x46c: 0x39, 0x46d: 0x39, 0x46e: 0x39, 0x46f: 0x39, + 0x470: 0x39, 0x471: 0x39, 0x472: 0x39, 0x473: 0xc1, 0x474: 0xc2, 0x476: 0x39, 0x477: 0xc3, + // Block 0x12, offset 0x480 + 0x4bf: 0xc4, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x39, 0x4c1: 0x39, 0x4c2: 0x39, 0x4c3: 0x39, 0x4c4: 0xc5, 0x4c5: 0xc6, 0x4c6: 0x39, 0x4c7: 0x39, + 0x4c8: 0x39, 0x4c9: 0x39, 0x4ca: 0x39, 0x4cb: 0xc7, + 0x4f2: 0xc8, + // Block 0x14, offset 0x500 + 0x53c: 0xc9, 0x53d: 0xca, + // Block 0x15, offset 0x540 + 0x545: 0xcb, 0x546: 0xcc, + 0x549: 0xcd, 0x54c: 0x39, 0x54d: 0xce, + 0x568: 0xcf, 0x569: 0xd0, 0x56a: 0xd1, + // Block 0x16, offset 0x580 + 0x580: 0xd2, 0x582: 0xbe, 0x584: 0xbd, + 0x58a: 0xd3, 0x58b: 0xd4, + 0x593: 0xd4, + 0x5a3: 0xd5, 0x5a5: 0xd6, + // Block 0x17, offset 0x5c0 + 0x5c0: 0xd7, 0x5c3: 0xd8, 0x5c4: 0xd9, 0x5c5: 0xda, 0x5c6: 0xdb, 0x5c7: 0xdc, + 0x5c8: 0xdd, 0x5c9: 0xde, 0x5cc: 0xdf, 0x5cd: 0xe0, 0x5ce: 0xe1, 0x5cf: 0xe2, + 0x5d0: 0xe3, 0x5d1: 0xe4, 0x5d2: 0x39, 0x5d3: 0xe5, 0x5d4: 0xe6, 0x5d5: 0xe7, 0x5d6: 0xe8, 0x5d7: 0xe9, + 0x5d8: 0x39, 0x5d9: 0xea, 0x5da: 0x39, 0x5db: 0xeb, 0x5df: 0xec, + 0x5e4: 0xed, 0x5e5: 0xee, 0x5e6: 0x39, 0x5e7: 0x39, + 0x5e9: 0xef, 0x5ea: 0xf0, 0x5eb: 0xf1, + // Block 0x18, offset 0x600 + 0x600: 0x39, 0x601: 0x39, 0x602: 0x39, 0x603: 0x39, 0x604: 0x39, 0x605: 0x39, 0x606: 0x39, 0x607: 0x39, + 0x608: 0x39, 0x609: 0x39, 0x60a: 0x39, 0x60b: 0x39, 0x60c: 0x39, 0x60d: 0x39, 0x60e: 0x39, 0x60f: 0x39, + 0x610: 0x39, 0x611: 0x39, 0x612: 0x39, 0x613: 0x39, 0x614: 0x39, 0x615: 0x39, 0x616: 0x39, 0x617: 0x39, + 0x618: 0x39, 0x619: 0x39, 0x61a: 0x39, 0x61b: 0x39, 0x61c: 0x39, 0x61d: 0x39, 0x61e: 0x39, 0x61f: 0x39, + 0x620: 0x39, 0x621: 0x39, 0x622: 0x39, 0x623: 0x39, 0x624: 0x39, 0x625: 0x39, 0x626: 0x39, 0x627: 0x39, + 0x628: 0x39, 0x629: 0x39, 0x62a: 0x39, 0x62b: 0x39, 0x62c: 0x39, 0x62d: 0x39, 0x62e: 0x39, 0x62f: 0x39, + 0x630: 0x39, 0x631: 0x39, 0x632: 0x39, 0x633: 0x39, 0x634: 0x39, 0x635: 0x39, 0x636: 0x39, 0x637: 0x39, + 0x638: 0x39, 0x639: 0x39, 0x63a: 0x39, 0x63b: 0x39, 0x63c: 0x39, 0x63d: 0x39, 0x63e: 0x39, 0x63f: 0xe6, + // Block 0x19, offset 0x640 + 0x650: 0x0b, 0x651: 0x0c, 0x653: 0x0d, 0x656: 0x0e, 0x657: 0x06, + 0x658: 0x0f, 0x65a: 0x10, 0x65b: 0x11, 0x65c: 0x12, 0x65d: 0x13, 0x65e: 0x14, 0x65f: 0x15, + 0x660: 0x06, 0x661: 0x06, 0x662: 0x06, 0x663: 0x06, 0x664: 0x06, 0x665: 0x06, 0x666: 0x06, 0x667: 0x06, + 0x668: 0x06, 0x669: 0x06, 0x66a: 0x06, 0x66b: 0x06, 0x66c: 0x06, 0x66d: 0x06, 0x66e: 0x06, 0x66f: 0x16, + 0x670: 0x06, 0x671: 0x06, 0x672: 0x06, 0x673: 0x06, 0x674: 0x06, 0x675: 0x06, 0x676: 0x06, 0x677: 0x06, + 0x678: 0x06, 0x679: 0x06, 0x67a: 0x06, 0x67b: 0x06, 0x67c: 0x06, 0x67d: 0x06, 0x67e: 0x06, 0x67f: 0x16, + // Block 0x1a, offset 0x680 + 0x680: 0xf2, 0x681: 0x08, 0x684: 0x08, 0x685: 0x08, 0x686: 0x08, 0x687: 0x09, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x5b, 0x6c1: 0x5b, 0x6c2: 0x5b, 0x6c3: 0x5b, 0x6c4: 0x5b, 0x6c5: 0x5b, 0x6c6: 0x5b, 0x6c7: 0x5b, + 0x6c8: 0x5b, 0x6c9: 0x5b, 0x6ca: 0x5b, 0x6cb: 0x5b, 0x6cc: 0x5b, 0x6cd: 0x5b, 0x6ce: 0x5b, 0x6cf: 0x5b, + 0x6d0: 0x5b, 0x6d1: 0x5b, 0x6d2: 0x5b, 0x6d3: 0x5b, 0x6d4: 0x5b, 0x6d5: 0x5b, 0x6d6: 0x5b, 0x6d7: 0x5b, + 0x6d8: 0x5b, 0x6d9: 0x5b, 0x6da: 0x5b, 0x6db: 0x5b, 0x6dc: 0x5b, 0x6dd: 0x5b, 0x6de: 0x5b, 0x6df: 0x5b, + 0x6e0: 0x5b, 0x6e1: 0x5b, 0x6e2: 0x5b, 0x6e3: 0x5b, 0x6e4: 0x5b, 0x6e5: 0x5b, 0x6e6: 0x5b, 0x6e7: 0x5b, + 0x6e8: 0x5b, 0x6e9: 0x5b, 0x6ea: 0x5b, 0x6eb: 0x5b, 0x6ec: 0x5b, 0x6ed: 0x5b, 0x6ee: 0x5b, 0x6ef: 0x5b, + 0x6f0: 0x5b, 0x6f1: 0x5b, 0x6f2: 0x5b, 0x6f3: 0x5b, 0x6f4: 0x5b, 0x6f5: 0x5b, 0x6f6: 0x5b, 0x6f7: 0x5b, + 0x6f8: 0x5b, 0x6f9: 0x5b, 0x6fa: 0x5b, 0x6fb: 0x5b, 0x6fc: 0x5b, 0x6fd: 0x5b, 0x6fe: 0x5b, 0x6ff: 0xf3, + // Block 0x1c, offset 0x700 + 0x720: 0x18, + 0x730: 0x09, 0x731: 0x09, 0x732: 0x09, 0x733: 0x09, 0x734: 0x09, 0x735: 0x09, 0x736: 0x09, 0x737: 0x09, + 0x738: 0x09, 0x739: 0x09, 0x73a: 0x09, 0x73b: 0x09, 0x73c: 0x09, 0x73d: 0x09, 0x73e: 0x09, 0x73f: 0x19, + // Block 0x1d, offset 0x740 + 0x740: 0x09, 0x741: 0x09, 0x742: 0x09, 0x743: 0x09, 0x744: 0x09, 0x745: 0x09, 0x746: 0x09, 0x747: 0x09, + 0x748: 0x09, 0x749: 0x09, 0x74a: 0x09, 0x74b: 0x09, 0x74c: 0x09, 0x74d: 0x09, 0x74e: 0x09, 0x74f: 0x19, +} diff --git a/vendor/github.com/clipperhouse/displaywidth/truncate.go b/vendor/github.com/clipperhouse/displaywidth/truncate.go new file mode 100644 index 000000000..b3e696f49 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/truncate.go @@ -0,0 +1,149 @@ +package displaywidth + +import ( + "strings" + + "github.com/clipperhouse/uax29/v2/graphemes" +) + +// TruncateString truncates a string to the given maxWidth, and appends the +// given tail if the string is truncated. +// +// It ensures the visible width, including the width of the tail, is less than or +// equal to maxWidth. +// +// When [Options.ControlSequences] is true, 7-bit ANSI escape sequences that +// appear after the truncation point are preserved in the output. This ensures +// that escape sequences such as SGR resets are not lost, preventing color +// bleed in terminal output. +// +// [Options.ControlSequences8Bit] is ignored by truncation. 8-bit C1 byte values +// (0x80-0x9F) overlap with UTF-8 multi-byte encoding, so manipulating them +// during truncation can shift byte boundaries and form unintended visible +// characters. Use [Options.String] or [Options.Bytes] for 8-bit-aware width +// measurement. +func (options Options) TruncateString(s string, maxWidth int, tail string) string { + // We deliberately ignore ControlSequences8Bit for truncation, see above. + options.ControlSequences8Bit = false + + maxWidthWithoutTail := maxWidth - options.String(tail) + + var pos, total int + g := graphemes.FromString(s) + g.AnsiEscapeSequences = options.ControlSequences + + for g.Next() { + gw := graphemeWidth(g.Value(), options) + if total+gw <= maxWidthWithoutTail { + pos = g.End() + } + total += gw + if total > maxWidth { + if options.ControlSequences { + // Build result with trailing 7-bit ANSI escape sequences preserved + var b strings.Builder + b.Grow(len(s) + len(tail)) // at most original + tail + b.WriteString(s[:pos]) + b.WriteString(tail) + + rem := graphemes.FromString(s[pos:]) + rem.AnsiEscapeSequences = options.ControlSequences + + for rem.Next() { + v := rem.Value() + // Only preserve 7-bit escapes (ESC = 0x1B) that measure + // as zero-width on their own; some sequences (e.g. SOS) + // are only valid in their original context. + if len(v) > 0 && v[0] == 0x1B && options.String(v) == 0 { + b.WriteString(v) + } + } + return b.String() + } + return s[:pos] + tail + } + } + // No truncation + return s +} + +// TruncateString truncates a string to the given maxWidth, and appends the +// given tail if the string is truncated. +// +// It ensures the total width, including the width of the tail, is less than or +// equal to maxWidth. +func TruncateString(s string, maxWidth int, tail string) string { + return DefaultOptions.TruncateString(s, maxWidth, tail) +} + +// TruncateBytes truncates a []byte to the given maxWidth, and appends the +// given tail if the []byte is truncated. +// +// It ensures the visible width, including the width of the tail, is less than or +// equal to maxWidth. +// +// When [Options.ControlSequences] is true, 7-bit ANSI escape sequences that +// appear after the truncation point are preserved in the output. This ensures +// that escape sequences such as SGR resets are not lost, preventing color +// bleed in terminal output. +// +// [Options.ControlSequences8Bit] is ignored by truncation. 8-bit C1 byte values +// (0x80-0x9F) overlap with UTF-8 multi-byte encoding, so manipulating them +// during truncation can shift byte boundaries and form unintended visible +// characters. Use [Options.String] or [Options.Bytes] for 8-bit-aware width +// measurement. +func (options Options) TruncateBytes(s []byte, maxWidth int, tail []byte) []byte { + // We deliberately ignore ControlSequences8Bit for truncation, see above. + options.ControlSequences8Bit = false + + maxWidthWithoutTail := maxWidth - options.Bytes(tail) + + var pos, total int + g := graphemes.FromBytes(s) + g.AnsiEscapeSequences = options.ControlSequences + + for g.Next() { + gw := graphemeWidth(g.Value(), options) + if total+gw <= maxWidthWithoutTail { + pos = g.End() + } + total += gw + if total > maxWidth { + if options.ControlSequences { + // Build result with trailing 7-bit ANSI escape sequences preserved + result := make([]byte, 0, len(s)+len(tail)) // at most original + tail + result = append(result, s[:pos]...) + result = append(result, tail...) + + rem := graphemes.FromBytes(s[pos:]) + rem.AnsiEscapeSequences = options.ControlSequences + + for rem.Next() { + v := rem.Value() + // Only preserve 7-bit escapes (ESC = 0x1B) that measure + // as zero-width on their own; some sequences (e.g. SOS) + // are only valid in their original context. + if len(v) > 0 && v[0] == 0x1B && options.Bytes(v) == 0 { + result = append(result, v...) + } + } + return result + } + result := make([]byte, 0, pos+len(tail)) + result = append(result, s[:pos]...) + result = append(result, tail...) + return result + } + } + // No truncation + return s +} + +// TruncateBytes truncates a []byte to the given maxWidth, and appends the +// given tail if the []byte is truncated. +// +// It ensures the total width, including the width of the tail, is less than or +// equal to maxWidth. +func TruncateBytes(s []byte, maxWidth int, tail []byte) []byte { + return DefaultOptions.TruncateBytes(s, maxWidth, tail) +} diff --git a/vendor/github.com/clipperhouse/displaywidth/width.go b/vendor/github.com/clipperhouse/displaywidth/width.go new file mode 100644 index 000000000..f6e0ab7fd --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/width.go @@ -0,0 +1,239 @@ +package displaywidth + +import ( + "unicode/utf8" + + "github.com/clipperhouse/uax29/v2/graphemes" +) + +// String calculates the display width of a string, +// by iterating over grapheme clusters in the string +// and summing their widths. +func String(s string) int { + return DefaultOptions.String(s) +} + +// String calculates the display width of a string, for the given options, by +// iterating over grapheme clusters in the string and summing their widths. +func (options Options) String(s string) int { + width := 0 + pos := 0 + + for pos < len(s) { + // Try ASCII optimization + asciiLen := printableASCIILength(s[pos:]) + if asciiLen > 0 { + width += asciiLen + pos += asciiLen + continue + } + + // Not ASCII, use grapheme parsing + g := graphemes.FromString(s[pos:]) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + start := pos + + for g.Next() { + v := g.Value() + width += graphemeWidth(v, options) + pos += len(v) + + // Quick check: if remaining might have printable ASCII, break to outer loop + if pos < len(s) && s[pos] >= 0x20 && s[pos] <= 0x7E { + break + } + } + + // Defensive, should not happen: if no progress was made, + // skip a byte to prevent infinite loop. Only applies if + // the grapheme parser misbehaves. + if pos == start { + pos++ + } + } + + return width +} + +// Bytes calculates the display width of a []byte, +// by iterating over grapheme clusters in the byte slice +// and summing their widths. +func Bytes(s []byte) int { + return DefaultOptions.Bytes(s) +} + +// Bytes calculates the display width of a []byte, for the given options, by +// iterating over grapheme clusters in the slice and summing their widths. +func (options Options) Bytes(s []byte) int { + width := 0 + pos := 0 + + for pos < len(s) { + // Try ASCII optimization + asciiLen := printableASCIILength(s[pos:]) + if asciiLen > 0 { + width += asciiLen + pos += asciiLen + continue + } + + // Not ASCII, use grapheme parsing + g := graphemes.FromBytes(s[pos:]) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + start := pos + + for g.Next() { + v := g.Value() + width += graphemeWidth(v, options) + pos += len(v) + + // Quick check: if remaining might have printable ASCII, break to outer loop + if pos < len(s) && s[pos] >= 0x20 && s[pos] <= 0x7E { + break + } + } + + // Defensive, should not happen: if no progress was made, + // skip a byte to prevent infinite loop. Only applies if + // the grapheme parser misbehaves. + if pos == start { + pos++ + } + } + + return width +} + +// Rune calculates the display width of a rune. You +// should almost certainly use [String] or [Bytes] for +// most purposes. +// +// The smallest unit of display width is a grapheme +// cluster, not a rune. Iterating over runes to measure +// width is incorrect in many cases. +func Rune(r rune) int { + return DefaultOptions.Rune(r) +} + +// Rune calculates the display width of a rune, for the given options. +// +// You should almost certainly use [String] or [Bytes] for most purposes. +// +// The smallest unit of display width is a grapheme cluster, not a rune. +// Iterating over runes to measure width is incorrect in many cases. +func (options Options) Rune(r rune) int { + if r < utf8.RuneSelf { + return asciiWidth(byte(r)) + } + + // Surrogates (U+D800-U+DFFF) are invalid UTF-8. + if r >= 0xD800 && r <= 0xDFFF { + return 0 + } + + var buf [4]byte + n := utf8.EncodeRune(buf[:], r) + + // Skip the grapheme iterator + return graphemeWidth(buf[:n], options) +} + +const _Default property = 0 + +// graphemeWidth returns the display width of a grapheme cluster. +// The passed string must be a single grapheme cluster. +func graphemeWidth[T ~string | []byte](s T, options Options) int { + if len(s) == 0 { + return 0 + } + + // C1 controls (0x80-0x9F) are zero-width when 8-bit control sequences + // are enabled. This must be checked before the single-byte optimization + // below, which would otherwise return width 1 for these bytes. + if options.ControlSequences8Bit && s[0] >= 0x80 && s[0] <= 0x9F { + return 0 + } + + // Optimization: single-byte graphemes need no property lookup + if len(s) == 1 { + return asciiWidth(s[0]) + } + + // Multi-byte grapheme clusters led by a C0 control (0x00-0x1F) + if s[0] <= 0x1F { + return 0 + } + + p, sz := lookup(s) + prop := property(p) + + // Variation Selector 16 (VS16) requests emoji presentation + if prop != _Wide && sz > 0 && len(s) >= sz+3 { + vs := s[sz : sz+3] + if isVS16(vs) { + prop = _Wide + } + // VS15 (0x8E) requests text presentation but does not affect width, + // in my reading of Unicode TR51. Falls through to return the base + // character's property. + } + + if options.EastAsianWidth && prop == _East_Asian_Ambiguous { + prop = _Wide + } + + if prop > upperBound { + prop = _Default + } + + return propertyWidths[prop] +} + +func asciiWidth(b byte) int { + if b <= 0x1F || b == 0x7F { + return 0 + } + return 1 +} + +// printableASCIILength returns the length of consecutive printable ASCII bytes +// starting at the beginning of s. +func printableASCIILength[T string | []byte](s T) int { + i := 0 + for ; i < len(s); i++ { + b := s[i] + // Printable ASCII is 0x20-0x7E (space through tilde) + if b < 0x20 || b > 0x7E { + break + } + } + + // If the next byte is non-ASCII (>= 0x80), back off by 1. The grapheme + // parser may group the last ASCII byte with subsequent non-ASCII bytes, + // such as combining marks. + if i > 0 && i < len(s) && s[i] >= 0x80 { + i-- + } + + return i +} + +// isVS16 checks if the slice matches VS16 (U+FE0F) UTF-8 encoding +// (EF B8 8F). It assumes len(s) >= 3. +func isVS16[T ~string | []byte](s T) bool { + return s[0] == 0xEF && s[1] == 0xB8 && s[2] == 0x8F +} + +// propertyWidths is a jump table of sorts, instead of a switch +var propertyWidths = [4]int{ + _Default: 1, + _Zero_Width: 0, + _Wide: 2, + _East_Asian_Ambiguous: 1, +} + +const upperBound = property(len(propertyWidths) - 1) diff --git a/vendor/github.com/clipperhouse/uax29/v2/LICENSE b/vendor/github.com/clipperhouse/uax29/v2/LICENSE new file mode 100644 index 000000000..6ae86a9a1 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Matt Sherman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md b/vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md new file mode 100644 index 000000000..3f8a5e3f9 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md @@ -0,0 +1,120 @@ +An implementation of grapheme cluster boundaries from [Unicode text segmentation](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) (UAX 29), for Unicode 17. + +[![Documentation](https://pkg.go.dev/badge/github.com/clipperhouse/uax29/v2/graphemes.svg)](https://pkg.go.dev/github.com/clipperhouse/uax29/v2/graphemes) +![Tests](https://github.com/clipperhouse/uax29/actions/workflows/gotest.yml/badge.svg) +![Fuzz](https://github.com/clipperhouse/uax29/actions/workflows/gofuzz.yml/badge.svg) + +## Quick start + +``` +go get github.com/clipperhouse/uax29/v2/graphemes +``` + +```go +import "github.com/clipperhouse/uax29/v2/graphemes" + +text := "Hello, δΈ–η•Œ. Nice dog! πŸ‘πŸΆ" +g := graphemes.FromString(text) + +for g.Next() { // Next() returns true until end of data + fmt.Println(g.Value()) // Do something with the current grapheme +} +``` + +_A grapheme is a β€œsingle visible character”, which might be a simple as a single letter, or a complex emoji that consists of several Unicode code points._ + +## Conformance + +We use the Unicode [test suite](https://unicode.org/reports/tr41/tr41-36.html#Tests29). + +![Tests](https://github.com/clipperhouse/uax29/actions/workflows/gotest.yml/badge.svg) +![Fuzz](https://github.com/clipperhouse/uax29/actions/workflows/gofuzz.yml/badge.svg) + +## APIs + +### If you have a `string` + +```go +text := "Hello, δΈ–η•Œ. Nice dog! πŸ‘πŸΆ" +g := graphemes.FromString(text) + +for g.Next() { // Next() returns true until end of data + fmt.Println(g.Value()) // Do something with the current grapheme +} +``` + +### If you have an `io.Reader` + +`FromReader` embeds a [`bufio.Scanner`](https://pkg.go.dev/bufio#Scanner), so just use those methods. + +```go +r := getYourReader() // from a file or network maybe +g := graphemes.FromReader(r) + +for g.Scan() { // Scan() returns true until error or EOF + fmt.Println(g.Text()) // Do something with the current grapheme +} + +if g.Err() != nil { // Check the error + log.Fatal(g.Err()) +} +``` + +### If you have a `[]byte` + +```go +b := []byte("Hello, δΈ–η•Œ. Nice dog! πŸ‘πŸΆ") + +g := graphemes.FromBytes(b) + +for g.Next() { // Next() returns true until end of data + fmt.Println(g.Value()) // Do something with the current grapheme +} +``` + +### ANSI escape sequences + +By the UAX 29 specification, ANSI escape sequences are not grapheme clusters. To treat 7-bit ANSI escape sequences as a single cluster, set `AnsiEscapeSequences` to true. + +```go +text := "Hello, \x1b[31mworld\x1b[0m!" +g := graphemes.FromString(text) +g.AnsiEscapeSequences = true + +for g.Next() { + fmt.Println(g.Value()) +} +``` + +To also parse 8-bit C1 controls (non-UTF-8 bytes), set `AnsiEscapeSequences8Bit` to true. + +```go +g.AnsiEscapeSequences = true // 7-bit forms (ESC ...) +g.AnsiEscapeSequences8Bit = true // 8-bit C1 forms (0x80-0x9F), not valid UTF-8 +``` + +For ESC-initiated (7-bit) control strings, only 7-bit terminators are recognized. +For C1-initiated (8-bit) control strings, only C1 ST (`0x9C`) is recognized as ST. + +We implement [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/) control codes in both 7-bit and 8-bit representations. 8-bit control codes are not UTF-8 encoded and are not valid UTF-8, caveat emptor. + +### Benchmarks + +``` +goos: darwin +goarch: arm64 +pkg: github.com/clipperhouse/uax29/graphemes/comparative +cpu: Apple M2 + +BenchmarkGraphemesMixed/clipperhouse/uax29-8 142635 ns/op 245.12 MB/s 0 B/op 0 allocs/op +BenchmarkGraphemesMixed/rivo/uniseg-8 2018284 ns/op 17.32 MB/s 0 B/op 0 allocs/op + +BenchmarkGraphemesASCII/clipperhouse/uax29-8 8846 ns/op 508.73 MB/s 0 B/op 0 allocs/op +BenchmarkGraphemesASCII/rivo/uniseg-8 366760 ns/op 12.27 MB/s 0 B/op 0 allocs/op +``` + +### Invalid inputs + +Invalid UTF-8 input is considered undefined behavior. We test to ensure that bad inputs will not cause pathological outcomes, such as a panic or infinite loop. Callers should expect β€œgarbage-in, garbage-out”. + +Your pipeline should probably include a call to [`utf8.Valid()`](https://pkg.go.dev/unicode/utf8#Valid). diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go new file mode 100644 index 000000000..9cd09b426 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go @@ -0,0 +1,138 @@ +package graphemes + +// ansiEscapeLength returns the byte length of a valid 7-bit ANSI escape +// sequence at the start of data, or 0 if none. +// +// Recognized forms (ECMA-48 / ISO 6429): +// - CSI: ESC [ then parameter bytes (0x30-0x3F), intermediate (0x20-0x2F), final (0x40-0x7E) +// - OSC: ESC ] then payload until BEL (0x07), 7-bit ST (ESC \), CAN (0x18), or SUB (0x1A) +// - DCS, SOS, PM, APC: ESC P/X/^/_ then payload until 7-bit ST (ESC \), CAN, or SUB +// - Two-byte: ESC + Fe/Fs (0x40-0x7E excluding above), or Fp (0x30-0x3F), or nF (0x20-0x2F then final) +func ansiEscapeLength[T ~string | ~[]byte](data T) int { + n := len(data) + if n < 2 || data[0] != esc { + return 0 + } + + b1 := data[1] + switch b1 { + case '[': // CSI + body := csiBodyLength(data[2:]) + if body == 0 { + return 0 + } + return 2 + body + case ']': // OSC - allows BEL or 7-bit ST terminator + body := oscLength(data[2:]) + if body < 0 { + return 0 + } + return 2 + body + case 'P', 'X', '^', '_': // DCS, SOS, PM, APC + body := stSequenceLength(data[2:]) + if body < 0 { + return 0 + } + return 2 + body + } + + if b1 >= 0x40 && b1 <= 0x7E { + // Fe/Fs two-byte; [ ] P X ^ _ handled above + return 2 + } + if b1 >= 0x30 && b1 <= 0x3F { + // Fp (private) two-byte + return 2 + } + if b1 >= 0x20 && b1 <= 0x2F { + // nF: intermediates then one final (0x30-0x7E) + i := 2 + for i < n && data[i] >= 0x20 && data[i] <= 0x2F { + i++ + } + if i < n && data[i] >= 0x30 && data[i] <= 0x7E { + return i + 1 + } + return 0 + } + + return 0 +} + +// csiBodyLength returns the length of the CSI body (param/intermediate/final bytes). +// data is the slice after "ESC [". +// Per ECMA-48, the CSI body has the form: +// +// parameters (0x30–0x3F)*, intermediates (0x20–0x2F)*, final (0x40–0x7E) +// +// Once an intermediate byte is seen, subsequent parameter bytes are invalid. +func csiBodyLength[T ~string | ~[]byte](data T) int { + seenIntermediate := false + for i := 0; i < len(data); i++ { + b := data[i] + if b >= 0x30 && b <= 0x3F { + if seenIntermediate { + return 0 + } + continue + } + if b >= 0x20 && b <= 0x2F { + seenIntermediate = true + continue + } + if b >= 0x40 && b <= 0x7E { + return i + 1 + } + return 0 + } + return 0 +} + +// oscLength returns the length of the OSC body. +// data is the slice after "ESC ]". +// +// Returns: +// - n >= 0: consumed body length (includes BEL/ST terminator when present) +// - -1: not terminated in the provided data +// +// OSC accepts BEL (0x07) or 7-bit ST (ESC \) as terminators by widespread convention. +// Per ECMA-48, CAN (0x18) and SUB (0x1A) cancel the control string; in that +// case they are not part of the OSC sequence length. +func oscLength[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + b := data[i] + if b == bel { + return i + 1 + } + if b == can || b == sub { + return i + } + if b == esc && i+1 < len(data) && data[i+1] == '\\' { + return i + 2 + } + } + return -1 +} + +// stSequenceLength returns the length of a control-string body. +// data is the slice after "ESC x". +// +// Returns: +// - n >= 0: consumed body length (includes ST terminator when present) +// - -1: not terminated in the provided data +// +// Used for DCS, SOS, PM, and APC, which per ECMA-48 terminate with ST. +// ST here is the 7-bit form (ESC \). +// CAN (0x18) and SUB (0x1A) cancel the control string; in that case they are +// not part of the sequence length. +func stSequenceLength[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + if data[i] == can || data[i] == sub { + return i + } + if data[i] == esc && i+1 < len(data) && data[i+1] == '\\' { + return i + 2 + } + } + return -1 +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go new file mode 100644 index 000000000..d9b0c48b6 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go @@ -0,0 +1,79 @@ +package graphemes + +// ansiEscapeLength8Bit returns the byte length of a valid 8-bit C1 ANSI +// sequence at the start of data, or 0 if none. +// +// Recognized forms (ECMA-48 / ISO 6429): +// - C1 CSI (0x9B) body as parameter/intermediate/final bytes +// - C1 OSC (0x9D) body terminated by BEL, C1 ST, CAN, or SUB +// - C1 DCS/SOS/PM/APC (0x90/0x98/0x9E/0x9F) body terminated by C1 ST, CAN, or SUB +// - Standalone C1 controls (0x80..0x9F not listed above): single byte +func ansiEscapeLength8Bit[T ~string | ~[]byte](data T) int { + if len(data) == 0 { + return 0 + } + + switch data[0] { + case 0x9B: // C1 CSI + body := csiBodyLength(data[1:]) + if body == 0 { + return 0 + } + return 1 + body + case 0x9D: // C1 OSC + body := oscLengthC1(data[1:]) + if body < 0 { + return 0 + } + return 1 + body + case 0x90, 0x98, 0x9E, 0x9F: // C1 DCS, SOS, PM, APC + body := stSequenceLengthC1(data[1:]) + if body < 0 { + return 0 + } + return 1 + body + default: + if data[0] >= 0x80 && data[0] <= 0x9F { + return 1 + } + } + + return 0 +} + +// oscLengthC1 returns the length of a C1 OSC body. +// data is the slice after the C1 OSC initiator (0x9D). +// +// Returns: +// - n >= 0: consumed body length (includes BEL/ST terminator when present) +// - -1: not terminated in the provided data +// +// Terminators: BEL (0x07) or C1 ST (0x9C). +// CAN (0x18) and SUB (0x1A) cancel the control string. +func oscLengthC1[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + b := data[i] + if b == bel || b == st { + return i + 1 + } + if b == can || b == sub { + return i + } + } + return -1 +} + +// stSequenceLengthC1 parses DCS/SOS/PM/APC bodies that terminate with C1 ST +// (0x9C), or are canceled by CAN/SUB. +func stSequenceLengthC1[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + b := data[i] + if b == can || b == sub { + return i + } + if b == st { + return i + 1 + } + } + return -1 +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go new file mode 100644 index 000000000..d37d43d71 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go @@ -0,0 +1,144 @@ +package graphemes + +import "unicode/utf8" + +// FromString returns an iterator for the grapheme clusters in the input string. +// Iterate while Next() is true, and access the grapheme via Value(). +func FromString(s string) *Iterator[string] { + return &Iterator[string]{ + split: splitFuncString, + data: s, + } +} + +// FromBytes returns an iterator for the grapheme clusters in the input bytes. +// Iterate while Next() is true, and access the grapheme via Value(). +func FromBytes(b []byte) *Iterator[[]byte] { + return &Iterator[[]byte]{ + split: splitFuncBytes, + data: b, + } +} + +// Iterator is a generic iterator for grapheme clusters in strings or byte slices, +// with an ASCII hot path optimization. +type Iterator[T ~string | ~[]byte] struct { + split func(T, bool) (int, T, error) + data T + pos int + start int + // AnsiEscapeSequences treats 7-bit ANSI escape sequences (ECMA-48) as + // single grapheme clusters when true. The default is false. + // + // 8-bit controls are not enabled by this option. See [AnsiEscapeSequences8Bit]. + AnsiEscapeSequences bool + // AnsiEscapeSequences8Bit treats 8-bit C1 ANSI escape sequences (ECMA-48) as single + // grapheme clusters when true. The default is false. + // + // 8-bit control bytes are not UTF-8 encoded, i.e. not valid UTF-8. If you + // choose this option, you are choosing to interpret non-UTF-8 data, caveat + // emptor. + AnsiEscapeSequences8Bit bool +} + +var ( + splitFuncString = splitFunc[string] + splitFuncBytes = splitFunc[[]byte] +) + +const ( + esc = 0x1B + cr = 0x0D + bel = 0x07 + can = 0x18 + sub = 0x1A + st = 0x9C +) + +// Next advances the iterator to the next grapheme cluster. +// Returns false when there are no more grapheme clusters. +func (iter *Iterator[T]) Next() bool { + if iter.pos >= len(iter.data) { + return false + } + iter.start = iter.pos + + b := iter.data[iter.pos] + if iter.AnsiEscapeSequences && b == esc { + if a := ansiEscapeLength(iter.data[iter.pos:]); a > 0 { + iter.pos += a + return true + } + } + if iter.AnsiEscapeSequences8Bit && b >= 0x80 && b <= 0x9F { + if a := ansiEscapeLength8Bit(iter.data[iter.pos:]); a > 0 { + iter.pos += a + return true + } + } + + // ASCII hot path: any ASCII is one grapheme when next byte is ASCII or end. + if b < utf8.RuneSelf && b != cr { + if iter.pos+1 >= len(iter.data) || iter.data[iter.pos+1] < utf8.RuneSelf { + iter.pos++ + return true + } + } + + // Fall back to UAX29 grapheme parsing + remaining := iter.data[iter.pos:] + advance, _, err := iter.split(remaining, true) + if err != nil { + panic(err) + } + if advance <= 0 { + panic("splitFunc returned a zero or negative advance") + } + iter.pos += advance + if iter.pos > len(iter.data) { + panic("splitFunc advanced beyond end of data") + } + return true +} + +// Value returns the current grapheme cluster. +func (iter *Iterator[T]) Value() T { + return iter.data[iter.start:iter.pos] +} + +// Start returns the byte position of the current grapheme in the original data. +func (iter *Iterator[T]) Start() int { + return iter.start +} + +// End returns the byte position after the current grapheme in the original data. +func (iter *Iterator[T]) End() int { + return iter.pos +} + +// Reset resets the iterator to the beginning of the data. +func (iter *Iterator[T]) Reset() { + iter.start = 0 + iter.pos = 0 +} + +// SetText sets the data for the iterator to operate on, and resets all state. +func (iter *Iterator[T]) SetText(data T) { + iter.data = data + iter.start = 0 + iter.pos = 0 +} + +// First returns the first grapheme cluster without advancing the iterator. +func (iter *Iterator[T]) First() T { + if len(iter.data) == 0 { + return iter.data + } + + // Use a copy to leverage Next()'s ASCII optimization + cp := *iter + cp.pos = 0 + cp.start = 0 + cp.Next() + return cp.Value() +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go new file mode 100644 index 000000000..9aa006618 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go @@ -0,0 +1,25 @@ +// Package graphemes implements Unicode grapheme cluster boundaries: https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries +package graphemes + +import ( + "bufio" + "io" +) + +type Scanner struct { + *bufio.Scanner +} + +// FromReader returns a Scanner, to split graphemes per +// https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries. +// +// It embeds a [bufio.Scanner], so you can use its methods. +// +// Iterate through graphemes by calling Scan() until false, then check Err(). +func FromReader(r io.Reader) *Scanner { + sc := bufio.NewScanner(r) + sc.Split(SplitFunc) + return &Scanner{ + Scanner: sc, + } +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go new file mode 100644 index 000000000..0ac7c6fb4 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go @@ -0,0 +1,205 @@ +package graphemes + +import ( + "bufio" +) + +// is determines if lookup intersects propert(ies) +func (lookup property) is(properties property) bool { + return (lookup & properties) != 0 +} + +const _Ignore = _Extend + +// incbState tracks state for GB9c rule (Indic conjunct clusters) +// Pattern: Consonant (Extend|Linker)* Linker (Extend|Linker)* Γ— Consonant +type incbState int + +const ( + incbNone incbState = iota // initial/reset + incbConsonant // seen Consonant, awaiting Linker + incbLinker // seen Consonant and Linker (conjunct ready) +) + +// SplitFunc is a bufio.SplitFunc implementation of Unicode grapheme cluster segmentation, for use with bufio.Scanner. +// +// See https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries. +var SplitFunc bufio.SplitFunc = splitFunc[[]byte] + +func splitFunc[T ~string | ~[]byte](data T, atEOF bool) (advance int, token T, err error) { + var empty T + if len(data) == 0 { + return 0, empty, nil + } + + // These vars are stateful across loop iterations + var pos int + var lastExIgnore property = 0 // "last excluding ignored categories" + var lastLastExIgnore property = 0 // "last one before that" + var regionalIndicatorCount int + + // GB9c state: tracking Indic conjunct clusters + var incb incbState + + // Rules are usually of the form Cat1 Γ— Cat2; "current" refers to the first property + // to the right of the Γ—, from which we look back or forward + + current, w := lookup(data[pos:]) + if w == 0 { + if !atEOF { + // Rune extends past current data, request more + return 0, empty, nil + } + pos = len(data) + return pos, data[:pos], nil + } + + // https://unicode.org/reports/tr29/#GB1 + // Start of text always advances + pos += w + + for { + eot := pos == len(data) // "end of text" + + if eot { + if !atEOF { + // Token extends past current data, request more + return 0, empty, nil + } + + // https://unicode.org/reports/tr29/#GB2 + break + } + + /* + We've switched the evaluation order of GB1↓ and GB2↑. It's ok: + because we've checked for len(data) at the top of this function, + sot and eot are mutually exclusive, order doesn't matter. + */ + + // Rules are usually of the form Cat1 Γ— Cat2; "current" refers to the first property + // to the right of the Γ—, from which we look back or forward + + // Remember previous properties to avoid lookups/lookbacks + last := current + if !last.is(_Ignore) { + lastLastExIgnore = lastExIgnore + lastExIgnore = last + } + + // Update GB9c state based on what we just advanced past + if last.is(_InCBConsonant | _InCBLinker | _InCBExtend) { + switch { + case last.is(_InCBConsonant): + if incb != incbLinker { + incb = incbConsonant + } + case last.is(_InCBLinker): + if incb >= incbConsonant { + incb = incbLinker + } + // case last.is(_InCBExtend): stay in current state + } + } else { + incb = incbNone + } + + current, w = lookup(data[pos:]) + if w == 0 { + if atEOF { + // Just return the bytes, we can't do anything with them + pos = len(data) + break + } + // Rune extends past current data, request more + return 0, empty, nil + } + + // Optimization: no rule can possibly apply + if current|last == 0 { // i.e. both are zero + break + } + + // https://unicode.org/reports/tr29/#GB3 + if current.is(_LF) && last.is(_CR) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB4 + // https://unicode.org/reports/tr29/#GB5 + if (current | last).is(_Control | _CR | _LF) { + break + } + + // https://unicode.org/reports/tr29/#GB6 + if current.is(_L|_V|_LV|_LVT) && last.is(_L) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB7 + if current.is(_V|_T) && last.is(_LV|_V) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB8 + if current.is(_T) && last.is(_LVT|_T) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9 + if current.is(_Extend | _ZWJ) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9a + if current.is(_SpacingMark) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9b + if last.is(_Prepend) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9c + // Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker. + if incb == incbLinker && current.is(_InCBConsonant) { + // After matching the pattern, reset state to start tracking a new pattern + // The current Consonant becomes the start of the new pattern + incb = incbConsonant + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB11 + if current.is(_ExtendedPictographic) && last.is(_ZWJ) && lastLastExIgnore.is(_ExtendedPictographic) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB12 + // https://unicode.org/reports/tr29/#GB13 + if (current & last).is(_RegionalIndicator) { + regionalIndicatorCount++ + + odd := regionalIndicatorCount%2 == 1 + if odd { + pos += w + continue + } + } + + // If we fall through all the above rules, it's a grapheme cluster break + break + } + + // Return token + return pos, data[:pos], nil +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go new file mode 100644 index 000000000..56192b7ee --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go @@ -0,0 +1,1717 @@ +package graphemes + +// generated by github.com/clipperhouse/uax29/v2 +// from https://www.unicode.org/Public/17.0.0/ucd/auxiliary/GraphemeBreakProperty.txt + +type property uint32 + +const ( + _CR property = 1 << iota + _Control + _Extend + _ExtendedPictographic + _InCBConsonant + _InCBExtend + _InCBLinker + _L + _LF + _LV + _LVT + _Prepend + _RegionalIndicator + _SpacingMark + _T + _V + _ZWJ +) + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func lookup[T ~string | ~[]byte](s T) (v property, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return graphemesValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := graphemesIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := graphemesIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = graphemesIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := graphemesIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = graphemesIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = graphemesIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// graphemesTrie. Total size: 61760 bytes (60.31 KiB). Checksum: af733ba94cd94ba6. +// type graphemesTrie struct { } + +// func newGraphemesTrie(i int) *graphemesTrie { +// return &graphemesTrie{} +// } + +// lookupValue determines the type of block n and looks up the value for b. +func lookupValue(n uint32, b byte) property { + switch { + default: + return property(graphemesValues[n<<6+uint32(b)]) + } +} + +// graphemesValues: 235 blocks, 15040 entries, 60160 bytes +// The third block is the zero block. +var graphemesValues = [15040]property{ + // Block 0x0, offset 0x0 + 0x00: 0x0002, 0x01: 0x0002, 0x02: 0x0002, 0x03: 0x0002, 0x04: 0x0002, 0x05: 0x0002, + 0x06: 0x0002, 0x07: 0x0002, 0x08: 0x0002, 0x09: 0x0002, 0x0a: 0x0100, 0x0b: 0x0002, + 0x0c: 0x0002, 0x0d: 0x0001, 0x0e: 0x0002, 0x0f: 0x0002, 0x10: 0x0002, 0x11: 0x0002, + 0x12: 0x0002, 0x13: 0x0002, 0x14: 0x0002, 0x15: 0x0002, 0x16: 0x0002, 0x17: 0x0002, + 0x18: 0x0002, 0x19: 0x0002, 0x1a: 0x0002, 0x1b: 0x0002, 0x1c: 0x0002, 0x1d: 0x0002, + 0x1e: 0x0002, 0x1f: 0x0002, + // Block 0x1, offset 0x40 + 0x7f: 0x0002, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x0002, 0xc1: 0x0002, 0xc2: 0x0002, 0xc3: 0x0002, 0xc4: 0x0002, 0xc5: 0x0002, + 0xc6: 0x0002, 0xc7: 0x0002, 0xc8: 0x0002, 0xc9: 0x0002, 0xca: 0x0002, 0xcb: 0x0002, + 0xcc: 0x0002, 0xcd: 0x0002, 0xce: 0x0002, 0xcf: 0x0002, 0xd0: 0x0002, 0xd1: 0x0002, + 0xd2: 0x0002, 0xd3: 0x0002, 0xd4: 0x0002, 0xd5: 0x0002, 0xd6: 0x0002, 0xd7: 0x0002, + 0xd8: 0x0002, 0xd9: 0x0002, 0xda: 0x0002, 0xdb: 0x0002, 0xdc: 0x0002, 0xdd: 0x0002, + 0xde: 0x0002, 0xdf: 0x0002, + 0xe9: 0x0008, + 0xed: 0x0002, 0xee: 0x0008, + // Block 0x4, offset 0x100 + 0x100: 0x0024, 0x101: 0x0024, 0x102: 0x0024, 0x103: 0x0024, 0x104: 0x0024, 0x105: 0x0024, + 0x106: 0x0024, 0x107: 0x0024, 0x108: 0x0024, 0x109: 0x0024, 0x10a: 0x0024, 0x10b: 0x0024, + 0x10c: 0x0024, 0x10d: 0x0024, 0x10e: 0x0024, 0x10f: 0x0024, 0x110: 0x0024, 0x111: 0x0024, + 0x112: 0x0024, 0x113: 0x0024, 0x114: 0x0024, 0x115: 0x0024, 0x116: 0x0024, 0x117: 0x0024, + 0x118: 0x0024, 0x119: 0x0024, 0x11a: 0x0024, 0x11b: 0x0024, 0x11c: 0x0024, 0x11d: 0x0024, + 0x11e: 0x0024, 0x11f: 0x0024, 0x120: 0x0024, 0x121: 0x0024, 0x122: 0x0024, 0x123: 0x0024, + 0x124: 0x0024, 0x125: 0x0024, 0x126: 0x0024, 0x127: 0x0024, 0x128: 0x0024, 0x129: 0x0024, + 0x12a: 0x0024, 0x12b: 0x0024, 0x12c: 0x0024, 0x12d: 0x0024, 0x12e: 0x0024, 0x12f: 0x0024, + 0x130: 0x0024, 0x131: 0x0024, 0x132: 0x0024, 0x133: 0x0024, 0x134: 0x0024, 0x135: 0x0024, + 0x136: 0x0024, 0x137: 0x0024, 0x138: 0x0024, 0x139: 0x0024, 0x13a: 0x0024, 0x13b: 0x0024, + 0x13c: 0x0024, 0x13d: 0x0024, 0x13e: 0x0024, 0x13f: 0x0024, + // Block 0x5, offset 0x140 + 0x140: 0x0024, 0x141: 0x0024, 0x142: 0x0024, 0x143: 0x0024, 0x144: 0x0024, 0x145: 0x0024, + 0x146: 0x0024, 0x147: 0x0024, 0x148: 0x0024, 0x149: 0x0024, 0x14a: 0x0024, 0x14b: 0x0024, + 0x14c: 0x0024, 0x14d: 0x0024, 0x14e: 0x0024, 0x14f: 0x0024, 0x150: 0x0024, 0x151: 0x0024, + 0x152: 0x0024, 0x153: 0x0024, 0x154: 0x0024, 0x155: 0x0024, 0x156: 0x0024, 0x157: 0x0024, + 0x158: 0x0024, 0x159: 0x0024, 0x15a: 0x0024, 0x15b: 0x0024, 0x15c: 0x0024, 0x15d: 0x0024, + 0x15e: 0x0024, 0x15f: 0x0024, 0x160: 0x0024, 0x161: 0x0024, 0x162: 0x0024, 0x163: 0x0024, + 0x164: 0x0024, 0x165: 0x0024, 0x166: 0x0024, 0x167: 0x0024, 0x168: 0x0024, 0x169: 0x0024, + 0x16a: 0x0024, 0x16b: 0x0024, 0x16c: 0x0024, 0x16d: 0x0024, 0x16e: 0x0024, 0x16f: 0x0024, + // Block 0x6, offset 0x180 + 0x183: 0x0024, 0x184: 0x0024, 0x185: 0x0024, + 0x186: 0x0024, 0x187: 0x0024, 0x188: 0x0024, 0x189: 0x0024, + // Block 0x7, offset 0x1c0 + 0x1d1: 0x0024, + 0x1d2: 0x0024, 0x1d3: 0x0024, 0x1d4: 0x0024, 0x1d5: 0x0024, 0x1d6: 0x0024, 0x1d7: 0x0024, + 0x1d8: 0x0024, 0x1d9: 0x0024, 0x1da: 0x0024, 0x1db: 0x0024, 0x1dc: 0x0024, 0x1dd: 0x0024, + 0x1de: 0x0024, 0x1df: 0x0024, 0x1e0: 0x0024, 0x1e1: 0x0024, 0x1e2: 0x0024, 0x1e3: 0x0024, + 0x1e4: 0x0024, 0x1e5: 0x0024, 0x1e6: 0x0024, 0x1e7: 0x0024, 0x1e8: 0x0024, 0x1e9: 0x0024, + 0x1ea: 0x0024, 0x1eb: 0x0024, 0x1ec: 0x0024, 0x1ed: 0x0024, 0x1ee: 0x0024, 0x1ef: 0x0024, + 0x1f0: 0x0024, 0x1f1: 0x0024, 0x1f2: 0x0024, 0x1f3: 0x0024, 0x1f4: 0x0024, 0x1f5: 0x0024, + 0x1f6: 0x0024, 0x1f7: 0x0024, 0x1f8: 0x0024, 0x1f9: 0x0024, 0x1fa: 0x0024, 0x1fb: 0x0024, + 0x1fc: 0x0024, 0x1fd: 0x0024, 0x1ff: 0x0024, + // Block 0x8, offset 0x200 + 0x201: 0x0024, 0x202: 0x0024, 0x204: 0x0024, 0x205: 0x0024, + 0x207: 0x0024, + // Block 0x9, offset 0x240 + 0x240: 0x0800, 0x241: 0x0800, 0x242: 0x0800, 0x243: 0x0800, 0x244: 0x0800, 0x245: 0x0800, + 0x250: 0x0024, 0x251: 0x0024, + 0x252: 0x0024, 0x253: 0x0024, 0x254: 0x0024, 0x255: 0x0024, 0x256: 0x0024, 0x257: 0x0024, + 0x258: 0x0024, 0x259: 0x0024, 0x25a: 0x0024, 0x25c: 0x0002, + // Block 0xa, offset 0x280 + 0x28b: 0x0024, + 0x28c: 0x0024, 0x28d: 0x0024, 0x28e: 0x0024, 0x28f: 0x0024, 0x290: 0x0024, 0x291: 0x0024, + 0x292: 0x0024, 0x293: 0x0024, 0x294: 0x0024, 0x295: 0x0024, 0x296: 0x0024, 0x297: 0x0024, + 0x298: 0x0024, 0x299: 0x0024, 0x29a: 0x0024, 0x29b: 0x0024, 0x29c: 0x0024, 0x29d: 0x0024, + 0x29e: 0x0024, 0x29f: 0x0024, + 0x2b0: 0x0024, + // Block 0xb, offset 0x2c0 + 0x2d6: 0x0024, 0x2d7: 0x0024, + 0x2d8: 0x0024, 0x2d9: 0x0024, 0x2da: 0x0024, 0x2db: 0x0024, 0x2dc: 0x0024, 0x2dd: 0x0800, + 0x2df: 0x0024, 0x2e0: 0x0024, 0x2e1: 0x0024, 0x2e2: 0x0024, 0x2e3: 0x0024, + 0x2e4: 0x0024, 0x2e7: 0x0024, 0x2e8: 0x0024, + 0x2ea: 0x0024, 0x2eb: 0x0024, 0x2ec: 0x0024, 0x2ed: 0x0024, + // Block 0xc, offset 0x300 + 0x30f: 0x0800, 0x311: 0x0024, + 0x330: 0x0024, 0x331: 0x0024, 0x332: 0x0024, 0x333: 0x0024, 0x334: 0x0024, 0x335: 0x0024, + 0x336: 0x0024, 0x337: 0x0024, 0x338: 0x0024, 0x339: 0x0024, 0x33a: 0x0024, 0x33b: 0x0024, + 0x33c: 0x0024, 0x33d: 0x0024, 0x33e: 0x0024, 0x33f: 0x0024, + // Block 0xd, offset 0x340 + 0x340: 0x0024, 0x341: 0x0024, 0x342: 0x0024, 0x343: 0x0024, 0x344: 0x0024, 0x345: 0x0024, + 0x346: 0x0024, 0x347: 0x0024, 0x348: 0x0024, 0x349: 0x0024, 0x34a: 0x0024, + // Block 0xe, offset 0x380 + 0x3a6: 0x0024, 0x3a7: 0x0024, 0x3a8: 0x0024, 0x3a9: 0x0024, + 0x3aa: 0x0024, 0x3ab: 0x0024, 0x3ac: 0x0024, 0x3ad: 0x0024, 0x3ae: 0x0024, 0x3af: 0x0024, + 0x3b0: 0x0024, + // Block 0xf, offset 0x3c0 + 0x3eb: 0x0024, 0x3ec: 0x0024, 0x3ed: 0x0024, 0x3ee: 0x0024, 0x3ef: 0x0024, + 0x3f0: 0x0024, 0x3f1: 0x0024, 0x3f2: 0x0024, 0x3f3: 0x0024, + 0x3fd: 0x0024, + // Block 0x10, offset 0x400 + 0x416: 0x0024, 0x417: 0x0024, + 0x418: 0x0024, 0x419: 0x0024, 0x41b: 0x0024, 0x41c: 0x0024, 0x41d: 0x0024, + 0x41e: 0x0024, 0x41f: 0x0024, 0x420: 0x0024, 0x421: 0x0024, 0x422: 0x0024, 0x423: 0x0024, + 0x425: 0x0024, 0x426: 0x0024, 0x427: 0x0024, 0x429: 0x0024, + 0x42a: 0x0024, 0x42b: 0x0024, 0x42c: 0x0024, 0x42d: 0x0024, + // Block 0x11, offset 0x440 + 0x459: 0x0024, 0x45a: 0x0024, 0x45b: 0x0024, + // Block 0x12, offset 0x480 + 0x490: 0x0800, 0x491: 0x0800, + 0x497: 0x0024, + 0x498: 0x0024, 0x499: 0x0024, 0x49a: 0x0024, 0x49b: 0x0024, 0x49c: 0x0024, 0x49d: 0x0024, + 0x49e: 0x0024, 0x49f: 0x0024, + // Block 0x13, offset 0x4c0 + 0x4ca: 0x0024, 0x4cb: 0x0024, + 0x4cc: 0x0024, 0x4cd: 0x0024, 0x4ce: 0x0024, 0x4cf: 0x0024, 0x4d0: 0x0024, 0x4d1: 0x0024, + 0x4d2: 0x0024, 0x4d3: 0x0024, 0x4d4: 0x0024, 0x4d5: 0x0024, 0x4d6: 0x0024, 0x4d7: 0x0024, + 0x4d8: 0x0024, 0x4d9: 0x0024, 0x4da: 0x0024, 0x4db: 0x0024, 0x4dc: 0x0024, 0x4dd: 0x0024, + 0x4de: 0x0024, 0x4df: 0x0024, 0x4e0: 0x0024, 0x4e1: 0x0024, 0x4e2: 0x0800, 0x4e3: 0x0024, + 0x4e4: 0x0024, 0x4e5: 0x0024, 0x4e6: 0x0024, 0x4e7: 0x0024, 0x4e8: 0x0024, 0x4e9: 0x0024, + 0x4ea: 0x0024, 0x4eb: 0x0024, 0x4ec: 0x0024, 0x4ed: 0x0024, 0x4ee: 0x0024, 0x4ef: 0x0024, + 0x4f0: 0x0024, 0x4f1: 0x0024, 0x4f2: 0x0024, 0x4f3: 0x0024, 0x4f4: 0x0024, 0x4f5: 0x0024, + 0x4f6: 0x0024, 0x4f7: 0x0024, 0x4f8: 0x0024, 0x4f9: 0x0024, 0x4fa: 0x0024, 0x4fb: 0x0024, + 0x4fc: 0x0024, 0x4fd: 0x0024, 0x4fe: 0x0024, 0x4ff: 0x0024, + // Block 0x14, offset 0x500 + 0x500: 0x0024, 0x501: 0x0024, 0x502: 0x0024, 0x503: 0x2000, + 0x515: 0x0010, 0x516: 0x0010, 0x517: 0x0010, + 0x518: 0x0010, 0x519: 0x0010, 0x51a: 0x0010, 0x51b: 0x0010, 0x51c: 0x0010, 0x51d: 0x0010, + 0x51e: 0x0010, 0x51f: 0x0010, 0x520: 0x0010, 0x521: 0x0010, 0x522: 0x0010, 0x523: 0x0010, + 0x524: 0x0010, 0x525: 0x0010, 0x526: 0x0010, 0x527: 0x0010, 0x528: 0x0010, 0x529: 0x0010, + 0x52a: 0x0010, 0x52b: 0x0010, 0x52c: 0x0010, 0x52d: 0x0010, 0x52e: 0x0010, 0x52f: 0x0010, + 0x530: 0x0010, 0x531: 0x0010, 0x532: 0x0010, 0x533: 0x0010, 0x534: 0x0010, 0x535: 0x0010, + 0x536: 0x0010, 0x537: 0x0010, 0x538: 0x0010, 0x539: 0x0010, 0x53a: 0x0024, 0x53b: 0x2000, + 0x53c: 0x0024, 0x53e: 0x2000, 0x53f: 0x2000, + // Block 0x15, offset 0x540 + 0x540: 0x2000, 0x541: 0x0024, 0x542: 0x0024, 0x543: 0x0024, 0x544: 0x0024, 0x545: 0x0024, + 0x546: 0x0024, 0x547: 0x0024, 0x548: 0x0024, 0x549: 0x2000, 0x54a: 0x2000, 0x54b: 0x2000, + 0x54c: 0x2000, 0x54d: 0x0044, 0x54e: 0x2000, 0x54f: 0x2000, 0x551: 0x0024, + 0x552: 0x0024, 0x553: 0x0024, 0x554: 0x0024, 0x555: 0x0024, 0x556: 0x0024, 0x557: 0x0024, + 0x558: 0x0010, 0x559: 0x0010, 0x55a: 0x0010, 0x55b: 0x0010, 0x55c: 0x0010, 0x55d: 0x0010, + 0x55e: 0x0010, 0x55f: 0x0010, 0x562: 0x0024, 0x563: 0x0024, + 0x578: 0x0010, 0x579: 0x0010, 0x57a: 0x0010, 0x57b: 0x0010, + 0x57c: 0x0010, 0x57d: 0x0010, 0x57e: 0x0010, 0x57f: 0x0010, + // Block 0x16, offset 0x580 + 0x581: 0x0024, 0x582: 0x2000, 0x583: 0x2000, + 0x595: 0x0010, 0x596: 0x0010, 0x597: 0x0010, + 0x598: 0x0010, 0x599: 0x0010, 0x59a: 0x0010, 0x59b: 0x0010, 0x59c: 0x0010, 0x59d: 0x0010, + 0x59e: 0x0010, 0x59f: 0x0010, 0x5a0: 0x0010, 0x5a1: 0x0010, 0x5a2: 0x0010, 0x5a3: 0x0010, + 0x5a4: 0x0010, 0x5a5: 0x0010, 0x5a6: 0x0010, 0x5a7: 0x0010, 0x5a8: 0x0010, + 0x5aa: 0x0010, 0x5ab: 0x0010, 0x5ac: 0x0010, 0x5ad: 0x0010, 0x5ae: 0x0010, 0x5af: 0x0010, + 0x5b0: 0x0010, 0x5b2: 0x0010, + 0x5b6: 0x0010, 0x5b7: 0x0010, 0x5b8: 0x0010, 0x5b9: 0x0010, + 0x5bc: 0x0024, 0x5be: 0x0024, 0x5bf: 0x2000, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x2000, 0x5c1: 0x0024, 0x5c2: 0x0024, 0x5c3: 0x0024, 0x5c4: 0x0024, + 0x5c7: 0x2000, 0x5c8: 0x2000, 0x5cb: 0x2000, + 0x5cc: 0x2000, 0x5cd: 0x0044, + 0x5d7: 0x0024, + 0x5dc: 0x0010, 0x5dd: 0x0010, + 0x5df: 0x0010, 0x5e2: 0x0024, 0x5e3: 0x0024, + 0x5f0: 0x0010, 0x5f1: 0x0010, + 0x5fe: 0x0024, + // Block 0x18, offset 0x600 + 0x601: 0x0024, 0x602: 0x0024, 0x603: 0x2000, + 0x63c: 0x0024, 0x63e: 0x2000, 0x63f: 0x2000, + // Block 0x19, offset 0x640 + 0x640: 0x2000, 0x641: 0x0024, 0x642: 0x0024, + 0x647: 0x0024, 0x648: 0x0024, 0x64b: 0x0024, + 0x64c: 0x0024, 0x64d: 0x0024, 0x651: 0x0024, + 0x670: 0x0024, 0x671: 0x0024, 0x675: 0x0024, + // Block 0x1a, offset 0x680 + 0x681: 0x0024, 0x682: 0x0024, 0x683: 0x2000, + 0x695: 0x0010, 0x696: 0x0010, 0x697: 0x0010, + 0x698: 0x0010, 0x699: 0x0010, 0x69a: 0x0010, 0x69b: 0x0010, 0x69c: 0x0010, 0x69d: 0x0010, + 0x69e: 0x0010, 0x69f: 0x0010, 0x6a0: 0x0010, 0x6a1: 0x0010, 0x6a2: 0x0010, 0x6a3: 0x0010, + 0x6a4: 0x0010, 0x6a5: 0x0010, 0x6a6: 0x0010, 0x6a7: 0x0010, 0x6a8: 0x0010, + 0x6aa: 0x0010, 0x6ab: 0x0010, 0x6ac: 0x0010, 0x6ad: 0x0010, 0x6ae: 0x0010, 0x6af: 0x0010, + 0x6b0: 0x0010, 0x6b2: 0x0010, 0x6b3: 0x0010, 0x6b5: 0x0010, + 0x6b6: 0x0010, 0x6b7: 0x0010, 0x6b8: 0x0010, 0x6b9: 0x0010, + 0x6bc: 0x0024, 0x6be: 0x2000, 0x6bf: 0x2000, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x2000, 0x6c1: 0x0024, 0x6c2: 0x0024, 0x6c3: 0x0024, 0x6c4: 0x0024, 0x6c5: 0x0024, + 0x6c7: 0x0024, 0x6c8: 0x0024, 0x6c9: 0x2000, 0x6cb: 0x2000, + 0x6cc: 0x2000, 0x6cd: 0x0044, + 0x6e2: 0x0024, 0x6e3: 0x0024, + 0x6f9: 0x0010, 0x6fa: 0x0024, 0x6fb: 0x0024, + 0x6fc: 0x0024, 0x6fd: 0x0024, 0x6fe: 0x0024, 0x6ff: 0x0024, + // Block 0x1c, offset 0x700 + 0x701: 0x0024, 0x702: 0x2000, 0x703: 0x2000, + 0x715: 0x0010, 0x716: 0x0010, 0x717: 0x0010, + 0x718: 0x0010, 0x719: 0x0010, 0x71a: 0x0010, 0x71b: 0x0010, 0x71c: 0x0010, 0x71d: 0x0010, + 0x71e: 0x0010, 0x71f: 0x0010, 0x720: 0x0010, 0x721: 0x0010, 0x722: 0x0010, 0x723: 0x0010, + 0x724: 0x0010, 0x725: 0x0010, 0x726: 0x0010, 0x727: 0x0010, 0x728: 0x0010, + 0x72a: 0x0010, 0x72b: 0x0010, 0x72c: 0x0010, 0x72d: 0x0010, 0x72e: 0x0010, 0x72f: 0x0010, + 0x730: 0x0010, 0x732: 0x0010, 0x733: 0x0010, 0x735: 0x0010, + 0x736: 0x0010, 0x737: 0x0010, 0x738: 0x0010, 0x739: 0x0010, + 0x73c: 0x0024, 0x73e: 0x0024, 0x73f: 0x0024, + // Block 0x1d, offset 0x740 + 0x740: 0x2000, 0x741: 0x0024, 0x742: 0x0024, 0x743: 0x0024, 0x744: 0x0024, + 0x747: 0x2000, 0x748: 0x2000, 0x74b: 0x2000, + 0x74c: 0x2000, 0x74d: 0x0044, + 0x755: 0x0024, 0x756: 0x0024, 0x757: 0x0024, + 0x75c: 0x0010, 0x75d: 0x0010, + 0x75f: 0x0010, 0x762: 0x0024, 0x763: 0x0024, + 0x771: 0x0010, + // Block 0x1e, offset 0x780 + 0x782: 0x0024, + 0x7be: 0x0024, 0x7bf: 0x2000, + // Block 0x1f, offset 0x7c0 + 0x7c0: 0x0024, 0x7c1: 0x2000, 0x7c2: 0x2000, + 0x7c6: 0x2000, 0x7c7: 0x2000, 0x7c8: 0x2000, 0x7ca: 0x2000, 0x7cb: 0x2000, + 0x7cc: 0x2000, 0x7cd: 0x0024, + 0x7d7: 0x0024, + // Block 0x20, offset 0x800 + 0x800: 0x0024, 0x801: 0x2000, 0x802: 0x2000, 0x803: 0x2000, 0x804: 0x0024, + 0x815: 0x0010, 0x816: 0x0010, 0x817: 0x0010, + 0x818: 0x0010, 0x819: 0x0010, 0x81a: 0x0010, 0x81b: 0x0010, 0x81c: 0x0010, 0x81d: 0x0010, + 0x81e: 0x0010, 0x81f: 0x0010, 0x820: 0x0010, 0x821: 0x0010, 0x822: 0x0010, 0x823: 0x0010, + 0x824: 0x0010, 0x825: 0x0010, 0x826: 0x0010, 0x827: 0x0010, 0x828: 0x0010, + 0x82a: 0x0010, 0x82b: 0x0010, 0x82c: 0x0010, 0x82d: 0x0010, 0x82e: 0x0010, 0x82f: 0x0010, + 0x830: 0x0010, 0x831: 0x0010, 0x832: 0x0010, 0x833: 0x0010, 0x834: 0x0010, 0x835: 0x0010, + 0x836: 0x0010, 0x837: 0x0010, 0x838: 0x0010, 0x839: 0x0010, + 0x83c: 0x0024, 0x83e: 0x0024, 0x83f: 0x0024, + // Block 0x21, offset 0x840 + 0x840: 0x0024, 0x841: 0x2000, 0x842: 0x2000, 0x843: 0x2000, 0x844: 0x2000, + 0x846: 0x0024, 0x847: 0x0024, 0x848: 0x0024, 0x84a: 0x0024, 0x84b: 0x0024, + 0x84c: 0x0024, 0x84d: 0x0044, + 0x855: 0x0024, 0x856: 0x0024, + 0x858: 0x0010, 0x859: 0x0010, 0x85a: 0x0010, + 0x862: 0x0024, 0x863: 0x0024, + // Block 0x22, offset 0x880 + 0x881: 0x0024, 0x882: 0x2000, 0x883: 0x2000, + 0x8bc: 0x0024, 0x8be: 0x2000, 0x8bf: 0x0024, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0024, 0x8c1: 0x2000, 0x8c2: 0x0024, 0x8c3: 0x2000, 0x8c4: 0x2000, + 0x8c6: 0x0024, 0x8c7: 0x0024, 0x8c8: 0x0024, 0x8ca: 0x0024, 0x8cb: 0x0024, + 0x8cc: 0x0024, 0x8cd: 0x0024, + 0x8d5: 0x0024, 0x8d6: 0x0024, + 0x8e2: 0x0024, 0x8e3: 0x0024, + 0x8f3: 0x2000, + // Block 0x24, offset 0x900 + 0x900: 0x0024, 0x901: 0x0024, 0x902: 0x2000, 0x903: 0x2000, + 0x915: 0x0010, 0x916: 0x0010, 0x917: 0x0010, + 0x918: 0x0010, 0x919: 0x0010, 0x91a: 0x0010, 0x91b: 0x0010, 0x91c: 0x0010, 0x91d: 0x0010, + 0x91e: 0x0010, 0x91f: 0x0010, 0x920: 0x0010, 0x921: 0x0010, 0x922: 0x0010, 0x923: 0x0010, + 0x924: 0x0010, 0x925: 0x0010, 0x926: 0x0010, 0x927: 0x0010, 0x928: 0x0010, 0x929: 0x0010, + 0x92a: 0x0010, 0x92b: 0x0010, 0x92c: 0x0010, 0x92d: 0x0010, 0x92e: 0x0010, 0x92f: 0x0010, + 0x930: 0x0010, 0x931: 0x0010, 0x932: 0x0010, 0x933: 0x0010, 0x934: 0x0010, 0x935: 0x0010, + 0x936: 0x0010, 0x937: 0x0010, 0x938: 0x0010, 0x939: 0x0010, 0x93a: 0x0010, 0x93b: 0x0024, + 0x93c: 0x0024, 0x93e: 0x0024, 0x93f: 0x2000, + // Block 0x25, offset 0x940 + 0x940: 0x2000, 0x941: 0x0024, 0x942: 0x0024, 0x943: 0x0024, 0x944: 0x0024, + 0x946: 0x2000, 0x947: 0x2000, 0x948: 0x2000, 0x94a: 0x2000, 0x94b: 0x2000, + 0x94c: 0x2000, 0x94d: 0x0044, 0x94e: 0x0800, + 0x957: 0x0024, + 0x962: 0x0024, 0x963: 0x0024, + // Block 0x26, offset 0x980 + 0x981: 0x0024, 0x982: 0x2000, 0x983: 0x2000, + // Block 0x27, offset 0x9c0 + 0x9ca: 0x0024, + 0x9cf: 0x0024, 0x9d0: 0x2000, 0x9d1: 0x2000, + 0x9d2: 0x0024, 0x9d3: 0x0024, 0x9d4: 0x0024, 0x9d6: 0x0024, + 0x9d8: 0x2000, 0x9d9: 0x2000, 0x9da: 0x2000, 0x9db: 0x2000, 0x9dc: 0x2000, 0x9dd: 0x2000, + 0x9de: 0x2000, 0x9df: 0x0024, + 0x9f2: 0x2000, 0x9f3: 0x2000, + // Block 0x28, offset 0xa00 + 0xa31: 0x0024, 0xa33: 0x2000, 0xa34: 0x0024, 0xa35: 0x0024, + 0xa36: 0x0024, 0xa37: 0x0024, 0xa38: 0x0024, 0xa39: 0x0024, 0xa3a: 0x0024, + // Block 0x29, offset 0xa40 + 0xa47: 0x0024, 0xa48: 0x0024, 0xa49: 0x0024, 0xa4a: 0x0024, 0xa4b: 0x0024, + 0xa4c: 0x0024, 0xa4d: 0x0024, 0xa4e: 0x0024, + // Block 0x2a, offset 0xa80 + 0xab1: 0x0024, 0xab3: 0x2000, 0xab4: 0x0024, 0xab5: 0x0024, + 0xab6: 0x0024, 0xab7: 0x0024, 0xab8: 0x0024, 0xab9: 0x0024, 0xaba: 0x0024, 0xabb: 0x0024, + 0xabc: 0x0024, + // Block 0x2b, offset 0xac0 + 0xac8: 0x0024, 0xac9: 0x0024, 0xaca: 0x0024, 0xacb: 0x0024, + 0xacc: 0x0024, 0xacd: 0x0024, 0xace: 0x0024, + // Block 0x2c, offset 0xb00 + 0xb18: 0x0024, 0xb19: 0x0024, + 0xb35: 0x0024, + 0xb37: 0x0024, 0xb39: 0x0024, + 0xb3e: 0x2000, 0xb3f: 0x2000, + // Block 0x2d, offset 0xb40 + 0xb71: 0x0024, 0xb72: 0x0024, 0xb73: 0x0024, 0xb74: 0x0024, 0xb75: 0x0024, + 0xb76: 0x0024, 0xb77: 0x0024, 0xb78: 0x0024, 0xb79: 0x0024, 0xb7a: 0x0024, 0xb7b: 0x0024, + 0xb7c: 0x0024, 0xb7d: 0x0024, 0xb7e: 0x0024, 0xb7f: 0x2000, + // Block 0x2e, offset 0xb80 + 0xb80: 0x0024, 0xb81: 0x0024, 0xb82: 0x0024, 0xb83: 0x0024, 0xb84: 0x0024, + 0xb86: 0x0024, 0xb87: 0x0024, + 0xb8d: 0x0024, 0xb8e: 0x0024, 0xb8f: 0x0024, 0xb90: 0x0024, 0xb91: 0x0024, + 0xb92: 0x0024, 0xb93: 0x0024, 0xb94: 0x0024, 0xb95: 0x0024, 0xb96: 0x0024, 0xb97: 0x0024, + 0xb99: 0x0024, 0xb9a: 0x0024, 0xb9b: 0x0024, 0xb9c: 0x0024, 0xb9d: 0x0024, + 0xb9e: 0x0024, 0xb9f: 0x0024, 0xba0: 0x0024, 0xba1: 0x0024, 0xba2: 0x0024, 0xba3: 0x0024, + 0xba4: 0x0024, 0xba5: 0x0024, 0xba6: 0x0024, 0xba7: 0x0024, 0xba8: 0x0024, 0xba9: 0x0024, + 0xbaa: 0x0024, 0xbab: 0x0024, 0xbac: 0x0024, 0xbad: 0x0024, 0xbae: 0x0024, 0xbaf: 0x0024, + 0xbb0: 0x0024, 0xbb1: 0x0024, 0xbb2: 0x0024, 0xbb3: 0x0024, 0xbb4: 0x0024, 0xbb5: 0x0024, + 0xbb6: 0x0024, 0xbb7: 0x0024, 0xbb8: 0x0024, 0xbb9: 0x0024, 0xbba: 0x0024, 0xbbb: 0x0024, + 0xbbc: 0x0024, + // Block 0x2f, offset 0xbc0 + 0xbc6: 0x0024, + // Block 0x30, offset 0xc00 + 0xc00: 0x0010, 0xc01: 0x0010, 0xc02: 0x0010, 0xc03: 0x0010, 0xc04: 0x0010, 0xc05: 0x0010, + 0xc06: 0x0010, 0xc07: 0x0010, 0xc08: 0x0010, 0xc09: 0x0010, 0xc0a: 0x0010, 0xc0b: 0x0010, + 0xc0c: 0x0010, 0xc0d: 0x0010, 0xc0e: 0x0010, 0xc0f: 0x0010, 0xc10: 0x0010, 0xc11: 0x0010, + 0xc12: 0x0010, 0xc13: 0x0010, 0xc14: 0x0010, 0xc15: 0x0010, 0xc16: 0x0010, 0xc17: 0x0010, + 0xc18: 0x0010, 0xc19: 0x0010, 0xc1a: 0x0010, 0xc1b: 0x0010, 0xc1c: 0x0010, 0xc1d: 0x0010, + 0xc1e: 0x0010, 0xc1f: 0x0010, 0xc20: 0x0010, 0xc21: 0x0010, 0xc22: 0x0010, 0xc23: 0x0010, + 0xc24: 0x0010, 0xc25: 0x0010, 0xc26: 0x0010, 0xc27: 0x0010, 0xc28: 0x0010, 0xc29: 0x0010, + 0xc2a: 0x0010, 0xc2d: 0x0024, 0xc2e: 0x0024, 0xc2f: 0x0024, + 0xc30: 0x0024, 0xc31: 0x2000, 0xc32: 0x0024, 0xc33: 0x0024, 0xc34: 0x0024, 0xc35: 0x0024, + 0xc36: 0x0024, 0xc37: 0x0024, 0xc39: 0x0044, 0xc3a: 0x0024, 0xc3b: 0x2000, + 0xc3c: 0x2000, 0xc3d: 0x0024, 0xc3e: 0x0024, 0xc3f: 0x0010, + // Block 0x31, offset 0xc40 + 0xc50: 0x0010, 0xc51: 0x0010, + 0xc52: 0x0010, 0xc53: 0x0010, 0xc54: 0x0010, 0xc55: 0x0010, 0xc56: 0x2000, 0xc57: 0x2000, + 0xc58: 0x0024, 0xc59: 0x0024, 0xc5a: 0x0010, 0xc5b: 0x0010, 0xc5c: 0x0010, 0xc5d: 0x0010, + 0xc5e: 0x0024, 0xc5f: 0x0024, 0xc60: 0x0024, 0xc61: 0x0010, + 0xc65: 0x0010, 0xc66: 0x0010, + 0xc6e: 0x0010, 0xc6f: 0x0010, + 0xc70: 0x0010, 0xc71: 0x0024, 0xc72: 0x0024, 0xc73: 0x0024, 0xc74: 0x0024, 0xc75: 0x0010, + 0xc76: 0x0010, 0xc77: 0x0010, 0xc78: 0x0010, 0xc79: 0x0010, 0xc7a: 0x0010, 0xc7b: 0x0010, + 0xc7c: 0x0010, 0xc7d: 0x0010, 0xc7e: 0x0010, 0xc7f: 0x0010, + // Block 0x32, offset 0xc80 + 0xc80: 0x0010, 0xc81: 0x0010, 0xc82: 0x0024, 0xc84: 0x2000, 0xc85: 0x0024, + 0xc86: 0x0024, + 0xc8d: 0x0024, 0xc8e: 0x0010, + 0xc9d: 0x0024, + // Block 0x33, offset 0xcc0 + 0xcc0: 0x0080, 0xcc1: 0x0080, 0xcc2: 0x0080, 0xcc3: 0x0080, 0xcc4: 0x0080, 0xcc5: 0x0080, + 0xcc6: 0x0080, 0xcc7: 0x0080, 0xcc8: 0x0080, 0xcc9: 0x0080, 0xcca: 0x0080, 0xccb: 0x0080, + 0xccc: 0x0080, 0xccd: 0x0080, 0xcce: 0x0080, 0xccf: 0x0080, 0xcd0: 0x0080, 0xcd1: 0x0080, + 0xcd2: 0x0080, 0xcd3: 0x0080, 0xcd4: 0x0080, 0xcd5: 0x0080, 0xcd6: 0x0080, 0xcd7: 0x0080, + 0xcd8: 0x0080, 0xcd9: 0x0080, 0xcda: 0x0080, 0xcdb: 0x0080, 0xcdc: 0x0080, 0xcdd: 0x0080, + 0xcde: 0x0080, 0xcdf: 0x0080, 0xce0: 0x0080, 0xce1: 0x0080, 0xce2: 0x0080, 0xce3: 0x0080, + 0xce4: 0x0080, 0xce5: 0x0080, 0xce6: 0x0080, 0xce7: 0x0080, 0xce8: 0x0080, 0xce9: 0x0080, + 0xcea: 0x0080, 0xceb: 0x0080, 0xcec: 0x0080, 0xced: 0x0080, 0xcee: 0x0080, 0xcef: 0x0080, + 0xcf0: 0x0080, 0xcf1: 0x0080, 0xcf2: 0x0080, 0xcf3: 0x0080, 0xcf4: 0x0080, 0xcf5: 0x0080, + 0xcf6: 0x0080, 0xcf7: 0x0080, 0xcf8: 0x0080, 0xcf9: 0x0080, 0xcfa: 0x0080, 0xcfb: 0x0080, + 0xcfc: 0x0080, 0xcfd: 0x0080, 0xcfe: 0x0080, 0xcff: 0x0080, + // Block 0x34, offset 0xd00 + 0xd00: 0x0080, 0xd01: 0x0080, 0xd02: 0x0080, 0xd03: 0x0080, 0xd04: 0x0080, 0xd05: 0x0080, + 0xd06: 0x0080, 0xd07: 0x0080, 0xd08: 0x0080, 0xd09: 0x0080, 0xd0a: 0x0080, 0xd0b: 0x0080, + 0xd0c: 0x0080, 0xd0d: 0x0080, 0xd0e: 0x0080, 0xd0f: 0x0080, 0xd10: 0x0080, 0xd11: 0x0080, + 0xd12: 0x0080, 0xd13: 0x0080, 0xd14: 0x0080, 0xd15: 0x0080, 0xd16: 0x0080, 0xd17: 0x0080, + 0xd18: 0x0080, 0xd19: 0x0080, 0xd1a: 0x0080, 0xd1b: 0x0080, 0xd1c: 0x0080, 0xd1d: 0x0080, + 0xd1e: 0x0080, 0xd1f: 0x0080, 0xd20: 0x8000, 0xd21: 0x8000, 0xd22: 0x8000, 0xd23: 0x8000, + 0xd24: 0x8000, 0xd25: 0x8000, 0xd26: 0x8000, 0xd27: 0x8000, 0xd28: 0x8000, 0xd29: 0x8000, + 0xd2a: 0x8000, 0xd2b: 0x8000, 0xd2c: 0x8000, 0xd2d: 0x8000, 0xd2e: 0x8000, 0xd2f: 0x8000, + 0xd30: 0x8000, 0xd31: 0x8000, 0xd32: 0x8000, 0xd33: 0x8000, 0xd34: 0x8000, 0xd35: 0x8000, + 0xd36: 0x8000, 0xd37: 0x8000, 0xd38: 0x8000, 0xd39: 0x8000, 0xd3a: 0x8000, 0xd3b: 0x8000, + 0xd3c: 0x8000, 0xd3d: 0x8000, 0xd3e: 0x8000, 0xd3f: 0x8000, + // Block 0x35, offset 0xd40 + 0xd40: 0x8000, 0xd41: 0x8000, 0xd42: 0x8000, 0xd43: 0x8000, 0xd44: 0x8000, 0xd45: 0x8000, + 0xd46: 0x8000, 0xd47: 0x8000, 0xd48: 0x8000, 0xd49: 0x8000, 0xd4a: 0x8000, 0xd4b: 0x8000, + 0xd4c: 0x8000, 0xd4d: 0x8000, 0xd4e: 0x8000, 0xd4f: 0x8000, 0xd50: 0x8000, 0xd51: 0x8000, + 0xd52: 0x8000, 0xd53: 0x8000, 0xd54: 0x8000, 0xd55: 0x8000, 0xd56: 0x8000, 0xd57: 0x8000, + 0xd58: 0x8000, 0xd59: 0x8000, 0xd5a: 0x8000, 0xd5b: 0x8000, 0xd5c: 0x8000, 0xd5d: 0x8000, + 0xd5e: 0x8000, 0xd5f: 0x8000, 0xd60: 0x8000, 0xd61: 0x8000, 0xd62: 0x8000, 0xd63: 0x8000, + 0xd64: 0x8000, 0xd65: 0x8000, 0xd66: 0x8000, 0xd67: 0x8000, 0xd68: 0x4000, 0xd69: 0x4000, + 0xd6a: 0x4000, 0xd6b: 0x4000, 0xd6c: 0x4000, 0xd6d: 0x4000, 0xd6e: 0x4000, 0xd6f: 0x4000, + 0xd70: 0x4000, 0xd71: 0x4000, 0xd72: 0x4000, 0xd73: 0x4000, 0xd74: 0x4000, 0xd75: 0x4000, + 0xd76: 0x4000, 0xd77: 0x4000, 0xd78: 0x4000, 0xd79: 0x4000, 0xd7a: 0x4000, 0xd7b: 0x4000, + 0xd7c: 0x4000, 0xd7d: 0x4000, 0xd7e: 0x4000, 0xd7f: 0x4000, + // Block 0x36, offset 0xd80 + 0xd80: 0x4000, 0xd81: 0x4000, 0xd82: 0x4000, 0xd83: 0x4000, 0xd84: 0x4000, 0xd85: 0x4000, + 0xd86: 0x4000, 0xd87: 0x4000, 0xd88: 0x4000, 0xd89: 0x4000, 0xd8a: 0x4000, 0xd8b: 0x4000, + 0xd8c: 0x4000, 0xd8d: 0x4000, 0xd8e: 0x4000, 0xd8f: 0x4000, 0xd90: 0x4000, 0xd91: 0x4000, + 0xd92: 0x4000, 0xd93: 0x4000, 0xd94: 0x4000, 0xd95: 0x4000, 0xd96: 0x4000, 0xd97: 0x4000, + 0xd98: 0x4000, 0xd99: 0x4000, 0xd9a: 0x4000, 0xd9b: 0x4000, 0xd9c: 0x4000, 0xd9d: 0x4000, + 0xd9e: 0x4000, 0xd9f: 0x4000, 0xda0: 0x4000, 0xda1: 0x4000, 0xda2: 0x4000, 0xda3: 0x4000, + 0xda4: 0x4000, 0xda5: 0x4000, 0xda6: 0x4000, 0xda7: 0x4000, 0xda8: 0x4000, 0xda9: 0x4000, + 0xdaa: 0x4000, 0xdab: 0x4000, 0xdac: 0x4000, 0xdad: 0x4000, 0xdae: 0x4000, 0xdaf: 0x4000, + 0xdb0: 0x4000, 0xdb1: 0x4000, 0xdb2: 0x4000, 0xdb3: 0x4000, 0xdb4: 0x4000, 0xdb5: 0x4000, + 0xdb6: 0x4000, 0xdb7: 0x4000, 0xdb8: 0x4000, 0xdb9: 0x4000, 0xdba: 0x4000, 0xdbb: 0x4000, + 0xdbc: 0x4000, 0xdbd: 0x4000, 0xdbe: 0x4000, 0xdbf: 0x4000, + // Block 0x37, offset 0xdc0 + 0xddd: 0x0024, + 0xdde: 0x0024, 0xddf: 0x0024, + // Block 0x38, offset 0xe00 + 0xe12: 0x0024, 0xe13: 0x0024, 0xe14: 0x0024, 0xe15: 0x0024, + 0xe32: 0x0024, 0xe33: 0x0024, 0xe34: 0x0024, + // Block 0x39, offset 0xe40 + 0xe52: 0x0024, 0xe53: 0x0024, + 0xe72: 0x0024, 0xe73: 0x0024, + // Block 0x3a, offset 0xe80 + 0xe80: 0x0010, 0xe81: 0x0010, 0xe82: 0x0010, 0xe83: 0x0010, 0xe84: 0x0010, 0xe85: 0x0010, + 0xe86: 0x0010, 0xe87: 0x0010, 0xe88: 0x0010, 0xe89: 0x0010, 0xe8a: 0x0010, 0xe8b: 0x0010, + 0xe8c: 0x0010, 0xe8d: 0x0010, 0xe8e: 0x0010, 0xe8f: 0x0010, 0xe90: 0x0010, 0xe91: 0x0010, + 0xe92: 0x0010, 0xe93: 0x0010, 0xe94: 0x0010, 0xe95: 0x0010, 0xe96: 0x0010, 0xe97: 0x0010, + 0xe98: 0x0010, 0xe99: 0x0010, 0xe9a: 0x0010, 0xe9b: 0x0010, 0xe9c: 0x0010, 0xe9d: 0x0010, + 0xe9e: 0x0010, 0xe9f: 0x0010, 0xea0: 0x0010, 0xea1: 0x0010, 0xea2: 0x0010, 0xea3: 0x0010, + 0xea4: 0x0010, 0xea5: 0x0010, 0xea6: 0x0010, 0xea7: 0x0010, 0xea8: 0x0010, 0xea9: 0x0010, + 0xeaa: 0x0010, 0xeab: 0x0010, 0xeac: 0x0010, 0xead: 0x0010, 0xeae: 0x0010, 0xeaf: 0x0010, + 0xeb0: 0x0010, 0xeb1: 0x0010, 0xeb2: 0x0010, 0xeb3: 0x0010, 0xeb4: 0x0024, 0xeb5: 0x0024, + 0xeb6: 0x2000, 0xeb7: 0x0024, 0xeb8: 0x0024, 0xeb9: 0x0024, 0xeba: 0x0024, 0xebb: 0x0024, + 0xebc: 0x0024, 0xebd: 0x0024, 0xebe: 0x2000, 0xebf: 0x2000, + // Block 0x3b, offset 0xec0 + 0xec0: 0x2000, 0xec1: 0x2000, 0xec2: 0x2000, 0xec3: 0x2000, 0xec4: 0x2000, 0xec5: 0x2000, + 0xec6: 0x0024, 0xec7: 0x2000, 0xec8: 0x2000, 0xec9: 0x0024, 0xeca: 0x0024, 0xecb: 0x0024, + 0xecc: 0x0024, 0xecd: 0x0024, 0xece: 0x0024, 0xecf: 0x0024, 0xed0: 0x0024, 0xed1: 0x0024, + 0xed2: 0x0044, 0xed3: 0x0024, + 0xedd: 0x0024, + // Block 0x3c, offset 0xf00 + 0xf0b: 0x0024, + 0xf0c: 0x0024, 0xf0d: 0x0024, 0xf0e: 0x0002, 0xf0f: 0x0024, + // Block 0x3d, offset 0xf40 + 0xf45: 0x0024, + 0xf46: 0x0024, + 0xf69: 0x0024, + // Block 0x3e, offset 0xf80 + 0xfa0: 0x0024, 0xfa1: 0x0024, 0xfa2: 0x0024, 0xfa3: 0x2000, + 0xfa4: 0x2000, 0xfa5: 0x2000, 0xfa6: 0x2000, 0xfa7: 0x0024, 0xfa8: 0x0024, 0xfa9: 0x2000, + 0xfaa: 0x2000, 0xfab: 0x2000, + 0xfb0: 0x2000, 0xfb1: 0x2000, 0xfb2: 0x0024, 0xfb3: 0x2000, 0xfb4: 0x2000, 0xfb5: 0x2000, + 0xfb6: 0x2000, 0xfb7: 0x2000, 0xfb8: 0x2000, 0xfb9: 0x0024, 0xfba: 0x0024, 0xfbb: 0x0024, + // Block 0x3f, offset 0xfc0 + 0xfd7: 0x0024, + 0xfd8: 0x0024, 0xfd9: 0x2000, 0xfda: 0x2000, 0xfdb: 0x0024, + 0xfe0: 0x0010, 0xfe1: 0x0010, 0xfe2: 0x0010, 0xfe3: 0x0010, + 0xfe4: 0x0010, 0xfe5: 0x0010, 0xfe6: 0x0010, 0xfe7: 0x0010, 0xfe8: 0x0010, 0xfe9: 0x0010, + 0xfea: 0x0010, 0xfeb: 0x0010, 0xfec: 0x0010, 0xfed: 0x0010, 0xfee: 0x0010, 0xfef: 0x0010, + 0xff0: 0x0010, 0xff1: 0x0010, 0xff2: 0x0010, 0xff3: 0x0010, 0xff4: 0x0010, 0xff5: 0x0010, + 0xff6: 0x0010, 0xff7: 0x0010, 0xff8: 0x0010, 0xff9: 0x0010, 0xffa: 0x0010, 0xffb: 0x0010, + 0xffc: 0x0010, 0xffd: 0x0010, 0xffe: 0x0010, 0xfff: 0x0010, + // Block 0x40, offset 0x1000 + 0x1000: 0x0010, 0x1001: 0x0010, 0x1002: 0x0010, 0x1003: 0x0010, 0x1004: 0x0010, 0x1005: 0x0010, + 0x1006: 0x0010, 0x1007: 0x0010, 0x1008: 0x0010, 0x1009: 0x0010, 0x100a: 0x0010, 0x100b: 0x0010, + 0x100c: 0x0010, 0x100d: 0x0010, 0x100e: 0x0010, 0x100f: 0x0010, 0x1010: 0x0010, 0x1011: 0x0010, + 0x1012: 0x0010, 0x1013: 0x0010, 0x1014: 0x0010, 0x1015: 0x2000, 0x1016: 0x0024, 0x1017: 0x2000, + 0x1018: 0x0024, 0x1019: 0x0024, 0x101a: 0x0024, 0x101b: 0x0024, 0x101c: 0x0024, 0x101d: 0x0024, + 0x101e: 0x0024, 0x1020: 0x0044, 0x1022: 0x0024, + 0x1025: 0x0024, 0x1026: 0x0024, 0x1027: 0x0024, 0x1028: 0x0024, 0x1029: 0x0024, + 0x102a: 0x0024, 0x102b: 0x0024, 0x102c: 0x0024, 0x102d: 0x2000, 0x102e: 0x2000, 0x102f: 0x2000, + 0x1030: 0x2000, 0x1031: 0x2000, 0x1032: 0x2000, 0x1033: 0x0024, 0x1034: 0x0024, 0x1035: 0x0024, + 0x1036: 0x0024, 0x1037: 0x0024, 0x1038: 0x0024, 0x1039: 0x0024, 0x103a: 0x0024, 0x103b: 0x0024, + 0x103c: 0x0024, 0x103f: 0x0024, + // Block 0x41, offset 0x1040 + 0x1070: 0x0024, 0x1071: 0x0024, 0x1072: 0x0024, 0x1073: 0x0024, 0x1074: 0x0024, 0x1075: 0x0024, + 0x1076: 0x0024, 0x1077: 0x0024, 0x1078: 0x0024, 0x1079: 0x0024, 0x107a: 0x0024, 0x107b: 0x0024, + 0x107c: 0x0024, 0x107d: 0x0024, 0x107e: 0x0024, 0x107f: 0x0024, + // Block 0x42, offset 0x1080 + 0x1080: 0x0024, 0x1081: 0x0024, 0x1082: 0x0024, 0x1083: 0x0024, 0x1084: 0x0024, 0x1085: 0x0024, + 0x1086: 0x0024, 0x1087: 0x0024, 0x1088: 0x0024, 0x1089: 0x0024, 0x108a: 0x0024, 0x108b: 0x0024, + 0x108c: 0x0024, 0x108d: 0x0024, 0x108e: 0x0024, 0x108f: 0x0024, 0x1090: 0x0024, 0x1091: 0x0024, + 0x1092: 0x0024, 0x1093: 0x0024, 0x1094: 0x0024, 0x1095: 0x0024, 0x1096: 0x0024, 0x1097: 0x0024, + 0x1098: 0x0024, 0x1099: 0x0024, 0x109a: 0x0024, 0x109b: 0x0024, 0x109c: 0x0024, 0x109d: 0x0024, + 0x10a0: 0x0024, 0x10a1: 0x0024, 0x10a2: 0x0024, 0x10a3: 0x0024, + 0x10a4: 0x0024, 0x10a5: 0x0024, 0x10a6: 0x0024, 0x10a7: 0x0024, 0x10a8: 0x0024, 0x10a9: 0x0024, + 0x10aa: 0x0024, 0x10ab: 0x0024, + // Block 0x43, offset 0x10c0 + 0x10c0: 0x0024, 0x10c1: 0x0024, 0x10c2: 0x0024, 0x10c3: 0x0024, 0x10c4: 0x2000, + 0x10cb: 0x0010, + 0x10cc: 0x0010, + 0x10d3: 0x0010, 0x10d4: 0x0010, 0x10d5: 0x0010, 0x10d6: 0x0010, 0x10d7: 0x0010, + 0x10d8: 0x0010, 0x10d9: 0x0010, 0x10da: 0x0010, 0x10db: 0x0010, 0x10dc: 0x0010, 0x10dd: 0x0010, + 0x10de: 0x0010, 0x10df: 0x0010, 0x10e0: 0x0010, 0x10e1: 0x0010, 0x10e2: 0x0010, 0x10e3: 0x0010, + 0x10e4: 0x0010, 0x10e5: 0x0010, 0x10e6: 0x0010, 0x10e7: 0x0010, 0x10e8: 0x0010, 0x10e9: 0x0010, + 0x10ea: 0x0010, 0x10eb: 0x0010, 0x10ec: 0x0010, 0x10ed: 0x0010, 0x10ee: 0x0010, 0x10ef: 0x0010, + 0x10f0: 0x0010, 0x10f1: 0x0010, 0x10f2: 0x0010, 0x10f3: 0x0010, 0x10f4: 0x0024, 0x10f5: 0x0024, + 0x10f6: 0x0024, 0x10f7: 0x0024, 0x10f8: 0x0024, 0x10f9: 0x0024, 0x10fa: 0x0024, 0x10fb: 0x0024, + 0x10fc: 0x0024, 0x10fd: 0x0024, 0x10fe: 0x2000, 0x10ff: 0x2000, + // Block 0x44, offset 0x1100 + 0x1100: 0x2000, 0x1101: 0x2000, 0x1102: 0x0024, 0x1103: 0x0024, 0x1104: 0x0044, 0x1105: 0x0010, + 0x1106: 0x0010, 0x1107: 0x0010, 0x1108: 0x0010, 0x1109: 0x0010, 0x110a: 0x0010, 0x110b: 0x0010, + 0x110c: 0x0010, + 0x112b: 0x0024, 0x112c: 0x0024, 0x112d: 0x0024, 0x112e: 0x0024, 0x112f: 0x0024, + 0x1130: 0x0024, 0x1131: 0x0024, 0x1132: 0x0024, 0x1133: 0x0024, + // Block 0x45, offset 0x1140 + 0x1140: 0x0024, 0x1141: 0x0024, 0x1142: 0x2000, 0x1143: 0x0010, 0x1144: 0x0010, 0x1145: 0x0010, + 0x1146: 0x0010, 0x1147: 0x0010, 0x1148: 0x0010, 0x1149: 0x0010, 0x114a: 0x0010, 0x114b: 0x0010, + 0x114c: 0x0010, 0x114d: 0x0010, 0x114e: 0x0010, 0x114f: 0x0010, 0x1150: 0x0010, 0x1151: 0x0010, + 0x1152: 0x0010, 0x1153: 0x0010, 0x1154: 0x0010, 0x1155: 0x0010, 0x1156: 0x0010, 0x1157: 0x0010, + 0x1158: 0x0010, 0x1159: 0x0010, 0x115a: 0x0010, 0x115b: 0x0010, 0x115c: 0x0010, 0x115d: 0x0010, + 0x115e: 0x0010, 0x115f: 0x0010, 0x1160: 0x0010, 0x1161: 0x2000, 0x1162: 0x0024, 0x1163: 0x0024, + 0x1164: 0x0024, 0x1165: 0x0024, 0x1166: 0x2000, 0x1167: 0x2000, 0x1168: 0x0024, 0x1169: 0x0024, + 0x116a: 0x0024, 0x116b: 0x0044, 0x116c: 0x0024, 0x116d: 0x0024, 0x116e: 0x0010, 0x116f: 0x0010, + 0x117b: 0x0010, + 0x117c: 0x0010, 0x117d: 0x0010, + // Block 0x46, offset 0x1180 + 0x11a6: 0x0024, 0x11a7: 0x2000, 0x11a8: 0x0024, 0x11a9: 0x0024, + 0x11aa: 0x2000, 0x11ab: 0x2000, 0x11ac: 0x2000, 0x11ad: 0x0024, 0x11ae: 0x2000, 0x11af: 0x0024, + 0x11b0: 0x0024, 0x11b1: 0x0024, 0x11b2: 0x0024, 0x11b3: 0x0024, + // Block 0x47, offset 0x11c0 + 0x11e4: 0x2000, 0x11e5: 0x2000, 0x11e6: 0x2000, 0x11e7: 0x2000, 0x11e8: 0x2000, 0x11e9: 0x2000, + 0x11ea: 0x2000, 0x11eb: 0x2000, 0x11ec: 0x0024, 0x11ed: 0x0024, 0x11ee: 0x0024, 0x11ef: 0x0024, + 0x11f0: 0x0024, 0x11f1: 0x0024, 0x11f2: 0x0024, 0x11f3: 0x0024, 0x11f4: 0x2000, 0x11f5: 0x2000, + 0x11f6: 0x0024, 0x11f7: 0x0024, + // Block 0x48, offset 0x1200 + 0x1210: 0x0024, 0x1211: 0x0024, + 0x1212: 0x0024, 0x1214: 0x0024, 0x1215: 0x0024, 0x1216: 0x0024, 0x1217: 0x0024, + 0x1218: 0x0024, 0x1219: 0x0024, 0x121a: 0x0024, 0x121b: 0x0024, 0x121c: 0x0024, 0x121d: 0x0024, + 0x121e: 0x0024, 0x121f: 0x0024, 0x1220: 0x0024, 0x1221: 0x2000, 0x1222: 0x0024, 0x1223: 0x0024, + 0x1224: 0x0024, 0x1225: 0x0024, 0x1226: 0x0024, 0x1227: 0x0024, 0x1228: 0x0024, + 0x122d: 0x0024, + 0x1234: 0x0024, + 0x1237: 0x2000, 0x1238: 0x0024, 0x1239: 0x0024, + // Block 0x49, offset 0x1240 + 0x124b: 0x0002, + 0x124c: 0x0004, 0x124d: 0x10020, 0x124e: 0x0002, 0x124f: 0x0002, + 0x1268: 0x0002, 0x1269: 0x0002, + 0x126a: 0x0002, 0x126b: 0x0002, 0x126c: 0x0002, 0x126d: 0x0002, 0x126e: 0x0002, + 0x127c: 0x0008, + // Block 0x4a, offset 0x1280 + 0x1289: 0x0008, + 0x12a0: 0x0002, 0x12a1: 0x0002, 0x12a2: 0x0002, 0x12a3: 0x0002, + 0x12a4: 0x0002, 0x12a5: 0x0002, 0x12a6: 0x0002, 0x12a7: 0x0002, 0x12a8: 0x0002, 0x12a9: 0x0002, + 0x12aa: 0x0002, 0x12ab: 0x0002, 0x12ac: 0x0002, 0x12ad: 0x0002, 0x12ae: 0x0002, 0x12af: 0x0002, + // Block 0x4b, offset 0x12c0 + 0x12d0: 0x0024, 0x12d1: 0x0024, + 0x12d2: 0x0024, 0x12d3: 0x0024, 0x12d4: 0x0024, 0x12d5: 0x0024, 0x12d6: 0x0024, 0x12d7: 0x0024, + 0x12d8: 0x0024, 0x12d9: 0x0024, 0x12da: 0x0024, 0x12db: 0x0024, 0x12dc: 0x0024, 0x12dd: 0x0024, + 0x12de: 0x0024, 0x12df: 0x0024, 0x12e0: 0x0024, 0x12e1: 0x0024, 0x12e2: 0x0024, 0x12e3: 0x0024, + 0x12e4: 0x0024, 0x12e5: 0x0024, 0x12e6: 0x0024, 0x12e7: 0x0024, 0x12e8: 0x0024, 0x12e9: 0x0024, + 0x12ea: 0x0024, 0x12eb: 0x0024, 0x12ec: 0x0024, 0x12ed: 0x0024, 0x12ee: 0x0024, 0x12ef: 0x0024, + 0x12f0: 0x0024, + // Block 0x4c, offset 0x1300 + 0x1322: 0x0008, + 0x1339: 0x0008, + // Block 0x4d, offset 0x1340 + 0x1354: 0x0008, 0x1355: 0x0008, 0x1356: 0x0008, 0x1357: 0x0008, + 0x1358: 0x0008, 0x1359: 0x0008, + 0x1369: 0x0008, + 0x136a: 0x0008, + // Block 0x4e, offset 0x1380 + 0x139a: 0x0008, 0x139b: 0x0008, + 0x13a8: 0x0008, + // Block 0x4f, offset 0x13c0 + 0x13cf: 0x0008, + 0x13e9: 0x0008, + 0x13ea: 0x0008, 0x13eb: 0x0008, 0x13ec: 0x0008, 0x13ed: 0x0008, 0x13ee: 0x0008, 0x13ef: 0x0008, + 0x13f0: 0x0008, 0x13f1: 0x0008, 0x13f2: 0x0008, 0x13f3: 0x0008, + 0x13f8: 0x0008, 0x13f9: 0x0008, 0x13fa: 0x0008, + // Block 0x50, offset 0x1400 + 0x1402: 0x0008, + // Block 0x51, offset 0x1440 + 0x146a: 0x0008, 0x146b: 0x0008, + 0x1476: 0x0008, + // Block 0x52, offset 0x1480 + 0x1480: 0x0008, + 0x14bb: 0x0008, + 0x14bc: 0x0008, 0x14bd: 0x0008, 0x14be: 0x0008, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x0008, 0x14c1: 0x0008, 0x14c2: 0x0008, 0x14c3: 0x0008, 0x14c4: 0x0008, + 0x14ce: 0x0008, 0x14d1: 0x0008, + 0x14d4: 0x0008, 0x14d5: 0x0008, + 0x14d8: 0x0008, 0x14dd: 0x0008, + 0x14e0: 0x0008, 0x14e2: 0x0008, 0x14e3: 0x0008, + 0x14e6: 0x0008, + 0x14ea: 0x0008, 0x14ee: 0x0008, 0x14ef: 0x0008, + 0x14f8: 0x0008, 0x14f9: 0x0008, 0x14fa: 0x0008, + // Block 0x54, offset 0x1500 + 0x1500: 0x0008, 0x1502: 0x0008, + 0x1508: 0x0008, 0x1509: 0x0008, 0x150a: 0x0008, 0x150b: 0x0008, + 0x150c: 0x0008, 0x150d: 0x0008, 0x150e: 0x0008, 0x150f: 0x0008, 0x1510: 0x0008, 0x1511: 0x0008, + 0x1512: 0x0008, 0x1513: 0x0008, + 0x151f: 0x0008, 0x1520: 0x0008, 0x1523: 0x0008, + 0x1525: 0x0008, 0x1526: 0x0008, 0x1528: 0x0008, + 0x153b: 0x0008, + 0x153e: 0x0008, 0x153f: 0x0008, + // Block 0x55, offset 0x1540 + 0x1552: 0x0008, 0x1553: 0x0008, 0x1554: 0x0008, 0x1555: 0x0008, 0x1556: 0x0008, 0x1557: 0x0008, + 0x1559: 0x0008, 0x155b: 0x0008, 0x155c: 0x0008, + 0x1560: 0x0008, 0x1561: 0x0008, + 0x1567: 0x0008, + 0x156a: 0x0008, 0x156b: 0x0008, + 0x1570: 0x0008, 0x1571: 0x0008, + 0x157d: 0x0008, 0x157e: 0x0008, + // Block 0x56, offset 0x1580 + 0x1584: 0x0008, 0x1585: 0x0008, + 0x1588: 0x0008, + 0x158e: 0x0008, 0x158f: 0x0008, 0x1591: 0x0008, + 0x1593: 0x0008, 0x1594: 0x0008, + 0x15a9: 0x0008, + 0x15aa: 0x0008, + 0x15b0: 0x0008, 0x15b1: 0x0008, 0x15b2: 0x0008, 0x15b3: 0x0008, 0x15b4: 0x0008, 0x15b5: 0x0008, + 0x15b7: 0x0008, 0x15b8: 0x0008, 0x15b9: 0x0008, 0x15ba: 0x0008, + 0x15bd: 0x0008, + // Block 0x57, offset 0x15c0 + 0x15c2: 0x0008, 0x15c5: 0x0008, + 0x15c8: 0x0008, 0x15c9: 0x0008, 0x15ca: 0x0008, 0x15cb: 0x0008, + 0x15cc: 0x0008, 0x15cd: 0x0008, 0x15cf: 0x0008, + 0x15d2: 0x0008, 0x15d4: 0x0008, 0x15d6: 0x0008, + 0x15dd: 0x0008, + 0x15e1: 0x0008, + 0x15e8: 0x0008, + 0x15f3: 0x0008, 0x15f4: 0x0008, + // Block 0x58, offset 0x1600 + 0x1604: 0x0008, + 0x1607: 0x0008, + 0x160c: 0x0008, 0x160e: 0x0008, + 0x1613: 0x0008, 0x1614: 0x0008, 0x1615: 0x0008, 0x1617: 0x0008, + 0x1623: 0x0008, + 0x1624: 0x0008, + // Block 0x59, offset 0x1640 + 0x1655: 0x0008, 0x1656: 0x0008, 0x1657: 0x0008, + 0x1661: 0x0008, + 0x1670: 0x0008, + 0x167f: 0x0008, + // Block 0x5a, offset 0x1680 + 0x16b4: 0x0008, 0x16b5: 0x0008, + // Block 0x5b, offset 0x16c0 + 0x16c5: 0x0008, + 0x16c6: 0x0008, 0x16c7: 0x0008, + 0x16db: 0x0008, 0x16dc: 0x0008, + // Block 0x5c, offset 0x1700 + 0x1710: 0x0008, + 0x1715: 0x0008, + // Block 0x5d, offset 0x1740 + 0x176f: 0x0024, + 0x1770: 0x0024, 0x1771: 0x0024, + // Block 0x5e, offset 0x1780 + 0x17bf: 0x0024, + // Block 0x5f, offset 0x17c0 + 0x17e0: 0x0024, 0x17e1: 0x0024, 0x17e2: 0x0024, 0x17e3: 0x0024, + 0x17e4: 0x0024, 0x17e5: 0x0024, 0x17e6: 0x0024, 0x17e7: 0x0024, 0x17e8: 0x0024, 0x17e9: 0x0024, + 0x17ea: 0x0024, 0x17eb: 0x0024, 0x17ec: 0x0024, 0x17ed: 0x0024, 0x17ee: 0x0024, 0x17ef: 0x0024, + 0x17f0: 0x0024, 0x17f1: 0x0024, 0x17f2: 0x0024, 0x17f3: 0x0024, 0x17f4: 0x0024, 0x17f5: 0x0024, + 0x17f6: 0x0024, 0x17f7: 0x0024, 0x17f8: 0x0024, 0x17f9: 0x0024, 0x17fa: 0x0024, 0x17fb: 0x0024, + 0x17fc: 0x0024, 0x17fd: 0x0024, 0x17fe: 0x0024, 0x17ff: 0x0024, + // Block 0x60, offset 0x1800 + 0x182a: 0x0024, 0x182b: 0x0024, 0x182c: 0x0024, 0x182d: 0x0024, 0x182e: 0x0024, 0x182f: 0x0024, + 0x1830: 0x0008, + 0x183d: 0x0008, + // Block 0x61, offset 0x1840 + 0x1859: 0x0024, 0x185a: 0x0024, + // Block 0x62, offset 0x1880 + 0x1897: 0x0008, + 0x1899: 0x0008, + // Block 0x63, offset 0x18c0 + 0x18ef: 0x0024, + 0x18f0: 0x0024, 0x18f1: 0x0024, 0x18f2: 0x0024, 0x18f4: 0x0024, 0x18f5: 0x0024, + 0x18f6: 0x0024, 0x18f7: 0x0024, 0x18f8: 0x0024, 0x18f9: 0x0024, 0x18fa: 0x0024, 0x18fb: 0x0024, + 0x18fc: 0x0024, 0x18fd: 0x0024, + // Block 0x64, offset 0x1900 + 0x191e: 0x0024, 0x191f: 0x0024, + // Block 0x65, offset 0x1940 + 0x1970: 0x0024, 0x1971: 0x0024, + // Block 0x66, offset 0x1980 + 0x1982: 0x0024, + 0x1986: 0x0024, 0x198b: 0x0024, + 0x19a3: 0x2000, + 0x19a4: 0x2000, 0x19a5: 0x0024, 0x19a6: 0x0024, 0x19a7: 0x2000, + 0x19ac: 0x0024, + // Block 0x67, offset 0x19c0 + 0x19c0: 0x2000, 0x19c1: 0x2000, + 0x19f4: 0x2000, 0x19f5: 0x2000, + 0x19f6: 0x2000, 0x19f7: 0x2000, 0x19f8: 0x2000, 0x19f9: 0x2000, 0x19fa: 0x2000, 0x19fb: 0x2000, + 0x19fc: 0x2000, 0x19fd: 0x2000, 0x19fe: 0x2000, 0x19ff: 0x2000, + // Block 0x68, offset 0x1a00 + 0x1a00: 0x2000, 0x1a01: 0x2000, 0x1a02: 0x2000, 0x1a03: 0x2000, 0x1a04: 0x0024, 0x1a05: 0x0024, + 0x1a20: 0x0024, 0x1a21: 0x0024, 0x1a22: 0x0024, 0x1a23: 0x0024, + 0x1a24: 0x0024, 0x1a25: 0x0024, 0x1a26: 0x0024, 0x1a27: 0x0024, 0x1a28: 0x0024, 0x1a29: 0x0024, + 0x1a2a: 0x0024, 0x1a2b: 0x0024, 0x1a2c: 0x0024, 0x1a2d: 0x0024, 0x1a2e: 0x0024, 0x1a2f: 0x0024, + 0x1a30: 0x0024, 0x1a31: 0x0024, + 0x1a3f: 0x0024, + // Block 0x69, offset 0x1a40 + 0x1a66: 0x0024, 0x1a67: 0x0024, 0x1a68: 0x0024, 0x1a69: 0x0024, + 0x1a6a: 0x0024, 0x1a6b: 0x0024, 0x1a6c: 0x0024, 0x1a6d: 0x0024, + // Block 0x6a, offset 0x1a80 + 0x1a87: 0x0024, 0x1a88: 0x0024, 0x1a89: 0x0024, 0x1a8a: 0x0024, 0x1a8b: 0x0024, + 0x1a8c: 0x0024, 0x1a8d: 0x0024, 0x1a8e: 0x0024, 0x1a8f: 0x0024, 0x1a90: 0x0024, 0x1a91: 0x0024, + 0x1a92: 0x2000, 0x1a93: 0x0024, + 0x1aa0: 0x0080, 0x1aa1: 0x0080, 0x1aa2: 0x0080, 0x1aa3: 0x0080, + 0x1aa4: 0x0080, 0x1aa5: 0x0080, 0x1aa6: 0x0080, 0x1aa7: 0x0080, 0x1aa8: 0x0080, 0x1aa9: 0x0080, + 0x1aaa: 0x0080, 0x1aab: 0x0080, 0x1aac: 0x0080, 0x1aad: 0x0080, 0x1aae: 0x0080, 0x1aaf: 0x0080, + 0x1ab0: 0x0080, 0x1ab1: 0x0080, 0x1ab2: 0x0080, 0x1ab3: 0x0080, 0x1ab4: 0x0080, 0x1ab5: 0x0080, + 0x1ab6: 0x0080, 0x1ab7: 0x0080, 0x1ab8: 0x0080, 0x1ab9: 0x0080, 0x1aba: 0x0080, 0x1abb: 0x0080, + 0x1abc: 0x0080, + // Block 0x6b, offset 0x1ac0 + 0x1ac0: 0x0024, 0x1ac1: 0x0024, 0x1ac2: 0x0024, 0x1ac3: 0x2000, + 0x1ac9: 0x0010, 0x1aca: 0x0010, 0x1acb: 0x0010, + 0x1acf: 0x0010, 0x1ad0: 0x0010, 0x1ad1: 0x0010, + 0x1ad2: 0x0010, 0x1ad3: 0x0010, 0x1ad4: 0x0010, 0x1ad5: 0x0010, 0x1ad6: 0x0010, 0x1ad7: 0x0010, + 0x1ad8: 0x0010, 0x1ad9: 0x0010, 0x1ada: 0x0010, 0x1adb: 0x0010, 0x1adc: 0x0010, 0x1add: 0x0010, + 0x1ade: 0x0010, 0x1adf: 0x0010, 0x1ae0: 0x0010, 0x1ae1: 0x0010, 0x1ae2: 0x0010, 0x1ae3: 0x0010, + 0x1ae4: 0x0010, 0x1ae5: 0x0010, 0x1ae6: 0x0010, 0x1ae7: 0x0010, 0x1ae8: 0x0010, 0x1ae9: 0x0010, + 0x1aea: 0x0010, 0x1aeb: 0x0010, 0x1aec: 0x0010, 0x1aed: 0x0010, 0x1aee: 0x0010, 0x1aef: 0x0010, + 0x1af0: 0x0010, 0x1af1: 0x0010, 0x1af2: 0x0010, 0x1af3: 0x0024, 0x1af4: 0x2000, 0x1af5: 0x2000, + 0x1af6: 0x0024, 0x1af7: 0x0024, 0x1af8: 0x0024, 0x1af9: 0x0024, 0x1afa: 0x2000, 0x1afb: 0x2000, + 0x1afc: 0x0024, 0x1afd: 0x0024, 0x1afe: 0x2000, 0x1aff: 0x2000, + // Block 0x6c, offset 0x1b00 + 0x1b00: 0x0044, + 0x1b20: 0x0010, 0x1b21: 0x0010, 0x1b22: 0x0010, 0x1b23: 0x0010, + 0x1b24: 0x0010, 0x1b25: 0x0024, 0x1b27: 0x0010, 0x1b28: 0x0010, 0x1b29: 0x0010, + 0x1b2a: 0x0010, 0x1b2b: 0x0010, 0x1b2c: 0x0010, 0x1b2d: 0x0010, 0x1b2e: 0x0010, 0x1b2f: 0x0010, + 0x1b3a: 0x0010, 0x1b3b: 0x0010, + 0x1b3c: 0x0010, 0x1b3d: 0x0010, 0x1b3e: 0x0010, + // Block 0x6d, offset 0x1b40 + 0x1b69: 0x0024, + 0x1b6a: 0x0024, 0x1b6b: 0x0024, 0x1b6c: 0x0024, 0x1b6d: 0x0024, 0x1b6e: 0x0024, 0x1b6f: 0x2000, + 0x1b70: 0x2000, 0x1b71: 0x0024, 0x1b72: 0x0024, 0x1b73: 0x2000, 0x1b74: 0x2000, 0x1b75: 0x0024, + 0x1b76: 0x0024, + // Block 0x6e, offset 0x1b80 + 0x1b83: 0x0024, + 0x1b8c: 0x0024, 0x1b8d: 0x2000, + 0x1ba0: 0x0010, 0x1ba1: 0x0010, 0x1ba2: 0x0010, 0x1ba3: 0x0010, + 0x1ba4: 0x0010, 0x1ba5: 0x0010, 0x1ba6: 0x0010, 0x1ba7: 0x0010, 0x1ba8: 0x0010, 0x1ba9: 0x0010, + 0x1baa: 0x0010, 0x1bab: 0x0010, 0x1bac: 0x0010, 0x1bad: 0x0010, 0x1bae: 0x0010, 0x1baf: 0x0010, + 0x1bb1: 0x0010, 0x1bb2: 0x0010, 0x1bb3: 0x0010, + 0x1bba: 0x0010, + 0x1bbc: 0x0024, 0x1bbe: 0x0010, 0x1bbf: 0x0010, + // Block 0x6f, offset 0x1bc0 + 0x1bf0: 0x0024, 0x1bf2: 0x0024, 0x1bf3: 0x0024, 0x1bf4: 0x0024, + 0x1bf7: 0x0024, 0x1bf8: 0x0024, + 0x1bfe: 0x0024, 0x1bff: 0x0024, + // Block 0x70, offset 0x1c00 + 0x1c01: 0x0024, + 0x1c20: 0x0010, 0x1c21: 0x0010, 0x1c22: 0x0010, 0x1c23: 0x0010, + 0x1c24: 0x0010, 0x1c25: 0x0010, 0x1c26: 0x0010, 0x1c27: 0x0010, 0x1c28: 0x0010, 0x1c29: 0x0010, + 0x1c2a: 0x0010, 0x1c2b: 0x2000, 0x1c2c: 0x0024, 0x1c2d: 0x0024, 0x1c2e: 0x2000, 0x1c2f: 0x2000, + 0x1c35: 0x2000, + 0x1c36: 0x0044, + // Block 0x71, offset 0x1c40 + 0x1c40: 0x0010, 0x1c41: 0x0010, 0x1c42: 0x0010, 0x1c43: 0x0010, 0x1c44: 0x0010, 0x1c45: 0x0010, + 0x1c46: 0x0010, 0x1c47: 0x0010, 0x1c48: 0x0010, 0x1c49: 0x0010, 0x1c4a: 0x0010, 0x1c4b: 0x0010, + 0x1c4c: 0x0010, 0x1c4d: 0x0010, 0x1c4e: 0x0010, 0x1c4f: 0x0010, 0x1c50: 0x0010, 0x1c51: 0x0010, + 0x1c52: 0x0010, 0x1c53: 0x0010, 0x1c54: 0x0010, 0x1c55: 0x0010, 0x1c56: 0x0010, 0x1c57: 0x0010, + 0x1c58: 0x0010, 0x1c59: 0x0010, 0x1c5a: 0x0010, + 0x1c63: 0x2000, + 0x1c64: 0x2000, 0x1c65: 0x0024, 0x1c66: 0x2000, 0x1c67: 0x2000, 0x1c68: 0x0024, 0x1c69: 0x2000, + 0x1c6a: 0x2000, 0x1c6c: 0x2000, 0x1c6d: 0x0024, + // Block 0x72, offset 0x1c80 + 0x1c80: 0x0200, 0x1c81: 0x0400, 0x1c82: 0x0400, 0x1c83: 0x0400, 0x1c84: 0x0400, 0x1c85: 0x0400, + 0x1c86: 0x0400, 0x1c87: 0x0400, 0x1c88: 0x0400, 0x1c89: 0x0400, 0x1c8a: 0x0400, 0x1c8b: 0x0400, + 0x1c8c: 0x0400, 0x1c8d: 0x0400, 0x1c8e: 0x0400, 0x1c8f: 0x0400, 0x1c90: 0x0400, 0x1c91: 0x0400, + 0x1c92: 0x0400, 0x1c93: 0x0400, 0x1c94: 0x0400, 0x1c95: 0x0400, 0x1c96: 0x0400, 0x1c97: 0x0400, + 0x1c98: 0x0400, 0x1c99: 0x0400, 0x1c9a: 0x0400, 0x1c9b: 0x0400, 0x1c9c: 0x0200, 0x1c9d: 0x0400, + 0x1c9e: 0x0400, 0x1c9f: 0x0400, 0x1ca0: 0x0400, 0x1ca1: 0x0400, 0x1ca2: 0x0400, 0x1ca3: 0x0400, + 0x1ca4: 0x0400, 0x1ca5: 0x0400, 0x1ca6: 0x0400, 0x1ca7: 0x0400, 0x1ca8: 0x0400, 0x1ca9: 0x0400, + 0x1caa: 0x0400, 0x1cab: 0x0400, 0x1cac: 0x0400, 0x1cad: 0x0400, 0x1cae: 0x0400, 0x1caf: 0x0400, + 0x1cb0: 0x0400, 0x1cb1: 0x0400, 0x1cb2: 0x0400, 0x1cb3: 0x0400, 0x1cb4: 0x0400, 0x1cb5: 0x0400, + 0x1cb6: 0x0400, 0x1cb7: 0x0400, 0x1cb8: 0x0200, 0x1cb9: 0x0400, 0x1cba: 0x0400, 0x1cbb: 0x0400, + 0x1cbc: 0x0400, 0x1cbd: 0x0400, 0x1cbe: 0x0400, 0x1cbf: 0x0400, + // Block 0x73, offset 0x1cc0 + 0x1cc0: 0x0400, 0x1cc1: 0x0400, 0x1cc2: 0x0400, 0x1cc3: 0x0400, 0x1cc4: 0x0400, 0x1cc5: 0x0400, + 0x1cc6: 0x0400, 0x1cc7: 0x0400, 0x1cc8: 0x0400, 0x1cc9: 0x0400, 0x1cca: 0x0400, 0x1ccb: 0x0400, + 0x1ccc: 0x0400, 0x1ccd: 0x0400, 0x1cce: 0x0400, 0x1ccf: 0x0400, 0x1cd0: 0x0400, 0x1cd1: 0x0400, + 0x1cd2: 0x0400, 0x1cd3: 0x0400, 0x1cd4: 0x0200, 0x1cd5: 0x0400, 0x1cd6: 0x0400, 0x1cd7: 0x0400, + 0x1cd8: 0x0400, 0x1cd9: 0x0400, 0x1cda: 0x0400, 0x1cdb: 0x0400, 0x1cdc: 0x0400, 0x1cdd: 0x0400, + 0x1cde: 0x0400, 0x1cdf: 0x0400, 0x1ce0: 0x0400, 0x1ce1: 0x0400, 0x1ce2: 0x0400, 0x1ce3: 0x0400, + 0x1ce4: 0x0400, 0x1ce5: 0x0400, 0x1ce6: 0x0400, 0x1ce7: 0x0400, 0x1ce8: 0x0400, 0x1ce9: 0x0400, + 0x1cea: 0x0400, 0x1ceb: 0x0400, 0x1cec: 0x0400, 0x1ced: 0x0400, 0x1cee: 0x0400, 0x1cef: 0x0400, + 0x1cf0: 0x0200, 0x1cf1: 0x0400, 0x1cf2: 0x0400, 0x1cf3: 0x0400, 0x1cf4: 0x0400, 0x1cf5: 0x0400, + 0x1cf6: 0x0400, 0x1cf7: 0x0400, 0x1cf8: 0x0400, 0x1cf9: 0x0400, 0x1cfa: 0x0400, 0x1cfb: 0x0400, + 0x1cfc: 0x0400, 0x1cfd: 0x0400, 0x1cfe: 0x0400, 0x1cff: 0x0400, + // Block 0x74, offset 0x1d00 + 0x1d00: 0x0400, 0x1d01: 0x0400, 0x1d02: 0x0400, 0x1d03: 0x0400, 0x1d04: 0x0400, 0x1d05: 0x0400, + 0x1d06: 0x0400, 0x1d07: 0x0400, 0x1d08: 0x0400, 0x1d09: 0x0400, 0x1d0a: 0x0400, 0x1d0b: 0x0400, + 0x1d0c: 0x0200, 0x1d0d: 0x0400, 0x1d0e: 0x0400, 0x1d0f: 0x0400, 0x1d10: 0x0400, 0x1d11: 0x0400, + 0x1d12: 0x0400, 0x1d13: 0x0400, 0x1d14: 0x0400, 0x1d15: 0x0400, 0x1d16: 0x0400, 0x1d17: 0x0400, + 0x1d18: 0x0400, 0x1d19: 0x0400, 0x1d1a: 0x0400, 0x1d1b: 0x0400, 0x1d1c: 0x0400, 0x1d1d: 0x0400, + 0x1d1e: 0x0400, 0x1d1f: 0x0400, 0x1d20: 0x0400, 0x1d21: 0x0400, 0x1d22: 0x0400, 0x1d23: 0x0400, + 0x1d24: 0x0400, 0x1d25: 0x0400, 0x1d26: 0x0400, 0x1d27: 0x0400, 0x1d28: 0x0200, 0x1d29: 0x0400, + 0x1d2a: 0x0400, 0x1d2b: 0x0400, 0x1d2c: 0x0400, 0x1d2d: 0x0400, 0x1d2e: 0x0400, 0x1d2f: 0x0400, + 0x1d30: 0x0400, 0x1d31: 0x0400, 0x1d32: 0x0400, 0x1d33: 0x0400, 0x1d34: 0x0400, 0x1d35: 0x0400, + 0x1d36: 0x0400, 0x1d37: 0x0400, 0x1d38: 0x0400, 0x1d39: 0x0400, 0x1d3a: 0x0400, 0x1d3b: 0x0400, + 0x1d3c: 0x0400, 0x1d3d: 0x0400, 0x1d3e: 0x0400, 0x1d3f: 0x0400, + // Block 0x75, offset 0x1d40 + 0x1d40: 0x0400, 0x1d41: 0x0400, 0x1d42: 0x0400, 0x1d43: 0x0400, 0x1d44: 0x0200, 0x1d45: 0x0400, + 0x1d46: 0x0400, 0x1d47: 0x0400, 0x1d48: 0x0400, 0x1d49: 0x0400, 0x1d4a: 0x0400, 0x1d4b: 0x0400, + 0x1d4c: 0x0400, 0x1d4d: 0x0400, 0x1d4e: 0x0400, 0x1d4f: 0x0400, 0x1d50: 0x0400, 0x1d51: 0x0400, + 0x1d52: 0x0400, 0x1d53: 0x0400, 0x1d54: 0x0400, 0x1d55: 0x0400, 0x1d56: 0x0400, 0x1d57: 0x0400, + 0x1d58: 0x0400, 0x1d59: 0x0400, 0x1d5a: 0x0400, 0x1d5b: 0x0400, 0x1d5c: 0x0400, 0x1d5d: 0x0400, + 0x1d5e: 0x0400, 0x1d5f: 0x0400, 0x1d60: 0x0200, 0x1d61: 0x0400, 0x1d62: 0x0400, 0x1d63: 0x0400, + 0x1d64: 0x0400, 0x1d65: 0x0400, 0x1d66: 0x0400, 0x1d67: 0x0400, 0x1d68: 0x0400, 0x1d69: 0x0400, + 0x1d6a: 0x0400, 0x1d6b: 0x0400, 0x1d6c: 0x0400, 0x1d6d: 0x0400, 0x1d6e: 0x0400, 0x1d6f: 0x0400, + 0x1d70: 0x0400, 0x1d71: 0x0400, 0x1d72: 0x0400, 0x1d73: 0x0400, 0x1d74: 0x0400, 0x1d75: 0x0400, + 0x1d76: 0x0400, 0x1d77: 0x0400, 0x1d78: 0x0400, 0x1d79: 0x0400, 0x1d7a: 0x0400, 0x1d7b: 0x0400, + 0x1d7c: 0x0200, 0x1d7d: 0x0400, 0x1d7e: 0x0400, 0x1d7f: 0x0400, + // Block 0x76, offset 0x1d80 + 0x1d80: 0x0400, 0x1d81: 0x0400, 0x1d82: 0x0400, 0x1d83: 0x0400, 0x1d84: 0x0400, 0x1d85: 0x0400, + 0x1d86: 0x0400, 0x1d87: 0x0400, 0x1d88: 0x0400, 0x1d89: 0x0400, 0x1d8a: 0x0400, 0x1d8b: 0x0400, + 0x1d8c: 0x0400, 0x1d8d: 0x0400, 0x1d8e: 0x0400, 0x1d8f: 0x0400, 0x1d90: 0x0400, 0x1d91: 0x0400, + 0x1d92: 0x0400, 0x1d93: 0x0400, 0x1d94: 0x0400, 0x1d95: 0x0400, 0x1d96: 0x0400, 0x1d97: 0x0400, + 0x1d98: 0x0200, 0x1d99: 0x0400, 0x1d9a: 0x0400, 0x1d9b: 0x0400, 0x1d9c: 0x0400, 0x1d9d: 0x0400, + 0x1d9e: 0x0400, 0x1d9f: 0x0400, 0x1da0: 0x0400, 0x1da1: 0x0400, 0x1da2: 0x0400, 0x1da3: 0x0400, + 0x1da4: 0x0400, 0x1da5: 0x0400, 0x1da6: 0x0400, 0x1da7: 0x0400, 0x1da8: 0x0400, 0x1da9: 0x0400, + 0x1daa: 0x0400, 0x1dab: 0x0400, 0x1dac: 0x0400, 0x1dad: 0x0400, 0x1dae: 0x0400, 0x1daf: 0x0400, + 0x1db0: 0x0400, 0x1db1: 0x0400, 0x1db2: 0x0400, 0x1db3: 0x0400, 0x1db4: 0x0200, 0x1db5: 0x0400, + 0x1db6: 0x0400, 0x1db7: 0x0400, 0x1db8: 0x0400, 0x1db9: 0x0400, 0x1dba: 0x0400, 0x1dbb: 0x0400, + 0x1dbc: 0x0400, 0x1dbd: 0x0400, 0x1dbe: 0x0400, 0x1dbf: 0x0400, + // Block 0x77, offset 0x1dc0 + 0x1dc0: 0x0400, 0x1dc1: 0x0400, 0x1dc2: 0x0400, 0x1dc3: 0x0400, 0x1dc4: 0x0400, 0x1dc5: 0x0400, + 0x1dc6: 0x0400, 0x1dc7: 0x0400, 0x1dc8: 0x0400, 0x1dc9: 0x0400, 0x1dca: 0x0400, 0x1dcb: 0x0400, + 0x1dcc: 0x0400, 0x1dcd: 0x0400, 0x1dce: 0x0400, 0x1dcf: 0x0400, 0x1dd0: 0x0200, 0x1dd1: 0x0400, + 0x1dd2: 0x0400, 0x1dd3: 0x0400, 0x1dd4: 0x0400, 0x1dd5: 0x0400, 0x1dd6: 0x0400, 0x1dd7: 0x0400, + 0x1dd8: 0x0400, 0x1dd9: 0x0400, 0x1dda: 0x0400, 0x1ddb: 0x0400, 0x1ddc: 0x0400, 0x1ddd: 0x0400, + 0x1dde: 0x0400, 0x1ddf: 0x0400, 0x1de0: 0x0400, 0x1de1: 0x0400, 0x1de2: 0x0400, 0x1de3: 0x0400, + 0x1de4: 0x0400, 0x1de5: 0x0400, 0x1de6: 0x0400, 0x1de7: 0x0400, 0x1de8: 0x0400, 0x1de9: 0x0400, + 0x1dea: 0x0400, 0x1deb: 0x0400, 0x1dec: 0x0200, 0x1ded: 0x0400, 0x1dee: 0x0400, 0x1def: 0x0400, + 0x1df0: 0x0400, 0x1df1: 0x0400, 0x1df2: 0x0400, 0x1df3: 0x0400, 0x1df4: 0x0400, 0x1df5: 0x0400, + 0x1df6: 0x0400, 0x1df7: 0x0400, 0x1df8: 0x0400, 0x1df9: 0x0400, 0x1dfa: 0x0400, 0x1dfb: 0x0400, + 0x1dfc: 0x0400, 0x1dfd: 0x0400, 0x1dfe: 0x0400, 0x1dff: 0x0400, + // Block 0x78, offset 0x1e00 + 0x1e00: 0x0400, 0x1e01: 0x0400, 0x1e02: 0x0400, 0x1e03: 0x0400, 0x1e04: 0x0400, 0x1e05: 0x0400, + 0x1e06: 0x0400, 0x1e07: 0x0400, 0x1e08: 0x0200, 0x1e09: 0x0400, 0x1e0a: 0x0400, 0x1e0b: 0x0400, + 0x1e0c: 0x0400, 0x1e0d: 0x0400, 0x1e0e: 0x0400, 0x1e0f: 0x0400, 0x1e10: 0x0400, 0x1e11: 0x0400, + 0x1e12: 0x0400, 0x1e13: 0x0400, 0x1e14: 0x0400, 0x1e15: 0x0400, 0x1e16: 0x0400, 0x1e17: 0x0400, + 0x1e18: 0x0400, 0x1e19: 0x0400, 0x1e1a: 0x0400, 0x1e1b: 0x0400, 0x1e1c: 0x0400, 0x1e1d: 0x0400, + 0x1e1e: 0x0400, 0x1e1f: 0x0400, 0x1e20: 0x0400, 0x1e21: 0x0400, 0x1e22: 0x0400, 0x1e23: 0x0400, + 0x1e24: 0x0200, 0x1e25: 0x0400, 0x1e26: 0x0400, 0x1e27: 0x0400, 0x1e28: 0x0400, 0x1e29: 0x0400, + 0x1e2a: 0x0400, 0x1e2b: 0x0400, 0x1e2c: 0x0400, 0x1e2d: 0x0400, 0x1e2e: 0x0400, 0x1e2f: 0x0400, + 0x1e30: 0x0400, 0x1e31: 0x0400, 0x1e32: 0x0400, 0x1e33: 0x0400, 0x1e34: 0x0400, 0x1e35: 0x0400, + 0x1e36: 0x0400, 0x1e37: 0x0400, 0x1e38: 0x0400, 0x1e39: 0x0400, 0x1e3a: 0x0400, 0x1e3b: 0x0400, + 0x1e3c: 0x0400, 0x1e3d: 0x0400, 0x1e3e: 0x0400, 0x1e3f: 0x0400, + // Block 0x79, offset 0x1e40 + 0x1e40: 0x0400, 0x1e41: 0x0400, 0x1e42: 0x0400, 0x1e43: 0x0400, 0x1e44: 0x0400, 0x1e45: 0x0400, + 0x1e46: 0x0400, 0x1e47: 0x0400, 0x1e48: 0x0200, 0x1e49: 0x0400, 0x1e4a: 0x0400, 0x1e4b: 0x0400, + 0x1e4c: 0x0400, 0x1e4d: 0x0400, 0x1e4e: 0x0400, 0x1e4f: 0x0400, 0x1e50: 0x0400, 0x1e51: 0x0400, + 0x1e52: 0x0400, 0x1e53: 0x0400, 0x1e54: 0x0400, 0x1e55: 0x0400, 0x1e56: 0x0400, 0x1e57: 0x0400, + 0x1e58: 0x0400, 0x1e59: 0x0400, 0x1e5a: 0x0400, 0x1e5b: 0x0400, 0x1e5c: 0x0400, 0x1e5d: 0x0400, + 0x1e5e: 0x0400, 0x1e5f: 0x0400, 0x1e60: 0x0400, 0x1e61: 0x0400, 0x1e62: 0x0400, 0x1e63: 0x0400, + 0x1e70: 0x8000, 0x1e71: 0x8000, 0x1e72: 0x8000, 0x1e73: 0x8000, 0x1e74: 0x8000, 0x1e75: 0x8000, + 0x1e76: 0x8000, 0x1e77: 0x8000, 0x1e78: 0x8000, 0x1e79: 0x8000, 0x1e7a: 0x8000, 0x1e7b: 0x8000, + 0x1e7c: 0x8000, 0x1e7d: 0x8000, 0x1e7e: 0x8000, 0x1e7f: 0x8000, + // Block 0x7a, offset 0x1e80 + 0x1e80: 0x8000, 0x1e81: 0x8000, 0x1e82: 0x8000, 0x1e83: 0x8000, 0x1e84: 0x8000, 0x1e85: 0x8000, + 0x1e86: 0x8000, 0x1e8b: 0x4000, + 0x1e8c: 0x4000, 0x1e8d: 0x4000, 0x1e8e: 0x4000, 0x1e8f: 0x4000, 0x1e90: 0x4000, 0x1e91: 0x4000, + 0x1e92: 0x4000, 0x1e93: 0x4000, 0x1e94: 0x4000, 0x1e95: 0x4000, 0x1e96: 0x4000, 0x1e97: 0x4000, + 0x1e98: 0x4000, 0x1e99: 0x4000, 0x1e9a: 0x4000, 0x1e9b: 0x4000, 0x1e9c: 0x4000, 0x1e9d: 0x4000, + 0x1e9e: 0x4000, 0x1e9f: 0x4000, 0x1ea0: 0x4000, 0x1ea1: 0x4000, 0x1ea2: 0x4000, 0x1ea3: 0x4000, + 0x1ea4: 0x4000, 0x1ea5: 0x4000, 0x1ea6: 0x4000, 0x1ea7: 0x4000, 0x1ea8: 0x4000, 0x1ea9: 0x4000, + 0x1eaa: 0x4000, 0x1eab: 0x4000, 0x1eac: 0x4000, 0x1ead: 0x4000, 0x1eae: 0x4000, 0x1eaf: 0x4000, + 0x1eb0: 0x4000, 0x1eb1: 0x4000, 0x1eb2: 0x4000, 0x1eb3: 0x4000, 0x1eb4: 0x4000, 0x1eb5: 0x4000, + 0x1eb6: 0x4000, 0x1eb7: 0x4000, 0x1eb8: 0x4000, 0x1eb9: 0x4000, 0x1eba: 0x4000, 0x1ebb: 0x4000, + // Block 0x7b, offset 0x1ec0 + 0x1ede: 0x0024, + // Block 0x7c, offset 0x1f00 + 0x1f00: 0x0024, 0x1f01: 0x0024, 0x1f02: 0x0024, 0x1f03: 0x0024, 0x1f04: 0x0024, 0x1f05: 0x0024, + 0x1f06: 0x0024, 0x1f07: 0x0024, 0x1f08: 0x0024, 0x1f09: 0x0024, 0x1f0a: 0x0024, 0x1f0b: 0x0024, + 0x1f0c: 0x0024, 0x1f0d: 0x0024, 0x1f0e: 0x0024, 0x1f0f: 0x0024, + 0x1f20: 0x0024, 0x1f21: 0x0024, 0x1f22: 0x0024, 0x1f23: 0x0024, + 0x1f24: 0x0024, 0x1f25: 0x0024, 0x1f26: 0x0024, 0x1f27: 0x0024, 0x1f28: 0x0024, 0x1f29: 0x0024, + 0x1f2a: 0x0024, 0x1f2b: 0x0024, 0x1f2c: 0x0024, 0x1f2d: 0x0024, 0x1f2e: 0x0024, 0x1f2f: 0x0024, + // Block 0x7d, offset 0x1f40 + 0x1f7f: 0x0002, + // Block 0x7e, offset 0x1f80 + 0x1fb0: 0x0002, 0x1fb1: 0x0002, 0x1fb2: 0x0002, 0x1fb3: 0x0002, 0x1fb4: 0x0002, 0x1fb5: 0x0002, + 0x1fb6: 0x0002, 0x1fb7: 0x0002, 0x1fb8: 0x0002, 0x1fb9: 0x0002, 0x1fba: 0x0002, 0x1fbb: 0x0002, + // Block 0x7f, offset 0x1fc0 + 0x1ffd: 0x0024, + // Block 0x80, offset 0x2000 + 0x2020: 0x0024, + // Block 0x81, offset 0x2040 + 0x2076: 0x0024, 0x2077: 0x0024, 0x2078: 0x0024, 0x2079: 0x0024, 0x207a: 0x0024, + // Block 0x82, offset 0x2080 + 0x2080: 0x0010, 0x2081: 0x0024, 0x2082: 0x0024, 0x2083: 0x0024, 0x2085: 0x0024, + 0x2086: 0x0024, + 0x208c: 0x0024, 0x208d: 0x0024, 0x208e: 0x0024, 0x208f: 0x0024, 0x2090: 0x0010, 0x2091: 0x0010, + 0x2092: 0x0010, 0x2093: 0x0010, 0x2095: 0x0010, 0x2096: 0x0010, 0x2097: 0x0010, + 0x2099: 0x0010, 0x209a: 0x0010, 0x209b: 0x0010, 0x209c: 0x0010, 0x209d: 0x0010, + 0x209e: 0x0010, 0x209f: 0x0010, 0x20a0: 0x0010, 0x20a1: 0x0010, 0x20a2: 0x0010, 0x20a3: 0x0010, + 0x20a4: 0x0010, 0x20a5: 0x0010, 0x20a6: 0x0010, 0x20a7: 0x0010, 0x20a8: 0x0010, 0x20a9: 0x0010, + 0x20aa: 0x0010, 0x20ab: 0x0010, 0x20ac: 0x0010, 0x20ad: 0x0010, 0x20ae: 0x0010, 0x20af: 0x0010, + 0x20b0: 0x0010, 0x20b1: 0x0010, 0x20b2: 0x0010, 0x20b3: 0x0010, 0x20b4: 0x0010, 0x20b5: 0x0010, + 0x20b8: 0x0024, 0x20b9: 0x0024, 0x20ba: 0x0024, + 0x20bf: 0x0044, + // Block 0x83, offset 0x20c0 + 0x20e5: 0x0024, 0x20e6: 0x0024, + // Block 0x84, offset 0x2100 + 0x2124: 0x0024, 0x2125: 0x0024, 0x2126: 0x0024, 0x2127: 0x0024, + // Block 0x85, offset 0x2140 + 0x2169: 0x0024, + 0x216a: 0x0024, 0x216b: 0x0024, 0x216c: 0x0024, 0x216d: 0x0024, + // Block 0x86, offset 0x2180 + 0x21ab: 0x0024, 0x21ac: 0x0024, + // Block 0x87, offset 0x21c0 + 0x21fa: 0x0024, 0x21fb: 0x0024, + 0x21fc: 0x0024, 0x21fd: 0x0024, 0x21fe: 0x0024, 0x21ff: 0x0024, + // Block 0x88, offset 0x2200 + 0x2206: 0x0024, 0x2207: 0x0024, 0x2208: 0x0024, 0x2209: 0x0024, 0x220a: 0x0024, 0x220b: 0x0024, + 0x220c: 0x0024, 0x220d: 0x0024, 0x220e: 0x0024, 0x220f: 0x0024, 0x2210: 0x0024, + // Block 0x89, offset 0x2240 + 0x2242: 0x0024, 0x2243: 0x0024, 0x2244: 0x0024, 0x2245: 0x0024, + // Block 0x8a, offset 0x2280 + 0x2280: 0x2000, 0x2281: 0x0024, 0x2282: 0x2000, + 0x22b8: 0x0024, 0x22b9: 0x0024, 0x22ba: 0x0024, 0x22bb: 0x0024, + 0x22bc: 0x0024, 0x22bd: 0x0024, 0x22be: 0x0024, 0x22bf: 0x0024, + // Block 0x8b, offset 0x22c0 + 0x22c0: 0x0024, 0x22c1: 0x0024, 0x22c2: 0x0024, 0x22c3: 0x0024, 0x22c4: 0x0024, 0x22c5: 0x0024, + 0x22c6: 0x0024, + 0x22f0: 0x0024, 0x22f3: 0x0024, 0x22f4: 0x0024, + 0x22ff: 0x0024, + // Block 0x8c, offset 0x2300 + 0x2300: 0x0024, 0x2301: 0x0024, 0x2302: 0x2000, + 0x2330: 0x2000, 0x2331: 0x2000, 0x2332: 0x2000, 0x2333: 0x0024, 0x2334: 0x0024, 0x2335: 0x0024, + 0x2336: 0x0024, 0x2337: 0x2000, 0x2338: 0x2000, 0x2339: 0x0024, 0x233a: 0x0024, + 0x233d: 0x0800, + // Block 0x8d, offset 0x2340 + 0x2342: 0x0024, + 0x234d: 0x0800, + // Block 0x8e, offset 0x2380 + 0x2380: 0x0024, 0x2381: 0x0024, 0x2382: 0x0024, 0x2383: 0x0010, 0x2384: 0x0010, 0x2385: 0x0010, + 0x2386: 0x0010, 0x2387: 0x0010, 0x2388: 0x0010, 0x2389: 0x0010, 0x238a: 0x0010, 0x238b: 0x0010, + 0x238c: 0x0010, 0x238d: 0x0010, 0x238e: 0x0010, 0x238f: 0x0010, 0x2390: 0x0010, 0x2391: 0x0010, + 0x2392: 0x0010, 0x2393: 0x0010, 0x2394: 0x0010, 0x2395: 0x0010, 0x2396: 0x0010, 0x2397: 0x0010, + 0x2398: 0x0010, 0x2399: 0x0010, 0x239a: 0x0010, 0x239b: 0x0010, 0x239c: 0x0010, 0x239d: 0x0010, + 0x239e: 0x0010, 0x239f: 0x0010, 0x23a0: 0x0010, 0x23a1: 0x0010, 0x23a2: 0x0010, 0x23a3: 0x0010, + 0x23a4: 0x0010, 0x23a5: 0x0010, 0x23a6: 0x0010, 0x23a7: 0x0024, 0x23a8: 0x0024, 0x23a9: 0x0024, + 0x23aa: 0x0024, 0x23ab: 0x0024, 0x23ac: 0x2000, 0x23ad: 0x0024, 0x23ae: 0x0024, 0x23af: 0x0024, + 0x23b0: 0x0024, 0x23b1: 0x0024, 0x23b2: 0x0024, 0x23b3: 0x0044, 0x23b4: 0x0024, + // Block 0x8f, offset 0x23c0 + 0x23c4: 0x0010, 0x23c5: 0x2000, + 0x23c6: 0x2000, 0x23c7: 0x0010, + 0x23f3: 0x0024, + // Block 0x90, offset 0x2400 + 0x2400: 0x0024, 0x2401: 0x0024, 0x2402: 0x2000, + 0x2433: 0x2000, 0x2434: 0x2000, 0x2435: 0x2000, + 0x2436: 0x0024, 0x2437: 0x0024, 0x2438: 0x0024, 0x2439: 0x0024, 0x243a: 0x0024, 0x243b: 0x0024, + 0x243c: 0x0024, 0x243d: 0x0024, 0x243e: 0x0024, 0x243f: 0x2000, + // Block 0x91, offset 0x2440 + 0x2440: 0x0024, 0x2442: 0x0800, 0x2443: 0x0800, + 0x2449: 0x0024, 0x244a: 0x0024, 0x244b: 0x0024, + 0x244c: 0x0024, 0x244e: 0x2000, 0x244f: 0x0024, + // Block 0x92, offset 0x2480 + 0x24ac: 0x2000, 0x24ad: 0x2000, 0x24ae: 0x2000, 0x24af: 0x0024, + 0x24b0: 0x0024, 0x24b1: 0x0024, 0x24b2: 0x2000, 0x24b3: 0x2000, 0x24b4: 0x0024, 0x24b5: 0x0024, + 0x24b6: 0x0024, 0x24b7: 0x0024, + 0x24be: 0x0024, + // Block 0x93, offset 0x24c0 + 0x24c1: 0x0024, + // Block 0x94, offset 0x2500 + 0x251f: 0x0024, 0x2520: 0x2000, 0x2521: 0x2000, 0x2522: 0x2000, 0x2523: 0x0024, + 0x2524: 0x0024, 0x2525: 0x0024, 0x2526: 0x0024, 0x2527: 0x0024, 0x2528: 0x0024, 0x2529: 0x0024, + 0x252a: 0x0024, + // Block 0x95, offset 0x2540 + 0x2540: 0x0024, 0x2541: 0x0024, 0x2542: 0x2000, 0x2543: 0x2000, + 0x257b: 0x0024, + 0x257c: 0x0024, 0x257e: 0x0024, 0x257f: 0x2000, + // Block 0x96, offset 0x2580 + 0x2580: 0x0024, 0x2581: 0x2000, 0x2582: 0x2000, 0x2583: 0x2000, 0x2584: 0x2000, + 0x2587: 0x2000, 0x2588: 0x2000, 0x258b: 0x2000, + 0x258c: 0x2000, 0x258d: 0x0024, + 0x2597: 0x0024, + 0x25a2: 0x2000, 0x25a3: 0x2000, + 0x25a6: 0x0024, 0x25a7: 0x0024, 0x25a8: 0x0024, 0x25a9: 0x0024, + 0x25aa: 0x0024, 0x25ab: 0x0024, 0x25ac: 0x0024, + 0x25b0: 0x0024, 0x25b1: 0x0024, 0x25b2: 0x0024, 0x25b3: 0x0024, 0x25b4: 0x0024, + // Block 0x97, offset 0x25c0 + 0x25c0: 0x0010, 0x25c1: 0x0010, 0x25c2: 0x0010, 0x25c3: 0x0010, 0x25c4: 0x0010, 0x25c5: 0x0010, + 0x25c6: 0x0010, 0x25c7: 0x0010, 0x25c8: 0x0010, 0x25c9: 0x0010, 0x25cb: 0x0010, + 0x25ce: 0x0010, 0x25d0: 0x0010, 0x25d1: 0x0010, + 0x25d2: 0x0010, 0x25d3: 0x0010, 0x25d4: 0x0010, 0x25d5: 0x0010, 0x25d6: 0x0010, 0x25d7: 0x0010, + 0x25d8: 0x0010, 0x25d9: 0x0010, 0x25da: 0x0010, 0x25db: 0x0010, 0x25dc: 0x0010, 0x25dd: 0x0010, + 0x25de: 0x0010, 0x25df: 0x0010, 0x25e0: 0x0010, 0x25e1: 0x0010, 0x25e2: 0x0010, 0x25e3: 0x0010, + 0x25e4: 0x0010, 0x25e5: 0x0010, 0x25e6: 0x0010, 0x25e7: 0x0010, 0x25e8: 0x0010, 0x25e9: 0x0010, + 0x25ea: 0x0010, 0x25eb: 0x0010, 0x25ec: 0x0010, 0x25ed: 0x0010, 0x25ee: 0x0010, 0x25ef: 0x0010, + 0x25f0: 0x0010, 0x25f1: 0x0010, 0x25f2: 0x0010, 0x25f3: 0x0010, 0x25f4: 0x0010, 0x25f5: 0x0010, + 0x25f8: 0x0024, 0x25f9: 0x2000, 0x25fa: 0x2000, 0x25fb: 0x0024, + 0x25fc: 0x0024, 0x25fd: 0x0024, 0x25fe: 0x0024, 0x25ff: 0x0024, + // Block 0x98, offset 0x2600 + 0x2600: 0x0024, 0x2602: 0x0024, 0x2605: 0x0024, + 0x2607: 0x0024, 0x2608: 0x0024, 0x2609: 0x0024, 0x260a: 0x2000, + 0x260c: 0x2000, 0x260d: 0x2000, 0x260e: 0x0024, 0x260f: 0x0024, 0x2610: 0x0044, 0x2611: 0x0800, + 0x2612: 0x0024, + 0x2621: 0x0024, 0x2622: 0x0024, + // Block 0x99, offset 0x2640 + 0x2675: 0x2000, + 0x2676: 0x2000, 0x2677: 0x2000, 0x2678: 0x0024, 0x2679: 0x0024, 0x267a: 0x0024, 0x267b: 0x0024, + 0x267c: 0x0024, 0x267d: 0x0024, 0x267e: 0x0024, 0x267f: 0x0024, + // Block 0x9a, offset 0x2680 + 0x2680: 0x2000, 0x2681: 0x2000, 0x2682: 0x0024, 0x2683: 0x0024, 0x2684: 0x0024, 0x2685: 0x2000, + 0x2686: 0x0024, + 0x269e: 0x0024, + // Block 0x9b, offset 0x26c0 + 0x26f0: 0x0024, 0x26f1: 0x2000, 0x26f2: 0x2000, 0x26f3: 0x0024, 0x26f4: 0x0024, 0x26f5: 0x0024, + 0x26f6: 0x0024, 0x26f7: 0x0024, 0x26f8: 0x0024, 0x26f9: 0x2000, 0x26fa: 0x0024, 0x26fb: 0x2000, + 0x26fc: 0x2000, 0x26fd: 0x0024, 0x26fe: 0x2000, 0x26ff: 0x0024, + // Block 0x9c, offset 0x2700 + 0x2700: 0x0024, 0x2701: 0x2000, 0x2702: 0x0024, 0x2703: 0x0024, + // Block 0x9d, offset 0x2740 + 0x276f: 0x0024, + 0x2770: 0x2000, 0x2771: 0x2000, 0x2772: 0x0024, 0x2773: 0x0024, 0x2774: 0x0024, 0x2775: 0x0024, + 0x2778: 0x2000, 0x2779: 0x2000, 0x277a: 0x2000, 0x277b: 0x2000, + 0x277c: 0x0024, 0x277d: 0x0024, 0x277e: 0x2000, 0x277f: 0x0024, + // Block 0x9e, offset 0x2780 + 0x2780: 0x0024, + 0x279c: 0x0024, 0x279d: 0x0024, + // Block 0x9f, offset 0x27c0 + 0x27f0: 0x2000, 0x27f1: 0x2000, 0x27f2: 0x2000, 0x27f3: 0x0024, 0x27f4: 0x0024, 0x27f5: 0x0024, + 0x27f6: 0x0024, 0x27f7: 0x0024, 0x27f8: 0x0024, 0x27f9: 0x0024, 0x27fa: 0x0024, 0x27fb: 0x2000, + 0x27fc: 0x2000, 0x27fd: 0x0024, 0x27fe: 0x2000, 0x27ff: 0x0024, + // Block 0xa0, offset 0x2800 + 0x2800: 0x0024, + // Block 0xa1, offset 0x2840 + 0x286b: 0x0024, 0x286c: 0x2000, 0x286d: 0x0024, 0x286e: 0x2000, 0x286f: 0x2000, + 0x2870: 0x0024, 0x2871: 0x0024, 0x2872: 0x0024, 0x2873: 0x0024, 0x2874: 0x0024, 0x2875: 0x0024, + 0x2876: 0x0024, 0x2877: 0x0024, + // Block 0xa2, offset 0x2880 + 0x289d: 0x0024, + 0x289e: 0x2000, 0x289f: 0x0024, 0x28a2: 0x0024, 0x28a3: 0x0024, + 0x28a4: 0x0024, 0x28a5: 0x0024, 0x28a6: 0x2000, 0x28a7: 0x0024, 0x28a8: 0x0024, 0x28a9: 0x0024, + 0x28aa: 0x0024, 0x28ab: 0x0024, + // Block 0xa3, offset 0x28c0 + 0x28ec: 0x2000, 0x28ed: 0x2000, 0x28ee: 0x2000, 0x28ef: 0x0024, + 0x28f0: 0x0024, 0x28f1: 0x0024, 0x28f2: 0x0024, 0x28f3: 0x0024, 0x28f4: 0x0024, 0x28f5: 0x0024, + 0x28f6: 0x0024, 0x28f7: 0x0024, 0x28f8: 0x2000, 0x28f9: 0x0024, 0x28fa: 0x0024, + // Block 0xa4, offset 0x2900 + 0x2900: 0x0010, 0x2901: 0x0010, 0x2902: 0x0010, 0x2903: 0x0010, 0x2904: 0x0010, 0x2905: 0x0010, + 0x2906: 0x0010, 0x2909: 0x0010, + 0x290c: 0x0010, 0x290d: 0x0010, 0x290e: 0x0010, 0x290f: 0x0010, 0x2910: 0x0010, 0x2911: 0x0010, + 0x2912: 0x0010, 0x2913: 0x0010, 0x2915: 0x0010, 0x2916: 0x0010, + 0x2918: 0x0010, 0x2919: 0x0010, 0x291a: 0x0010, 0x291b: 0x0010, 0x291c: 0x0010, 0x291d: 0x0010, + 0x291e: 0x0010, 0x291f: 0x0010, 0x2920: 0x0010, 0x2921: 0x0010, 0x2922: 0x0010, 0x2923: 0x0010, + 0x2924: 0x0010, 0x2925: 0x0010, 0x2926: 0x0010, 0x2927: 0x0010, 0x2928: 0x0010, 0x2929: 0x0010, + 0x292a: 0x0010, 0x292b: 0x0010, 0x292c: 0x0010, 0x292d: 0x0010, 0x292e: 0x0010, 0x292f: 0x0010, + 0x2930: 0x0024, 0x2931: 0x2000, 0x2932: 0x2000, 0x2933: 0x2000, 0x2934: 0x2000, 0x2935: 0x2000, + 0x2937: 0x2000, 0x2938: 0x2000, 0x293b: 0x0024, + 0x293c: 0x0024, 0x293d: 0x0024, 0x293e: 0x0044, 0x293f: 0x0800, + // Block 0xa5, offset 0x2940 + 0x2940: 0x2000, 0x2941: 0x0800, 0x2942: 0x2000, 0x2943: 0x0024, + // Block 0xa6, offset 0x2980 + 0x2991: 0x2000, + 0x2992: 0x2000, 0x2993: 0x2000, 0x2994: 0x0024, 0x2995: 0x0024, 0x2996: 0x0024, 0x2997: 0x0024, + 0x299a: 0x0024, 0x299b: 0x0024, 0x299c: 0x2000, 0x299d: 0x2000, + 0x299e: 0x2000, 0x299f: 0x2000, 0x29a0: 0x0024, + 0x29a4: 0x2000, + // Block 0xa7, offset 0x29c0 + 0x29c0: 0x0010, 0x29c1: 0x0024, 0x29c2: 0x0024, 0x29c3: 0x0024, 0x29c4: 0x0024, 0x29c5: 0x0024, + 0x29c6: 0x0024, 0x29c7: 0x0024, 0x29c8: 0x0024, 0x29c9: 0x0024, 0x29ca: 0x0024, 0x29cb: 0x0010, + 0x29cc: 0x0010, 0x29cd: 0x0010, 0x29ce: 0x0010, 0x29cf: 0x0010, 0x29d0: 0x0010, 0x29d1: 0x0010, + 0x29d2: 0x0010, 0x29d3: 0x0010, 0x29d4: 0x0010, 0x29d5: 0x0010, 0x29d6: 0x0010, 0x29d7: 0x0010, + 0x29d8: 0x0010, 0x29d9: 0x0010, 0x29da: 0x0010, 0x29db: 0x0010, 0x29dc: 0x0010, 0x29dd: 0x0010, + 0x29de: 0x0010, 0x29df: 0x0010, 0x29e0: 0x0010, 0x29e1: 0x0010, 0x29e2: 0x0010, 0x29e3: 0x0010, + 0x29e4: 0x0010, 0x29e5: 0x0010, 0x29e6: 0x0010, 0x29e7: 0x0010, 0x29e8: 0x0010, 0x29e9: 0x0010, + 0x29ea: 0x0010, 0x29eb: 0x0010, 0x29ec: 0x0010, 0x29ed: 0x0010, 0x29ee: 0x0010, 0x29ef: 0x0010, + 0x29f0: 0x0010, 0x29f1: 0x0010, 0x29f2: 0x0010, 0x29f3: 0x0024, 0x29f4: 0x0024, 0x29f5: 0x0024, + 0x29f6: 0x0024, 0x29f7: 0x0024, 0x29f8: 0x0024, 0x29f9: 0x2000, 0x29fb: 0x0024, + 0x29fc: 0x0024, 0x29fd: 0x0024, 0x29fe: 0x0024, + // Block 0xa8, offset 0x2a00 + 0x2a07: 0x0044, + 0x2a10: 0x0010, 0x2a11: 0x0024, + 0x2a12: 0x0024, 0x2a13: 0x0024, 0x2a14: 0x0024, 0x2a15: 0x0024, 0x2a16: 0x0024, 0x2a17: 0x2000, + 0x2a18: 0x2000, 0x2a19: 0x0024, 0x2a1a: 0x0024, 0x2a1b: 0x0024, 0x2a1c: 0x0010, 0x2a1d: 0x0010, + 0x2a1e: 0x0010, 0x2a1f: 0x0010, 0x2a20: 0x0010, 0x2a21: 0x0010, 0x2a22: 0x0010, 0x2a23: 0x0010, + 0x2a24: 0x0010, 0x2a25: 0x0010, 0x2a26: 0x0010, 0x2a27: 0x0010, 0x2a28: 0x0010, 0x2a29: 0x0010, + 0x2a2a: 0x0010, 0x2a2b: 0x0010, 0x2a2c: 0x0010, 0x2a2d: 0x0010, 0x2a2e: 0x0010, 0x2a2f: 0x0010, + 0x2a30: 0x0010, 0x2a31: 0x0010, 0x2a32: 0x0010, 0x2a33: 0x0010, 0x2a34: 0x0010, 0x2a35: 0x0010, + 0x2a36: 0x0010, 0x2a37: 0x0010, 0x2a38: 0x0010, 0x2a39: 0x0010, 0x2a3a: 0x0010, 0x2a3b: 0x0010, + 0x2a3c: 0x0010, 0x2a3d: 0x0010, 0x2a3e: 0x0010, 0x2a3f: 0x0010, + // Block 0xa9, offset 0x2a40 + 0x2a40: 0x0010, 0x2a41: 0x0010, 0x2a42: 0x0010, 0x2a43: 0x0010, 0x2a44: 0x0800, 0x2a45: 0x0800, + 0x2a46: 0x0800, 0x2a47: 0x0800, 0x2a48: 0x0800, 0x2a49: 0x0800, 0x2a4a: 0x0024, 0x2a4b: 0x0024, + 0x2a4c: 0x0024, 0x2a4d: 0x0024, 0x2a4e: 0x0024, 0x2a4f: 0x0024, 0x2a50: 0x0024, 0x2a51: 0x0024, + 0x2a52: 0x0024, 0x2a53: 0x0024, 0x2a54: 0x0024, 0x2a55: 0x0024, 0x2a56: 0x0024, 0x2a57: 0x2000, + 0x2a58: 0x0024, 0x2a59: 0x0044, + // Block 0xaa, offset 0x2a80 + 0x2aa0: 0x0024, 0x2aa1: 0x2000, 0x2aa2: 0x0024, 0x2aa3: 0x0024, + 0x2aa4: 0x0024, 0x2aa5: 0x2000, 0x2aa6: 0x0024, 0x2aa7: 0x2000, + // Block 0xab, offset 0x2ac0 + 0x2aef: 0x2000, + 0x2af0: 0x0024, 0x2af1: 0x0024, 0x2af2: 0x0024, 0x2af3: 0x0024, 0x2af4: 0x0024, 0x2af5: 0x0024, + 0x2af6: 0x0024, 0x2af8: 0x0024, 0x2af9: 0x0024, 0x2afa: 0x0024, 0x2afb: 0x0024, + 0x2afc: 0x0024, 0x2afd: 0x0024, 0x2afe: 0x2000, 0x2aff: 0x0024, + // Block 0xac, offset 0x2b00 + 0x2b12: 0x0024, 0x2b13: 0x0024, 0x2b14: 0x0024, 0x2b15: 0x0024, 0x2b16: 0x0024, 0x2b17: 0x0024, + 0x2b18: 0x0024, 0x2b19: 0x0024, 0x2b1a: 0x0024, 0x2b1b: 0x0024, 0x2b1c: 0x0024, 0x2b1d: 0x0024, + 0x2b1e: 0x0024, 0x2b1f: 0x0024, 0x2b20: 0x0024, 0x2b21: 0x0024, 0x2b22: 0x0024, 0x2b23: 0x0024, + 0x2b24: 0x0024, 0x2b25: 0x0024, 0x2b26: 0x0024, 0x2b27: 0x0024, 0x2b29: 0x2000, + 0x2b2a: 0x0024, 0x2b2b: 0x0024, 0x2b2c: 0x0024, 0x2b2d: 0x0024, 0x2b2e: 0x0024, 0x2b2f: 0x0024, + 0x2b30: 0x0024, 0x2b31: 0x2000, 0x2b32: 0x0024, 0x2b33: 0x0024, 0x2b34: 0x2000, 0x2b35: 0x0024, + 0x2b36: 0x0024, + // Block 0xad, offset 0x2b40 + 0x2b71: 0x0024, 0x2b72: 0x0024, 0x2b73: 0x0024, 0x2b74: 0x0024, 0x2b75: 0x0024, + 0x2b76: 0x0024, 0x2b7a: 0x0024, + 0x2b7c: 0x0024, 0x2b7d: 0x0024, 0x2b7f: 0x0024, + // Block 0xae, offset 0x2b80 + 0x2b80: 0x0024, 0x2b81: 0x0024, 0x2b82: 0x0024, 0x2b83: 0x0024, 0x2b84: 0x0024, 0x2b85: 0x0024, + 0x2b86: 0x0800, 0x2b87: 0x0024, + // Block 0xaf, offset 0x2bc0 + 0x2bca: 0x2000, 0x2bcb: 0x2000, + 0x2bcc: 0x2000, 0x2bcd: 0x2000, 0x2bce: 0x2000, 0x2bd0: 0x0024, 0x2bd1: 0x0024, + 0x2bd3: 0x2000, 0x2bd4: 0x2000, 0x2bd5: 0x0024, 0x2bd6: 0x2000, 0x2bd7: 0x0024, + // Block 0xb0, offset 0x2c00 + 0x2c33: 0x0024, 0x2c34: 0x0024, 0x2c35: 0x2000, + 0x2c36: 0x2000, + // Block 0xb1, offset 0x2c40 + 0x2c40: 0x0024, 0x2c41: 0x0024, 0x2c42: 0x0800, 0x2c43: 0x2000, 0x2c44: 0x0010, 0x2c45: 0x0010, + 0x2c46: 0x0010, 0x2c47: 0x0010, 0x2c48: 0x0010, 0x2c49: 0x0010, 0x2c4a: 0x0010, 0x2c4b: 0x0010, + 0x2c4c: 0x0010, 0x2c4d: 0x0010, 0x2c4e: 0x0010, 0x2c4f: 0x0010, 0x2c50: 0x0010, + 0x2c52: 0x0010, 0x2c53: 0x0010, 0x2c54: 0x0010, 0x2c55: 0x0010, 0x2c56: 0x0010, 0x2c57: 0x0010, + 0x2c58: 0x0010, 0x2c59: 0x0010, 0x2c5a: 0x0010, 0x2c5b: 0x0010, 0x2c5c: 0x0010, 0x2c5d: 0x0010, + 0x2c5e: 0x0010, 0x2c5f: 0x0010, 0x2c60: 0x0010, 0x2c61: 0x0010, 0x2c62: 0x0010, 0x2c63: 0x0010, + 0x2c64: 0x0010, 0x2c65: 0x0010, 0x2c66: 0x0010, 0x2c67: 0x0010, 0x2c68: 0x0010, 0x2c69: 0x0010, + 0x2c6a: 0x0010, 0x2c6b: 0x0010, 0x2c6c: 0x0010, 0x2c6d: 0x0010, 0x2c6e: 0x0010, 0x2c6f: 0x0010, + 0x2c70: 0x0010, 0x2c71: 0x0010, 0x2c72: 0x0010, 0x2c73: 0x0010, 0x2c74: 0x2000, 0x2c75: 0x2000, + 0x2c76: 0x0024, 0x2c77: 0x0024, 0x2c78: 0x0024, 0x2c79: 0x0024, 0x2c7a: 0x0024, + 0x2c7e: 0x2000, 0x2c7f: 0x2000, + // Block 0xb2, offset 0x2c80 + 0x2c80: 0x0024, 0x2c81: 0x0024, 0x2c82: 0x0044, + 0x2c9a: 0x0024, + // Block 0xb3, offset 0x2cc0 + 0x2cf0: 0x0002, 0x2cf1: 0x0002, 0x2cf2: 0x0002, 0x2cf3: 0x0002, 0x2cf4: 0x0002, 0x2cf5: 0x0002, + 0x2cf6: 0x0002, 0x2cf7: 0x0002, 0x2cf8: 0x0002, 0x2cf9: 0x0002, 0x2cfa: 0x0002, 0x2cfb: 0x0002, + 0x2cfc: 0x0002, 0x2cfd: 0x0002, 0x2cfe: 0x0002, 0x2cff: 0x0002, + // Block 0xb4, offset 0x2d00 + 0x2d00: 0x0024, + 0x2d07: 0x0024, 0x2d08: 0x0024, 0x2d09: 0x0024, 0x2d0a: 0x0024, 0x2d0b: 0x0024, + 0x2d0c: 0x0024, 0x2d0d: 0x0024, 0x2d0e: 0x0024, 0x2d0f: 0x0024, 0x2d10: 0x0024, 0x2d11: 0x0024, + 0x2d12: 0x0024, 0x2d13: 0x0024, 0x2d14: 0x0024, 0x2d15: 0x0024, + // Block 0xb5, offset 0x2d40 + 0x2d5e: 0x0024, 0x2d5f: 0x0024, 0x2d60: 0x0024, 0x2d61: 0x0024, 0x2d62: 0x0024, 0x2d63: 0x0024, + 0x2d64: 0x0024, 0x2d65: 0x0024, 0x2d66: 0x0024, 0x2d67: 0x0024, 0x2d68: 0x0024, 0x2d69: 0x0024, + 0x2d6a: 0x2000, 0x2d6b: 0x2000, 0x2d6c: 0x2000, 0x2d6d: 0x0024, 0x2d6e: 0x0024, 0x2d6f: 0x0024, + // Block 0xb6, offset 0x2d80 + 0x2db0: 0x0024, 0x2db1: 0x0024, 0x2db2: 0x0024, 0x2db3: 0x0024, 0x2db4: 0x0024, + // Block 0xb7, offset 0x2dc0 + 0x2df0: 0x0024, 0x2df1: 0x0024, 0x2df2: 0x0024, 0x2df3: 0x0024, 0x2df4: 0x0024, 0x2df5: 0x0024, + 0x2df6: 0x0024, + // Block 0xb8, offset 0x2e00 + 0x2e23: 0x8000, + 0x2e27: 0x8000, 0x2e28: 0x8000, 0x2e29: 0x8000, + 0x2e2a: 0x8000, + // Block 0xb9, offset 0x2e40 + 0x2e4f: 0x0024, 0x2e51: 0x2000, + 0x2e52: 0x2000, 0x2e53: 0x2000, 0x2e54: 0x2000, 0x2e55: 0x2000, 0x2e56: 0x2000, 0x2e57: 0x2000, + 0x2e58: 0x2000, 0x2e59: 0x2000, 0x2e5a: 0x2000, 0x2e5b: 0x2000, 0x2e5c: 0x2000, 0x2e5d: 0x2000, + 0x2e5e: 0x2000, 0x2e5f: 0x2000, 0x2e60: 0x2000, 0x2e61: 0x2000, 0x2e62: 0x2000, 0x2e63: 0x2000, + 0x2e64: 0x2000, 0x2e65: 0x2000, 0x2e66: 0x2000, 0x2e67: 0x2000, 0x2e68: 0x2000, 0x2e69: 0x2000, + 0x2e6a: 0x2000, 0x2e6b: 0x2000, 0x2e6c: 0x2000, 0x2e6d: 0x2000, 0x2e6e: 0x2000, 0x2e6f: 0x2000, + 0x2e70: 0x2000, 0x2e71: 0x2000, 0x2e72: 0x2000, 0x2e73: 0x2000, 0x2e74: 0x2000, 0x2e75: 0x2000, + 0x2e76: 0x2000, 0x2e77: 0x2000, 0x2e78: 0x2000, 0x2e79: 0x2000, 0x2e7a: 0x2000, 0x2e7b: 0x2000, + 0x2e7c: 0x2000, 0x2e7d: 0x2000, 0x2e7e: 0x2000, 0x2e7f: 0x2000, + // Block 0xba, offset 0x2e80 + 0x2e80: 0x2000, 0x2e81: 0x2000, 0x2e82: 0x2000, 0x2e83: 0x2000, 0x2e84: 0x2000, 0x2e85: 0x2000, + 0x2e86: 0x2000, 0x2e87: 0x2000, + 0x2e8f: 0x0024, 0x2e90: 0x0024, 0x2e91: 0x0024, + 0x2e92: 0x0024, + // Block 0xbb, offset 0x2ec0 + 0x2ee4: 0x0024, + 0x2ef0: 0x0024, 0x2ef1: 0x0024, + // Block 0xbc, offset 0x2f00 + 0x2f1d: 0x0024, + 0x2f1e: 0x0024, 0x2f20: 0x0002, 0x2f21: 0x0002, 0x2f22: 0x0002, 0x2f23: 0x0002, + // Block 0xbd, offset 0x2f40 + 0x2f40: 0x0024, 0x2f41: 0x0024, 0x2f42: 0x0024, 0x2f43: 0x0024, 0x2f44: 0x0024, 0x2f45: 0x0024, + 0x2f46: 0x0024, 0x2f47: 0x0024, 0x2f48: 0x0024, 0x2f49: 0x0024, 0x2f4a: 0x0024, 0x2f4b: 0x0024, + 0x2f4c: 0x0024, 0x2f4d: 0x0024, 0x2f4e: 0x0024, 0x2f4f: 0x0024, 0x2f50: 0x0024, 0x2f51: 0x0024, + 0x2f52: 0x0024, 0x2f53: 0x0024, 0x2f54: 0x0024, 0x2f55: 0x0024, 0x2f56: 0x0024, 0x2f57: 0x0024, + 0x2f58: 0x0024, 0x2f59: 0x0024, 0x2f5a: 0x0024, 0x2f5b: 0x0024, 0x2f5c: 0x0024, 0x2f5d: 0x0024, + 0x2f5e: 0x0024, 0x2f5f: 0x0024, 0x2f60: 0x0024, 0x2f61: 0x0024, 0x2f62: 0x0024, 0x2f63: 0x0024, + 0x2f64: 0x0024, 0x2f65: 0x0024, 0x2f66: 0x0024, 0x2f67: 0x0024, 0x2f68: 0x0024, 0x2f69: 0x0024, + 0x2f6a: 0x0024, 0x2f6b: 0x0024, 0x2f6c: 0x0024, 0x2f6d: 0x0024, + 0x2f70: 0x0024, 0x2f71: 0x0024, 0x2f72: 0x0024, 0x2f73: 0x0024, 0x2f74: 0x0024, 0x2f75: 0x0024, + 0x2f76: 0x0024, 0x2f77: 0x0024, 0x2f78: 0x0024, 0x2f79: 0x0024, 0x2f7a: 0x0024, 0x2f7b: 0x0024, + 0x2f7c: 0x0024, 0x2f7d: 0x0024, 0x2f7e: 0x0024, 0x2f7f: 0x0024, + // Block 0xbe, offset 0x2f80 + 0x2f80: 0x0024, 0x2f81: 0x0024, 0x2f82: 0x0024, 0x2f83: 0x0024, 0x2f84: 0x0024, 0x2f85: 0x0024, + 0x2f86: 0x0024, + // Block 0xbf, offset 0x2fc0 + 0x2fe5: 0x0024, 0x2fe6: 0x0024, 0x2fe7: 0x0024, 0x2fe8: 0x0024, 0x2fe9: 0x0024, + 0x2fed: 0x0024, 0x2fee: 0x0024, 0x2fef: 0x0024, + 0x2ff0: 0x0024, 0x2ff1: 0x0024, 0x2ff2: 0x0024, 0x2ff3: 0x0002, 0x2ff4: 0x0002, 0x2ff5: 0x0002, + 0x2ff6: 0x0002, 0x2ff7: 0x0002, 0x2ff8: 0x0002, 0x2ff9: 0x0002, 0x2ffa: 0x0002, 0x2ffb: 0x0024, + 0x2ffc: 0x0024, 0x2ffd: 0x0024, 0x2ffe: 0x0024, 0x2fff: 0x0024, + // Block 0xc0, offset 0x3000 + 0x3000: 0x0024, 0x3001: 0x0024, 0x3002: 0x0024, 0x3005: 0x0024, + 0x3006: 0x0024, 0x3007: 0x0024, 0x3008: 0x0024, 0x3009: 0x0024, 0x300a: 0x0024, 0x300b: 0x0024, + 0x302a: 0x0024, 0x302b: 0x0024, 0x302c: 0x0024, 0x302d: 0x0024, + // Block 0xc1, offset 0x3040 + 0x3042: 0x0024, 0x3043: 0x0024, 0x3044: 0x0024, + // Block 0xc2, offset 0x3080 + 0x3080: 0x0024, 0x3081: 0x0024, 0x3082: 0x0024, 0x3083: 0x0024, 0x3084: 0x0024, 0x3085: 0x0024, + 0x3086: 0x0024, 0x3087: 0x0024, 0x3088: 0x0024, 0x3089: 0x0024, 0x308a: 0x0024, 0x308b: 0x0024, + 0x308c: 0x0024, 0x308d: 0x0024, 0x308e: 0x0024, 0x308f: 0x0024, 0x3090: 0x0024, 0x3091: 0x0024, + 0x3092: 0x0024, 0x3093: 0x0024, 0x3094: 0x0024, 0x3095: 0x0024, 0x3096: 0x0024, 0x3097: 0x0024, + 0x3098: 0x0024, 0x3099: 0x0024, 0x309a: 0x0024, 0x309b: 0x0024, 0x309c: 0x0024, 0x309d: 0x0024, + 0x309e: 0x0024, 0x309f: 0x0024, 0x30a0: 0x0024, 0x30a1: 0x0024, 0x30a2: 0x0024, 0x30a3: 0x0024, + 0x30a4: 0x0024, 0x30a5: 0x0024, 0x30a6: 0x0024, 0x30a7: 0x0024, 0x30a8: 0x0024, 0x30a9: 0x0024, + 0x30aa: 0x0024, 0x30ab: 0x0024, 0x30ac: 0x0024, 0x30ad: 0x0024, 0x30ae: 0x0024, 0x30af: 0x0024, + 0x30b0: 0x0024, 0x30b1: 0x0024, 0x30b2: 0x0024, 0x30b3: 0x0024, 0x30b4: 0x0024, 0x30b5: 0x0024, + 0x30b6: 0x0024, 0x30bb: 0x0024, + 0x30bc: 0x0024, 0x30bd: 0x0024, 0x30be: 0x0024, 0x30bf: 0x0024, + // Block 0xc3, offset 0x30c0 + 0x30c0: 0x0024, 0x30c1: 0x0024, 0x30c2: 0x0024, 0x30c3: 0x0024, 0x30c4: 0x0024, 0x30c5: 0x0024, + 0x30c6: 0x0024, 0x30c7: 0x0024, 0x30c8: 0x0024, 0x30c9: 0x0024, 0x30ca: 0x0024, 0x30cb: 0x0024, + 0x30cc: 0x0024, 0x30cd: 0x0024, 0x30ce: 0x0024, 0x30cf: 0x0024, 0x30d0: 0x0024, 0x30d1: 0x0024, + 0x30d2: 0x0024, 0x30d3: 0x0024, 0x30d4: 0x0024, 0x30d5: 0x0024, 0x30d6: 0x0024, 0x30d7: 0x0024, + 0x30d8: 0x0024, 0x30d9: 0x0024, 0x30da: 0x0024, 0x30db: 0x0024, 0x30dc: 0x0024, 0x30dd: 0x0024, + 0x30de: 0x0024, 0x30df: 0x0024, 0x30e0: 0x0024, 0x30e1: 0x0024, 0x30e2: 0x0024, 0x30e3: 0x0024, + 0x30e4: 0x0024, 0x30e5: 0x0024, 0x30e6: 0x0024, 0x30e7: 0x0024, 0x30e8: 0x0024, 0x30e9: 0x0024, + 0x30ea: 0x0024, 0x30eb: 0x0024, 0x30ec: 0x0024, + 0x30f5: 0x0024, + // Block 0xc4, offset 0x3100 + 0x3104: 0x0024, + 0x311b: 0x0024, 0x311c: 0x0024, 0x311d: 0x0024, + 0x311e: 0x0024, 0x311f: 0x0024, 0x3121: 0x0024, 0x3122: 0x0024, 0x3123: 0x0024, + 0x3124: 0x0024, 0x3125: 0x0024, 0x3126: 0x0024, 0x3127: 0x0024, 0x3128: 0x0024, 0x3129: 0x0024, + 0x312a: 0x0024, 0x312b: 0x0024, 0x312c: 0x0024, 0x312d: 0x0024, 0x312e: 0x0024, 0x312f: 0x0024, + // Block 0xc5, offset 0x3140 + 0x3140: 0x0024, 0x3141: 0x0024, 0x3142: 0x0024, 0x3143: 0x0024, 0x3144: 0x0024, 0x3145: 0x0024, + 0x3146: 0x0024, 0x3148: 0x0024, 0x3149: 0x0024, 0x314a: 0x0024, 0x314b: 0x0024, + 0x314c: 0x0024, 0x314d: 0x0024, 0x314e: 0x0024, 0x314f: 0x0024, 0x3150: 0x0024, 0x3151: 0x0024, + 0x3152: 0x0024, 0x3153: 0x0024, 0x3154: 0x0024, 0x3155: 0x0024, 0x3156: 0x0024, 0x3157: 0x0024, + 0x3158: 0x0024, 0x315b: 0x0024, 0x315c: 0x0024, 0x315d: 0x0024, + 0x315e: 0x0024, 0x315f: 0x0024, 0x3160: 0x0024, 0x3161: 0x0024, 0x3163: 0x0024, + 0x3164: 0x0024, 0x3166: 0x0024, 0x3167: 0x0024, 0x3168: 0x0024, 0x3169: 0x0024, + 0x316a: 0x0024, + // Block 0xc6, offset 0x3180 + 0x318f: 0x0024, + // Block 0xc7, offset 0x31c0 + 0x31ee: 0x0024, + // Block 0xc8, offset 0x3200 + 0x322c: 0x0024, 0x322d: 0x0024, 0x322e: 0x0024, 0x322f: 0x0024, + // Block 0xc9, offset 0x3240 + 0x326e: 0x0024, 0x326f: 0x0024, + // Block 0xca, offset 0x3280 + 0x32a3: 0x0024, + 0x32a6: 0x0024, + 0x32ae: 0x0024, 0x32af: 0x0024, + 0x32b5: 0x0024, + // Block 0xcb, offset 0x32c0 + 0x32d0: 0x0024, 0x32d1: 0x0024, + 0x32d2: 0x0024, 0x32d3: 0x0024, 0x32d4: 0x0024, 0x32d5: 0x0024, 0x32d6: 0x0024, + // Block 0xcc, offset 0x3300 + 0x3304: 0x0024, 0x3305: 0x0024, + 0x3306: 0x0024, 0x3307: 0x0024, 0x3308: 0x0024, 0x3309: 0x0024, 0x330a: 0x0024, + // Block 0xcd, offset 0x3340 + 0x3344: 0x0008, + 0x336c: 0x0008, 0x336d: 0x0008, 0x336e: 0x0008, 0x336f: 0x0008, + // Block 0xce, offset 0x3380 + 0x3394: 0x0008, 0x3395: 0x0008, 0x3396: 0x0008, 0x3397: 0x0008, + 0x3398: 0x0008, 0x3399: 0x0008, 0x339a: 0x0008, 0x339b: 0x0008, 0x339c: 0x0008, 0x339d: 0x0008, + 0x339e: 0x0008, 0x339f: 0x0008, + 0x33af: 0x0008, + 0x33b0: 0x0008, + // Block 0xcf, offset 0x33c0 + 0x33c0: 0x0008, + 0x33cf: 0x0008, 0x33d0: 0x0008, + 0x33f6: 0x0008, 0x33f7: 0x0008, 0x33f8: 0x0008, 0x33f9: 0x0008, 0x33fa: 0x0008, 0x33fb: 0x0008, + 0x33fc: 0x0008, 0x33fd: 0x0008, 0x33fe: 0x0008, 0x33ff: 0x0008, + // Block 0xd0, offset 0x3400 + 0x3430: 0x0008, 0x3431: 0x0008, + 0x343e: 0x0008, 0x343f: 0x0008, + // Block 0xd1, offset 0x3440 + 0x344e: 0x0008, 0x3451: 0x0008, + 0x3452: 0x0008, 0x3453: 0x0008, 0x3454: 0x0008, 0x3455: 0x0008, 0x3456: 0x0008, 0x3457: 0x0008, + 0x3458: 0x0008, 0x3459: 0x0008, 0x345a: 0x0008, + 0x346e: 0x0008, 0x346f: 0x0008, + 0x3470: 0x0008, 0x3471: 0x0008, 0x3472: 0x0008, 0x3473: 0x0008, 0x3474: 0x0008, 0x3475: 0x0008, + 0x3476: 0x0008, 0x3477: 0x0008, 0x3478: 0x0008, 0x3479: 0x0008, 0x347a: 0x0008, 0x347b: 0x0008, + 0x347c: 0x0008, 0x347d: 0x0008, 0x347e: 0x0008, 0x347f: 0x0008, + // Block 0xd2, offset 0x3480 + 0x3480: 0x0008, 0x3481: 0x0008, 0x3482: 0x0008, 0x3483: 0x0008, 0x3484: 0x0008, 0x3485: 0x0008, + 0x3486: 0x0008, 0x3487: 0x0008, 0x3488: 0x0008, 0x3489: 0x0008, 0x348a: 0x0008, 0x348b: 0x0008, + 0x348c: 0x0008, 0x348d: 0x0008, 0x348e: 0x0008, 0x348f: 0x0008, 0x3490: 0x0008, 0x3491: 0x0008, + 0x3492: 0x0008, 0x3493: 0x0008, 0x3494: 0x0008, 0x3495: 0x0008, 0x3496: 0x0008, 0x3497: 0x0008, + 0x3498: 0x0008, 0x3499: 0x0008, 0x349a: 0x0008, 0x349b: 0x0008, 0x349c: 0x0008, 0x349d: 0x0008, + 0x349e: 0x0008, 0x349f: 0x0008, 0x34a0: 0x0008, 0x34a1: 0x0008, 0x34a2: 0x0008, 0x34a3: 0x0008, + 0x34a4: 0x0008, 0x34a5: 0x0008, 0x34a6: 0x1000, 0x34a7: 0x1000, 0x34a8: 0x1000, 0x34a9: 0x1000, + 0x34aa: 0x1000, 0x34ab: 0x1000, 0x34ac: 0x1000, 0x34ad: 0x1000, 0x34ae: 0x1000, 0x34af: 0x1000, + 0x34b0: 0x1000, 0x34b1: 0x1000, 0x34b2: 0x1000, 0x34b3: 0x1000, 0x34b4: 0x1000, 0x34b5: 0x1000, + 0x34b6: 0x1000, 0x34b7: 0x1000, 0x34b8: 0x1000, 0x34b9: 0x1000, 0x34ba: 0x1000, 0x34bb: 0x1000, + 0x34bc: 0x1000, 0x34bd: 0x1000, 0x34be: 0x1000, 0x34bf: 0x1000, + // Block 0xd3, offset 0x34c0 + 0x34c1: 0x0008, 0x34c2: 0x0008, 0x34c3: 0x0008, 0x34c4: 0x0008, 0x34c5: 0x0008, + 0x34c6: 0x0008, 0x34c7: 0x0008, 0x34c8: 0x0008, 0x34c9: 0x0008, 0x34ca: 0x0008, 0x34cb: 0x0008, + 0x34cc: 0x0008, 0x34cd: 0x0008, 0x34ce: 0x0008, 0x34cf: 0x0008, + 0x34da: 0x0008, + 0x34ef: 0x0008, + 0x34f2: 0x0008, 0x34f3: 0x0008, 0x34f4: 0x0008, 0x34f5: 0x0008, + 0x34f6: 0x0008, 0x34f7: 0x0008, 0x34f8: 0x0008, 0x34f9: 0x0008, 0x34fa: 0x0008, + 0x34fc: 0x0008, 0x34fd: 0x0008, 0x34fe: 0x0008, 0x34ff: 0x0008, + // Block 0xd4, offset 0x3500 + 0x3509: 0x0008, 0x350a: 0x0008, 0x350b: 0x0008, + 0x350c: 0x0008, 0x350d: 0x0008, 0x350e: 0x0008, 0x350f: 0x0008, 0x3510: 0x0008, 0x3511: 0x0008, + 0x3512: 0x0008, 0x3513: 0x0008, 0x3514: 0x0008, 0x3515: 0x0008, 0x3516: 0x0008, 0x3517: 0x0008, + 0x3518: 0x0008, 0x3519: 0x0008, 0x351a: 0x0008, 0x351b: 0x0008, 0x351c: 0x0008, 0x351d: 0x0008, + 0x351e: 0x0008, 0x351f: 0x0008, + 0x3526: 0x0008, 0x3527: 0x0008, 0x3528: 0x0008, 0x3529: 0x0008, + 0x352a: 0x0008, 0x352b: 0x0008, 0x352c: 0x0008, 0x352d: 0x0008, 0x352e: 0x0008, 0x352f: 0x0008, + 0x3530: 0x0008, 0x3531: 0x0008, 0x3532: 0x0008, 0x3533: 0x0008, 0x3534: 0x0008, 0x3535: 0x0008, + 0x3536: 0x0008, 0x3537: 0x0008, 0x3538: 0x0008, 0x3539: 0x0008, 0x353a: 0x0008, 0x353b: 0x0008, + 0x353c: 0x0008, 0x353d: 0x0008, 0x353e: 0x0008, 0x353f: 0x0008, + // Block 0xd5, offset 0x3540 + 0x3540: 0x0008, 0x3541: 0x0008, 0x3542: 0x0008, 0x3543: 0x0008, 0x3544: 0x0008, 0x3545: 0x0008, + 0x3546: 0x0008, 0x3547: 0x0008, 0x3548: 0x0008, 0x3549: 0x0008, 0x354a: 0x0008, 0x354b: 0x0008, + 0x354c: 0x0008, 0x354d: 0x0008, 0x354e: 0x0008, 0x354f: 0x0008, 0x3550: 0x0008, 0x3551: 0x0008, + 0x3552: 0x0008, 0x3553: 0x0008, 0x3554: 0x0008, 0x3555: 0x0008, 0x3556: 0x0008, 0x3557: 0x0008, + 0x3558: 0x0008, 0x3559: 0x0008, 0x355a: 0x0008, 0x355b: 0x0008, 0x355c: 0x0008, 0x355d: 0x0008, + 0x355e: 0x0008, 0x355f: 0x0008, 0x3560: 0x0008, 0x3561: 0x0008, 0x3562: 0x0008, 0x3563: 0x0008, + 0x3564: 0x0008, 0x3565: 0x0008, 0x3566: 0x0008, 0x3567: 0x0008, 0x3568: 0x0008, 0x3569: 0x0008, + 0x356a: 0x0008, 0x356b: 0x0008, 0x356c: 0x0008, 0x356d: 0x0008, 0x356e: 0x0008, 0x356f: 0x0008, + 0x3570: 0x0008, 0x3571: 0x0008, 0x3572: 0x0008, 0x3573: 0x0008, 0x3574: 0x0008, 0x3575: 0x0008, + 0x3576: 0x0008, 0x3577: 0x0008, 0x3578: 0x0008, 0x3579: 0x0008, 0x357a: 0x0008, 0x357b: 0x0008, + 0x357c: 0x0008, 0x357d: 0x0008, 0x357e: 0x0008, 0x357f: 0x0008, + // Block 0xd6, offset 0x3580 + 0x3580: 0x0008, 0x3581: 0x0008, 0x3582: 0x0008, 0x3583: 0x0008, 0x3584: 0x0008, 0x3585: 0x0008, + 0x3586: 0x0008, 0x3587: 0x0008, 0x3588: 0x0008, 0x3589: 0x0008, 0x358a: 0x0008, 0x358b: 0x0008, + 0x358c: 0x0008, 0x358d: 0x0008, 0x358e: 0x0008, 0x358f: 0x0008, 0x3590: 0x0008, 0x3591: 0x0008, + 0x3592: 0x0008, 0x3593: 0x0008, 0x3594: 0x0008, 0x3595: 0x0008, 0x3596: 0x0008, 0x3597: 0x0008, + 0x3598: 0x0008, 0x3599: 0x0008, 0x359a: 0x0008, 0x359b: 0x0008, 0x359c: 0x0008, 0x359d: 0x0008, + 0x359e: 0x0008, 0x359f: 0x0008, 0x35a0: 0x0008, 0x35a1: 0x0008, + 0x35a4: 0x0008, 0x35a5: 0x0008, 0x35a6: 0x0008, 0x35a7: 0x0008, 0x35a8: 0x0008, 0x35a9: 0x0008, + 0x35aa: 0x0008, 0x35ab: 0x0008, 0x35ac: 0x0008, 0x35ad: 0x0008, 0x35ae: 0x0008, 0x35af: 0x0008, + 0x35b0: 0x0008, 0x35b1: 0x0008, 0x35b2: 0x0008, 0x35b3: 0x0008, 0x35b4: 0x0008, 0x35b5: 0x0008, + 0x35b6: 0x0008, 0x35b7: 0x0008, 0x35b8: 0x0008, 0x35b9: 0x0008, 0x35ba: 0x0008, 0x35bb: 0x0008, + 0x35bc: 0x0008, 0x35bd: 0x0008, 0x35be: 0x0008, 0x35bf: 0x0008, + // Block 0xd7, offset 0x35c0 + 0x35c0: 0x0008, 0x35c1: 0x0008, 0x35c2: 0x0008, 0x35c3: 0x0008, 0x35c4: 0x0008, 0x35c5: 0x0008, + 0x35c6: 0x0008, 0x35c7: 0x0008, 0x35c8: 0x0008, 0x35c9: 0x0008, 0x35ca: 0x0008, 0x35cb: 0x0008, + 0x35cc: 0x0008, 0x35cd: 0x0008, 0x35ce: 0x0008, 0x35cf: 0x0008, 0x35d0: 0x0008, 0x35d1: 0x0008, + 0x35d2: 0x0008, 0x35d3: 0x0008, 0x35d6: 0x0008, 0x35d7: 0x0008, + 0x35d9: 0x0008, 0x35da: 0x0008, 0x35db: 0x0008, + 0x35de: 0x0008, 0x35df: 0x0008, 0x35e0: 0x0008, 0x35e1: 0x0008, 0x35e2: 0x0008, 0x35e3: 0x0008, + 0x35e4: 0x0008, 0x35e5: 0x0008, 0x35e6: 0x0008, 0x35e7: 0x0008, 0x35e8: 0x0008, 0x35e9: 0x0008, + 0x35ea: 0x0008, 0x35eb: 0x0008, 0x35ec: 0x0008, 0x35ed: 0x0008, 0x35ee: 0x0008, 0x35ef: 0x0008, + 0x35f0: 0x0008, 0x35f1: 0x0008, 0x35f2: 0x0008, 0x35f3: 0x0008, 0x35f4: 0x0008, 0x35f5: 0x0008, + 0x35f6: 0x0008, 0x35f7: 0x0008, 0x35f8: 0x0008, 0x35f9: 0x0008, 0x35fa: 0x0008, 0x35fb: 0x0008, + 0x35fc: 0x0008, 0x35fd: 0x0008, 0x35fe: 0x0008, 0x35ff: 0x0008, + // Block 0xd8, offset 0x3600 + 0x3600: 0x0008, 0x3601: 0x0008, 0x3602: 0x0008, 0x3603: 0x0008, 0x3604: 0x0008, 0x3605: 0x0008, + 0x3606: 0x0008, 0x3607: 0x0008, 0x3608: 0x0008, 0x3609: 0x0008, 0x360a: 0x0008, 0x360b: 0x0008, + 0x360c: 0x0008, 0x360d: 0x0008, 0x360e: 0x0008, 0x360f: 0x0008, 0x3610: 0x0008, 0x3611: 0x0008, + 0x3612: 0x0008, 0x3613: 0x0008, 0x3614: 0x0008, 0x3615: 0x0008, 0x3616: 0x0008, 0x3617: 0x0008, + 0x3618: 0x0008, 0x3619: 0x0008, 0x361a: 0x0008, 0x361b: 0x0008, 0x361c: 0x0008, 0x361d: 0x0008, + 0x361e: 0x0008, 0x361f: 0x0008, 0x3620: 0x0008, 0x3621: 0x0008, 0x3622: 0x0008, 0x3623: 0x0008, + 0x3624: 0x0008, 0x3625: 0x0008, 0x3626: 0x0008, 0x3627: 0x0008, 0x3628: 0x0008, 0x3629: 0x0008, + 0x362a: 0x0008, 0x362b: 0x0008, 0x362c: 0x0008, 0x362d: 0x0008, 0x362e: 0x0008, 0x362f: 0x0008, + 0x3630: 0x0008, 0x3633: 0x0008, 0x3634: 0x0008, 0x3635: 0x0008, + 0x3637: 0x0008, 0x3638: 0x0008, 0x3639: 0x0008, 0x363a: 0x0008, 0x363b: 0x0024, + 0x363c: 0x0024, 0x363d: 0x0024, 0x363e: 0x0024, 0x363f: 0x0024, + // Block 0xd9, offset 0x3640 + 0x3640: 0x0008, 0x3641: 0x0008, 0x3642: 0x0008, 0x3643: 0x0008, 0x3644: 0x0008, 0x3645: 0x0008, + 0x3646: 0x0008, 0x3647: 0x0008, 0x3648: 0x0008, 0x3649: 0x0008, 0x364a: 0x0008, 0x364b: 0x0008, + 0x364c: 0x0008, 0x364d: 0x0008, 0x364e: 0x0008, 0x364f: 0x0008, 0x3650: 0x0008, 0x3651: 0x0008, + 0x3652: 0x0008, 0x3653: 0x0008, 0x3654: 0x0008, 0x3655: 0x0008, 0x3656: 0x0008, 0x3657: 0x0008, + 0x3658: 0x0008, 0x3659: 0x0008, 0x365a: 0x0008, 0x365b: 0x0008, 0x365c: 0x0008, 0x365d: 0x0008, + 0x365e: 0x0008, 0x365f: 0x0008, 0x3660: 0x0008, 0x3661: 0x0008, 0x3662: 0x0008, 0x3663: 0x0008, + 0x3664: 0x0008, 0x3665: 0x0008, 0x3666: 0x0008, 0x3667: 0x0008, 0x3668: 0x0008, 0x3669: 0x0008, + 0x366a: 0x0008, 0x366b: 0x0008, 0x366c: 0x0008, 0x366d: 0x0008, 0x366e: 0x0008, 0x366f: 0x0008, + 0x3670: 0x0008, 0x3671: 0x0008, 0x3672: 0x0008, 0x3673: 0x0008, 0x3674: 0x0008, 0x3675: 0x0008, + 0x3676: 0x0008, 0x3677: 0x0008, 0x3678: 0x0008, 0x3679: 0x0008, 0x367a: 0x0008, 0x367b: 0x0008, + 0x367c: 0x0008, 0x367d: 0x0008, 0x367f: 0x0008, + // Block 0xda, offset 0x3680 + 0x3680: 0x0008, 0x3681: 0x0008, 0x3682: 0x0008, 0x3683: 0x0008, 0x3684: 0x0008, 0x3685: 0x0008, + 0x3686: 0x0008, 0x3687: 0x0008, 0x3688: 0x0008, 0x3689: 0x0008, 0x368a: 0x0008, 0x368b: 0x0008, + 0x368c: 0x0008, 0x368d: 0x0008, 0x368e: 0x0008, 0x368f: 0x0008, 0x3690: 0x0008, 0x3691: 0x0008, + 0x3692: 0x0008, 0x3693: 0x0008, 0x3694: 0x0008, 0x3695: 0x0008, 0x3696: 0x0008, 0x3697: 0x0008, + 0x3698: 0x0008, 0x3699: 0x0008, 0x369a: 0x0008, 0x369b: 0x0008, 0x369c: 0x0008, 0x369d: 0x0008, + 0x369e: 0x0008, 0x369f: 0x0008, 0x36a0: 0x0008, 0x36a1: 0x0008, 0x36a2: 0x0008, 0x36a3: 0x0008, + 0x36a4: 0x0008, 0x36a5: 0x0008, 0x36a6: 0x0008, 0x36a7: 0x0008, 0x36a8: 0x0008, 0x36a9: 0x0008, + 0x36aa: 0x0008, 0x36ab: 0x0008, 0x36ac: 0x0008, 0x36ad: 0x0008, 0x36ae: 0x0008, 0x36af: 0x0008, + 0x36b0: 0x0008, 0x36b1: 0x0008, 0x36b2: 0x0008, 0x36b3: 0x0008, 0x36b4: 0x0008, 0x36b5: 0x0008, + 0x36b6: 0x0008, 0x36b7: 0x0008, 0x36b8: 0x0008, 0x36b9: 0x0008, 0x36ba: 0x0008, 0x36bb: 0x0008, + 0x36bc: 0x0008, 0x36bd: 0x0008, + // Block 0xdb, offset 0x36c0 + 0x36c9: 0x0008, 0x36ca: 0x0008, 0x36cb: 0x0008, + 0x36cc: 0x0008, 0x36cd: 0x0008, 0x36ce: 0x0008, 0x36d0: 0x0008, 0x36d1: 0x0008, + 0x36d2: 0x0008, 0x36d3: 0x0008, 0x36d4: 0x0008, 0x36d5: 0x0008, 0x36d6: 0x0008, 0x36d7: 0x0008, + 0x36d8: 0x0008, 0x36d9: 0x0008, 0x36da: 0x0008, 0x36db: 0x0008, 0x36dc: 0x0008, 0x36dd: 0x0008, + 0x36de: 0x0008, 0x36df: 0x0008, 0x36e0: 0x0008, 0x36e1: 0x0008, 0x36e2: 0x0008, 0x36e3: 0x0008, + 0x36e4: 0x0008, 0x36e5: 0x0008, 0x36e6: 0x0008, 0x36e7: 0x0008, + 0x36ef: 0x0008, + 0x36f0: 0x0008, 0x36f3: 0x0008, 0x36f4: 0x0008, 0x36f5: 0x0008, + 0x36f6: 0x0008, 0x36f7: 0x0008, 0x36f8: 0x0008, 0x36f9: 0x0008, 0x36fa: 0x0008, + // Block 0xdc, offset 0x3700 + 0x3707: 0x0008, 0x370a: 0x0008, 0x370b: 0x0008, + 0x370c: 0x0008, 0x370d: 0x0008, 0x3710: 0x0008, + 0x3715: 0x0008, 0x3716: 0x0008, + 0x3724: 0x0008, 0x3725: 0x0008, 0x3728: 0x0008, + 0x3731: 0x0008, 0x3732: 0x0008, + 0x373c: 0x0008, + // Block 0xdd, offset 0x3740 + 0x3742: 0x0008, 0x3743: 0x0008, 0x3744: 0x0008, + 0x3751: 0x0008, + 0x3752: 0x0008, 0x3753: 0x0008, + 0x375c: 0x0008, 0x375d: 0x0008, + 0x375e: 0x0008, 0x3761: 0x0008, 0x3763: 0x0008, + 0x3768: 0x0008, + 0x376f: 0x0008, + 0x3773: 0x0008, + 0x377a: 0x0008, 0x377b: 0x0008, + 0x377c: 0x0008, 0x377d: 0x0008, 0x377e: 0x0008, 0x377f: 0x0008, + // Block 0xde, offset 0x3780 + 0x3780: 0x0008, 0x3781: 0x0008, 0x3782: 0x0008, 0x3783: 0x0008, 0x3784: 0x0008, 0x3785: 0x0008, + 0x3786: 0x0008, 0x3787: 0x0008, 0x3788: 0x0008, 0x3789: 0x0008, 0x378a: 0x0008, 0x378b: 0x0008, + 0x378c: 0x0008, 0x378d: 0x0008, 0x378e: 0x0008, 0x378f: 0x0008, + // Block 0xdf, offset 0x37c0 + 0x37c0: 0x0008, 0x37c1: 0x0008, 0x37c2: 0x0008, 0x37c3: 0x0008, 0x37c4: 0x0008, 0x37c5: 0x0008, + 0x37cb: 0x0008, + 0x37cc: 0x0008, 0x37cd: 0x0008, 0x37ce: 0x0008, 0x37cf: 0x0008, 0x37d0: 0x0008, 0x37d1: 0x0008, + 0x37d2: 0x0008, 0x37d5: 0x0008, 0x37d6: 0x0008, 0x37d7: 0x0008, + 0x37d8: 0x0008, 0x37d9: 0x0008, 0x37da: 0x0008, 0x37db: 0x0008, 0x37dc: 0x0008, 0x37dd: 0x0008, + 0x37de: 0x0008, 0x37df: 0x0008, 0x37e0: 0x0008, 0x37e1: 0x0008, 0x37e2: 0x0008, 0x37e3: 0x0008, + 0x37e4: 0x0008, 0x37e5: 0x0008, 0x37e9: 0x0008, + 0x37eb: 0x0008, 0x37ec: 0x0008, 0x37ed: 0x0008, 0x37ee: 0x0008, 0x37ef: 0x0008, + 0x37f0: 0x0008, 0x37f3: 0x0008, 0x37f4: 0x0008, 0x37f5: 0x0008, + 0x37f6: 0x0008, 0x37f7: 0x0008, 0x37f8: 0x0008, 0x37f9: 0x0008, 0x37fa: 0x0008, 0x37fb: 0x0008, + 0x37fc: 0x0008, 0x37fd: 0x0008, 0x37fe: 0x0008, 0x37ff: 0x0008, + // Block 0xe0, offset 0x3800 + 0x381a: 0x0008, 0x381b: 0x0008, 0x381c: 0x0008, 0x381d: 0x0008, + 0x381e: 0x0008, 0x381f: 0x0008, 0x3820: 0x0008, 0x3821: 0x0008, 0x3822: 0x0008, 0x3823: 0x0008, + 0x3824: 0x0008, 0x3825: 0x0008, 0x3826: 0x0008, 0x3827: 0x0008, 0x3828: 0x0008, 0x3829: 0x0008, + 0x382a: 0x0008, 0x382b: 0x0008, 0x382c: 0x0008, 0x382d: 0x0008, 0x382e: 0x0008, 0x382f: 0x0008, + 0x3830: 0x0008, 0x3831: 0x0008, 0x3832: 0x0008, 0x3833: 0x0008, 0x3834: 0x0008, 0x3835: 0x0008, + 0x3836: 0x0008, 0x3837: 0x0008, 0x3838: 0x0008, 0x3839: 0x0008, 0x383a: 0x0008, 0x383b: 0x0008, + 0x383c: 0x0008, 0x383d: 0x0008, 0x383e: 0x0008, 0x383f: 0x0008, + // Block 0xe1, offset 0x3840 + 0x384c: 0x0008, 0x384d: 0x0008, 0x384e: 0x0008, 0x384f: 0x0008, + // Block 0xe2, offset 0x3880 + 0x3888: 0x0008, 0x3889: 0x0008, 0x388a: 0x0008, 0x388b: 0x0008, + 0x388c: 0x0008, 0x388d: 0x0008, 0x388e: 0x0008, 0x388f: 0x0008, + 0x389a: 0x0008, 0x389b: 0x0008, 0x389c: 0x0008, 0x389d: 0x0008, + 0x389e: 0x0008, 0x389f: 0x0008, + // Block 0xe3, offset 0x38c0 + 0x38c8: 0x0008, 0x38c9: 0x0008, 0x38ca: 0x0008, 0x38cb: 0x0008, + 0x38cc: 0x0008, 0x38cd: 0x0008, 0x38ce: 0x0008, 0x38cf: 0x0008, + 0x38ee: 0x0008, 0x38ef: 0x0008, + 0x38fc: 0x0008, 0x38fd: 0x0008, 0x38fe: 0x0008, 0x38ff: 0x0008, + // Block 0xe4, offset 0x3900 + 0x3902: 0x0008, 0x3903: 0x0008, 0x3904: 0x0008, 0x3905: 0x0008, + 0x3906: 0x0008, 0x3907: 0x0008, 0x3908: 0x0008, 0x3909: 0x0008, 0x390a: 0x0008, 0x390b: 0x0008, + 0x390c: 0x0008, 0x390d: 0x0008, 0x390e: 0x0008, 0x390f: 0x0008, + 0x3919: 0x0008, 0x391a: 0x0008, 0x391b: 0x0008, 0x391c: 0x0008, 0x391d: 0x0008, + 0x391e: 0x0008, 0x391f: 0x0008, 0x3920: 0x0008, 0x3921: 0x0008, 0x3922: 0x0008, 0x3923: 0x0008, + 0x3924: 0x0008, 0x3925: 0x0008, 0x3926: 0x0008, 0x3927: 0x0008, 0x3928: 0x0008, 0x3929: 0x0008, + 0x392a: 0x0008, 0x392b: 0x0008, 0x392c: 0x0008, 0x392d: 0x0008, 0x392e: 0x0008, 0x392f: 0x0008, + 0x3930: 0x0008, 0x3931: 0x0008, 0x3932: 0x0008, 0x3933: 0x0008, 0x3934: 0x0008, 0x3935: 0x0008, + 0x3936: 0x0008, 0x3937: 0x0008, 0x3938: 0x0008, 0x3939: 0x0008, 0x393a: 0x0008, 0x393b: 0x0008, + 0x393c: 0x0008, 0x393d: 0x0008, 0x393e: 0x0008, 0x393f: 0x0008, + // Block 0xe5, offset 0x3940 + 0x394c: 0x0008, 0x394d: 0x0008, 0x394e: 0x0008, 0x394f: 0x0008, 0x3950: 0x0008, 0x3951: 0x0008, + 0x3952: 0x0008, 0x3953: 0x0008, 0x3954: 0x0008, 0x3955: 0x0008, 0x3956: 0x0008, 0x3957: 0x0008, + 0x3958: 0x0008, 0x3959: 0x0008, 0x395a: 0x0008, 0x395b: 0x0008, 0x395c: 0x0008, 0x395d: 0x0008, + 0x395e: 0x0008, 0x395f: 0x0008, 0x3960: 0x0008, 0x3961: 0x0008, 0x3962: 0x0008, 0x3963: 0x0008, + 0x3964: 0x0008, 0x3965: 0x0008, 0x3966: 0x0008, 0x3967: 0x0008, 0x3968: 0x0008, 0x3969: 0x0008, + 0x396a: 0x0008, 0x396b: 0x0008, 0x396c: 0x0008, 0x396d: 0x0008, 0x396e: 0x0008, 0x396f: 0x0008, + 0x3970: 0x0008, 0x3971: 0x0008, 0x3972: 0x0008, 0x3973: 0x0008, 0x3974: 0x0008, 0x3975: 0x0008, + 0x3976: 0x0008, 0x3977: 0x0008, 0x3978: 0x0008, 0x3979: 0x0008, 0x397a: 0x0008, + 0x397c: 0x0008, 0x397d: 0x0008, 0x397e: 0x0008, 0x397f: 0x0008, + // Block 0xe6, offset 0x3980 + 0x3980: 0x0008, 0x3981: 0x0008, 0x3982: 0x0008, 0x3983: 0x0008, 0x3984: 0x0008, 0x3985: 0x0008, + 0x3987: 0x0008, 0x3988: 0x0008, 0x3989: 0x0008, 0x398a: 0x0008, 0x398b: 0x0008, + 0x398c: 0x0008, 0x398d: 0x0008, 0x398e: 0x0008, 0x398f: 0x0008, 0x3990: 0x0008, 0x3991: 0x0008, + 0x3992: 0x0008, 0x3993: 0x0008, 0x3994: 0x0008, 0x3995: 0x0008, 0x3996: 0x0008, 0x3997: 0x0008, + 0x3998: 0x0008, 0x3999: 0x0008, 0x399a: 0x0008, 0x399b: 0x0008, 0x399c: 0x0008, 0x399d: 0x0008, + 0x399e: 0x0008, 0x399f: 0x0008, 0x39a0: 0x0008, 0x39a1: 0x0008, 0x39a2: 0x0008, 0x39a3: 0x0008, + 0x39a4: 0x0008, 0x39a5: 0x0008, 0x39a6: 0x0008, 0x39a7: 0x0008, 0x39a8: 0x0008, 0x39a9: 0x0008, + 0x39aa: 0x0008, 0x39ab: 0x0008, 0x39ac: 0x0008, 0x39ad: 0x0008, 0x39ae: 0x0008, 0x39af: 0x0008, + 0x39b0: 0x0008, 0x39b1: 0x0008, 0x39b2: 0x0008, 0x39b3: 0x0008, 0x39b4: 0x0008, 0x39b5: 0x0008, + 0x39b6: 0x0008, 0x39b7: 0x0008, 0x39b8: 0x0008, 0x39b9: 0x0008, 0x39ba: 0x0008, 0x39bb: 0x0008, + 0x39bc: 0x0008, 0x39bd: 0x0008, 0x39be: 0x0008, 0x39bf: 0x0008, + // Block 0xe7, offset 0x39c0 + 0x39d8: 0x0008, 0x39d9: 0x0008, 0x39da: 0x0008, 0x39db: 0x0008, 0x39dc: 0x0008, 0x39dd: 0x0008, + 0x39de: 0x0008, 0x39df: 0x0008, + 0x39ee: 0x0008, 0x39ef: 0x0008, + 0x39f0: 0x0008, 0x39f1: 0x0008, 0x39f2: 0x0008, 0x39f3: 0x0008, 0x39f4: 0x0008, 0x39f5: 0x0008, + 0x39f6: 0x0008, 0x39f7: 0x0008, 0x39f8: 0x0008, 0x39f9: 0x0008, 0x39fa: 0x0008, 0x39fb: 0x0008, + 0x39fc: 0x0008, 0x39fd: 0x0008, 0x39fe: 0x0008, 0x39ff: 0x0008, + // Block 0xe8, offset 0x3a00 + 0x3a00: 0x0002, 0x3a01: 0x0002, 0x3a02: 0x0002, 0x3a03: 0x0002, 0x3a04: 0x0002, 0x3a05: 0x0002, + 0x3a06: 0x0002, 0x3a07: 0x0002, 0x3a08: 0x0002, 0x3a09: 0x0002, 0x3a0a: 0x0002, 0x3a0b: 0x0002, + 0x3a0c: 0x0002, 0x3a0d: 0x0002, 0x3a0e: 0x0002, 0x3a0f: 0x0002, 0x3a10: 0x0002, 0x3a11: 0x0002, + 0x3a12: 0x0002, 0x3a13: 0x0002, 0x3a14: 0x0002, 0x3a15: 0x0002, 0x3a16: 0x0002, 0x3a17: 0x0002, + 0x3a18: 0x0002, 0x3a19: 0x0002, 0x3a1a: 0x0002, 0x3a1b: 0x0002, 0x3a1c: 0x0002, 0x3a1d: 0x0002, + 0x3a1e: 0x0002, 0x3a1f: 0x0002, 0x3a20: 0x0024, 0x3a21: 0x0024, 0x3a22: 0x0024, 0x3a23: 0x0024, + 0x3a24: 0x0024, 0x3a25: 0x0024, 0x3a26: 0x0024, 0x3a27: 0x0024, 0x3a28: 0x0024, 0x3a29: 0x0024, + 0x3a2a: 0x0024, 0x3a2b: 0x0024, 0x3a2c: 0x0024, 0x3a2d: 0x0024, 0x3a2e: 0x0024, 0x3a2f: 0x0024, + 0x3a30: 0x0024, 0x3a31: 0x0024, 0x3a32: 0x0024, 0x3a33: 0x0024, 0x3a34: 0x0024, 0x3a35: 0x0024, + 0x3a36: 0x0024, 0x3a37: 0x0024, 0x3a38: 0x0024, 0x3a39: 0x0024, 0x3a3a: 0x0024, 0x3a3b: 0x0024, + 0x3a3c: 0x0024, 0x3a3d: 0x0024, 0x3a3e: 0x0024, 0x3a3f: 0x0024, + // Block 0xe9, offset 0x3a40 + 0x3a40: 0x0002, 0x3a41: 0x0002, 0x3a42: 0x0002, 0x3a43: 0x0002, 0x3a44: 0x0002, 0x3a45: 0x0002, + 0x3a46: 0x0002, 0x3a47: 0x0002, 0x3a48: 0x0002, 0x3a49: 0x0002, 0x3a4a: 0x0002, 0x3a4b: 0x0002, + 0x3a4c: 0x0002, 0x3a4d: 0x0002, 0x3a4e: 0x0002, 0x3a4f: 0x0002, 0x3a50: 0x0002, 0x3a51: 0x0002, + 0x3a52: 0x0002, 0x3a53: 0x0002, 0x3a54: 0x0002, 0x3a55: 0x0002, 0x3a56: 0x0002, 0x3a57: 0x0002, + 0x3a58: 0x0002, 0x3a59: 0x0002, 0x3a5a: 0x0002, 0x3a5b: 0x0002, 0x3a5c: 0x0002, 0x3a5d: 0x0002, + 0x3a5e: 0x0002, 0x3a5f: 0x0002, 0x3a60: 0x0002, 0x3a61: 0x0002, 0x3a62: 0x0002, 0x3a63: 0x0002, + 0x3a64: 0x0002, 0x3a65: 0x0002, 0x3a66: 0x0002, 0x3a67: 0x0002, 0x3a68: 0x0002, 0x3a69: 0x0002, + 0x3a6a: 0x0002, 0x3a6b: 0x0002, 0x3a6c: 0x0002, 0x3a6d: 0x0002, 0x3a6e: 0x0002, 0x3a6f: 0x0002, + 0x3a70: 0x0002, 0x3a71: 0x0002, 0x3a72: 0x0002, 0x3a73: 0x0002, 0x3a74: 0x0002, 0x3a75: 0x0002, + 0x3a76: 0x0002, 0x3a77: 0x0002, 0x3a78: 0x0002, 0x3a79: 0x0002, 0x3a7a: 0x0002, 0x3a7b: 0x0002, + 0x3a7c: 0x0002, 0x3a7d: 0x0002, 0x3a7e: 0x0002, 0x3a7f: 0x0002, + // Block 0xea, offset 0x3a80 + 0x3a80: 0x0024, 0x3a81: 0x0024, 0x3a82: 0x0024, 0x3a83: 0x0024, 0x3a84: 0x0024, 0x3a85: 0x0024, + 0x3a86: 0x0024, 0x3a87: 0x0024, 0x3a88: 0x0024, 0x3a89: 0x0024, 0x3a8a: 0x0024, 0x3a8b: 0x0024, + 0x3a8c: 0x0024, 0x3a8d: 0x0024, 0x3a8e: 0x0024, 0x3a8f: 0x0024, 0x3a90: 0x0024, 0x3a91: 0x0024, + 0x3a92: 0x0024, 0x3a93: 0x0024, 0x3a94: 0x0024, 0x3a95: 0x0024, 0x3a96: 0x0024, 0x3a97: 0x0024, + 0x3a98: 0x0024, 0x3a99: 0x0024, 0x3a9a: 0x0024, 0x3a9b: 0x0024, 0x3a9c: 0x0024, 0x3a9d: 0x0024, + 0x3a9e: 0x0024, 0x3a9f: 0x0024, 0x3aa0: 0x0024, 0x3aa1: 0x0024, 0x3aa2: 0x0024, 0x3aa3: 0x0024, + 0x3aa4: 0x0024, 0x3aa5: 0x0024, 0x3aa6: 0x0024, 0x3aa7: 0x0024, 0x3aa8: 0x0024, 0x3aa9: 0x0024, + 0x3aaa: 0x0024, 0x3aab: 0x0024, 0x3aac: 0x0024, 0x3aad: 0x0024, 0x3aae: 0x0024, 0x3aaf: 0x0024, + 0x3ab0: 0x0002, 0x3ab1: 0x0002, 0x3ab2: 0x0002, 0x3ab3: 0x0002, 0x3ab4: 0x0002, 0x3ab5: 0x0002, + 0x3ab6: 0x0002, 0x3ab7: 0x0002, 0x3ab8: 0x0002, 0x3ab9: 0x0002, 0x3aba: 0x0002, 0x3abb: 0x0002, + 0x3abc: 0x0002, 0x3abd: 0x0002, 0x3abe: 0x0002, 0x3abf: 0x0002, +} + +// graphemesIndex: 25 blocks, 1600 entries, 1600 bytes +// Block 0 is the zero block. +var graphemesIndex = [1600]property{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, + 0xcc: 0x02, 0xcd: 0x03, + 0xd2: 0x04, 0xd6: 0x05, 0xd7: 0x06, + 0xd8: 0x07, 0xd9: 0x08, 0xdb: 0x09, 0xdc: 0x0a, 0xdd: 0x0b, 0xde: 0x0c, 0xdf: 0x0d, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x14, 0xf3: 0x16, + // Block 0x4, offset 0x100 + 0x120: 0x0e, 0x121: 0x0f, 0x122: 0x10, 0x123: 0x11, 0x124: 0x12, 0x125: 0x13, 0x126: 0x14, 0x127: 0x15, + 0x128: 0x16, 0x129: 0x17, 0x12a: 0x18, 0x12b: 0x19, 0x12c: 0x1a, 0x12d: 0x1b, 0x12e: 0x1c, 0x12f: 0x1d, + 0x130: 0x1e, 0x131: 0x1f, 0x132: 0x20, 0x133: 0x21, 0x134: 0x22, 0x135: 0x23, 0x136: 0x24, 0x137: 0x25, + 0x138: 0x26, 0x139: 0x27, 0x13a: 0x28, 0x13b: 0x29, 0x13c: 0x2a, 0x13d: 0x2b, 0x13e: 0x2c, 0x13f: 0x2d, + // Block 0x5, offset 0x140 + 0x140: 0x2e, 0x141: 0x2f, 0x142: 0x30, 0x144: 0x31, 0x145: 0x32, 0x146: 0x33, 0x147: 0x34, + 0x14d: 0x35, + 0x15c: 0x36, 0x15d: 0x37, 0x15e: 0x38, 0x15f: 0x39, + 0x160: 0x3a, 0x162: 0x3b, 0x164: 0x3c, + 0x168: 0x3d, 0x169: 0x3e, 0x16a: 0x3f, 0x16b: 0x40, 0x16c: 0x41, 0x16d: 0x42, 0x16e: 0x43, 0x16f: 0x44, + 0x170: 0x45, 0x173: 0x46, 0x177: 0x02, + // Block 0x6, offset 0x180 + 0x180: 0x47, 0x181: 0x48, 0x183: 0x49, 0x184: 0x4a, 0x186: 0x4b, + 0x18c: 0x4c, 0x18f: 0x4d, + 0x193: 0x4e, 0x196: 0x4f, 0x197: 0x50, + 0x198: 0x51, 0x199: 0x52, 0x19a: 0x53, 0x19b: 0x54, 0x19c: 0x55, 0x19d: 0x56, 0x19e: 0x57, + 0x1a4: 0x58, + 0x1ac: 0x59, 0x1ad: 0x5a, + 0x1b3: 0x5b, 0x1b5: 0x5c, 0x1b7: 0x5d, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x5e, 0x1c2: 0x5f, + 0x1ca: 0x60, + // Block 0x8, offset 0x200 + 0x219: 0x61, 0x21a: 0x62, 0x21b: 0x63, + 0x220: 0x64, 0x222: 0x65, 0x223: 0x66, 0x224: 0x67, 0x225: 0x68, 0x226: 0x69, 0x227: 0x6a, + 0x228: 0x6b, 0x229: 0x6c, 0x22a: 0x6d, 0x22b: 0x6e, 0x22f: 0x6f, + 0x230: 0x70, 0x231: 0x71, 0x232: 0x72, 0x233: 0x73, 0x234: 0x74, 0x235: 0x75, 0x236: 0x76, 0x237: 0x70, + 0x238: 0x71, 0x239: 0x72, 0x23a: 0x73, 0x23b: 0x74, 0x23c: 0x75, 0x23d: 0x76, 0x23e: 0x70, 0x23f: 0x71, + // Block 0x9, offset 0x240 + 0x240: 0x72, 0x241: 0x73, 0x242: 0x74, 0x243: 0x75, 0x244: 0x76, 0x245: 0x70, 0x246: 0x71, 0x247: 0x72, + 0x248: 0x73, 0x249: 0x74, 0x24a: 0x75, 0x24b: 0x76, 0x24c: 0x70, 0x24d: 0x71, 0x24e: 0x72, 0x24f: 0x73, + 0x250: 0x74, 0x251: 0x75, 0x252: 0x76, 0x253: 0x70, 0x254: 0x71, 0x255: 0x72, 0x256: 0x73, 0x257: 0x74, + 0x258: 0x75, 0x259: 0x76, 0x25a: 0x70, 0x25b: 0x71, 0x25c: 0x72, 0x25d: 0x73, 0x25e: 0x74, 0x25f: 0x75, + 0x260: 0x76, 0x261: 0x70, 0x262: 0x71, 0x263: 0x72, 0x264: 0x73, 0x265: 0x74, 0x266: 0x75, 0x267: 0x76, + 0x268: 0x70, 0x269: 0x71, 0x26a: 0x72, 0x26b: 0x73, 0x26c: 0x74, 0x26d: 0x75, 0x26e: 0x76, 0x26f: 0x70, + 0x270: 0x71, 0x271: 0x72, 0x272: 0x73, 0x273: 0x74, 0x274: 0x75, 0x275: 0x76, 0x276: 0x70, 0x277: 0x71, + 0x278: 0x72, 0x279: 0x73, 0x27a: 0x74, 0x27b: 0x75, 0x27c: 0x76, 0x27d: 0x70, 0x27e: 0x71, 0x27f: 0x72, + // Block 0xa, offset 0x280 + 0x280: 0x73, 0x281: 0x74, 0x282: 0x75, 0x283: 0x76, 0x284: 0x70, 0x285: 0x71, 0x286: 0x72, 0x287: 0x73, + 0x288: 0x74, 0x289: 0x75, 0x28a: 0x76, 0x28b: 0x70, 0x28c: 0x71, 0x28d: 0x72, 0x28e: 0x73, 0x28f: 0x74, + 0x290: 0x75, 0x291: 0x76, 0x292: 0x70, 0x293: 0x71, 0x294: 0x72, 0x295: 0x73, 0x296: 0x74, 0x297: 0x75, + 0x298: 0x76, 0x299: 0x70, 0x29a: 0x71, 0x29b: 0x72, 0x29c: 0x73, 0x29d: 0x74, 0x29e: 0x75, 0x29f: 0x76, + 0x2a0: 0x70, 0x2a1: 0x71, 0x2a2: 0x72, 0x2a3: 0x73, 0x2a4: 0x74, 0x2a5: 0x75, 0x2a6: 0x76, 0x2a7: 0x70, + 0x2a8: 0x71, 0x2a9: 0x72, 0x2aa: 0x73, 0x2ab: 0x74, 0x2ac: 0x75, 0x2ad: 0x76, 0x2ae: 0x70, 0x2af: 0x71, + 0x2b0: 0x72, 0x2b1: 0x73, 0x2b2: 0x74, 0x2b3: 0x75, 0x2b4: 0x76, 0x2b5: 0x70, 0x2b6: 0x71, 0x2b7: 0x72, + 0x2b8: 0x73, 0x2b9: 0x74, 0x2ba: 0x75, 0x2bb: 0x76, 0x2bc: 0x70, 0x2bd: 0x71, 0x2be: 0x72, 0x2bf: 0x73, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x74, 0x2c1: 0x75, 0x2c2: 0x76, 0x2c3: 0x70, 0x2c4: 0x71, 0x2c5: 0x72, 0x2c6: 0x73, 0x2c7: 0x74, + 0x2c8: 0x75, 0x2c9: 0x76, 0x2ca: 0x70, 0x2cb: 0x71, 0x2cc: 0x72, 0x2cd: 0x73, 0x2ce: 0x74, 0x2cf: 0x75, + 0x2d0: 0x76, 0x2d1: 0x70, 0x2d2: 0x71, 0x2d3: 0x72, 0x2d4: 0x73, 0x2d5: 0x74, 0x2d6: 0x75, 0x2d7: 0x76, + 0x2d8: 0x70, 0x2d9: 0x71, 0x2da: 0x72, 0x2db: 0x73, 0x2dc: 0x74, 0x2dd: 0x75, 0x2de: 0x77, 0x2df: 0x78, + // Block 0xc, offset 0x300 + 0x32c: 0x79, + 0x338: 0x7a, 0x33b: 0x7b, 0x33e: 0x62, 0x33f: 0x7c, + // Block 0xd, offset 0x340 + 0x347: 0x7d, + 0x34b: 0x7e, 0x34d: 0x7f, + 0x368: 0x80, 0x36b: 0x81, + 0x374: 0x82, 0x375: 0x83, + 0x37a: 0x84, 0x37b: 0x85, 0x37d: 0x86, 0x37e: 0x87, + // Block 0xe, offset 0x380 + 0x380: 0x88, 0x381: 0x89, 0x382: 0x8a, 0x383: 0x8b, 0x384: 0x8c, 0x385: 0x8d, 0x386: 0x8e, 0x387: 0x8f, + 0x388: 0x90, 0x389: 0x91, 0x38b: 0x92, 0x38c: 0x93, 0x38d: 0x94, 0x38e: 0x95, 0x38f: 0x96, + 0x390: 0x97, 0x391: 0x98, 0x392: 0x99, 0x393: 0x9a, 0x396: 0x9b, 0x397: 0x9c, + 0x398: 0x9d, 0x399: 0x9e, 0x39a: 0x9f, 0x39c: 0xa0, + 0x3a0: 0xa1, 0x3a4: 0xa2, 0x3a5: 0xa3, 0x3a7: 0xa4, + 0x3a8: 0xa5, 0x3a9: 0xa6, 0x3aa: 0xa7, 0x3ad: 0xa8, + 0x3b0: 0xa9, 0x3b2: 0xaa, 0x3b4: 0xab, 0x3b5: 0xac, 0x3b6: 0xad, + 0x3bb: 0xae, 0x3bc: 0xaf, 0x3bd: 0xb0, + // Block 0xf, offset 0x3c0 + 0x3d0: 0xb1, 0x3d1: 0xb2, + // Block 0x10, offset 0x400 + 0x404: 0xb3, + 0x42b: 0xb4, 0x42c: 0xb5, + 0x435: 0xb6, + 0x43d: 0xb7, 0x43e: 0xb8, 0x43f: 0xb9, + // Block 0x11, offset 0x440 + 0x472: 0xba, + // Block 0x12, offset 0x480 + 0x4bc: 0xbb, 0x4bd: 0xbc, + // Block 0x13, offset 0x4c0 + 0x4c5: 0xbd, 0x4c6: 0xbe, + 0x4c9: 0xbf, + 0x4e8: 0xc0, 0x4e9: 0xc1, 0x4ea: 0xc2, + // Block 0x14, offset 0x500 + 0x500: 0xc3, 0x502: 0xc4, 0x504: 0xb5, + 0x50a: 0xc5, 0x50b: 0xc6, + 0x513: 0xc6, 0x517: 0xc7, + 0x51b: 0xc8, + 0x523: 0xc9, 0x525: 0xca, + // Block 0x15, offset 0x540 + 0x540: 0xcb, 0x542: 0xcc, 0x543: 0xcd, 0x545: 0xce, 0x546: 0xcf, 0x547: 0xd0, + 0x548: 0xd1, 0x549: 0xd2, 0x54a: 0xd3, 0x54b: 0xd3, 0x54c: 0xd4, 0x54d: 0xd3, 0x54e: 0xd5, 0x54f: 0xd6, + 0x550: 0xd3, 0x551: 0xd3, 0x552: 0xd3, 0x553: 0xd7, 0x554: 0xd8, 0x555: 0xd9, 0x556: 0xda, 0x557: 0xdb, + 0x558: 0xd3, 0x559: 0xdc, 0x55a: 0xd3, 0x55b: 0xdd, 0x55f: 0xde, + 0x560: 0xdf, 0x561: 0xe0, 0x562: 0xe1, 0x563: 0xe2, 0x564: 0xe3, 0x565: 0xe4, 0x566: 0xd3, 0x567: 0xd3, + 0x569: 0xe5, 0x56a: 0xd3, 0x56b: 0xd3, + 0x570: 0xd3, 0x571: 0xd3, 0x572: 0xd3, 0x573: 0xd3, 0x574: 0xd3, 0x575: 0xd3, 0x576: 0xd3, 0x577: 0xd3, + 0x578: 0xd3, 0x579: 0xd3, 0x57a: 0xd3, 0x57b: 0xd3, 0x57c: 0xd3, 0x57d: 0xd3, 0x57e: 0xd3, 0x57f: 0xd8, + // Block 0x16, offset 0x580 + 0x590: 0x0b, 0x591: 0x0c, 0x593: 0x0d, 0x596: 0x0e, + 0x59b: 0x0f, 0x59c: 0x10, 0x59d: 0x11, 0x59e: 0x12, 0x59f: 0x13, + // Block 0x17, offset 0x5c0 + 0x5c0: 0xe6, 0x5c1: 0x02, 0x5c2: 0xe7, 0x5c3: 0xe7, 0x5c4: 0x02, 0x5c5: 0x02, 0x5c6: 0x02, 0x5c7: 0xe8, + 0x5c8: 0xe7, 0x5c9: 0xe7, 0x5ca: 0xe7, 0x5cb: 0xe7, 0x5cc: 0xe7, 0x5cd: 0xe7, 0x5ce: 0xe7, 0x5cf: 0xe7, + 0x5d0: 0xe7, 0x5d1: 0xe7, 0x5d2: 0xe7, 0x5d3: 0xe7, 0x5d4: 0xe7, 0x5d5: 0xe7, 0x5d6: 0xe7, 0x5d7: 0xe7, + 0x5d8: 0xe7, 0x5d9: 0xe7, 0x5da: 0xe7, 0x5db: 0xe7, 0x5dc: 0xe7, 0x5dd: 0xe7, 0x5de: 0xe7, 0x5df: 0xe7, + 0x5e0: 0xe7, 0x5e1: 0xe7, 0x5e2: 0xe7, 0x5e3: 0xe7, 0x5e4: 0xe7, 0x5e5: 0xe7, 0x5e6: 0xe7, 0x5e7: 0xe7, + 0x5e8: 0xe7, 0x5e9: 0xe7, 0x5ea: 0xe7, 0x5eb: 0xe7, 0x5ec: 0xe7, 0x5ed: 0xe7, 0x5ee: 0xe7, 0x5ef: 0xe7, + 0x5f0: 0xe7, 0x5f1: 0xe7, 0x5f2: 0xe7, 0x5f3: 0xe7, 0x5f4: 0xe7, 0x5f5: 0xe7, 0x5f6: 0xe7, 0x5f7: 0xe7, + 0x5f8: 0xe7, 0x5f9: 0xe7, 0x5fa: 0xe7, 0x5fb: 0xe7, 0x5fc: 0xe7, 0x5fd: 0xe7, 0x5fe: 0xe7, 0x5ff: 0xe7, + // Block 0x18, offset 0x600 + 0x620: 0x15, +} diff --git a/vendor/github.com/gdamore/tcell/v2/color.go b/vendor/github.com/gdamore/tcell/v2/color.go deleted file mode 100644 index 904848eaa..000000000 --- a/vendor/github.com/gdamore/tcell/v2/color.go +++ /dev/null @@ -1,1128 +0,0 @@ -// Copyright 2023 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 tcell - -import ( - "fmt" - ic "image/color" - "strconv" -) - -// Color represents a color. The low numeric values are the same as used -// by ECMA-48, and beyond that XTerm. A 24-bit RGB value may be used by -// adding in the ColorIsRGB flag. For Color names we use the W3C approved -// color names. -// -// We use a 64-bit integer to allow future expansion if we want to add an -// 8-bit alpha, while still leaving us some room for extra options. -// -// Note that on various terminals colors may be approximated however, or -// not supported at all. If no suitable representation for a color is known, -// the library will simply not set any color, deferring to whatever default -// attributes the terminal uses. -type Color uint64 - -const ( - // ColorDefault is used to leave the Color unchanged from whatever - // system or terminal default may exist. It's also the zero value. - ColorDefault Color = 0 - - // ColorValid is used to indicate the color value is actually - // valid (initialized). This is useful to permit the zero value - // to be treated as the default. - ColorValid Color = 1 << 32 - - // ColorIsRGB is used to indicate that the numeric value is not - // a known color constant, but rather an RGB value. The lower - // order 3 bytes are RGB. - ColorIsRGB Color = 1 << 33 - - // ColorSpecial is a flag used to indicate that the values have - // special meaning, and live outside of the color space(s). - ColorSpecial Color = 1 << 34 -) - -// Note that the order of these options is important -- it follows the -// definitions used by ECMA and XTerm. Hence any further named colors -// must begin at a value not less than 256. -const ( - ColorBlack = ColorValid + iota - ColorMaroon - ColorGreen - ColorOlive - ColorNavy - ColorPurple - ColorTeal - ColorSilver - ColorGray - ColorRed - ColorLime - ColorYellow - ColorBlue - ColorFuchsia - ColorAqua - ColorWhite - Color16 - Color17 - Color18 - Color19 - Color20 - Color21 - Color22 - Color23 - Color24 - Color25 - Color26 - Color27 - Color28 - Color29 - Color30 - Color31 - Color32 - Color33 - Color34 - Color35 - Color36 - Color37 - Color38 - Color39 - Color40 - Color41 - Color42 - Color43 - Color44 - Color45 - Color46 - Color47 - Color48 - Color49 - Color50 - Color51 - Color52 - Color53 - Color54 - Color55 - Color56 - Color57 - Color58 - Color59 - Color60 - Color61 - Color62 - Color63 - Color64 - Color65 - Color66 - Color67 - Color68 - Color69 - Color70 - Color71 - Color72 - Color73 - Color74 - Color75 - Color76 - Color77 - Color78 - Color79 - Color80 - Color81 - Color82 - Color83 - Color84 - Color85 - Color86 - Color87 - Color88 - Color89 - Color90 - Color91 - Color92 - Color93 - Color94 - Color95 - Color96 - Color97 - Color98 - Color99 - Color100 - Color101 - Color102 - Color103 - Color104 - Color105 - Color106 - Color107 - Color108 - Color109 - Color110 - Color111 - Color112 - Color113 - Color114 - Color115 - Color116 - Color117 - Color118 - Color119 - Color120 - Color121 - Color122 - Color123 - Color124 - Color125 - Color126 - Color127 - Color128 - Color129 - Color130 - Color131 - Color132 - Color133 - Color134 - Color135 - Color136 - Color137 - Color138 - Color139 - Color140 - Color141 - Color142 - Color143 - Color144 - Color145 - Color146 - Color147 - Color148 - Color149 - Color150 - Color151 - Color152 - Color153 - Color154 - Color155 - Color156 - Color157 - Color158 - Color159 - Color160 - Color161 - Color162 - Color163 - Color164 - Color165 - Color166 - Color167 - Color168 - Color169 - Color170 - Color171 - Color172 - Color173 - Color174 - Color175 - Color176 - Color177 - Color178 - Color179 - Color180 - Color181 - Color182 - Color183 - Color184 - Color185 - Color186 - Color187 - Color188 - Color189 - Color190 - Color191 - Color192 - Color193 - Color194 - Color195 - Color196 - Color197 - Color198 - Color199 - Color200 - Color201 - Color202 - Color203 - Color204 - Color205 - Color206 - Color207 - Color208 - Color209 - Color210 - Color211 - Color212 - Color213 - Color214 - Color215 - Color216 - Color217 - Color218 - Color219 - Color220 - Color221 - Color222 - Color223 - Color224 - Color225 - Color226 - Color227 - Color228 - Color229 - Color230 - Color231 - Color232 - Color233 - Color234 - Color235 - Color236 - Color237 - Color238 - Color239 - Color240 - Color241 - Color242 - Color243 - Color244 - Color245 - Color246 - Color247 - Color248 - Color249 - Color250 - Color251 - Color252 - Color253 - Color254 - Color255 - ColorAliceBlue = ColorIsRGB | ColorValid | 0xF0F8FF - ColorAntiqueWhite = ColorIsRGB | ColorValid | 0xFAEBD7 - ColorAquaMarine = ColorIsRGB | ColorValid | 0x7FFFD4 - ColorAzure = ColorIsRGB | ColorValid | 0xF0FFFF - ColorBeige = ColorIsRGB | ColorValid | 0xF5F5DC - ColorBisque = ColorIsRGB | ColorValid | 0xFFE4C4 - ColorBlanchedAlmond = ColorIsRGB | ColorValid | 0xFFEBCD - ColorBlueViolet = ColorIsRGB | ColorValid | 0x8A2BE2 - ColorBrown = ColorIsRGB | ColorValid | 0xA52A2A - ColorBurlyWood = ColorIsRGB | ColorValid | 0xDEB887 - ColorCadetBlue = ColorIsRGB | ColorValid | 0x5F9EA0 - ColorChartreuse = ColorIsRGB | ColorValid | 0x7FFF00 - ColorChocolate = ColorIsRGB | ColorValid | 0xD2691E - ColorCoral = ColorIsRGB | ColorValid | 0xFF7F50 - ColorCornflowerBlue = ColorIsRGB | ColorValid | 0x6495ED - ColorCornsilk = ColorIsRGB | ColorValid | 0xFFF8DC - ColorCrimson = ColorIsRGB | ColorValid | 0xDC143C - ColorDarkBlue = ColorIsRGB | ColorValid | 0x00008B - ColorDarkCyan = ColorIsRGB | ColorValid | 0x008B8B - ColorDarkGoldenrod = ColorIsRGB | ColorValid | 0xB8860B - ColorDarkGray = ColorIsRGB | ColorValid | 0xA9A9A9 - ColorDarkGreen = ColorIsRGB | ColorValid | 0x006400 - ColorDarkKhaki = ColorIsRGB | ColorValid | 0xBDB76B - ColorDarkMagenta = ColorIsRGB | ColorValid | 0x8B008B - ColorDarkOliveGreen = ColorIsRGB | ColorValid | 0x556B2F - ColorDarkOrange = ColorIsRGB | ColorValid | 0xFF8C00 - ColorDarkOrchid = ColorIsRGB | ColorValid | 0x9932CC - ColorDarkRed = ColorIsRGB | ColorValid | 0x8B0000 - ColorDarkSalmon = ColorIsRGB | ColorValid | 0xE9967A - ColorDarkSeaGreen = ColorIsRGB | ColorValid | 0x8FBC8F - ColorDarkSlateBlue = ColorIsRGB | ColorValid | 0x483D8B - ColorDarkSlateGray = ColorIsRGB | ColorValid | 0x2F4F4F - ColorDarkTurquoise = ColorIsRGB | ColorValid | 0x00CED1 - ColorDarkViolet = ColorIsRGB | ColorValid | 0x9400D3 - ColorDeepPink = ColorIsRGB | ColorValid | 0xFF1493 - ColorDeepSkyBlue = ColorIsRGB | ColorValid | 0x00BFFF - ColorDimGray = ColorIsRGB | ColorValid | 0x696969 - ColorDodgerBlue = ColorIsRGB | ColorValid | 0x1E90FF - ColorFireBrick = ColorIsRGB | ColorValid | 0xB22222 - ColorFloralWhite = ColorIsRGB | ColorValid | 0xFFFAF0 - ColorForestGreen = ColorIsRGB | ColorValid | 0x228B22 - ColorGainsboro = ColorIsRGB | ColorValid | 0xDCDCDC - ColorGhostWhite = ColorIsRGB | ColorValid | 0xF8F8FF - ColorGold = ColorIsRGB | ColorValid | 0xFFD700 - ColorGoldenrod = ColorIsRGB | ColorValid | 0xDAA520 - ColorGreenYellow = ColorIsRGB | ColorValid | 0xADFF2F - ColorHoneydew = ColorIsRGB | ColorValid | 0xF0FFF0 - ColorHotPink = ColorIsRGB | ColorValid | 0xFF69B4 - ColorIndianRed = ColorIsRGB | ColorValid | 0xCD5C5C - ColorIndigo = ColorIsRGB | ColorValid | 0x4B0082 - ColorIvory = ColorIsRGB | ColorValid | 0xFFFFF0 - ColorKhaki = ColorIsRGB | ColorValid | 0xF0E68C - ColorLavender = ColorIsRGB | ColorValid | 0xE6E6FA - ColorLavenderBlush = ColorIsRGB | ColorValid | 0xFFF0F5 - ColorLawnGreen = ColorIsRGB | ColorValid | 0x7CFC00 - ColorLemonChiffon = ColorIsRGB | ColorValid | 0xFFFACD - ColorLightBlue = ColorIsRGB | ColorValid | 0xADD8E6 - ColorLightCoral = ColorIsRGB | ColorValid | 0xF08080 - ColorLightCyan = ColorIsRGB | ColorValid | 0xE0FFFF - ColorLightGoldenrodYellow = ColorIsRGB | ColorValid | 0xFAFAD2 - ColorLightGray = ColorIsRGB | ColorValid | 0xD3D3D3 - ColorLightGreen = ColorIsRGB | ColorValid | 0x90EE90 - ColorLightPink = ColorIsRGB | ColorValid | 0xFFB6C1 - ColorLightSalmon = ColorIsRGB | ColorValid | 0xFFA07A - ColorLightSeaGreen = ColorIsRGB | ColorValid | 0x20B2AA - ColorLightSkyBlue = ColorIsRGB | ColorValid | 0x87CEFA - ColorLightSlateGray = ColorIsRGB | ColorValid | 0x778899 - ColorLightSteelBlue = ColorIsRGB | ColorValid | 0xB0C4DE - ColorLightYellow = ColorIsRGB | ColorValid | 0xFFFFE0 - ColorLimeGreen = ColorIsRGB | ColorValid | 0x32CD32 - ColorLinen = ColorIsRGB | ColorValid | 0xFAF0E6 - ColorMediumAquamarine = ColorIsRGB | ColorValid | 0x66CDAA - ColorMediumBlue = ColorIsRGB | ColorValid | 0x0000CD - ColorMediumOrchid = ColorIsRGB | ColorValid | 0xBA55D3 - ColorMediumPurple = ColorIsRGB | ColorValid | 0x9370DB - ColorMediumSeaGreen = ColorIsRGB | ColorValid | 0x3CB371 - ColorMediumSlateBlue = ColorIsRGB | ColorValid | 0x7B68EE - ColorMediumSpringGreen = ColorIsRGB | ColorValid | 0x00FA9A - ColorMediumTurquoise = ColorIsRGB | ColorValid | 0x48D1CC - ColorMediumVioletRed = ColorIsRGB | ColorValid | 0xC71585 - ColorMidnightBlue = ColorIsRGB | ColorValid | 0x191970 - ColorMintCream = ColorIsRGB | ColorValid | 0xF5FFFA - ColorMistyRose = ColorIsRGB | ColorValid | 0xFFE4E1 - ColorMoccasin = ColorIsRGB | ColorValid | 0xFFE4B5 - ColorNavajoWhite = ColorIsRGB | ColorValid | 0xFFDEAD - ColorOldLace = ColorIsRGB | ColorValid | 0xFDF5E6 - ColorOliveDrab = ColorIsRGB | ColorValid | 0x6B8E23 - ColorOrange = ColorIsRGB | ColorValid | 0xFFA500 - ColorOrangeRed = ColorIsRGB | ColorValid | 0xFF4500 - ColorOrchid = ColorIsRGB | ColorValid | 0xDA70D6 - ColorPaleGoldenrod = ColorIsRGB | ColorValid | 0xEEE8AA - ColorPaleGreen = ColorIsRGB | ColorValid | 0x98FB98 - ColorPaleTurquoise = ColorIsRGB | ColorValid | 0xAFEEEE - ColorPaleVioletRed = ColorIsRGB | ColorValid | 0xDB7093 - ColorPapayaWhip = ColorIsRGB | ColorValid | 0xFFEFD5 - ColorPeachPuff = ColorIsRGB | ColorValid | 0xFFDAB9 - ColorPeru = ColorIsRGB | ColorValid | 0xCD853F - ColorPink = ColorIsRGB | ColorValid | 0xFFC0CB - ColorPlum = ColorIsRGB | ColorValid | 0xDDA0DD - ColorPowderBlue = ColorIsRGB | ColorValid | 0xB0E0E6 - ColorRebeccaPurple = ColorIsRGB | ColorValid | 0x663399 - ColorRosyBrown = ColorIsRGB | ColorValid | 0xBC8F8F - ColorRoyalBlue = ColorIsRGB | ColorValid | 0x4169E1 - ColorSaddleBrown = ColorIsRGB | ColorValid | 0x8B4513 - ColorSalmon = ColorIsRGB | ColorValid | 0xFA8072 - ColorSandyBrown = ColorIsRGB | ColorValid | 0xF4A460 - ColorSeaGreen = ColorIsRGB | ColorValid | 0x2E8B57 - ColorSeashell = ColorIsRGB | ColorValid | 0xFFF5EE - ColorSienna = ColorIsRGB | ColorValid | 0xA0522D - ColorSkyblue = ColorIsRGB | ColorValid | 0x87CEEB - ColorSlateBlue = ColorIsRGB | ColorValid | 0x6A5ACD - ColorSlateGray = ColorIsRGB | ColorValid | 0x708090 - ColorSnow = ColorIsRGB | ColorValid | 0xFFFAFA - ColorSpringGreen = ColorIsRGB | ColorValid | 0x00FF7F - ColorSteelBlue = ColorIsRGB | ColorValid | 0x4682B4 - ColorTan = ColorIsRGB | ColorValid | 0xD2B48C - ColorThistle = ColorIsRGB | ColorValid | 0xD8BFD8 - ColorTomato = ColorIsRGB | ColorValid | 0xFF6347 - ColorTurquoise = ColorIsRGB | ColorValid | 0x40E0D0 - ColorViolet = ColorIsRGB | ColorValid | 0xEE82EE - ColorWheat = ColorIsRGB | ColorValid | 0xF5DEB3 - ColorWhiteSmoke = ColorIsRGB | ColorValid | 0xF5F5F5 - ColorYellowGreen = ColorIsRGB | ColorValid | 0x9ACD32 -) - -// These are aliases for the color gray, because some of us spell -// it as grey. -const ( - ColorGrey = ColorGray - ColorDimGrey = ColorDimGray - ColorDarkGrey = ColorDarkGray - ColorDarkSlateGrey = ColorDarkSlateGray - ColorLightGrey = ColorLightGray - ColorLightSlateGrey = ColorLightSlateGray - ColorSlateGrey = ColorSlateGray -) - -// ColorValues maps color constants to their RGB values. -var ColorValues = map[Color]int32{ - ColorBlack: 0x000000, - ColorMaroon: 0x800000, - ColorGreen: 0x008000, - ColorOlive: 0x808000, - ColorNavy: 0x000080, - ColorPurple: 0x800080, - ColorTeal: 0x008080, - ColorSilver: 0xC0C0C0, - ColorGray: 0x808080, - ColorRed: 0xFF0000, - ColorLime: 0x00FF00, - ColorYellow: 0xFFFF00, - ColorBlue: 0x0000FF, - ColorFuchsia: 0xFF00FF, - ColorAqua: 0x00FFFF, - ColorWhite: 0xFFFFFF, - Color16: 0x000000, // black - Color17: 0x00005F, - Color18: 0x000087, - Color19: 0x0000AF, - Color20: 0x0000D7, - Color21: 0x0000FF, // blue - Color22: 0x005F00, - Color23: 0x005F5F, - Color24: 0x005F87, - Color25: 0x005FAF, - Color26: 0x005FD7, - Color27: 0x005FFF, - Color28: 0x008700, - Color29: 0x00875F, - Color30: 0x008787, - Color31: 0x0087Af, - Color32: 0x0087D7, - Color33: 0x0087FF, - Color34: 0x00AF00, - Color35: 0x00AF5F, - Color36: 0x00AF87, - Color37: 0x00AFAF, - Color38: 0x00AFD7, - Color39: 0x00AFFF, - Color40: 0x00D700, - Color41: 0x00D75F, - Color42: 0x00D787, - Color43: 0x00D7AF, - Color44: 0x00D7D7, - Color45: 0x00D7FF, - Color46: 0x00FF00, // lime - Color47: 0x00FF5F, - Color48: 0x00FF87, - Color49: 0x00FFAF, - Color50: 0x00FFd7, - Color51: 0x00FFFF, // aqua - Color52: 0x5F0000, - Color53: 0x5F005F, - Color54: 0x5F0087, - Color55: 0x5F00AF, - Color56: 0x5F00D7, - Color57: 0x5F00FF, - Color58: 0x5F5F00, - Color59: 0x5F5F5F, - Color60: 0x5F5F87, - Color61: 0x5F5FAF, - Color62: 0x5F5FD7, - Color63: 0x5F5FFF, - Color64: 0x5F8700, - Color65: 0x5F875F, - Color66: 0x5F8787, - Color67: 0x5F87AF, - Color68: 0x5F87D7, - Color69: 0x5F87FF, - Color70: 0x5FAF00, - Color71: 0x5FAF5F, - Color72: 0x5FAF87, - Color73: 0x5FAFAF, - Color74: 0x5FAFD7, - Color75: 0x5FAFFF, - Color76: 0x5FD700, - Color77: 0x5FD75F, - Color78: 0x5FD787, - Color79: 0x5FD7AF, - Color80: 0x5FD7D7, - Color81: 0x5FD7FF, - Color82: 0x5FFF00, - Color83: 0x5FFF5F, - Color84: 0x5FFF87, - Color85: 0x5FFFAF, - Color86: 0x5FFFD7, - Color87: 0x5FFFFF, - Color88: 0x870000, - Color89: 0x87005F, - Color90: 0x870087, - Color91: 0x8700AF, - Color92: 0x8700D7, - Color93: 0x8700FF, - Color94: 0x875F00, - Color95: 0x875F5F, - Color96: 0x875F87, - Color97: 0x875FAF, - Color98: 0x875FD7, - Color99: 0x875FFF, - Color100: 0x878700, - Color101: 0x87875F, - Color102: 0x878787, - Color103: 0x8787AF, - Color104: 0x8787D7, - Color105: 0x8787FF, - Color106: 0x87AF00, - Color107: 0x87AF5F, - Color108: 0x87AF87, - Color109: 0x87AFAF, - Color110: 0x87AFD7, - Color111: 0x87AFFF, - Color112: 0x87D700, - Color113: 0x87D75F, - Color114: 0x87D787, - Color115: 0x87D7AF, - Color116: 0x87D7D7, - Color117: 0x87D7FF, - Color118: 0x87FF00, - Color119: 0x87FF5F, - Color120: 0x87FF87, - Color121: 0x87FFAF, - Color122: 0x87FFD7, - Color123: 0x87FFFF, - Color124: 0xAF0000, - Color125: 0xAF005F, - Color126: 0xAF0087, - Color127: 0xAF00AF, - Color128: 0xAF00D7, - Color129: 0xAF00FF, - Color130: 0xAF5F00, - Color131: 0xAF5F5F, - Color132: 0xAF5F87, - Color133: 0xAF5FAF, - Color134: 0xAF5FD7, - Color135: 0xAF5FFF, - Color136: 0xAF8700, - Color137: 0xAF875F, - Color138: 0xAF8787, - Color139: 0xAF87AF, - Color140: 0xAF87D7, - Color141: 0xAF87FF, - Color142: 0xAFAF00, - Color143: 0xAFAF5F, - Color144: 0xAFAF87, - Color145: 0xAFAFAF, - Color146: 0xAFAFD7, - Color147: 0xAFAFFF, - Color148: 0xAFD700, - Color149: 0xAFD75F, - Color150: 0xAFD787, - Color151: 0xAFD7AF, - Color152: 0xAFD7D7, - Color153: 0xAFD7FF, - Color154: 0xAFFF00, - Color155: 0xAFFF5F, - Color156: 0xAFFF87, - Color157: 0xAFFFAF, - Color158: 0xAFFFD7, - Color159: 0xAFFFFF, - Color160: 0xD70000, - Color161: 0xD7005F, - Color162: 0xD70087, - Color163: 0xD700AF, - Color164: 0xD700D7, - Color165: 0xD700FF, - Color166: 0xD75F00, - Color167: 0xD75F5F, - Color168: 0xD75F87, - Color169: 0xD75FAF, - Color170: 0xD75FD7, - Color171: 0xD75FFF, - Color172: 0xD78700, - Color173: 0xD7875F, - Color174: 0xD78787, - Color175: 0xD787AF, - Color176: 0xD787D7, - Color177: 0xD787FF, - Color178: 0xD7AF00, - Color179: 0xD7AF5F, - Color180: 0xD7AF87, - Color181: 0xD7AFAF, - Color182: 0xD7AFD7, - Color183: 0xD7AFFF, - Color184: 0xD7D700, - Color185: 0xD7D75F, - Color186: 0xD7D787, - Color187: 0xD7D7AF, - Color188: 0xD7D7D7, - Color189: 0xD7D7FF, - Color190: 0xD7FF00, - Color191: 0xD7FF5F, - Color192: 0xD7FF87, - Color193: 0xD7FFAF, - Color194: 0xD7FFD7, - Color195: 0xD7FFFF, - Color196: 0xFF0000, // red - Color197: 0xFF005F, - Color198: 0xFF0087, - Color199: 0xFF00AF, - Color200: 0xFF00D7, - Color201: 0xFF00FF, // fuchsia - Color202: 0xFF5F00, - Color203: 0xFF5F5F, - Color204: 0xFF5F87, - Color205: 0xFF5FAF, - Color206: 0xFF5FD7, - Color207: 0xFF5FFF, - Color208: 0xFF8700, - Color209: 0xFF875F, - Color210: 0xFF8787, - Color211: 0xFF87AF, - Color212: 0xFF87D7, - Color213: 0xFF87FF, - Color214: 0xFFAF00, - Color215: 0xFFAF5F, - Color216: 0xFFAF87, - Color217: 0xFFAFAF, - Color218: 0xFFAFD7, - Color219: 0xFFAFFF, - Color220: 0xFFD700, - Color221: 0xFFD75F, - Color222: 0xFFD787, - Color223: 0xFFD7AF, - Color224: 0xFFD7D7, - Color225: 0xFFD7FF, - Color226: 0xFFFF00, // yellow - Color227: 0xFFFF5F, - Color228: 0xFFFF87, - Color229: 0xFFFFAF, - Color230: 0xFFFFD7, - Color231: 0xFFFFFF, // white - Color232: 0x080808, - Color233: 0x121212, - Color234: 0x1C1C1C, - Color235: 0x262626, - Color236: 0x303030, - Color237: 0x3A3A3A, - Color238: 0x444444, - Color239: 0x4E4E4E, - Color240: 0x585858, - Color241: 0x626262, - Color242: 0x6C6C6C, - Color243: 0x767676, - Color244: 0x808080, // grey - Color245: 0x8A8A8A, - Color246: 0x949494, - Color247: 0x9E9E9E, - Color248: 0xA8A8A8, - Color249: 0xB2B2B2, - Color250: 0xBCBCBC, - Color251: 0xC6C6C6, - Color252: 0xD0D0D0, - Color253: 0xDADADA, - Color254: 0xE4E4E4, - Color255: 0xEEEEEE, - ColorAliceBlue: 0xF0F8FF, - ColorAntiqueWhite: 0xFAEBD7, - ColorAquaMarine: 0x7FFFD4, - ColorAzure: 0xF0FFFF, - ColorBeige: 0xF5F5DC, - ColorBisque: 0xFFE4C4, - ColorBlanchedAlmond: 0xFFEBCD, - ColorBlueViolet: 0x8A2BE2, - ColorBrown: 0xA52A2A, - ColorBurlyWood: 0xDEB887, - ColorCadetBlue: 0x5F9EA0, - ColorChartreuse: 0x7FFF00, - ColorChocolate: 0xD2691E, - ColorCoral: 0xFF7F50, - ColorCornflowerBlue: 0x6495ED, - ColorCornsilk: 0xFFF8DC, - ColorCrimson: 0xDC143C, - ColorDarkBlue: 0x00008B, - ColorDarkCyan: 0x008B8B, - ColorDarkGoldenrod: 0xB8860B, - ColorDarkGray: 0xA9A9A9, - ColorDarkGreen: 0x006400, - ColorDarkKhaki: 0xBDB76B, - ColorDarkMagenta: 0x8B008B, - ColorDarkOliveGreen: 0x556B2F, - ColorDarkOrange: 0xFF8C00, - ColorDarkOrchid: 0x9932CC, - ColorDarkRed: 0x8B0000, - ColorDarkSalmon: 0xE9967A, - ColorDarkSeaGreen: 0x8FBC8F, - ColorDarkSlateBlue: 0x483D8B, - ColorDarkSlateGray: 0x2F4F4F, - ColorDarkTurquoise: 0x00CED1, - ColorDarkViolet: 0x9400D3, - ColorDeepPink: 0xFF1493, - ColorDeepSkyBlue: 0x00BFFF, - ColorDimGray: 0x696969, - ColorDodgerBlue: 0x1E90FF, - ColorFireBrick: 0xB22222, - ColorFloralWhite: 0xFFFAF0, - ColorForestGreen: 0x228B22, - ColorGainsboro: 0xDCDCDC, - ColorGhostWhite: 0xF8F8FF, - ColorGold: 0xFFD700, - ColorGoldenrod: 0xDAA520, - ColorGreenYellow: 0xADFF2F, - ColorHoneydew: 0xF0FFF0, - ColorHotPink: 0xFF69B4, - ColorIndianRed: 0xCD5C5C, - ColorIndigo: 0x4B0082, - ColorIvory: 0xFFFFF0, - ColorKhaki: 0xF0E68C, - ColorLavender: 0xE6E6FA, - ColorLavenderBlush: 0xFFF0F5, - ColorLawnGreen: 0x7CFC00, - ColorLemonChiffon: 0xFFFACD, - ColorLightBlue: 0xADD8E6, - ColorLightCoral: 0xF08080, - ColorLightCyan: 0xE0FFFF, - ColorLightGoldenrodYellow: 0xFAFAD2, - ColorLightGray: 0xD3D3D3, - ColorLightGreen: 0x90EE90, - ColorLightPink: 0xFFB6C1, - ColorLightSalmon: 0xFFA07A, - ColorLightSeaGreen: 0x20B2AA, - ColorLightSkyBlue: 0x87CEFA, - ColorLightSlateGray: 0x778899, - ColorLightSteelBlue: 0xB0C4DE, - ColorLightYellow: 0xFFFFE0, - ColorLimeGreen: 0x32CD32, - ColorLinen: 0xFAF0E6, - ColorMediumAquamarine: 0x66CDAA, - ColorMediumBlue: 0x0000CD, - ColorMediumOrchid: 0xBA55D3, - ColorMediumPurple: 0x9370DB, - ColorMediumSeaGreen: 0x3CB371, - ColorMediumSlateBlue: 0x7B68EE, - ColorMediumSpringGreen: 0x00FA9A, - ColorMediumTurquoise: 0x48D1CC, - ColorMediumVioletRed: 0xC71585, - ColorMidnightBlue: 0x191970, - ColorMintCream: 0xF5FFFA, - ColorMistyRose: 0xFFE4E1, - ColorMoccasin: 0xFFE4B5, - ColorNavajoWhite: 0xFFDEAD, - ColorOldLace: 0xFDF5E6, - ColorOliveDrab: 0x6B8E23, - ColorOrange: 0xFFA500, - ColorOrangeRed: 0xFF4500, - ColorOrchid: 0xDA70D6, - ColorPaleGoldenrod: 0xEEE8AA, - ColorPaleGreen: 0x98FB98, - ColorPaleTurquoise: 0xAFEEEE, - ColorPaleVioletRed: 0xDB7093, - ColorPapayaWhip: 0xFFEFD5, - ColorPeachPuff: 0xFFDAB9, - ColorPeru: 0xCD853F, - ColorPink: 0xFFC0CB, - ColorPlum: 0xDDA0DD, - ColorPowderBlue: 0xB0E0E6, - ColorRebeccaPurple: 0x663399, - ColorRosyBrown: 0xBC8F8F, - ColorRoyalBlue: 0x4169E1, - ColorSaddleBrown: 0x8B4513, - ColorSalmon: 0xFA8072, - ColorSandyBrown: 0xF4A460, - ColorSeaGreen: 0x2E8B57, - ColorSeashell: 0xFFF5EE, - ColorSienna: 0xA0522D, - ColorSkyblue: 0x87CEEB, - ColorSlateBlue: 0x6A5ACD, - ColorSlateGray: 0x708090, - ColorSnow: 0xFFFAFA, - ColorSpringGreen: 0x00FF7F, - ColorSteelBlue: 0x4682B4, - ColorTan: 0xD2B48C, - ColorThistle: 0xD8BFD8, - ColorTomato: 0xFF6347, - ColorTurquoise: 0x40E0D0, - ColorViolet: 0xEE82EE, - ColorWheat: 0xF5DEB3, - ColorWhiteSmoke: 0xF5F5F5, - ColorYellowGreen: 0x9ACD32, -} - -// Special colors. -const ( - // ColorReset is used to indicate that the color should use the - // vanilla terminal colors. (Basically go back to the defaults.) - ColorReset = ColorSpecial | iota - - // ColorNone indicates that we should not change the color from - // whatever is already displayed. This can only be used in limited - // circumstances. - ColorNone -) - -// ColorNames holds the written names of colors. Useful to present a list of -// recognized named colors. -var ColorNames = map[string]Color{ - "black": ColorBlack, - "maroon": ColorMaroon, - "green": ColorGreen, - "olive": ColorOlive, - "navy": ColorNavy, - "purple": ColorPurple, - "teal": ColorTeal, - "silver": ColorSilver, - "gray": ColorGray, - "red": ColorRed, - "lime": ColorLime, - "yellow": ColorYellow, - "blue": ColorBlue, - "fuchsia": ColorFuchsia, - "aqua": ColorAqua, - "white": ColorWhite, - "aliceblue": ColorAliceBlue, - "antiquewhite": ColorAntiqueWhite, - "aquamarine": ColorAquaMarine, - "azure": ColorAzure, - "beige": ColorBeige, - "bisque": ColorBisque, - "blanchedalmond": ColorBlanchedAlmond, - "blueviolet": ColorBlueViolet, - "brown": ColorBrown, - "burlywood": ColorBurlyWood, - "cadetblue": ColorCadetBlue, - "chartreuse": ColorChartreuse, - "chocolate": ColorChocolate, - "coral": ColorCoral, - "cornflowerblue": ColorCornflowerBlue, - "cornsilk": ColorCornsilk, - "crimson": ColorCrimson, - "darkblue": ColorDarkBlue, - "darkcyan": ColorDarkCyan, - "darkgoldenrod": ColorDarkGoldenrod, - "darkgray": ColorDarkGray, - "darkgreen": ColorDarkGreen, - "darkkhaki": ColorDarkKhaki, - "darkmagenta": ColorDarkMagenta, - "darkolivegreen": ColorDarkOliveGreen, - "darkorange": ColorDarkOrange, - "darkorchid": ColorDarkOrchid, - "darkred": ColorDarkRed, - "darksalmon": ColorDarkSalmon, - "darkseagreen": ColorDarkSeaGreen, - "darkslateblue": ColorDarkSlateBlue, - "darkslategray": ColorDarkSlateGray, - "darkturquoise": ColorDarkTurquoise, - "darkviolet": ColorDarkViolet, - "deeppink": ColorDeepPink, - "deepskyblue": ColorDeepSkyBlue, - "dimgray": ColorDimGray, - "dodgerblue": ColorDodgerBlue, - "firebrick": ColorFireBrick, - "floralwhite": ColorFloralWhite, - "forestgreen": ColorForestGreen, - "gainsboro": ColorGainsboro, - "ghostwhite": ColorGhostWhite, - "gold": ColorGold, - "goldenrod": ColorGoldenrod, - "greenyellow": ColorGreenYellow, - "honeydew": ColorHoneydew, - "hotpink": ColorHotPink, - "indianred": ColorIndianRed, - "indigo": ColorIndigo, - "ivory": ColorIvory, - "khaki": ColorKhaki, - "lavender": ColorLavender, - "lavenderblush": ColorLavenderBlush, - "lawngreen": ColorLawnGreen, - "lemonchiffon": ColorLemonChiffon, - "lightblue": ColorLightBlue, - "lightcoral": ColorLightCoral, - "lightcyan": ColorLightCyan, - "lightgoldenrodyellow": ColorLightGoldenrodYellow, - "lightgray": ColorLightGray, - "lightgreen": ColorLightGreen, - "lightpink": ColorLightPink, - "lightsalmon": ColorLightSalmon, - "lightseagreen": ColorLightSeaGreen, - "lightskyblue": ColorLightSkyBlue, - "lightslategray": ColorLightSlateGray, - "lightsteelblue": ColorLightSteelBlue, - "lightyellow": ColorLightYellow, - "limegreen": ColorLimeGreen, - "linen": ColorLinen, - "mediumaquamarine": ColorMediumAquamarine, - "mediumblue": ColorMediumBlue, - "mediumorchid": ColorMediumOrchid, - "mediumpurple": ColorMediumPurple, - "mediumseagreen": ColorMediumSeaGreen, - "mediumslateblue": ColorMediumSlateBlue, - "mediumspringgreen": ColorMediumSpringGreen, - "mediumturquoise": ColorMediumTurquoise, - "mediumvioletred": ColorMediumVioletRed, - "midnightblue": ColorMidnightBlue, - "mintcream": ColorMintCream, - "mistyrose": ColorMistyRose, - "moccasin": ColorMoccasin, - "navajowhite": ColorNavajoWhite, - "oldlace": ColorOldLace, - "olivedrab": ColorOliveDrab, - "orange": ColorOrange, - "orangered": ColorOrangeRed, - "orchid": ColorOrchid, - "palegoldenrod": ColorPaleGoldenrod, - "palegreen": ColorPaleGreen, - "paleturquoise": ColorPaleTurquoise, - "palevioletred": ColorPaleVioletRed, - "papayawhip": ColorPapayaWhip, - "peachpuff": ColorPeachPuff, - "peru": ColorPeru, - "pink": ColorPink, - "plum": ColorPlum, - "powderblue": ColorPowderBlue, - "rebeccapurple": ColorRebeccaPurple, - "rosybrown": ColorRosyBrown, - "royalblue": ColorRoyalBlue, - "saddlebrown": ColorSaddleBrown, - "salmon": ColorSalmon, - "sandybrown": ColorSandyBrown, - "seagreen": ColorSeaGreen, - "seashell": ColorSeashell, - "sienna": ColorSienna, - "skyblue": ColorSkyblue, - "slateblue": ColorSlateBlue, - "slategray": ColorSlateGray, - "snow": ColorSnow, - "springgreen": ColorSpringGreen, - "steelblue": ColorSteelBlue, - "tan": ColorTan, - "thistle": ColorThistle, - "tomato": ColorTomato, - "turquoise": ColorTurquoise, - "violet": ColorViolet, - "wheat": ColorWheat, - "whitesmoke": ColorWhiteSmoke, - "yellowgreen": ColorYellowGreen, - "grey": ColorGray, - "dimgrey": ColorDimGray, - "darkgrey": ColorDarkGray, - "darkslategrey": ColorDarkSlateGray, - "lightgrey": ColorLightGray, - "lightslategrey": ColorLightSlateGray, - "slategrey": ColorSlateGray, -} - -// Valid indicates the color is a valid value (has been set). -func (c Color) Valid() bool { - return c&ColorValid != 0 -} - -// IsRGB is true if the color is an RGB specific value. -func (c Color) IsRGB() bool { - return c&(ColorValid|ColorIsRGB) == (ColorValid | ColorIsRGB) -} - -// CSS returns the CSS hex string ( #ABCDEF ) if valid -// if not a valid color returns empty string -func (c Color) CSS() string { - if !c.Valid() { - return "" - } - return fmt.Sprintf("#%06X", c.Hex()) -} - -// String implements fmt.Stringer to return either the -// W3C name if it has one or the CSS hex string '#ABCDEF' -func (c Color) String() string { - if !c.Valid() { - switch c { - case ColorNone: - return "none" - case ColorDefault: - return "default" - case ColorReset: - return "reset" - } - return "" - } - return c.Name(true) -} - -// Name returns W3C name or an empty string if no arguments -// if passed true as an argument it will falls back to -// the CSS hex string if no W3C name found '#ABCDEF' -func (c Color) Name(css ...bool) string { - for name, hex := range ColorNames { - if c == hex { - return name - } - } - if len(css) > 0 && css[0] { - return c.CSS() - } - return "" -} - -// Hex returns the color's hexadecimal RGB 24-bit value with each component -// consisting of a single byte, R << 16 | G << 8 | B. If the color -// is unknown or unset, -1 is returned. -func (c Color) Hex() int32 { - if !c.Valid() { - return -1 - } - if c&ColorIsRGB != 0 { - return int32(c & 0xffffff) - } - if v, ok := ColorValues[c]; ok { - return v - } - return -1 -} - -// RGB returns the red, green, and blue components of the color, with -// each component represented as a value 0-255. In the event that the -// color cannot be broken up (not set usually), -1 is returned for each value. -func (c Color) RGB() (int32, int32, int32) { - v := c.Hex() - if v < 0 { - return -1, -1, -1 - } - return (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff -} - -// TrueColor returns the true color (RGB) version of the provided color. -// This is useful for ensuring color accuracy when using named colors. -// This will override terminal theme colors. -func (c Color) TrueColor() Color { - if !c.Valid() { - return ColorDefault - } - if c&ColorIsRGB != 0 { - return c | ColorValid - } - return Color(c.Hex()) | ColorIsRGB | ColorValid -} - -// NewRGBColor returns a new color with the given red, green, and blue values. -// Each value must be represented in the range 0-255. -func NewRGBColor(r, g, b int32) Color { - return NewHexColor(((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) -} - -// NewHexColor returns a color using the given 24-bit RGB value. -func NewHexColor(v int32) Color { - return ColorIsRGB | Color(v) | ColorValid -} - -// GetColor creates a Color from a color name (W3C name). A hex value may -// be supplied as a string in the format "#ffffff". -func GetColor(name string) Color { - if c, ok := ColorNames[name]; ok { - return c - } - if len(name) == 7 && name[0] == '#' { - if v, e := strconv.ParseInt(name[1:], 16, 32); e == nil { - return NewHexColor(int32(v)) - } - } - return ColorDefault -} - -// PaletteColor creates a color based on the palette index. -func PaletteColor(index int) Color { - return Color(index) | ColorValid -} - -// FromImageColor converts an image/color.Color into tcell.Color. -// The alpha value is dropped, so it should be tracked separately if it is -// needed. -func FromImageColor(imageColor ic.Color) Color { - r, g, b, _ := imageColor.RGBA() - // NOTE image/color.Color RGB values range is [0, 0xFFFF] as uint32 - return NewRGBColor(int32(r>>8), int32(g>>8), int32(b>>8)) -} diff --git a/vendor/github.com/gdamore/tcell/v2/console_stub.go b/vendor/github.com/gdamore/tcell/v2/console_stub.go deleted file mode 100644 index 6ff7e92a0..000000000 --- a/vendor/github.com/gdamore/tcell/v2/console_stub.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build !windows -// +build !windows - -// Copyright 2015 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 tcell - -// NewConsoleScreen returns a console based screen. This platform -// doesn't have support for any, so it returns nil and a suitable error. -func NewConsoleScreen() (Screen, error) { - return nil, ErrNoScreen -} diff --git a/vendor/github.com/gdamore/tcell/v2/console_win.go b/vendor/github.com/gdamore/tcell/v2/console_win.go deleted file mode 100644 index 1cfdb8dad..000000000 --- a/vendor/github.com/gdamore/tcell/v2/console_win.go +++ /dev/null @@ -1,1275 +0,0 @@ -//go:build windows -// +build windows - -// Copyright 2025 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 tcell - -import ( - "errors" - "fmt" - "os" - "strings" - "sync" - "syscall" - "unicode/utf16" - "unsafe" -) - -type cScreen struct { - in syscall.Handle - out syscall.Handle - cancelflag syscall.Handle - scandone chan struct{} - quit chan struct{} - curx int - cury int - style Style - fini bool - truecolor bool - running bool - disableAlt bool // disable the alternate screen - title string - - w int - h int - - oscreen consoleInfo - ocursor cursorInfo - cursorStyle CursorStyle - cursorColor Color - oimode uint32 - oomode uint32 - cells CellBuffer - focusEnable bool - - mouseEnabled bool - wg sync.WaitGroup - eventQ chan Event - stopQ chan struct{} - finiOnce sync.Once - - sync.Mutex -} - -var winLock sync.Mutex - -var winPalette = []Color{ - ColorBlack, - ColorMaroon, - ColorGreen, - ColorNavy, - ColorOlive, - ColorPurple, - ColorTeal, - ColorSilver, - ColorGray, - ColorRed, - ColorLime, - ColorBlue, - ColorYellow, - ColorFuchsia, - ColorAqua, - ColorWhite, -} - -var winColors = map[Color]Color{ - ColorBlack: ColorBlack, - ColorMaroon: ColorMaroon, - ColorGreen: ColorGreen, - ColorNavy: ColorNavy, - ColorOlive: ColorOlive, - ColorPurple: ColorPurple, - ColorTeal: ColorTeal, - ColorSilver: ColorSilver, - ColorGray: ColorGray, - ColorRed: ColorRed, - ColorLime: ColorLime, - ColorBlue: ColorBlue, - ColorYellow: ColorYellow, - ColorFuchsia: ColorFuchsia, - ColorAqua: ColorAqua, - ColorWhite: ColorWhite, -} - -var ( - u32 = syscall.NewLazyDLL("user32.dll") -) - -// We have to bring in the kernel32 and user32 DLLs directly, so we can get -// access to some system calls that the core Go API lacks. -// -// Note that Windows appends some functions with W to indicate that wide -// characters (Unicode) are in use. The documentation refers to them -// without this suffix, as the resolution is made via preprocessor. -var ( - procGetConsoleCursorInfo = k32.NewProc("GetConsoleCursorInfo") - procSetConsoleCursorInfo = k32.NewProc("SetConsoleCursorInfo") - procSetConsoleWindowInfo = k32.NewProc("SetConsoleWindowInfo") - procSetConsoleScreenBufferSize = k32.NewProc("SetConsoleScreenBufferSize") - procSetConsoleTextAttribute = k32.NewProc("SetConsoleTextAttribute") - procGetLargestConsoleWindowSize = k32.NewProc("GetLargestConsoleWindowSize") - procMessageBeep = u32.NewProc("MessageBeep") -) - -const ( - w32Infinite = ^uintptr(0) - w32WaitObject0 = uintptr(0) -) - -const ( - // VT100/XTerm escapes understood by the console - vtShowCursor = "\x1b[?25h" - vtHideCursor = "\x1b[?25l" - vtCursorPos = "\x1b[%d;%dH" // Note that it is Y then X - vtSgr0 = "\x1b[0m" - vtBold = "\x1b[1m" - vtUnderline = "\x1b[4m" - vtBlink = "\x1b[5m" // Not sure if this is processed - vtReverse = "\x1b[7m" - vtSetFg = "\x1b[38;5;%dm" - vtSetBg = "\x1b[48;5;%dm" - vtSetFgRGB = "\x1b[38;2;%d;%d;%dm" // RGB - vtSetBgRGB = "\x1b[48;2;%d;%d;%dm" // RGB - vtCursorDefault = "\x1b[0 q" - vtCursorBlinkingBlock = "\x1b[1 q" - vtCursorSteadyBlock = "\x1b[2 q" - vtCursorBlinkingUnderline = "\x1b[3 q" - vtCursorSteadyUnderline = "\x1b[4 q" - vtCursorBlinkingBar = "\x1b[5 q" - vtCursorSteadyBar = "\x1b[6 q" - vtDisableAm = "\x1b[?7l" - vtEnableAm = "\x1b[?7h" - vtEnterCA = "\x1b[?1049h\x1b[22;0;0t" - vtExitCA = "\x1b[?1049l\x1b[23;0;0t" - vtDoubleUnderline = "\x1b[4:2m" - vtCurlyUnderline = "\x1b[4:3m" - vtDottedUnderline = "\x1b[4:4m" - vtDashedUnderline = "\x1b[4:5m" - vtUnderColor = "\x1b[58:5:%dm" - vtUnderColorRGB = "\x1b[58:2::%d:%d:%dm" - vtUnderColorReset = "\x1b[59m" - vtEnterUrl = "\x1b]8;%s;%s\x1b\\" // NB arg 1 is id, arg 2 is url - vtExitUrl = "\x1b]8;;\x1b\\" - vtCursorColorRGB = "\x1b]12;#%02x%02x%02x\007" - vtCursorColorReset = "\x1b]112\007" - vtSaveTitle = "\x1b[22;2t" - vtRestoreTitle = "\x1b[23;2t" - vtSetTitle = "\x1b]2;%s\x1b\\" -) - -var vtCursorStyles = map[CursorStyle]string{ - CursorStyleDefault: vtCursorDefault, - CursorStyleBlinkingBlock: vtCursorBlinkingBlock, - CursorStyleSteadyBlock: vtCursorSteadyBlock, - CursorStyleBlinkingUnderline: vtCursorBlinkingUnderline, - CursorStyleSteadyUnderline: vtCursorSteadyUnderline, - CursorStyleBlinkingBar: vtCursorBlinkingBar, - CursorStyleSteadyBar: vtCursorSteadyBar, -} - -// NewConsoleScreen returns a Screen for the Windows console associated -// with the current process. The Screen makes use of the Windows Console -// API to display content and read events. -// -// Deprecated: The console API based implementation will be fully replaced -// with the VT based model. Use NewScreen() to get a reasonable screen -// by default. -func NewConsoleScreen() (Screen, error) { - return &baseScreen{screenImpl: &cScreen{}}, nil -} - -func (s *cScreen) Init() error { - s.eventQ = make(chan Event, 10) - s.quit = make(chan struct{}) - s.scandone = make(chan struct{}) - in, e := syscall.Open("CONIN$", syscall.O_RDWR, 0) - if e != nil { - return e - } - s.in = in - out, e := syscall.Open("CONOUT$", syscall.O_RDWR, 0) - if e != nil { - _ = syscall.Close(s.in) - return e - } - s.out = out - - s.truecolor = true - - switch os.Getenv("TCELL_TRUECOLOR") { - case "disable": - s.truecolor = false - case "enable": - s.truecolor = true - } - - s.Lock() - - s.curx = -1 - s.cury = -1 - s.style = StyleDefault - s.getCursorInfo(&s.ocursor) - s.getConsoleInfo(&s.oscreen) - s.getOutMode(&s.oomode) - s.getInMode(&s.oimode) - s.resize() - - s.fini = false - s.setInMode(modeResizeEn | modeExtendFlg) - - switch os.Getenv("TCELL_ALTSCREEN") { - case "enable": - s.disableAlt = false // also the default - case "disable": - s.disableAlt = true - } - s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline) - var om uint32 - s.getOutMode(&om) - if om&modeVtOutput != modeVtOutput { - return errors.New("failed to initialize: VT output not supported?") - } - - s.Unlock() - - return s.engage() -} - -func (s *cScreen) CharacterSet() string { - // We are always UTF-16LE on Windows - return "UTF-16LE" -} - -func (s *cScreen) EnableMouse(...MouseFlags) { - s.Lock() - s.mouseEnabled = true - s.enableMouse(true) - s.Unlock() -} - -func (s *cScreen) DisableMouse() { - s.Lock() - s.mouseEnabled = false - s.enableMouse(false) - s.Unlock() -} - -func (s *cScreen) enableMouse(on bool) { - if on { - s.setInMode(modeResizeEn | modeMouseEn | modeExtendFlg) - } else { - s.setInMode(modeResizeEn | modeExtendFlg) - } -} - -// Windows lacks bracketed paste (for now) - -func (s *cScreen) EnablePaste() {} - -func (s *cScreen) DisablePaste() {} - -func (s *cScreen) EnableFocus() { - s.Lock() - s.focusEnable = true - s.Unlock() -} - -func (s *cScreen) DisableFocus() { - s.Lock() - s.focusEnable = false - s.Unlock() -} - -func (s *cScreen) Fini() { - s.finiOnce.Do(func() { - close(s.quit) - s.disengage() - }) -} - -func (s *cScreen) disengage() { - s.Lock() - if !s.running { - s.Unlock() - return - } - s.running = false - stopQ := s.stopQ - _, _, _ = procSetEvent.Call(uintptr(s.cancelflag)) - close(stopQ) - s.Unlock() - - s.wg.Wait() - - s.emitVtString(vtCursorStyles[CursorStyleDefault]) - s.emitVtString(vtCursorColorReset) - s.emitVtString(vtEnableAm) - if !s.disableAlt { - s.emitVtString(vtRestoreTitle) - s.emitVtString(vtExitCA) - } - s.setCursorInfo(&s.ocursor) - s.setBufferSize(int(s.oscreen.size.x), int(s.oscreen.size.y)) - s.setInMode(s.oimode) - s.setOutMode(s.oomode) - _, _, _ = procSetConsoleTextAttribute.Call( - uintptr(s.out), - uintptr(s.mapStyle(StyleDefault))) -} - -func (s *cScreen) engage() error { - s.Lock() - defer s.Unlock() - if s.running { - return errors.New("already engaged") - } - s.stopQ = make(chan struct{}) - cf, _, e := procCreateEvent.Call( - uintptr(0), - uintptr(1), - uintptr(0), - uintptr(0)) - if cf == uintptr(0) { - return e - } - s.running = true - s.cancelflag = syscall.Handle(cf) - s.enableMouse(s.mouseEnabled) - s.setInMode(modeVtInput | modeResizeEn | modeExtendFlg) - s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline) - if !s.disableAlt { - s.emitVtString(vtSaveTitle) - s.emitVtString(vtEnterCA) - } - s.emitVtString(vtDisableAm) - if s.title != "" { - s.emitVtString(fmt.Sprintf(vtSetTitle, s.title)) - } - - s.clearScreen(s.style) - s.hideCursor() - - s.cells.Invalidate() - s.hideCursor() - s.resize() - s.draw() - s.doCursor() - - s.wg.Add(1) - go s.scanInput(s.stopQ) - return nil -} - -type cursorInfo struct { - size uint32 - visible uint32 -} - -type coord struct { - x int16 - y int16 -} - -func (c coord) uintptr() uintptr { - // little endian, put x first - return uintptr(c.x) | (uintptr(c.y) << 16) -} - -type rect struct { - left int16 - top int16 - right int16 - bottom int16 -} - -func (s *cScreen) emitVtString(vs string) { - esc := utf16.Encode([]rune(vs)) - _ = syscall.WriteConsole(s.out, &esc[0], uint32(len(esc)), nil, nil) -} - -func (s *cScreen) showCursor() { - s.emitVtString(vtShowCursor) - s.emitVtString(vtCursorStyles[s.cursorStyle]) - if s.cursorColor == ColorReset { - s.emitVtString(vtCursorColorReset) - } else if s.cursorColor.Valid() { - r, g, b := s.cursorColor.RGB() - s.emitVtString(fmt.Sprintf(vtCursorColorRGB, r, g, b)) - } -} - -func (s *cScreen) hideCursor() { - s.emitVtString(vtHideCursor) -} - -func (s *cScreen) ShowCursor(x, y int) { - s.Lock() - if !s.fini { - s.curx = x - s.cury = y - } - s.doCursor() - s.Unlock() -} - -func (s *cScreen) SetCursor(cs CursorStyle, cc Color) { - s.Lock() - if !s.fini { - if _, ok := vtCursorStyles[cs]; ok { - s.cursorStyle = cs - s.cursorColor = cc - s.doCursor() - } - } - s.Unlock() -} - -func (s *cScreen) doCursor() { - x, y := s.curx, s.cury - - if x < 0 || y < 0 || x >= s.w || y >= s.h { - s.hideCursor() - } else { - s.setCursorPos(x, y) - s.showCursor() - } -} - -func (s *cScreen) HideCursor() { - s.ShowCursor(-1, -1) -} - -type mouseRecord struct { - x int16 - y int16 - btns uint32 - mod uint32 - flags uint32 -} - -type focusRecord struct { - focused int32 // actually BOOL -} - -const ( - mouseHWheeled uint32 = 0x8 - mouseVWheeled uint32 = 0x4 - // mouseDoubleClick uint32 = 0x2 - // mouseMoved uint32 = 0x1 -) - -type resizeRecord struct { - x int16 - y int16 -} - -type keyRecord struct { - isdown int32 - repeat uint16 - kcode uint16 - scode uint16 - ch uint16 - mod uint32 -} - -const ( - // Constants per Microsoft. We don't put the modifiers - // here. - vkCancel = 0x03 - vkBack = 0x08 // Backspace - vkTab = 0x09 - vkClear = 0x0c - vkReturn = 0x0d - vkPause = 0x13 - vkEscape = 0x1b - vkSpace = 0x20 - vkPrior = 0x21 // PgUp - vkNext = 0x22 // PgDn - vkEnd = 0x23 - vkHome = 0x24 - vkLeft = 0x25 - vkUp = 0x26 - vkRight = 0x27 - vkDown = 0x28 - vkPrint = 0x2a - vkPrtScr = 0x2c - vkInsert = 0x2d - vkDelete = 0x2e - vkHelp = 0x2f - vkF1 = 0x70 - vkF2 = 0x71 - vkF3 = 0x72 - vkF4 = 0x73 - vkF5 = 0x74 - vkF6 = 0x75 - vkF7 = 0x76 - vkF8 = 0x77 - vkF9 = 0x78 - vkF10 = 0x79 - vkF11 = 0x7a - vkF12 = 0x7b - vkF13 = 0x7c - vkF14 = 0x7d - vkF15 = 0x7e - vkF16 = 0x7f - vkF17 = 0x80 - vkF18 = 0x81 - vkF19 = 0x82 - vkF20 = 0x83 - vkF21 = 0x84 - vkF22 = 0x85 - vkF23 = 0x86 - vkF24 = 0x87 -) - -var vkKeys = map[uint16]Key{ - vkCancel: KeyCancel, - vkBack: KeyBackspace, - vkTab: KeyTab, - vkClear: KeyClear, - vkPause: KeyPause, - vkPrint: KeyPrint, - vkPrtScr: KeyPrint, - vkPrior: KeyPgUp, - vkNext: KeyPgDn, - vkReturn: KeyEnter, - vkEnd: KeyEnd, - vkHome: KeyHome, - vkLeft: KeyLeft, - vkUp: KeyUp, - vkRight: KeyRight, - vkDown: KeyDown, - vkInsert: KeyInsert, - vkDelete: KeyDelete, - vkHelp: KeyHelp, - vkEscape: KeyEscape, - vkSpace: ' ', - vkF1: KeyF1, - vkF2: KeyF2, - vkF3: KeyF3, - vkF4: KeyF4, - vkF5: KeyF5, - vkF6: KeyF6, - vkF7: KeyF7, - vkF8: KeyF8, - vkF9: KeyF9, - vkF10: KeyF10, - vkF11: KeyF11, - vkF12: KeyF12, - vkF13: KeyF13, - vkF14: KeyF14, - vkF15: KeyF15, - vkF16: KeyF16, - vkF17: KeyF17, - vkF18: KeyF18, - vkF19: KeyF19, - vkF20: KeyF20, - vkF21: KeyF21, - vkF22: KeyF22, - vkF23: KeyF23, - vkF24: KeyF24, -} - -// NB: All Windows platforms are little endian. We assume this -// never, ever change. The following code is endian safe. and does -// not use unsafe pointers. -func getu32(v []byte) uint32 { - return uint32(v[0]) + (uint32(v[1]) << 8) + (uint32(v[2]) << 16) + (uint32(v[3]) << 24) -} - -func geti32(v []byte) int32 { - return int32(getu32(v)) -} - -func getu16(v []byte) uint16 { - return uint16(v[0]) + (uint16(v[1]) << 8) -} - -func geti16(v []byte) int16 { - return int16(getu16(v)) -} - -// Convert windows dwControlKeyState to modifier mask -func mod2mask(cks uint32, filter_ctrl_alt bool) ModMask { - mm := ModNone - // Left or right control - ctrl := (cks & (0x0008 | 0x0004)) != 0 - // Left or right alt - alt := (cks & (0x0002 | 0x0001)) != 0 - // Filter out ctrl+alt (it means AltGr) - if !filter_ctrl_alt || !(ctrl && alt) { - if ctrl { - mm |= ModCtrl - } - if alt { - mm |= ModAlt - } - } - // Any shift - if (cks & 0x0010) != 0 { - mm |= ModShift - } - return mm -} - -func mrec2btns(mbtns, flags uint32) ButtonMask { - btns := ButtonNone - if mbtns&0x1 != 0 { - btns |= Button1 - } - if mbtns&0x2 != 0 { - btns |= Button2 - } - if mbtns&0x4 != 0 { - btns |= Button3 - } - if mbtns&0x8 != 0 { - btns |= Button4 - } - if mbtns&0x10 != 0 { - btns |= Button5 - } - if mbtns&0x20 != 0 { - btns |= Button6 - } - if mbtns&0x40 != 0 { - btns |= Button7 - } - if mbtns&0x80 != 0 { - btns |= Button8 - } - - if flags&mouseVWheeled != 0 { - if mbtns&0x80000000 == 0 { - btns |= WheelUp - } else { - btns |= WheelDown - } - } - if flags&mouseHWheeled != 0 { - if mbtns&0x80000000 == 0 { - btns |= WheelRight - } else { - btns |= WheelLeft - } - } - return btns -} - -func (s *cScreen) postEvent(ev Event) { - select { - case s.eventQ <- ev: - case <-s.quit: - } -} - -func (s *cScreen) getConsoleInput() error { - // cancelFlag comes first as WaitForMultipleObjects returns the lowest index - // in the event that both events are signalled. - waitObjects := []syscall.Handle{s.cancelflag, s.in} - // As arrays are contiguous in memory, a pointer to the first object is the - // same as a pointer to the array itself. - pWaitObjects := unsafe.Pointer(&waitObjects[0]) - - rv, _, er := procWaitForMultipleObjects.Call( - uintptr(len(waitObjects)), - uintptr(pWaitObjects), - uintptr(0), - w32Infinite) - // WaitForMultipleObjects returns WAIT_OBJECT_0 + the index. - switch rv { - case w32WaitObject0: // s.cancelFlag - return errors.New("cancelled") - case w32WaitObject0 + 1: // s.in - rec := &inputRecord{} - var nrec int32 - rv, _, er := procReadConsoleInput.Call( - uintptr(s.in), - uintptr(unsafe.Pointer(rec)), - uintptr(1), - uintptr(unsafe.Pointer(&nrec))) - if rv == 0 { - return er - } - if nrec != 1 { - return nil - } - switch rec.typ { - case keyEvent: - krec := &keyRecord{} - krec.isdown = geti32(rec.data[0:]) - krec.repeat = getu16(rec.data[4:]) - krec.kcode = getu16(rec.data[6:]) - krec.scode = getu16(rec.data[8:]) - krec.ch = getu16(rec.data[10:]) - krec.mod = getu32(rec.data[12:]) - - if krec.isdown == 0 || krec.repeat < 1 { - // it's a key release event, ignore it - return nil - } - if krec.ch != 0 { - // synthesized key code - for krec.repeat > 0 { - if krec.ch < ' ' && mod2mask(krec.mod, false) == ModCtrl { - krec.ch += '\x60' - } - - // convert shift+tab to backtab - if mod2mask(krec.mod, false) == ModShift && krec.ch == vkTab { - s.postEvent(NewEventKey(KeyBacktab, 0, ModNone)) - } else { - s.postEvent(NewEventKey(KeyRune, rune(krec.ch), mod2mask(krec.mod, true))) - } - krec.repeat-- - } - return nil - } - key := KeyNUL // impossible on Windows - ok := false - if key, ok = vkKeys[krec.kcode]; !ok { - return nil - } - for krec.repeat > 0 { - s.postEvent(NewEventKey(key, rune(krec.ch), mod2mask(krec.mod, false))) - krec.repeat-- - } - - case mouseEvent: - var mrec mouseRecord - mrec.x = geti16(rec.data[0:]) - mrec.y = geti16(rec.data[2:]) - mrec.btns = getu32(rec.data[4:]) - mrec.mod = getu32(rec.data[8:]) - mrec.flags = getu32(rec.data[12:]) - btns := mrec2btns(mrec.btns, mrec.flags) - // we ignore double click, events are delivered normally - s.postEvent(NewEventMouse(int(mrec.x), int(mrec.y), btns, mod2mask(mrec.mod, false))) - - case resizeEvent: - var rrec resizeRecord - rrec.x = geti16(rec.data[0:]) - rrec.y = geti16(rec.data[2:]) - s.postEvent(NewEventResize(int(rrec.x), int(rrec.y))) - - case focusEvent: - var focus focusRecord - focus.focused = geti32(rec.data[0:]) - s.Lock() - enabled := s.focusEnable - s.Unlock() - if enabled { - s.postEvent(NewEventFocus(focus.focused != 0)) - } - - default: - } - default: - return er - } - - return nil -} - -func (s *cScreen) scanInput(stopQ chan struct{}) { - defer s.wg.Done() - for { - select { - case <-stopQ: - return - default: - } - if e := s.getConsoleInput(); e != nil { - return - } - } -} - -func (s *cScreen) Colors() int { - if !s.truecolor { - return 16 - } - return 1 << 24 -} - -var vgaColors = map[Color]uint16{ - ColorBlack: 0, - ColorMaroon: 0x4, - ColorGreen: 0x2, - ColorNavy: 0x1, - ColorOlive: 0x6, - ColorPurple: 0x5, - ColorTeal: 0x3, - ColorSilver: 0x7, - ColorGrey: 0x8, - ColorRed: 0xc, - ColorLime: 0xa, - ColorBlue: 0x9, - ColorYellow: 0xe, - ColorFuchsia: 0xd, - ColorAqua: 0xb, - ColorWhite: 0xf, -} - -// Windows uses RGB signals -func mapColor2RGB(c Color) uint16 { - winLock.Lock() - if v, ok := winColors[c]; ok { - c = v - } else { - v = FindColor(c, winPalette) - winColors[c] = v - c = v - } - winLock.Unlock() - - if vc, ok := vgaColors[c]; ok { - return vc - } - return 0 -} - -// Map a tcell style to Windows attributes -func (s *cScreen) mapStyle(style Style) uint16 { - f, b, a := style.fg, style.bg, style.attrs - fa := s.oscreen.attrs & 0xf - ba := (s.oscreen.attrs) >> 4 & 0xf - if f != ColorDefault && f != ColorReset { - fa = mapColor2RGB(f) - } - if b != ColorDefault && b != ColorReset { - ba = mapColor2RGB(b) - } - var attr uint16 - // We simulate reverse by doing the color swap ourselves. - // Apparently windows cannot really do this except in DBCS - // views. - if a&AttrReverse != 0 { - attr = ba - attr |= fa << 4 - } else { - attr = fa - attr |= ba << 4 - } - if a&AttrBold != 0 { - attr |= 0x8 - } - if a&AttrDim != 0 { - attr &^= 0x8 - } - if a&AttrUnderline != 0 { - // Best effort -- doesn't seem to work though. - attr |= 0x8000 - } - // Blink is unsupported - return attr -} - -func (s *cScreen) makeVtStyle(style Style) string { - esc := &strings.Builder{} - - fg, bg, attrs := style.fg, style.bg, style.attrs - us, uc := style.ulStyle, style.ulColor - - esc.WriteString(vtSgr0) - if attrs&(AttrBold|AttrDim) == AttrBold { - esc.WriteString(vtBold) - } - if attrs&AttrBlink != 0 { - esc.WriteString(vtBlink) - } - if us != UnderlineStyleNone { - if uc == ColorReset { - esc.WriteString(vtUnderColorReset) - } else if uc.IsRGB() { - r, g, b := uc.RGB() - _, _ = fmt.Fprintf(esc, vtUnderColorRGB, int(r), int(g), int(b)) - } else if uc.Valid() { - _, _ = fmt.Fprintf(esc, vtUnderColor, uc&0xff) - } - - esc.WriteString(vtUnderline) - // legacy ConHost does not understand these but Terminal does - switch us { - case UnderlineStyleSolid: - case UnderlineStyleDouble: - esc.WriteString(vtDoubleUnderline) - case UnderlineStyleCurly: - esc.WriteString(vtCurlyUnderline) - case UnderlineStyleDotted: - esc.WriteString(vtDottedUnderline) - case UnderlineStyleDashed: - esc.WriteString(vtDashedUnderline) - } - } - - if attrs&AttrReverse != 0 { - esc.WriteString(vtReverse) - } - if fg.IsRGB() { - r, g, b := fg.RGB() - _, _ = fmt.Fprintf(esc, vtSetFgRGB, r, g, b) - } else if fg.Valid() { - _, _ = fmt.Fprintf(esc, vtSetFg, fg&0xff) - } - if bg.IsRGB() { - r, g, b := bg.RGB() - _, _ = fmt.Fprintf(esc, vtSetBgRGB, r, g, b) - } else if bg.Valid() { - _, _ = fmt.Fprintf(esc, vtSetBg, bg&0xff) - } - // URL string can be long, so don't send it unless we really need to - if style.url != "" { - _, _ = fmt.Fprintf(esc, vtEnterUrl, style.urlId, style.url) - } else { - esc.WriteString(vtExitUrl) - } - - return esc.String() -} - -func (s *cScreen) sendVtStyle(style Style) { - s.emitVtString(s.makeVtStyle(style)) -} - -func (s *cScreen) writeString(x, y int, style Style, vtBuf, ch []uint16) { - // we assume the caller has hidden the cursor - if len(ch) == 0 { - return - } - - vtBuf = append(vtBuf, utf16.Encode([]rune(fmt.Sprintf(vtCursorPos, y+1, x+1)))...) - styleStr := s.makeVtStyle(style) - vtBuf = append(vtBuf, utf16.Encode([]rune(styleStr))...) - vtBuf = append(vtBuf, ch...) - _ = syscall.WriteConsole(s.out, &vtBuf[0], uint32(len(vtBuf)), nil, nil) - vtBuf = vtBuf[:0] -} - -func (s *cScreen) draw() { - // allocate a scratch line bit enough for no combining chars. - // if you have combining characters, you may pay for extra allocations. - buf := make([]uint16, 0, s.w) - var vtBuf []uint16 - wcs := buf[:] - lstyle := styleInvalid - - lx, ly := -1, -1 - ra := make([]rune, 1) - - for y := 0; y < s.h; y++ { - for x := 0; x < s.w; x++ { - mainc, combc, style, width := s.cells.GetContent(x, y) - dirty := s.cells.Dirty(x, y) - if style == StyleDefault { - style = s.style - } - - if !dirty || style != lstyle { - // write out any data queued thus far - // because we are going to skip over some - // cells, or because we need to change styles - s.writeString(lx, ly, lstyle, vtBuf, wcs) - wcs = buf[0:0] - lstyle = StyleDefault - if !dirty { - continue - } - } - if x > s.w-width { - mainc = ' ' - combc = nil - width = 1 - } - if len(wcs) == 0 { - lstyle = style - lx = x - ly = y - } - ra[0] = mainc - wcs = append(wcs, utf16.Encode(ra)...) - if len(combc) != 0 { - wcs = append(wcs, utf16.Encode(combc)...) - } - for dx := 0; dx < width; dx++ { - s.cells.SetDirty(x+dx, y, false) - } - x += width - 1 - } - s.writeString(lx, ly, lstyle, vtBuf, wcs) - wcs = buf[0:0] - lstyle = styleInvalid - } -} - -func (s *cScreen) Show() { - s.Lock() - if !s.fini { - s.hideCursor() - s.resize() - s.draw() - s.doCursor() - } - s.Unlock() -} - -func (s *cScreen) Sync() { - s.Lock() - if !s.fini { - s.cells.Invalidate() - s.hideCursor() - s.resize() - s.draw() - s.doCursor() - } - s.Unlock() -} - -type consoleInfo struct { - size coord - pos coord - attrs uint16 - win rect - maxsz coord -} - -func (s *cScreen) getConsoleInfo(info *consoleInfo) { - _, _, _ = procGetConsoleScreenBufferInfo.Call( - uintptr(s.out), - uintptr(unsafe.Pointer(info))) -} - -func (s *cScreen) getCursorInfo(info *cursorInfo) { - _, _, _ = procGetConsoleCursorInfo.Call( - uintptr(s.out), - uintptr(unsafe.Pointer(info))) -} - -func (s *cScreen) setCursorInfo(info *cursorInfo) { - _, _, _ = procSetConsoleCursorInfo.Call( - uintptr(s.out), - uintptr(unsafe.Pointer(info))) -} - -func (s *cScreen) setCursorPos(x, y int) { - // Note that the string is Y first. Origin is 1,1. - s.emitVtString(fmt.Sprintf(vtCursorPos, y+1, x+1)) -} - -func (s *cScreen) setBufferSize(x, y int) { - _, _, _ = procSetConsoleScreenBufferSize.Call( - uintptr(s.out), - coord{int16(x), int16(y)}.uintptr()) -} - -func (s *cScreen) Size() (int, int) { - s.Lock() - w, h := s.w, s.h - s.Unlock() - - return w, h -} - -func (s *cScreen) SetSize(w, h int) { - xy, _, _ := procGetLargestConsoleWindowSize.Call(uintptr(s.out)) - - // xy is little endian packed - y := int(xy >> 16) - x := int(xy & 0xffff) - - if x == 0 || y == 0 { - return - } - - // This is a hacky workaround for Windows Terminal. - // Essentially Windows Terminal (Windows 11) does not support application - // initiated resizing. To detect this, we look for an extremely large size - // for the maximum width. If it is > 500, then this is almost certainly - // Windows Terminal, and won't support this. (Note that the legacy console - // does support application resizing.) - if x >= 500 { - return - } - - s.setBufferSize(x, y) - r := rect{0, 0, int16(w - 1), int16(h - 1)} - _, _, _ = procSetConsoleWindowInfo.Call( - uintptr(s.out), - uintptr(1), - uintptr(unsafe.Pointer(&r))) - - s.resize() -} - -func (s *cScreen) resize() { - info := consoleInfo{} - s.getConsoleInfo(&info) - - w := int((info.win.right - info.win.left) + 1) - h := int((info.win.bottom - info.win.top) + 1) - - if s.w == w && s.h == h { - return - } - - s.cells.Resize(w, h) - s.w = w - s.h = h - - s.setBufferSize(w, h) - - r := rect{0, 0, int16(w - 1), int16(h - 1)} - _, _, _ = procSetConsoleWindowInfo.Call( - uintptr(s.out), - uintptr(1), - uintptr(unsafe.Pointer(&r))) - select { - case s.eventQ <- NewEventResize(w, h): - default: - } -} - -func (s *cScreen) clearScreen(style Style) { - s.sendVtStyle(style) - row := strings.Repeat(" ", s.w) - for y := 0; y < s.h; y++ { - s.setCursorPos(0, y) - s.emitVtString(row) - } - s.setCursorPos(0, 0) -} - -const ( - // Input modes - modeExtendFlg = uint32(0x0080) - modeMouseEn = uint32(0x0010) - modeResizeEn = uint32(0x0008) - modeVtInput = uint32(0x0200) - // modeCooked = uint32(0x0001) - - // Output modes - modeCookedOut = uint32(0x0001) - modeVtOutput = uint32(0x0004) - modeNoAutoNL = uint32(0x0008) - modeUnderline = uint32(0x0010) // ENABLE_LVB_GRID_WORLDWIDE, needed for underlines - // modeWrapEOL = uint32(0x0002) -) - -func (s *cScreen) setInMode(mode uint32) { - _, _, _ = procSetConsoleMode.Call( - uintptr(s.in), - uintptr(mode)) -} - -func (s *cScreen) setOutMode(mode uint32) { - _, _, _ = procSetConsoleMode.Call( - uintptr(s.out), - uintptr(mode)) -} - -func (s *cScreen) getInMode(v *uint32) { - _, _, _ = procGetConsoleMode.Call( - uintptr(s.in), - uintptr(unsafe.Pointer(v))) -} - -func (s *cScreen) getOutMode(v *uint32) { - _, _, _ = procGetConsoleMode.Call( - uintptr(s.out), - uintptr(unsafe.Pointer(v))) -} - -func (s *cScreen) SetStyle(style Style) { - s.Lock() - s.style = style - s.Unlock() -} - -func (s *cScreen) SetTitle(title string) { - s.Lock() - s.title = title - s.emitVtString(fmt.Sprintf(vtSetTitle, title)) - s.Unlock() -} - -// No fallback rune support, since we have Unicode. Yay! - -func (s *cScreen) RegisterRuneFallback(_ rune, _ string) { -} - -func (s *cScreen) UnregisterRuneFallback(_ rune) { -} - -func (s *cScreen) CanDisplay(_ rune, _ bool) bool { - // We presume we can display anything -- we're Unicode. - // (Sadly this not precisely true. Combining characters are especially - // poorly supported under Windows.) - return true -} - -func (s *cScreen) HasMouse() bool { - return true -} - -func (s *cScreen) SetClipboard(_ []byte) { -} - -func (s *cScreen) GetClipboard() { -} - -func (s *cScreen) Resize(int, int, int, int) {} - -func (s *cScreen) HasKey(_ Key) bool { - return true -} - -func (s *cScreen) Beep() error { - // A simple beep. If the sound card is not available, the sound is generated - // using the speaker. - // - // Reference: - // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebeep - const simpleBeep = 0xffffffff - if rv, _, err := procMessageBeep.Call(simpleBeep); rv == 0 { - return err - } - return nil -} - -func (s *cScreen) Suspend() error { - s.disengage() - return nil -} - -func (s *cScreen) Resume() error { - return s.engage() -} - -func (s *cScreen) Tty() (Tty, bool) { - return nil, false -} - -func (s *cScreen) GetCells() *CellBuffer { - return &s.cells -} - -func (s *cScreen) EventQ() chan Event { - return s.eventQ -} - -func (s *cScreen) StopQ() <-chan struct{} { - return s.quit -} diff --git a/vendor/github.com/gdamore/tcell/v2/doc.go b/vendor/github.com/gdamore/tcell/v2/doc.go deleted file mode 100644 index 690dd27ad..000000000 --- a/vendor/github.com/gdamore/tcell/v2/doc.go +++ /dev/null @@ -1,47 +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 tcell provides a lower-level, portable API for building -// programs that interact with terminals or consoles. It works with -// both common (and many uncommon!) terminals or terminal emulators, -// and Windows console implementations. -// -// It provides support for up to 256 colors, text attributes, and box drawing -// elements. A database of terminals built from a real terminfo database -// is provided, along with code to generate new database entries. -// -// Tcell offers very rich support for mice, dependent upon the terminal -// of course. (Windows, XTerm, and iTerm 2 are known to work very well.) -// -// If the environment is not Unicode by default, such as an ISO8859 based -// locale or GB18030, Tcell can convert input and output, so that your -// terminal can operate in whatever locale is most convenient, while the -// application program can just assume "everything is UTF-8". Reasonable -// defaults are used for updating characters to something suitable for -// display. Unicode box drawing characters will be converted to use the -// alternate character set of your terminal, if native conversions are -// not available. If no ACS is available, then some ASCII fallbacks will -// be used. -// -// Note that support for non-UTF-8 locales (other than C) must be enabled -// by the application using RegisterEncoding() -- we don't have them all -// enabled by default to avoid bloating the application unnecessarily. -// (These days UTF-8 is good enough for almost everyone, and nobody should -// be using legacy locales anymore.) Also, actual glyphs for various code -// point will only be displayed if your terminal or emulator (or the font -// the emulator is using) supports them. -// -// A rich set of key codes is supported, with support for up to 65 function -// keys, and various other special keys. -package tcell diff --git a/vendor/github.com/gdamore/tcell/v2/simulation.go b/vendor/github.com/gdamore/tcell/v2/simulation.go deleted file mode 100644 index 9a09c3c0e..000000000 --- a/vendor/github.com/gdamore/tcell/v2/simulation.go +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright 2024 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 tcell - -import ( - "sync" - "unicode/utf8" - - "golang.org/x/text/transform" -) - -// NewSimulationScreen returns a SimulationScreen. Note that -// SimulationScreen is also a Screen. -func NewSimulationScreen(charset string) SimulationScreen { - if charset == "" { - charset = "UTF-8" - } - ss := &simscreen{charset: charset} - ss.Screen = &baseScreen{screenImpl: ss} - return ss -} - -// SimulationScreen represents a screen simulation. This is intended to -// be a superset of normal Screens, but also adds some important interfaces -// for testing. -type SimulationScreen interface { - Screen - - // InjectKeyBytes injects a stream of bytes corresponding to - // the native encoding (see charset). It turns true if the entire - // set of bytes were processed and delivered as KeyEvents, false - // if any bytes were not fully understood. Any bytes that are not - // fully converted are discarded. - InjectKeyBytes(buf []byte) bool - - // InjectKey injects a key event. The rune is a UTF-8 rune, post - // any translation. - InjectKey(key Key, r rune, mod ModMask) - - // InjectMouse injects a mouse event. - InjectMouse(x, y int, buttons ButtonMask, mod ModMask) - - // GetContents returns screen contents as an array of - // cells, along with the physical width & height. Note that the - // physical contents will be used until the next time SetSize() - // is called. - GetContents() (cells []SimCell, width int, height int) - - // GetCursor returns the cursor details. - GetCursor() (x int, y int, visible bool) - - // GetTitle gets the previously set title. - GetTitle() string - - // GetClipboardData gets the actual data for the clipboard. - GetClipboardData() []byte -} - -// SimCell represents a simulated screen cell. The purpose of this -// is to track on screen content. -type SimCell struct { - // Bytes is the actual character bytes. Normally this is - // rune data, but it could be be data in another encoding system. - Bytes []byte - - // Style is the style used to display the data. - Style Style - - // Runes is the list of runes, unadulterated, in UTF-8. - Runes []rune -} - -type simscreen struct { - physw int - physh int - fini bool - style Style - evch chan Event - quit chan struct{} - - front []SimCell - back CellBuffer - clear bool - cursorx int - cursory int - cursorvis bool - mouse bool - paste bool - charset string - encoder transform.Transformer - decoder transform.Transformer - fillchar rune - fillstyle Style - fallback map[rune]string - title string - clipboard []byte - - Screen - sync.Mutex -} - -func (s *simscreen) Init() error { - s.evch = make(chan Event, 10) - s.quit = make(chan struct{}) - s.fillchar = 'X' - s.fillstyle = StyleDefault - s.mouse = false - s.physw = 80 - s.physh = 25 - s.cursorx = -1 - s.cursory = -1 - s.style = StyleDefault - - if enc := GetEncoding(s.charset); enc != nil { - s.encoder = enc.NewEncoder() - s.decoder = enc.NewDecoder() - } else { - return ErrNoCharset - } - - s.front = make([]SimCell, s.physw*s.physh) - s.back.Resize(80, 25) - - // default fallbacks - s.fallback = make(map[rune]string) - for k, v := range RuneFallbacks { - s.fallback[k] = v - } - return nil -} - -func (s *simscreen) Fini() { - s.Lock() - s.fini = true - s.back.Resize(0, 0) - s.Unlock() - if s.quit != nil { - close(s.quit) - } - s.physw = 0 - s.physh = 0 - s.front = nil -} - -func (s *simscreen) SetStyle(style Style) { - s.Lock() - s.style = style - s.Unlock() -} - -func (s *simscreen) drawCell(x, y int) int { - - mainc, combc, style, width := s.back.GetContent(x, y) - if !s.back.Dirty(x, y) { - return width - } - if x >= s.physw || y >= s.physh || x < 0 || y < 0 { - return width - } - simc := &s.front[(y*s.physw)+x] - - if style == StyleDefault { - style = s.style - } - simc.Style = style - simc.Runes = append([]rune{mainc}, combc...) - - // now emit runes - taking care to not overrun width with a - // wide character, and to ensure that we emit exactly one regular - // character followed up by any residual combing characters - - simc.Bytes = nil - - if x > s.physw-width { - simc.Runes = []rune{' '} - simc.Bytes = []byte{' '} - return width - } - - lbuf := make([]byte, 12) - ubuf := make([]byte, 12) - nout := 0 - - for _, r := range simc.Runes { - - l := utf8.EncodeRune(ubuf, r) - - nout, _, _ = s.encoder.Transform(lbuf, ubuf[:l], true) - - if nout == 0 || lbuf[0] == '\x1a' { - - // skip combining - - if subst, ok := s.fallback[r]; ok { - simc.Bytes = append(simc.Bytes, - []byte(subst)...) - - } else if r >= ' ' && r <= '~' { - simc.Bytes = append(simc.Bytes, byte(r)) - - } else if simc.Bytes == nil { - simc.Bytes = append(simc.Bytes, '?') - } - } else { - simc.Bytes = append(simc.Bytes, lbuf[:nout]...) - } - } - s.back.SetDirty(x, y, false) - return width -} - -func (s *simscreen) ShowCursor(x, y int) { - s.Lock() - s.cursorx, s.cursory = x, y - s.showCursor() - s.Unlock() -} - -func (s *simscreen) HideCursor() { - s.ShowCursor(-1, -1) -} - -func (s *simscreen) showCursor() { - - x, y := s.cursorx, s.cursory - if x < 0 || y < 0 || x >= s.physw || y >= s.physh { - s.cursorvis = false - } else { - s.cursorvis = true - } -} - -func (s *simscreen) hideCursor() { - // does not update cursor position - s.cursorvis = false -} - -func (s *simscreen) SetCursor(CursorStyle, Color) {} - -func (s *simscreen) Show() { - s.Lock() - s.resize() - s.draw() - s.Unlock() -} - -func (s *simscreen) clearScreen() { - // We emulate a hardware clear by filling with a specific pattern - for i := range s.front { - s.front[i].Style = s.fillstyle - s.front[i].Runes = []rune{s.fillchar} - s.front[i].Bytes = []byte{byte(s.fillchar)} - } - s.clear = false -} - -func (s *simscreen) draw() { - s.hideCursor() - if s.clear { - s.clearScreen() - } - - w, h := s.back.Size() - for y := 0; y < h; y++ { - for x := 0; x < w; x++ { - width := s.drawCell(x, y) - x += width - 1 - } - } - s.showCursor() -} - -func (s *simscreen) EnableMouse(...MouseFlags) { - s.mouse = true -} - -func (s *simscreen) DisableMouse() { - s.mouse = false -} - -func (s *simscreen) EnablePaste() { - s.paste = true -} - -func (s *simscreen) DisablePaste() { - s.paste = false -} - -func (s *simscreen) EnableFocus() { -} - -func (s *simscreen) DisableFocus() { -} - -func (s *simscreen) Size() (int, int) { - s.Lock() - w, h := s.back.Size() - s.Unlock() - return w, h -} - -func (s *simscreen) resize() { - w, h := s.physw, s.physh - ow, oh := s.back.Size() - if w != ow || h != oh { - s.back.Resize(w, h) - ev := NewEventResize(w, h) - s.postEvent(ev) - } -} - -func (s *simscreen) Colors() int { - return 256 -} - -func (s *simscreen) postEvent(ev Event) { - select { - case s.evch <- ev: - case <-s.quit: - } -} - -func (s *simscreen) InjectMouse(x, y int, buttons ButtonMask, mod ModMask) { - ev := NewEventMouse(x, y, buttons, mod) - s.postEvent(ev) -} - -func (s *simscreen) InjectKey(key Key, r rune, mod ModMask) { - ev := NewEventKey(key, r, mod) - s.postEvent(ev) -} - -func (s *simscreen) InjectKeyBytes(b []byte) bool { - failed := false - -outer: - for len(b) > 0 { - if b[0] >= ' ' && b[0] <= 0x7F { - // printable ASCII easy to deal with -- no encodings - ev := NewEventKey(KeyRune, rune(b[0]), ModNone) - s.postEvent(ev) - b = b[1:] - continue - } - - if b[0] < 0x80 { - // No encodings start with low numbered values - if b[0] > 0 && b[0] < ' ' { // control keys - switch Key(b[0]) { - case KeyESC, KeyEnter, KeyTAB: - s.postEvent(NewEventKey(Key(b[0]), 0, 0)) - continue; - default: - s.postEvent(NewEventKey(Key(b[0]), rune(b[0])+'\x60', ModCtrl)) - continue - } - } - mod := ModNone - ev := NewEventKey(Key(b[0]), 0, mod) - s.postEvent(ev) - b = b[1:] - continue - } - - utfb := make([]byte, len(b)*4) // worst case - for l := 1; l < len(b); l++ { - s.decoder.Reset() - nout, nin, _ := s.decoder.Transform(utfb, b[:l], true) - - if nout != 0 { - r, _ := utf8.DecodeRune(utfb[:nout]) - if r != utf8.RuneError { - ev := NewEventKey(KeyRune, r, ModNone) - s.postEvent(ev) - } - b = b[nin:] - continue outer - } - } - failed = true - b = b[1:] - continue - } - - return !failed -} - -func (s *simscreen) Sync() { - s.Lock() - s.clear = true - s.resize() - s.back.Invalidate() - s.draw() - s.Unlock() -} - -func (s *simscreen) CharacterSet() string { - return s.charset -} - -func (s *simscreen) SetSize(w, h int) { - s.Lock() - newc := make([]SimCell, w*h) - for row := 0; row < h && row < s.physh; row++ { - for col := 0; col < w && col < s.physw; col++ { - newc[(row*w)+col] = s.front[(row*s.physw)+col] - } - } - s.cursorx, s.cursory = -1, -1 - s.physw, s.physh = w, h - s.front = newc - s.back.Resize(w, h) - s.Unlock() -} - -func (s *simscreen) GetContents() ([]SimCell, int, int) { - s.Lock() - cells, w, h := s.front, s.physw, s.physh - s.Unlock() - return cells, w, h -} - -func (s *simscreen) GetCursor() (int, int, bool) { - s.Lock() - x, y, vis := s.cursorx, s.cursory, s.cursorvis - s.Unlock() - return x, y, vis -} - -func (s *simscreen) RegisterRuneFallback(r rune, subst string) { - s.Lock() - s.fallback[r] = subst - s.Unlock() -} - -func (s *simscreen) UnregisterRuneFallback(r rune) { - s.Lock() - delete(s.fallback, r) - s.Unlock() -} - -func (s *simscreen) CanDisplay(r rune, checkFallbacks bool) bool { - - if enc := s.encoder; enc != nil { - nb := make([]byte, 6) - ob := make([]byte, 6) - num := utf8.EncodeRune(ob, r) - - enc.Reset() - dst, _, err := enc.Transform(nb, ob[:num], true) - if dst != 0 && err == nil && nb[0] != '\x1A' { - return true - } - } - if !checkFallbacks { - return false - } - if _, ok := s.fallback[r]; ok { - return true - } - return false -} - -func (s *simscreen) HasMouse() bool { - return false -} - -func (s *simscreen) Resize(int, int, int, int) {} - -func (s *simscreen) HasKey(Key) bool { - return true -} - -func (s *simscreen) Beep() error { - return nil -} - -func (s *simscreen) Suspend() error { - return nil -} - -func (s *simscreen) Resume() error { - return nil -} - -func (s *simscreen) Tty() (Tty, bool) { - return nil, false -} - -func (s *simscreen) GetCells() *CellBuffer { - return &s.back -} - -func (s *simscreen) EventQ() chan Event { - return s.evch -} - -func (s *simscreen) StopQ() <-chan struct{} { - return s.quit -} - -func (s *simscreen) SetTitle(title string) { - s.title = title -} - -func (s *simscreen) GetTitle() string { - return s.title -} - -func (s *simscreen) SetClipboard(data []byte) { - s.clipboard = data -} - -func (s *simscreen) GetClipboard() { - if s.clipboard != nil { - ev := NewEventClipboard(s.clipboard) - s.postEvent(ev) - } -} - -func (s *simscreen) GetClipboardData() []byte { - return s.clipboard -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/.gitignore b/vendor/github.com/gdamore/tcell/v2/terminfo/.gitignore deleted file mode 100644 index 74f3c04fd..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/.gitignore +++ /dev/null @@ -1 +0,0 @@ -mkinfo diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/README.md b/vendor/github.com/gdamore/tcell/v2/terminfo/README.md deleted file mode 100644 index 20ae937f3..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/README.md +++ /dev/null @@ -1,25 +0,0 @@ -This package represents the parent for all terminals. - -In older versions of tcell we had (a couple of) different -external file formats for the terminal database. Those are -now removed. All terminal definitions are supplied by -one of two methods: - -1. Compiled Go code - -2. For systems with terminfo and infocmp, dynamically - generated at runtime. - -The Go code can be generated using the mkinfo utility in -this directory. The database entry should be generated -into a package in a directory named as the first character -of the package name. (This permits us to group them all -without having a huge directory of little packages.) - -It may be desirable to add new packages to the extended -package, or -- rarely -- the base package. - -Applications which want to have the large set of terminal -descriptions built into the binary can simply import the -extended package. Otherwise a smaller reasonable default -set (the base package) will be included instead. diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/TERMINALS.md b/vendor/github.com/gdamore/tcell/v2/terminfo/TERMINALS.md deleted file mode 100644 index 85c1e61c2..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/TERMINALS.md +++ /dev/null @@ -1,7 +0,0 @@ -TERMINALS -========= - -The best way to populate terminals on Debian is to install ncurses, -ncurses-term, screen, tmux, rxvt-unicode, and dvtm. This populates the -the terminfo database so that we can have a reasonable set of starting -terminals. diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/a/aixterm/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/a/aixterm/term.go deleted file mode 100644 index 4da68f4e0..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/a/aixterm/term.go +++ /dev/null @@ -1,31 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package aixterm - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // IBM Aixterm Terminal Emulator - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "aixterm", - Columns: 80, - Lines: 25, - Colors: 8, - Clear: "\x1b[H\x1b[J", - AttrOff: "\x1b[0;10m\x1b(B", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Reverse: "\x1b[7m", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[32m\x1b[40m", - PadChar: "\x00", - AltChars: "jjkkllmmnnqqttuuvvwwxx", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/direct.go b/vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/direct.go deleted file mode 100644 index 8026a721e..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/direct.go +++ /dev/null @@ -1,41 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package alacritty - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // alacritty with direct color indexing - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "alacritty-direct", - Columns: 80, - Lines: 24, - Colors: 16777216, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h\x1b[22;0;0t", - ExitCA: "\x1b[?1049l\x1b[23;0;0t", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - TrueColor: true, - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/term.go deleted file mode 100644 index 0e45869c0..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/term.go +++ /dev/null @@ -1,44 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package alacritty - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // alacritty terminal emulator - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "alacritty", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h\x1b[22;0;0t", - ExitCA: "\x1b[?1049l\x1b[23;0;0t", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[<", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/a/ansi/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/a/ansi/term.go deleted file mode 100644 index 24370a777..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/a/ansi/term.go +++ /dev/null @@ -1,32 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package ansi - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // ansi/pc-term compatible with color - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "ansi", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[J", - AttrOff: "\x1b[0;10m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "+\x10,\x11-\x18.\x190\xdb`\x04a\xb1f\xf8g\xf1h\xb0j\xd9k\xbfl\xdam\xc0n\xc5o~p\xc4q\xc4r\xc4s_t\xc3u\xb4v\xc1w\xc2x\xb3y\xf3z\xf2{\xe3|\xd8}\x9c~\xfe", - EnterAcs: "\x1b[11m", - ExitAcs: "\x1b[10m", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/base/base.go b/vendor/github.com/gdamore/tcell/v2/terminfo/base/base.go deleted file mode 100644 index 75aeb15f2..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/base/base.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 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. - -// This is just a "minimalist" set of the base terminal descriptions. -// It should be sufficient for most applications. - -// Package base contains the base terminal descriptions that are likely -// to be needed by any stock application. It is imported by default in the -// terminfo package, so terminal types listed here will be available to any -// tcell application. -package base - -import ( - // The following imports just register themselves -- - // these are the terminal types we aggregate in this package. - _ "github.com/gdamore/tcell/v2/terminfo/a/ansi" - _ "github.com/gdamore/tcell/v2/terminfo/t/tmux" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt100" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt102" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt220" - _ "github.com/gdamore/tcell/v2/terminfo/x/xterm" -) diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/c/cygwin/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/c/cygwin/term.go deleted file mode 100644 index 1ea431626..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/c/cygwin/term.go +++ /dev/null @@ -1,32 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package cygwin - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // ANSI emulation for Cygwin - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "cygwin", - Colors: 8, - Clear: "\x1b[H\x1b[J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - AttrOff: "\x1b[0;10m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Reverse: "\x1b[7m", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "+\x10,\x11-\x18.\x190\xdb`\x04a\xb1f\xf8g\xf1h\xb0j\xd9k\xbfl\xdam\xc0n\xc5o~p\xc4q\xc4r\xc4s_t\xc3u\xb4v\xc1w\xc2x\xb3y\xf3z\xf2{\xe3|\xd8}\x9c~\xfe", - EnterAcs: "\x1b[11m", - ExitAcs: "\x1b[10m", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - InsertChar: "\x1b[@", - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/d/dtterm/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/d/dtterm/term.go deleted file mode 100644 index b4e49b76f..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/d/dtterm/term.go +++ /dev/null @@ -1,38 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package dtterm - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // CDE desktop terminal - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "dtterm", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[J", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/dynamic/dynamic.go b/vendor/github.com/gdamore/tcell/v2/terminfo/dynamic/dynamic.go deleted file mode 100644 index 8bc0dbb7a..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/dynamic/dynamic.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2021 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. - -// The dynamic package is used to generate a terminal description dynamically, -// using infocmp. This is really a method of last resort, as the performance -// will be slow, and it requires a working infocmp. But, the hope is that it -// will assist folks who have to deal with a terminal description that isn't -// already built in. This requires infocmp to be in the user's path, and to -// support reasonably the -1 option. - -package dynamic - -import ( - "bytes" - "errors" - "fmt" - "os/exec" - "regexp" - "strconv" - "strings" - - "github.com/gdamore/tcell/v2/terminfo" -) - -type termcap struct { - name string - desc string - aliases []string - bools map[string]bool - nums map[string]int - strs map[string]string -} - -func (tc *termcap) getnum(s string) int { - return (tc.nums[s]) -} - -func (tc *termcap) getflag(s string) bool { - return (tc.bools[s]) -} - -func (tc *termcap) getstr(s string) string { - return (tc.strs[s]) -} - -const ( - none = iota - control - escaped -) - -var errNotAddressable = errors.New("terminal not cursor addressable") - -func unescape(s string) string { - // Various escapes are in \x format. Control codes are - // encoded as ^M (carat followed by ASCII equivalent). - // escapes are: \e, \E - escape - // \0 NULL, \n \l \r \t \b \f \s for equivalent C escape. - buf := &bytes.Buffer{} - esc := none - - for i := 0; i < len(s); i++ { - c := s[i] - switch esc { - case none: - switch c { - case '\\': - esc = escaped - case '^': - esc = control - default: - buf.WriteByte(c) - } - case control: - buf.WriteByte(c ^ 1<<6) - esc = none - case escaped: - switch c { - case 'E', 'e': - buf.WriteByte(0x1b) - case '0', '1', '2', '3', '4', '5', '6', '7': - if i+2 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' && s[i+2] >= '0' && s[i+2] <= '7' { - buf.WriteByte(((c - '0') * 64) + ((s[i+1] - '0') * 8) + (s[i+2] - '0')) - i = i + 2 - } else if c == '0' { - buf.WriteByte(0) - } - case 'n': - buf.WriteByte('\n') - case 'r': - buf.WriteByte('\r') - case 't': - buf.WriteByte('\t') - case 'b': - buf.WriteByte('\b') - case 'f': - buf.WriteByte('\f') - case 's': - buf.WriteByte(' ') - default: - buf.WriteByte(c) - } - esc = none - } - } - return (buf.String()) -} - -func (tc *termcap) setupterm(name string) error { - cmd := exec.Command("infocmp", "-1", name) - output := &bytes.Buffer{} - cmd.Stdout = output - - tc.strs = make(map[string]string) - tc.bools = make(map[string]bool) - tc.nums = make(map[string]int) - - if err := cmd.Run(); err != nil { - return fmt.Errorf("couldn't open terminfo ($TERM) file for %s: %w", name, err) - } - - // Now parse the output. - // We get comment lines (starting with "#"), followed by - // a header line that looks like "||...|" - // then capabilities, one per line, starting with a tab and ending - // with a comma and newline. - lines := strings.Split(output.String(), "\n") - for len(lines) > 0 && strings.HasPrefix(lines[0], "#") { - lines = lines[1:] - } - - // Ditch trailing empty last line - if lines[len(lines)-1] == "" { - lines = lines[:len(lines)-1] - } - header := lines[0] - header = strings.TrimSuffix(header, ",") - names := strings.Split(header, "|") - tc.name = names[0] - names = names[1:] - if len(names) > 0 { - tc.desc = names[len(names)-1] - names = names[:len(names)-1] - } - tc.aliases = names - for _, val := range lines[1:] { - if (!strings.HasPrefix(val, "\t")) || - (!strings.HasSuffix(val, ",")) { - return (errors.New("malformed infocmp: " + val)) - } - - val = val[1:] - val = val[:len(val)-1] - - if k := strings.SplitN(val, "=", 2); len(k) == 2 { - tc.strs[k[0]] = unescape(k[1]) - } else if k := strings.SplitN(val, "#", 2); len(k) == 2 { - u, err := strconv.ParseUint(k[1], 0, 0) - if err != nil { - return (err) - } - tc.nums[k[0]] = int(u) - } else { - tc.bools[val] = true - } - } - return nil -} - -// LoadTerminfo creates a Terminfo by for named terminal by attempting to parse -// the output from infocmp. This returns the terminfo entry, a description of -// the terminal, and either nil or an error. -func LoadTerminfo(name string) (*terminfo.Terminfo, string, error) { - var tc termcap - if err := tc.setupterm(name); err != nil { - return nil, "", err - } - t := &terminfo.Terminfo{} - t.Name = tc.name - t.Aliases = tc.aliases - t.Colors = tc.getnum("colors") - t.Columns = tc.getnum("cols") - t.Lines = tc.getnum("lines") - t.Clear = tc.getstr("clear") - t.EnterCA = tc.getstr("smcup") - t.ExitCA = tc.getstr("rmcup") - t.ShowCursor = tc.getstr("cnorm") - t.HideCursor = tc.getstr("civis") - t.AttrOff = tc.getstr("sgr0") - t.Underline = tc.getstr("smul") - t.Bold = tc.getstr("bold") - t.Blink = tc.getstr("blink") - t.Dim = tc.getstr("dim") - t.Italic = tc.getstr("sitm") - t.Reverse = tc.getstr("rev") - t.EnterKeypad = tc.getstr("smkx") - t.ExitKeypad = tc.getstr("rmkx") - t.SetFg = tc.getstr("setaf") - t.SetBg = tc.getstr("setab") - t.SetCursor = tc.getstr("cup") - t.AltChars = tc.getstr("acsc") - t.EnterAcs = tc.getstr("smacs") - t.ExitAcs = tc.getstr("rmacs") - t.EnableAcs = tc.getstr("enacs") - t.Mouse = tc.getstr("kmous") - - // Technically the RGB flag that is provided for xterm-direct is not - // quite right. The problem is that the -direct flag that was introduced - // with ncurses 6.1 requires a parsing for the parameters that we lack. - // For this case we'll just assume it's XTerm compatible. Someday this - // may be incorrect, but right now it is correct, and nobody uses it - // anyway. - if tc.getflag("Tc") { - // This presumes XTerm 24-bit true color. - t.TrueColor = true - } else if tc.getflag("RGB") { - // This is for xterm-direct, which uses a different scheme entirely. - // (ncurses went a very different direction from everyone else, and - // so it's unlikely anything is using this definition.) - t.TrueColor = true - t.SetBg = "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m" - t.SetFg = "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m" - } - - // We only support colors in ANSI 8 or 256 color mode. - if t.Colors < 8 || t.SetFg == "" { - t.Colors = 0 - } - if t.SetCursor == "" { - return nil, "", errNotAddressable - } - - // For padding, we lookup the pad char. If that isn't present, - // and npc is *not* set, then we assume a null byte. - t.PadChar = tc.getstr("pad") - if t.PadChar == "" { - if !tc.getflag("npc") { - t.PadChar = "\u0000" - } - } - - // For terminals that use "standard" SGR sequences, lets combine the - // foreground and background together. - if strings.HasPrefix(t.SetFg, "\x1b[") && - strings.HasPrefix(t.SetBg, "\x1b[") && - strings.HasSuffix(t.SetFg, "m") && - strings.HasSuffix(t.SetBg, "m") { - fg := t.SetFg[:len(t.SetFg)-1] - r := regexp.MustCompile("%p1") - bg := r.ReplaceAllString(t.SetBg[2:], "%p2") - t.SetFgBg = fg + ";" + bg - } - - return t, tc.desc, nil -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/e/emacs/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/e/emacs/term.go deleted file mode 100644 index 80358b553..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/e/emacs/term.go +++ /dev/null @@ -1,48 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package emacs - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // GNU Emacs term.el terminal emulation - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "eterm", - Columns: 80, - Lines: 24, - Clear: "\x1b[H\x1b[J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - AttrOff: "\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Reverse: "\x1b[7m", - PadChar: "\x00", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) - - // Emacs term.el terminal emulator term-protocol-version 0.96 - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "eterm-color", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - AttrOff: "\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - SetFg: "\x1b[%p1%{30}%+%dm", - SetBg: "\x1b[%p1%'('%+%dm", - SetFgBg: "\x1b[%p1%{30}%+%d;%p2%'('%+%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/extended/extended.go b/vendor/github.com/gdamore/tcell/v2/terminfo/extended/extended.go deleted file mode 100644 index 3b75d8e15..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/extended/extended.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2024 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 extended contains an extended set of terminal descriptions. -// Applications desiring to have a better chance of Just Working by -// default should include this package. This will significantly increase -// the size of the program. -package extended - -import ( - // The following imports just register themselves -- - // these are the terminal types we aggregate in this package. - _ "github.com/gdamore/tcell/v2/terminfo/a/aixterm" - _ "github.com/gdamore/tcell/v2/terminfo/a/alacritty" - _ "github.com/gdamore/tcell/v2/terminfo/a/ansi" - _ "github.com/gdamore/tcell/v2/terminfo/c/cygwin" - _ "github.com/gdamore/tcell/v2/terminfo/d/dtterm" - _ "github.com/gdamore/tcell/v2/terminfo/e/emacs" - _ "github.com/gdamore/tcell/v2/terminfo/f/foot" - _ "github.com/gdamore/tcell/v2/terminfo/g/gnome" - _ "github.com/gdamore/tcell/v2/terminfo/k/konsole" - _ "github.com/gdamore/tcell/v2/terminfo/k/kterm" - _ "github.com/gdamore/tcell/v2/terminfo/l/linux" - _ "github.com/gdamore/tcell/v2/terminfo/p/pcansi" - _ "github.com/gdamore/tcell/v2/terminfo/r/rxvt" - _ "github.com/gdamore/tcell/v2/terminfo/s/screen" - _ "github.com/gdamore/tcell/v2/terminfo/s/simpleterm" - _ "github.com/gdamore/tcell/v2/terminfo/s/sun" - _ "github.com/gdamore/tcell/v2/terminfo/t/tmux" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt100" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt102" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt220" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt320" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt400" - _ "github.com/gdamore/tcell/v2/terminfo/v/vt420" - _ "github.com/gdamore/tcell/v2/terminfo/x/xfce" - _ "github.com/gdamore/tcell/v2/terminfo/x/xterm" - _ "github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty" - _ "github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty" -) diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/f/foot/foot.go b/vendor/github.com/gdamore/tcell/v2/terminfo/f/foot/foot.go deleted file mode 100644 index a07572738..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/f/foot/foot.go +++ /dev/null @@ -1,42 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package foot - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // foot terminal emulator - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "foot", - Aliases: []string{"foot-extra"}, - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h\x1b[22;0;0t", - ExitCA: "\x1b[?1049l\x1b[23;0;0t", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38:5:%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48:5:%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/g/gnome/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/g/gnome/term.go deleted file mode 100644 index 29565169d..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/g/gnome/term.go +++ /dev/null @@ -1,80 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package gnome - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // GNOME Terminal - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "gnome", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[0m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // GNOME Terminal with xterm 256-colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "gnome-256color", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[0m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/gen.sh b/vendor/github.com/gdamore/tcell/v2/terminfo/gen.sh deleted file mode 100644 index 851175a3f..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/gen.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -while read line -do - case "$line" in - *'|'*) - alias=${line#*|} - line=${line%|*} - ;; - *) - alias=${line%%,*} - ;; - esac - - alias=${alias//-/_} - direc=${alias:0:1} - - mkdir -p ${direc}/${alias} - go run mkinfo.go -P ${alias} -go ${direc}/${alias}/term.go ${line//,/ } -done < models.txt diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/k/konsole/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/k/konsole/term.go deleted file mode 100644 index 88dad2f17..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/k/konsole/term.go +++ /dev/null @@ -1,82 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package konsole - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // KDE console window - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "konsole", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[0m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[<", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // KDE console window with xterm 256-colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "konsole-256color", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[0m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[<", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/k/kterm/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/k/kterm/term.go deleted file mode 100644 index a402ab9da..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/k/kterm/term.go +++ /dev/null @@ -1,39 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package kterm - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // kterm kanji terminal emulator (X window system) - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "kterm", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - AttrOff: "\x1b[m\x1b(B", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aajjkkllmmnnooppqqrrssttuuvvwwxx~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/l/linux/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/l/linux/term.go deleted file mode 100644 index 250c8e4b8..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/l/linux/term.go +++ /dev/null @@ -1,38 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package linux - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // Linux console - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "linux", - Colors: 8, - Clear: "\x1b[H\x1b[J", - ShowCursor: "\x1b[?25h\x1b[?0c", - HideCursor: "\x1b[?25l\x1b[?1c", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - InsertChar: "\x1b[@", - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/models.txt b/vendor/github.com/gdamore/tcell/v2/terminfo/models.txt deleted file mode 100644 index f12a8dbca..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/models.txt +++ /dev/null @@ -1,29 +0,0 @@ -aixterm -alacritty -ansi -cygwin -dtterm -eterm,eterm-color|emacs -gnome,gnome-256color -hpterm -konsole,konsole-256color -kterm -linux -pcansi -rxvt,rxvt-256color,rxvt-88color,rxvt-unicode,rxvt-unicode-256color -screen,screen-256color -st,st-256color|simpleterm -tmux,tmux-256color -vt100 -vt102 -vt220 -vt320 -vt400 -vt420 -wy50 -wy60 -wy99-ansi,wy99a-ansi -xfce -xterm,xterm-88color,xterm-256color -xterm-ghostty -xterm-kitty diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/p/pcansi/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/p/pcansi/term.go deleted file mode 100644 index a6050176e..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/p/pcansi/term.go +++ /dev/null @@ -1,32 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package pcansi - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // ibm-pc terminal programs claiming to be ANSI - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "pcansi", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[J", - AttrOff: "\x1b[0;10m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[37;40m", - PadChar: "\x00", - AltChars: "+\x10,\x11-\x18.\x190\xdb`\x04a\xb1f\xf8g\xf1h\xb0j\xd9k\xbfl\xdam\xc0n\xc5o~p\xc4q\xc4r\xc4s_t\xc3u\xb4v\xc1w\xc2x\xb3y\xf3z\xf2{\xe3|\xd8}\x9c~\xfe", - EnterAcs: "\x1b[12m", - ExitAcs: "\x1b[10m", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/r/rxvt/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/r/rxvt/term.go deleted file mode 100644 index 1a9f6884c..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/r/rxvt/term.go +++ /dev/null @@ -1,176 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package rxvt - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // rxvt terminal emulator (X Window System) - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "rxvt", - Aliases: []string{"rxvt-color"}, - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b=", - ExitKeypad: "\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // rxvt 2.7.9 with xterm 256-colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "rxvt-256color", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b=", - ExitKeypad: "\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // rxvt 2.7.9 with xterm 88-colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "rxvt-88color", - Columns: 80, - Lines: 24, - Colors: 88, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b=", - ExitKeypad: "\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // rxvt-unicode terminal (X Window System) - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "rxvt-unicode", - Columns: 80, - Lines: 24, - Colors: 88, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[r\x1b[?1049l", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x1b(B", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b=", - ExitKeypad: "\x1b>", - SetFg: "\x1b[38;5;%p1%dm", - SetBg: "\x1b[48;5;%p1%dm", - SetFgBg: "\x1b[38;5;%p1%d;48;5;%p2%dm", - ResetFgBg: "\x1b[39;49m", - AltChars: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - InsertChar: "\x1b[@", - }) - - // rxvt-unicode terminal with 256 colors (X Window System) - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "rxvt-unicode-256color", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[r\x1b[?1049l", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x1b(B", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b=", - ExitKeypad: "\x1b>", - SetFg: "\x1b[38;5;%p1%dm", - SetBg: "\x1b[48;5;%p1%dm", - SetFgBg: "\x1b[38;5;%p1%d;48;5;%p2%dm", - ResetFgBg: "\x1b[39;49m", - AltChars: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - InsertChar: "\x1b[@", - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/s/screen/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/s/screen/term.go deleted file mode 100644 index 4d5065498..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/s/screen/term.go +++ /dev/null @@ -1,74 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package screen - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // VT 100/ANSI X3.64 virtual terminal - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "screen", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[34h\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) - - // GNU Screen with 256 colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "screen-256color", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[34h\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/s/simpleterm/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/s/simpleterm/term.go deleted file mode 100644 index a0640ac68..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/s/simpleterm/term.go +++ /dev/null @@ -1,80 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package simpleterm - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // aka simpleterm - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "st", - Aliases: []string{"stterm"}, - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[0m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - AltChars: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAcs: "\x1b)0", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // simpleterm with 256 colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "st-256color", - Aliases: []string{"stterm-256color"}, - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[0m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAcs: "\x1b)0", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/s/sun/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/s/sun/term.go deleted file mode 100644 index 52327bccb..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/s/sun/term.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2021 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. - -// This terminal definition is hand-coded, as the default terminfo for -// this terminal is busted with respect to color. Unlike pretty much every -// other ANSI compliant terminal, this terminal cannot combine foreground and -// background escapes. The default terminfo also only provides escapes for -// 16-bit color. - -package sun - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // Sun Microsystems Inc. workstation console - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "sun", - Aliases: []string{"sun1", "sun2"}, - Columns: 80, - Lines: 34, - Clear: "\f", - AttrOff: "\x1b[m", - Reverse: "\x1b[7m", - PadChar: "\x00", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - InsertChar: "\x1b[@", - }) - - // Sun Microsystems Workstation console with color support (IA systems) - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "sun-color", - Columns: 80, - Lines: 34, - Colors: 256, - Clear: "\f", - AttrOff: "\x1b[m", - Bold: "\x1b[1m", - Reverse: "\x1b[7m", - SetFg: "\x1b[38;5;%p1%dm", - SetBg: "\x1b[48;5;%p1%dm", - ResetFgBg: "\x1b[0m", - PadChar: "\x00", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - InsertChar: "\x1b[@", - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/t/tmux/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/t/tmux/term.go deleted file mode 100644 index 5f4c87176..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/t/tmux/term.go +++ /dev/null @@ -1,80 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package tmux - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // tmux terminal multiplexer - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "tmux", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[34h\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // tmux with 256 colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "tmux-256color", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[34h\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/terminfo.go b/vendor/github.com/gdamore/tcell/v2/terminfo/terminfo.go deleted file mode 100644 index 2e1e5638c..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/terminfo.go +++ /dev/null @@ -1,628 +0,0 @@ -// Copyright 2025 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 - 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 - PadChar string // pad - Mouse string // kmous - AltChars string // acsc - EnterAcs string // smacs - ExitAcs string // rmacs - EnableAcs string // enacs - - // 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 - 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 - DisableAutoMargin string // smam - EnableAutoMargin string // rmam - XTermLike bool // (XT) has XTerm extensions -} - -type stack []any - -func (st stack) Push(v any) 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 ...any) string { - var stk stack - var a string - var ai, bi int - var dvars [26]string - var params [9]any - 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 -} - -func TerminfoNames() []string { - res := make([]string, 0, len(terminfos)) - for m := range terminfos { - res = append(res, m) - } - return res -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt100/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt100/term.go deleted file mode 100644 index ddd09efa3..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt100/term.go +++ /dev/null @@ -1,33 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package vt100 - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // DEC VT100 (w/advanced video) - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "vt100", - Aliases: []string{"vt100-am"}, - Columns: 80, - Lines: 24, - Clear: "\x1b[H\x1b[J$<50>", - AttrOff: "\x1b[m\x0f$<2>", - Underline: "\x1b[4m$<2>", - Bold: "\x1b[1m$<2>", - Blink: "\x1b[5m$<2>", - Reverse: "\x1b[7m$<2>", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - SetCursor: "\x1b[%i%p1%d;%p2%dH$<5>", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt102/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt102/term.go deleted file mode 100644 index df5d23d98..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt102/term.go +++ /dev/null @@ -1,32 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package vt102 - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // DEC VT102 - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "vt102", - Columns: 80, - Lines: 24, - Clear: "\x1b[H\x1b[J$<50>", - AttrOff: "\x1b[m\x0f$<2>", - Underline: "\x1b[4m$<2>", - Bold: "\x1b[1m$<2>", - Blink: "\x1b[5m$<2>", - Reverse: "\x1b[7m$<2>", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b(B\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - SetCursor: "\x1b[%i%p1%d;%p2%dH$<5>", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt220/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt220/term.go deleted file mode 100644 index b851993a2..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt220/term.go +++ /dev/null @@ -1,33 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package vt220 - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // DEC VT220 - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "vt220", - Aliases: []string{"vt200"}, - Columns: 80, - Lines: 24, - Clear: "\x1b[H\x1b[J", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x1b(B", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0$<2>", - ExitAcs: "\x1b(B$<4>", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt320/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt320/term.go deleted file mode 100644 index d50a2d7d8..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt320/term.go +++ /dev/null @@ -1,34 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package vt320 - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // DEC VT320 7 bit terminal - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "vt320", - Aliases: []string{"vt300"}, - Columns: 80, - Lines: 24, - Clear: "\x1b[H\x1b[2J", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x1b(B", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt400/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt400/term.go deleted file mode 100644 index 573eae8fe..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt400/term.go +++ /dev/null @@ -1,35 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package vt400 - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // DEC VT400 24x80 column autowrap - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "vt400", - Aliases: []string{"vt400-24", "dec-vt400"}, - Columns: 80, - Lines: 24, - Clear: "\x1b[H\x1b[J$<10/>", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x1b(B", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - InsertChar: "\x1b[@", - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt420/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt420/term.go deleted file mode 100644 index 275f9b59a..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/v/vt420/term.go +++ /dev/null @@ -1,37 +0,0 @@ -// This file was originally generated automatically, -// but it is edited to correct for errors in the VT420 -// terminfo data. Additionally we have added extended -// information for the extended F-keys. - -package vt420 - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // DEC VT420 - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "vt420", - Columns: 80, - Lines: 24, - Clear: "\x1b[H\x1b[2J$<50>", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[m\x1b(B$<2>", - Underline: "\x1b[4m", - Bold: "\x1b[1m$<2>", - Blink: "\x1b[5m$<2>", - Reverse: "\x1b[7m$<2>", - EnterKeypad: "\x1b=", - ExitKeypad: "\x1b>", - PadChar: "\x00", - AltChars: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0$<2>", - ExitAcs: "\x1b(B$<4>", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - SetCursor: "\x1b[%i%p1%d;%p2%dH$<10>", - AutoMargin: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xfce/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/x/xfce/term.go deleted file mode 100644 index 1a4490091..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xfce/term.go +++ /dev/null @@ -1,42 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package xfce - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // Xfce Terminal - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "xfce", - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b7\x1b[?47h", - ExitCA: "\x1b[2J\x1b[?47l\x1b8", - ShowCursor: "\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b[0m\x0f", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - PadChar: "\x00", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x0e", - ExitAcs: "\x0f", - EnableAcs: "\x1b)0", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm/direct.go b/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm/direct.go deleted file mode 100644 index 18917f14a..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm/direct.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2021 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. - -// This terminal definition is derived from the xterm-256color definition, but -// makes use of the RGB property these terminals have to support direct color. -// The terminfo entry for this uses a new format for the color handling introduced -// by ncurses 6.1 (and used by nobody else), so this override ensures we get -// good handling even in the face of this. - -package xterm - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // derived from xterm-256color, but adds full RGB support - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "xterm-direct", - Aliases: []string{"xterm-truecolor"}, - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h\x1b[22;0;0t", - ExitCA: "\x1b[?1049l\x1b[23;0;0t", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - SetFgRGB: "\x1b[38;2;%p1%d;%p2%d;%p3%dm", - SetBgRGB: "\x1b[48;2;%p1%d;%p2%d;%p3%dm", - SetFgBgRGB: "\x1b[38;2;%p1%d;%p2%d;%p3%d;48;2;%p4%d;%p5%d;%p6%dm", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - TrueColor: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm/term.go deleted file mode 100644 index 7595f51e0..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm/term.go +++ /dev/null @@ -1,117 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package xterm - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // xterm terminal emulator (X Window System) - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "xterm", - Aliases: []string{"xterm-debian"}, - Columns: 80, - Lines: 24, - Colors: 8, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h\x1b[22;0;0t", - ExitCA: "\x1b[?1049l\x1b[23;0;0t", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[3%p1%dm", - SetBg: "\x1b[4%p1%dm", - SetFgBg: "\x1b[3%p1%d;4%p2%dm", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[<", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // xterm with 88 colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "xterm-88color", - Columns: 80, - Lines: 24, - Colors: 88, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h\x1b[22;0;0t", - ExitCA: "\x1b[?1049l\x1b[23;0;0t", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[<", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) - - // xterm with 256 colors - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "xterm-256color", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h\x1b[22;0;0t", - ExitCA: "\x1b[?1049l\x1b[23;0;0t", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[<", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty/term.go deleted file mode 100644 index c57951212..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty/term.go +++ /dev/null @@ -1,47 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package xterm_ghostty - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // Ghostty - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "xterm-ghostty", - Aliases: []string{"ghostty"}, - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[?12l\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h\x1b=", - ExitKeypad: "\x1b[?1l\x1b>", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[<", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - TrueColor: true, - AutoMargin: true, - InsertChar: "\x1b[@", - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty/term.go b/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty/term.go deleted file mode 100644 index f7edaf3aa..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty/term.go +++ /dev/null @@ -1,44 +0,0 @@ -// Generated automatically. DO NOT HAND-EDIT. - -package xterm_kitty - -import "github.com/gdamore/tcell/v2/terminfo" - -func init() { - - // KovIdTTY - terminfo.AddTerminfo(&terminfo.Terminfo{ - Name: "xterm-kitty", - Columns: 80, - Lines: 24, - Colors: 256, - Clear: "\x1b[H\x1b[2J", - EnterCA: "\x1b[?1049h", - ExitCA: "\x1b[?1049l", - ShowCursor: "\x1b[?12h\x1b[?25h", - HideCursor: "\x1b[?25l", - AttrOff: "\x1b(B\x1b[m", - Underline: "\x1b[4m", - Bold: "\x1b[1m", - Dim: "\x1b[2m", - Italic: "\x1b[3m", - Reverse: "\x1b[7m", - EnterKeypad: "\x1b[?1h", - ExitKeypad: "\x1b[?1l", - SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", - SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", - 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", - ResetFgBg: "\x1b[39;49m", - AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", - EnterAcs: "\x1b(0", - ExitAcs: "\x1b(B", - EnableAutoMargin: "\x1b[?7h", - DisableAutoMargin: "\x1b[?7l", - StrikeThrough: "\x1b[9m", - Mouse: "\x1b[M", - SetCursor: "\x1b[%i%p1%d;%p2%dH", - TrueColor: true, - AutoMargin: true, - XTermLike: true, - }) -} diff --git a/vendor/github.com/gdamore/tcell/v2/terms_dynamic.go b/vendor/github.com/gdamore/tcell/v2/terms_dynamic.go deleted file mode 100644 index 9e5494498..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terms_dynamic.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build !tcell_minimal && !nacl && !js && !zos && !plan9 && !windows && !android -// +build !tcell_minimal,!nacl,!js,!zos,!plan9,!windows,!android - -// Copyright 2019 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 tcell - -import ( - // This imports a dynamic version of the terminal database, which - // is built using infocmp. This relies on a working installation - // of infocmp (typically supplied with ncurses). We only do this - // for systems likely to have that -- i.e. UNIX based hosts. We - // also don't support Android here, because you really don't want - // to run external programs there. Generally the android terminals - // will be automatically included anyway. - "github.com/gdamore/tcell/v2/terminfo" - "github.com/gdamore/tcell/v2/terminfo/dynamic" - - "fmt" -) - -func loadDynamicTerminfo(term string) (*terminfo.Terminfo, error) { - if term == "" { - return nil, fmt.Errorf("%w: term not set", ErrTermNotFound) - } - ti, _, e := dynamic.LoadTerminfo(term) - if e != nil { - return nil, e - } - return ti, nil -} diff --git a/vendor/github.com/gdamore/tcell/v2/terms_static.go b/vendor/github.com/gdamore/tcell/v2/terms_static.go deleted file mode 100644 index 6d725cbcc..000000000 --- a/vendor/github.com/gdamore/tcell/v2/terms_static.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build tcell_minimal || nacl || zos || plan9 || windows || android || js -// +build tcell_minimal nacl zos plan9 windows android js - -// Copyright 2019 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 tcell - -import ( - "errors" - - "github.com/gdamore/tcell/v2/terminfo" -) - -func loadDynamicTerminfo(_ string) (*terminfo.Terminfo, error) { - return nil, errors.New("terminal type unsupported") -} diff --git a/vendor/github.com/gdamore/tcell/v2/tscreen.go b/vendor/github.com/gdamore/tcell/v2/tscreen.go deleted file mode 100644 index 7dc7cdf81..000000000 --- a/vendor/github.com/gdamore/tcell/v2/tscreen.go +++ /dev/null @@ -1,1317 +0,0 @@ -// Copyright 2025 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. - -//go:build !(js && wasm) -// +build !js !wasm - -package tcell - -import ( - "bytes" - "encoding/base64" - "errors" - "io" - "maps" - "os" - "runtime" - "strconv" - "strings" - "sync" - "unicode/utf8" - - "golang.org/x/term" - "golang.org/x/text/transform" - - "github.com/gdamore/tcell/v2/terminfo" -) - -// NewTerminfoScreen returns a Screen that uses the stock TTY interface -// and POSIX terminal control, combined with a terminfo description taken from -// the $TERM environment variable. It returns an error if the terminal -// is not supported for any reason. -// -// For terminals that do not support dynamic resize events, the $LINES -// $COLUMNS environment variables can be set to the actual window size, -// otherwise defaults taken from the terminal database are used. -func NewTerminfoScreen() (Screen, error) { - return NewTerminfoScreenFromTty(nil) -} - -// LookupTerminfo attempts to find a definition for the named $TERM falling -// back to attempting to parse the output from infocmp. -func LookupTerminfo(name string) (ti *terminfo.Terminfo, e error) { - ti, e = terminfo.LookupTerminfo(name) - if e != nil { - ti, e = loadDynamicTerminfo(name) - if e != nil { - return nil, e - } - terminfo.AddTerminfo(ti) - } - - return -} - -var defaultTerm string - -// NewTerminfoScreenFromTtyTerminfo returns a Screen using a custom Tty -// implementation and custom terminfo specification. -// If the passed in tty is nil, then a reasonable default (typically /dev/tty) -// is presumed, at least on UNIX hosts. (Windows hosts will typically fail this -// call altogether.) -// If passed terminfo is nil, then TERM environment variable is queried for -// terminal specification. -func NewTerminfoScreenFromTtyTerminfo(tty Tty, ti *terminfo.Terminfo) (s Screen, e error) { - term := defaultTerm - if term == "" { - term = os.Getenv("TERM") - } - if ti == nil { - ti, e = LookupTerminfo(term) - if e != nil { - return nil, e - } - } - - t := &tScreen{ti: ti, tty: tty} - - if len(ti.Mouse) > 0 { - t.mouse = []byte(ti.Mouse) - } - t.prepareKeys() - t.buildAcsMap() - t.resizeQ = make(chan bool, 1) - t.fallback = make(map[rune]string) - maps.Copy(t.fallback, RuneFallbacks) - - return &baseScreen{screenImpl: t}, nil -} - -// NewTerminfoScreenFromTty returns a Screen using a custom Tty implementation. -// If the passed in tty is nil, then a reasonable default (typically /dev/tty) -// is presumed, at least on UNIX hosts. (Windows hosts will typically fail this -// call altogether.) -func NewTerminfoScreenFromTty(tty Tty) (Screen, error) { - return NewTerminfoScreenFromTtyTerminfo(tty, nil) -} - -// tKeyCode represents a combination of a key code and modifiers. -type tKeyCode struct { - key Key - mod ModMask -} - -// tScreen represents a screen backed by a terminfo implementation. -type tScreen struct { - ti *terminfo.Terminfo - tty Tty - h int - w int - fini bool - cells CellBuffer - buffering bool // true if we are collecting writes to buf instead of sending directly to out - buf bytes.Buffer - curstyle Style - style Style - resizeQ chan bool - quit chan struct{} - keychan chan []byte - cx int - cy int - mouse []byte - clear bool - cursorx int - cursory int - acs map[rune]string - charset string - encoder transform.Transformer - decoder transform.Transformer - fallback map[rune]string - colors map[Color]Color - palette []Color - truecolor bool - escaped bool - buttondn bool - finiOnce sync.Once - enablePaste string - disablePaste string - enterUrl string - exitUrl string - setWinSize string - enableFocus string - disableFocus string - doubleUnder string - curlyUnder string - dottedUnder string - dashedUnder string - underColor string - underRGB string - underFg string // reset underline color to foreground - cursorStyles map[CursorStyle]string - cursorStyle CursorStyle - cursorColor Color - cursorRGB string - cursorFg string - saved *term.State - stopQ chan struct{} - eventQ chan Event - running bool - wg sync.WaitGroup - mouseFlags MouseFlags - pasteEnabled bool - focusEnabled bool - setTitle string - saveTitle string - restoreTitle string - title string - setClipboard string - startSyncOut string - endSyncOut string - enableCsiU string - disableCsiU string - disableEmojiWA bool // if true don't try to workaround emoji bugs - input InputProcessor - - sync.Mutex -} - -func (t *tScreen) Init() error { - if e := t.initialize(); e != nil { - return e - } - - t.keychan = make(chan []byte, 10) - - t.charset = getCharset() - if enc := GetEncoding(t.charset); enc != nil { - t.encoder = enc.NewEncoder() - t.decoder = enc.NewDecoder() - } else { - return ErrNoCharset - } - ti := t.ti - - // environment overrides - w := ti.Columns - h := ti.Lines - if i, _ := strconv.Atoi(os.Getenv("LINES")); i != 0 { - h = i - } - if i, _ := strconv.Atoi(os.Getenv("COLUMNS")); i != 0 { - w = i - } - if t.ti.SetFgBgRGB != "" || t.ti.SetFgRGB != "" || t.ti.SetBgRGB != "" { - t.truecolor = true - } - // A user who wants to have his themes honored can - // set this environment variable. - if os.Getenv("TCELL_TRUECOLOR") == "disable" { - t.truecolor = false - } - // clip to reasonable limits - nColors := min(t.nColors(), 256) - t.colors = make(map[Color]Color, nColors) - t.palette = make([]Color, nColors) - for i := range nColors { - t.palette[i] = Color(i) | ColorValid - // identity map for our builtin colors - t.colors[Color(i)|ColorValid] = Color(i) | ColorValid - } - - t.quit = make(chan struct{}) - t.eventQ = make(chan Event, 256) - t.input = NewInputProcessor(t.eventQ) - - t.Lock() - t.cx = -1 - t.cy = -1 - t.style = StyleDefault - t.cells.Resize(w, h) - t.cursorx = -1 - t.cursory = -1 - t.resize() - t.Unlock() - - if err := t.engage(); err != nil { - return err - } - - return nil -} - -func (t *tScreen) prepareBracketedPaste() { - // Another workaround for lack of reporting in terminfo. - // We assume if the terminal has a mouse entry, that it - // offers bracketed paste. But we allow specific overrides - // via our terminal database. - if t.ti.Mouse != "" || t.ti.XTermLike { - t.enablePaste = "\x1b[?2004h" - t.disablePaste = "\x1b[?2004l" - } -} - -func (t *tScreen) prepareUnderlines() { - if t.ti.XTermLike { - t.doubleUnder = "\x1b[4:2m" - t.curlyUnder = "\x1b[4:3m" - t.dottedUnder = "\x1b[4:4m" - t.dashedUnder = "\x1b[4:5m" - t.underColor = "\x1b[58:5:%p1%dm" - t.underRGB = "\x1b[58:2::%p1%d:%p2%d:%p3%dm" - t.underFg = "\x1b[59m" - } -} - -func (t *tScreen) prepareExtendedOSC() { - // Linux is a special beast - because it has a mouse entry, but does - // not swallow these OSC commands properly. - if strings.Contains(t.ti.Name, "linux") { - return - } - // More stuff for limits in terminfo. This time we are applying - // the most common OSC (operating system commands). Generally - // terminals that don't understand these will ignore them. - // Again, we condition this based on mouse capabilities. - if t.ti.Mouse != "" || t.ti.XTermLike { - t.enterUrl = "\x1b]8;%p2%s;%p1%s\x1b\\" - t.exitUrl = "\x1b]8;;\x1b\\" - } - - if t.ti.Mouse != "" || t.ti.XTermLike { - t.setWinSize = "\x1b[8;%p1%p2%d;%dt" - } - - if t.ti.Mouse != "" || t.ti.XTermLike { - t.enableFocus = "\x1b[?1004h" - t.disableFocus = "\x1b[?1004l" - } - - if t.ti.XTermLike { - t.saveTitle = "\x1b[22;2t" - t.restoreTitle = "\x1b[23;2t" - // this also tries to request that UTF-8 is allowed in the title - t.setTitle = "\x1b[>2t\x1b]2;%p1%s\x1b\\" - } - - if t.setClipboard == "" && t.ti.XTermLike { - // this string takes a base64 string and sends it to the clipboard. - // it will also be able to retrieve the clipboard using "?" as the - // sent string, when we support that. - t.setClipboard = "\x1b]52;c;%p1%s\x1b\\" - } - - if t.startSyncOut == "" && t.ti.XTermLike { - // this is in theory a queryable private mode, but we just assume it will be ok - // The terminals we have been able to test it all either just swallow it, or - // handle it. - t.startSyncOut = "\x1b[?2026h" - t.endSyncOut = "\x1b[?2026l" - } - - if t.enableCsiU == "" && t.ti.XTermLike { - if runtime.GOOS == "windows" && os.Getenv("TERM") == "" { - // on Windows, if we don't have a TERM, use only win32-input-mode - t.enableCsiU = "\x1b[?9001h" - t.disableCsiU = "\x1b[?9001l" - } else { - // three advanced keyboard protocols: - // - xterm modifyOtherKeys (uses CSI 27 ~ ) - // - kitty csi-u (uses CSI u) - // - win32-input-mode (uses CSI _) - t.enableCsiU = "\x1b[>4;2m" + "\x1b[>1u" + "\x1b[?9001h" - t.disableCsiU = "\x1b[?9001l" + "\x1b[4;0m" - } - } -} - -func (t *tScreen) prepareCursorStyles() { - if t.ti.Mouse != "" || t.ti.XTermLike { - t.cursorStyles = map[CursorStyle]string{ - CursorStyleDefault: "\x1b[0 q", - CursorStyleBlinkingBlock: "\x1b[1 q", - CursorStyleSteadyBlock: "\x1b[2 q", - CursorStyleBlinkingUnderline: "\x1b[3 q", - CursorStyleSteadyUnderline: "\x1b[4 q", - CursorStyleBlinkingBar: "\x1b[5 q", - CursorStyleSteadyBar: "\x1b[6 q", - } - if t.cursorRGB == "" { - t.cursorRGB = "\x1b]12;#%p1%02x%p2%02x%p3%02x\007" - t.cursorFg = "\x1b]112\007" - } - } -} - -func (t *tScreen) prepareKeys() { - ti := t.ti - if strings.HasPrefix(ti.Name, "xterm") { - // assume its some form of XTerm clone - t.ti.XTermLike = true - ti.XTermLike = true - } - t.prepareBracketedPaste() - t.prepareCursorStyles() - t.prepareUnderlines() - t.prepareExtendedOSC() -} - -func (t *tScreen) Fini() { - t.finiOnce.Do(t.finish) -} - -func (t *tScreen) finish() { - close(t.quit) - t.finalize() -} - -func (t *tScreen) SetStyle(style Style) { - t.Lock() - if !t.fini { - t.style = style - } - t.Unlock() -} - -func (t *tScreen) encodeStr(s string) []byte { - - var dstBuf [128]byte - var buf []byte - nb := dstBuf[:] - dst := 0 - var err error - if enc := t.encoder; enc != nil { - enc.Reset() - dst, _, err = enc.Transform(nb, []byte(s), true) - } - if err != nil || dst == 0 || nb[0] == '\x1a' { - // Combining characters are elided - r, _ := utf8.DecodeRuneInString(s) - if len(buf) == 0 { - if acs, ok := t.acs[r]; ok { - buf = append(buf, []byte(acs)...) - } else if fb, ok := t.fallback[r]; ok { - buf = append(buf, []byte(fb)...) - } else { - buf = append(buf, '?') - } - } - } else { - buf = append(buf, nb[:dst]...) - } - - return buf -} - -func (t *tScreen) sendFgBg(fg Color, bg Color, attr AttrMask) AttrMask { - ti := t.ti - if t.Colors() == 0 { - // foreground vs background, we calculate luminance - // and possibly do a reverse video - if !fg.Valid() { - return attr - } - v, ok := t.colors[fg] - if !ok { - v = FindColor(fg, []Color{ColorBlack, ColorWhite}) - t.colors[fg] = v - } - switch v { - case ColorWhite: - return attr - case ColorBlack: - return attr ^ AttrReverse - } - } - - if fg == ColorReset || bg == ColorReset { - t.TPuts(ti.ResetFgBg) - } - if t.truecolor { - if ti.SetFgBgRGB != "" && fg.IsRGB() && bg.IsRGB() { - r1, g1, b1 := fg.RGB() - r2, g2, b2 := bg.RGB() - t.TPuts(ti.TParm(ti.SetFgBgRGB, - int(r1), int(g1), int(b1), - int(r2), int(g2), int(b2))) - return attr - } - - if fg.IsRGB() && ti.SetFgRGB != "" { - r, g, b := fg.RGB() - t.TPuts(ti.TParm(ti.SetFgRGB, int(r), int(g), int(b))) - fg = ColorDefault - } - - if bg.IsRGB() && ti.SetBgRGB != "" { - r, g, b := bg.RGB() - t.TPuts(ti.TParm(ti.SetBgRGB, - int(r), int(g), int(b))) - bg = ColorDefault - } - } - - if fg.Valid() { - if v, ok := t.colors[fg]; ok { - fg = v - } else { - v = FindColor(fg, t.palette) - t.colors[fg] = v - fg = v - } - } - - if bg.Valid() { - if v, ok := t.colors[bg]; ok { - bg = v - } else { - v = FindColor(bg, t.palette) - t.colors[bg] = v - bg = v - } - } - - if fg.Valid() && bg.Valid() && ti.SetFgBg != "" { - t.TPuts(ti.TParm(ti.SetFgBg, int(fg&0xff), int(bg&0xff))) - } else { - if fg.Valid() && ti.SetFg != "" { - t.TPuts(ti.TParm(ti.SetFg, int(fg&0xff))) - } - if bg.Valid() && ti.SetBg != "" { - t.TPuts(ti.TParm(ti.SetBg, int(bg&0xff))) - } - } - return attr -} - -func (t *tScreen) drawCell(x, y int) int { - - ti := t.ti - - str, style, width := t.cells.Get(x, y) - if !t.cells.Dirty(x, y) { - return width - } - - if y == t.h-1 && x == t.w-1 && t.ti.AutoMargin && ti.DisableAutoMargin == "" && ti.InsertChar != "" { - // our solution is somewhat goofy. - // we write to the second to the last cell what we want in the last cell, then we - // insert a character at that 2nd to last position to shift the last column into - // place, then we rewrite that 2nd to last cell. Old terminals suck. - t.TPuts(ti.TGoto(x-1, y)) - defer func() { - t.TPuts(ti.TGoto(x-1, y)) - t.TPuts(ti.InsertChar) - t.cy = y - t.cx = x - 1 - t.cells.SetDirty(x-1, y, true) - _ = t.drawCell(x-1, y) - t.TPuts(t.ti.TGoto(0, 0)) - t.cy = 0 - t.cx = 0 - }() - } else if t.cy != y || t.cx != x { - t.TPuts(ti.TGoto(x, y)) - t.cx = x - t.cy = y - } - - if style == StyleDefault { - style = t.style - } - if style != t.curstyle { - fg, bg, attrs := style.fg, style.bg, style.attrs - - t.TPuts(ti.AttrOff) - - attrs = t.sendFgBg(fg, bg, attrs) - if attrs&AttrBold != 0 { - t.TPuts(ti.Bold) - } - if us, uc := style.ulStyle, style.ulColor; us != UnderlineStyleNone { - if t.underColor != "" || t.underRGB != "" { - if uc == ColorReset { - t.TPuts(t.underFg) - } else if uc.IsRGB() { - if t.underRGB != "" { - r, g, b := uc.RGB() - t.TPuts(ti.TParm(t.underRGB, int(r), int(g), int(b))) - } else { - if v, ok := t.colors[uc]; ok { - uc = v - } else { - v = FindColor(uc, t.palette) - t.colors[uc] = v - uc = v - } - t.TPuts(ti.TParm(t.underColor, int(uc&0xff))) - } - } else if uc.Valid() { - t.TPuts(ti.TParm(t.underColor, int(uc&0xff))) - } - } - t.TPuts(ti.Underline) // to ensure everyone gets at least a basic underline - switch us { - case UnderlineStyleDouble: - t.TPuts(t.doubleUnder) - case UnderlineStyleCurly: - t.TPuts(t.curlyUnder) - case UnderlineStyleDotted: - t.TPuts(t.dottedUnder) - case UnderlineStyleDashed: - t.TPuts(t.dashedUnder) - } - } - if attrs&AttrReverse != 0 { - t.TPuts(ti.Reverse) - } - if attrs&AttrBlink != 0 { - t.TPuts(ti.Blink) - } - if attrs&AttrDim != 0 { - t.TPuts(ti.Dim) - } - if attrs&AttrItalic != 0 { - t.TPuts(ti.Italic) - } - if attrs&AttrStrikeThrough != 0 { - t.TPuts(ti.StrikeThrough) - } - - // URL string can be long, so don't send it unless we really need to - if t.enterUrl != "" && t.curstyle.url != style.url { - if style.url != "" { - t.TPuts(ti.TParm(t.enterUrl, style.url, style.urlId)) - } else { - t.TPuts(t.exitUrl) - } - } - - t.curstyle = style - } - - // now emit runes - taking care to not overrun width with a - // wide character, and to ensure that we emit exactly one regular - // character followed up by any residual combing characters - - if width < 1 { - width = 1 - } - - buf := t.encodeStr(str) - str = string(buf) - - if width > 1 && str == "?" { - // No FullWidth character support - str = "? " - t.cx = -1 - } - - if x > t.w-width { - // too wide to fit; emit a single space instead - width = 1 - str = " " - } - if width > 1 && x+width < t.w { - // Clobber over any content in the next cell. - // This fixes a problem with some terminals where overwriting two - // adjacent single cells with a wide rune would leave an image - // of the second cell. This is a workaround for buggy terminals. - t.writeString(" \b\b") - } - - t.writeString(str) - t.cx += width - t.cells.SetDirty(x, y, false) - if width > 1 { - t.cx = -1 - } - - return width -} - -func (t *tScreen) ShowCursor(x, y int) { - t.Lock() - t.cursorx = x - t.cursory = y - t.Unlock() -} - -func (t *tScreen) SetCursor(cs CursorStyle, cc Color) { - t.Lock() - t.cursorStyle = cs - t.cursorColor = cc - t.Unlock() -} - -func (t *tScreen) HideCursor() { - t.ShowCursor(-1, -1) -} - -func (t *tScreen) showCursor() { - - x, y := t.cursorx, t.cursory - w, h := t.cells.Size() - if x < 0 || y < 0 || x >= w || y >= h { - t.hideCursor() - return - } - t.TPuts(t.ti.TGoto(x, y)) - t.TPuts(t.ti.ShowCursor) - if t.cursorStyles != nil { - if esc, ok := t.cursorStyles[t.cursorStyle]; ok { - t.TPuts(esc) - } - } - if t.cursorRGB != "" { - if t.cursorColor == ColorReset { - t.TPuts(t.cursorFg) - } else if t.cursorColor.Valid() { - r, g, b := t.cursorColor.RGB() - t.TPuts(t.ti.TParm(t.cursorRGB, int(r), int(g), int(b))) - } - } - t.cx = x - t.cy = y -} - -// writeString sends a string to the terminal. The string is sent as-is and -// this function does not expand inline padding indications (of the form -// $<[delay]> where [delay] is msec). In order to have these expanded, use -// TPuts. If the screen is "buffering", the string is collected in a buffer, -// with the intention that the entire buffer be sent to the terminal in one -// write operation at some point later. -func (t *tScreen) writeString(s string) { - if t.buffering { - _, _ = io.WriteString(&t.buf, s) - } else { - _, _ = io.WriteString(t.tty, s) - } -} - -func (t *tScreen) TPuts(s string) { - if t.buffering { - t.ti.TPuts(&t.buf, s) - } else { - t.ti.TPuts(t.tty, s) - } -} - -func (t *tScreen) Show() { - t.Lock() - if !t.fini { - t.resize() - t.draw() - } - t.Unlock() -} - -func (t *tScreen) clearScreen() { - t.TPuts(t.ti.AttrOff) - t.TPuts(t.exitUrl) - _ = t.sendFgBg(t.style.fg, t.style.bg, AttrNone) - t.TPuts(t.ti.Clear) - t.clear = false -} - -func (t *tScreen) startBuffering() { - t.TPuts(t.startSyncOut) -} - -func (t *tScreen) endBuffering() { - t.TPuts(t.endSyncOut) -} - -func (t *tScreen) hideCursor() { - // does not update cursor position - if t.ti.HideCursor != "" { - t.TPuts(t.ti.HideCursor) - } else { - // No way to hide cursor, stick it - // at bottom right of screen - t.cx, t.cy = t.cells.Size() - t.TPuts(t.ti.TGoto(t.cx, t.cy)) - } -} - -func (t *tScreen) draw() { - // clobber cursor position, because we're going to change it all - t.cx = -1 - t.cy = -1 - // make no style assumptions - t.curstyle = styleInvalid - - t.buf.Reset() - t.buffering = true - t.startBuffering() - defer func() { - t.buffering = false - t.endBuffering() - }() - - // hide the cursor while we move stuff around - t.hideCursor() - - if t.clear { - t.clearScreen() - } - - for y := 0; y < t.h; y++ { - for x := 0; x < t.w; x++ { - width := t.drawCell(x, y) - if width > 1 { - if x+1 < t.w { - // this is necessary so that if we ever - // go back to drawing that cell, we - // actually will *draw* it. - t.cells.SetDirty(x+1, y, true) - } - } - x += width - 1 - } - } - - // restore the cursor - t.showCursor() - - _, _ = t.buf.WriteTo(t.tty) -} - -func (t *tScreen) EnableMouse(flags ...MouseFlags) { - var f MouseFlags - flagsPresent := false - for _, flag := range flags { - f |= flag - flagsPresent = true - } - if !flagsPresent { - f = MouseMotionEvents | MouseDragEvents | MouseButtonEvents - } - - t.Lock() - t.mouseFlags = f - t.enableMouse(f) - t.Unlock() -} - -func (t *tScreen) enableMouse(f MouseFlags) { - // Rather than using terminfo to find mouse escape sequences, we rely on the fact that - // pretty much *every* terminal that supports mouse tracking follows the - // XTerm standards (the modern ones). - if len(t.mouse) != 0 { - // start by disabling all tracking. - t.TPuts("\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l") - if f&MouseButtonEvents != 0 { - t.TPuts("\x1b[?1000h") - } - if f&MouseDragEvents != 0 { - t.TPuts("\x1b[?1002h") - } - if f&MouseMotionEvents != 0 { - t.TPuts("\x1b[?1003h") - } - if f&(MouseButtonEvents|MouseDragEvents|MouseMotionEvents) != 0 { - t.TPuts("\x1b[?1006h") - } - } - -} - -func (t *tScreen) DisableMouse() { - t.Lock() - t.mouseFlags = 0 - t.enableMouse(0) - t.Unlock() -} - -func (t *tScreen) EnablePaste() { - t.Lock() - t.pasteEnabled = true - t.enablePasting(true) - t.Unlock() -} - -func (t *tScreen) DisablePaste() { - t.Lock() - t.pasteEnabled = false - t.enablePasting(false) - t.Unlock() -} - -func (t *tScreen) enablePasting(on bool) { - var s string - if on { - s = t.enablePaste - } else { - s = t.disablePaste - } - if s != "" { - t.TPuts(s) - } -} - -func (t *tScreen) EnableFocus() { - t.Lock() - t.focusEnabled = true - t.enableFocusReporting() - t.Unlock() -} - -func (t *tScreen) DisableFocus() { - t.Lock() - t.focusEnabled = false - t.disableFocusReporting() - t.Unlock() -} - -func (t *tScreen) enableFocusReporting() { - if t.enableFocus != "" { - t.TPuts(t.enableFocus) - } -} - -func (t *tScreen) disableFocusReporting() { - if t.disableFocus != "" { - t.TPuts(t.disableFocus) - } -} - -func (t *tScreen) Size() (int, int) { - t.Lock() - w, h := t.w, t.h - t.Unlock() - return w, h -} - -func (t *tScreen) resize() { - ws, err := t.tty.WindowSize() - if err != nil { - return - } - if ws.Width == t.w && ws.Height == t.h { - return - } - t.cx = -1 - t.cy = -1 - - t.cells.Resize(ws.Width, ws.Height) - t.cells.Invalidate() - t.h = ws.Height - t.w = ws.Width - t.input.SetSize(ws.Width, ws.Height) -} - -func (t *tScreen) Colors() int { - if os.Getenv("NO_COLOR") != "" { - return 0 - } - // this doesn't change, no need for lock - if t.truecolor { - return 1 << 24 - } - return t.ti.Colors -} - -// nColors returns the size of the built-in palette. -// This is distinct from Colors(), as it will generally -// always be a small number. (<= 256) -func (t *tScreen) nColors() int { - if os.Getenv("NO_COLOR") != "" { - return 0 - } - return t.ti.Colors -} - -// vtACSNames is a map of bytes defined by terminfo that are used in -// the terminals Alternate Character Set to represent other glyphs. -// For example, the upper left corner of the box drawing set can be -// displayed by printing "l" while in the alternate character set. -// It's not quite that simple, since the "l" is the terminfo name, -// and it may be necessary to use a different character based on -// the terminal implementation (or the terminal may lack support for -// this altogether). See buildAcsMap below for detail. -var vtACSNames = map[byte]rune{ - '+': RuneRArrow, - ',': RuneLArrow, - '-': RuneUArrow, - '.': RuneDArrow, - '0': RuneBlock, - '`': RuneDiamond, - 'a': RuneCkBoard, - 'b': '␉', // VT100, Not defined by terminfo - 'c': '␌', // VT100, Not defined by terminfo - 'd': '␋', // VT100, Not defined by terminfo - 'e': '␊', // VT100, Not defined by terminfo - 'f': RuneDegree, - 'g': RunePlMinus, - 'h': RuneBoard, - 'i': RuneLantern, - 'j': RuneLRCorner, - 'k': RuneURCorner, - 'l': RuneULCorner, - 'm': RuneLLCorner, - 'n': RunePlus, - 'o': RuneS1, - 'p': RuneS3, - 'q': RuneHLine, - 'r': RuneS7, - 's': RuneS9, - 't': RuneLTee, - 'u': RuneRTee, - 'v': RuneBTee, - 'w': RuneTTee, - 'x': RuneVLine, - 'y': RuneLEqual, - 'z': RuneGEqual, - '{': RunePi, - '|': RuneNEqual, - '}': RuneSterling, - '~': RuneBullet, -} - -// buildAcsMap builds a map of characters that we translate from Unicode to -// alternate character encodings. To do this, we use the standard VT100 ACS -// maps. This is only done if the terminal lacks support for Unicode; we -// always prefer to emit Unicode glyphs when we are able. -func (t *tScreen) buildAcsMap() { - acsstr := t.ti.AltChars - t.acs = make(map[rune]string) - for len(acsstr) > 2 { - srcv := acsstr[0] - dstv := string(acsstr[1]) - if r, ok := vtACSNames[srcv]; ok { - t.acs[r] = t.ti.EnterAcs + dstv + t.ti.ExitAcs - } - acsstr = acsstr[2:] - } -} - -func (t *tScreen) scanInput(buf *bytes.Buffer) { - // The end of the buffer isn't necessarily the end of the input, because - // large inputs are chunked. Set atEOF to false so the UTF-8 validating decoder - // returns ErrShortSrc instead of ErrInvalidUTF8 for incomplete multi-byte codepoints. - const atEOF = false - - for buf.Len() > 0 { - utf := make([]byte, min(8, max(buf.Len()*2, 128))) - nOut, nIn, e := t.decoder.Transform(utf, buf.Bytes(), atEOF) - _ = buf.Next(nIn) - t.input.ScanUTF8(utf[:nOut]) - if e == transform.ErrShortSrc { - return - } - } -} - -func (t *tScreen) mainLoop(stopQ chan struct{}) { - defer t.wg.Done() - buf := &bytes.Buffer{} - for { - select { - case <-stopQ: - return - case <-t.quit: - return - case <-t.resizeQ: - t.Lock() - t.cx = -1 - t.cy = -1 - t.resize() - t.cells.Invalidate() - t.draw() - t.Unlock() - continue - case chunk := <-t.keychan: - buf.Write(chunk) - t.scanInput(buf) - } - } -} - -func (t *tScreen) inputLoop(stopQ chan struct{}) { - - defer t.wg.Done() - for { - select { - case <-stopQ: - return - default: - } - chunk := make([]byte, 128) - n, e := t.tty.Read(chunk) - switch e { - case nil: - default: - t.Lock() - running := t.running - t.Unlock() - if running { - select { - case t.eventQ <- NewEventError(e): - case <-t.quit: - } - } - return - } - if n > 0 { - t.keychan <- chunk[:n] - } - } -} - -func (t *tScreen) Sync() { - t.Lock() - t.cx = -1 - t.cy = -1 - if !t.fini { - t.resize() - t.clear = true - t.cells.Invalidate() - t.draw() - } - t.Unlock() -} - -func (t *tScreen) CharacterSet() string { - return t.charset -} - -func (t *tScreen) RegisterRuneFallback(orig rune, fallback string) { - t.Lock() - t.fallback[orig] = fallback - t.Unlock() -} - -func (t *tScreen) UnregisterRuneFallback(orig rune) { - t.Lock() - delete(t.fallback, orig) - t.Unlock() -} - -func (t *tScreen) CanDisplay(r rune, checkFallbacks bool) bool { - - if enc := t.encoder; enc != nil { - nb := make([]byte, 6) - - enc.Reset() - dst, _, err := enc.Transform(nb, []byte(string(r)), true) - if dst != 0 && err == nil && nb[0] != '\x1A' { - return true - } - } - // Terminal fallbacks always permitted, since we assume they are - // basically nearly perfect renditions. - if _, ok := t.acs[r]; ok { - return true - } - if !checkFallbacks { - return false - } - if _, ok := t.fallback[r]; ok { - return true - } - return false -} - -func (t *tScreen) HasMouse() bool { - return len(t.mouse) != 0 -} - -func (t *tScreen) HasKey(_ Key) bool { - // We always return true - return true -} - -func (t *tScreen) SetSize(w, h int) { - if t.setWinSize != "" { - t.TPuts(t.ti.TParm(t.setWinSize, w, h)) - } - t.cells.Invalidate() - t.resize() -} - -func (t *tScreen) Resize(int, int, int, int) {} - -func (t *tScreen) Suspend() error { - t.disengage() - return nil -} - -func (t *tScreen) Resume() error { - return t.engage() -} - -func (t *tScreen) Tty() (Tty, bool) { - return t.tty, true -} - -// engage is used to place the terminal in raw mode and establish screen size, etc. -// Think of this is as tcell "engaging" the clutch, as it's going to be driving the -// terminal interface. -func (t *tScreen) engage() error { - t.Lock() - defer t.Unlock() - if t.tty == nil { - return ErrNoScreen - } - t.tty.NotifyResize(func() { - select { - case t.resizeQ <- true: - default: - } - }) - if t.running { - return errors.New("already engaged") - } - if err := t.tty.Start(); err != nil { - return err - } - t.running = true - if ws, err := t.tty.WindowSize(); err == nil && ws.Width != 0 && ws.Height != 0 { - t.cells.Resize(ws.Width, ws.Height) - } - stopQ := make(chan struct{}) - t.stopQ = stopQ - t.enableMouse(t.mouseFlags) - t.enablePasting(t.pasteEnabled) - if t.focusEnabled { - t.enableFocusReporting() - } - ti := t.ti - if os.Getenv("TCELL_ALTSCREEN") != "disable" { - // Technically this may not be right, but every terminal we know about - // (even Wyse 60) uses this to enter the alternate screen buffer, and - // possibly save and restore the window title and/or icon. - // (In theory there could be terminals that don't support X,Y cursor - // positions without a setup command, but we don't support them.) - t.TPuts(ti.EnterCA) - t.TPuts(t.saveTitle) - } - t.TPuts(ti.EnterKeypad) - t.TPuts(ti.HideCursor) - t.TPuts(ti.EnableAcs) - t.TPuts(ti.DisableAutoMargin) - t.TPuts(ti.Clear) - if t.title != "" && t.setTitle != "" { - t.TPuts(t.ti.TParm(t.setTitle, t.title)) - } - t.TPuts(t.enableCsiU) - - t.wg.Add(2) - go t.inputLoop(stopQ) - go t.mainLoop(stopQ) - return nil -} - -// disengage is used to release the terminal back to support from the caller. -// Think of this as tcell disengaging the clutch, so that another application -// can take over the terminal interface. This restores the TTY mode that was -// present when the application was first started. -func (t *tScreen) disengage() { - - t.Lock() - if !t.running { - t.Unlock() - return - } - - t.running = false - stopQ := t.stopQ - close(stopQ) - _ = t.tty.Drain() - t.Unlock() - - t.tty.NotifyResize(nil) - // wait for everything to shut down - t.wg.Wait() - - // shutdown the screen and disable special modes (e.g. mouse and bracketed paste) - ti := t.ti - t.cells.Resize(0, 0) - t.TPuts(ti.ShowCursor) - if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault { - t.TPuts(t.cursorStyles[CursorStyleDefault]) - } - if t.cursorFg != "" && t.cursorColor.Valid() { - t.TPuts(t.cursorFg) - } - t.TPuts(ti.ResetFgBg) - t.TPuts(ti.AttrOff) - t.TPuts(ti.ExitKeypad) - t.TPuts(ti.EnableAutoMargin) - t.TPuts(t.disableCsiU) - if os.Getenv("TCELL_ALTSCREEN") != "disable" { - if t.restoreTitle != "" { - t.TPuts(t.restoreTitle) - } - t.TPuts(ti.Clear) // only needed if ExitCA is empty - t.TPuts(ti.ExitCA) - } - t.enableMouse(0) - t.enablePasting(false) - t.disableFocusReporting() - - _ = t.tty.Stop() -} - -// Beep emits a beep to the terminal. -func (t *tScreen) Beep() error { - t.writeString(string(byte(7))) - return nil -} - -// finalize is used to at application shutdown, and restores the terminal -// to it's initial state. It should not be called more than once. -func (t *tScreen) finalize() { - t.disengage() - _ = t.tty.Close() -} - -func (t *tScreen) StopQ() <-chan struct{} { - return t.quit -} - -func (t *tScreen) EventQ() chan Event { - return t.eventQ -} - -func (t *tScreen) GetCells() *CellBuffer { - return &t.cells -} - -func (t *tScreen) SetTitle(title string) { - t.Lock() - t.title = title - if t.setTitle != "" && t.running { - t.TPuts(t.ti.TParm(t.setTitle, title)) - } - t.Unlock() -} - -func (t *tScreen) SetClipboard(data []byte) { - // Post binary data to the system clipboard. It might be UTF-8, it might not be. - t.Lock() - if t.setClipboard != "" { - encoded := base64.StdEncoding.EncodeToString(data) - t.TPuts(t.ti.TParm(t.setClipboard, encoded)) - } - t.Unlock() -} - -func (t *tScreen) GetClipboard() { - t.Lock() - if t.setClipboard != "" { - t.TPuts(t.ti.TParm(t.setClipboard, "?")) - } - t.Unlock() -} diff --git a/vendor/github.com/gdamore/tcell/v3/.codecov.yml b/vendor/github.com/gdamore/tcell/v3/.codecov.yml new file mode 100644 index 000000000..8bd926d8f --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/.codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "vt/tests" diff --git a/vendor/github.com/gdamore/tcell/v2/.gitignore b/vendor/github.com/gdamore/tcell/v3/.gitignore similarity index 100% rename from vendor/github.com/gdamore/tcell/v2/.gitignore rename to vendor/github.com/gdamore/tcell/v3/.gitignore diff --git a/vendor/github.com/gdamore/tcell/v3/AGENTS.md b/vendor/github.com/gdamore/tcell/v3/AGENTS.md new file mode 100644 index 000000000..11d8d9f6a --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/AGENTS.md @@ -0,0 +1 @@ +Use the `gopls` MCP server by default when working on Go code in this repository, unless I explicitly ask you not to. diff --git a/vendor/github.com/gdamore/tcell/v2/AUTHORS b/vendor/github.com/gdamore/tcell/v3/AUTHORS similarity index 100% rename from vendor/github.com/gdamore/tcell/v2/AUTHORS rename to vendor/github.com/gdamore/tcell/v3/AUTHORS diff --git a/vendor/github.com/gdamore/tcell/v2/CHANGESv2.md b/vendor/github.com/gdamore/tcell/v3/CHANGESv2.md similarity index 98% rename from vendor/github.com/gdamore/tcell/v2/CHANGESv2.md rename to vendor/github.com/gdamore/tcell/v3/CHANGESv2.md index ad97c11b5..4b5affd93 100644 --- a/vendor/github.com/gdamore/tcell/v2/CHANGESv2.md +++ b/vendor/github.com/gdamore/tcell/v3/CHANGESv2.md @@ -79,4 +79,4 @@ _Tcell_ provides the long requested capability to discriminate paste event by us bracketed-paste capability present in some terminals. This is automatically available on terminals that support XTerm style mouse handling, but applications must opt-in to this by using the new `EnablePaste()` function. A new `EventPaste` type of event will be -delivered when starting and finishing a paste operation. \ No newline at end of file +delivered when starting and finishing a paste operation. diff --git a/vendor/github.com/gdamore/tcell/v3/CHANGESv3.md b/vendor/github.com/gdamore/tcell/v3/CHANGESv3.md new file mode 100644 index 000000000..78e8dbadd --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/CHANGESv3.md @@ -0,0 +1,106 @@ +## Breaking Changes in _Tcell_ v3 + +There are a number of changes in _Tcell_ v3, mostly aimed at simplifying things for +applications, but some also intended to reduce the burden for support. Every application +will need at least some changes, but it is expected that those changes will be small, +possibly even mechanical in nature. + +### Cell and Contents APIs + +In order to improve support for multi-rune grapheme clusters, and to provide an +experience that reduces friction when using it, some APIs have been removed, and +newer APIs exist in their place. + +- `SetCell` and `SetContents` are removed. Use `Put` instead. +- `GetContents` is removed. Use `Get` instead. + +### Events (PostEvent, PollEvent, ChannelEvents) + +The event channel is now directly exposed via `EventQ`, and events may be read from or written +directly to the channel in the standard Go fashion. This should help applications that want to +integrate into `select` statements (e.g. for timed key presses). + +The `ChannelEvents`, `PollEvent`, `PostEvent`, and `PostEventWait` functions are removed, as +applications can now just access the event channel directly. + +### Key Event Changes + +`EventKey` now carries a string for `KeyRune` instead of a single rune. +As a result the old `Rune` method for `EventKey` is replaced by `Str`. +The main difference for most users will be that `Str` returns a string, and most +of the time that string will consist of only a single rune. However, it is possible +now to inject synthetic key strokes consisting of multi-rune grapheme clusters. + +Additionally the following special keys are removed, as they are delivered +instead as `KeyRune` with the relevant rune, and the `ModCtrl` modifier: +`KeyCtrlSpace`, `KeyCtrlLeftSq`, `KeyCtrlRightSq`, `KeyCtrlBackslash`, and +`KeyCtrlUnderscore`. + +Note that `KeyRune` will never have a `ModShift` applied unless it is applied +also with other modifiers. + +The `KeyCtrlA` through `KeyCtrlZ` keys are delivered, but will also carry +the associated lower case rune (e.g. "a", "b", etc.) and `ModCtrl`. + +The `KeyBackspace2` key is no longer delivered, but is converted to +`KeyBackspace`. (This resolves some inconsistency around e.g. CTRL-H vs DELETE.) + +### Termbox Compatibility Removed + +The `termbox` compatibility package is removed. Few applications were using it, +and the compatibility was imperfect. Also the package had limited support for many +newer features. Further, _Termbox_ itself is no longer being maintained. +Applications that still need this should keep using _Tcell_ v2. + +### Terminfo Removed + +The Terminfo subsystem has been removed entirely. +Essentially the old terminfo based design has long proved to be inferior for modern terminal +applications, and has not kept up with newer terminal features such as 24-bit color, +different mouse reporting modes, bracketed paste, advanced text styling, and so forth. + +As part of this, we're removing the parsed terminfo logic entirely. It turns out that pretty much +all of the terminal logic can be consolidated to just a few classes of terminals with substantial +overlap. + +A consequence of this is that support for some legacy terminals that are either functionally +extinct (such as _hpterm_) or unlikely to be found outside of a museum (such as VT52, Wyse50, or +anything produced more than 40 years ago.) + +Note that VT100 and later will work in emulation, and VT220 and later physical terminals should still work. +VT100 physical terminals may not work, as the padding delays that existed for them are removed. +Those delays hurt emulations that do not need them, and existed only to accommodate limitations found on the +physical hardware from the 1970s. + +Note that we still examine `$TERM` when appropriate, but if the value is not one we recognize, +then we will assume something reasonably capable and compatible at some level with _xterm_ or +at least ECMA-48. + +### Color, Attributes, Etc. Bit Sizes + +The `Color` type is now only 32-bits, which should save some memory on large terminal windows. +The `AttrMask` type is now only 16-bits, and the `UnderlineStyle` is now 8 bits. +All these lead to further savings in the memory per cell. + +### Underline + +`AttrUnderline` is gone. It was not sufficient to describe styled and colored underlines. + +### Removed Capability Queries + +Deprecated APIs `HasKey`, `HasMouse`, and `CanDisplay` are removed. +These functions weren't reliable and served no useful purpose. + +### Windows Console API + +`NewConsoleScreen` is removed as is support for Windows console mode. + +Instead this uses the more modern Windows VT modes. +As a consequence, this means that _Tcell_ on Windows requires at least Winows 10 build 1703 (the Creators Update). +If you are using a version of Windows 10 older than that, you should really upgrade for _many_ reasons, not just +because _Tcell_ doesn't support it anymore. + +### InputProcessor is no longer Public + +This structure, and the associated `NewInputProcessor` function, were made public incorrectly. +They are not part of our public API going forward, and are now private symbols. diff --git a/vendor/github.com/gdamore/tcell/v2/LICENSE b/vendor/github.com/gdamore/tcell/v3/LICENSE similarity index 100% rename from vendor/github.com/gdamore/tcell/v2/LICENSE rename to vendor/github.com/gdamore/tcell/v3/LICENSE diff --git a/vendor/github.com/gdamore/tcell/v3/README-plan9.md b/vendor/github.com/gdamore/tcell/v3/README-plan9.md new file mode 100644 index 000000000..2d0934011 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/README-plan9.md @@ -0,0 +1,16 @@ +# _Tcell_ on Plan 9 + +> [!NOTE] +> Plan 9 is supported on a best-effort basis, as the main _Tcell_ development team does not have a Plan 9 environment. + +The Plan 9 backend opens `/dev/cons` for I/O, enables raw mode by writing `rawon`/`rawoff` to `/dev/consctl`. +It watches `/dev/wctl` for resize notifications. + +The default mode for `vt((1)` is VT100, which will only provide basic monochrome text, and few additional features. +In this case, it is expected that `TERM=vt100` is set. + +It may be possible to emulate more modern terminals using `-2` (VT220), `-a` (ANSI), or `-x` (XTerm) flags to `vt`. +While this has not been tested, the use of `-x` to get xterm like features, combinerd with a `TERM=xterm` may yield superior results, +including possibly color and mouse support. + +Note that if _Tcell_ does not find a suitable value for `TERM` in the environment, it will assume XTerm like functionality. diff --git a/vendor/github.com/gdamore/tcell/v2/README-wasm.md b/vendor/github.com/gdamore/tcell/v3/README-wasm.md similarity index 100% rename from vendor/github.com/gdamore/tcell/v2/README-wasm.md rename to vendor/github.com/gdamore/tcell/v3/README-wasm.md diff --git a/vendor/github.com/gdamore/tcell/v3/README-windows.md b/vendor/github.com/gdamore/tcell/v3/README-windows.md new file mode 100644 index 000000000..e85ac23d8 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/README-windows.md @@ -0,0 +1,52 @@ +# _Tcell_ on Windows + +Windows is supported starting from either Windows 10 version 1703 (the Creators Update, released in April 2017) +or Windows Server 2016. + +> [NOTE!] +> Windows 8 and earlier are _not_ supported! + +On Windows, _Tcell_ uses the modern VT API for console applications, including the _win32-input-mode_ to give +advanced key reporting. However, in order to receive resize notifications, the `ReadConsoleInput` API is +used even while in VT input mode. + +On Windows we use 24-bit color by default. + +## Terminal Emulators + +Our preferred terminal emulator on Windows 11 is actually the modern _Windows Terminal_, which can also be +used as a portable application. This is the main test target we use, and the one we recommend if problems are +encountered using third party applications. + +We have tested _Alacritty_ and found it to work reasonably well, including support for modern +key reporting, mouse events, and bracketed paste, although its support support for advanced Unicode features +is limited. + +We have also tested _WezTerm_, _Termius_, _Putty_, and _MobaXterm_. +These appear to work reasonably for remote sessions, but do not support the newer keyboard protocols, and +may not work well for local sessions at all. + +_Termius_ in particular gave a poor experience when used for local sessions, and we would not recommend it. + +While historically popular, we cannot recommend _ConEmu_ or _mintty_. These applications have not kept pace +with modern APIs nor modern terminal standards, and we found their experience suboptimal. + +## SSH From Windows + +Unfortunately, we have found that some features (particularly the rich keyboard support) are degraded when +using SSH from a Windows Terminal (and probably other terminals as well!) to a remote host. It appears that +the full _win32-input-mode_ is captured and refactored into legacy VT style encodings, which can result in +old-school issues such as the inability to to distinguish CTRL-I from TAB. This appears to be something +done by the Windows SSH or terminal application and is nothing we can fix. + +It's likely that WSL will suffer these limitations as well. + +Further, you'll probably need to request 24-bit color explicitly by setting `COLORTERM=truecolor` in your +environment, as this is not typically done for Windows terminals as it is for Posix terminals. + +Note that _Alacritty_ has support for the full key bindings both locally and remotely. Others may as well. +_WezTerm_, while not great locally, performed quite well as an SSH client, with complete support for all +various modern keyboard featuers, bracketed paste, and good Unicode support. + +Another option might be to run an X11 server (such as _MobaXterm_) and then remotely display a Linux terminal +application such as _Ghostty_ or _Kitty_. diff --git a/vendor/github.com/gdamore/tcell/v2/README.md b/vendor/github.com/gdamore/tcell/v3/README.md similarity index 53% rename from vendor/github.com/gdamore/tcell/v2/README.md rename to vendor/github.com/gdamore/tcell/v3/README.md index e40a278b6..f17609bb3 100644 --- a/vendor/github.com/gdamore/tcell/v2/README.md +++ b/vendor/github.com/gdamore/tcell/v3/README.md @@ -5,19 +5,23 @@ _Tcell_ is a _Go_ package that provides a cell based view for text terminals, like _XTerm_. It was inspired by _termbox_, but includes many additional improvements. -[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) +[![Stand With Ukraine](logos/ukraine.svg)](https://stand-with-ukraine.pp.ua) +[![Docs](https://img.shields.io/badge/godoc-reference-blue.svg?label=&logo=go)](https://pkg.go.dev/github.com/gdamore/tcell/v3) [![Linux](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/linux.yml?branch=main&logoColor=grey&logo=linux&label=)](https://github.com/gdamore/tcell/actions/workflows/linux.yml) -[![Windows](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/windows.yml?branch=main&logoColor=grey&label=Windows)](https://github.com/gdamore/tcell/actions/workflows/windows.yml) +[![macOS](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/macos.yml?branch=main&logoColor=grey&logo=apple&label=)](https://github.com/gdamore/tcell/actions/workflows/macos.yml) +[![Windows](https://custom-icon-badges.demolab.com/github/actions/workflow/status/gdamore/tcell/windows.yml?branch=main&logoColor=grey&logo=windows10&label=)](https://github.com/gdamore/tcell/actions/workflows/windows.yml) [![Web Assembly](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/webasm.yml?branch=main&logoColor=grey&logo=webassembly&label=)](https://github.com/gdamore/tcell/actions/workflows/webasm.yml) -[![Apache License](https://img.shields.io/github/license/gdamore/tcell.svg?logoColor=silver&logo=opensourceinitiative&color=blue&label=)](https://github.com/gdamore/tcell/blob/master/LICENSE) -[![Docs](https://img.shields.io/badge/godoc-reference-blue.svg?label=&logo=go)](https://pkg.go.dev/github.com/gdamore/tcell/v2) -[![Discord](https://img.shields.io/discord/639503822733180969?label=&logo=discord)](https://discord.gg/urTTxDN) [![Coverage](https://img.shields.io/codecov/c/github/gdamore/tcell?logoColor=grey&logo=codecov&label=)](https://codecov.io/gh/gdamore/tcell) -[![Go Report Card](https://goreportcard.com/badge/github.com/gdamore/tcell/v2)](https://goreportcard.com/report/github.com/gdamore/tcell/v2) +[![Go Report Card](https://img.shields.io/badge/go%20report-A+-brightgreen.svg?style=flat&label=&logo=go&logoColor=grey)](https://goreportcard.com/report/github.com/gdamore/tcell/v3) +[![Discord](https://img.shields.io/discord/639503822733180969?label=&logo=discord)](https://discord.gg/urTTxDN) [![Latest Release](https://img.shields.io/github/v/release/gdamore/tcell.svg?logo=github&label=)](https://github.com/gdamore/tcell/releases) -NOTE: This is version 2 of _Tcell_. There are breaking changes relative to version 1. -Version 1.x remains available using the import `github.com/gdamore/tcell`. +> [!NOTE] +> This is version 3 of _Tcell_. +> There are breaking changes relative to versions 1 and 2. +> [Version 2](https://github.com/gdamore/tcell/tree/v2) remains available using the import `github.com/gdamore/tcell/v2`. +> [Version 1](https://github.com/gdamore/tcell/tree/v1) Version 1.x remains available using the import `github.com/gdamore/tcell`, but is +> unmaintained and should not be used. ## Tutorial @@ -26,14 +30,14 @@ A brief, and still somewhat rough, [tutorial](TUTORIAL.md) is available. ## Examples A number of example are posted up on our [Gallery](https://github.com/gdamore/tcell/wikis/Gallery/). +That's a wiki, and please do submit updates if you have something you want to showcase. -Let us know if you want to add your masterpiece to the list! +There are also demonstration programs in the `./demos` directory, as well as some in `./_demos`. ## More Portable -_Tcell_ is portable to a wide variety of systems, and is pure Go, without -any need for CGO. -_Tcell_ is believed to work with mainstream systems officially supported by golang. +_Tcell_ is portable to a wide variety of systems, and is pure Go, without any need for CGO. +_Tcell_ works with mainstream systems officially supported by golang. Following the Go support policy, _Tcell_ officially only supports the current ("stable") version of go, and the version immediately prior ("oldstable"). This policy is necessary to make sure that we can @@ -43,9 +47,7 @@ update dependencies to pick up security fixes and new features, and it allows us ## Rich Unicode & non-Unicode support _Tcell_ includes enhanced support for Unicode, including wide characters and -combining characters, provided your terminal can support them. -Note that -Windows terminals generally don't support the full Unicode repertoire. +grapheme clusters, provided your terminal can support them. It will also convert to and from Unicode locales, so that the program can work with UTF-8 internally, and get reasonable output in other locales. @@ -53,21 +55,17 @@ _Tcell_ tries hard to convert to native characters on both input and output. On output _Tcell_ even makes use of the alternate character set to facilitate drawing certain characters. -## More Function Keys +## Better Keyboard Support _Tcell_ also has richer support for a larger number of special keys that some -terminals can send. +terminals can send. On modern terminal emulators we can also support a rich set of +modifiers, and can discriminate between e.g. CTRL-I and TAB. (This does require +the terminal emulator to support one of the modern keyboard protocols.) ## Better Mouse Support _Tcell_ supports enhanced mouse tracking mode, so your application can receive -regular mouse motion events, and wheel events, if your terminal supports it. - -## _Termbox_ Compatibility - -A compatibility layer for _termbox_ is provided in the `compat` directory. -To use it, try importing `github.com/gdamore/tcell/termbox` instead. -Most _termbox-go_ programs will probably work without further modification. +regular mouse motion events, click-drag, and wheel events, if your terminal supports it. ## Working With Unicode @@ -82,8 +80,8 @@ If you're lazy, and want them all anyway, see the `encoding` sub-directory. ## Wide & Combining Characters The `Put()` API takes a string, which should be legal UTF-8, and displays -the first grapheme (which may composed of multiple runes). It returns the -actual width displayed, which can be used to advance the column positiion +the first grapheme cluster (which may composed of multiple runes). +It returns the actual width displayed, which can be used to advance the column positiion for the next display grapheme. Alternatively, `PutStr()` or `PutStrStyled()` can be used to display a single line of text (which will be clipped at the edge of the screen). @@ -93,12 +91,8 @@ wide character (offset by one instead of by two), then the results are undefined ## Colors -_Tcell_ assumes the ANSI/XTerm color model, including the 256 color map that -XTerm uses when it supports 256 colors. The terminfo guidance will be -honored, with respect to the number of colors supported. Also, only -terminals which expose ANSI style `setaf` and `setab` will support color; -if you have a color terminal that only has `setf` and `setb`, please submit -a ticket. +_Tcell_ assumes the ANSI/XTerm color palette for up to 256 colors, although terminals +such as legacy ANSI terminals may only support 8 colors. ## 24-bit Color @@ -106,18 +100,14 @@ _Tcell_ _supports 24-bit color!_ (That is, if your terminal can support it.) There are a few ways you can enable (or disable) 24-bit color. -- For many terminals, we can detect it automatically if your terminal - includes the `RGB` or `Tc` capabilities (or rather it did when the database - was updated.) - - You can force this one by setting the `COLORTERM` environment variable to - `24-bit`, `truecolor` or `24bit`. This is the same method used - by most other terminal applications that support 24-bit color. + `truecolor`. This environment variable is frequently set by terminal emulators + that support 24-bit color. + +- On Windows, 24-bit color support is assumed. (All modern Windows terminal emulators support it.) - If you set your `TERM` environment variable to a value with the suffix `-truecolor` - then 24-bit color compatible with XTerm and ECMA-48 will be assumed. - (This feature is deprecated. - It is recommended to use one of other methods listed above.) + or `-direct`, then 24-bit color compatible with XTerm and ECMA-48 will be assumed. - You can disable 24-bit color by setting `TCELL_TRUECOLOR=disable` in your environment. @@ -136,42 +126,44 @@ avoiding repeated sequences or drawing the same cell on refresh updates. ## Mouse Support -Mouse tracking, buttons, and even wheel mice works fine on most terminal +Mouse tracking, buttons, and even wheel mice are supported on most terminal emulators, as well as Windows. ## Bracketed Paste -Terminals that appear to support the XTerm mouse model also can support -bracketed paste, for applications that opt-in. See `EnablePaste()` for details. +Terminals that support support it, can use bracketed paste. +See `EnablePaste()` for details. -## Testability +## Breaking Changes in v3 -There is a `SimulationScreen`, that can be used to simulate a real screen -for automated testing. The supplied tests do this. The simulation contains -event delivery, screen resizing support, and capabilities to inject events -and examine "`physical`" screen contents. +There are a number of changes in _Tcell_ version 3, which break compatibility with +version 2 and version 1. + +Your application will almost certainly need some minor updates to work with version 3. + +Please see the [CHANGESv3](CHANGESv3.md) document for a list. ## Platforms ### POSIX (Linux, FreeBSD, macOS, Solaris, etc.) -Everything works using pure Go on mainstream platforms. Some more esoteric -platforms (e.g., AIX) may need to be added. Pull requests are welcome! +Everything works using pure Go on mainstream platforms. +Esoteric platforms (e.g. zOS or AIX) are supported on a best-effort +only basis. Pull requests to fix any issues found are welcome! ### Windows -Windows console mode applications are supported. - -Modern console applications like ConEmu and the Windows Terminal, -support all the good features (resize, mouse tracking, etc.) +Modern Windows is supported. Please see the [README-windows](README-windows.md) +document for much more detailed information. ### WASM WASM is supported, but needs additional setup detailed in [README-wasm](README-wasm.md). -### Plan9 and its variants +### Plan 9 -Plan 9 is supported on a limited basis. The Plan 9 backend opens `/dev/cons` for I/O, enables raw mode by writing `rawon`/`rawoff` to `/dev/consctl`, watches `/dev/wctl` for resize notifications, and then constructs a **terminfo-backed** `Screen` (so `NewScreen` works as on other platforms). Typical usage is inside `vt(1)` with `TERM=vt100`. Expect **monochrome text** and **no mouse reporting** under stock `vt(1)` (it generally does not emit ANSI color or xterm mouse sequences). If a Plan 9 terminal supplies ANSI color escape sequences and xterm-style mouse reporting, color can be picked up via **terminfo** and mouse support could be added by wiring those sequences into the Plan 9 TTY path; contributions that improve terminal detection and broaden feature support are welcome. +Plan 9 is supported on a best-effort basis. Please see the [README-plan9](README-plan9.md) +document for more information. ### Commercial Support diff --git a/vendor/github.com/gdamore/tcell/v2/SECURITY.md b/vendor/github.com/gdamore/tcell/v3/SECURITY.md similarity index 94% rename from vendor/github.com/gdamore/tcell/v2/SECURITY.md rename to vendor/github.com/gdamore/tcell/v3/SECURITY.md index 5c0aa5ab4..65bd7cdc5 100644 --- a/vendor/github.com/gdamore/tcell/v2/SECURITY.md +++ b/vendor/github.com/gdamore/tcell/v3/SECURITY.md @@ -3,7 +3,7 @@ It's somewhat unlikely that tcell is in a security sensitive path, but we do take security seriously. -## Vulnerabilityu Response +## Vulnerability Response If you report a vulnerability, we will respond within 2 business days. diff --git a/vendor/github.com/gdamore/tcell/v2/TUTORIAL.md b/vendor/github.com/gdamore/tcell/v3/TUTORIAL.md similarity index 87% rename from vendor/github.com/gdamore/tcell/v2/TUTORIAL.md rename to vendor/github.com/gdamore/tcell/v3/TUTORIAL.md index 92321c763..fa734c26b 100644 --- a/vendor/github.com/gdamore/tcell/v2/TUTORIAL.md +++ b/vendor/github.com/gdamore/tcell/v3/TUTORIAL.md @@ -38,8 +38,8 @@ When a non-rune key is pressed, it is available as the `Key` of the event. ```go switch ev := ev.(type) { case *tcell.EventKey: - mod, key, ch := ev.Mod(), ev.Key(), ev.Rune() - logMessage(fmt.Sprintf("EventKey Modifiers: %d Key: %d Rune: %d", mod, key, ch)) + mod, key, ch := ev.Mod(), ev.Key(), ev.Str() + logMessage(fmt.Sprintf("EventKey Modifiers: %d Key: %d Str: %q", mod, key, ch)) } ``` @@ -100,7 +100,7 @@ if err := s.Init(); err != nil { } // Set default text style -defStyle := tcell.StyleDefault.Background(tcell.ColorReset).Foreground(tcell.ColorReset) +defStyle := tcell.StyleDefault.Background(color.Reset).Foreground(color.Reset) s.SetStyle(defStyle) // Clear screen @@ -110,9 +110,9 @@ s.Clear() Text may be drawn on the screen using `Put`, `PutStr`, or `PutStrStyled`. ```go -s.Put(0, 0, 'H', defStyle) -s.Put(1, 0, 'i', defStyle) -s.Put(2, 0, '!', defStyle) +s.Put(0, 0, "H", defStyle) +s.Put(1, 0, "i", defStyle) +s.Put(2, 0, "!", defStyle) ``` which is equivalent to @@ -157,8 +157,8 @@ for { // Update screen s.Show() - // Poll event - ev := s.PollEvent() + // Poll event (can be used in select statement as well) + ev := <-s.EventQ() // Process event switch ev := ev.(type) { @@ -183,7 +183,8 @@ import ( "fmt" "log" - "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v3" + "github.com/gdamore/tcell/v3/color" ) func drawText(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, text string) { @@ -244,8 +245,8 @@ func drawBox(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, text string) } func main() { - defStyle := tcell.StyleDefault.Background(tcell.ColorReset).Foreground(tcell.ColorReset) - boxStyle := tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorPurple) + defStyle := tcell.StyleDefault.Background(color.Reset).Foreground(color.Reset) + boxStyle := tcell.StyleDefault.Foreground(color.White).Background(color.Purple) // Initialize screen s, err := tcell.NewScreen() @@ -280,10 +281,11 @@ func main() { // xmax, ymax := s.Size() // Here's an example of how to inject a keystroke where it will - // be picked up by the next PollEvent call. Note that the - // queue is LIFO, it has a limited length, and PostEvent() can - // return an error. - // s.PostEvent(tcell.NewEventKey(tcell.KeyRune, rune('a'), 0)) + // be picked up by a future read of the event queue. Note that + // care should be used to avoid blocking writes to the queue if + // this is done from the same thread that is responsible for reading + // the queue, or else a single-party deadlock might occur. + // s.EventQ() <- tcell.NewEventKey(tcell.KeyRune, rune('a'), 0) // Event loop ox, oy := -1, -1 @@ -291,8 +293,8 @@ func main() { // Update screen s.Show() - // Poll event - ev := s.PollEvent() + // Poll event (this can be in a select statement as well) + ev := <-s.EventQ() // Process event switch ev := ev.(type) { @@ -303,7 +305,7 @@ func main() { return } else if ev.Key() == tcell.KeyCtrlL { s.Sync() - } else if ev.Rune() == 'C' || ev.Rune() == 'c' { + } else if ev.Str() == "C" || ev.Str() == "c" { s.Clear() } case *tcell.EventMouse: diff --git a/vendor/github.com/gdamore/tcell/v2/attr.go b/vendor/github.com/gdamore/tcell/v3/attr.go similarity index 72% rename from vendor/github.com/gdamore/tcell/v2/attr.go rename to vendor/github.com/gdamore/tcell/v3/attr.go index 05af5e5d7..66fc2b096 100644 --- a/vendor/github.com/gdamore/tcell/v2/attr.go +++ b/vendor/github.com/gdamore/tcell/v3/attr.go @@ -1,8 +1,8 @@ // Copyright 2024 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -16,7 +16,10 @@ package tcell // AttrMask represents a mask of text attributes, apart from color. // Note that support for attributes may vary widely across terminals. -type AttrMask uint +// Deprecated: This should not be used directly by applications. +// Instead use the accessor functions on the style. (In particular the +// details of the encoding are subject to change.) +type AttrMask uint16 // Attributes are not colors, but affect the display of text. They can // be combined, in some cases, but not others. (E.g. you can have Dim Italic, @@ -25,10 +28,9 @@ const ( AttrBold AttrMask = 1 << iota AttrBlink AttrReverse - AttrUnderline // Deprecated: Use UnderlineStyle AttrDim AttrItalic AttrStrikeThrough - AttrInvalid AttrMask = 1 << 31 // Mark the style or attributes invalid + AttrInvalid AttrMask = 1 << 15 // Mark the style or attributes invalid AttrNone AttrMask = 0 // Just normal text. ) diff --git a/vendor/github.com/gdamore/tcell/v2/cell.go b/vendor/github.com/gdamore/tcell/v3/cell.go similarity index 76% rename from vendor/github.com/gdamore/tcell/v2/cell.go rename to vendor/github.com/gdamore/tcell/v3/cell.go index c139fbda7..eb2e92f76 100644 --- a/vendor/github.com/gdamore/tcell/v2/cell.go +++ b/vendor/github.com/gdamore/tcell/v3/cell.go @@ -1,8 +1,8 @@ -// Copyright 2025 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -14,10 +14,6 @@ package tcell -import ( - "github.com/rivo/uniseg" -) - type cell struct { currStr string lastStr string @@ -40,7 +36,7 @@ func (c *cell) setDirty(dirty bool) { } // CellBuffer represents a two-dimensional array of character cells. -// This is primarily intended for use by Screen implementors; it +// This is primarily intended for use by Screen implementers; it // contains much of the common code they need. To create one, just // declare a variable of its type; no explicit initialization is necessary. // @@ -51,41 +47,29 @@ type CellBuffer struct { cells []cell } -// SetContent sets the contents (primary rune, combining runes, -// and style) for a cell at a given location. If the background or -// foreground of the style is set to ColorNone, then the respective -// color is left un changed. -// -// Deprecated: Use Put instead, which this is implemented in terms of. -func (cb *CellBuffer) SetContent(x int, y int, mainc rune, combc []rune, style Style) { - cb.Put(x, y, string(append([]rune{mainc}, combc...)), style) -} - // Put a single styled grapheme using the given string and style // at the same location. Note that only the first grapheme in the string -// will bre displayed, using only the 1 or 2 (depending on width) cells +// will be displayed, using only the 1 or 2 (depending on width) cells // located at x, y. It returns the rest of the string, and the width used. func (cb *CellBuffer) Put(x int, y int, str string, style Style) (string, int) { var width int = 0 if x >= 0 && y >= 0 && x < cb.w && y < cb.h { var cl string c := &cb.cells[(y*cb.w)+x] - state := -1 - for width == 0 && str != "" { - var g string - g, str, width, state = uniseg.FirstGraphemeClusterInString(str, state) - cl += g - if g == "" { - break - } + g := textWidthOptions.StringGraphemes(str) + for width == 0 && g.Next() { + cluster := g.Value() + cl += cluster + width = g.Width() + str = str[len(cluster):] } // Wide characters: we want to mark the "wide" cells // dirty as well as the base cell, to make sure we consider // both cells as dirty together. We only need to do this // if we're changing content - if width > 0 && cl != c.currStr { - // Prevent unnecessary boundchecks for first cell, since we already + if width > 1 && cl != c.currStr { + // Prevent unnecessary bounds checks for first cell, since we already // received that one. c.setDirty(true) for i := 1; i < width; i++ { @@ -126,28 +110,6 @@ func (cb *CellBuffer) Get(x, y int) (string, Style, int) { return str, style, width } -// GetContent returns the contents of a character cell, including the -// primary rune, any combining character runes (which will usually be -// nil), the style, and the display width in cells. (The width can be -// either 1, normally, or 2 for East Asian full-width characters.) -// -// Deprecated: Use Get, which this implemented in terms of. -func (cb *CellBuffer) GetContent(x, y int) (rune, []rune, Style, int) { - var style Style - var width int - var mainc rune - var combc []rune - str, style, width := cb.Get(x, y) - for i, r := range str { - if i == 0 { - mainc = r - } else { - combc = append(combc, r) - } - } - return mainc, combc, style, width -} - // Size returns the (width, height) in cells of the buffer. func (cb *CellBuffer) Size() (int, int) { return cb.w, cb.h diff --git a/vendor/github.com/gdamore/tcell/v2/charset_plan9.go b/vendor/github.com/gdamore/tcell/v3/charset_plan9.go similarity index 85% rename from vendor/github.com/gdamore/tcell/v2/charset_plan9.go rename to vendor/github.com/gdamore/tcell/v3/charset_plan9.go index 959d181e1..9b33545e3 100644 --- a/vendor/github.com/gdamore/tcell/v2/charset_plan9.go +++ b/vendor/github.com/gdamore/tcell/v3/charset_plan9.go @@ -4,8 +4,8 @@ // Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // diff --git a/vendor/github.com/gdamore/tcell/v2/charset_unix.go b/vendor/github.com/gdamore/tcell/v3/charset_unix.go similarity index 83% rename from vendor/github.com/gdamore/tcell/v2/charset_unix.go rename to vendor/github.com/gdamore/tcell/v3/charset_unix.go index 8bbf1f5ed..63877372d 100644 --- a/vendor/github.com/gdamore/tcell/v2/charset_unix.go +++ b/vendor/github.com/gdamore/tcell/v3/charset_unix.go @@ -1,11 +1,11 @@ -//go:build !windows && !nacl && !plan9 -// +build !windows,!nacl,!plan9 +//go:build unix +// +build unix -// Copyright 2016 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -45,6 +45,5 @@ func getCharset() string { // without a character set, which we assume implies UTF-8. return "UTF-8" } - // XXX: add support for aliases return locale } diff --git a/vendor/github.com/gdamore/tcell/v2/charset_windows.go b/vendor/github.com/gdamore/tcell/v3/charset_windows.go similarity index 83% rename from vendor/github.com/gdamore/tcell/v2/charset_windows.go rename to vendor/github.com/gdamore/tcell/v3/charset_windows.go index 68e498291..0b45c7f23 100644 --- a/vendor/github.com/gdamore/tcell/v2/charset_windows.go +++ b/vendor/github.com/gdamore/tcell/v3/charset_windows.go @@ -4,8 +4,8 @@ // Copyright 2015 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // diff --git a/vendor/github.com/gdamore/tcell/v3/color.go b/vendor/github.com/gdamore/tcell/v3/color.go new file mode 100644 index 000000000..fe414d8ae --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/color.go @@ -0,0 +1,515 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 tcell + +import ( + ic "image/color" + + "github.com/gdamore/tcell/v3/color" +) + +// Note that the entire contents of this file should be considered deprecated +// in favor of the color subpackage. (This also means others can use the color +// package without importing the entirety of tcell into their binaries.) + +// Color represents a color. The low numeric values are the same as used +// by ECMA-48, and beyond that XTerm. +// +// Note that on various terminals colors may be approximated however, or +// not supported at all. If no suitable representation for a color is known, +// the library will simply not set any color, deferring to whatever default +// attributes the terminal uses. +type Color = color.Color + +const ( + // ColorDefault is used to leave the Color unchanged from whatever + // system or terminal default may exist. It's also the zero value. + ColorDefault = color.Default + + // ColorValid is used to indicate the color value is actually + // valid (initialized). + // Deprecated: Use color.IsValid instead. + ColorValid = color.IsValid + + // ColorIsRGB is used to indicate that the numeric value is not + // a known color constant, but rather an RGB value. + // Deprecated: Use color.IsRGB instead. + ColorIsRGB = color.IsRGB + + // ColorSpecial is a flag used to indicate that the values have + // special meaning, and live outside of the color space(s). + // Deprecated. + ColorSpecial = color.IsSpecial +) + +// Note that the order of these options is important -- it follows the +// definitions used by ECMA and XTerm. Hence any further named colors +// must begin at a value not less than 256. +// +// Deprecated: Use color.XXX symbols instead. +const ( + ColorBlack = color.XTerm0 + ColorMaroon = color.XTerm1 + ColorGreen = color.XTerm2 + ColorOlive = color.XTerm3 + ColorNavy = color.XTerm4 + ColorPurple = color.XTerm5 + ColorTeal = color.XTerm6 + ColorSilver = color.XTerm7 + ColorGray = color.XTerm8 + ColorRed = color.XTerm9 + ColorLime = color.XTerm10 + ColorYellow = color.XTerm11 + ColorBlue = color.XTerm12 + ColorFuchsia = color.XTerm13 + ColorAqua = color.XTerm14 + ColorWhite = color.XTerm15 + Color16 = color.XTerm16 + Color17 = color.XTerm17 + Color18 = color.XTerm18 + Color19 = color.XTerm19 + Color20 = color.XTerm20 + Color21 = color.XTerm21 + Color22 = color.XTerm22 + Color23 = color.XTerm23 + Color24 = color.XTerm24 + Color25 = color.XTerm25 + Color26 = color.XTerm26 + Color27 = color.XTerm27 + Color28 = color.XTerm28 + Color29 = color.XTerm29 + Color30 = color.XTerm30 + Color31 = color.XTerm31 + Color32 = color.XTerm32 + Color33 = color.XTerm33 + Color34 = color.XTerm34 + Color35 = color.XTerm35 + Color36 = color.XTerm36 + Color37 = color.XTerm37 + Color38 = color.XTerm38 + Color39 = color.XTerm39 + Color40 = color.XTerm40 + Color41 = color.XTerm41 + Color42 = color.XTerm42 + Color43 = color.XTerm43 + Color44 = color.XTerm44 + Color45 = color.XTerm45 + Color46 = color.XTerm46 + Color47 = color.XTerm47 + Color48 = color.XTerm48 + Color49 = color.XTerm49 + Color50 = color.XTerm50 + Color51 = color.XTerm51 + Color52 = color.XTerm52 + Color53 = color.XTerm53 + Color54 = color.XTerm54 + Color55 = color.XTerm55 + Color56 = color.XTerm56 + Color57 = color.XTerm57 + Color58 = color.XTerm58 + Color59 = color.XTerm59 + Color60 = color.XTerm60 + Color61 = color.XTerm61 + Color62 = color.XTerm62 + Color63 = color.XTerm63 + Color64 = color.XTerm64 + Color65 = color.XTerm65 + Color66 = color.XTerm66 + Color67 = color.XTerm67 + Color68 = color.XTerm68 + Color69 = color.XTerm69 + Color70 = color.XTerm70 + Color71 = color.XTerm71 + Color72 = color.XTerm72 + Color73 = color.XTerm73 + Color74 = color.XTerm74 + Color75 = color.XTerm75 + Color76 = color.XTerm76 + Color77 = color.XTerm77 + Color78 = color.XTerm78 + Color79 = color.XTerm79 + Color80 = color.XTerm80 + Color81 = color.XTerm81 + Color82 = color.XTerm82 + Color83 = color.XTerm83 + Color84 = color.XTerm84 + Color85 = color.XTerm85 + Color86 = color.XTerm86 + Color87 = color.XTerm87 + Color88 = color.XTerm88 + Color89 = color.XTerm89 + Color90 = color.XTerm90 + Color91 = color.XTerm91 + Color92 = color.XTerm92 + Color93 = color.XTerm93 + Color94 = color.XTerm94 + Color95 = color.XTerm95 + Color96 = color.XTerm96 + Color97 = color.XTerm97 + Color98 = color.XTerm98 + Color99 = color.XTerm99 + Color100 = color.XTerm100 + Color101 = color.XTerm101 + Color102 = color.XTerm102 + Color103 = color.XTerm103 + Color104 = color.XTerm104 + Color105 = color.XTerm105 + Color106 = color.XTerm106 + Color107 = color.XTerm107 + Color108 = color.XTerm108 + Color109 = color.XTerm109 + Color110 = color.XTerm110 + Color111 = color.XTerm111 + Color112 = color.XTerm112 + Color113 = color.XTerm113 + Color114 = color.XTerm114 + Color115 = color.XTerm115 + Color116 = color.XTerm116 + Color117 = color.XTerm117 + Color118 = color.XTerm118 + Color119 = color.XTerm119 + Color120 = color.XTerm120 + Color121 = color.XTerm121 + Color122 = color.XTerm122 + Color123 = color.XTerm123 + Color124 = color.XTerm124 + Color125 = color.XTerm125 + Color126 = color.XTerm126 + Color127 = color.XTerm127 + Color128 = color.XTerm128 + Color129 = color.XTerm129 + Color130 = color.XTerm130 + Color131 = color.XTerm131 + Color132 = color.XTerm132 + Color133 = color.XTerm133 + Color134 = color.XTerm134 + Color135 = color.XTerm135 + Color136 = color.XTerm136 + Color137 = color.XTerm137 + Color138 = color.XTerm138 + Color139 = color.XTerm139 + Color140 = color.XTerm140 + Color141 = color.XTerm141 + Color142 = color.XTerm142 + Color143 = color.XTerm143 + Color144 = color.XTerm144 + Color145 = color.XTerm145 + Color146 = color.XTerm146 + Color147 = color.XTerm147 + Color148 = color.XTerm148 + Color149 = color.XTerm149 + Color150 = color.XTerm150 + Color151 = color.XTerm151 + Color152 = color.XTerm152 + Color153 = color.XTerm153 + Color154 = color.XTerm154 + Color155 = color.XTerm155 + Color156 = color.XTerm156 + Color157 = color.XTerm157 + Color158 = color.XTerm158 + Color159 = color.XTerm159 + Color160 = color.XTerm160 + Color161 = color.XTerm161 + Color162 = color.XTerm162 + Color163 = color.XTerm163 + Color164 = color.XTerm164 + Color165 = color.XTerm165 + Color166 = color.XTerm166 + Color167 = color.XTerm167 + Color168 = color.XTerm168 + Color169 = color.XTerm169 + Color170 = color.XTerm170 + Color171 = color.XTerm171 + Color172 = color.XTerm172 + Color173 = color.XTerm173 + Color174 = color.XTerm174 + Color175 = color.XTerm175 + Color176 = color.XTerm176 + Color177 = color.XTerm177 + Color178 = color.XTerm178 + Color179 = color.XTerm179 + Color180 = color.XTerm180 + Color181 = color.XTerm181 + Color182 = color.XTerm182 + Color183 = color.XTerm183 + Color184 = color.XTerm184 + Color185 = color.XTerm185 + Color186 = color.XTerm186 + Color187 = color.XTerm187 + Color188 = color.XTerm188 + Color189 = color.XTerm189 + Color190 = color.XTerm190 + Color191 = color.XTerm191 + Color192 = color.XTerm192 + Color193 = color.XTerm193 + Color194 = color.XTerm194 + Color195 = color.XTerm195 + Color196 = color.XTerm196 + Color197 = color.XTerm197 + Color198 = color.XTerm198 + Color199 = color.XTerm199 + Color200 = color.XTerm200 + Color201 = color.XTerm201 + Color202 = color.XTerm202 + Color203 = color.XTerm203 + Color204 = color.XTerm204 + Color205 = color.XTerm205 + Color206 = color.XTerm206 + Color207 = color.XTerm207 + Color208 = color.XTerm208 + Color209 = color.XTerm209 + Color210 = color.XTerm210 + Color211 = color.XTerm211 + Color212 = color.XTerm212 + Color213 = color.XTerm213 + Color214 = color.XTerm214 + Color215 = color.XTerm215 + Color216 = color.XTerm216 + Color217 = color.XTerm217 + Color218 = color.XTerm218 + Color219 = color.XTerm219 + Color220 = color.XTerm220 + Color221 = color.XTerm221 + Color222 = color.XTerm222 + Color223 = color.XTerm223 + Color224 = color.XTerm224 + Color225 = color.XTerm225 + Color226 = color.XTerm226 + Color227 = color.XTerm227 + Color228 = color.XTerm228 + Color229 = color.XTerm229 + Color230 = color.XTerm230 + Color231 = color.XTerm231 + Color232 = color.XTerm232 + Color233 = color.XTerm233 + Color234 = color.XTerm234 + Color235 = color.XTerm235 + Color236 = color.XTerm236 + Color237 = color.XTerm237 + Color238 = color.XTerm238 + Color239 = color.XTerm239 + Color240 = color.XTerm240 + Color241 = color.XTerm241 + Color242 = color.XTerm242 + Color243 = color.XTerm243 + Color244 = color.XTerm244 + Color245 = color.XTerm245 + Color246 = color.XTerm246 + Color247 = color.XTerm247 + Color248 = color.XTerm248 + Color249 = color.XTerm249 + Color250 = color.XTerm250 + Color251 = color.XTerm251 + Color252 = color.XTerm252 + Color253 = color.XTerm253 + Color254 = color.XTerm254 + Color255 = color.XTerm255 + ColorAliceBlue = color.AliceBlue + ColorAntiqueWhite = color.AntiqueWhite + ColorAquaMarine = color.AquaMarine + ColorAzure = color.Azure + ColorBeige = color.Beige + ColorBisque = color.Bisque + ColorBlanchedAlmond = color.BlanchedAlmond + ColorBlueViolet = color.BlueViolet + ColorBrown = color.Brown + ColorBurlyWood = color.BurlyWood + ColorCadetBlue = color.CadetBlue + ColorChartreuse = color.Chartreuse + ColorChocolate = color.Chocolate + ColorCoral = color.Coral + ColorCornflowerBlue = color.CornflowerBlue + ColorCornsilk = color.Cornsilk + ColorCrimson = color.Crimson + ColorDarkBlue = color.DarkBlue + ColorDarkCyan = color.DarkCyan + ColorDarkGoldenrod = color.DarkGoldenrod + ColorDarkGray = color.DarkGray + ColorDarkGreen = color.DarkGreen + ColorDarkKhaki = color.DarkKhaki + ColorDarkMagenta = color.DarkMagenta + ColorDarkOliveGreen = color.DarkOliveGreen + ColorDarkOrange = color.DarkOrange + ColorDarkOrchid = color.DarkOrchid + ColorDarkRed = color.DarkRed + ColorDarkSalmon = color.DarkSalmon + ColorDarkSeaGreen = color.DarkSeaGreen + ColorDarkSlateBlue = color.DarkSlateBlue + ColorDarkSlateGray = color.DarkSlateGray + ColorDarkTurquoise = color.DarkTurquoise + ColorDarkViolet = color.DarkViolet + ColorDeepPink = color.DeepPink + ColorDeepSkyBlue = color.DeepSkyBlue + ColorDimGray = color.DimGray + ColorDodgerBlue = color.DodgerBlue + ColorFireBrick = color.FireBrick + ColorFloralWhite = color.FloralWhite + ColorForestGreen = color.ForestGreen + ColorGainsboro = color.Gainsboro + ColorGhostWhite = color.GhostWhite + ColorGold = color.Gold + ColorGoldenrod = color.Goldenrod + ColorGreenYellow = color.GreenYellow + ColorHoneydew = color.Honeydew + ColorHotPink = color.HotPink + ColorIndianRed = color.IndianRed + ColorIndigo = color.Indigo + ColorIvory = color.Ivory + ColorKhaki = color.Khaki + ColorLavender = color.Lavender + ColorLavenderBlush = color.LavenderBlush + ColorLawnGreen = color.LawnGreen + ColorLemonChiffon = color.LemonChiffon + ColorLightBlue = color.LightBlue + ColorLightCoral = color.LightCoral + ColorLightCyan = color.LightCyan + ColorLightGoldenrodYellow = color.LightGoldenrodYellow + ColorLightGray = color.LightGray + ColorLightGreen = color.LightGreen + ColorLightPink = color.LightPink + ColorLightSalmon = color.LightSalmon + ColorLightSeaGreen = color.LightSeaGreen + ColorLightSkyBlue = color.LightSkyBlue + ColorLightSlateGray = color.LightSlateGray + ColorLightSteelBlue = color.LightSteelBlue + ColorLightYellow = color.LightYellow + ColorLimeGreen = color.LimeGreen + ColorLinen = color.Linen + ColorMediumAquamarine = color.MediumAquamarine + ColorMediumBlue = color.MediumBlue + ColorMediumOrchid = color.MediumOrchid + ColorMediumPurple = color.MediumPurple + ColorMediumSeaGreen = color.MediumSeaGreen + ColorMediumSlateBlue = color.MediumSlateBlue + ColorMediumSpringGreen = color.MediumSpringGreen + ColorMediumTurquoise = color.MediumTurquoise + ColorMediumVioletRed = color.MediumVioletRed + ColorMidnightBlue = color.MidnightBlue + ColorMintCream = color.MintCream + ColorMistyRose = color.MistyRose + ColorMoccasin = color.Moccasin + ColorNavajoWhite = color.NavajoWhite + ColorOldLace = color.OldLace + ColorOliveDrab = color.OliveDrab + ColorOrange = color.Orange + ColorOrangeRed = color.OrangeRed + ColorOrchid = color.Orchid + ColorPaleGoldenrod = color.PaleGoldenrod + ColorPaleGreen = color.PaleGreen + ColorPaleTurquoise = color.PaleTurquoise + ColorPaleVioletRed = color.PaleVioletRed + ColorPapayaWhip = color.PapayaWhip + ColorPeachPuff = color.PeachPuff + ColorPeru = color.Peru + ColorPink = color.Pink + ColorPlum = color.Plum + ColorPowderBlue = color.PowderBlue + ColorRebeccaPurple = color.RebeccaPurple + ColorRosyBrown = color.RosyBrown + ColorRoyalBlue = color.RoyalBlue + ColorSaddleBrown = color.SaddleBrown + ColorSalmon = color.Salmon + ColorSandyBrown = color.SandyBrown + ColorSeaGreen = color.SeaGreen + ColorSeashell = color.Seashell + ColorSienna = color.Sienna + ColorSkyblue = color.Skyblue + ColorSlateBlue = color.SlateBlue + ColorSlateGray = color.SlateGray + ColorSnow = color.Snow + ColorSpringGreen = color.SpringGreen + ColorSteelBlue = color.SteelBlue + ColorTan = color.Tan + ColorThistle = color.Thistle + ColorTomato = color.Tomato + ColorTurquoise = color.Turquoise + ColorViolet = color.Violet + ColorWheat = color.Wheat + ColorWhiteSmoke = color.WhiteSmoke + ColorYellowGreen = color.YellowGreen +) + +// These are aliases for the color gray, because some of us spell +// it as grey. Deprecated: Use color values. +const ( + ColorGrey = color.Gray + ColorDimGrey = color.DimGray + ColorDarkGrey = color.DarkGray + ColorDarkSlateGrey = color.DarkSlateGray + ColorLightGrey = color.LightGray + ColorLightSlateGrey = color.LightSlateGray + ColorSlateGrey = color.SlateGray +) + +// ColorValues maps color constants to their RGB values. +var ColorValues = color.ColorValues + +// Special colors. +const ( + // ColorReset is used to indicate that the color should use the + // vanilla terminal colors. (Basically go back to the defaults.) + // Deprecated: Use color.Reset. + ColorReset = color.Reset + + // ColorNone indicates that we should not change the color from + // whatever is already displayed. This can only be used in limited + // circumstances. + // Deprecated: Use color.None. + ColorNone = color.None +) + +// ColorNames holds the written names of colors. Useful to present a list of +// recognized named colors. Deprecated: Use color.Names. +var ColorNames = color.Names + +// NewRGBColor returns a new color with the given red, green, and blue values. +// Each value must be represented in the range 0-255. +// Deprecated: Use color.NewRGBColor. +func NewRGBColor(r, g, b int32) Color { + return color.NewRGBColor(r, g, b) +} + +// NewHexColor returns a color using the given 24-bit RGB value. +// Deprecated: Use color.NewHexColor. +func NewHexColor(v int32) Color { + return color.NewHexColor(v) +} + +// GetColor creates a Color from a color name (W3C name). A hex value may +// be supplied as a string in the format "#ffffff". +// Deprecated: Use color.GetColor. +func GetColor(name string) Color { + return color.GetColor(name) +} + +// PaletteColor creates a color based on the palette index. +// Deprecated: Use color.PaletteColor. +func PaletteColor(index int) Color { + return color.PaletteColor(index) +} + +// FromImageColor converts an image/color.Color into Color. +// Deprecated: Use color.FromImageColor. +func FromImageColor(imageColor ic.Color) Color { + return color.FromImageColor(imageColor) +} + +// FindColor attempts to find a given color, or the best match possible for it, +// from the palette given. This is an expensive operation, so results should +// be cached by the caller. +// Deprecated: Use color.Find. +func FindColor(c Color, palette []Color) Color { + return color.Find(c, palette) +} diff --git a/vendor/github.com/gdamore/tcell/v3/color/color.go b/vendor/github.com/gdamore/tcell/v3/color/color.go new file mode 100644 index 000000000..0634e3986 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/color/color.go @@ -0,0 +1,1174 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 color + +import ( + "fmt" + ic "image/color" + "strconv" +) + +// Color represents a color. The low numeric values are the same as used +// by ECMA-48, and beyond that XTerm. +// +// For Color names we use the W3C approved color names. +// +// Note that on various terminals colors may be approximated however, or +// not supported at all. If no suitable representation for a color is known, +// the library will simply not set any color, deferring to whatever default +// attributes the terminal uses. +type Color uint32 + +const ( + // Default is used to leave the Color unchanged from whatever + // system or terminal default may exist. It's also the zero value. + Default Color = 0 + + // IsValid is used to indicate the color value is actually + // valid (initialized). This is useful to permit the zero value + // to be treated as the default. This should not be used + // directly by applications. Use the IsValid method on Color instead. + IsValid Color = 1 << 31 + + // IsRGB is used to indicate that the numeric value is not + // a known color constant, but rather an RGB value. The lower + // order 3 bytes are RGB. This should not be used directly, + // instead use the Color.IsRGB method. + IsRGB Color = 1 << 30 + + // IsSpecial is a flag used to indicate that the values have + // special meaning, and live outside of the color space(s). + // This should not be used directly by applications. + IsSpecial Color = 1 << 29 +) + +// Note that the order of these options is important -- it follows the +// definitions used by ECMA and XTerm. Hence any further named colors +// must begin at a value not less than 256. +const ( + Black = XTerm0 + Maroon = XTerm1 + Green = XTerm2 + Olive = XTerm3 + Navy = XTerm4 + Purple = XTerm5 + Teal = XTerm6 + Silver = XTerm7 + Gray = XTerm8 + Red = XTerm9 + Lime = XTerm10 + Yellow = XTerm11 + Blue = XTerm12 + Fuchsia = XTerm13 + Aqua = XTerm14 + White = XTerm15 +) + +const ( + XTerm0 = IsValid + iota + XTerm1 + XTerm2 + XTerm3 + XTerm4 + XTerm5 + XTerm6 + XTerm7 + XTerm8 + XTerm9 + XTerm10 + XTerm11 + XTerm12 + XTerm13 + XTerm14 + XTerm15 + XTerm16 + XTerm17 + XTerm18 + XTerm19 + XTerm20 + XTerm21 + XTerm22 + XTerm23 + XTerm24 + XTerm25 + XTerm26 + XTerm27 + XTerm28 + XTerm29 + XTerm30 + XTerm31 + XTerm32 + XTerm33 + XTerm34 + XTerm35 + XTerm36 + XTerm37 + XTerm38 + XTerm39 + XTerm40 + XTerm41 + XTerm42 + XTerm43 + XTerm44 + XTerm45 + XTerm46 + XTerm47 + XTerm48 + XTerm49 + XTerm50 + XTerm51 + XTerm52 + XTerm53 + XTerm54 + XTerm55 + XTerm56 + XTerm57 + XTerm58 + XTerm59 + XTerm60 + XTerm61 + XTerm62 + XTerm63 + XTerm64 + XTerm65 + XTerm66 + XTerm67 + XTerm68 + XTerm69 + XTerm70 + XTerm71 + XTerm72 + XTerm73 + XTerm74 + XTerm75 + XTerm76 + XTerm77 + XTerm78 + XTerm79 + XTerm80 + XTerm81 + XTerm82 + XTerm83 + XTerm84 + XTerm85 + XTerm86 + XTerm87 + XTerm88 + XTerm89 + XTerm90 + XTerm91 + XTerm92 + XTerm93 + XTerm94 + XTerm95 + XTerm96 + XTerm97 + XTerm98 + XTerm99 + XTerm100 + XTerm101 + XTerm102 + XTerm103 + XTerm104 + XTerm105 + XTerm106 + XTerm107 + XTerm108 + XTerm109 + XTerm110 + XTerm111 + XTerm112 + XTerm113 + XTerm114 + XTerm115 + XTerm116 + XTerm117 + XTerm118 + XTerm119 + XTerm120 + XTerm121 + XTerm122 + XTerm123 + XTerm124 + XTerm125 + XTerm126 + XTerm127 + XTerm128 + XTerm129 + XTerm130 + XTerm131 + XTerm132 + XTerm133 + XTerm134 + XTerm135 + XTerm136 + XTerm137 + XTerm138 + XTerm139 + XTerm140 + XTerm141 + XTerm142 + XTerm143 + XTerm144 + XTerm145 + XTerm146 + XTerm147 + XTerm148 + XTerm149 + XTerm150 + XTerm151 + XTerm152 + XTerm153 + XTerm154 + XTerm155 + XTerm156 + XTerm157 + XTerm158 + XTerm159 + XTerm160 + XTerm161 + XTerm162 + XTerm163 + XTerm164 + XTerm165 + XTerm166 + XTerm167 + XTerm168 + XTerm169 + XTerm170 + XTerm171 + XTerm172 + XTerm173 + XTerm174 + XTerm175 + XTerm176 + XTerm177 + XTerm178 + XTerm179 + XTerm180 + XTerm181 + XTerm182 + XTerm183 + XTerm184 + XTerm185 + XTerm186 + XTerm187 + XTerm188 + XTerm189 + XTerm190 + XTerm191 + XTerm192 + XTerm193 + XTerm194 + XTerm195 + XTerm196 + XTerm197 + XTerm198 + XTerm199 + XTerm200 + XTerm201 + XTerm202 + XTerm203 + XTerm204 + XTerm205 + XTerm206 + XTerm207 + XTerm208 + XTerm209 + XTerm210 + XTerm211 + XTerm212 + XTerm213 + XTerm214 + XTerm215 + XTerm216 + XTerm217 + XTerm218 + XTerm219 + XTerm220 + XTerm221 + XTerm222 + XTerm223 + XTerm224 + XTerm225 + XTerm226 + XTerm227 + XTerm228 + XTerm229 + XTerm230 + XTerm231 + XTerm232 + XTerm233 + XTerm234 + XTerm235 + XTerm236 + XTerm237 + XTerm238 + XTerm239 + XTerm240 + XTerm241 + XTerm242 + XTerm243 + XTerm244 + XTerm245 + XTerm246 + XTerm247 + XTerm248 + XTerm249 + XTerm250 + XTerm251 + XTerm252 + XTerm253 + XTerm254 + XTerm255 + AliceBlue = IsRGB | IsValid | 0xF0F8FF + AntiqueWhite = IsRGB | IsValid | 0xFAEBD7 + AquaMarine = IsRGB | IsValid | 0x7FFFD4 + Azure = IsRGB | IsValid | 0xF0FFFF + Beige = IsRGB | IsValid | 0xF5F5DC + Bisque = IsRGB | IsValid | 0xFFE4C4 + BlanchedAlmond = IsRGB | IsValid | 0xFFEBCD + BlueViolet = IsRGB | IsValid | 0x8A2BE2 + Brown = IsRGB | IsValid | 0xA52A2A + BurlyWood = IsRGB | IsValid | 0xDEB887 + CadetBlue = IsRGB | IsValid | 0x5F9EA0 + Chartreuse = IsRGB | IsValid | 0x7FFF00 + Chocolate = IsRGB | IsValid | 0xD2691E + Coral = IsRGB | IsValid | 0xFF7F50 + CornflowerBlue = IsRGB | IsValid | 0x6495ED + Cornsilk = IsRGB | IsValid | 0xFFF8DC + Crimson = IsRGB | IsValid | 0xDC143C + DarkBlue = IsRGB | IsValid | 0x00008B + DarkCyan = IsRGB | IsValid | 0x008B8B + DarkGoldenrod = IsRGB | IsValid | 0xB8860B + DarkGray = IsRGB | IsValid | 0xA9A9A9 + DarkGreen = IsRGB | IsValid | 0x006400 + DarkKhaki = IsRGB | IsValid | 0xBDB76B + DarkMagenta = IsRGB | IsValid | 0x8B008B + DarkOliveGreen = IsRGB | IsValid | 0x556B2F + DarkOrange = IsRGB | IsValid | 0xFF8C00 + DarkOrchid = IsRGB | IsValid | 0x9932CC + DarkRed = IsRGB | IsValid | 0x8B0000 + DarkSalmon = IsRGB | IsValid | 0xE9967A + DarkSeaGreen = IsRGB | IsValid | 0x8FBC8F + DarkSlateBlue = IsRGB | IsValid | 0x483D8B + DarkSlateGray = IsRGB | IsValid | 0x2F4F4F + DarkTurquoise = IsRGB | IsValid | 0x00CED1 + DarkViolet = IsRGB | IsValid | 0x9400D3 + DeepPink = IsRGB | IsValid | 0xFF1493 + DeepSkyBlue = IsRGB | IsValid | 0x00BFFF + DimGray = IsRGB | IsValid | 0x696969 + DodgerBlue = IsRGB | IsValid | 0x1E90FF + FireBrick = IsRGB | IsValid | 0xB22222 + FloralWhite = IsRGB | IsValid | 0xFFFAF0 + ForestGreen = IsRGB | IsValid | 0x228B22 + Gainsboro = IsRGB | IsValid | 0xDCDCDC + GhostWhite = IsRGB | IsValid | 0xF8F8FF + Gold = IsRGB | IsValid | 0xFFD700 + Goldenrod = IsRGB | IsValid | 0xDAA520 + GreenYellow = IsRGB | IsValid | 0xADFF2F + Honeydew = IsRGB | IsValid | 0xF0FFF0 + HotPink = IsRGB | IsValid | 0xFF69B4 + IndianRed = IsRGB | IsValid | 0xCD5C5C + Indigo = IsRGB | IsValid | 0x4B0082 + Ivory = IsRGB | IsValid | 0xFFFFF0 + Khaki = IsRGB | IsValid | 0xF0E68C + Lavender = IsRGB | IsValid | 0xE6E6FA + LavenderBlush = IsRGB | IsValid | 0xFFF0F5 + LawnGreen = IsRGB | IsValid | 0x7CFC00 + LemonChiffon = IsRGB | IsValid | 0xFFFACD + LightBlue = IsRGB | IsValid | 0xADD8E6 + LightCoral = IsRGB | IsValid | 0xF08080 + LightCyan = IsRGB | IsValid | 0xE0FFFF + LightGoldenrodYellow = IsRGB | IsValid | 0xFAFAD2 + LightGray = IsRGB | IsValid | 0xD3D3D3 + LightGreen = IsRGB | IsValid | 0x90EE90 + LightPink = IsRGB | IsValid | 0xFFB6C1 + LightSalmon = IsRGB | IsValid | 0xFFA07A + LightSeaGreen = IsRGB | IsValid | 0x20B2AA + LightSkyBlue = IsRGB | IsValid | 0x87CEFA + LightSlateGray = IsRGB | IsValid | 0x778899 + LightSteelBlue = IsRGB | IsValid | 0xB0C4DE + LightYellow = IsRGB | IsValid | 0xFFFFE0 + LimeGreen = IsRGB | IsValid | 0x32CD32 + Linen = IsRGB | IsValid | 0xFAF0E6 + MediumAquamarine = IsRGB | IsValid | 0x66CDAA + MediumBlue = IsRGB | IsValid | 0x0000CD + MediumOrchid = IsRGB | IsValid | 0xBA55D3 + MediumPurple = IsRGB | IsValid | 0x9370DB + MediumSeaGreen = IsRGB | IsValid | 0x3CB371 + MediumSlateBlue = IsRGB | IsValid | 0x7B68EE + MediumSpringGreen = IsRGB | IsValid | 0x00FA9A + MediumTurquoise = IsRGB | IsValid | 0x48D1CC + MediumVioletRed = IsRGB | IsValid | 0xC71585 + MidnightBlue = IsRGB | IsValid | 0x191970 + MintCream = IsRGB | IsValid | 0xF5FFFA + MistyRose = IsRGB | IsValid | 0xFFE4E1 + Moccasin = IsRGB | IsValid | 0xFFE4B5 + NavajoWhite = IsRGB | IsValid | 0xFFDEAD + OldLace = IsRGB | IsValid | 0xFDF5E6 + OliveDrab = IsRGB | IsValid | 0x6B8E23 + Orange = IsRGB | IsValid | 0xFFA500 + OrangeRed = IsRGB | IsValid | 0xFF4500 + Orchid = IsRGB | IsValid | 0xDA70D6 + PaleGoldenrod = IsRGB | IsValid | 0xEEE8AA + PaleGreen = IsRGB | IsValid | 0x98FB98 + PaleTurquoise = IsRGB | IsValid | 0xAFEEEE + PaleVioletRed = IsRGB | IsValid | 0xDB7093 + PapayaWhip = IsRGB | IsValid | 0xFFEFD5 + PeachPuff = IsRGB | IsValid | 0xFFDAB9 + Peru = IsRGB | IsValid | 0xCD853F + Pink = IsRGB | IsValid | 0xFFC0CB + Plum = IsRGB | IsValid | 0xDDA0DD + PowderBlue = IsRGB | IsValid | 0xB0E0E6 + RebeccaPurple = IsRGB | IsValid | 0x663399 + RosyBrown = IsRGB | IsValid | 0xBC8F8F + RoyalBlue = IsRGB | IsValid | 0x4169E1 + SaddleBrown = IsRGB | IsValid | 0x8B4513 + Salmon = IsRGB | IsValid | 0xFA8072 + SandyBrown = IsRGB | IsValid | 0xF4A460 + SeaGreen = IsRGB | IsValid | 0x2E8B57 + Seashell = IsRGB | IsValid | 0xFFF5EE + Sienna = IsRGB | IsValid | 0xA0522D + Skyblue = IsRGB | IsValid | 0x87CEEB + SlateBlue = IsRGB | IsValid | 0x6A5ACD + SlateGray = IsRGB | IsValid | 0x708090 + Snow = IsRGB | IsValid | 0xFFFAFA + SpringGreen = IsRGB | IsValid | 0x00FF7F + SteelBlue = IsRGB | IsValid | 0x4682B4 + Tan = IsRGB | IsValid | 0xD2B48C + Thistle = IsRGB | IsValid | 0xD8BFD8 + Tomato = IsRGB | IsValid | 0xFF6347 + Turquoise = IsRGB | IsValid | 0x40E0D0 + Violet = IsRGB | IsValid | 0xEE82EE + Wheat = IsRGB | IsValid | 0xF5DEB3 + WhiteSmoke = IsRGB | IsValid | 0xF5F5F5 + YellowGreen = IsRGB | IsValid | 0x9ACD32 +) + +// These are aliases for the color gray, because some of us spell +// it as grey. +const ( + Grey = Gray + DimGrey = DimGray + DarkGrey = DarkGray + DarkSlateGrey = DarkSlateGray + LightGrey = LightGray + LightSlateGrey = LightSlateGray + SlateGrey = SlateGray +) + +// ColorValues maps color constants to their RGB values. +var ColorValues = map[Color]int32{ + Black: 0x000000, + Maroon: 0x800000, + Green: 0x008000, + Olive: 0x808000, + Navy: 0x000080, + Purple: 0x800080, + Teal: 0x008080, + Silver: 0xC0C0C0, + Gray: 0x808080, + Red: 0xFF0000, + Lime: 0x00FF00, + Yellow: 0xFFFF00, + Blue: 0x0000FF, + Fuchsia: 0xFF00FF, + Aqua: 0x00FFFF, + White: 0xFFFFFF, + XTerm16: 0x000000, // black + XTerm17: 0x00005F, + XTerm18: 0x000087, + XTerm19: 0x0000AF, + XTerm20: 0x0000D7, + XTerm21: 0x0000FF, // blue + XTerm22: 0x005F00, + XTerm23: 0x005F5F, + XTerm24: 0x005F87, + XTerm25: 0x005FAF, + XTerm26: 0x005FD7, + XTerm27: 0x005FFF, + XTerm28: 0x008700, + XTerm29: 0x00875F, + XTerm30: 0x008787, + XTerm31: 0x0087Af, + XTerm32: 0x0087D7, + XTerm33: 0x0087FF, + XTerm34: 0x00AF00, + XTerm35: 0x00AF5F, + XTerm36: 0x00AF87, + XTerm37: 0x00AFAF, + XTerm38: 0x00AFD7, + XTerm39: 0x00AFFF, + XTerm40: 0x00D700, + XTerm41: 0x00D75F, + XTerm42: 0x00D787, + XTerm43: 0x00D7AF, + XTerm44: 0x00D7D7, + XTerm45: 0x00D7FF, + XTerm46: 0x00FF00, // lime + XTerm47: 0x00FF5F, + XTerm48: 0x00FF87, + XTerm49: 0x00FFAF, + XTerm50: 0x00FFd7, + XTerm51: 0x00FFFF, // aqua + XTerm52: 0x5F0000, + XTerm53: 0x5F005F, + XTerm54: 0x5F0087, + XTerm55: 0x5F00AF, + XTerm56: 0x5F00D7, + XTerm57: 0x5F00FF, + XTerm58: 0x5F5F00, + XTerm59: 0x5F5F5F, + XTerm60: 0x5F5F87, + XTerm61: 0x5F5FAF, + XTerm62: 0x5F5FD7, + XTerm63: 0x5F5FFF, + XTerm64: 0x5F8700, + XTerm65: 0x5F875F, + XTerm66: 0x5F8787, + XTerm67: 0x5F87AF, + XTerm68: 0x5F87D7, + XTerm69: 0x5F87FF, + XTerm70: 0x5FAF00, + XTerm71: 0x5FAF5F, + XTerm72: 0x5FAF87, + XTerm73: 0x5FAFAF, + XTerm74: 0x5FAFD7, + XTerm75: 0x5FAFFF, + XTerm76: 0x5FD700, + XTerm77: 0x5FD75F, + XTerm78: 0x5FD787, + XTerm79: 0x5FD7AF, + XTerm80: 0x5FD7D7, + XTerm81: 0x5FD7FF, + XTerm82: 0x5FFF00, + XTerm83: 0x5FFF5F, + XTerm84: 0x5FFF87, + XTerm85: 0x5FFFAF, + XTerm86: 0x5FFFD7, + XTerm87: 0x5FFFFF, + XTerm88: 0x870000, + XTerm89: 0x87005F, + XTerm90: 0x870087, + XTerm91: 0x8700AF, + XTerm92: 0x8700D7, + XTerm93: 0x8700FF, + XTerm94: 0x875F00, + XTerm95: 0x875F5F, + XTerm96: 0x875F87, + XTerm97: 0x875FAF, + XTerm98: 0x875FD7, + XTerm99: 0x875FFF, + XTerm100: 0x878700, + XTerm101: 0x87875F, + XTerm102: 0x878787, + XTerm103: 0x8787AF, + XTerm104: 0x8787D7, + XTerm105: 0x8787FF, + XTerm106: 0x87AF00, + XTerm107: 0x87AF5F, + XTerm108: 0x87AF87, + XTerm109: 0x87AFAF, + XTerm110: 0x87AFD7, + XTerm111: 0x87AFFF, + XTerm112: 0x87D700, + XTerm113: 0x87D75F, + XTerm114: 0x87D787, + XTerm115: 0x87D7AF, + XTerm116: 0x87D7D7, + XTerm117: 0x87D7FF, + XTerm118: 0x87FF00, + XTerm119: 0x87FF5F, + XTerm120: 0x87FF87, + XTerm121: 0x87FFAF, + XTerm122: 0x87FFD7, + XTerm123: 0x87FFFF, + XTerm124: 0xAF0000, + XTerm125: 0xAF005F, + XTerm126: 0xAF0087, + XTerm127: 0xAF00AF, + XTerm128: 0xAF00D7, + XTerm129: 0xAF00FF, + XTerm130: 0xAF5F00, + XTerm131: 0xAF5F5F, + XTerm132: 0xAF5F87, + XTerm133: 0xAF5FAF, + XTerm134: 0xAF5FD7, + XTerm135: 0xAF5FFF, + XTerm136: 0xAF8700, + XTerm137: 0xAF875F, + XTerm138: 0xAF8787, + XTerm139: 0xAF87AF, + XTerm140: 0xAF87D7, + XTerm141: 0xAF87FF, + XTerm142: 0xAFAF00, + XTerm143: 0xAFAF5F, + XTerm144: 0xAFAF87, + XTerm145: 0xAFAFAF, + XTerm146: 0xAFAFD7, + XTerm147: 0xAFAFFF, + XTerm148: 0xAFD700, + XTerm149: 0xAFD75F, + XTerm150: 0xAFD787, + XTerm151: 0xAFD7AF, + XTerm152: 0xAFD7D7, + XTerm153: 0xAFD7FF, + XTerm154: 0xAFFF00, + XTerm155: 0xAFFF5F, + XTerm156: 0xAFFF87, + XTerm157: 0xAFFFAF, + XTerm158: 0xAFFFD7, + XTerm159: 0xAFFFFF, + XTerm160: 0xD70000, + XTerm161: 0xD7005F, + XTerm162: 0xD70087, + XTerm163: 0xD700AF, + XTerm164: 0xD700D7, + XTerm165: 0xD700FF, + XTerm166: 0xD75F00, + XTerm167: 0xD75F5F, + XTerm168: 0xD75F87, + XTerm169: 0xD75FAF, + XTerm170: 0xD75FD7, + XTerm171: 0xD75FFF, + XTerm172: 0xD78700, + XTerm173: 0xD7875F, + XTerm174: 0xD78787, + XTerm175: 0xD787AF, + XTerm176: 0xD787D7, + XTerm177: 0xD787FF, + XTerm178: 0xD7AF00, + XTerm179: 0xD7AF5F, + XTerm180: 0xD7AF87, + XTerm181: 0xD7AFAF, + XTerm182: 0xD7AFD7, + XTerm183: 0xD7AFFF, + XTerm184: 0xD7D700, + XTerm185: 0xD7D75F, + XTerm186: 0xD7D787, + XTerm187: 0xD7D7AF, + XTerm188: 0xD7D7D7, + XTerm189: 0xD7D7FF, + XTerm190: 0xD7FF00, + XTerm191: 0xD7FF5F, + XTerm192: 0xD7FF87, + XTerm193: 0xD7FFAF, + XTerm194: 0xD7FFD7, + XTerm195: 0xD7FFFF, + XTerm196: 0xFF0000, // red + XTerm197: 0xFF005F, + XTerm198: 0xFF0087, + XTerm199: 0xFF00AF, + XTerm200: 0xFF00D7, + XTerm201: 0xFF00FF, // fuchsia + XTerm202: 0xFF5F00, + XTerm203: 0xFF5F5F, + XTerm204: 0xFF5F87, + XTerm205: 0xFF5FAF, + XTerm206: 0xFF5FD7, + XTerm207: 0xFF5FFF, + XTerm208: 0xFF8700, + XTerm209: 0xFF875F, + XTerm210: 0xFF8787, + XTerm211: 0xFF87AF, + XTerm212: 0xFF87D7, + XTerm213: 0xFF87FF, + XTerm214: 0xFFAF00, + XTerm215: 0xFFAF5F, + XTerm216: 0xFFAF87, + XTerm217: 0xFFAFAF, + XTerm218: 0xFFAFD7, + XTerm219: 0xFFAFFF, + XTerm220: 0xFFD700, + XTerm221: 0xFFD75F, + XTerm222: 0xFFD787, + XTerm223: 0xFFD7AF, + XTerm224: 0xFFD7D7, + XTerm225: 0xFFD7FF, + XTerm226: 0xFFFF00, // yellow + XTerm227: 0xFFFF5F, + XTerm228: 0xFFFF87, + XTerm229: 0xFFFFAF, + XTerm230: 0xFFFFD7, + XTerm231: 0xFFFFFF, // white + XTerm232: 0x080808, + XTerm233: 0x121212, + XTerm234: 0x1C1C1C, + XTerm235: 0x262626, + XTerm236: 0x303030, + XTerm237: 0x3A3A3A, + XTerm238: 0x444444, + XTerm239: 0x4E4E4E, + XTerm240: 0x585858, + XTerm241: 0x626262, + XTerm242: 0x6C6C6C, + XTerm243: 0x767676, + XTerm244: 0x808080, // grey + XTerm245: 0x8A8A8A, + XTerm246: 0x949494, + XTerm247: 0x9E9E9E, + XTerm248: 0xA8A8A8, + XTerm249: 0xB2B2B2, + XTerm250: 0xBCBCBC, + XTerm251: 0xC6C6C6, + XTerm252: 0xD0D0D0, + XTerm253: 0xDADADA, + XTerm254: 0xE4E4E4, + XTerm255: 0xEEEEEE, + AliceBlue: 0xF0F8FF, + AntiqueWhite: 0xFAEBD7, + AquaMarine: 0x7FFFD4, + Azure: 0xF0FFFF, + Beige: 0xF5F5DC, + Bisque: 0xFFE4C4, + BlanchedAlmond: 0xFFEBCD, + BlueViolet: 0x8A2BE2, + Brown: 0xA52A2A, + BurlyWood: 0xDEB887, + CadetBlue: 0x5F9EA0, + Chartreuse: 0x7FFF00, + Chocolate: 0xD2691E, + Coral: 0xFF7F50, + CornflowerBlue: 0x6495ED, + Cornsilk: 0xFFF8DC, + Crimson: 0xDC143C, + DarkBlue: 0x00008B, + DarkCyan: 0x008B8B, + DarkGoldenrod: 0xB8860B, + DarkGray: 0xA9A9A9, + DarkGreen: 0x006400, + DarkKhaki: 0xBDB76B, + DarkMagenta: 0x8B008B, + DarkOliveGreen: 0x556B2F, + DarkOrange: 0xFF8C00, + DarkOrchid: 0x9932CC, + DarkRed: 0x8B0000, + DarkSalmon: 0xE9967A, + DarkSeaGreen: 0x8FBC8F, + DarkSlateBlue: 0x483D8B, + DarkSlateGray: 0x2F4F4F, + DarkTurquoise: 0x00CED1, + DarkViolet: 0x9400D3, + DeepPink: 0xFF1493, + DeepSkyBlue: 0x00BFFF, + DimGray: 0x696969, + DodgerBlue: 0x1E90FF, + FireBrick: 0xB22222, + FloralWhite: 0xFFFAF0, + ForestGreen: 0x228B22, + Gainsboro: 0xDCDCDC, + GhostWhite: 0xF8F8FF, + Gold: 0xFFD700, + Goldenrod: 0xDAA520, + GreenYellow: 0xADFF2F, + Honeydew: 0xF0FFF0, + HotPink: 0xFF69B4, + IndianRed: 0xCD5C5C, + Indigo: 0x4B0082, + Ivory: 0xFFFFF0, + Khaki: 0xF0E68C, + Lavender: 0xE6E6FA, + LavenderBlush: 0xFFF0F5, + LawnGreen: 0x7CFC00, + LemonChiffon: 0xFFFACD, + LightBlue: 0xADD8E6, + LightCoral: 0xF08080, + LightCyan: 0xE0FFFF, + LightGoldenrodYellow: 0xFAFAD2, + LightGray: 0xD3D3D3, + LightGreen: 0x90EE90, + LightPink: 0xFFB6C1, + LightSalmon: 0xFFA07A, + LightSeaGreen: 0x20B2AA, + LightSkyBlue: 0x87CEFA, + LightSlateGray: 0x778899, + LightSteelBlue: 0xB0C4DE, + LightYellow: 0xFFFFE0, + LimeGreen: 0x32CD32, + Linen: 0xFAF0E6, + MediumAquamarine: 0x66CDAA, + MediumBlue: 0x0000CD, + MediumOrchid: 0xBA55D3, + MediumPurple: 0x9370DB, + MediumSeaGreen: 0x3CB371, + MediumSlateBlue: 0x7B68EE, + MediumSpringGreen: 0x00FA9A, + MediumTurquoise: 0x48D1CC, + MediumVioletRed: 0xC71585, + MidnightBlue: 0x191970, + MintCream: 0xF5FFFA, + MistyRose: 0xFFE4E1, + Moccasin: 0xFFE4B5, + NavajoWhite: 0xFFDEAD, + OldLace: 0xFDF5E6, + OliveDrab: 0x6B8E23, + Orange: 0xFFA500, + OrangeRed: 0xFF4500, + Orchid: 0xDA70D6, + PaleGoldenrod: 0xEEE8AA, + PaleGreen: 0x98FB98, + PaleTurquoise: 0xAFEEEE, + PaleVioletRed: 0xDB7093, + PapayaWhip: 0xFFEFD5, + PeachPuff: 0xFFDAB9, + Peru: 0xCD853F, + Pink: 0xFFC0CB, + Plum: 0xDDA0DD, + PowderBlue: 0xB0E0E6, + RebeccaPurple: 0x663399, + RosyBrown: 0xBC8F8F, + RoyalBlue: 0x4169E1, + SaddleBrown: 0x8B4513, + Salmon: 0xFA8072, + SandyBrown: 0xF4A460, + SeaGreen: 0x2E8B57, + Seashell: 0xFFF5EE, + Sienna: 0xA0522D, + Skyblue: 0x87CEEB, + SlateBlue: 0x6A5ACD, + SlateGray: 0x708090, + Snow: 0xFFFAFA, + SpringGreen: 0x00FF7F, + SteelBlue: 0x4682B4, + Tan: 0xD2B48C, + Thistle: 0xD8BFD8, + Tomato: 0xFF6347, + Turquoise: 0x40E0D0, + Violet: 0xEE82EE, + Wheat: 0xF5DEB3, + WhiteSmoke: 0xF5F5F5, + YellowGreen: 0x9ACD32, +} + +// Special colors. +const ( + // Reset is used to indicate that the color should use the + // vanilla terminal colors. (Basically go back to the defaults.) + Reset = IsSpecial | iota + + // None indicates that we should not change the color from + // whatever is already displayed. This can only be used in limited + // circumstances. + None +) + +// Names holds the written names of colors. Useful to present a list of +// recognized named colors. +var Names = map[string]Color{ + "black": Black, + "maroon": Maroon, + "green": Green, + "olive": Olive, + "navy": Navy, + "purple": Purple, + "teal": Teal, + "silver": Silver, + "gray": Gray, + "red": Red, + "lime": Lime, + "yellow": Yellow, + "blue": Blue, + "fuchsia": Fuchsia, + "aqua": Aqua, + "white": White, + "aliceblue": AliceBlue, + "antiquewhite": AntiqueWhite, + "aquamarine": AquaMarine, + "azure": Azure, + "beige": Beige, + "bisque": Bisque, + "blanchedalmond": BlanchedAlmond, + "blueviolet": BlueViolet, + "brown": Brown, + "burlywood": BurlyWood, + "cadetblue": CadetBlue, + "chartreuse": Chartreuse, + "chocolate": Chocolate, + "coral": Coral, + "cornflowerblue": CornflowerBlue, + "cornsilk": Cornsilk, + "crimson": Crimson, + "darkblue": DarkBlue, + "darkcyan": DarkCyan, + "darkgoldenrod": DarkGoldenrod, + "darkgray": DarkGray, + "darkgreen": DarkGreen, + "darkkhaki": DarkKhaki, + "darkmagenta": DarkMagenta, + "darkolivegreen": DarkOliveGreen, + "darkorange": DarkOrange, + "darkorchid": DarkOrchid, + "darkred": DarkRed, + "darksalmon": DarkSalmon, + "darkseagreen": DarkSeaGreen, + "darkslateblue": DarkSlateBlue, + "darkslategray": DarkSlateGray, + "darkturquoise": DarkTurquoise, + "darkviolet": DarkViolet, + "deeppink": DeepPink, + "deepskyblue": DeepSkyBlue, + "dimgray": DimGray, + "dodgerblue": DodgerBlue, + "firebrick": FireBrick, + "floralwhite": FloralWhite, + "forestgreen": ForestGreen, + "gainsboro": Gainsboro, + "ghostwhite": GhostWhite, + "gold": Gold, + "goldenrod": Goldenrod, + "greenyellow": GreenYellow, + "honeydew": Honeydew, + "hotpink": HotPink, + "indianred": IndianRed, + "indigo": Indigo, + "ivory": Ivory, + "khaki": Khaki, + "lavender": Lavender, + "lavenderblush": LavenderBlush, + "lawngreen": LawnGreen, + "lemonchiffon": LemonChiffon, + "lightblue": LightBlue, + "lightcoral": LightCoral, + "lightcyan": LightCyan, + "lightgoldenrodyellow": LightGoldenrodYellow, + "lightgray": LightGray, + "lightgreen": LightGreen, + "lightpink": LightPink, + "lightsalmon": LightSalmon, + "lightseagreen": LightSeaGreen, + "lightskyblue": LightSkyBlue, + "lightslategray": LightSlateGray, + "lightsteelblue": LightSteelBlue, + "lightyellow": LightYellow, + "limegreen": LimeGreen, + "linen": Linen, + "mediumaquamarine": MediumAquamarine, + "mediumblue": MediumBlue, + "mediumorchid": MediumOrchid, + "mediumpurple": MediumPurple, + "mediumseagreen": MediumSeaGreen, + "mediumslateblue": MediumSlateBlue, + "mediumspringgreen": MediumSpringGreen, + "mediumturquoise": MediumTurquoise, + "mediumvioletred": MediumVioletRed, + "midnightblue": MidnightBlue, + "mintcream": MintCream, + "mistyrose": MistyRose, + "moccasin": Moccasin, + "navajowhite": NavajoWhite, + "oldlace": OldLace, + "olivedrab": OliveDrab, + "orange": Orange, + "orangered": OrangeRed, + "orchid": Orchid, + "palegoldenrod": PaleGoldenrod, + "palegreen": PaleGreen, + "paleturquoise": PaleTurquoise, + "palevioletred": PaleVioletRed, + "papayawhip": PapayaWhip, + "peachpuff": PeachPuff, + "peru": Peru, + "pink": Pink, + "plum": Plum, + "powderblue": PowderBlue, + "rebeccapurple": RebeccaPurple, + "rosybrown": RosyBrown, + "royalblue": RoyalBlue, + "saddlebrown": SaddleBrown, + "salmon": Salmon, + "sandybrown": SandyBrown, + "seagreen": SeaGreen, + "seashell": Seashell, + "sienna": Sienna, + "skyblue": Skyblue, + "slateblue": SlateBlue, + "slategray": SlateGray, + "snow": Snow, + "springgreen": SpringGreen, + "steelblue": SteelBlue, + "tan": Tan, + "thistle": Thistle, + "tomato": Tomato, + "turquoise": Turquoise, + "violet": Violet, + "wheat": Wheat, + "whitesmoke": WhiteSmoke, + "yellowgreen": YellowGreen, + "grey": Gray, + "dimgrey": DimGray, + "darkgrey": DarkGray, + "darkslategrey": DarkSlateGray, + "lightgrey": LightGray, + "lightslategrey": LightSlateGray, + "slategrey": SlateGray, +} + +// Valid indicates the color is a valid value (has been set). +func (c Color) Valid() bool { + return c&IsValid != 0 +} + +// IsRGB is true if the color is an RGB specific value. +func (c Color) IsRGB() bool { + return c&(IsValid|IsRGB) == (IsValid | IsRGB) +} + +// CSS returns the CSS hex string ( #ABCDEF ) if valid +// if not a valid color returns empty string +func (c Color) CSS() string { + if !c.Valid() { + return "" + } + return fmt.Sprintf("#%06X", c.Hex()) +} + +// String implements fmt.Stringer to return either the +// W3C name if it has one or the CSS hex string '#ABCDEF' +func (c Color) String() string { + if !c.Valid() { + switch c { + case None: + return "none" + case Default: + return "default" + case Reset: + return "reset" + } + return "" + } + return c.Name(true) +} + +// Name returns W3C name or an empty string if no arguments +// if passed true as an argument it will falls back to +// the CSS hex string if no W3C name found '#ABCDEF' +func (c Color) Name(css ...bool) string { + for name, hex := range Names { + if c == hex { + return name + } + } + if len(css) > 0 && css[0] { + return c.CSS() + } + return "" +} + +// Hex returns the color's hexadecimal RGB 24-bit value with each component +// consisting of a single byte, R << 16 | G << 8 | B. If the color +// is unknown or unset, -1 is returned. +func (c Color) Hex() int32 { + if !c.Valid() { + return -1 + } + if c&IsRGB != 0 { + return int32(c & 0xffffff) + } + if v, ok := ColorValues[c]; ok { + return v + } + return -1 +} + +// RGB returns the red, green, and blue components of the color, with +// each component represented as a value 0-255. In the event that the +// color cannot be broken up (not set usually), -1 is returned for each value. +func (c Color) RGB() (int32, int32, int32) { + v := c.Hex() + if v < 0 { + return -1, -1, -1 + } + return (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff +} + +// TrueColor returns the true color (RGB) version of the provided color. +// This is useful for ensuring color accuracy when using named colors. +// This will override terminal theme colors. +func (c Color) TrueColor() Color { + if !c.Valid() { + return Default + } + if c&IsRGB != 0 { + return c | IsValid + } + if hex := c.Hex(); hex < 0 { + return Default + } else { + return Color(hex) | IsRGB | IsValid + } +} + +// RGBA makes these colors directly usable as imageColor colors. +// The values are scaled only to 16 bits. Invalid colors are returned +// with all values being zero (notably the alpha is zero, so fully transparent), +// otherwise the alpha channel is set to 0xffff (fully opaque). +func (c Color) RGBA() (r, g, b, a uint32) { + if !c.Valid() { + return 0, 0, 0, 0 + } + r1, g1, b1 := c.RGB() + r = uint32(r1) + g = uint32(g1) + b = uint32(b1) + r = r | r<<8 + g = g | g<<8 + b = b | b<<8 + a = 0xffff + return r, g, b, a +} + +// NewRGBColor returns a new color with the given red, green, and blue values. +// Each value must be represented in the range 0-255. +func NewRGBColor(r, g, b int32) Color { + return NewHexColor(((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) +} + +// NewHexColor returns a color using the given 24-bit RGB value. +func NewHexColor(v int32) Color { + return IsRGB | Color(v) | IsValid +} + +// GetColor creates a Color from a color name (W3C name). A hex value may +// be supplied as a string in the format "#ffffff". +func GetColor(name string) Color { + if c, ok := Names[name]; ok { + return c + } + if len(name) == 7 && name[0] == '#' { + if v, e := strconv.ParseInt(name[1:], 16, 32); e == nil { + return NewHexColor(int32(v)) + } + } + return Default +} + +// PaletteColor creates a color based on the palette index. +func PaletteColor(index int) Color { + return Color(index) | IsValid +} + +// FromImageColor converts an image/color.Color into Color. +// The alpha value is limited to just zero and non-zero, so it should +// be tracked separately if full detail is needed. (A zero alpha +// becomes the default color, which means no color change at all.) +func FromImageColor(imageColor ic.Color) Color { + r, g, b, a := imageColor.RGBA() + if a == 0 { + return Default + } + // NOTE image/color.Color RGB values range is [0, 0xFFFF] as uint32 + return NewRGBColor(int32(r>>8), int32(g>>8), int32(b>>8)) +} diff --git a/vendor/github.com/gdamore/tcell/v2/colorfit.go b/vendor/github.com/gdamore/tcell/v3/color/fit.go similarity index 70% rename from vendor/github.com/gdamore/tcell/v2/colorfit.go rename to vendor/github.com/gdamore/tcell/v3/color/fit.go index f690097f5..c8e292d34 100644 --- a/vendor/github.com/gdamore/tcell/v2/colorfit.go +++ b/vendor/github.com/gdamore/tcell/v3/color/fit.go @@ -1,8 +1,8 @@ -// Copyright 2016 The TCell Authors +// Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -12,19 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -package tcell +package color import ( - "math" - "github.com/lucasb-eyer/go-colorful" ) -// FindColor attempts to find a given color, or the best match possible for it, +// Find attempts to find a given color, or the best match possible for it, // from the palette given. This is an expensive operation, so results should // be cached by the caller. -func FindColor(c Color, palette []Color) Color { - match := ColorDefault +func Find(c Color, palette []Color) Color { + match := Default dist := float64(0) r, g, b := c.RGB() c1 := colorful.Color{ @@ -41,10 +39,9 @@ func FindColor(c Color, palette []Color) Color { } // CIE94 is more accurate, but really really expensive. nd := c1.DistanceCIE76(c2) - if math.IsNaN(nd) { - nd = math.Inf(1) - } - if match == ColorDefault || nd < dist { + // NB: nd < dist is false if is NaN. + // We have never seen a case where the CIE76 algorithm returns NaN. + if match == Default || nd < dist { match = d dist = nd } diff --git a/vendor/github.com/gdamore/tcell/v3/doc.go b/vendor/github.com/gdamore/tcell/v3/doc.go new file mode 100644 index 000000000..54075d455 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/doc.go @@ -0,0 +1,23 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 tcell provides a lower-level, portable API for building +// programs that interact with terminals or consoles. It works with +// both common (and many uncommon!) terminals or terminal emulators, +// and Windows console implementations. +// +// It supports rich color, and modern terminal capabilities such as +// rich key reporting, mouse tracking, bracketed paste, desktop notifications +// and 24-bit color, when the underlying terminal supports it. +package tcell diff --git a/vendor/github.com/gdamore/tcell/v2/charset_stub.go b/vendor/github.com/gdamore/tcell/v3/eastasian.go similarity index 64% rename from vendor/github.com/gdamore/tcell/v2/charset_stub.go rename to vendor/github.com/gdamore/tcell/v3/eastasian.go index 829be2c26..dd3abc0d0 100644 --- a/vendor/github.com/gdamore/tcell/v2/charset_stub.go +++ b/vendor/github.com/gdamore/tcell/v3/eastasian.go @@ -1,11 +1,8 @@ -//go:build nacl -// +build nacl - -// Copyright 2015 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -17,6 +14,8 @@ package tcell -func getCharset() string { - return "" -} +import ( + "github.com/gdamore/tcell/v3/internal/widthutil" +) + +var textWidthOptions = widthutil.Options() diff --git a/vendor/github.com/gdamore/tcell/v2/encoding.go b/vendor/github.com/gdamore/tcell/v3/encoding.go similarity index 81% rename from vendor/github.com/gdamore/tcell/v2/encoding.go rename to vendor/github.com/gdamore/tcell/v3/encoding.go index b7644c27e..0a06d377e 100644 --- a/vendor/github.com/gdamore/tcell/v2/encoding.go +++ b/vendor/github.com/gdamore/tcell/v3/encoding.go @@ -1,8 +1,8 @@ // 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -25,23 +25,17 @@ import ( var encodings map[string]encoding.Encoding var encodingLk sync.Mutex -var encodingFallback EncodingFallback = EncodingFallbackFail +var encodingFallback EncodingFallback = EncodingFallbackASCII // RegisterEncoding may be called by the application to register an encoding. // The presence of additional encodings will facilitate application usage with // terminal environments where the I/O subsystem does not support Unicode. // -// Windows systems use Unicode natively, and do not need any of the encoding -// subsystem when using Windows Console screens. +// Modern systems and terminal emulators usually use UTF-8, and for those +// systems, this API is also unnecessary. For example, Windows, macOS, and +// modern Linux systems generally will work out of the box without any of this. // -// Please see the Go documentation for golang.org/x/text/encoding -- most of -// the common ones exist already as stock variables. For example, ISO8859-15 -// can be registered using the following code: -// -// import "golang.org/x/text/encoding/charmap" -// -// ... -// RegisterEncoding("ISO8859-15", charmap.ISO8859_15) +// Use of UTF-8 is recommended when possible, as it saves quite a lot processing overhead. // // Aliases can be registered as well, for example "8859-15" could be an alias // for "ISO8859-15". @@ -57,16 +51,14 @@ var encodingFallback EncodingFallback = EncodingFallbackFail // or "C", then we assume US-ASCII (the POSIX 'portable character set' // and assume all other characters are somehow invalid.) // -// Modern POSIX systems and terminal emulators may use UTF-8, and for those -// systems, this API is also unnecessary. For example, Darwin (MacOS X) and -// modern Linux running modern xterm generally will out of the box without -// any of this. Use of UTF-8 is recommended when possible, as it saves -// quite a lot processing overhead. +// Please see the Go documentation for golang.org/x/text/encoding -- most of +// the common ones exist already as stock variables. For example, ISO8859-15 +// can be registered using the following code: // // Note that some encodings are quite large (for example GB18030 which is a // superset of Unicode) and so the application size can be expected to // increase quite a bit as each encoding is added. - +// // The East Asian encodings have been seen to add 100-200K per encoding to the // size of the resulting binary. func RegisterEncoding(charset string, enc encoding.Encoding) { @@ -82,22 +74,21 @@ func RegisterEncoding(charset string, enc encoding.Encoding) { // supported automatically. Other character sets must be added using the // RegisterEncoding API. (A large group of nearly all of them can be // added using the RegisterAll function in the encoding sub package.) +// The default action will be to fallback to UTF-8. type EncodingFallback int const ( + // EncodingFallbackUTF8 behavior causes GetEncoding to assume + // UTF8 can pass unmodified upon failure. + EncodingFallbackUTF8 = iota + // EncodingFallbackFail behavior causes GetEncoding to fail // when it cannot find an encoding. - EncodingFallbackFail = iota + EncodingFallbackFail // EncodingFallbackASCII behavior causes GetEncoding to fall back // to a 7-bit ASCII encoding, if no other encoding can be found. EncodingFallbackASCII - - // EncodingFallbackUTF8 behavior causes GetEncoding to assume - // UTF8 can pass unmodified upon failure. Note that this behavior - // is not recommended, unless you are sure your terminal can cope - // with real UTF8 sequences. - EncodingFallbackUTF8 ) // SetEncodingFallback changes the behavior of GetEncoding when a suitable diff --git a/vendor/github.com/gdamore/tcell/v2/errors.go b/vendor/github.com/gdamore/tcell/v3/errors.go similarity index 64% rename from vendor/github.com/gdamore/tcell/v2/errors.go rename to vendor/github.com/gdamore/tcell/v3/errors.go index 201dff9f8..db17b735f 100644 --- a/vendor/github.com/gdamore/tcell/v2/errors.go +++ b/vendor/github.com/gdamore/tcell/v3/errors.go @@ -1,8 +1,8 @@ -// Copyright 2015 The TCell Authors +// Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -16,24 +16,12 @@ package tcell import ( "errors" - "time" - - "github.com/gdamore/tcell/v2/terminfo" ) 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 = terminfo.ErrTermNotFound - // ErrNoScreen indicates that no suitable screen could be found. // This may result from attempting to run on a platform where there - // is no support for either termios or console I/O (such as nacl), + // is no support for either termios or console I/O (such as js), // or from running in an environment where there is no access to // a suitable console/terminal device. (For example, running on // without a controlling TTY or with no /dev/tty on POSIX platforms.) @@ -53,21 +41,25 @@ var ( // An EventError is an event representing some sort of error, and carries // an error payload. type EventError struct { - t time.Time + EventTime err error } -// When returns the time when the event was created. -func (ev *EventError) When() time.Time { - return ev.t -} - // Error implements the error. func (ev *EventError) Error() string { return ev.err.Error() } +// Unwrap exposes the underlying error payload so callers can use +// errors.Is / errors.As to match against sentinel values such as +// io.EOF. +func (ev *EventError) Unwrap() error { + return ev.err +} + // NewEventError creates an ErrorEvent with the given error payload. func NewEventError(err error) *EventError { - return &EventError{t: time.Now(), err: err} + ev := &EventError{err: err} + ev.SetEventNow() + return ev } diff --git a/vendor/github.com/gdamore/tcell/v2/event.go b/vendor/github.com/gdamore/tcell/v3/event.go similarity index 92% rename from vendor/github.com/gdamore/tcell/v2/event.go rename to vendor/github.com/gdamore/tcell/v3/event.go index a3b770063..23440537d 100644 --- a/vendor/github.com/gdamore/tcell/v2/event.go +++ b/vendor/github.com/gdamore/tcell/v3/event.go @@ -1,8 +1,8 @@ // Copyright 2015 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // diff --git a/vendor/github.com/gdamore/tcell/v2/focus.go b/vendor/github.com/gdamore/tcell/v3/focus.go similarity index 80% rename from vendor/github.com/gdamore/tcell/v2/focus.go rename to vendor/github.com/gdamore/tcell/v3/focus.go index e9b93ef6d..cadd68780 100644 --- a/vendor/github.com/gdamore/tcell/v2/focus.go +++ b/vendor/github.com/gdamore/tcell/v3/focus.go @@ -1,8 +1,8 @@ // Copyright 2023 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -17,12 +17,14 @@ package tcell // EventFocus is a focus event. It is sent when the terminal window (or tab) // gets or loses focus. type EventFocus struct { - *EventTime + EventTime // True if the window received focus, false if it lost focus Focused bool } func NewEventFocus(focused bool) *EventFocus { - return &EventFocus{Focused: focused} + ev := &EventFocus{Focused: focused} + ev.SetEventNow() + return ev } diff --git a/vendor/github.com/gdamore/tcell/v2/input.go b/vendor/github.com/gdamore/tcell/v3/input.go similarity index 54% rename from vendor/github.com/gdamore/tcell/v2/input.go rename to vendor/github.com/gdamore/tcell/v3/input.go index d5dbf51a6..32e0452e6 100644 --- a/vendor/github.com/gdamore/tcell/v2/input.go +++ b/vendor/github.com/gdamore/tcell/v3/input.go @@ -1,8 +1,8 @@ -// Copyright 2025 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -22,6 +22,9 @@ // There is unfortunately *one* conflict, with aixterm, for CSI-P - which is KeyDelete // in aixterm, but F1 in others. +//go:build !js && !wasm +// +build !js,!wasm + package tcell import ( @@ -33,62 +36,70 @@ import ( "time" "unicode/utf16" "unicode/utf8" + + "github.com/gdamore/tcell/v3/vt" ) -type inpState int +type inputState int const ( - inpStateInit = inpState(iota) - inpStateUtf - inpStateEsc - inpStateCsi // control sequence introducer - inpStateOsc // operating system command - inpStateDcs // device control string - inpStateSos // start of string (unused) - inpStatePm // privacy message (unused) - inpStateApc // application program command - inpStateSt // string terminator - inpStateSs2 // single shift 2 - inpStateSs3 // single shift 3 - inpStateLFK // linux F-key (not ECMA-48 compliant - bogus CSI) + istInit = inputState(iota) + istUtf // utf8 state + istEsc // escape + istCsi // control sequence introducer + istOsc // operating system command + istDcs // device control string + istSos // start of string (unused) + istPm // privacy message (unused) + istApc // application program command + istSt // string terminator + istSs2 // single shift 2 + istSs3 // single shift 3 + istLnx // linux F-key (not ECMA-48 compliant - bogus CSI) + istXda // extended device attributes (ESC P Ps ST) ) -type InputProcessor interface { - ScanUTF8([]byte) - ScanUTF16([]uint16) - SetSize(rows, cols int) -} - -func NewInputProcessor(eq chan<- Event) InputProcessor { - return &inputProcessor{ +func newInputParser(eq chan<- Event) *inputParser { + return &inputParser{ evch: eq, buf: make([]rune, 0, 128), } } -type inputProcessor struct { - ut8 []byte - ut16 []uint16 - buf []rune - scratch []byte - csiParams []byte - csiInterm []byte - escaped bool - btnDown bool // mouse button tracking for broken terms - state inpState - strState inpState // saved str state (needed for ST) - timer *time.Timer - expire time.Time - l sync.Mutex - encBuf []rune - evch chan<- Event - rows int // used for clipping mouse coordinates - cols int // used for clipping mouse coordinates - surrogate rune - nested *inputProcessor +type inputParser struct { + buf []rune // bytes to process (ingest data) + utfBuf []byte // accrued UTF8 bytes + strBuf []byte // accrued string data (for ST, OSC, etc.) + csiParams []byte // accrued parameter bytes for CSI (and SS3) + csiInterm []byte // accrued intermediate bytes for CSI + escChar byte // last byte for escape + escaped bool // true if next key should be modified by ESC + btnsDown ButtonMask // mouse buttons down (excludes wheel buttons) + state inputState // tracks processor state + strState inputState // saved str state (needed for ST) + l sync.Mutex // protects local state + evch chan<- Event // where events are routed + rows int // used for clipping mouse coordinates + cols int // used for clipping mouse coordinates + keyTime time.Time // time of last key press / byte ingested + nested *inputParser // for buggy win32-input-mode implementations + surrogate rune // high surrogate pair seen (for Win32 input mode) } -func (ip *inputProcessor) SetSize(w, h int) { +// Waiting returns true if the processor is waiting for +// some more input (i.e. we are not in in the initial state.) +// This can occur when we have ambiguous escape sequences, such +// as the lone escape. If this is typed, we expect at least a minimal +// inter-key delay before the next stroke occurs, and the caller +// should check for waiting, and call Scan() or ScanUTF8() to +// finish the processing. (Typically after a delay of around 100ms.) +func (ip *inputParser) Waiting() bool { + ip.l.Lock() + defer ip.l.Unlock() + return ip.state != istInit +} + +func (ip *inputParser) SetSize(w, h int) { if ip.nested != nil { ip.nested.SetSize(w, h) return @@ -101,11 +112,11 @@ func (ip *inputProcessor) SetSize(w, h int) { ip.l.Unlock() }() } -func (ip *inputProcessor) post(ev Event) { +func (ip *inputParser) post(ev Event) { if ip.escaped { ip.escaped = false if ke, ok := ev.(*EventKey); ok { - ev = NewEventKey(ke.Key(), ke.Rune(), ke.Modifiers()|ModAlt) + ev = NewEventKey(ke.Key(), ke.Str(), ke.Modifiers()|ModAlt) } } else if ke, ok := ev.(*EventKey); ok { switch ke.Key() { @@ -119,17 +130,6 @@ func (ip *inputProcessor) post(ev Event) { ip.evch <- ev } -func (ip *inputProcessor) escTimeout() { - ip.l.Lock() - defer ip.l.Unlock() - if ip.state == inpStateEsc && ip.expire.Before(time.Now()) { - // post it - ip.state = inpStateInit - ip.escaped = false - ip.post(NewEventKey(KeyEsc, 0, ModNone)) - } -} - type csiParamMode struct { M rune // Mode P int // Parameter (first) @@ -146,6 +146,7 @@ var csiAllKeys = map[csiParamMode]keyMap{ {M: 'B'}: {Key: KeyDown}, {M: 'C'}: {Key: KeyRight}, {M: 'D'}: {Key: KeyLeft}, + {M: 'E'}: {Key: KeyClear}, {M: 'F'}: {Key: KeyEnd}, {M: 'H'}: {Key: KeyHome}, {M: 'L'}: {Key: KeyInsert}, @@ -214,6 +215,12 @@ var csiAllKeys = map[csiParamMode]keyMap{ {M: 'z', P: 234}: {Key: KeyF11}, {M: 'z', P: 235}: {Key: KeyF12}, {M: 'z', P: 247}: {Key: KeyInsert}, + {M: '^', P: 1}: {Key: KeyHome, Mod: ModCtrl}, + {M: '^', P: 2}: {Key: KeyInsert, Mod: ModCtrl}, + {M: '^', P: 3}: {Key: KeyDelete, Mod: ModCtrl}, + {M: '^', P: 4}: {Key: KeyEnd, Mod: ModCtrl}, + {M: '^', P: 5}: {Key: KeyPgUp, Mod: ModCtrl}, + {M: '^', P: 6}: {Key: KeyPgDn, Mod: ModCtrl}, {M: '^', P: 7}: {Key: KeyHome, Mod: ModCtrl}, {M: '^', P: 8}: {Key: KeyEnd, Mod: ModCtrl}, {M: '^', P: 11}: {Key: KeyF23}, @@ -238,8 +245,19 @@ var csiAllKeys = map[csiParamMode]keyMap{ {M: '^', P: 34}: {Key: KeyF42}, {M: '@', P: 23}: {Key: KeyF43}, {M: '@', P: 24}: {Key: KeyF44}, + {M: '@', P: 1}: {Key: KeyHome, Mod: ModShift | ModCtrl}, + {M: '@', P: 2}: {Key: KeyInsert, Mod: ModShift | ModCtrl}, + {M: '@', P: 3}: {Key: KeyDelete, Mod: ModShift | ModCtrl}, + {M: '@', P: 4}: {Key: KeyEnd, Mod: ModShift | ModCtrl}, + {M: '@', P: 5}: {Key: KeyPgUp, Mod: ModShift | ModCtrl}, + {M: '@', P: 6}: {Key: KeyPgDn, Mod: ModShift | ModCtrl}, + {M: '@', P: 7}: {Key: KeyHome, Mod: ModShift | ModCtrl}, + {M: '@', P: 8}: {Key: KeyEnd, Mod: ModShift | ModCtrl}, + {M: '$', P: 1}: {Key: KeyHome, Mod: ModShift}, {M: '$', P: 2}: {Key: KeyInsert, Mod: ModShift}, {M: '$', P: 3}: {Key: KeyDelete, Mod: ModShift}, + {M: '$', P: 5}: {Key: KeyPgUp, Mod: ModShift}, + {M: '$', P: 6}: {Key: KeyPgDn, Mod: ModShift}, {M: '$', P: 7}: {Key: KeyHome, Mod: ModShift}, {M: '$', P: 8}: {Key: KeyEnd, Mod: ModShift}, {M: '$', P: 23}: {Key: KeyF21}, @@ -349,7 +367,6 @@ var winKeys = map[int]Key{ 0x03: KeyCancel, // vkCancel 0x08: KeyBackspace, // vkBackspace 0x09: KeyTab, // vkTab - 0x0c: KeyClear, // vClear 0x0d: KeyEnter, // vkReturn 0x13: KeyPause, // vkPause 0x1b: KeyEscape, // vkEscape @@ -398,6 +415,7 @@ var ss3Keys = map[rune]Key{ 'B': KeyDown, 'C': KeyRight, 'D': KeyLeft, + 'E': KeyClear, 'F': KeyEnd, 'H': KeyHome, 'P': KeyF1, @@ -421,151 +439,233 @@ var linuxFKeys = map[rune]Key{ 'E': KeyF5, } -func (ip *inputProcessor) scan() { +func (ip *inputParser) scan() { for _, r := range ip.buf { ip.buf = ip.buf[1:] - if r > 0x7F { + ip.escChar = 0 + ip.keyTime = time.Now() + if r >= 0xA0 { // 8-bit extended Unicode we just treat as such - this will swallow anything else queued up - ip.state = inpStateInit - ip.post(NewEventKey(KeyRune, r, ModNone)) + ip.state = istInit + ip.post(NewEventKey(KeyRune, string(r), ModNone)) continue + } else if r >= 0x80 { + // ISO 2022 control chars + ip.state = istEsc + r -= 0x40 + // we fall through so it will be treated as the 7-bit equivalent } switch ip.state { - case inpStateInit: + case istInit: switch r { case '\x1b': // escape.. pending - ip.state = inpStateEsc - if len(ip.buf) == 0 && ip.nested == nil { - ip.expire = time.Now().Add(time.Millisecond * 50) - ip.timer = time.AfterFunc(time.Millisecond*60, ip.escTimeout) - } + ip.state = istEsc + ip.escChar = 0 case '\t': - ip.post(NewEventKey(KeyTab, 0, ModNone)) + ip.post(NewEventKey(KeyTab, "", ModNone)) case '\b', '\x7F': - ip.post(NewEventKey(KeyBackspace, 0, ModNone)) + ip.post(NewEventKey(KeyBackspace, "", ModNone)) case '\r': - ip.post(NewEventKey(KeyEnter, 0, ModNone)) + ip.post(NewEventKey(KeyEnter, "", ModNone)) default: // Control keys - legacy handling - if r < ' ' { - ip.post(NewEventKey(KeyCtrlSpace+Key(r), 0, ModCtrl)) + if r == 0 { + ip.post(NewEventKey(KeyRune, " ", ModCtrl)) + } else if r < ' ' { + ip.post(NewEventKey(KeyRune, string(r+0x40), ModCtrl)) } else { - ip.post(NewEventKey(KeyRune, r, ModNone)) + ip.post(NewEventKey(KeyRune, string(r), ModNone)) } } - case inpStateEsc: + case istEsc: switch r { case '[': - ip.state = inpStateCsi + ip.state = istCsi ip.csiInterm = nil ip.csiParams = nil + ip.escChar = byte(r) case ']': - ip.state = inpStateOsc - ip.scratch = nil + ip.state = istOsc + ip.strBuf = nil + ip.escChar = byte(r) case 'N': - ip.state = inpStateSs2 // no known uses - ip.scratch = nil + ip.state = istSs2 // no known uses + ip.strBuf = nil + ip.escChar = byte(r) case 'O': - ip.state = inpStateSs3 - ip.scratch = nil + ip.state = istSs3 + ip.csiParams = nil + ip.strBuf = nil + ip.escChar = byte(r) + case 'P': + ip.state = istXda + ip.csiParams = nil + ip.strBuf = nil + ip.escChar = byte(r) case 'X': - ip.state = inpStateSos - ip.scratch = nil + ip.state = istSos + ip.strBuf = nil + ip.escChar = byte(r) case '^': - ip.state = inpStatePm - ip.scratch = nil + ip.state = istPm + ip.strBuf = nil + ip.escChar = byte(r) case '_': - ip.state = inpStateApc - ip.scratch = nil + ip.state = istApc + ip.strBuf = nil + ip.escChar = byte(r) case '\\': // string terminator reached, (orphaned?) - ip.state = inpStateInit + ip.state = istInit case '\t': // Linux console only, does not conform to ECMA - ip.state = inpStateInit - ip.post(NewEventKey(KeyBacktab, 0, ModNone)) + ip.state = istInit + ip.post(NewEventKey(KeyBacktab, "", ModNone)) default: if r == '\x1b' { // leading ESC to capture alt ip.escaped = true + ip.escChar = byte(r) } else { // treat as alt-key ... legacy emulators only (no CSI-u or other) - ip.state = inpStateInit + ip.state = istInit mod := ModAlt if r < ' ' { mod |= ModCtrl r += 0x60 } - ip.post(NewEventKey(KeyRune, r, mod)) + ip.post(NewEventKey(KeyRune, string(r), mod)) } } - case inpStateCsi: + case istCsi: // usual case for incoming keys - if r >= 0x30 && r <= 0x3F { // parameter bytes + // NB: rxvt uses terminating '$' which is not a legal CSI terminator, + // for certain shifted key sequences. We special case this, and it's ok + // because no other terminal seems to use this for CSI intermediates from + // the terminal to the host (queries in the other direction can use it.) + // However, this is only true if the first parameter does not have a "?", + // because it *does* collide with DEC private mode queries otherwise. + if r == '\x1b' { + // Per ECMA-48 Β§5.3.1, ESC restarts the escape + // sequence machine from any intermediate state. + ip.state = istEsc + ip.escChar = 0 + } else if r >= 0x30 && r <= 0x3F { // parameter bytes ip.csiParams = append(ip.csiParams, byte(r)) + } else if r == '$' && len(ip.csiParams) > 0 && ip.csiParams[0] != '?' { // rxvt non-standard + ip.handleCsi(r, ip.csiParams, ip.csiInterm) } else if r >= 0x20 && r <= 0x2F { // intermediate bytes, rarely used ip.csiInterm = append(ip.csiInterm, byte(r)) } else if r >= 0x40 && r <= 0x7F { // final byte ip.handleCsi(r, ip.csiParams, ip.csiInterm) } else { // bad parse, just swallow it all - ip.state = inpStateInit + ip.state = istInit } - case inpStateSs2: + case istSs2: // No known uses for SS2 - ip.state = inpStateInit + ip.state = istInit - case inpStateSs3: // typically application mode keys or older terminals - ip.state = inpStateInit - if k, ok := ss3Keys[r]; ok { - ip.post(NewEventKey(k, 0, ModNone)) + case istSs3: // typically application mode keys or older terminals + ip.state = istInit + // some SS3 sequences (old VTE) encode modifiers here just like CSI + if r == '\x1b' { + // Per ECMA-48 Β§5.3.1, ESC restarts the escape + // sequence machine from any intermediate state. + ip.state = istEsc + ip.escChar = 0 + } else if r >= 0x30 && r <= 0x3F { + ip.csiParams = append(ip.csiParams, byte(r)) + ip.state = istSs3 + } else if k, ok := ss3Keys[r]; ok { + // If there are no parameters, then it's simple without modifiers. + // The options for parameters are "1;" , or ";modifiers" (empty + // first parameter defaults to 1), or just . If a sequence has + // parameters that do not match one of these forms, we just discard it. + if len(ip.csiParams) == 0 { + // simple SS3 case + ip.post(NewEventKey(k, "", ModNone)) + } else if parts := strings.Split(string(ip.csiParams), ";"); len(parts) >= 1 { + // SS3 with modifier (old style). Note old terminfo would declare these as high + // numbered function keys, but we encode as modified since that's how they are entered. + if len(parts) >= 2 { + if m, err := strconv.Atoi(parts[1]); err == nil && (parts[0] == "1" || parts[0] == "") { + ip.post(NewEventKey(k, "", calcModifier(m))) + } + } else if m, err := strconv.Atoi(parts[0]); err == nil { + ip.post(NewEventKey(k, "", calcModifier(m))) + } + } } - case inpStatePm, inpStateApc, inpStateSos, inpStateDcs: // these we just eat + case istPm, istApc, istSos, istDcs: // these we just eat switch r { case '\x1b': ip.strState = ip.state - ip.state = inpStateSt + ip.state = istSt case '\x07': // bell - some send this instead of ST - ip.state = inpStateInit + ip.state = istInit } - case inpStateOsc: // not sure if used + case istXda: switch r { case '\x1b': ip.strState = ip.state - ip.state = inpStateSt + ip.state = istSt case '\x07': - ip.handleOsc(string(ip.scratch)) + ip.handleXda(string(ip.strBuf)) default: - ip.scratch = append(ip.scratch, byte(r&0x7f)) + ip.strBuf = append(ip.strBuf, byte(r&0x7f)) } - case inpStateSt: + + case istOsc: // not sure if used + switch r { + case '\x1b': + ip.strState = ip.state + ip.state = istSt + case '\x07': + ip.handleOsc(string(ip.strBuf)) + default: + ip.strBuf = append(ip.strBuf, byte(r&0x7f)) + } + case istSt: if r == '\\' || r == '\x07' { - ip.state = inpStateInit + ip.state = istInit switch ip.strState { - case inpStateOsc: - ip.handleOsc(string(ip.scratch)) - case inpStatePm, inpStateApc, inpStateSos, inpStateDcs: - ip.state = inpStateInit + case istOsc: + ip.handleOsc(string(ip.strBuf)) + case istXda: + ip.handleXda(string(ip.strBuf)) + case istPm, istApc, istSos, istDcs: + ip.state = istInit } } else { - ip.scratch = append(ip.scratch, '\x1b', byte(r)) + ip.strBuf = append(ip.strBuf, '\x1b', byte(r)) ip.state = ip.strState } - case inpStateLFK: + case istLnx: // linux console does not follow ECMA if k, ok := linuxFKeys[r]; ok { - ip.post(NewEventKey(k, 0, ModNone)) + ip.post(NewEventKey(k, "", ModNone)) } - ip.state = inpStateInit + ip.state = istInit } } + + if ip.state != istInit && time.Since(ip.keyTime) > time.Millisecond*50 { + if ip.state == istEsc { + ip.post(NewEventKey(KeyEscape, "", ModNone)) + } else if ec := ip.escChar; ec != 0 { + ip.post(NewEventKey(KeyRune, string(ec), ModAlt)) + } + // if we take too long between bytes, reset the state machine. + ip.state = istInit + } } -func (ip *inputProcessor) handleOsc(str string) { - ip.state = inpStateInit +func (ip *inputParser) handleOsc(str string) { + ip.state = istInit if content, ok := strings.CutPrefix(str, "52;c;"); ok { decoded := make([]byte, base64.StdEncoding.DecodedLen(len(content))) if count, err := base64.StdEncoding.Decode(decoded, []byte(content)); err == nil { @@ -575,6 +675,20 @@ func (ip *inputProcessor) handleOsc(str string) { } } +func (ip *inputParser) handleXda(str string) { + ip.state = istInit + if content, ok := strings.CutPrefix(str, ">|"); ok { + // two approaches, one with version like (1.23) another with just spaces + if name, vers, ok := strings.Cut(content, "("); ok && strings.HasSuffix(vers, ")") { + name = strings.TrimSpace(name) + vers = strings.TrimSpace(strings.TrimSuffix(vers, ")")) + ip.post(&eventTermName{Name: name, Version: vers}) + } else if name, vers, ok = strings.Cut(content, " "); ok { + ip.post(&eventTermName{Name: name, Version: vers}) + } + } +} + func calcModifier(n int) ModMask { n-- m := ModNone @@ -603,8 +717,7 @@ func calcModifier(n int) ModMask { return m } -// func (ip *inputProcessor) handleMouse(x, y, btn int, down bool) *EventMouse { -func (ip *inputProcessor) handleMouse(mode rune, params []int) { +func (ip *inputParser) handleMouse(mode rune, params []int) { // XTerm mouse events only report at most one button at a time, // which may include a wheel button. Wheel motion events are @@ -619,29 +732,6 @@ func (ip *inputProcessor) handleMouse(mode rune, params []int) { // to the screen in that case. x := max(min(params[1]-1, ip.cols-1), 0) y := max(min(params[2]-1, ip.rows-1), 0) - motion := (btn & 0x20) != 0 - scroll := (btn & 0x42) == 0x40 - btn &^= 0x20 - if mode == 'm' { - // mouse release, clear all buttons - btn |= 3 - btn &^= 0x40 - ip.btnDown = false - } else if motion { - /* - * Some broken terminals appear to send - * mouse button one motion events, instead of - * encoding 35 (no buttons) into these events. - * We resolve these by looking for a non-motion - * event first. - */ - if !ip.btnDown { - btn |= 3 - btn &^= 0x40 - } - } else if !scroll { - ip.btnDown = true - } button := ButtonNone mod := ModNone @@ -650,7 +740,8 @@ func (ip *inputProcessor) handleMouse(mode rune, params []int) { // that wheel events are sometimes misdelivered as mouse button events // during a click-drag, so we debounce these, considering them to be // button press events unless we see an intervening release event. - switch btn & 0x43 { + // This excludes motion (bit 5) and modifiers (bits 2, 3, 4) for now. + switch btn & 0xC3 { case 0: button = Button1 case 1: @@ -667,6 +758,40 @@ func (ip *inputProcessor) handleMouse(mode rune, params []int) { button = WheelLeft case 0x43: button = WheelRight + case 0x80: + button = Button4 + case 0x81: + button = Button5 + case 0x82: + button = Button6 + case 0x83: + button = Button7 + } + + switch mode { + case 'm': + if (ip.btnsDown & button) == 0 { + // a release without a corresponding press, so clear it + button = ButtonNone + } else { + ip.btnsDown &^= button + button = ip.btnsDown + } + + case 'M': + if btn&0x20 != 0 && button != ButtonNone && (ip.btnsDown&button) == 0 { + // Ghostty may send out motion signals that indicate a button has + // been pressed, even when the button is not actually pressed. + // Do not create a synthetic button-down state from these packets. + button = ip.btnsDown + break + } + // record this press + ip.btnsDown |= button + // and use the full set so can see chords + button = ip.btnsDown + // mice wheel do not have release events + ip.btnsDown &^= (WheelDown | WheelUp | WheelLeft | WheelRight) } if btn&0x4 != 0 { @@ -682,7 +807,7 @@ func (ip *inputProcessor) handleMouse(mode rune, params []int) { ip.post(NewEventMouse(x, y, button, mod)) } -func (ip *inputProcessor) handleWinKey(P []int) { +func (ip *inputParser) handleWinKey(P []int) { // win32-input-mode // ^[ [ Vk ; Sc ; Uc ; Kd ; Cs ; Rc _ // Vk: the value of wVirtualKeyCode - any number. If omitted, defaults to '0'. @@ -707,16 +832,20 @@ func (ip *inputProcessor) handleWinKey(P []int) { return } + // these terminals never send ambiguous escapes + ip.escaped = false + if P[0] == 0 && P[1] == 0 && P[2] > 0 && P[2] < 0x80 { // only ASCII in win32-input-mode if ip.nested == nil { - ip.nested = &inputProcessor{ + ip.nested = &inputParser{ evch: ip.evch, rows: ip.rows, cols: ip.cols, } } - - ip.nested.ScanUTF8([]byte{byte(P[2])}) + if P[2] > 0 { + ip.nested.ScanUTF8([]byte{byte(P[2])}) + } return } @@ -732,7 +861,6 @@ func (ip *inputProcessor) handleWinKey(P []int) { } else if chr < ' ' && P[0] >= 0x41 && P[0] <= 0x5a { key = Key(P[0]) chr = 0 - } else if chr >= 0xD800 && chr <= 0xDBFF { // high surrogate pair ip.surrogate = chr @@ -768,31 +896,104 @@ func (ip *inputProcessor) handleWinKey(P []int) { } for range rpt { - if key != KeyRune || chr != 0 { - ip.post(NewEventKey(key, chr, mod)) + if key != KeyRune { + ip.post(NewEventKey(key, "", mod)) + } else if chr != 0 { + ip.post(NewEventKey(KeyRune, string(chr), mod)) } } } -func (ip *inputProcessor) handleCsi(mode rune, params []byte, intermediate []byte) { - - // reset state - ip.state = inpStateInit - - if len(intermediate) != 0 { - // we don't know what to do with these for now +func (ip *inputParser) handlePrimaryDA(params []int) { + if len(params) < 1 { return } + evDA := &eventPrimaryAttributes{Class: params[0]} + params = params[1:] + if evDA.Class >= 60 { + for _, v := range params { + switch v { + case 3: + evDA.ReGIS = true + case 4: + evDA.Sixel = true + case 9: + evDA.National = true + case 12: + evDA.SerboCroation = true + case 22: + evDA.Color = true + case 23: + evDA.Greek = true + case 24: + evDA.Turkish = true + case 42: + evDA.Latin2 = true + case 52: + evDA.Clipboard = true + } + } + } + ip.post(evDA) +} + +func (ip *inputParser) handlePrivateModeResponse(params []int) { + for len(params) < 2 { + params = append(params, 0) + } + if params[1] >= 0 && params[1] <= 4 { + ev := &eventPrivateMode{ + Mode: vt.PrivateMode(params[0]), + Status: vt.ModeStatus(params[1]), + } + ip.post(ev) + } +} + +func (ip *inputParser) handleKittyMode(params []int) { + if len(params) == 1 && params[0] >= 0 && params[0] < 32 { + ev := &eventKittyKbdMode{ + Mode: KittyKbdMode(params[0] & 0xffff), + } + ip.post(ev) + } +} + +func (ip *inputParser) handleXTermMode(params []int) { + if len(params) >= 1 && params[0] == 4 { + if len(params) == 1 { + params = append(params, 0) + } + ev := &eventXTermKbdMode{ + Mode: XtermKbdMode(params[1] & 0x3), + } + ip.post(ev) + } +} + +func (ip *inputParser) handleCsi(mode rune, params []byte, intermediate []byte) { + + // reset state + ip.state = istInit var parts []string var P []int hasLT := false + hasQM := false + hasGT := false pstr := string(params) // extract numeric parameters if strings.HasPrefix(pstr, "<") { hasLT = true pstr = pstr[1:] + } else if strings.HasPrefix(pstr, "?") { + hasQM = true + pstr = pstr[1:] + } else if strings.HasPrefix(pstr, ">") { + hasGT = true + pstr = pstr[1:] } + if pstr != "" && pstr[0] >= '0' && pstr[0] <= '9' { parts = strings.Split(pstr, ";") for i := range parts { @@ -800,6 +1001,8 @@ func (ip *inputProcessor) handleCsi(mode rune, params []byte, intermediate []byt if n, e := strconv.ParseInt(parts[i], 10, 32); e == nil { P = append(P, int(n)) } + } else { + P = append(P, 0) } } } @@ -808,11 +1011,43 @@ func (ip *inputProcessor) handleCsi(mode rune, params []byte, intermediate []byt P0 = P[0] } - if hasLT { + if hasLT && len(intermediate) == 0 { switch mode { case 'm', 'M': // mouse event, we only do SGR tracking ip.handleMouse(mode, P) } + return + } + if hasQM { + switch mode { + case 'c': + if len(intermediate) == 0 { + ip.handlePrimaryDA(P) + } + case 'y': + if string(intermediate) == "$" { + ip.handlePrivateModeResponse(P) + } + case 'u': + if len(intermediate) == 0 { + ip.handleKittyMode(P) + } + } + return + } + if hasGT { + switch mode { + case 'm': + if len(intermediate) == 0 { + ip.handleXTermMode(P) + } + } + return + } + + if len(intermediate) != 0 { + // we don't know what to do with these for now + return } switch mode { @@ -824,11 +1059,11 @@ func (ip *inputProcessor) handleCsi(mode rune, params []byte, intermediate []byt return case '[': // linux console F-key - CSI-[ modifies next key - ip.state = inpStateLFK + ip.state = istLnx return case 'u': - // CSI-u kitty keyboard protocol - if len(P) > 0 && !hasLT { + // CSI-u kitty keyboard protocol, is unambiguous + if len(P) > 0 { mod := ModNone key := KeyRune chr := rune(0) @@ -841,88 +1076,168 @@ func (ip *inputProcessor) handleCsi(mode rune, params []byte, intermediate []byt if len(P) > 1 { mod = calcModifier(P[1]) } - ip.post(NewEventKey(key, chr, mod)) + if key != KeyRune { + ip.post(NewEventKey(key, "", mod)) + } else if chr != 0 { + ip.post(NewEventKey(KeyRune, string(chr), mod)) + } + return } - return case '_': - if len(intermediate) == 0 && len(P) > 0 { + if len(P) > 0 { ip.handleWinKey(P) return } + case 't': + if len(P) < 1 { + break + } + switch P[0] { + case 8: + if len(P) > 2 { + // window size report + h := P[1] + w := P[2] + if h != ip.rows || w != ip.cols { + ip.SetSize(w, h) + } + return + } + case 48: + if len(P) > 2 { + // window resize report + ip.post(NewEventResize(P[2], P[1])) + return + } + } case '~': - if len(intermediate) == 0 && len(P) >= 2 { + if len(P) >= 2 { mod := calcModifier(P[1]) if ks, ok := csiAllKeys[csiParamMode{M: mode, P: P0}]; ok { - ip.post(NewEventKey(ks.Key, 0, mod)) + ip.post(NewEventKey(ks.Key, "", mod)) return } if P0 == 27 && len(P) > 2 && P[2] > 0 && P[2] <= 0xff { if P[2] < ' ' || P[2] == 0x7F { - ip.post(NewEventKey(Key(P[2]), 0, mod)) + ip.post(NewEventKey(Key(P[2]), "", mod)) } else { - ip.post(NewEventKey(KeyRune, rune(P[2]), mod)) + ip.post(NewEventKey(KeyRune, string(rune(P[2])), mod)) } return } } } - if ks, ok := csiAllKeys[csiParamMode{M: mode, P: P0}]; ok && !hasLT { + if ks, ok := csiAllKeys[csiParamMode{M: mode, P: P0}]; ok { if mode == '~' && len(P) > 1 && ks.Mod == ModNone { // apply modifiers if present ks.Mod = calcModifier(P[1]) } else if mode == 'P' && os.Getenv("TERM") == "aixterm" { ks.Key = KeyDelete // aixterm hack - conflicts with kitty protocol } - ip.post(NewEventKey(ks.Key, 0, ks.Mod)) + ip.post(NewEventKey(ks.Key, "", ks.Mod)) return } // this might have been an SS3 style key with modifiers applied if k, ok := ss3Keys[mode]; ok && P0 == 1 && len(P) > 1 { - ip.post(NewEventKey(k, 0, calcModifier(P[1]))) + ip.post(NewEventKey(k, "", calcModifier(P[1]))) return } // if we got here we just swallow the unknown sequence } -func (ip *inputProcessor) ScanUTF8(b []byte) { +func (ip *inputParser) ScanUTF8(b []byte) { ip.l.Lock() defer ip.l.Unlock() - ip.ut8 = append(ip.ut8, b...) - for len(ip.ut8) > 0 { - // fast path, basic ascii - if ip.ut8[0] < 0x7F { - ip.buf = append(ip.buf, rune(ip.ut8[0])) - ip.ut8 = ip.ut8[1:] + ip.utfBuf = append(ip.utfBuf, b...) + for len(ip.utfBuf) > 0 { + // fast path, basic ascii, also includes ISO2022 8-bit controls + if ip.utfBuf[0] < 0xA0 { + ip.buf = append(ip.buf, rune(ip.utfBuf[0])) + ip.utfBuf = ip.utfBuf[1:] } else { - r, len := utf8.DecodeRune(ip.ut8) + r, utfLen := utf8.DecodeRune(ip.utfBuf) if r == utf8.RuneError { - r = rune(ip.ut8[0]) - len = 1 + // discard the leading byte as bad, + // hopefully it will recover. + utfLen = 1 + } else { + ip.buf = append(ip.buf, r) } - ip.buf = append(ip.buf, r) - ip.ut8 = ip.ut8[len:] + ip.utfBuf = ip.utfBuf[utfLen:] } } ip.scan() } -func (ip *inputProcessor) ScanUTF16(u []uint16) { +// Scan scans the existing input, but does not take new content. +// This is typically called after a delay when Waiting() is true. +func (ip *inputParser) Scan() { ip.l.Lock() - defer ip.l.Unlock() - ip.ut16 = append(ip.ut16, u...) - for len(ip.ut16) > 0 { - if !utf16.IsSurrogate(rune(ip.ut16[0])) { - ip.buf = append(ip.buf, rune(ip.ut16[0])) - ip.ut16 = ip.ut16[1:] - } else if len(ip.ut16) > 1 { - ip.buf = append(ip.buf, utf16.DecodeRune(rune(ip.ut16[0]), rune(ip.ut16[1]))) - ip.ut16 = ip.ut16[2:] - } else { - break - } - } + ip.scan() + ip.l.Unlock() +} + +// Private events between input and tscreen. + +// eventPrimaryAttributes is for primary device attributes -- this should be +// the last event returned during initial handshaking +type eventPrimaryAttributes struct { + EventTime + Class int // Terminal class, 1 is vt100, vt101, 6 is vt102, > 60 for vt200 and up + ReGIS bool // Terminal supports ReGIS graphics (DA 3) + Sixel bool // Terminal supports Sixel graphics (DA 4) + National bool // Terminal supports national replacement character sets (DA 9) + SerboCroation bool // Serbo-Croatian(DA 12) + Color bool // Terminal supports color (DA 22) + Greek bool // Greek (DA 23) + Turkish bool // Turkish (DA 24) + Latin2 bool // ISO Latin-2 (DA 42) + Clipboard bool // OSC 52 support (DA 52) +} + +// eventTermName is for extended attributes +type eventTermName struct { + EventTime + Name string + Version string +} + +type eventPrivateMode struct { + EventTime + Mode vt.PrivateMode // numeric mode e.g. 7 for auto-margin, 1006 for SGR mouse reports, etc + Status vt.ModeStatus // value of status +} + +type KittyKbdMode uint16 + +const ( + KittyKbdModeOff = KittyKbdMode(0) // Disable Kitty keyboard mode + KittyKbdModeBase = KittyKbdMode(1) // Enable disambiguated keys + KittyKbdModeEvents = KittyKbdMode(2) // Report event types (e.g. key release) + KittyKbdModeAlternate = KittyKbdMode(4) // Report alternate keys + KittyKbdModeAll = KittyKbdMode(8) // Report all keys using kitty keyboard protocol + KittyKbdModeText = KittyKbdMode(16) // Report associated text +) + +type eventKittyKbdMode struct { + EventTime + Mode KittyKbdMode +} + +type XtermKbdMode uint16 + +const ( + XtermKbdModeOff = XtermKbdMode(0) // Disabled + XtermKbdModeBase = XtermKbdMode(1) // Enabled except for ones with legacy behavior + XtermKbdModeExt = XtermKbdMode(2) // Enabled for all modified keys + XtermKbdModeAll = XtermKbdMode(3) // Send all keys (including unmodified) +) + +type eventXTermKbdMode struct { + EventTime + Mode XtermKbdMode } diff --git a/vendor/github.com/gdamore/tcell/v2/eastasian.go b/vendor/github.com/gdamore/tcell/v3/internal/widthutil/widthutil.go similarity index 55% rename from vendor/github.com/gdamore/tcell/v2/eastasian.go rename to vendor/github.com/gdamore/tcell/v3/internal/widthutil/widthutil.go index 56b9af692..7ab693181 100644 --- a/vendor/github.com/gdamore/tcell/v2/eastasian.go +++ b/vendor/github.com/gdamore/tcell/v3/internal/widthutil/widthutil.go @@ -1,8 +1,8 @@ -// Copyright 2025 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -12,19 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package tcell +package widthutil import ( "os" "strings" - "github.com/rivo/uniseg" + "github.com/clipperhouse/displaywidth" ) -func init() { +// Options returns the display-width options derived from the user's +// environment. We preserve the historical RUNEWIDTH_EASTASIAN toggle. +func Options() displaywidth.Options { if rw := strings.ToLower(os.Getenv("RUNEWIDTH_EASTASIAN")); rw == "1" || rw == "true" || rw == "yes" { - uniseg.EastAsianAmbiguousWidth = 2 - } else { - uniseg.EastAsianAmbiguousWidth = 1 + return displaywidth.Options{EastAsianWidth: true} } + return displaywidth.Options{} } diff --git a/vendor/github.com/gdamore/tcell/v2/interrupt.go b/vendor/github.com/gdamore/tcell/v3/interrupt.go similarity index 62% rename from vendor/github.com/gdamore/tcell/v2/interrupt.go rename to vendor/github.com/gdamore/tcell/v3/interrupt.go index 70dddfce2..2aeaa990f 100644 --- a/vendor/github.com/gdamore/tcell/v2/interrupt.go +++ b/vendor/github.com/gdamore/tcell/v3/interrupt.go @@ -1,8 +1,8 @@ -// Copyright 2015 The TCell Authors +// Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -14,28 +14,21 @@ package tcell -import ( - "time" -) - // EventInterrupt is a generic wakeup event. Its can be used to // to request a redraw. It can carry an arbitrary payload, as well. type EventInterrupt struct { - t time.Time - v interface{} -} - -// When returns the time when this event was created. -func (ev *EventInterrupt) When() time.Time { - return ev.t + EventTime + v any } // Data is used to obtain the opaque event payload. -func (ev *EventInterrupt) Data() interface{} { +func (ev *EventInterrupt) Data() any { return ev.v } // NewEventInterrupt creates an EventInterrupt with the given payload. -func NewEventInterrupt(data interface{}) *EventInterrupt { - return &EventInterrupt{t: time.Now(), v: data} +func NewEventInterrupt(data any) *EventInterrupt { + ev := &EventInterrupt{v: data} + ev.SetEventNow() + return ev } diff --git a/vendor/github.com/gdamore/tcell/v2/key.go b/vendor/github.com/gdamore/tcell/v3/key.go similarity index 56% rename from vendor/github.com/gdamore/tcell/v2/key.go rename to vendor/github.com/gdamore/tcell/v3/key.go index 58f8c4388..db4d79b21 100644 --- a/vendor/github.com/gdamore/tcell/v2/key.go +++ b/vendor/github.com/gdamore/tcell/v3/key.go @@ -1,8 +1,8 @@ // Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -17,7 +17,6 @@ package tcell import ( "fmt" "strings" - "time" ) // EventKey represents a key press. Usually this is a key press followed @@ -31,7 +30,9 @@ import ( // high bit set, or in some cases, by sending an ESC prior to the rune.) // // If the value of Key() is KeyRune, then the actual key value will be -// available with the Rune() method. This will be the case for most keys. +// available (as a grapheme cluster) with the Str() method. +// This will be the case for most keys. +// // In most situations, the modifiers will not be set. For example, if the // rune is 'A', this will be reported without the ModShift bit set, since // really can't tell if the Shift key was pressed (it might have been CAPSLOCK, @@ -43,29 +44,24 @@ import ( // overly much on availability of modifiers, or the availability of any // specific keys. type EventKey struct { - t time.Time + EventTime mod ModMask key Key - ch rune + str string // string for key, usually just one character, but may be composed sequence } -// When returns the time when this Event was created, which should closely -// match the time when the key was pressed. -func (ev *EventKey) When() time.Time { - return ev.t -} - -// Rune returns the rune corresponding to the key press, if it makes sense. -// The result is only defined if the value of Key() is KeyRune. -func (ev *EventKey) Rune() rune { - return ev.ch +// Str returns the string corresponding to the key press, if it makes sense. +// The result is only defined if the value of Key() is KeyRune. It will be +// either one key (e.g. 'A'), or could be a composed sequence. +func (ev *EventKey) Str() string { + return ev.str } // Key returns a virtual key code. We use this to identify specific key // codes, such as KeyEnter, etc. Most control and function keys are reported // with unique Key values. Normal alphanumeric and punctuation keys will // generally return KeyRune here; the specific key can be further decoded -// using the Rune() function. +// using the Str() function. func (ev *EventKey) Key() Key { return ev.key } @@ -81,132 +77,126 @@ func (ev *EventKey) Modifiers() ModMask { // KeyNames holds the written names of special keys. Useful to echo back a key // name, or to look up a key from a string value. var KeyNames = map[Key]string{ - KeyEnter: "Enter", - KeyBackspace: "Backspace", - KeyTab: "Tab", - KeyBacktab: "Backtab", - KeyEsc: "Esc", - KeyBackspace2: "Backspace2", - KeyDelete: "Delete", - KeyInsert: "Insert", - KeyUp: "Up", - KeyDown: "Down", - KeyLeft: "Left", - KeyRight: "Right", - KeyHome: "Home", - KeyEnd: "End", - KeyUpLeft: "UpLeft", - KeyUpRight: "UpRight", - KeyDownLeft: "DownLeft", - KeyDownRight: "DownRight", - KeyCenter: "Center", - KeyPgDn: "PgDn", - KeyPgUp: "PgUp", - KeyClear: "Clear", - KeyExit: "Exit", - KeyCancel: "Cancel", - KeyPause: "Pause", - KeyPrint: "Print", - KeyF1: "F1", - KeyF2: "F2", - KeyF3: "F3", - KeyF4: "F4", - KeyF5: "F5", - KeyF6: "F6", - KeyF7: "F7", - KeyF8: "F8", - KeyF9: "F9", - KeyF10: "F10", - KeyF11: "F11", - KeyF12: "F12", - KeyF13: "F13", - KeyF14: "F14", - KeyF15: "F15", - KeyF16: "F16", - KeyF17: "F17", - KeyF18: "F18", - KeyF19: "F19", - KeyF20: "F20", - KeyF21: "F21", - KeyF22: "F22", - KeyF23: "F23", - KeyF24: "F24", - KeyF25: "F25", - KeyF26: "F26", - KeyF27: "F27", - KeyF28: "F28", - KeyF29: "F29", - KeyF30: "F30", - KeyF31: "F31", - KeyF32: "F32", - KeyF33: "F33", - KeyF34: "F34", - KeyF35: "F35", - KeyF36: "F36", - KeyF37: "F37", - KeyF38: "F38", - KeyF39: "F39", - KeyF40: "F40", - KeyF41: "F41", - KeyF42: "F42", - KeyF43: "F43", - KeyF44: "F44", - KeyF45: "F45", - KeyF46: "F46", - KeyF47: "F47", - KeyF48: "F48", - KeyF49: "F49", - KeyF50: "F50", - KeyF51: "F51", - KeyF52: "F52", - KeyF53: "F53", - KeyF54: "F54", - KeyF55: "F55", - KeyF56: "F56", - KeyF57: "F57", - KeyF58: "F58", - KeyF59: "F59", - KeyF60: "F60", - KeyF61: "F61", - KeyF62: "F62", - KeyF63: "F63", - KeyF64: "F64", - KeyMenu: "Menu", - KeyCapsLock: "CapsLock", - KeyScrollLock: "ScrollLock", - KeyNumLock: "NumLock", - KeyCtrlSpace: "Ctrl-Space", - KeyCtrlA: "Ctrl-A", - KeyCtrlB: "Ctrl-B", - KeyCtrlC: "Ctrl-C", - KeyCtrlD: "Ctrl-D", - KeyCtrlE: "Ctrl-E", - KeyCtrlF: "Ctrl-F", - KeyCtrlG: "Ctrl-G", - KeyCtrlH: "Ctrl-H", - KeyCtrlI: "Ctrl-I", - KeyCtrlJ: "Ctrl-J", - KeyCtrlK: "Ctrl-K", - KeyCtrlL: "Ctrl-L", - KeyCtrlM: "Ctrl-M", - KeyCtrlN: "Ctrl-N", - KeyCtrlO: "Ctrl-O", - KeyCtrlP: "Ctrl-P", - KeyCtrlQ: "Ctrl-Q", - KeyCtrlR: "Ctrl-R", - KeyCtrlS: "Ctrl-S", - KeyCtrlT: "Ctrl-T", - KeyCtrlU: "Ctrl-U", - KeyCtrlV: "Ctrl-V", - KeyCtrlW: "Ctrl-W", - KeyCtrlX: "Ctrl-X", - KeyCtrlY: "Ctrl-Y", - KeyCtrlZ: "Ctrl-Z", - KeyCtrlLeftSq: "Ctrl-[", - KeyCtrlRightSq: "Ctrl-]", - KeyCtrlBackslash: "Ctrl-\\", - KeyCtrlCarat: "Ctrl-^", - KeyCtrlUnderscore: "Ctrl-_", + KeyEnter: "Enter", + KeyBackspace: "Backspace", + KeyTab: "Tab", + KeyBacktab: "Backtab", + KeyEsc: "Esc", + KeyBackspace2: "Backspace2", + KeyDelete: "Delete", + KeyInsert: "Insert", + KeyUp: "Up", + KeyDown: "Down", + KeyLeft: "Left", + KeyRight: "Right", + KeyHome: "Home", + KeyEnd: "End", + KeyUpLeft: "UpLeft", + KeyUpRight: "UpRight", + KeyDownLeft: "DownLeft", + KeyDownRight: "DownRight", + KeyCenter: "Center", + KeyPgDn: "PgDn", + KeyPgUp: "PgUp", + KeyClear: "Clear", + KeyExit: "Exit", + KeyCancel: "Cancel", + KeyPause: "Pause", + KeyPrint: "Print", + KeyF1: "F1", + KeyF2: "F2", + KeyF3: "F3", + KeyF4: "F4", + KeyF5: "F5", + KeyF6: "F6", + KeyF7: "F7", + KeyF8: "F8", + KeyF9: "F9", + KeyF10: "F10", + KeyF11: "F11", + KeyF12: "F12", + KeyF13: "F13", + KeyF14: "F14", + KeyF15: "F15", + KeyF16: "F16", + KeyF17: "F17", + KeyF18: "F18", + KeyF19: "F19", + KeyF20: "F20", + KeyF21: "F21", + KeyF22: "F22", + KeyF23: "F23", + KeyF24: "F24", + KeyF25: "F25", + KeyF26: "F26", + KeyF27: "F27", + KeyF28: "F28", + KeyF29: "F29", + KeyF30: "F30", + KeyF31: "F31", + KeyF32: "F32", + KeyF33: "F33", + KeyF34: "F34", + KeyF35: "F35", + KeyF36: "F36", + KeyF37: "F37", + KeyF38: "F38", + KeyF39: "F39", + KeyF40: "F40", + KeyF41: "F41", + KeyF42: "F42", + KeyF43: "F43", + KeyF44: "F44", + KeyF45: "F45", + KeyF46: "F46", + KeyF47: "F47", + KeyF48: "F48", + KeyF49: "F49", + KeyF50: "F50", + KeyF51: "F51", + KeyF52: "F52", + KeyF53: "F53", + KeyF54: "F54", + KeyF55: "F55", + KeyF56: "F56", + KeyF57: "F57", + KeyF58: "F58", + KeyF59: "F59", + KeyF60: "F60", + KeyF61: "F61", + KeyF62: "F62", + KeyF63: "F63", + KeyF64: "F64", + KeyMenu: "Menu", + KeyCapsLock: "CapsLock", + KeyScrollLock: "ScrollLock", + KeyNumLock: "NumLock", + KeyCtrlA: "Ctrl-A", + KeyCtrlB: "Ctrl-B", + KeyCtrlC: "Ctrl-C", + KeyCtrlD: "Ctrl-D", + KeyCtrlE: "Ctrl-E", + KeyCtrlF: "Ctrl-F", + KeyCtrlG: "Ctrl-G", + KeyCtrlH: "Ctrl-H", + KeyCtrlI: "Ctrl-I", + KeyCtrlJ: "Ctrl-J", + KeyCtrlK: "Ctrl-K", + KeyCtrlL: "Ctrl-L", + KeyCtrlM: "Ctrl-M", + KeyCtrlN: "Ctrl-N", + KeyCtrlO: "Ctrl-O", + KeyCtrlP: "Ctrl-P", + KeyCtrlQ: "Ctrl-Q", + KeyCtrlR: "Ctrl-R", + KeyCtrlS: "Ctrl-S", + KeyCtrlT: "Ctrl-T", + KeyCtrlU: "Ctrl-U", + KeyCtrlV: "Ctrl-V", + KeyCtrlW: "Ctrl-W", + KeyCtrlX: "Ctrl-X", + KeyCtrlY: "Ctrl-Y", + KeyCtrlZ: "Ctrl-Z", } // Name returns a printable value or the key stroke. This can be used @@ -233,9 +223,9 @@ func (ev *EventKey) Name() string { ok := false if s, ok = KeyNames[ev.key]; !ok { if ev.key == KeyRune { - s = "Rune[" + string(ev.ch) + "]" + s = "Rune[" + ev.str + "]" } else { - s = fmt.Sprintf("Key[%d,%d]", ev.key, int(ev.ch)) + s = fmt.Sprintf("Key[%d,%s]", ev.key, ev.str) } } if len(m) != 0 { @@ -251,44 +241,47 @@ func (ev *EventKey) Name() string { // ASCII control sequences if KeyRune is passed for Key, but if the caller // has more precise information it should set that specifically. Callers // that aren't sure about modifier state (most) should just pass ModNone. -func NewEventKey(k Key, ch rune, mod ModMask) *EventKey { - if k == KeyRune && (ch < ' ' || ch == 0x7f) { - // Turn specials into proper key codes. This is for - // control characters and the DEL. - k = Key(ch) - if mod == ModNone && ch < ' ' { - switch k { - case KeyBackspace, KeyTab, KeyEsc, KeyEnter: - // these keys are directly typeable without CTRL - default: - // most likely entered with a CTRL keypress - mod = ModCtrl +func NewEventKey(k Key, str string, mod ModMask) *EventKey { + ch := rune(0) + if len(str) == 1 { + ch = []rune(str)[0] + } + + if k == KeyRune { + if ch != 0 && (ch < ' ' || ch == 0x7f) { + // Turn specials into proper key codes. This is for + // control characters and the DEL. + k = Key(ch) + if mod == ModNone && ch < ' ' { + switch k { + case KeyBackspace, KeyTab, KeyEsc, KeyEnter: + // these keys are directly typeable without CTRL + str = "" + default: + // most likely entered with a CTRL keypress + mod = ModCtrl + } + ch = ch + '\x60' } - ch = ch + '\x60' } - } - if k == KeyRune && ch >= 'A' && ch <= 'Z' && mod == ModCtrl { - // We don't do Ctrl-[ or backslash or those specially. - k = KeyCtrlA + Key(ch-'A') - } - // Might be lower case - if k == KeyRune && ch >= 'a' && ch <= 'z' && mod == ModCtrl { - // We don't do Ctrl-[ or backslash or those specially. - k = KeyCtrlA + Key(ch-'a') - } + // For legacy reasons, if Ctrl is pressed with an ASCII alphabetic, then we + // emit it as a KeyCtrlXX symbol. + if mod == ModCtrl { + // We don't do Ctrl-[ or backslash or those specially. + if ch >= 'A' && ch <= 'Z' { // upper case + k = KeyCtrlA + Key(ch-'A') + str = "" + } else if ch >= 'a' && ch <= 'z' { // lower case + k = KeyCtrlA + Key(ch-'a') + str = "" + } + } - // Windows reports ModShift for shifted keys. This is inconsistent - // with UNIX, lets harmonize this. - if k == KeyRune && mod == ModShift && ch != 0 { - mod = ModNone - } - - if k >= KeyCtrlA && k <= KeyCtrlZ { - if mod&ModShift != 0 { - ch = rune((k - KeyCtrlA) + 'A') - } else { - ch = rune((k - KeyCtrlA) + 'a') + // Windows reports ModShift for shifted keys. This is inconsistent + // with UNIX, lets harmonize this. + if mod == ModShift && str != "" { + mod = ModNone } } @@ -302,8 +295,9 @@ func NewEventKey(k Key, ch rune, mod ModMask) *EventKey { k = KeyBacktab mod &^= ModShift } - - return &EventKey{t: time.Now(), key: k, ch: ch, mod: mod} + ev := &EventKey{key: k, str: str, mod: mod} + ev.SetEventNow() + return ev } // ModMask is a mask of modifier keys. Note that it will not always be @@ -327,7 +321,7 @@ const ( // Key is a generic value for representing keys, and especially special // keys (function keys, cursor movement keys, etc.) For normal keys, like // ASCII letters, we use KeyRune, and then expect the application to -// inspect the Rune() member of the EventKey. +// inspect the Str() member of the EventKey. type Key int16 // This is the list of named keys. KeyRune is special however, in that it is @@ -439,8 +433,7 @@ const ( // or other modifiers are present then these will *NOT* be reported, // but reported instead as KeyRune. const ( - KeyCtrlSpace Key = iota + 64 - KeyCtrlA + KeyCtrlA Key = iota + 65 KeyCtrlB KeyCtrlC KeyCtrlD @@ -466,11 +459,6 @@ const ( KeyCtrlX KeyCtrlY KeyCtrlZ - KeyCtrlLeftSq // Escape - KeyCtrlBackslash - KeyCtrlRightSq - KeyCtrlCarat - KeyCtrlUnderscore ) // Special values - these are fixed in an attempt to make it more likely diff --git a/vendor/github.com/gdamore/tcell/v2/mouse.go b/vendor/github.com/gdamore/tcell/v3/mouse.go similarity index 90% rename from vendor/github.com/gdamore/tcell/v2/mouse.go rename to vendor/github.com/gdamore/tcell/v3/mouse.go index 29de4c3a4..c78092c1d 100644 --- a/vendor/github.com/gdamore/tcell/v2/mouse.go +++ b/vendor/github.com/gdamore/tcell/v3/mouse.go @@ -1,8 +1,8 @@ // Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -14,10 +14,6 @@ package tcell -import ( - "time" -) - // EventMouse is a mouse event. It is sent on either mouse up or mouse down // events. It is also sent on mouse motion events - if the terminal supports // it. We make every effort to ensure that mouse release events are delivered. @@ -35,18 +31,13 @@ import ( // Applications can inspect the time between events to resolve double or // triple clicks. type EventMouse struct { - t time.Time + EventTime btn ButtonMask mod ModMask x int y int } -// When returns the time when this EventMouse was created. -func (ev *EventMouse) When() time.Time { - return ev.t -} - // Buttons returns the list of buttons that were pressed or wheel motions. func (ev *EventMouse) Buttons() ButtonMask { return ev.btn @@ -65,9 +56,11 @@ func (ev *EventMouse) Position() (int, int) { } // NewEventMouse is used to create a new mouse event. Applications -// shouldn't need to use this; its mostly for screen implementors. +// shouldn't need to use this; its mostly for screen implementers. func NewEventMouse(x, y int, btn ButtonMask, mod ModMask) *EventMouse { - return &EventMouse{t: time.Now(), x: x, y: y, btn: btn, mod: mod} + ev := &EventMouse{x: x, y: y, btn: btn, mod: mod} + ev.SetEventNow() + return ev } // ButtonMask is a mask of mouse buttons and wheel events. Mouse button presses diff --git a/vendor/github.com/gdamore/tcell/v2/paste.go b/vendor/github.com/gdamore/tcell/v3/paste.go similarity index 93% rename from vendor/github.com/gdamore/tcell/v2/paste.go rename to vendor/github.com/gdamore/tcell/v3/paste.go index f511f63cb..9d7f0c7e3 100644 --- a/vendor/github.com/gdamore/tcell/v2/paste.go +++ b/vendor/github.com/gdamore/tcell/v3/paste.go @@ -1,8 +1,8 @@ // Copyright 2024 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -26,7 +26,6 @@ import ( type EventPaste struct { start bool t time.Time - data []byte } // When returns the time when this EventPaste was created. diff --git a/vendor/github.com/gdamore/tcell/v2/resize.go b/vendor/github.com/gdamore/tcell/v3/resize.go similarity index 63% rename from vendor/github.com/gdamore/tcell/v2/resize.go rename to vendor/github.com/gdamore/tcell/v3/resize.go index f3e2b3a5f..8c713e259 100644 --- a/vendor/github.com/gdamore/tcell/v2/resize.go +++ b/vendor/github.com/gdamore/tcell/v3/resize.go @@ -1,8 +1,8 @@ -// Copyright 2015 The TCell Authors +// Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -14,13 +14,11 @@ package tcell -import ( - "time" -) +import "github.com/gdamore/tcell/v3/tty" // EventResize is sent when the window size changes. type EventResize struct { - t time.Time + EventTime ws WindowSize } @@ -31,12 +29,9 @@ func NewEventResize(width, height int) *EventResize { Width: width, Height: height, } - return &EventResize{t: time.Now(), ws: ws} -} - -// When returns the time when the Event was created. -func (ev *EventResize) When() time.Time { - return ev.t + ev := &EventResize{ws: ws} + ev.SetEventNow() + return ev } // Size returns the new window size as width, height in character cells. @@ -50,17 +45,4 @@ func (ev *EventResize) PixelSize() (int, int) { return ev.ws.PixelWidth, ev.ws.PixelHeight } -type WindowSize struct { - Width int - Height int - PixelWidth int - PixelHeight int -} - -// CellDimensions returns the dimensions of a single cell, in pixels -func (ws WindowSize) CellDimensions() (int, int) { - if ws.PixelWidth == 0 || ws.PixelHeight == 0 { - return 0, 0 - } - return (ws.PixelWidth / ws.Width), (ws.PixelHeight / ws.Height) -} +type WindowSize = tty.WindowSize diff --git a/vendor/github.com/gdamore/tcell/v2/runes.go b/vendor/github.com/gdamore/tcell/v3/runes.go similarity index 96% rename from vendor/github.com/gdamore/tcell/v2/runes.go rename to vendor/github.com/gdamore/tcell/v3/runes.go index ed9c63b5c..f707113d6 100644 --- a/vendor/github.com/gdamore/tcell/v2/runes.go +++ b/vendor/github.com/gdamore/tcell/v3/runes.go @@ -1,8 +1,8 @@ // Copyright 2015 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // diff --git a/vendor/github.com/gdamore/tcell/v2/screen.go b/vendor/github.com/gdamore/tcell/v3/screen.go similarity index 71% rename from vendor/github.com/gdamore/tcell/v2/screen.go rename to vendor/github.com/gdamore/tcell/v3/screen.go index db2f0088e..f8c93e5c4 100644 --- a/vendor/github.com/gdamore/tcell/v2/screen.go +++ b/vendor/github.com/gdamore/tcell/v3/screen.go @@ -1,8 +1,8 @@ -// Copyright 2025 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -14,7 +14,11 @@ package tcell -import "sync" +import ( + "sync" + + "github.com/gdamore/tcell/v3/color" +) // Screen represents the physical (or emulated) screen. // This can be a terminal window or a physical console. Platforms implement @@ -35,7 +39,7 @@ type Screen interface { // is called (or Sync). Fill(rune, Style) - // Put writes the first graphme of the given string with th + // Put writes the first grapheme of the given string with th // given style at the given coordinates. (Only the first grapheme // occupying either one or two cells is stored.) It returns the // remainder of the string, and the width displayed. @@ -46,14 +50,9 @@ type Screen interface { PutStr(x int, y int, str string) // PutStrStyled writes a string starting at the given position, using - // the given style. The cont4ent is clipped to the screen dimensions. + // the given style. The content is clipped to the screen dimensions. PutStrStyled(x int, y int, str string, style Style) - // SetCell is an older API, and will be removed. - //jj - // Deprecated: Please use Put instead. - SetCell(x int, y int, style Style, ch ...rune) - // Get the contents at the given location. If the // coordinates are out of range, then the values will be 0, nil, // StyleDefault. Note that the contents returned are logical contents @@ -63,11 +62,6 @@ type Screen interface { // characters and emoji require two cells. Get(x, y int) (str string, style Style, width int) - // GetContent is the old way to get cell contents. - // - // Deprecated: Use Get() instead. - GetContent(x, y int) (primary rune, combining []rune, style Style, width int) - // SetContent sets the contents of the given cell location. If // the coordinates are out of range, then the operation is ignored. // @@ -101,52 +95,19 @@ type Screen interface { // is not supported (or cursor styles are not supported at all), // then this will have no effect. Color will be changed if supplied, // and the terminal supports doing so. - SetCursorStyle(CursorStyle, ...Color) + SetCursorStyle(CursorStyle, ...color.Color) // Size returns the screen size as width, height. This changes in // response to a call to Clear or Flush. Size() (width, height int) - // ChannelEvents is an infinite loop that waits for an event and - // channels it into the user provided channel ch. Closing the - // quit channel and calling the Fini method are cancellation - // signals. When a cancellation signal is received the method - // returns after closing ch. - // - // This method should be used as a goroutine. - // - // NOTE: PollEvent should not be called while this method is running. - ChannelEvents(ch chan<- Event, quit <-chan struct{}) - - // PollEvent waits for events to arrive. Main application loops - // must spin on this to prevent the application from stalling. - // Furthermore, this will return nil if the Screen is finalized. - PollEvent() Event - - // HasPendingEvent returns true if PollEvent would return an event - // without blocking. If the screen is stopped and PollEvent would - // return nil, then the return value from this function is unspecified. - // The purpose of this function is to allow multiple events to be collected - // at once, to minimize screen redraws. - HasPendingEvent() bool - - // PostEvent tries to post an event into the event stream. This - // can fail if the event queue is full. In that case, the event - // is dropped, and ErrEventQFull is returned. - PostEvent(ev Event) error - - // Deprecated: PostEventWait is unsafe, and will be removed - // in the future. - // - // PostEventWait is like PostEvent, but if the queue is full, it - // blocks until there is space in the queue, making delivery - // reliable. However, it is VERY important that this function - // never be called from within whatever event loop is polling - // with PollEvent(), otherwise a deadlock may arise. - // - // For this reason, when using this function, the use of a - // Goroutine is recommended to ensure no deadlock can occur. - PostEventWait(ev Event) + // EventQ returns the channel of events, and is usable just like + // any other channel. Events can be injected by writing to + // the channel, and they can be read by reading from it. The + // channel will remain open until the screen is completely shut down + // with Fini(). Consequently, applications must not write to this + // channel after Fini() is called. + EventQ() chan Event // EnableMouse enables the mouse. (If your terminal supports it.) // If no flags are specified, then all events are reported, if the @@ -168,12 +129,6 @@ type Screen interface { // DisableFocus disables reporting of focus events. DisableFocus() - // HasMouse returns true if the terminal (apparently) supports a - // mouse. Note that the return value of true doesn't guarantee that - // a mouse/pointing device is present; a false return definitely - // indicates no mouse support is available. - HasMouse() bool - // Colors returns the number of colors. All colors are assumed to // use the ANSI color map. If a terminal is monochrome, it will // return 0. @@ -232,34 +187,11 @@ type Screen interface { // by your terminal except by changing the terminal database. UnregisterRuneFallback(r rune) - // CanDisplay returns true if the given rune can be displayed on - // this screen. Note that this is a best-guess effort -- whether - // your fonts support the character or not may be questionable. - // Mostly this is for folks who work outside of Unicode. - // - // If checkFallbacks is true, then if any (possibly imperfect) - // fallbacks are registered, this will return true. This will - // also return true if the terminal can replace the glyph with - // one that is visually indistinguishable from the one requested. - // - // Deprecated: This is not a particularly useful or reliable function, - // due to limitations in fonts, etc. It will be removed in the future. - CanDisplay(r rune, checkFallbacks bool) bool - // Resize does nothing, since it's generally not possible to // ask a screen to resize, but it allows the Screen to implement // the View interface. Resize(int, int, int, int) - // HasKey always returns true. - // - // Deprecated: This function always returns true. Applications - // cannot reliably detect whether a key is supported or not with - // modern terminal emulators. (The intended use here was to help - // applications determine whether a given key stroke was supported - // by the terminal, but it was never reliable.) - HasKey(Key) bool - // Suspend pauses input and output processing. It also restores the // terminal settings to what they were when the application started. // This can be used to, for example, run a sub-shell. @@ -298,6 +230,7 @@ type Screen interface { // SetClipboard is used to post arbitrary data to the system clipboard. // This need not be UTF-8 string data. It's up to the recipient to decode the // data meaningfully. Terminals may prevent this for security reasons. + // An empty byte or nil can be used to clear the clipboard. SetClipboard([]byte) // GetClipboard is used to request the clipboard contents. It may be ignored. @@ -305,20 +238,56 @@ type Screen interface { // EventPaste with the clipboard content as the Data() field. Terminals may // prevent this for security reasons. GetClipboard() + + // HasClipboard is true if the screen claims to support the clipboard. + // Note that GetClipboard may still not work, but SetClipboard should be functional. + // Note that many terminals that support the clipboard don't actually report that they + // do, so a false indication is not necessarily conclusive. + HasClipboard() bool + + // ShowNotification is used to show a desktop notification, when the terminal + // supports it. Right now only terminals supporting OSC 777 support this. + ShowNotification(title string, body string) + + // Terminal returns the terminal name and version if known. If either of these + // are unknown, then empty strings are returned in their place. This is intended + // to facilitate debug, and also applications that wish to enable very specific + // behaviors for the terminal + Terminal() (string, string) } -// NewScreen returns a default Screen suitable for the user's terminal -// environment. +var overrideScreen chan Screen +var overrideOnce sync.Once + +// NewScreen returns a default Screen suitable for the user's terminal environment. func NewScreen() (Screen, error) { - if s, e := NewTerminfoScreen(); s != nil { + + // Allow an application (presumably test code) to inject a replacement default + // screen. This could also be used to create shims for things like nesting screens. + select { + case s := <-overrideScreen: return s, nil - } else if s, _ := NewConsoleScreen(); s != nil { + default: + } + + if s, e := NewTerminfoScreen(); s != nil { return s, nil } else { return nil, e } } +// ShimScreen allows an application to override the screen that will +// be returned by NewScreen. Typically this is used for testing, +// where the test code calls this once before running an example. +// It could also be used to intercept a regular Screen. +func ShimScreen(s Screen) { + overrideOnce.Do(func() { + overrideScreen = make(chan Screen, 8) // normally would only be one anyway + }) + overrideScreen <- s +} + // MouseFlags are options to modify the handling of mouse events. // Actual events can be ORed together. type MouseFlags int @@ -351,7 +320,7 @@ type screenImpl interface { SetStyle(style Style) ShowCursor(x int, y int) HideCursor() - SetCursor(CursorStyle, Color) + SetCursor(CursorStyle, color.Color) Size() (width, height int) EnableMouse(...MouseFlags) DisableMouse() @@ -359,16 +328,13 @@ type screenImpl interface { DisablePaste() EnableFocus() DisableFocus() - HasMouse() bool Colors() int Show() Sync() CharacterSet() string RegisterRuneFallback(r rune, subst string) UnregisterRuneFallback(r rune) - CanDisplay(r rune, checkFallbacks bool) bool Resize(int, int, int, int) - HasKey(Key) bool Suspend() error Resume() error Beep() error @@ -377,6 +343,9 @@ type screenImpl interface { Tty() (Tty, bool) SetClipboard([]byte) GetClipboard() + HasClipboard() bool + ShowNotification(string, string) + Terminal() (string, string) // Following methods are not part of the Screen api, but are used for interaction with // the common layer code. @@ -429,14 +398,6 @@ func (b *baseScreen) PutStr(x, y int, str string) { b.PutStrStyled(x, y, str, StyleDefault) } -func (b *baseScreen) SetCell(x int, y int, style Style, ch ...rune) { - if len(ch) > 0 { - b.Put(x, y, string(ch), style) - } else { - b.Put(x, y, " ", style) - } -} - func (b *baseScreen) Clear() { b.Fill(' ', StyleDefault) } @@ -459,18 +420,6 @@ func (b *baseScreen) Get(x, y int) (string, Style, int) { return cells.Get(x, y) } -func (b *baseScreen) GetContent(x, y int) (rune, []rune, Style, int) { - var primary rune - var combining []rune - var style Style - var width int - cells := b.GetCells() - b.Lock() - primary, combining, style, width = cells.GetContent(x, y) - b.Unlock() - return primary, combining, style, width -} - func (b *baseScreen) LockRegion(x, y, width, height int, lock bool) { cells := b.GetCells() b.Lock() @@ -487,56 +436,7 @@ func (b *baseScreen) LockRegion(x, y, width, height int, lock bool) { b.Unlock() } -func (b *baseScreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) { - defer close(ch) - for { - select { - case <-quit: - return - case <-b.StopQ(): - return - case ev := <-b.EventQ(): - select { - case <-quit: - return - case <-b.StopQ(): - return - case ch <- ev: - } - } - } -} - -func (b *baseScreen) PollEvent() Event { - select { - case <-b.StopQ(): - return nil - case ev := <-b.EventQ(): - return ev - } -} - -func (b *baseScreen) HasPendingEvent() bool { - return len(b.EventQ()) > 0 -} - -func (b *baseScreen) PostEventWait(ev Event) { - select { - case b.EventQ() <- ev: - case <-b.StopQ(): - } -} - -func (b *baseScreen) PostEvent(ev Event) error { - select { - case b.EventQ() <- ev: - return nil - default: - return ErrEventQFull - } -} - -func (b *baseScreen) SetCursorStyle(cs CursorStyle, ccs ...Color) { +func (b *baseScreen) SetCursorStyle(cs CursorStyle, ccs ...color.Color) { if len(ccs) > 0 { b.SetCursor(cs, ccs[0]) } else { diff --git a/vendor/github.com/gdamore/tcell/v2/style.go b/vendor/github.com/gdamore/tcell/v3/style.go similarity index 59% rename from vendor/github.com/gdamore/tcell/v2/style.go rename to vendor/github.com/gdamore/tcell/v3/style.go index 73995c0e4..8aedd97db 100644 --- a/vendor/github.com/gdamore/tcell/v2/style.go +++ b/vendor/github.com/gdamore/tcell/v3/style.go @@ -1,8 +1,8 @@ -// Copyright 2024 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -14,6 +14,13 @@ package tcell +import ( + "strings" + "unicode/utf8" + + "github.com/gdamore/tcell/v3/color" +) + // Style represents a complete text style, including both foreground color, // background color, and additional attributes such as "bold" or "underline". // @@ -23,13 +30,42 @@ package tcell // // To use Style, just declare a variable of its type. type Style struct { - fg Color - bg Color - ulStyle UnderlineStyle - ulColor Color + fg color.Color + bg color.Color + ulColor color.Color attrs AttrMask - url string - urlId string + ulStyle UnderlineStyle + url *urlInfo +} + +type urlInfo struct { + url string + id string +} + +func stripOSCControls(s string) string { + var b strings.Builder + b.Grow(len(s)) + for i := 0; i < len(s); { + r, size := utf8.DecodeRuneInString(s[i:]) + if r == utf8.RuneError && size == 1 { + c := s[i] + if c <= 0x1f || c == 0x7f || (c >= 0x80 && c <= 0x9f) { + i++ + continue + } + _ = b.WriteByte(c) + i++ + continue + } + if r <= 0x1f || r == 0x7f || (r >= 0x80 && r <= 0x9f) { + i += size + continue + } + b.WriteString(s[i : i+size]) + i += size + } + return b.String() } // StyleDefault represents a default style, based upon the context. @@ -41,7 +77,7 @@ var styleInvalid = Style{attrs: AttrInvalid} // Foreground returns a new style based on s, with the foreground color set // as requested. ColorDefault can be used to select the global default. -func (s Style) Foreground(c Color) Style { +func (s Style) Foreground(c color.Color) Style { s2 := s s2.fg = c return s2 @@ -49,20 +85,12 @@ func (s Style) Foreground(c Color) Style { // Background returns a new style based on s, with the background color set // as requested. ColorDefault can be used to select the global default. -func (s Style) Background(c Color) Style { +func (s Style) Background(c color.Color) Style { s2 := s s2.bg = c return s2 } -// Decompose breaks a style up, returning the foreground, background, -// and other attributes. The URL if set is not included. -// Deprecated: Applications should not attempt to decompose style, -// as this content is not sufficient to describe the actual style. -func (s Style) Decompose() (fg Color, bg Color, attr AttrMask) { - return s.fg, s.bg, s.attrs -} - func (s Style) setAttrs(attrs AttrMask, on bool) Style { s2 := s if on { @@ -112,14 +140,14 @@ func (s Style) Reverse(on bool) Style { return s.setAttrs(AttrReverse, on) } -// StrikeThrough sets strikethrough mode. +// StrikeThrough sets strike-through mode. func (s Style) StrikeThrough(on bool) Style { return s.setAttrs(AttrStrikeThrough, on) } // Underline style. Modern terminals have the option of rendering the // underline using different styles, and even different colors. -type UnderlineStyle int +type UnderlineStyle uint8 const ( UnderlineStyleNone = UnderlineStyle(iota) @@ -136,24 +164,17 @@ const ( // bool: on / off - enables just a simple underline // UnderlineStyle: sets a specific style (should not coexist with the bool) // Color: the color to use -func (s Style) Underline(params ...interface{}) Style { +func (s Style) Underline(params ...any) Style { s2 := s for _, param := range params { switch v := param.(type) { case bool: if v { s2.ulStyle = UnderlineStyleSolid - s2.attrs |= AttrUnderline } else { s2.ulStyle = UnderlineStyleNone - s2.attrs &^= AttrUnderline } case UnderlineStyle: - if v == UnderlineStyleNone { - s2.attrs &^= AttrUnderline - } else { - s2.attrs |= AttrUnderline - } s2.ulStyle = v case Color: s2.ulColor = v @@ -164,30 +185,52 @@ func (s Style) Underline(params ...interface{}) Style { return s2 } +// GetForeground returns the foreground (text) color. +func (s Style) GetForeground() color.Color { + return s.fg +} + +// GetBackground returns the background color. +func (s Style) GetBackground() color.Color { + return s.bg +} + // GetUnderlineStyle returns the underline style for the style. func (s Style) GetUnderlineStyle() UnderlineStyle { return s.ulStyle } // GetUnderlineColor returns the underline color for the style. -func (s Style) GetUnderlineColor() Color { +func (s Style) GetUnderlineColor() color.Color { return s.ulColor } // Attributes returns a new style based on s, with its attributes set as // specified. +// +// Deprecated: Use direct functions instead. func (s Style) Attributes(attrs AttrMask) Style { s2 := s s2.attrs = attrs return s2 } +// GetAttributes gets the attributes for a style. +// Deprecated: Use individual properties instead. +func (s Style) GetAttributes() AttrMask { + return s.attrs +} + // Url returns a style with the Url set. If the provided Url is not empty, // and the terminal supports it, text will typically be marked up as a clickable // link to that Url. If the Url is empty, then this mode is turned off. func (s Style) Url(url string) Style { + s2 := s - s2.url = url + s2.url = &urlInfo{url: stripOSCControls(url)} + if s.url != nil { + s2.url.id = s.url.id + } return s2 } @@ -197,6 +240,58 @@ func (s Style) Url(url string) Style { // were one Url, even if it spans multiple lines. func (s Style) UrlId(id string) Style { s2 := s - s2.urlId = "id=" + id + s2.url = &urlInfo{ + id: "id=" + stripOSCControls(id), + } + if s.url != nil { + s2.url.url = s.url.url + } return s2 } + +// GetUrl returns the URL (id and actual URL) associated with the style. +// This is a hyper link that will be used for cells marked up with this style. +func (s Style) GetUrl() (id string, url string) { + if s.url != nil { + return strings.TrimPrefix(s.url.id, "id="), s.url.url + } + return "", "" +} + +// HasBold returns true if the style indicates bold text. +// Note that on some terminals bold text is simply brighter. +func (s Style) HasBold() bool { + return s.attrs&AttrBold != 0 +} + +// HasBlink returns true if the style indicates blinking text. +func (s Style) HasBlink() bool { + return s.attrs&AttrBlink != 0 +} + +// HasReverse returns true if the style indicates reverse video text. +func (s Style) HasReverse() bool { + return s.attrs&AttrReverse != 0 +} + +// HasItalic returns true if the style indicates italicized text. +func (s Style) HasItalic() bool { + return s.attrs&AttrItalic != 0 +} + +// HasDim returns true if the style indicates dim or faint text. +func (s Style) HasDim() bool { + return s.attrs&AttrDim != 0 +} + +// HasStrikeThrough returns true if the style indicates crossed-out text. +func (s Style) HasStrikeThrough() bool { + return s.attrs&AttrStrikeThrough != 0 +} + +// HasUnderline returns true if any underline style is set. +// Note that more detail is available via the GetUnderlineStyle +// and GetUnderlineColor methods. +func (s Style) HasUnderline() bool { + return s.ulStyle != UnderlineStyleNone +} diff --git a/vendor/github.com/gdamore/tcell/v3/tscreen.go b/vendor/github.com/gdamore/tcell/v3/tscreen.go new file mode 100644 index 000000000..3ff2c85bb --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/tscreen.go @@ -0,0 +1,1443 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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. + +//go:build !js && !wasm +// +build !js,!wasm + +package tcell + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "io" + "maps" + "os" + "runtime" + "slices" + "strconv" + "strings" + "sync" + "time" + "unicode/utf8" + + "github.com/gdamore/tcell/v3/color" + "github.com/gdamore/tcell/v3/vt" + "golang.org/x/text/transform" +) + +// NewTerminfoScreen returns a Screen that uses the stock TTY interface +// and POSIX terminal control, combined with a terminfo description taken from +// the $TERM environment variable. It returns an error if the terminal +// is not supported for any reason. +// +// For terminals that do not support dynamic resize events, the $LINES +// $COLUMNS environment variables can be set to the actual window size, +// otherwise defaults taken from the terminal database are used. +func NewTerminfoScreen(opts ...TerminfoScreenOption) (Screen, error) { + return NewTerminfoScreenFromTty(nil, opts...) +} + +type TerminfoScreenOption interface { + apply(*tScreen) +} + +// OptColors forces the number of colors, overriding the value +// of the color count that would be detected by the environment. +// If the value is 0, then color is forced off. Other reasonable values +// are 8, 16, 88, 256, or 1<<24. The latter case intrinsically enables +// 24-bit color as well. +type OptColors int + +func (o OptColors) apply(t *tScreen) { + t.ncolor = min(int(o), 256) + t.truecolor = o > 256 + t.noColor = o == 0 +} + +// OptTerm overrides the detection of $TERM. +type OptTerm string + +func (o OptTerm) apply(t *tScreen) { + t.term = string(o) +} + +// OptAltScreen controls whether the alternate screen buffer is used. +// The default is true. The TCELL_ALTSCREEN=disable environment override +// is still honored. +type OptAltScreen bool + +func (o OptAltScreen) apply(t *tScreen) { + t.altScreen = bool(o) +} + +// Some terminal escapes that are basically universal. +// We would really like to be able to use private mode queries for some of +// these but generally we've found that support for queries is not always present, +// even when the private modes can be controlled. It appears that *all* terminals +// will happily swallow the escapes that they do not recognize, with the small annoyance +// in "st" where it prints error messages to its stderr (which is usually not visible +// to the user unless they started it from another terminal session). But apart from +// the complaint to stderr from "st", everything else is fine. +const ( + enableAutoMargin = "\x1b[?7h" // dec private mode 7 + setCursorPosition = "\x1b[%[1]d;%[2]dH" + sgr0 = "\x1b[m" // attrOff + bold = "\x1b[1m" + dim = "\x1b[2m" + italic = "\x1b[3m" + underline = "\x1b[4m" + blink = "\x1b[5m" + reverse = "\x1b[7m" + strikeThrough = "\x1b[9m" + clear = "\x1b[H\x1b[J" + doubleUnder = "\x1b[4:2m" + curlyUnder = "\x1b[4:3m" + dottedUnder = "\x1b[4:4m" + dashedUnder = "\x1b[4:5m" + underColor = "\x1b[58:5:%dm" + underRGB = "\x1b[58:2::%d:%d:%dm" + underFg = "\x1b[59m" + enableAltChars = "\x1b(B\x1b)0" // set G0 as US-ASCII, G1 as DEC line drawing + startAltChars = "\x0e" // aka Shift-Out + endAltChars = "\x0f" // aka Shift-In + setFg8 = "\x1b[3%dm" // for colors less than 8 + setFg256 = "\x1b[38;5;%dm" // for colors less than 256 + setFgRgb = "\x1b[38;2;%d;%d;%dm" // for RGB + setBg8 = "\x1b[4%dm" // color colors less than 8 + setBg256 = "\x1b[48;5;%dm" // for colors less than 256 + setBgRgb = "\x1b[48;2;%d;%d;%dm" // for RGB + setFgBgRgb = "\x1b[38;2;%d;%d;%d;48;2;%d;%d;%dm" // for RGB, in one shot + enterCA = "\x1b[?1049h" // alternate screen + exitCA = "\x1b[?1049l" // alternate screen + enterKeypad = "\x1b[?1h\x1b=" // Note mode 1 might not be supported everywhere + exitKeypad = "\x1b[?1l\x1b>" // Also mode 1 + requestWindowSize = "\x1b[18t" // For modern terminals + requestPrimaryDA = "\x1b[c" // Request primary device attributes + requestExtAttr = "\x1b[>q" // Request extended attribute (emulator name and version) + setClipboard = "\x1b]52;c;%s\x1b\\" // Clipboard content is base64 + notifyDesktop9 = "\x1b]9;%[2]s\x1b\\" // Args are title, body (but OSC 9 only has body) + notifyDesktop777 = "\x1b]777;notify;%s;%s\x1b\\" // Most commonly supported + queryKittyKbd = "\x1b[?u" // Query for Kitty keyboard support + enableKittyKbd = "\x1b[=1u" // Technically this pushes + disableKittyKbd = "\x1b[=0u" // Technically this means pop previous mode + queryXTermKbd = "\x1b[?4m" // Query for XTerm modify other keys support + enableXTermKbd = "\x1b[>4;2m" // Enable modify other keys protocol + disableXTermKbd = "\x1b[>4;0m" // Disable modify other keys protocol +) + +// NewTerminfoScreenFromTty returns a Screen using a custom Tty implementation. +// If the passed in tty is nil, then a reasonable default (typically /dev/tty) +// is presumed, at least on UNIX hosts. (Windows hosts will typically fail this +// call altogether.) +func NewTerminfoScreenFromTty(tty Tty, opts ...TerminfoScreenOption) (Screen, error) { + t := &tScreen{tty: tty, altScreen: true} + + t.prepareCursorStyles() + t.prepareExtendedOSC() + t.buildAcsMap() + t.resizeQ = make(chan bool, 1) + t.fallback = make(map[rune]string) + maps.Copy(t.fallback, RuneFallbacks) + for _, o := range opts { + o.apply(t) + } + + return &baseScreen{screenImpl: t}, nil +} + +// tScreen represents a screen backed by a terminfo implementation. +type tScreen struct { + tty Tty + h int + w int + fini bool + cells CellBuffer + buffering bool // true if we are collecting writes to buf instead of sending directly to out + buf bytes.Buffer + curstyle Style + style Style + resizeQ chan bool + quit chan struct{} + keyQ chan []byte + cx int + cy int + cls bool // clear screen + cursorx int + cursory int + acs map[rune]string + charset string + encoder transform.Transformer + decoder transform.Transformer + fallback map[rune]string + ncolor int + colors map[color.Color]color.Color + palette []color.Color + truecolor bool + noColor bool + legacy bool + hasClipboard bool // true if OSC 52 reported via DA1 + finiOnce sync.Once + enterUrl string + exitUrl string + setWinSize string + cursorStyles map[CursorStyle]string + cursorStyle CursorStyle + cursorColor color.Color + cursorRGB string + cursorFg string + stopQ chan struct{} + eventQ chan Event + initQ chan Event + initted bool + running bool + startTime time.Time + wg sync.WaitGroup + mouseFlags MouseFlags + pasteEnabled bool + focusEnabled bool + setTitle string + saveTitle string + restoreTitle string + title string + setClipboard string + notifyDesktop string + termName string + termVers string + term string // value from $TERM + altScreen bool + inlineResize bool + haveMouse bool + haveMouseSgr bool + haveKittyKbd bool + haveWin32Kbd bool + haveXTermKbd bool + input *inputParser + sync.Mutex +} + +func (t *tScreen) useAltScreen() bool { + return t.altScreen && os.Getenv("TCELL_ALTSCREEN") != "disable" +} + +func (t *tScreen) Init() error { + if e := t.initialize(); e != nil { + return e + } + + t.startTime = time.Now() + t.keyQ = make(chan []byte, 10) + + t.charset = getCharset() + if enc := GetEncoding(t.charset); enc != nil { + t.encoder = enc.NewEncoder() + t.decoder = enc.NewDecoder() + } else { + return ErrNoCharset + } + + // environment overrides + w := 80 + h := 24 + if i, _ := strconv.Atoi(os.Getenv("LINES")); i != 0 { + h = i + } + if i, _ := strconv.Atoi(os.Getenv("COLUMNS")); i != 0 { + w = i + } + if t.term == "" { + t.term = os.Getenv("TERM") + } + nterm := t.term + + if t.ncolor == 0 && !t.noColor { + cterm := os.Getenv("COLORTERM") + + // On Windows, enable 24-bit color by default (all terminals there are 24-bit capable) + if runtime.GOOS == "windows" { + t.truecolor = true + t.ncolor = 256 + } else if slices.Contains([]string{"truecolor", "direct", "24bit"}, cterm) || strings.HasSuffix(nterm, "-direct") || strings.HasSuffix(nterm, "-truecolor") { + t.truecolor = true + t.ncolor = 256 // base 8-bit palette + } else if strings.HasSuffix(nterm, "-256color") || strings.Contains(cterm, "256") { + t.ncolor = 256 + } else if strings.HasSuffix(nterm, "-88color") { + t.ncolor = 88 + } else if strings.HasSuffix(nterm, "-16color") { + t.ncolor = 16 + } else if strings.Contains(nterm, "color") || cterm != "" { + t.ncolor = 8 + } else if strings.Contains(nterm, "mono") || strings.HasSuffix(nterm, "-m") { // monochrome variants + t.ncolor = 0 + } else if strings.Contains(nterm, "ansi") || slices.Contains([]string{"dtterm", "xterm", "aixterm", "linux"}, nterm) { + t.ncolor = 8 + } else if strings.HasPrefix(nterm, "vt") || nterm == "sun" { + // legacy DEC VT 100/220 etc. family. (technically the VT525 can do ANSI, but they should set to ansi) + t.ncolor = 0 + } else { + // best guess - this covers all the modern variants like ghostty, + t.ncolor = 256 + } + if os.Getenv("NO_COLOR") != "" { + t.truecolor = false + t.ncolor = 0 + t.noColor = true + } + // A user who wants to have his themes honored can set this environment variable. + if os.Getenv("TCELL_TRUECOLOR") == "disable" { + t.truecolor = false + } + } + + if strings.HasPrefix(nterm, "vt") || strings.Contains(nterm, "ansi") || nterm == "linux" || nterm == "sun" || nterm == "sun-color" { + // these terminals are "legacy" and not expected to support most OSC functions + t.legacy = true + } + + t.initted = false + t.quit = make(chan struct{}) + t.initQ = make(chan Event, 32) + t.eventQ = make(chan Event, 128) + t.input = newInputParser(t.filterEvents()) + + t.Lock() + t.cx = -1 + t.cy = -1 + t.style = StyleDefault + t.cells.Resize(w, h) + t.cursorx = -1 + t.cursory = -1 + t.resize() + t.Unlock() + + if err := t.engage(); err != nil { + return err + } + + // clip to reasonable limits + nColors := min(t.ncolor, 256) + t.colors = make(map[color.Color]color.Color, nColors) + t.palette = make([]color.Color, nColors) + for i := range nColors { + t.palette[i] = color.PaletteColor(i) + // identity map for our builtin colors + t.colors[color.PaletteColor(i)] = color.PaletteColor(i) + } + + return nil +} + +func (t *tScreen) processInitQ() { + // NB: called with lock held + if t.initted { + return + } + + expire := time.After(time.Second) + + for { + select { + case <-expire: + t.initted = true + return + case ev := <-t.initQ: + switch ev := ev.(type) { + case *eventPrimaryAttributes: + if ev.Color && t.ncolor == 0 && !t.noColor { + t.ncolor = 8 + } + if ev.Clipboard && t.setClipboard == "" { + t.setClipboard = setClipboard + } + t.hasClipboard = ev.Clipboard + t.initted = true + return + case *eventTermName: + // terminal specific overrides + t.termName = ev.Name + t.termVers = ev.Version + switch ev.Name { + case "iTerm2": + // Some terminals can use OSC 9. Unfortunately we can only discover + // them using this means. It appears that pretty much all of them + // except iTerm2 also support more standard OSC 777, and it seems like + // only Kitty has its OSC 99 thing, but it also does OSC 777 well. + t.notifyDesktop = notifyDesktop9 + } + case *eventPrivateMode: + switch ev.Mode { + case vt.PmResizeReports: + t.inlineResize = ev.Status.Changeable() + case vt.PmMouseSgr: + t.haveMouseSgr = ev.Status.Changeable() + case vt.PmMouseButton: + t.haveMouse = ev.Status.Changeable() + case vt.PmWin32Input: + t.haveWin32Kbd = ev.Status.Changeable() + } + case *eventKittyKbdMode: + t.haveKittyKbd = true + case *eventXTermKbdMode: + t.haveXTermKbd = true + } + } + } +} + +func (t *tScreen) filterEvents() chan Event { + inQ := make(chan Event, 128) + go func() { + for { + var ev Event + select { + case ev = <-inQ: + case <-t.quit: + return + } + switch ev.(type) { + case *eventTermName, *eventPrimaryAttributes, *eventPrivateMode, *eventKittyKbdMode, *eventXTermKbdMode: + select { + case t.initQ <- ev: + default: + } + + default: + t.eventQ <- ev + } + } + }() + return inQ +} + +func (t *tScreen) prepareExtendedOSC() { + if t.legacy { + return + } + + // OSC 8 is for enter/exit URL. + t.enterUrl = "\x1b]8;%[2]s;%[1]s\x1b\\" + t.exitUrl = "\x1b]8;;\x1b\\" + + // CSI .. t is for window operations. + t.setWinSize = "\x1b[8;%[2]d;%[1]dt" + t.saveTitle = "\x1b[22;2t" + t.restoreTitle = "\x1b[23;2t" + // this also tries to request that UTF-8 is allowed in the title + t.setTitle = "\x1b[>2t\x1b]2;%s\x1b\\" + + // OSC 52 is for saving to the clipboard. + // this string takes a base64 string and sends it to the clipboard. + // it will also be able to retrieve the clipboard using "?" as the + // sent string, when we support that. + t.setClipboard = setClipboard + + // OSC 777 is the desktop notification supported by a variety of + // newer terminals. (There was also OSC 9 and OSC 99, but they + // are not as widely deployed, and OSC 9 is not unique.) + t.notifyDesktop = notifyDesktop777 +} + +func (t *tScreen) prepareCursorStyles() { + t.cursorStyles = map[CursorStyle]string{ + CursorStyleDefault: "\x1b[0 q", + CursorStyleBlinkingBlock: "\x1b[1 q", + CursorStyleSteadyBlock: "\x1b[2 q", + CursorStyleBlinkingUnderline: "\x1b[3 q", + CursorStyleSteadyUnderline: "\x1b[4 q", + CursorStyleBlinkingBar: "\x1b[5 q", + CursorStyleSteadyBar: "\x1b[6 q", + } + if t.legacy { + return + } + if t.cursorRGB == "" { + t.cursorRGB = "\x1b]12;#%02x%02x%02x\007" + t.cursorFg = "\x1b]112\007" + } +} + +func (t *tScreen) Fini() { + // Ensure that enough time passes for terminals to finish sending + // their initial response (gnome-terminal sends terminal dimensions + // asynchronously later than the response to primary DA for some reason.) + if time.Since(t.startTime) < 50*time.Millisecond { + time.Sleep(time.Millisecond * 50) + } + t.finiOnce.Do(t.finish) +} + +func (t *tScreen) finish() { + close(t.quit) + t.finalize() +} + +func (t *tScreen) SetStyle(style Style) { + t.Lock() + if !t.fini { + t.style = style + } + t.Unlock() +} + +func (t *tScreen) encodeStr(s string) []byte { + + var dstBuf [128]byte + var buf []byte + nb := dstBuf[:] + dst := 0 + var err error + if enc := t.encoder; enc != nil { + enc.Reset() + dst, _, err = enc.Transform(nb, []byte(s), true) + } + if err != nil || dst == 0 || nb[0] == '\x1a' { + // Combining characters are elided + r, _ := utf8.DecodeRuneInString(s) + if len(buf) == 0 { + if acs, ok := t.acs[r]; ok { + buf = append(buf, []byte(acs)...) + } else if fb, ok := t.fallback[r]; ok { + buf = append(buf, []byte(fb)...) + } else { + buf = append(buf, '?') + } + } + } else { + buf = append(buf, nb[:dst]...) + } + + return buf +} + +// resolvePalette looks up a color to obtain the palette entry for it. +func (t *tScreen) resolvePalette(c Color) Color { + if v, ok := t.colors[c]; ok { + return v + } + v := color.Find(c, t.palette) + t.colors[c] = v + return v +} + +// sendFgBg sends the foreground and background. It is assumed that sgr0 +// was already emitted prior to calling this (so colors are already in default). +func (t *tScreen) sendFgBg(fg Color, bg Color, attr AttrMask) AttrMask { + if t.Colors() == 0 { + // foreground vs background, we calculate luminance + // and possibly do a reverse video + if !fg.Valid() { + return attr + } + v, ok := t.colors[fg] + if !ok { + v = color.Find(fg, []Color{ColorBlack, ColorWhite}) + t.colors[fg] = v + } + switch v { + case ColorWhite: + return attr + case ColorBlack: + return attr ^ AttrReverse + } + } + + if t.truecolor { + if fg.IsRGB() && bg.IsRGB() { + r1, g1, b1 := fg.RGB() + r2, g2, b2 := bg.RGB() + t.Printf(setFgBgRgb, r1, g1, b1, r2, g2, b2) + return attr + } + + if fg.IsRGB() { + r, g, b := fg.RGB() + t.Printf(setFgRgb, r, g, b) + fg = ColorDefault + } + + if bg.IsRGB() { + r, g, b := bg.RGB() + t.Printf(setBgRgb, r, g, b) + bg = ColorDefault + } + } + + if fg.Valid() { + fg = t.resolvePalette(fg) + fgc := fg & 0xffffff + if fgc < 8 { + t.Printf(setFg8, fgc) + } else if fgc < 256 { + t.Printf(setFg256, fgc) + } + } + + if bg.Valid() { + bg = t.resolvePalette(bg) + bgc := bg & 0xffffff + if bgc < 8 { + t.Printf(setBg8, bgc) + } else if bgc < 256 { + t.Printf(setBg256, bgc) + } + } + + return attr +} + +// emitAttrs dumps prints the attributes, aside from underline that is special +// The assumption is that sgr0 was already printed ahead of this. +func (t *tScreen) emitAttrs(attrs AttrMask) { + + if attrs&AttrBold != 0 { + t.Print(bold) + } + if attrs&AttrReverse != 0 { + t.Print(reverse) + } + if attrs&AttrBlink != 0 { + t.Print(blink) + } + if attrs&AttrDim != 0 { + t.Print(dim) + } + if attrs&AttrItalic != 0 { + t.Print(italic) + } + if attrs&AttrStrikeThrough != 0 { + t.Print(strikeThrough) + } +} + +// emitUl dumps prints the underline, which may be colored. +// The assumption is that sgr0 was already printed ahead of this. +func (t *tScreen) emitUnderline(us UnderlineStyle, uc Color) { + if us != UnderlineStyleNone { + // NB: under color should have been reset by sgr0 + if uc.IsRGB() { + r, g, b := uc.RGB() + uc = t.resolvePalette(uc) + t.Printf(underColor, uc&0xff) + t.Printf(underRGB, r, g, b) + } else if uc.Valid() { + t.Printf(underColor, uc&0xff) + } + + t.Print(underline) // to ensure everyone gets at least a basic underline + switch us { + case UnderlineStyleDouble: + t.Print(doubleUnder) + case UnderlineStyleCurly: + t.Print(curlyUnder) + case UnderlineStyleDotted: + t.Print(dottedUnder) + case UnderlineStyleDashed: + t.Print(dashedUnder) + } + } +} + +// emitUrl either emits a url (OSC 8), or if the string is empty +// then the OSC 8 to exit the URL. It should only be called if we +// either have a new URL, or need to exit an old one, as it always emits +// the OSC 8 sequence (if OSC 8 is supported). +func (t *tScreen) emitUrl(u urlInfo) { + if t.enterUrl != "" { + if u.url != "" { + t.Printf(t.enterUrl, u.url, u.id) + } else { + t.Print(t.exitUrl) + } + } +} + +func (t *tScreen) drawCell(x, y int) int { + + str, style, width := t.cells.Get(x, y) + if !t.cells.Dirty(x, y) { + return width + } + + if t.cy != y || t.cx != x { + t.Printf(setCursorPosition, y+1, x+1) + t.cx = x + t.cy = y + } + + if style == StyleDefault { + style = t.style + } + if style != t.curstyle { + fg, bg, attrs := style.fg, style.bg, style.attrs + + t.Print(sgr0) + + attrs = t.sendFgBg(fg, bg, attrs) + t.emitAttrs(attrs) + t.emitUnderline(style.ulStyle, style.ulColor) + + var newUrl urlInfo + var oldUrl urlInfo + if t.curstyle.url != nil { + oldUrl = *t.curstyle.url + } + if style.url != nil { + newUrl = *style.url + } + // URL string can be long, so don't send it unless we really need to + if newUrl != oldUrl { + t.emitUrl(newUrl) + } + + t.curstyle = style + } + + // now emit runes - taking care to not overrun width with a + // wide character, and to ensure that we emit exactly one regular + // character followed up by any residual combing characters + + if width < 1 { + width = 1 + } + + buf := t.encodeStr(str) + str = string(buf) + + if width > 1 && str == "?" { + // No FullWidth character support + str = "? " + t.cx = -1 + } + + if x > t.w-width { + // too wide to fit; emit a single space instead + width = 1 + str = " " + } + if width > 1 && x+width < t.w { + // Clobber over any content in the next cell. + // This fixes a problem with some terminals where overwriting two + // adjacent single cells with a wide rune would leave an image + // of the second cell. This is a workaround for buggy terminals. + t.Print(" \b\b") + } + t.Print(str) + t.cx += width + t.cells.SetDirty(x, y, false) + if width > 1 && len([]rune(str)) > 1 { + t.cx = -1 + } + + return width +} + +func (t *tScreen) ShowCursor(x, y int) { + t.Lock() + t.cursorx = x + t.cursory = y + t.Unlock() +} + +func (t *tScreen) SetCursor(cs CursorStyle, cc Color) { + t.Lock() + t.cursorStyle = cs + t.cursorColor = cc + t.Unlock() +} + +func (t *tScreen) HideCursor() { + t.ShowCursor(-1, -1) +} + +func (t *tScreen) showCursor() { + + x, y := t.cursorx, t.cursory + w, h := t.cells.Size() + if x < 0 || y < 0 || x >= w || y >= h { + t.hideCursor() + return + } + t.Printf(setCursorPosition, y+1, x+1) + t.Print(vt.PmShowCursor.Enable()) + if t.cursorStyles != nil { + if esc, ok := t.cursorStyles[t.cursorStyle]; ok { + t.Print(esc) + } + } + if t.cursorRGB != "" { + if t.cursorColor == ColorReset { + t.Print(t.cursorFg) + } else if t.cursorColor.Valid() { + r, g, b := t.cursorColor.RGB() + t.Printf(t.cursorRGB, r, g, b) + } + } + t.cx = x + t.cy = y +} + +func (t *tScreen) Write(b []byte) (int, error) { + if t.buffering { + return t.buf.Write(b) + } + return t.tty.Write(b) +} + +func (t *tScreen) Print(s string) { + _, _ = io.WriteString(t, s) +} + +func (t *tScreen) Printf(f string, args ...any) { + _, _ = fmt.Fprintf(t, f, args...) +} + +func (t *tScreen) Show() { + t.Lock() + if !t.fini { + t.resize() + t.draw() + } + t.Unlock() +} + +func (t *tScreen) clearScreen() { + t.Print(sgr0) + t.Print(t.exitUrl) + _ = t.sendFgBg(t.style.fg, t.style.bg, AttrNone) + + t.Print(clear) + + t.cls = false +} + +func (t *tScreen) startBuffering() { + t.Print(vt.PmSyncOutput.Enable()) +} + +func (t *tScreen) endBuffering() { + t.Print(vt.PmSyncOutput.Disable()) +} + +func (t *tScreen) hideCursor() { + // just in case we cannot hide it, move it to the end + t.cx, t.cy = t.cells.Size() + t.Printf(setCursorPosition, t.cy+1, t.cx+1) + // then hide it + t.Print(vt.PmShowCursor.Disable()) +} + +func (t *tScreen) draw() { + // clobber cursor position, because we're going to change it all + t.cx = -1 + t.cy = -1 + // make no style assumptions + t.curstyle = styleInvalid + + t.buf.Reset() + t.buffering = true + t.startBuffering() + defer func() { + t.buffering = false + t.endBuffering() + }() + + // hide the cursor while we move stuff around + t.hideCursor() + + if t.cls { + t.clearScreen() + } + + for y := 0; y < t.h; y++ { + for x := 0; x < t.w; x++ { + width := t.drawCell(x, y) + if width > 1 { + if x+1 < t.w { + // this is necessary so that if we ever + // go back to drawing that cell, we + // actually will *draw* it. + t.cells.SetDirty(x+1, y, true) + } + } + x += width - 1 + } + } + + // restore the cursor + t.showCursor() + + _, _ = t.buf.WriteTo(t.tty) +} + +func (t *tScreen) EnableMouse(flags ...MouseFlags) { + var f MouseFlags + flagsPresent := false + for _, flag := range flags { + f |= flag + flagsPresent = true + } + if !flagsPresent { + f = MouseMotionEvents | MouseDragEvents | MouseButtonEvents + } + + t.Lock() + t.mouseFlags = f + t.enableMouse(f) + t.Unlock() +} + +func (t *tScreen) enableMouse(f MouseFlags) { + // Rather than using terminfo to find mouse escape sequences, we rely on the fact that + // pretty much *every* terminal that supports mouse tracking follows the + // XTerm standards (the modern ones). It is expected that all terminals understand + // the same DEC private modes. Note that the SGR mode is required for the mouse sequences + // to be understood. + + // We rely on dec private mode queries for this. + // If your terminal doesn't support these, then ask them to fix it. + // Note that as of macOS 26, macOS Terminal does not support them, + // so we enable the mouse unconditionally unless we get a report + // that says we have mouse, but not SGR mouse. This is suboptimal, but + // a concession forced by the sorry state of terminal emulators. + if t.haveMouse && !t.haveMouseSgr { + return + } + + // start by disabling all tracking. + t.Print(vt.PmMouseButton.Disable()) + t.Print(vt.PmMouseDrag.Disable()) + t.Print(vt.PmMouseMotion.Disable()) + t.Print(vt.PmMouseSgr.Disable()) + + if f&(MouseButtonEvents|MouseDragEvents|MouseMotionEvents) != 0 { + t.Print(vt.PmMouseButton.Enable()) + } + if f&MouseDragEvents != 0 { + t.Print(vt.PmMouseDrag.Enable()) + } + if f&MouseMotionEvents != 0 { + t.Print(vt.PmMouseMotion.Enable()) + } + if f&(MouseButtonEvents|MouseDragEvents|MouseMotionEvents) != 0 { + t.Print(vt.PmMouseSgr.Enable()) + } +} + +func (t *tScreen) DisableMouse() { + t.Lock() + t.mouseFlags = 0 + t.enableMouse(0) + t.Unlock() +} + +func (t *tScreen) EnablePaste() { + t.Lock() + t.pasteEnabled = true + t.enablePasting(true) + t.Unlock() +} + +func (t *tScreen) DisablePaste() { + t.Lock() + t.pasteEnabled = false + t.enablePasting(false) + t.Unlock() +} + +func (t *tScreen) enablePasting(on bool) { + var s string + if on { + s = vt.PmBracketedPaste.Enable() + } else { + s = vt.PmBracketedPaste.Disable() + } + if s != "" { + t.Print(s) + } +} + +func (t *tScreen) EnableFocus() { + t.Lock() + t.focusEnabled = true + t.enableFocusReporting() + t.Unlock() +} + +func (t *tScreen) DisableFocus() { + t.Lock() + t.focusEnabled = false + t.disableFocusReporting() + t.Unlock() +} + +func (t *tScreen) enableFocusReporting() { + t.Print(vt.PmFocusReports.Enable()) +} + +func (t *tScreen) disableFocusReporting() { + t.Print(vt.PmFocusReports.Disable()) +} + +func (t *tScreen) Size() (int, int) { + t.Lock() + w, h := t.w, t.h + t.Unlock() + return w, h +} + +func (t *tScreen) resize() { + ws, err := t.tty.WindowSize() + if err != nil { + return + } + if ws.Width == t.w && ws.Height == t.h { + return + } + t.cx = -1 + t.cy = -1 + + t.cells.Resize(ws.Width, ws.Height) + t.cells.Invalidate() + t.h = ws.Height + t.w = ws.Width + t.input.SetSize(ws.Width, ws.Height) +} + +func (t *tScreen) Colors() int { + // this doesn't change, no need for lock + if t.truecolor { + return 1 << 24 + } + return t.ncolor +} + +// vtACSNames is a map of bytes defined by terminfo that are used in +// the terminals Alternate Character Set to represent other glyphs. +// For example, the upper left corner of the box drawing set can be +// displayed by printing "l" while in the alternate character set. +// It's not quite that simple, since the "l" is the terminfo name, +// and it may be necessary to use a different character based on +// the terminal implementation (or the terminal may lack support for +// this altogether). These values are from the DEC VT100, and all +// modern terminal emulators support this as charset 0. +var vtACSNames = map[byte]rune{ + '`': RuneDiamond, + 'a': RuneCkBoard, + 'f': RuneDegree, + 'g': RunePlMinus, + 'h': RuneBoard, + 'i': RuneLantern, + 'j': RuneLRCorner, + 'k': RuneURCorner, + 'l': RuneULCorner, + 'm': RuneLLCorner, + 'n': RunePlus, + 'o': RuneS1, + 'p': RuneS3, + 'q': RuneHLine, + 'r': RuneS7, + 's': RuneS9, + 't': RuneLTee, + 'u': RuneRTee, + 'v': RuneBTee, + 'w': RuneTTee, + 'x': RuneVLine, + 'y': RuneLEqual, + 'z': RuneGEqual, + '{': RunePi, + '|': RuneNEqual, + '}': RuneSterling, + '~': RuneBullet, +} + +// buildAcsMap builds a map of characters that we translate from Unicode to +// alternate character encodings. To do this, we use the standard VT100 ACS +// maps. This is only done if the terminal lacks support for Unicode; we +// always prefer to emit Unicode glyphs when we are able. +func (t *tScreen) buildAcsMap() { + const acsstr = "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~" + + t.acs = make(map[rune]string) + for b, r := range vtACSNames { + t.acs[r] = startAltChars + string(b) + endAltChars + } +} + +func (t *tScreen) scanInput(buf *bytes.Buffer) { + // The end of the buffer isn't necessarily the end of the input, because + // large inputs are chunked. Set atEOF to false so the UTF-8 validating decoder + // returns ErrShortSrc instead of ErrInvalidUTF8 for incomplete multi-byte codepoints. + const atEOF = false + + for buf.Len() > 0 { + utf := make([]byte, min(8, max(buf.Len()*2, 128))) + nOut, nIn, e := t.decoder.Transform(utf, buf.Bytes(), atEOF) + _ = buf.Next(nIn) + t.input.ScanUTF8(utf[:nOut]) + if e == transform.ErrShortSrc { + return + } + } +} + +func (t *tScreen) mainLoop(stopQ chan struct{}) { + defer t.wg.Done() + buf := &bytes.Buffer{} + var ta <-chan time.Time + for { + select { + case <-stopQ: + return + case <-t.quit: + return + case <-t.resizeQ: + go func() { + t.Lock() + t.cx = -1 + t.cy = -1 + t.resize() + t.cells.Invalidate() + t.draw() + t.Unlock() + }() + continue + case chunk := <-t.keyQ: + buf.Write(chunk) + t.scanInput(buf) + if t.input.Waiting() { + ta = time.After(time.Millisecond * 100) + } else { + ta = nil + } + case <-ta: + t.input.Scan() + } + } +} + +func (t *tScreen) inputLoop(stopQ chan struct{}) { + + defer t.wg.Done() + for { + select { + case <-stopQ: + return + default: + } + chunk := make([]byte, 128) + n, e := t.tty.Read(chunk) + switch e { + case nil: + default: + t.Lock() + running := t.running + t.Unlock() + if running { + select { + case t.eventQ <- NewEventError(e): + case <-t.quit: + } + } + return + } + if n > 0 { + t.keyQ <- chunk[:n] + } + } +} + +func (t *tScreen) Sync() { + t.Lock() + t.cx = -1 + t.cy = -1 + if !t.fini { + t.resize() + t.cls = true + t.cells.Invalidate() + t.draw() + } + t.Unlock() +} + +func (t *tScreen) CharacterSet() string { + return t.charset +} + +func (t *tScreen) RegisterRuneFallback(orig rune, fallback string) { + t.Lock() + t.fallback[orig] = fallback + t.Unlock() +} + +func (t *tScreen) UnregisterRuneFallback(orig rune) { + t.Lock() + delete(t.fallback, orig) + t.Unlock() +} + +func (t *tScreen) SetSize(w, h int) { + if t.setWinSize != "" { + t.Printf(t.setWinSize, w, h) + } + t.cells.Invalidate() + t.resize() +} + +func (t *tScreen) Resize(int, int, int, int) {} + +func (t *tScreen) Suspend() error { + t.disengage() + return nil +} + +func (t *tScreen) Resume() error { + return t.engage() +} + +func (t *tScreen) Tty() (Tty, bool) { + return t.tty, true +} + +// engage is used to place the terminal in raw mode and establish screen size, etc. +// Think of this is as tcell "engaging" the clutch, as it's going to be driving the +// terminal interface. +func (t *tScreen) engage() error { + t.Lock() + defer t.Unlock() + if t.tty == nil { + return ErrNoScreen + } + if t.running { + return errors.New("already engaged") + } + if err := t.tty.Start(); err != nil { + return err + } + + stopQ := make(chan struct{}) + t.stopQ = stopQ + t.wg.Add(2) + go t.inputLoop(stopQ) + go t.mainLoop(stopQ) + + if !t.initted { + t.Print(requestWindowSize) + // macOS Terminal.app is brain damaged + // https://garrett.damore.org/2025/12/macos-terminal-still-missing-mark-apple.html + // Eventually they'll hopefully fix this. As the environment variable + // does not convey by default via ssh, remote sessions might see spurious characters + // emitted during startup. See the blog post for alternatives. + if os.Getenv("TERM_PROGRAM") != "Apple_Terminal" { + t.Print(vt.PmResizeReports.Query()) + t.Print(vt.PmMouseButton.Query()) + t.Print(vt.PmMouseSgr.Query()) + t.Print(vt.PmWin32Input.Query()) + t.Print(queryKittyKbd) + t.Print(queryXTermKbd) + t.Print(requestExtAttr) + } + t.Print(requestPrimaryDA) // NB: MUST BE LAST + } + t.processInitQ() + if t.useAltScreen() { + // Technically this may not be right, but every terminal we know about + // (even Wyse 60) uses this to enter the alternate screen buffer, and + // possibly save and restore the window title and/or icon. + // (In theory there could be terminals that don't support X,Y cursor + // positions without a setup command, but we don't support them.) + t.Print(enterCA) + t.Print(t.saveTitle) + } + if t.haveWin32Kbd { + t.Print(vt.PmWin32Input.Enable()) + } else if t.haveKittyKbd { + t.Print(enableKittyKbd) + } else if t.haveXTermKbd { + t.Print(enableXTermKbd) + } + + t.running = true + if ws, err := t.tty.WindowSize(); err == nil && ws.Width != 0 && ws.Height != 0 { + t.cells.Resize(ws.Width, ws.Height) + } + t.enableMouse(t.mouseFlags) + t.enablePasting(t.pasteEnabled) + if t.focusEnabled { + t.enableFocusReporting() + } + t.Print(enterKeypad) + t.Print(enableAltChars) + t.Print(vt.PmShowCursor.Disable()) + t.Print(vt.PmAutoMargin.Disable()) + t.Print(clear) + if t.title != "" && t.setTitle != "" { + t.Printf(t.setTitle, t.title) + } + if runtime.GOOS == "windows" { + // This workaround exists because of what we believe to be bugs in the + // interaction between ConPTY, the VT-Input layer, and some terminal emulators + // such as WezTerm. Note that it is *not* needed for Windows Terminal, but + // should be benign there. As another note, we have observed that at least Alacritty + // and WezTerm do not properly handle the primaryDA query on these platforms. + // (WezTerm performs much better when running a remote shell or on macOS.) + t.Print(enableKittyKbd) + t.Print(vt.PmWin32Input.Enable()) + } + t.Print(requestWindowSize) + + if t.inlineResize { + t.Print(vt.PmResizeReports.Enable()) + } else { + t.tty.NotifyResize(t.resizeQ) + } + return nil +} + +// disengage is used to release the terminal back to support from the caller. +// Think of this as tcell disengaging the clutch, so that another application +// can take over the terminal interface. This restores the TTY mode that was +// present when the application was first started. +func (t *tScreen) disengage() { + + t.Lock() + if !t.running { + t.Unlock() + return + } + + t.running = false + if t.inlineResize { + t.Print(vt.PmResizeReports.Disable()) + } else { + t.tty.NotifyResize(nil) + } + stopQ := t.stopQ + close(stopQ) + _ = t.tty.Drain() + t.Unlock() + + // wait for everything to shut down + t.wg.Wait() + + // shutdown the screen and disable special modes (e.g. mouse and bracketed paste) + t.cells.Resize(0, 0) + t.Print(vt.PmShowCursor.Enable()) + if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault { + t.Print(t.cursorStyles[CursorStyleDefault]) + } + if t.cursorFg != "" && t.cursorColor.Valid() { + t.Print(t.cursorFg) + } + t.Print(exitKeypad) + t.Print(sgr0) + t.Print(vt.PmAutoMargin.Enable()) + if t.haveWin32Kbd { + t.Print(vt.PmWin32Input.Disable()) + } + if t.haveKittyKbd { + t.Print(disableKittyKbd) + } + if t.haveXTermKbd { + t.Print(disableXTermKbd) + } + + // Hack for Windows. + if runtime.GOOS == "windows" { + t.Print(vt.PmWin32Input.Disable()) + t.Print(disableKittyKbd) + } + + // t.Print(t.disableCsiU) + if t.useAltScreen() { + t.Print(t.restoreTitle) + t.Print(clear) + t.Print(exitCA) + } + t.enableMouse(0) + t.enablePasting(false) + t.disableFocusReporting() + + _ = t.tty.Stop() +} + +// Beep emits a beep to the terminal. +func (t *tScreen) Beep() error { + t.Print(string(byte(7))) + return nil +} + +// finalize is used to at application shutdown, and restores the terminal +// to it's initial state. It should not be called more than once. +func (t *tScreen) finalize() { + t.disengage() + _ = t.tty.Close() + close(t.eventQ) +} + +func (t *tScreen) StopQ() <-chan struct{} { + return t.quit +} + +func (t *tScreen) EventQ() chan Event { + return t.eventQ +} + +func (t *tScreen) GetCells() *CellBuffer { + return &t.cells +} + +func (t *tScreen) SetTitle(title string) { + t.Lock() + t.title = title + if t.setTitle != "" && t.running { + t.Printf(t.setTitle, title) + } + t.Unlock() +} + +func (t *tScreen) SetClipboard(data []byte) { + // Post binary data to the system clipboard. It might be UTF-8, it might not be. + t.Lock() + if t.setClipboard != "" { + encoded := base64.StdEncoding.EncodeToString(data) + t.Printf(t.setClipboard, encoded) + } + t.Unlock() +} + +func (t *tScreen) GetClipboard() { + t.Lock() + if t.setClipboard != "" { + t.Printf(t.setClipboard, "?") + } + t.Unlock() +} + +func (t *tScreen) HasClipboard() bool { + return t.hasClipboard +} + +func (t *tScreen) ShowNotification(title string, body string) { + t.Lock() + t.Printf(t.notifyDesktop, title, body) + t.Unlock() +} + +func (t *tScreen) Terminal() (string, string) { + t.Lock() + defer t.Unlock() + return t.termName, t.termVers +} diff --git a/vendor/github.com/gdamore/tcell/v2/tscreen_plan9.go b/vendor/github.com/gdamore/tcell/v3/tscreen_plan9.go similarity index 72% rename from vendor/github.com/gdamore/tcell/v2/tscreen_plan9.go rename to vendor/github.com/gdamore/tcell/v3/tscreen_plan9.go index fdd55b8c8..1b165f74b 100644 --- a/vendor/github.com/gdamore/tcell/v2/tscreen_plan9.go +++ b/vendor/github.com/gdamore/tcell/v3/tscreen_plan9.go @@ -4,8 +4,8 @@ // Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -17,14 +17,8 @@ package tcell -import "os" - // initialize on Plan 9: if no TTY was provided, use the Plan 9 TTY. func (t *tScreen) initialize() error { - if os.Getenv("TERM") == "" { - // TERM should be "vt100" in a vt(1) window; color/mouse support will be limited. - _ = os.Setenv("TERM", "vt100") - } if t.tty == nil { tty, err := NewDevTty() if err != nil { diff --git a/vendor/github.com/gdamore/tcell/v2/tscreen_unix.go b/vendor/github.com/gdamore/tcell/v3/tscreen_unix.go similarity index 84% rename from vendor/github.com/gdamore/tcell/v2/tscreen_unix.go rename to vendor/github.com/gdamore/tcell/v3/tscreen_unix.go index 27f4c8134..a1082e459 100644 --- a/vendor/github.com/gdamore/tcell/v2/tscreen_unix.go +++ b/vendor/github.com/gdamore/tcell/v3/tscreen_unix.go @@ -1,8 +1,8 @@ // Copyright 2024 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -17,11 +17,6 @@ package tcell -import ( - // import the stock terminals - _ "github.com/gdamore/tcell/v2/terminfo/base" -) - // initialize is used at application startup, and sets up the initial values // including file descriptors used for terminals and saving the initial state // so that it can be restored when the application terminates. diff --git a/vendor/github.com/gdamore/tcell/v2/tscreen_win.go b/vendor/github.com/gdamore/tcell/v3/tscreen_win.go similarity index 78% rename from vendor/github.com/gdamore/tcell/v2/tscreen_win.go rename to vendor/github.com/gdamore/tcell/v3/tscreen_win.go index f2f9e2431..c0248992c 100644 --- a/vendor/github.com/gdamore/tcell/v2/tscreen_win.go +++ b/vendor/github.com/gdamore/tcell/v3/tscreen_win.go @@ -1,8 +1,8 @@ // Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -17,11 +17,6 @@ package tcell -import ( - // import the stock terminals - _ "github.com/gdamore/tcell/v2/terminfo/base" -) - // initialize is used at application startup, and sets up the initial values // including file descriptors used for terminals and saving the initial state // so that it can be restored when the application terminates. @@ -35,7 +30,3 @@ func (t *tScreen) initialize() error { } return nil } - -func init() { - defaultTerm = "xterm-truecolor" -} diff --git a/vendor/github.com/gdamore/tcell/v3/tty.go b/vendor/github.com/gdamore/tcell/v3/tty.go new file mode 100644 index 000000000..15813ac41 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/tty.go @@ -0,0 +1,34 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 tcell + +import "github.com/gdamore/tcell/v3/tty" + +type Tty = tty.Tty + +// NewDevTty obtains a default tty from the console or TTY (e.g. /dev/tty) for the process. +func NewDevTty() (Tty, error) { + return tty.NewDevTty() +} + +// NewDevTtyFromDev obtains a tty from the given device path. Not supported on Windows. +func NewDevTtyFromDev(dev string) (Tty, error) { + return tty.NewDevTtyFromDev(dev) +} + +// NewStdIoTty obtains a tty from stdin and stdout. +func NewStdIoTty() (Tty, error) { + return tty.NewStdIoTty() +} diff --git a/vendor/github.com/gdamore/tcell/v2/nonblock_bsd.go b/vendor/github.com/gdamore/tcell/v3/tty/nonblock_bsd.go similarity index 73% rename from vendor/github.com/gdamore/tcell/v2/nonblock_bsd.go rename to vendor/github.com/gdamore/tcell/v3/tty/nonblock_bsd.go index 622888e31..48fd23a1c 100644 --- a/vendor/github.com/gdamore/tcell/v2/nonblock_bsd.go +++ b/vendor/github.com/gdamore/tcell/v3/tty/nonblock_bsd.go @@ -1,8 +1,8 @@ // Copyright 2021 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -15,7 +15,7 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd -package tcell +package tty import ( "syscall" @@ -41,3 +41,10 @@ func tcSetBufParams(fd int, vMin uint8, vTime uint8) error { } return nil } + +// tcFlushInput discards any queued input before the caller starts reading from +// the tty. This avoids stale bytes, such as delayed mouse reports, from being +// delivered to the next foreground application. +func tcFlushInput(fd int) error { + return unix.IoctlSetPointerInt(fd, unix.TIOCFLUSH, unix.TCIFLUSH) +} diff --git a/vendor/github.com/gdamore/tcell/v2/nonblock_unix.go b/vendor/github.com/gdamore/tcell/v3/tty/nonblock_unix.go similarity index 72% rename from vendor/github.com/gdamore/tcell/v2/nonblock_unix.go rename to vendor/github.com/gdamore/tcell/v3/tty/nonblock_unix.go index 160a6419d..1dc1db2ef 100644 --- a/vendor/github.com/gdamore/tcell/v2/nonblock_unix.go +++ b/vendor/github.com/gdamore/tcell/v3/tty/nonblock_unix.go @@ -1,8 +1,8 @@ // Copyright 2021 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -15,7 +15,7 @@ //go:build linux || aix || zos || solaris // +build linux aix zos solaris -package tcell +package tty import ( "syscall" @@ -39,3 +39,10 @@ func tcSetBufParams(fd int, vMin uint8, vTime uint8) error { } return nil } + +// tcFlushInput discards any queued input before the caller starts reading from +// the tty. This avoids stale bytes, such as delayed mouse reports, from being +// delivered to the next foreground application. +func tcFlushInput(fd int) error { + return unix.IoctlSetInt(fd, unix.TCFLSH, unix.TCIFLUSH) +} diff --git a/vendor/github.com/gdamore/tcell/v2/stdin_unix.go b/vendor/github.com/gdamore/tcell/v3/tty/stdin_unix.go similarity index 63% rename from vendor/github.com/gdamore/tcell/v2/stdin_unix.go rename to vendor/github.com/gdamore/tcell/v3/tty/stdin_unix.go index b478b8918..3a101af7f 100644 --- a/vendor/github.com/gdamore/tcell/v2/stdin_unix.go +++ b/vendor/github.com/gdamore/tcell/v3/tty/stdin_unix.go @@ -1,8 +1,8 @@ // Copyright 2021 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -15,7 +15,7 @@ //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos -package tcell +package tty import ( "errors" @@ -23,7 +23,6 @@ import ( "os" "os/signal" "strconv" - "sync" "syscall" "time" @@ -33,16 +32,12 @@ import ( // stdIoTty is an implementation of the Tty API based upon stdin/stdout. type stdIoTty struct { - fd int - in *os.File - out *os.File - saved *term.State - sig chan os.Signal - cb func() - stopQ chan struct{} - dev string - wg sync.WaitGroup - l sync.Mutex + fd int + in *os.File + out *os.File + saved *term.State + sig chan os.Signal + started bool } func (tty *stdIoTty) Read(b []byte) (int, error) { @@ -58,18 +53,10 @@ func (tty *stdIoTty) Close() error { } func (tty *stdIoTty) Start() error { - tty.l.Lock() - defer tty.l.Unlock() + if tty.started { + return nil + } - // We open another copy of /dev/tty. This is a workaround for unusual behavior - // observed in macOS, apparently caused when a sub-shell (for example) closes our - // own tty device (when it exits for example). Getting a fresh new one seems to - // resolve the problem. (We believe this is a bug in the macOS tty driver that - // fails to account for dup() references to the same file before applying close() - // related behaviors to the tty.) We're also holding the original copy we opened - // since closing that might have deleterious effects as well. The upshot is that - // we will have up to two separate file handles open on /dev/tty. (Note that when - // using stdin/stdout instead of /dev/tty this problem is not observed.) var err error tty.in = os.Stdin tty.out = os.Stdout @@ -84,28 +71,13 @@ func (tty *stdIoTty) Start() error { if err != nil { return err } + if err = tcFlushInput(tty.fd); err != nil { + _ = term.Restore(tty.fd, saved) + return err + } tty.saved = saved + tty.started = true - tty.stopQ = make(chan struct{}) - tty.wg.Add(1) - go func(stopQ chan struct{}) { - defer tty.wg.Done() - for { - select { - case <-tty.sig: - tty.l.Lock() - cb := tty.cb - tty.l.Unlock() - if cb != nil { - cb() - } - case <-stopQ: - return - } - } - }(tty.stopQ) - - signal.Notify(tty.sig, syscall.SIGWINCH) return nil } @@ -118,18 +90,14 @@ func (tty *stdIoTty) Drain() error { } func (tty *stdIoTty) Stop() error { - tty.l.Lock() if err := term.Restore(tty.fd, tty.saved); err != nil { - tty.l.Unlock() return err } _ = tty.in.SetReadDeadline(time.Now()) - signal.Stop(tty.sig) - close(tty.stopQ) - tty.l.Unlock() + tty.NotifyResize(nil) - tty.wg.Wait() + tty.started = false return nil } @@ -161,10 +129,33 @@ func (tty *stdIoTty) WindowSize() (WindowSize, error) { return size, nil } -func (tty *stdIoTty) NotifyResize(cb func()) { - tty.l.Lock() - tty.cb = cb - tty.l.Unlock() +func (tty *stdIoTty) NotifyResize(resizeQ chan<- bool) { + + sigQ := tty.sig + tty.sig = nil + + if sigQ != nil { + signal.Stop(sigQ) + close(sigQ) + } + + if resizeQ == nil { + return + } + + sigQ = make(chan os.Signal, 1) + signal.Notify(sigQ, syscall.SIGWINCH) + + tty.sig = sigQ + + go func() { + for range sigQ { + select { + case resizeQ <- true: + default: // queue full, so nvm. + } + } + }() } // NewStdioTty opens a tty using standard input/output. diff --git a/vendor/github.com/gdamore/tcell/v2/tty.go b/vendor/github.com/gdamore/tcell/v3/tty/tty.go similarity index 64% rename from vendor/github.com/gdamore/tcell/v2/tty.go rename to vendor/github.com/gdamore/tcell/v3/tty/tty.go index 8bb1ac506..1387739f0 100644 --- a/vendor/github.com/gdamore/tcell/v2/tty.go +++ b/vendor/github.com/gdamore/tcell/v3/tty/tty.go @@ -1,8 +1,8 @@ -// Copyright 2021 The TCell Authors +// Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package tcell +package tty import "io" @@ -22,10 +22,18 @@ import "io" // with the terminfo-style based API. It extends the io.ReadWriter API. It is reasonable // that the implementation might choose to use different underlying files for the Reader // and Writer sides of this API, as part of it's internal implementation. +// +// Note that the consumer of these interfaces will provide mutual exclusion guarantees +// for the methods. Implementations need only be concerned about locking for any +// asynchronous functions that they use (e.g. signal handlers.) The exception to this +// is that Read and Write may be called concurrently to each other (but only after +// a successful Start), and Stop may be called while an outstanding Read or Write +// call is pending. (Stop should interrupt any blocking read.) type Tty interface { // Start is used to activate the Tty for use. Upon return the terminal should be // in raw mode, non-blocking, etc. The implementation should take care of saving // any state that is required so that it may be restored when Stop is called. + // Start must be idempotent. Start() error // Stop is used to stop using this Tty instance. This may be a suspend, so that other @@ -43,10 +51,15 @@ type Tty interface { // emitted between the time this is called, and when Stop is called. Drain() error - // NotifyResize is used register a callback when the tty thinks the dimensions have - // changed. The standard UNIX implementation links this to a handler for SIGWINCH. - // If the supplied callback is nil, then any handler should be unregistered. - NotifyResize(cb func()) + // NotifyResize is used to post a signal that will be written to (non-blocking) if the + // system detects that a resize event happened. If the channel is null, then the caller + // does not desire such notifications (or no longer desires them.) + // The standard UNIX implementation links this to a handler for SIGWINCH. + // + // If window resize events are delivered inline as part of Read, then the implementation may stub this. + // If the caller determines that the underlying terminal can deliver notifications without OS support + // (i.e. the terminal supports in-band resize notifications), then it may not call this function at all. + NotifyResize(chan<- bool) // WindowSize is called to determine the terminal dimensions. This might be determined // by an ioctl or other means. diff --git a/vendor/github.com/gdamore/tcell/v2/tty_plan9.go b/vendor/github.com/gdamore/tcell/v3/tty/tty_plan9.go similarity index 86% rename from vendor/github.com/gdamore/tcell/v2/tty_plan9.go rename to vendor/github.com/gdamore/tcell/v3/tty/tty_plan9.go index 6c99ee6d3..9b72c6b11 100644 --- a/vendor/github.com/gdamore/tcell/v2/tty_plan9.go +++ b/vendor/github.com/gdamore/tcell/v3/tty/tty_plan9.go @@ -4,8 +4,8 @@ // Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package tcell +package tty import ( "bufio" @@ -40,22 +40,20 @@ import ( // - vt(1): VT100 emulator typically used for TUI programs on Plan 9 // // Limitations: -// - We assume VT100-level capabilities (often no colors, no mouse). -// - Window size is conservative: we return 80x24 unless overridden. -// Set LINES/COLUMNS (or TCELL_LINES/TCELL_COLS) to refine. -// - Mouse and bracketed paste are not wired; terminfo/xterm queries -// are not attempted because vt(1) may not support them. +// - We assume VT100-level capabilities (often no colors, no mouse). +// - Window size is conservative: we return 80x24 unless overridden. +// Set LINES/COLUMNS (or TCELL_LINES/TCELL_COLS) to refine. +// - Mouse and bracketed paste are not wired; terminfo/xterm queries +// are not attempted because vt(1) may not support them. type p9Tty struct { cons *os.File // /dev/cons (read+write) consctl *os.File // /dev/consctl (write "rawon"/"rawoff") wctl *os.File // /dev/wctl (resize notifications) - // protect close/stop; Read/Write are serialized by os.File - mu sync.Mutex - closed atomic.Bool + closed atomic.Bool + started bool - // resize callback - onResize atomic.Value // func() + onResize atomic.Value // resize channel wg sync.WaitGroup stopCh chan struct{} } @@ -99,9 +97,10 @@ func newPlan9TTY() (Tty, error) { } func (t *p9Tty) Start() error { - t.mu.Lock() - defer t.mu.Unlock() + if t.started { + return nil + } if t.closed.Load() { return errors.New("tty closed") } @@ -127,6 +126,7 @@ func (t *p9Tty) Start() error { t.wg.Add(1) go t.watchResize() } + t.started = true return nil } @@ -137,8 +137,6 @@ func (t *p9Tty) Drain() error { } func (t *p9Tty) Stop() error { - t.mu.Lock() - defer t.mu.Unlock() // Signal watcher to stop (if not already). if t.stopCh != nil && !isClosed(t.stopCh) { @@ -156,12 +154,11 @@ func (t *p9Tty) Stop() error { // Ensure watcher goroutine has exited before returning. t.wg.Wait() + t.started = false return nil } func (t *p9Tty) Close() error { - t.mu.Lock() - defer t.mu.Unlock() if t.closed.Swap(true) { return nil @@ -191,12 +188,8 @@ func (t *p9Tty) Write(p []byte) (int, error) { return t.cons.Write(p) } -func (t *p9Tty) NotifyResize(cb func()) { - if cb == nil { - t.onResize.Store((func())(nil)) - return - } - t.onResize.Store(cb) +func (t *p9Tty) NotifyResize(resizeQ chan<- bool) { + t.onResize.Store(resizeQ) } func (t *p9Tty) WindowSize() (WindowSize, error) { @@ -244,8 +237,11 @@ func (t *p9Tty) watchResize() { } // transient errors: continue } - if cb, _ := t.onResize.Load().(func()); cb != nil { - cb() + if rq, ok := t.onResize.Load().(chan<- bool); ok && rq != nil { + select { + case rq <- true: + default: + } } } } diff --git a/vendor/github.com/gdamore/tcell/v2/tty_unix.go b/vendor/github.com/gdamore/tcell/v3/tty/tty_unix.go similarity index 58% rename from vendor/github.com/gdamore/tcell/v2/tty_unix.go rename to vendor/github.com/gdamore/tcell/v3/tty/tty_unix.go index ca82d83d8..e2dc49363 100644 --- a/vendor/github.com/gdamore/tcell/v2/tty_unix.go +++ b/vendor/github.com/gdamore/tcell/v3/tty/tty_unix.go @@ -1,8 +1,8 @@ -// Copyright 2021 The TCell Authors +// Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -15,7 +15,7 @@ //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos -package tcell +package tty import ( "errors" @@ -23,7 +23,6 @@ import ( "os" "os/signal" "strconv" - "sync" "syscall" "time" @@ -31,18 +30,17 @@ import ( "golang.org/x/term" ) +// Use -1 to differentiate from stdin (fd=0). +const uninitializedTtyFd = -1 + // devTty is an implementation of the Tty API based upon /dev/tty. type devTty struct { - fd int - f *os.File - of *os.File // the first open of /dev/tty - saved *term.State - sig chan os.Signal - cb func() - stopQ chan struct{} - dev string - wg sync.WaitGroup - l sync.Mutex + fd int + f *os.File + saved *term.State + sig chan os.Signal + dev string + started bool } func (tty *devTty) Read(b []byte) (int, error) { @@ -58,54 +56,43 @@ func (tty *devTty) Close() error { } func (tty *devTty) Start() error { - tty.l.Lock() - defer tty.l.Unlock() + if tty.started { + return nil + } // We open another copy of /dev/tty. This is a workaround for unusual behavior // observed in macOS, apparently caused when a subshell (for example) closes our // own tty device (when it exits for example). Getting a fresh new one seems to // resolve the problem. (We believe this is a bug in the macOS tty driver that // fails to account for dup() references to the same file before applying close() - // related behaviors to the tty.) We're also holding the original copy we opened - // since closing that might have deleterious effects as well. The upshot is that - // we will have up to two separate file handles open on /dev/tty. (Note that when - // using stdin/stdout instead of /dev/tty this problem is not observed.) + // related behaviors to the tty.) (Note that when using stdin/stdout instead of + // /dev/tty this problem is not observed.) var err error if tty.f, err = os.OpenFile(tty.dev, os.O_RDWR, 0); err != nil { return err } + tty.fd = int(tty.f.Fd()) + if !term.IsTerminal(tty.fd) { + tty.f.Close() return errors.New("device is not a terminal") } _ = tty.f.SetReadDeadline(time.Time{}) saved, err := term.MakeRaw(tty.fd) // also sets vMin and vTime if err != nil { + tty.f.Close() + return err + } + if err = tcFlushInput(tty.fd); err != nil { + _ = term.Restore(tty.fd, saved) + tty.f.Close() return err } tty.saved = saved + tty.started = true - tty.stopQ = make(chan struct{}) - tty.wg.Add(1) - go func(stopQ chan struct{}) { - defer tty.wg.Done() - for { - select { - case <-tty.sig: - tty.l.Lock() - cb := tty.cb - tty.l.Unlock() - if cb != nil { - cb() - } - case <-stopQ: - return - } - } - }(tty.stopQ) - - signal.Notify(tty.sig, syscall.SIGWINCH) return nil } @@ -118,28 +105,40 @@ func (tty *devTty) Drain() error { } func (tty *devTty) Stop() error { - tty.l.Lock() + // unconditionally set this, because we cannot recover + // if we fail anyway, so this gives the best hope of + // picking up the pieces in such a circumstance + tty.started = false + if err := term.Restore(tty.fd, tty.saved); err != nil { - tty.l.Unlock() return err } _ = tty.f.SetReadDeadline(time.Now()) - signal.Stop(tty.sig) - close(tty.stopQ) - tty.l.Unlock() - - tty.wg.Wait() + tty.NotifyResize(nil) // close our tty device -- we'll get another one if we Start again later. _ = tty.f.Close() + tty.fd = uninitializedTtyFd return nil } func (tty *devTty) WindowSize() (WindowSize, error) { size := WindowSize{} - ws, err := unix.IoctlGetWinsize(tty.fd, unix.TIOCGWINSZ) + fd := tty.fd + if tty.fd == uninitializedTtyFd { + // If WindowSize is called when the tty isn't yet running, the fd for /dev/tty won't be initialized, + // so open the file just long enough to retrieve the window size. + f, err := os.OpenFile(tty.dev, os.O_RDWR, 0) + if err != nil { + return size, err + } + defer func() { _ = f.Close() }() + fd = int(f.Fd()) + } + + ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) if err != nil { return size, err } @@ -164,10 +163,33 @@ func (tty *devTty) WindowSize() (WindowSize, error) { return size, nil } -func (tty *devTty) NotifyResize(cb func()) { - tty.l.Lock() - tty.cb = cb - tty.l.Unlock() +func (tty *devTty) NotifyResize(resizeQ chan<- bool) { + + sigQ := tty.sig + tty.sig = nil + + if sigQ != nil { + signal.Stop(sigQ) + close(sigQ) + } + + if resizeQ == nil { + return + } + + sigQ = make(chan os.Signal, 1) + signal.Notify(sigQ, syscall.SIGWINCH) + + tty.sig = sigQ + + go func() { + for range sigQ { + select { + case resizeQ <- true: + default: // queue full, so nvm. + } + } + }() } // NewDevTty opens a /dev/tty based Tty. @@ -178,21 +200,24 @@ func NewDevTty() (Tty, error) { // NewDevTtyFromDev opens a tty device given a path. This can be useful to bind to other nodes. func NewDevTtyFromDev(dev string) (Tty, error) { tty := &devTty{ + fd: uninitializedTtyFd, dev: dev, sig: make(chan os.Signal), } - var err error - if tty.of, err = os.OpenFile(dev, os.O_RDWR, 0); err != nil { + // Only open the file long enough to check that the device + // represents a TTY. We will reopen it in start. We do collect + // the terminal state so we can restore it later though. + if f, err := os.OpenFile(dev, os.O_RDWR, 0); err != nil { return nil, err - } - tty.fd = int(tty.of.Fd()) - if !term.IsTerminal(tty.fd) { - _ = tty.f.Close() - return nil, errors.New("not a terminal") - } - if tty.saved, err = term.GetState(tty.fd); err != nil { - _ = tty.f.Close() - return nil, fmt.Errorf("failed to get state: %w", err) + } else { + defer func() { _ = f.Close() }() + fd := int(f.Fd()) + if !term.IsTerminal(fd) { + return nil, errors.New("not a terminal") + } + if tty.saved, err = term.GetState(fd); err != nil { + return nil, fmt.Errorf("failed to get state: %w", err) + } } return tty, nil } diff --git a/vendor/github.com/gdamore/tcell/v3/tty/tty_wasm.go b/vendor/github.com/gdamore/tcell/v3/tty/tty_wasm.go new file mode 100644 index 000000000..cf4ad6e7c --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/tty/tty_wasm.go @@ -0,0 +1,21 @@ +//go:build wasm || js +// +build wasm js + +package tty + +import "errors" + +// NewDevTty obtains a default tty from the console or TTY (e.g. /dev/tty) for the process. +func NewDevTty() (Tty, error) { + return nil, errors.New("No tty device on wasm") +} + +// NewDevTtyFromDev obtains a tty from the given device path. Not supported on Windows. +func NewDevTtyFromDev(dev string) (Tty, error) { + return nil, errors.New("No tty device on wasm") +} + +// NewStdIoTty obtains a tty from stdin and stdout. +func NewStdIoTty() (Tty, error) { + return nil, errors.New("No tty device on wasm") +} diff --git a/vendor/github.com/gdamore/tcell/v2/tty_win.go b/vendor/github.com/gdamore/tcell/v3/tty/tty_win.go similarity index 78% rename from vendor/github.com/gdamore/tcell/v2/tty_win.go rename to vendor/github.com/gdamore/tcell/v3/tty/tty_win.go index 0a6d10bb3..2bf9769d1 100644 --- a/vendor/github.com/gdamore/tcell/v2/tty_win.go +++ b/vendor/github.com/gdamore/tcell/v3/tty/tty_win.go @@ -1,8 +1,8 @@ // Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -15,7 +15,7 @@ //go:build windows // +build windows -package tcell +package tty import ( "encoding/binary" @@ -51,6 +51,47 @@ const ( focusEvent uint16 = 16 ) +const ( + w32Infinite = ^uintptr(0) + w32WaitObject0 = uintptr(0) +) + +const ( + // Input modes + modeExtendFlg = uint32(0x0080) + modeMouseEn = uint32(0x0010) + modeResizeEn = uint32(0x0008) + modeVtInput = uint32(0x0200) + // modeCooked = uint32(0x0001) + + // Output modes + modeCookedOut = uint32(0x0001) + modeVtOutput = uint32(0x0004) + modeNoAutoNL = uint32(0x0008) + modeUnderline = uint32(0x0010) // ENABLE_LVB_GRID_WORLDWIDE, needed for underlines + // modeWrapEOL = uint32(0x0002) +) + +type coord struct { + x int16 + y int16 +} + +type rect struct { + left int16 + top int16 + right int16 + bottom int16 +} + +type consoleInfo struct { + size coord + pos coord + attrs uint16 + win rect + maxsz coord +} + type inputRecord struct { typ uint16 _ uint16 @@ -64,7 +105,7 @@ type winTty struct { cancelFlag syscall.Handle running bool stopQ chan struct{} - resizeCb func() + resizeQ chan<- bool cols uint16 rows uint16 pair []uint16 // for surrogate pairs (UTF-16) @@ -86,7 +127,6 @@ func (w *winTty) Read(b []byte) (int, error) { case <-w.stopQ: // stopping, so make sure we eat everything, which might require // very short sleeps to ensure all buffered data is consumed. - break } // second character read is non-blocking @@ -145,12 +185,11 @@ func (w *winTty) getConsoleInput() error { case w32WaitObject0: // w.cancelFlag return errors.New("cancelled") case w32WaitObject0 + 1: // w.in - // rec := &inputRecord{} var nrec int32 rv, _, er := procGetNumberOfConsoleInputEvents.Call( uintptr(w.in), uintptr(unsafe.Pointer(&nrec))) - rec := make([]inputRecord, nrec) + rec := make([]inputRecord, max(nrec, 1)) rv, _, er = procReadConsoleInput.Call( uintptr(w.in), uintptr(unsafe.Pointer(&rec[0])), @@ -189,11 +228,13 @@ func (w *winTty) getConsoleInput() error { w.Lock() w.cols = binary.LittleEndian.Uint16(ir.data[0:]) w.rows = binary.LittleEndian.Uint16(ir.data[2:]) - cb := w.resizeCb - w.Unlock() - if cb != nil { - cb() + if w.resizeQ != nil { + select { + case w.resizeQ <- true: + default: + } } + w.Unlock() default: } @@ -215,11 +256,8 @@ func (w *winTty) scanInput() { func (w *winTty) Start() error { - w.Lock() - defer w.Unlock() - if w.running { - return errors.New("already engaged") + return nil } _, _, _ = procFlushConsoleInputBuffer.Call(uintptr(w.in)) w.stopQ = make(chan struct{}) @@ -246,8 +284,6 @@ func (w *winTty) Start() error { func (w *winTty) Stop() error { w.wg.Wait() - w.Lock() - defer w.Unlock() _, _, _ = procSetConsoleMode.Call(uintptr(w.in), uintptr(w.oimode)) _, _, _ = procSetConsoleMode.Call(uintptr(w.out), uintptr(w.oomode)) _, _, _ = procFlushConsoleInputBuffer.Call(uintptr(w.in)) @@ -256,8 +292,10 @@ func (w *winTty) Stop() error { return nil } -func (w *winTty) NotifyResize(cb func()) { - w.resizeCb = cb +func (tty *winTty) NotifyResize(resizeQ chan<- bool) { + tty.Lock() + tty.resizeQ = resizeQ + tty.Unlock() } func (w *winTty) WindowSize() (WindowSize, error) { @@ -288,3 +326,26 @@ func NewDevTty() (Tty, error) { return w, nil } + +func NewDevTtyFromDev(dev string) (Tty, error) { + return nil, errors.New("No tty device on Windows") +} + +func NewStdIoTty() (Tty, error) { + w := &winTty{} + w.in = syscall.Stdin + w.out = syscall.Stdout + w.buf = make(chan byte, 128) + + _, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(w.out), uintptr(unsafe.Pointer(&w.oscreen))) + if r, _, err := procGetConsoleMode.Call(uintptr(w.out), uintptr(unsafe.Pointer(&w.oomode))); r == 0 || err != nil { + return nil, errors.New("output is not a terminal") + } + if r, _, err := procGetConsoleMode.Call(uintptr(w.in), uintptr(unsafe.Pointer(&w.oimode))); r == 0 || err != nil { + return nil, errors.New("input is not a terminal") + } + w.rows = uint16(w.oscreen.size.y) + w.cols = uint16(w.oscreen.size.x) + + return w, nil +} diff --git a/vendor/github.com/gdamore/tcell/v3/tty/winsize.go b/vendor/github.com/gdamore/tcell/v3/tty/winsize.go new file mode 100644 index 000000000..7950055fd --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/tty/winsize.go @@ -0,0 +1,31 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 tty + +// WindowSize represents the dimensions of the window of a terminal. +type WindowSize struct { + Width int // Width in characters + Height int // Height in characters + PixelWidth int // Width in pixels (zero if not available or known) + PixelHeight int // Height in pixels (zero if not available or known) +} + +// CellDimensions returns the dimensions of a single cell, in pixels +func (ws WindowSize) CellDimensions() (int, int) { + if ws.PixelWidth == 0 || ws.PixelHeight == 0 { + return 0, 0 + } + return (ws.PixelWidth / ws.Width), (ws.PixelHeight / ws.Height) +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/attr.go b/vendor/github.com/gdamore/tcell/v3/vt/attr.go new file mode 100644 index 000000000..4d2ed2898 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/attr.go @@ -0,0 +1,38 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +// Attr is a synthetic combination of display attributes for cells, apart +// from color which is handled separately. +type Attr uint16 + +const ( + Plain = Attr(0) // basic, plain style + Bold = Attr(1 << 0) // maybe double strike, or just brighter + Blink = Attr(1 << 1) // NB: many terminals do not support it + Reverse = Attr(1 << 2) // foreground and background reversed + Dim = Attr(1 << 3) // fainter, may also be lower alpha + Italic = Attr(1 << 4) // italicized + StrikeThrough = Attr(1 << 5) // crossed-out + Underline = Attr(1 << 6) // any underline style + Overline = Attr(1 << 7) // rarely supported + + // Underline styles, always mixed with underline, only one can be selected + PlainUnderline = Underline + DoubleUnderline = Underline | 1<<13 + CurlyUnderline = Underline | 2<<13 + DottedUnderline = Underline | 3<<13 + DashedUnderline = Underline | 4<<13 + UnderlineMask = Underline | 7<<13 // bits 13, 14, 15 +) diff --git a/vendor/github.com/gdamore/tcell/v3/vt/backend.go b/vendor/github.com/gdamore/tcell/v3/vt/backend.go new file mode 100644 index 000000000..f7f5624b6 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/backend.go @@ -0,0 +1,138 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +// Backend describes the backend of a terminal. +// This can be used to create a real emulator, while allowing the processor +// front end to handle the common details of parsing escape sequences, the state +// machine, and so forth. Backends support a limited set of common functionality, +// including a cursor. They only need to support writing at the cursor. +type Backend interface { + + // GetPrivateMode returns the status of a given private mode. + GetPrivateMode(PrivateMode) ModeStatus + + // SetPrivateMode sets a private mode to the given status. + // If either value is invalid, this should simply ignore the operation. + SetPrivateMode(PrivateMode, ModeStatus) error + + // GetSize returns the size of the terminal in characters. + // The X and Y are counts, so the bottom right cell should be at coordinate (X-1, Y-1). + GetSize() Coord + + // Colors returns the number of colors this terminal can support. For direct color, + // return 1<<24. The XTerm palette is assumed. Monochrome terminals should return 0. + Colors() int + + // Put content at the given location. The string in the cell might be a grapheme cluster, and the width can be + // 0, 1, or 2. The backend should try to optimize by keeping style and last coordinates if needed. + // A graphical backend could use this and be completely stateless. + Put(Coord, Cell) + + // GetPosition returns the cursor position. + GetPosition() Coord + + // SetPosition sets the cursor position. If the position is out of bounds, + // it should be clipped to the window size. + SetPosition(Coord) + + // Reset resets the terminal to default state. + Reset() + + // RaiseResize is called by the emulation layer when it has completed its own internal resizing. + // The backend is responsible for sending a signal (if needed) to child processes as part of this + // function. (The emulation layer knows nothing of child processes.) + RaiseResize() + + // Buffering is called by the emulator to indicate that the backend should buffer contents because + // multiple updates are taking place. This should be treated in addition to mode 2026, if the backend + // supports it. (Mode 2026 should only be supported by the backend if it actually supports true + // double buffering.) + Buffering(bool) + + // SetCursor is used to set the current cursor style. If the backend does not support changing + // the cursor shape, it should implement at least hidden, steady, and blinking (typically as a block). + SetCursor(CursorStyle) +} + +// Beeper can be implemented by a backend to indicate it can ring the bell or beep. +// This is typically done in response to a 0x07 bell. +type Beeper interface { + Beep() +} + +// Resizer adds notifications when the window size changes. +type Resizer interface { + // NotifyResize registers a channel to be posted to if the window size changes. + NotifyResize(chan<- bool) +} + +// Titler adds support for setting the window title. (Typically this is OSC 2.) +// Note that for security reasons we only support setting this. +// We don't bother with icon titles, since few terminal emulators support it, and it +// would be hard for us to do this in any portable fashion. +type Titler interface { + // SetWindowTitle only changes the window title. + SetWindowTitle(string) +} + +// MouseReporting determines what mouse events the backend reports. +type MouseReporting int + +const ( + MouseDisabled = MouseReporting(iota) // No mouse reports at all. + MouseButtons // Report button events only. + MouseDrag // Report drag events. + MouseMotion // Report motion events (movement). +) + +// Mouser adds support configuring mouse reporting. +// We also assume that a mouse reporter can report focus events. +type Mouser interface { + SetMouse(MouseReporting) +} + +// Blitter implements a cell-level blit, where a rectangular range of cells is copied from one +// location to another. The source and destination may overlap. The old locations will remain +// unchanged except of course or cells overwritten by the blit. The content will also be clipped +// to the visible dimensions. +type Blitter interface { + Blit(src, dst, dim Coord) +} + +// Clipboard implements a clipboard or copy buffer for copy/paste activity. +// The backend may prevent sending clipboard data by returning an empty string +// for the clipboard. Frequently this is done for security reasons. +type Clipboard interface { + + // SetClipboard sets the contents of the clipboard. + SetClipboard([]byte) + + // GetClipboard gets the contents of the clipboard. + // It will return nil if the operation is not supported. + // An empty clipboard will be []byte{} + GetClipboard() []byte +} + +// AdvancedKeyboard provides raw keyboard events, which gives +// access to key presses, and releases, physical keys, and so forth. +// These keyboards should provide a mapping facility to obtain associated +// Unicode text via a layout, as well. +type AdvancedKeyboard interface { + // IsAdvancedKeyboard returns true if the emulator supports full keyboard + // reporting. This must include key press and release events, and mapping + // of physical keys (thus permitting key disambiguation). + IsAdvancedKeyboard() bool +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/coord.go b/vendor/github.com/gdamore/tcell/v3/vt/coord.go new file mode 100644 index 000000000..a9ff7eda3 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/coord.go @@ -0,0 +1,31 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +// Separate Row and Col types are used to reduce the chance of mixing up the coordinate axes. +// We use zero-based coordinates (although VT hardware underneath uses one-based in escape sequences). +// The upper left corner of the screen is at coordinate (0, 0). + +// Row indicates a row number (y position). We use zero based indices, although the VT +// standard mostly communicates using 1-based offsets. +type Row int + +// Col indicates a column number (x position). We use zero based indices. +type Col int + +// Coord indicates a coordinate. This can also be used for window sizes. +type Coord struct { + X Col // Column number, or X position. + Y Row // Row number, or Y position. +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/cursor.go b/vendor/github.com/gdamore/tcell/v3/vt/cursor.go new file mode 100644 index 000000000..442b83e3a --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/cursor.go @@ -0,0 +1,54 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +// CursorStyle represents the style of cursor, and covers the shape, whether it +// blinks, and whether it is visible. Cursor color is handled separately, if at all. +type CursorStyle byte + +const ( + SteadyBlock = CursorStyle(iota) // The default + SteadyBar + SteadyUnderline + BlinkingBlock = SteadyBlock | blinkingCursor + BlinkingBar = SteadyBar | blinkingCursor + BlinkingUnderline = SteadyUnderline | blinkingCursor + + hiddenCursor = CursorStyle(1 << 7) // If set, cursor should be hidden + blinkingCursor = CursorStyle(1 << 6) // If set, cursor should blink +) + +func (cs CursorStyle) IsVisible() bool { + return cs&hiddenCursor == 0 +} + +func (cs CursorStyle) IsBlinking() bool { + return cs&blinkingCursor != 0 +} + +func (cs CursorStyle) Hide() CursorStyle { + return cs | hiddenCursor +} + +func (cs CursorStyle) Show() CursorStyle { + return cs &^ hiddenCursor +} + +func (cs CursorStyle) Blink() CursorStyle { + return cs | blinkingCursor +} + +func (cs CursorStyle) Steady() CursorStyle { + return cs &^ blinkingCursor +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/emulate.go b/vendor/github.com/gdamore/tcell/v3/vt/emulate.go new file mode 100644 index 000000000..b2dd2129b --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/emulate.go @@ -0,0 +1,2869 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "io" + "slices" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" + + "github.com/clipperhouse/uax29/v2/graphemes" + "github.com/gdamore/tcell/v3/color" +) + +// Emulator is a terminal emulator API. It implements the state machinery +// (escape parsing and so forth) associated with being a terminal emulator. +// The backend handles rendering the content, and some low level details. +// +// NOTE: This is not a committed interface yet, its entirely a work in progress. +type Emulator interface { + // SetId sets our identity. + SetId(name string, version string) + + // SendRaw sends raw data to the consumer. This bypasses the normal encoding, + // so it should be used with caution. + SendRaw([]byte) + + // KeyEvent injects a keyboard event into the emulator, which will ultimately + // result in data being sent via SendRaw. + KeyEvent(ev KeyEvent) + + // ResizeEvent is called by a backend when the terminal has resized + // This will send in-band resize notifications if the client has requested them. + ResizeEvent(Coord) + + // MouseEvent is called by a backend to report mouse activity. + MouseEvent(ev MouseEvent) + + // FocusEvent is called by a backend to report that focus is gained (true) or lost (false). + FocusEvent(bool) + + // Drain waits until any queued but not processed input has finished processing. + // It also wakes the reader. + Drain() error + + // Start starts processing. + Start() error + + // Stop stops processing. + Stop() error + + // Reader reads data from the emulator. These are bytes that would be transmitted + // to a remote party. + io.Reader + + // Writer writes data to the emulator. These are commands that the emulator should process. + io.Writer +} + +// Style represents the styling of a cell. +// This is an interface to prevent direct modification. +type Style interface { + Fg() color.Color // Fg returns the foreground color. + Bg() color.Color // Bg returns the background color. + Uc() color.Color // Uc returns the underline color.k + Attr() Attr // Attr returns the associated attributes. + Url() (string, string) // Url returns the URL and associated id if one was set. + WithFg(color.Color) Style // WithFg creates a new style with the foreground + WithBg(color.Color) Style // WithBg creates a new style with the background. + WithUc(color.Color) Style // WithUc creates a new style with the underline color + WithAttr(Attr) Style // WithAttr creates a new style with the attributes. + WithUrl(string, string) Style // WithLink creates a new style with the URL and id. + Equal(Style) bool // Equal returns true if the styles are the same. +} + +// styleStruct implements Style. Note that it is possible to make this even more +// compact, but we don't think further optimization here on size will justify the +// complexity and runtime performance hit to do so. We're also already only storing +// a class reference to this per cell. +type styleStruct struct { + fg color.Color + bg color.Color + uc color.Color // underline color + attr Attr + url string // URL + id string // Id for link +} + +var BaseStyle = &styleStruct{} + +var asciiRuneStrings = func() [utf8.RuneSelf]string { + var table [utf8.RuneSelf]string + for i := 0; i < utf8.RuneSelf; i++ { + table[i] = string(rune(i)) + } + return table +}() + +const ( + runeStringCacheSize = 32 + clusterStringCacheSize = 32 + clusterStringCacheMaxLen = 128 +) + +type runeStringCache struct { + entries [runeStringCacheSize]runeStringCacheEntry + n int +} + +type runeStringCacheEntry struct { + r rune + s string +} + +func (c *runeStringCache) stringFor(r rune) string { + for i := 0; i < c.n; i++ { + if c.entries[i].r == r { + return c.entries[i].s + } + } + + s := string(r) + n := c.n + if n < len(c.entries) { + n++ + } + copy(c.entries[1:n], c.entries[:n-1]) + c.entries[0] = runeStringCacheEntry{r: r, s: s} + c.n = n + return s +} + +type clusterStringCache struct { + entries [clusterStringCacheSize]clusterStringCacheEntry + n int +} + +type clusterStringCacheEntry struct { + n int + b [clusterStringCacheMaxLen]byte + s string +} + +func (c *clusterStringCache) stringFor(cluster []byte) string { + if len(cluster) == 0 { + return "" + } + if len(cluster) > clusterStringCacheMaxLen { + return string(cluster) + } + for i := 0; i < c.n; i++ { + e := &c.entries[i] + if e.n == len(cluster) && bytes.Equal(e.b[:e.n], cluster) { + return e.s + } + } + + s := string(cluster) + n := c.n + if n < len(c.entries) { + n++ + } + copy(c.entries[1:n], c.entries[:n-1]) + e := &c.entries[0] + e.n = len(cluster) + copy(e.b[:], cluster) + e.s = s + c.n = n + return s +} + +func (ss *styleStruct) Fg() color.Color { return ss.fg } +func (ss *styleStruct) Bg() color.Color { return ss.bg } +func (ss *styleStruct) Uc() color.Color { return ss.uc } +func (ss *styleStruct) Attr() Attr { return ss.attr } +func (ss *styleStruct) Url() (string, string) { return ss.url, ss.id } +func (ss *styleStruct) WithFg(fg color.Color) Style { ns := *ss; ns.fg = fg; return &ns } +func (ss *styleStruct) WithBg(bg color.Color) Style { ns := *ss; ns.bg = bg; return &ns } +func (ss *styleStruct) WithUc(uc color.Color) Style { ns := *ss; ns.uc = uc; return &ns } +func (ss *styleStruct) WithAttr(a Attr) Style { ns := *ss; ns.attr = a; return &ns } +func (ss *styleStruct) WithUrl(url, id string) Style { ns := *ss; ns.url = url; ns.id = id; return &ns } +func (ss *styleStruct) Equal(other Style) bool { + if s2, ok := other.(*styleStruct); ok { + return *ss == *s2 + } + // We have chosen not to support alternative implementations for this compare. + // We could delegate to the other style, but that could lead to a loop if they + // do the same. + return (false) +} + +// Cell is a representation of a display cell. Most consumers will not need this. +// Note, this is not the simplest possible representation, and a 256x256 cell +// display is going to need about 3MB to store it all, but it's simple, and adequate +// to retain pretty much all of what we need for Unicode. We could save some memory +// by using explicit struct pointers and by eliminating grapheme cluster support, +// but modern users expect these features. +type Cell struct { + C string // Content, it will be a grapheme cluster + S Style // Style, a pointer is used efficiency + W int // Display width (0, 1, or 2) +} + +// NewEmulator creates an emulator instance on top of the given backend. +// The input is relative to the emulator, so it receives data from the host, +// whereas the emulator sends data to the application through the output. +func NewEmulator(be Backend) Emulator { + stopQ := make(chan bool) + defStyle := BaseStyle.WithFg(color.Silver).WithBg(color.Black) + em := &emulator{ + be: be, + inBuf: &bytes.Buffer{}, + writeQ: make(chan any), + readQ: make(chan any, 1024), + stopQ: stopQ, + style: defStyle, + defaultStyle: defStyle, + ansiModes: map[AnsiMode]ModeStatus{ + AmNewLineMode: ModeOff, + }, + localModes: map[PrivateMode]ModeStatus{ + PmAppCursor: ModeOff, + PmAutoMargin: ModeOn, + PmAutoRepeat: ModeOn, + PmVT52: ModeOnLocked, // we never support VT52 mode (note ON means ANSI mode) + PmLeftRightMargin: ModeOff, + PmShowCursor: ModeOn, + PmBlinkCursor: ModeOn, + PmWin32Input: ModeOff, + }, + mouseReports: MouseDisabled, + } + if _, ok := be.(Resizer); ok { + em.localModes[PmResizeReports] = ModeOff + } + + // add mouse modes - we also add focus reporting mode + if _, ok := be.(Mouser); ok { + em.localModes[PmMouseX10] = ModeOff + em.localModes[PmMouseButton] = ModeOff + em.localModes[PmMouseDrag] = ModeOff + em.localModes[PmMouseMotion] = ModeOff + em.localModes[PmMouseSgr] = ModeOff + em.localModes[PmFocusReports] = ModeOff + } + + if ak, ok := be.(AdvancedKeyboard); ok && ak.IsAdvancedKeyboard() { + em.localModes[PmWin32Input] = ModeOff + } + + em.size = em.be.GetSize() + em.topMargin = 0 + em.botMargin = em.size.Y - 1 + em.ltMargin = 0 + em.rtMargin = em.size.X - 1 + em.cells = make([]Cell, int(em.size.X)*int(em.size.Y)) + em.graphemeIter = *graphemes.FromBytes(nil) + close(stopQ) + em.inb = em.inbInit + em.cursor = BlinkingBlock + em.be.SetCursor(em.cursor) + return em +} + +// emulator is an implementation of a terminal emulator built on top of +// a Backend. It implements the common escape sequence handling and high +// level functionality that a real terminal emulator, or a mock, would need. +type emulator struct { + stopQ chan bool + writeQ chan any // queues data from application to emulator + readQ chan any // queues data from emulator to application + be Backend + inBuf *bytes.Buffer // buffer queued for input + inb func(byte) // input byte function (faster than state switch) + style Style + defaultStyle Style + utfLen int + pos Coord + buffering uint // reference count - number of (re-entrant) buffering calls + autoWrap bool // next character will wrap (auto margin, deferred until char emitted) + sevenOnly bool // only allow 7-bit escapes (needed for KOI8, ShiftJIS, etc.) + appKeyPad bool // use application key pad keys? + name string // name of this emulator (used for extended attributes) + vers string // version string of this emulator (used for extended attributes) + saved savedCursor // data saved by save cursor (DECSC) + sendLock sync.Mutex // ensures that send data cannot be intermixed + modeLock sync.RWMutex // protects localModes/ansiModes and related derived state + tabStops []Col // tab stops, ordered. if nil every 8th position is used + lastIndex int // index of last cell written + 1 (for grapheme clustering) (zero means none) + graphemeBuf []byte // scratch buffer for grapheme clustering checks + graphemeIter graphemes.Iterator[[]byte] + runeStrings runeStringCache + clusterStrings clusterStringCache + cells []Cell // content of cells, we have to maintain our own copy (backend might or might not) + mouseReports MouseReporting // whether we have enabled mouse reports + size Coord // physical window size + topMargin Row // top margin, scrollable region includes this row + botMargin Row // bottom margin, scrollable region includes this row + ltMargin Col // left margin, scrollable region to the right + rtMargin Col // right margin, scrollable region to the left + cursor CursorStyle // current cursor style (visibility, blink, shape) + + localModes map[PrivateMode]ModeStatus // some modes we handle locally + ansiModes map[AnsiMode]ModeStatus // some modes we handle locally +} + +// savedCursor is the content we save when saving the cursor, +// which is more than just the cursor location itself. +type savedCursor struct { + pos Coord + style Style + autoWrap bool + // We should probably store OSC 8 data here, eventually. + // TODO: Character sets + // TODO: Origin mode (DEC Mode 6) +} + +func (em *emulator) saveCursor() { + em.saved.pos = em.getPosition() + em.saved.style = em.style + em.saved.autoWrap = em.autoWrap +} + +func (em *emulator) restoreCursor() { + em.setPosition(em.saved.pos) + em.autoWrap = em.saved.autoWrap + em.style = em.saved.style +} + +func (em *emulator) bufferingStart() { + em.buffering++ + if em.buffering == 1 { + em.be.Buffering(true) + } +} + +func (em *emulator) bufferingEnd() { + em.buffering-- + if em.buffering == 0 { + em.be.Buffering(false) + } +} + +// inbInit processes bytes received in the "default" state. Most often these are just +// text characters to display on screen, but if ESC is seen then additional processing will result. +func (em *emulator) inbInit(b byte) { + em.inBuf.Reset() + + // hot path - just doing ASCII directly. + if b >= ' ' && b < 0x7f { + // plain ascii + em.putRune(rune(b)) + return + } + + // For 8-bit encodings, we treat these as Fe sequences. + // Basically the same as ESC followed by (b - 0x40). + // TODO: condition this so that we do not do this if + // the encoding cannot support it (UTF, 8859, and EUC encodings + // are all fine here, but others like ShiftJIS or KOI8 might not be). + if b >= 0x80 && b <= 0x9F && !em.sevenOnly { + em.inbEsc(b - 0x40) + return + } + + // TODO: To support non-UTF-8 locales, include a check here for > 0x7F. Those locales + // might preclude 8-bit control sequences - 8859 character sets are fine, but e.g. KOI8, + // and ShiftJIS use values in those ranges. + + switch b { + case 0x1b: // ESC (escape) + em.inb = em.inbEsc + case 0x07: // BEL (bell) + em.beep() + case 0x08: // BS (backspace) + em.moveLeft() + case 0x09: // horizontal tab + em.nextTab() + case 0x0a, 0x0b, 0x0c: // LF (line feed), VF, FF + em.processLineFeed() + case 0x0d: // CR (carriage return) + em.processCarriageReturn() + case 0x0e: // TODO: SO + em.lastIndex = 0 + case 0x0f: // TODO: SI + em.lastIndex = 0 + case 0x18: //TODO Cancel (reset parser) + em.lastIndex = 0 + default: + // TODO: consider separating Unicode from other 8-bit character sets + if b&0xE0 == 0xC0 { + em.utfLen = 2 + em.inb = em.inbUTF + em.inBuf.WriteByte(b) + } else if b&0xF0 == 0xE0 { + em.utfLen = 3 + em.inb = em.inbUTF + em.inBuf.WriteByte(b) + } else if b&0xF8 == 0xF0 { + em.utfLen = 4 + em.inb = em.inbUTF + em.inBuf.WriteByte(b) + } else { + em.lastIndex = 0 + em.beep() + } + } +} + +// inbEsc processes the next byte after an escape character is seen. +func (em *emulator) inbEsc(b byte) { + + // By default, reset to init state. Other states will be set explicitly as needed. + em.inb = em.inbInit + em.lastIndex = 0 + + switch b { + case '[': + em.inb = em.inbCSI + case ']': + em.inb = em.inbOSC + case ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/': + // 0x20 - 0x2F -- usually followed by just one terminating character, but could include others + em.inb = em.inbNF + em.inBuf.WriteByte(b) + case '^': // privacy message (PM) + em.inb = em.inbStr + case '_': // application program command (APC) + em.inb = em.inbStr + case '=': + em.appKeyPad = true + case '>': + em.appKeyPad = false + case 'D': // down one line (IND) + em.processIndex() + case 'E': // next line (NEL) + em.nextLine() + case 'H': // set tab stop (HTS) - VT52 is go home, but we do not support VT52 + em.setTabStop(em.getPosition().X) + case 'M': // up one line (RI) + em.processReverseIndex() + case 'N': // single shift two (SS2) (TODO) + case 'O': // single shift three (SS3) (TODO) + case 'P': + em.inb = em.inbStr // device control string (DCS) (TODO) + case 'X': // start of string (SOS) + em.inb = em.inbStr + case 'Z': // DECID, obsolete form to get primary DA + em.sendDA() + case 'c': // RIS, soft reset + em.softReset() + case '6': // back index (DECBI, VT420, not widely supported) + em.moveLeft() + case '7': // save cursor (DECSC, VT100) + em.saveCursor() + case '8': // restore cursor (DECRC, VT100) + em.restoreCursor() + case '9': // forward index (DECFI, VT420, not widely supported) + em.moveRight() + default: + // ESC-V and ESC-W are for guarded area (TODO) + em.inb = em.inbInit + } +} + +// inbNF processes bytes that are part of an "nF" sequence (see ECMA-48). +func (em *emulator) inbNF(b byte) { + if b >= 0x20 && b <= 0x2F { + em.inBuf.WriteByte(b) + return + } + if b < 0x20 || b > 0x7E { // not a valid sequence + em.beep() + em.inb = em.inbInit + return + } + em.inBuf.WriteByte(b) + em.inb = em.inbInit + switch em.inBuf.String() { + case "#8": // DECALN - fill screen with 'E' + size := em.size + em.autoWrap = false + em.topMargin = 0 + em.botMargin = em.size.Y - 1 + em.ltMargin = 0 + em.rtMargin = em.size.X - 1 + em.setPosition(Coord{0, 0}) + em.style = em.style.WithAttr(Plain) + // TODO: Reset DECOM (when we implement origin mode) + for row := range size.Y { + ix := em.index(Coord{X: 0, Y: row}) + for col := range size.X { + em.cells[ix].S = em.style + em.cells[ix].C = "E" + em.cells[ix].W = 1 + em.be.Put(Coord{X: col, Y: row}, em.cells[ix]) + ix++ + } + } + // most implementations leave the cursor at home for this + em.setPosition(Coord{0, 0}) + + // case "%@": // TODO: select 8859-1 + // case "%G": // TODO: select UTF-8 + // case "(A": // TODO: select G0 as UK + // case "(B": // TODO: select G0 as US + // case "(C", "(5": // TODO: select G0 as Finnish + // case "(H", "(7": // TODO: select G0 as Swedish + // case "(K": // TODO: select G0 as German + // case "(Q", "(9": // TODO: select G0 as French Canadian + // case "(R", "(f": // TODO: select G0 as French + // case "(Y": // TODO: select G0 as Italian + } +} + +// inbCSI handles bytes that are part of a CSI based sequence. +func (em *emulator) inbCSI(b byte) { + if (b >= 0x30) && (b <= 0x3F) { + em.inBuf.WriteByte(b) // parameter bytes + } else if (b >= 0x20) && (b <= 0x2F) { + em.inBuf.WriteByte(b) // intermediate bytes + } else if b >= 0x40 && (b <= 0x7F) { + em.inb = em.inbInit + em.processCsi(b) + } else { + // error state + em.beep() + em.inb = em.inbInit + } +} + +// inbOSC handles bytes that are part of on OSC sequences (operating system command). +func (em *emulator) inbOSC(b byte) { + switch b { + case 0x9c, 0x07: + em.inb = em.inbInit + em.processOSC() + case '\\': + if buf := em.inBuf.Bytes(); len(buf) > 0 && buf[len(buf)-1] == 0x1b { + em.inb = em.inbInit + em.inBuf.Truncate(em.inBuf.Len() - 1) + em.processOSC() + } else { + em.inBuf.WriteByte(b) + } + default: + em.inBuf.WriteByte(b) + } +} + +// inbStr handles PM, SOS, and any other string we want to consume and discard. +func (em *emulator) inbStr(b byte) { + switch b { + case 0x9c, 0x07: + em.inb = em.inbInit + case '\\': + if buf := em.inBuf.Bytes(); len(buf) > 0 && buf[len(buf)-1] == 0x1b { + em.inb = em.inbInit + em.inBuf.Truncate(em.inBuf.Len() - 1) + } else { + em.inBuf.WriteByte(b) + } + default: + em.inBuf.WriteByte(b) + } +} + +// inbUTF handles continuation bytes for UTF-8 sequences. +func (em *emulator) inbUTF(b byte) { + if b&0xC0 == 0x80 { + // good continuation byte + em.inBuf.WriteByte(b) + if em.inBuf.Len() == em.utfLen { + em.inb = em.inbInit + r, _, err := em.inBuf.ReadRune() + if err != nil { + em.beep() + } else { + em.putRune(r) + } + } + } else { + em.beep() + em.inb = em.inbInit + } +} + +func (em *emulator) beep() { + if beeper, ok := em.be.(Beeper); ok { + beeper.Beep() + } +} + +// numericParams splits the string consisting of numeric parameters into integers. +// It ensures a minimum number are present (needed for some safety cases). +// Empty strings default to zero. +func numericParams(str string, minimumLen int) ([]int, error) { + ps := strings.Split(str, ";") + pi := make([]int, max(len(ps), minimumLen)) + for i, str := range ps { + if str != "" { + if iv, err := strconv.Atoi(str); err != nil { + return nil, err + } else { + pi[i] = iv + } + } + } + return pi, nil +} + +// parseSgrColor grabs either 2 arguments, or 4 arguments for palette or rgb values +// used with SGR 38 and 48. The arguments must be numbers, and are returned as such. +func (em *emulator) parseSgrColor(args []string, words []string) (color.Color, []string, error) { + if len(args) == 0 { + if len(words) == 0 { + return color.None, nil, errors.New("invalid color specification") + } + + switch words[0] { + case "2": // RGB (direct) + if len(words) < 4 { + return color.None, nil, errors.New("invalid color specification") + } + args = words[:4] + words = words[4:] + case "5": // palette index + if len(words) < 2 { + return color.None, nil, errors.New("invalid color specification") + } + args = words[:2] + words = words[2:] + default: + return color.None, nil, errors.New("invalid color specification") + } + } + + switch args[0] { + case "2": // RGB color + if len(args) < 4 || em.be.Colors() <= 256 { + return color.None, nil, errors.New("invalid color specification") + } + r, re := strconv.Atoi(args[1]) + g, ge := strconv.Atoi(args[2]) + b, be := strconv.Atoi(args[3]) + if re != nil || ge != nil || be != nil || r > 255 || g > 255 || b > 255 || r < 0 || g < 0 || b < 0 { + return color.None, nil, errors.New("invalid color specification") + } + return color.NewRGBColor(int32(r), int32(g), int32(b)), words, nil + case "5": // palette index + if len(args) < 2 { + return color.None, nil, errors.New("invalid color specification") + } + p, e := strconv.Atoi(args[1]) + if e != nil || p < 0 || p >= em.be.Colors() { + return color.None, nil, errors.New("invalid color specification") + } + return color.IsValid | color.Color(p&0xff), words, nil + } + + return color.None, nil, errors.New("invalid color specification") +} + +func (em *emulator) pickColor(c color.Color, def color.Color) (color.Color, bool) { + numColors := em.be.Colors() + if numColors == 0 { + return color.None, false + } + if c.Valid() { + if c.IsRGB() { + if numColors > 256 { + return c, true + } + } + if (int(c) & 255) < numColors { + return c, true + } + } + if c == color.Reset { + return def, true + } + return color.None, false +} + +// processSgr processes SGR commands (things that change how characters are displayed). +func (em *emulator) processSgr(str string) { + words := strings.Split(str, ";") + + // technically parameters for 38 or 48 should be separated by colons, but due to historical + // accident it is more common to see semicolon separation. Underline styles are also separated + // by a colon, if present. + if len(words) == 0 { + words = []string{"0"} + } + for len(words) > 0 { + // we do this instead of a range so we can lop off + // multiple words for SGR38 and 48. + word := words[0] + words = words[1:] + + if word == "" { + word = "0" + } + args := []string(nil) + if strings.Contains(word, ":") { + args = strings.Split(word, ":") + word = args[0] + args = args[1:] + } + + v, err := strconv.Atoi(word) + if err != nil { + // just swallow it for now + return + } + switch v { + case 0: + em.style = em.defaultStyle + case 1: + em.style = em.style.WithAttr((em.style.Attr() &^ Dim) | Bold) + case 2: + em.style = em.style.WithAttr((em.style.Attr() &^ Bold) | Dim) + case 3: + em.style = em.style.WithAttr(em.style.Attr() | Italic) + case 4: + em.style = em.style.WithAttr((em.style.Attr() &^ UnderlineMask) | Underline) + + if len(args) > 0 { + switch args[0] { + case "2": + em.style = em.style.WithAttr(em.style.Attr() | DoubleUnderline) + case "3": + em.style = em.style.WithAttr(em.style.Attr() | CurlyUnderline) + case "4": + em.style = em.style.WithAttr(em.style.Attr() | DottedUnderline) + case "5": + em.style = em.style.WithAttr(em.style.Attr() | DashedUnderline) + } + } + case 5, 6: + em.style = em.style.WithAttr(em.style.Attr() | Blink) + case 7: + em.style = em.style.WithAttr(em.style.Attr() | Reverse) + case 8: // ignore, its for invisible + case 9: + em.style = em.style.WithAttr(em.style.Attr() | StrikeThrough) + case 21: // Doubly underlined, per ECMA + em.style = em.style.WithAttr((em.style.Attr() &^ UnderlineMask) | DoubleUnderline) + case 22: + em.style = em.style.WithAttr(em.style.Attr() &^ (Bold | Dim)) + case 23: + em.style = em.style.WithAttr(em.style.Attr() &^ Italic) + case 24: + em.style = em.style.WithAttr(em.style.Attr() &^ UnderlineMask) + case 25: + em.style = em.style.WithAttr(em.style.Attr() &^ Blink) + case 27: + em.style = em.style.WithAttr(em.style.Attr() &^ Reverse) + case 29: + em.style = em.style.WithAttr(em.style.Attr() &^ StrikeThrough) + + case 30, 31, 32, 33, 34, 35, 36, 37: // simple foreground colors + if c, ok := em.pickColor(color.Black+color.Color(v-30), em.defaultStyle.Fg()); ok { + em.style = em.style.WithFg(c) + } + case 38: + if c, rest, err := em.parseSgrColor(args, words); err == nil { + words = rest + em.style = em.style.WithFg(c) + } + case 39: + if c, ok := em.pickColor(color.Reset, em.defaultStyle.Fg()); ok { + em.style = em.style.WithFg(c) + } + case 40, 41, 42, 43, 44, 45, 46, 47: // simple background colors + if c, ok := em.pickColor(color.Black+color.Color(v-40), em.defaultStyle.Bg()); ok { + em.style = em.style.WithBg(c) + } + case 48: + if c, rest, err := em.parseSgrColor(args, words); err == nil { + words = rest + em.style = em.style.WithBg(c) + } + case 49: + if c, ok := em.pickColor(color.Reset, em.defaultStyle.Bg()); ok { + em.style = em.style.WithBg(c) + } + case 53: + em.style = em.style.WithAttr(em.style.Attr() | Overline) + case 55: + em.style = em.style.WithAttr(em.style.Attr() &^ Overline) + case 58: + if c, rest, err := em.parseSgrColor(args, words); err == nil { + words = rest + em.style = em.style.WithUc(c) + } + } + } +} + +// processCursorUp implements CUU. +func (em *emulator) processCursorUp(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + em.moveUpN(Row(max(1, pi[0]))) + } +} + +// processCursorDown implements CUD. +func (em *emulator) processCursorDown(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + em.moveDownN(Row(max(1, pi[0]))) + } +} + +// processCursorForward implements CUF. +func (em *emulator) processCursorForward(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + em.moveRightN(Col(max(1, pi[0]))) + } +} + +// processCursorBackward implements CUB. +func (em *emulator) processCursorBackward(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + em.moveLeftN(Col(max(1, pi[0]))) + } +} + +// processCursorNextLine implements CNL. +func (em *emulator) processCursorNextLine(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + em.moveDownN(Row(max(1, pi[0]))) + pos := em.getPosition() + pos.X = 0 + em.setPosition(pos) + } +} + +// processCursorPreviousLine implements CPL. +func (em *emulator) processCursorPreviousLine(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + em.moveUpN(Row(max(1, pi[0]))) + pos := em.getPosition() + pos.X = 0 + em.setPosition(pos) + } +} + +// processCursorColumn implements CHA. +func (em *emulator) processCursorColumn(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + pos := em.getPosition() + // TODO: possibly clip to margins (origin mode) + pos.X = min(Col(max(1, pi[0])), em.size.X) - 1 + em.setPosition(pos) + } +} + +// processCursorPosition implements CUP, and also HVP. +func (em *emulator) processCursorPosition(str string) { + if pi, err := numericParams(str, 2); err == nil { + em.autoWrap = false + pos := em.getPosition() + wsz := em.size + row := Row(max(1, pi[0])) + col := Col(max(1, pi[1])) + row = max(1, min(row, wsz.Y)) + col = max(1, min(col, wsz.X)) + pos.X = col - 1 + pos.Y = row - 1 + em.setPosition(pos) + } +} + +// processCursorTab implements CHT. +func (em *emulator) processCursorTab(str string) { + if pi, err := numericParams(str, 1); err == nil { + // Note: tab does not clear this field. + for range max(1, pi[0]) { + em.nextTab() + } + } +} + +// processCursorBackTab implements CBT. +func (em *emulator) processCursorBackTab(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + for range max(1, pi[0]) { + em.prevTab() + } + } +} + +// processEraseDisplay implements ED. +func (em *emulator) processEraseDisplay(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.bufferingStart() + defer em.bufferingEnd() + + switch pi[0] { + case 0: // erase below + em.eraseBelow() + case 1: // erase above + em.eraseAbove() + case 2: // erase all + em.eraseAll() + // others not supported (3 is erase saved lines) + } + } +} + +// processEraseLine implements EL. +func (em *emulator) processEraseLine(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.bufferingStart() + defer em.bufferingEnd() + + switch pi[0] { + case 0: + em.eraseToLineEnd() + case 1: + em.eraseToLineStart() + case 2: + em.eraseLine() + } + } +} + +// processEraseCharacter implements ECH. +// This ignores the margin. +func (em *emulator) processEraseCharacter(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + pos := em.pos + // TODO: delete wide character if we are splitting it at the start + em.bufferingStart() + defer em.bufferingEnd() + for range max(1, pi[0]) { + + em.eraseCell(pos) + pos.X++ + if pos.X >= em.size.X { + break + } + } + } +} + +// processScrollUp implements SU (VT420.) +func (em *emulator) processScrollUp(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.bufferingStart() + defer em.bufferingEnd() + for range max(pi[0], 1) { + // TODO: consider faster jump scroll. + // This should be something tunable as well. + em.scrollUp() + } + } +} + +// processScrollDown implements SD (VT420.) +func (em *emulator) processScrollDown(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.bufferingStart() + defer em.bufferingEnd() + for range max(pi[0], 1) { + // TODO: consider faster jump scroll. + // This should be something tunable as well. + em.scrollDown() + } + } +} + +// processWindowOps handles CSI ... t window operations. +func (em *emulator) processWindowOps(str string) { + if pi, err := numericParams(str, 3); err == nil { + switch pi[0] { + case 8: // Resize window: CSI 8 ; rows ; cols t + rows := pi[1] + cols := pi[2] + if rows < 1 || cols < 1 { + return + } + size := Coord{X: Col(cols), Y: Row(rows)} + if ws, ok := em.be.(interface{ SetSize(Coord) }); ok { + ws.SetSize(size) + em.applyResize(size) + } + + case 18: // Report text area size: CSI 8 ; rows ; cols t + em.SendRaw(fmt.Appendf(nil, "\x1b[8;%d;%dt", em.size.Y, em.size.X)) + } + } +} + +// processVerticalMargins implements DECSTBM (set top and bottom margins, VT220.) +func (em *emulator) processVerticalMargins(str string) { + if pi, err := numericParams(str, 2); err == nil { + pi[0] = max(1, pi[0]) + if pi[1] == 0 { + pi[1] = int(em.size.Y) + } + pi[0]-- + pi[1]-- + + top := min(Row(pi[0]), em.size.Y-1) + bot := min(Row(pi[1]), em.size.Y-1) + + // no change if values are out of range + if bot > top { + em.topMargin = top + em.botMargin = bot + em.setPosition(Coord{X: 0, Y: 0}) + } + } +} + +// processHorizontalMargins implements DECSLRM (set left and right margins, VT400.) +// It only works if Private Mode 69 (Left and Right margins) +func (em *emulator) processHorizontalMargins(str string) { + if em.getPrivateMode(PmLeftRightMargin) != ModeOn { + // For compat with SCO and ANSI.SYS. + if str == "" { + em.saveCursor() + } + return + } + if pi, err := numericParams(str, 2); err == nil { + pi[0] = max(1, pi[0]) + if pi[1] == 0 { + pi[1] = int(em.size.X) + } + pi[0]-- + pi[1]-- + + lm := min(Col(pi[0]), em.size.X-1) + rm := min(Col(pi[1]), em.size.X-1) + + // no change if values are out of range + if rm > lm { + em.rtMargin = rm + em.ltMargin = lm + em.setPosition(Coord{X: 0, Y: 0}) + } + } +} + +// processIndex moves down, unless already on the bottom margin, in which case it scrolls Up. +func (em *emulator) processIndex() { + pos := em.getPosition() + em.autoWrap = false + if pos.Y == em.botMargin && em.ltMargin <= pos.X && pos.X <= em.rtMargin { + em.scrollUp() + } else { + em.processCursorDown("") + } +} + +// processCarriageReturn handle CR. +func (em *emulator) processCarriageReturn() { + em.lastIndex = 0 + em.setPosition(Coord{0, em.getPosition().Y}) +} + +// processLineFeed is like IND, but if ANSI mode 20 is set, then a CR is appended as well. +func (em *emulator) processLineFeed() { + em.lastIndex = 0 + em.processIndex() + if em.getAnsiMode(AmNewLineMode) == ModeOn { + em.processCarriageReturn() + } +} + +// processReverseIndex moves up, unless already on the top margin, in which case it scrolls down. +func (em *emulator) processReverseIndex() { + pos := em.getPosition() + if pos.Y == em.topMargin { + em.scrollDown() + } else { + em.processCursorUp("") + } +} + +// processCursorRow implements VPA (set vertical position absolute) +func (em *emulator) processCursorRow(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + pos := em.getPosition() + pos.Y = min(Row(max(1, pi[0])), em.size.Y) - 1 + em.setPosition(pos) + } +} + +// processCursorRowAdvance implements VPR (vertical position relative). +func (em *emulator) processCursorRowAdvance(str string) { + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + pos := em.getPosition() + pos.Y = min(pos.Y+Row(max(1, pi[0])), em.size.Y-1) + em.setPosition(pos) + } +} + +// processInsertLine implements IL. +func (em *emulator) processInsertLine(str string) { + // insert line only takes effect within the scrolling region + if em.pos.X < em.ltMargin || em.pos.X > em.rtMargin || + em.pos.Y < em.topMargin || em.pos.Y > em.botMargin { + return + } + + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + num := Row(max(1, pi[0])) + num = min(num, em.botMargin-em.pos.Y+1) + + // process as a scroll down at our position. + top := em.topMargin + em.topMargin = em.pos.Y + for range num { + em.scrollDown() + } + em.topMargin = top + em.pos.X = 0 + em.setPosition(em.pos) + } +} + +// processDeleteLine implements DL. +func (em *emulator) processDeleteLine(str string) { + // delete line only takes effect within the scrolling region + if em.pos.X < em.ltMargin || em.pos.X > em.rtMargin || + em.pos.Y < em.topMargin || em.pos.Y > em.botMargin { + return + } + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + num := Row(max(1, pi[0])) + num = min(num, em.botMargin-em.pos.Y+1) + if num < 1 { + return + } + // process as a scroll up at our position. + top := em.topMargin + em.topMargin = em.pos.Y + for range num { + em.scrollUp() + } + em.topMargin = top + em.pos.X = 0 + em.setPosition(em.pos) + } +} + +// processDeleteCharacter implements DCH. +func (em *emulator) processDeleteCharacter(str string) { + // only takes effect within the scrolling region + if em.pos.X < em.ltMargin || em.pos.X > em.rtMargin || + em.pos.Y < em.topMargin || em.pos.Y > em.botMargin { + return + } + em.bufferingStart() + defer em.bufferingEnd() + + if pi, err := numericParams(str, 1); err == nil { + em.autoWrap = false + num := Col(max(1, pi[0])) + num = min(num, em.rtMargin-em.pos.X+1) + if num < 1 { + return + } + // this is essentially a one line scroll left + pos := em.pos + + // if we are breaking a wide rune, delete it (but preserve style) + if em.pos.X > 0 { + if ix := em.index(em.pos); em.cells[ix-1].W > 1 { + em.cells[ix-1].C = "" + em.cells[ix-1].W = 0 + em.be.Put(Coord{X: em.pos.X - 1, Y: em.pos.Y}, em.cells[ix-1]) + } + } + + for range num { + src := Coord{X: em.pos.X + 1, Y: em.pos.Y} + dst := Coord{X: em.pos.X, Y: em.pos.Y} + dim := Coord{X: em.rtMargin - em.pos.X, Y: 1} + em.blit(src, dst, dim) + em.eraseCell(Coord{X: em.rtMargin, Y: em.pos.Y}) + } + em.pos = pos + em.setPosition(em.pos) + } +} + +// processInsertCharacter implements ICH. +func (em *emulator) processInsertCharacter(str string) { + em.autoWrap = false + // only takes effect within the scrolling region -- HOWEVER, + // ICH still resets auto-wrap in this case, unlike DCH. + if em.pos.X < em.ltMargin || em.pos.X > em.rtMargin || + em.pos.Y < em.topMargin || em.pos.Y > em.botMargin { + return + } + em.bufferingStart() + defer em.bufferingEnd() + if pi, err := numericParams(str, 1); err == nil { + num := Col(max(1, pi[0])) + num = min(num, em.rtMargin-em.pos.X+1) + if num < 1 { + return + } + + // this is essentially a one line scroll right + pos := em.pos + + // if we are breaking a wide rune, delete it + if em.pos.X > 0 { + if ix := em.index(em.pos); em.cells[ix-1].W > 1 { + em.cells[ix-1].C = "" + em.cells[ix-1].W = 0 + em.be.Put(Coord{X: em.pos.X - 1, Y: em.pos.Y}, em.cells[ix-1]) + } + } + + for range num { + src := Coord{X: em.pos.X, Y: em.pos.Y} + dst := Coord{X: em.pos.X + 1, Y: em.pos.Y} + dim := Coord{X: em.rtMargin - em.pos.X, Y: 1} + em.blit(src, dst, dim) + ix := em.index(Coord{X: em.pos.X, Y: em.pos.Y}) + em.cells[ix].C = "" + em.cells[ix].W = 0 + em.cells[ix].S = em.style + // NB: We don't use eraseCell, because we need to preserve attributes. + em.be.Put(Coord{X: em.pos.X, Y: em.pos.Y}, em.cells[ix]) + } + + // if we clipped off the end of a wide character, then delete it. + if ix := em.index(Coord{X: em.rtMargin, Y: em.pos.Y}); em.cells[ix].W > 1 { + em.cells[ix].C = "" + em.cells[ix].W = 0 + em.be.Put(Coord{X: em.rtMargin, Y: em.pos.Y}, em.cells[ix]) + } + + em.pos = pos + em.setPosition(em.pos) + } +} + +// processSetMode implements SM (set ANSI mode). +func (em *emulator) processSetMode(str string) { + if pi, err := numericParams(str, 1); err == nil { + for _, pm := range pi { + em.setAnsiMode(AnsiMode(pm), ModeOn) + } + } +} + +// processResetMode implements RM (reset ANSI mode). +func (em *emulator) processResetMode(str string) { + if pi, err := numericParams(str, 1); err == nil { + for _, pm := range pi { + em.setAnsiMode(AnsiMode(pm), ModeOff) + } + } +} + +// processRequestMode implements DECRQM for ANSI modes. +// Only a single numeric parameter (mode number) can be supplied (VT300+) +func (em *emulator) processRequestMode(str string) { + if m, err := strconv.Atoi(str); err == nil { + am := AnsiMode(m) + status := em.getAnsiMode(am) + em.SendRaw([]byte(am.Reply(status))) + } +} + +// processSetPrivateMode implements DECSET (set private mode). +func (em *emulator) processSetPrivateMode(str string) { + if pi, err := numericParams(str, 1); err == nil { + for _, pm := range pi { + em.setPrivateMode(PrivateMode(pm), ModeOn) + } + } +} + +// processResetPrivateMode implements DECRST (reset private mode). +func (em *emulator) processResetPrivateMode(str string) { + if pi, err := numericParams(str, 1); err == nil { + for _, pm := range pi { + em.setPrivateMode(PrivateMode(pm), ModeOff) + } + } +} + +// processRequestPrivateMode implements DECRQM for private modes. +// Only a single numeric parameter (mode number) can be supplied (VT300+) +func (em *emulator) processRequestPrivateMode(str string) { + if m, err := strconv.Atoi(str); err == nil { + pm := PrivateMode(m) + status := em.getPrivateMode(pm) + em.SendRaw([]byte(pm.Reply(status))) + } +} + +// processTabReset implements DECST8C (set tab stops to every 8 chars) +func (em *emulator) processTabReset(str string) { + if pi, err := numericParams(str, 1); err == nil && pi[0] == 5 { + em.tabStops = nil + } +} + +// processTabClear implements TBC (clear horizontal tab). +func (em *emulator) processTabClear(str string) { + if pi, err := numericParams(str, 1); err == nil { + switch pi[0] { + case 0: // clear stop at current column + em.clrTabStop(em.getPosition().X) + case 3: // clear all columns + em.tabStops = []Col{} // this is distinct from nil + } + } +} + +// processPrimaryAttributes implements send DA. +func (em *emulator) processPrimaryAttributes(str string) { + if pi, err := numericParams(str, 1); err == nil && pi[0] == 0 { + em.sendDA() + } +} + +// processExtendedAttributes implements XTVERSION (send terminal name and version). +func (em *emulator) processExtendedAttributes(str string) { + if pi, err := numericParams(str, 1); err == nil && pi[0] == 0 && em.name != "" { + em.SendRaw(fmt.Appendf(nil, "\x1bP>|%s %s\x1b\\", em.name, em.vers)) + } +} + +// processCursorStyle implements DECSCUSR (set cursor style). +func (em *emulator) processCursorStyle(str string) { + // get previous visibility state, as we don't change it with this call. + visible := em.cursor.IsVisible() + if pi, err := numericParams(str, 1); err == nil { + switch pi[0] { + case 0, 1: + em.cursor = BlinkingBlock + case 2: + em.cursor = SteadyBlock + case 3: + em.cursor = BlinkingUnderline + case 4: + em.cursor = SteadyUnderline + case 5: + em.cursor = BlinkingBar + case 6: + em.cursor = SteadyBar + } + if !visible { + em.cursor = em.cursor.Hide() + } + em.be.SetCursor(em.cursor) + } +} + +// processCsi processes CSI sequences. +func (em *emulator) processCsi(final byte) { + + // CSI sequences are supported in several different possible ways: + // parameters may have a prefix character that is not numeric, typically + // indicating a whole different mode of operation than the final byte. + // There may also be intermediate bytes, but we only look for one, because + // the use cases we have this are that only a single intermediate byte is + // sometimes used to affect function. (E.g. $ in some cases.) + cmd := "" + if em.inBuf.Len() > 0 { + if b := em.inBuf.Bytes()[0]; b > '9' && b <= '?' { + cmd += string(b) + em.inBuf.ReadByte() + } + } + if l := em.inBuf.Len(); l > 0 { + if b := em.inBuf.Bytes()[l-1]; b >= 0x20 && b <= 0x2F { + cmd += string(b) + em.inBuf.Truncate(l - 1) + } + } + cmd += string(final) + + str := em.inBuf.String() + switch cmd { + + case "@": + em.processInsertCharacter(str) + case "A": + em.processCursorUp(str) + case "B": + em.processCursorDown(str) + case "C": + em.processCursorForward(str) + case "D": + em.processCursorBackward(str) + case "E": + em.processCursorNextLine(str) + case "F": + em.processCursorPreviousLine(str) + case "G": + em.processCursorColumn(str) + case "H", "f": + em.processCursorPosition(str) + case "I": + em.processCursorTab(str) + case "J": + em.processEraseDisplay(str) + case "K": + em.processEraseLine(str) + case "L": + em.processInsertLine(str) + case "M": + em.processDeleteLine(str) + case "P": + em.processDeleteCharacter(str) + case "S": + em.processScrollUp(str) + case "T": + em.processScrollDown(str) + case "X": + em.processEraseCharacter(str) + case "Z": + em.processCursorBackTab(str) + case "c": + em.processPrimaryAttributes(str) + case "d": + em.processCursorRow(str) + case "e": + em.processCursorRowAdvance(str) + case "g": + em.processTabClear(str) + case "h": + em.processSetMode(str) + case "l": + em.processResetMode(str) + case "m": + em.processSgr(str) + case "n": + em.deviceReport(str) + case "r": + em.processVerticalMargins(str) + case "s": + em.processHorizontalMargins(str) + case "t": + em.processWindowOps(str) + case " q": + em.processCursorStyle(str) + case "?W": + em.processTabReset(str) + case "?h": + em.processSetPrivateMode(str) + case "?l": + em.processResetPrivateMode(str) + case "$p": + em.processRequestMode(str) + case "?$p": + em.processRequestPrivateMode(str) + case ">q": + em.processExtendedAttributes(str) + } +} + +// processClipboard handles OSC 52 commands. +func (em *emulator) processClipboard(str string) { + clipper, ok := em.be.(Clipboard) + if !ok { + return + } + + // first parameter is the target. We only have a single + // target, and alias all possibilities to the same. + parts := strings.SplitN(str, ";", 2) + if len(parts) != 2 { + return + } + + if parts[1] == "?" { + // request for clipboard content + data := clipper.GetClipboard() + if data != nil { + em.SendRaw(fmt.Appendf(nil, "\x1b]52;c;%s\x1b\\", base64.StdEncoding.EncodeToString(data))) + } + return + } + + buf := make([]byte, base64.StdEncoding.DecodedLen(len(parts[1]))) + if n, err := base64.StdEncoding.Decode(buf, []byte(parts[1])); err == nil { + clipper.SetClipboard(buf[:n]) + return + } + + clipper.SetClipboard([]byte{}) +} + +// processHyperLink handles OSC 8 commands. +func (em *emulator) processHyperLink(str string) { + // format is params;URI params are colon separated key value pairs. + // if the URI is absent, then the link is terminated. + parts := strings.SplitN(str, ";", 2) + if len(parts) == 2 { + if parts[1] == "" { + // No URI + em.style = em.style.WithUrl("", "") + return + } + url := parts[1] + id := "" + for pair := range strings.SplitSeq(parts[0], ":") { + if val, ok := strings.CutPrefix(pair, "id="); ok { + id = val + } + } + em.style = em.style.WithUrl(url, id) + } +} + +// processOSC processes an operating system command. +func (em *emulator) processOSC() { + + // Every OSC we support has a number, semicolon, then string. + ns, str, ok := strings.Cut(em.inBuf.String(), ";") + if !ok { + return + } + if num, err := strconv.Atoi(ns); err != nil { + return + } else { + switch num { + case 2: // Set window title + if t, ok := em.be.(Titler); ok { + // TODO: possibly validate the UTF-8 content? + em.bufferingStart() + defer em.bufferingEnd() + t.SetWindowTitle(str) + } + case 8: + em.processHyperLink(str) + case 52: + em.processClipboard(str) + } + } +} + +func (em *emulator) getPosition() Coord { + pos := em.be.GetPosition() + em.pos = pos + return em.pos +} + +func (em *emulator) setPosition(pos Coord) { + em.pos = pos + em.be.SetPosition(pos) +} + +func (em *emulator) deviceReport(s string) { + switch s { + case "5": + em.SendRaw([]byte("\x1b[0n")) + case "6": + pos := em.getPosition() + em.SendRaw(fmt.Appendf(nil, "\x1b[%d;%dR", pos.Y+1, pos.X+1)) + default: // ignore + } +} + +func (em *emulator) moveUpN(count Row) { + for range count { + em.moveUp() + } +} + +func (em *emulator) moveDownN(count Row) { + for range count { + em.moveDown() + } +} + +func (em *emulator) moveLeftN(count Col) { + for range count { + em.moveLeft() + } +} + +func (em *emulator) moveRightN(count Col) { + for range count { + em.moveRight() + } +} + +// moveDown moves down, to the limit of either bottom margin, or the bottom of the screen if outside the margin. +func (em *emulator) moveDown() { + pos := em.getPosition() + win := em.size + if pos.Y == em.botMargin || pos.Y == win.Y-1 { + return + } + pos.Y++ + em.setPosition(pos) +} + +// moveUp moves up, to the limit of either top margin, or zero if outside the margin. +func (em *emulator) moveUp() { + pos := em.getPosition() + if pos.Y == 0 || pos.Y == em.topMargin { + return + } + pos.Y-- + em.setPosition(pos) +} + +func (em *emulator) moveLeft() { + em.autoWrap = false + em.lastIndex = 0 + pos := em.getPosition() + if pos.X > 0 { + pos.X-- + em.setPosition(pos) + } +} + +func (em *emulator) moveRight() { + pos := em.getPosition() + win := em.size + if pos.X < win.X-1 { + pos.X++ + em.setPosition(pos) + } +} + +// nextLine is like CNL with 1, but it optionally also scrolls. +func (em *emulator) nextLine() { + em.autoWrap = false + if em.pos.Y == em.botMargin { + em.scrollUp() + } + em.moveDown() + em.pos.X = 0 + em.setPosition(em.pos) +} + +// blit performs a data move operation. It does ignores margins. +func (em *emulator) blit(src, dst, dim Coord) { + + em.bufferingStart() + defer em.bufferingEnd() + + // save the source and destination for the backend blit + bsrc := src + bdst := dst + + lim := em.size + + // clip to visible source + if dim.X+src.X > lim.X { + dim.X = lim.X - src.X + } + if dim.Y+src.Y > lim.Y { + dim.Y = lim.Y - src.Y + } + // and clip to final destination + if dim.X+dst.X > lim.X { + dim.X = lim.X - dst.X + } + if dim.Y+dst.Y > lim.Y { + dim.Y = lim.Y - dst.Y + } + + // gap represents decrement when shifting to the next row -- + // skipping over the irrelevant cells. (The increment in the + // index when going from last cell of row to first cell of next row, + // or vice versa.) + gap := int(lim.X - dim.X) + + // the following logic is carefully constructed to avoid expensive + // operations in the loops (only addition or subtraction) + if em.index(src) > em.index(dst) { // source appears later, so we can forward copy + si := em.index(src) + di := em.index(dst) + for range dim.Y { + for range dim.X { + em.cells[di] = em.cells[si] + di++ + si++ + } + // advance to next row + si += gap + di += gap + } + } else { // source appears earlier, so we have to reverse copy + src.Y += dim.Y - 1 + dst.Y += dim.Y - 1 + src.X += dim.X - 1 + dst.X += dim.X - 1 + si := em.index(src) + di := em.index(dst) + + for range dim.Y { + for range dim.X { + em.cells[di] = em.cells[si] + si-- + di-- + } + si -= gap + di -= gap + } + } + + // Now we possibly blit underneath. We'll use the underlying + // implementation's blit operation if it has one, else we'll + // just rewrite the cells in linear order. + if b, ok := em.be.(Blitter); ok { + // The backend implements what should be a fast blit. + b.Blit(bsrc, bdst, dim) + } else { + // This does math for each cell, so you're looking at a lot of multiplications + // for a bit display -- 100x100 means 10,000x2 multiplications. This could be + // optimized, but this is really a fallback as every backend really *should* have + // an efficient blit operation. (The ones that don't probably don't keep their own + // state, such as a wrappers on top of TTYs.) In these cases the cost of writing + // the content is probably substantially dominant anyway. + for row := range dim.Y { + for col := range dim.X { + pos := bdst + pos.X += col + pos.Y += row + cell := em.cells[em.index(pos)] + em.be.Put(pos, cell) + } + } + } +} + +func (em *emulator) scrollUp() { + dim := Coord{X: em.rtMargin - em.ltMargin + 1, Y: em.botMargin - em.topMargin} + src := Coord{X: em.ltMargin, Y: em.topMargin + 1} + dst := Coord{X: em.ltMargin, Y: em.topMargin} + + // TODO: deal with wide characters broken across the margin + pos := em.pos + em.blit(src, dst, dim) + bot := Coord{X: em.ltMargin, Y: em.botMargin} + for bot.X <= em.rtMargin { + em.eraseCell(bot) + bot.X++ + } + em.setPosition(pos) +} + +func (em *emulator) scrollDown() { + dim := Coord{X: em.rtMargin - em.ltMargin + 1, Y: em.botMargin - em.topMargin} + src := Coord{X: em.ltMargin, Y: em.topMargin} + dst := Coord{X: em.ltMargin, Y: em.topMargin + 1} + + pos := em.pos + em.blit(src, dst, dim) + em.setPosition(Coord{X: em.ltMargin, Y: em.topMargin}) + top := Coord{X: em.ltMargin, Y: em.topMargin} + for top.X <= em.rtMargin { + em.eraseCell(top) + top.X++ + } + em.setPosition(pos) +} + +// nextTab advances to the next tab stop, or the end of +// the line if there is no further tab. +func (em *emulator) nextTab() { + em.lastIndex = 0 + maxX := em.size.X - 1 + curX := em.getPosition().X + if curX == maxX { // already at end + return + } + nextX := maxX + if em.tabStops == nil { + // just advance to the next one + nextX = min((curX+8)&^7, maxX) + } else { + for _, p := range em.tabStops { + if p > curX { + nextX = p + break + } + } + } + em.setPosition(Coord{X: nextX, Y: em.pos.Y}) +} + +func (em *emulator) prevTab() { + curX := em.getPosition().X + if curX == 0 { + return + } + nextX := curX - 1 + if em.tabStops == nil { + nextX &^= 7 + } else if i, exist := slices.BinarySearch(em.tabStops, nextX); exist { + nextX = em.tabStops[i] + } else if i > 0 { + nextX = em.tabStops[i-1] + } else { + nextX = 0 + } + em.setPosition(Coord{X: nextX, Y: em.pos.Y}) +} + +// initTabStops initializes the tab stops assuming every 8th column +// is a tab stop. This should only be called if the user is intentionally +// changing the tab stops, because it will no longer support expanding +// tab stops on resizing. +func (em *emulator) initTabStops() { + if em.tabStops == nil { + // no tab stop at offset 0 since that would be pointless + em.tabStops = make([]Col, 0, int(em.size.X/8)+1) + for col := Col(8); col < em.size.X; col += 8 { + em.tabStops = append(em.tabStops, col) + } + } +} + +// setTabStop sets a tab stop at the given location. +// This calls initTabStops - please see the description of that function for ramifications. +func (em *emulator) setTabStop(ts Col) { + em.initTabStops() + if index, exist := slices.BinarySearch(em.tabStops, ts); !exist { + em.tabStops = slices.Insert(em.tabStops, index, ts) + } +} + +// clrTabStop clears the tab stop at the given column. This calls +// initTabStops - please see the description of that function for ramifications. +func (em *emulator) clrTabStop(ts Col) { + em.initTabStops() + em.tabStops = slices.DeleteFunc(em.tabStops, func(x Col) bool { return x == ts }) +} + +// index obtains the index in the cells slice for the given coordinates, +// which must be within the bounds of the display size. +func (em *emulator) index(c Coord) int { + return int(c.Y)*int(em.size.X) + int(c.X) +} + +// putRune puts out a single rune. This might be a subsequent part of a grapheme cluster, in +// which case it will be emitted together with the preceding base character. +func (em *emulator) putRune(r rune) { + dim := em.size + + if lastIdx := em.lastIndex; lastIdx != 0 { + lastIdx-- + if pm := em.getPrivateMode(PmGraphemeClusters); pm == ModeOn || pm == ModeOnLocked { + // ASCII-to-ASCII pairs cannot extend a grapheme cluster, except CRLF. + prev := em.cells[lastIdx].C + if len(prev) == 1 && prev[0] < utf8.RuneSelf && !shouldCheckGrapheme(prev[0], r) { + // fall through to the normal single-rune path + } else { + // maybe we need to update the last index + buf := em.graphemeBuf[:0] + need := len(prev) + utf8.UTFMax + if cap(buf) < need { + buf = make([]byte, 0, need) + } + buf = append(buf, prev...) + buf = utf8.AppendRune(buf, r) + em.graphemeIter.SetText(buf) + if em.graphemeIter.Next() && len(em.graphemeIter.Value()) == len(buf) { + // we are adding to a cluster + cluster := em.graphemeIter.Value() + width := em.cells[lastIdx].W + if w := textWidthOptions.Rune(r); w > width { + width = w + } + if isRegionalIndicator(r) && width < 2 { + width = 2 + } + if r == '\uFE0F' && width < 2 { + width = 2 + } + em.cells[lastIdx].C = em.clusterString(cluster) + em.cells[lastIdx].W = width + col := Col(lastIdx) % dim.X + row := Row(lastIdx / int(dim.X)) + // we may have to move position if this switches to wide, so recalculate expected end + next := col + Col(width) + if em.getPrivateMode(PmAutoMargin) == ModeOn && next >= dim.X { + em.autoWrap = true + } + end := next + if end >= dim.X { + end = dim.X - 1 + } + if width == 2 && col < dim.X-1 && em.cells[lastIdx+1].W != 0 { + // erase the next cell before putting down a character + em.cells[lastIdx+1].C = "" + em.cells[lastIdx+1].S = em.cells[lastIdx].S + em.cells[lastIdx+1].W = 0 + em.be.Put(Coord{X: col + 1, Y: row}, em.cells[lastIdx+1]) + } + // we leave the em.lastIndex for now, we might keep extending this cluster + em.be.Put(Coord{X: col, Y: row}, em.cells[lastIdx]) + em.setPosition(Coord{X: end, Y: row}) + em.graphemeBuf = buf[:0] + return + } + em.graphemeBuf = buf[:0] + } + } + } + + if em.autoWrap { + em.nextLine() + } + + autoMargin := em.getPrivateMode(PmAutoMargin) == ModeOn + + pos := em.getPosition() + w := textWidthOptions.Rune(r) + if autoMargin && pos.X+Col(w) >= dim.X { + em.autoWrap = true + } + index := em.index(pos) + em.cells[index].C = em.runeString(r) + em.cells[index].S = em.style + em.cells[index].W = w + em.be.Put(em.pos, em.cells[index]) + em.lastIndex = index + 1 + + if w == 2 && pos.X < dim.X-1 { + index++ + em.cells[index].C = "" + em.cells[index].S = em.style + em.cells[index].W = 0 + } + // Advance the cursor. This will stop at the margin. + // Note that if auto margin is enabled, we will have set + // autoWrap above if we were at the margin already. + em.moveRightN(Col(w)) +} + +func (em *emulator) runeString(r rune) string { + if r < utf8.RuneSelf { + return asciiRuneStrings[r] + } + return em.runeStrings.stringFor(r) +} + +func (em *emulator) clusterString(cluster []byte) string { + return em.clusterStrings.stringFor(cluster) +} + +func shouldCheckGrapheme(prev byte, r rune) bool { + if r < utf8.RuneSelf { + return prev == '\r' && r == '\n' + } + + if unicode.Is(unicode.M, r) { + return true + } + if r == '\u200d' { + return true + } + if r >= 0xFE00 && r <= 0xFE0F { + return true + } + if r >= 0xE0100 && r <= 0xE01EF { + return true + } + + return false +} + +func isRegionalIndicator(r rune) bool { + return r >= 0x1F1E6 && r <= 0x1F1FF +} + +// eraseCell erases a single cell at the given offset. +// It clears attributes, but leaves the colors intact. +func (em *emulator) eraseCell(c Coord) { + s := em.style.WithAttr(Plain) + index := em.index(c) + em.cells[index].C = "" + em.cells[index].S = s + em.cells[index].W = 0 + em.be.Put(c, em.cells[index]) +} + +// eraseBelow erases from (and including) the current cursor position to the end of the window. +func (em *emulator) eraseBelow() { + size := em.size + pos := em.getPosition() + for x := pos.X; x < size.X; x++ { + em.eraseCell(Coord{X: x, Y: pos.Y}) + } + for y := pos.Y + 1; y < size.Y; y++ { + for x := Col(0); x < size.X; x++ { + em.eraseCell(Coord{X: x, Y: y}) + } + } + em.setPosition(pos) +} + +// eraseAbove erases from the origin to (and including) the current cursor position. +func (em *emulator) eraseAbove() { + size := em.size + pos := em.getPosition() + for y := Row(0); y < pos.Y; y++ { + for x := Col(0); x < size.X; x++ { + em.eraseCell(Coord{X: x, Y: y}) + } + } + for x := Col(0); x <= pos.X; x++ { + em.eraseCell(Coord{X: x, Y: pos.Y}) + } + em.setPosition(pos) +} + +// eraseAll erases the entire screen. It uses the color, but resets all other attributes. +func (em *emulator) eraseAll() { + size := em.size + pos := em.getPosition() + for y := Row(0); y < size.Y; y++ { + for x := Col(0); x < size.X; x++ { + em.eraseCell(Coord{X: x, Y: y}) + } + } + em.setPosition(pos) +} + +// eraseToLineEnd erases to the end of the line, including the cursor position. +func (em *emulator) eraseToLineEnd() { + size := em.size + pos := em.getPosition() + for x := pos.X; x < size.X; x++ { + em.eraseCell(Coord{x, pos.Y}) + } + em.setPosition(pos) +} + +// eraseToLineStart erases to the start of the line, including the cursor position. +func (em *emulator) eraseToLineStart() { + pos := em.getPosition() + for x := Col(0); x <= pos.X; x++ { + em.eraseCell(Coord{x, pos.Y}) + } + em.setPosition(pos) +} + +// eraseLine erases the entire line. +func (em *emulator) eraseLine() { + size := em.size + pos := em.getPosition() + for x := range size.X { + em.eraseCell(Coord{x, pos.Y}) + } + em.setPosition(pos) +} + +// softReset performs a soft reset. +func (em *emulator) softReset() { + // TODO: + // Select default character sets + em.tabStops = nil + em.autoWrap = false + em.style = em.defaultStyle + em.saved = savedCursor{style: em.defaultStyle} + em.topMargin = 0 + em.botMargin = em.size.Y - 1 + em.ltMargin = 0 + em.rtMargin = em.size.X - 1 + em.appKeyPad = false + em.be.Reset() + // start by resetting all modes + for _, am := range em.ansiModeKeys() { + em.setAnsiMode(am, ModeOff) // NB: No effect for non-changeable modes + } + for _, pm := range em.privateModeKeys() { + em.setPrivateMode(pm, ModeOff) // NB: No effect for non-changeable modes + } + // and set any that should reset on (auto-margin) + em.setPrivateMode(PmAutoMargin, ModeOn) + em.setPrivateMode(PmAutoRepeat, ModeOn) + em.setPrivateMode(PmShowCursor, ModeOn) + em.setPrivateMode(PmBlinkCursor, ModeOn) + // set default cursor - matches VT defaults + em.cursor = BlinkingBlock + em.be.SetCursor(em.cursor) + em.setPosition(Coord{0, 0}) + em.eraseAll() +} + +func (em *emulator) ansiModeKeys() []AnsiMode { + em.modeLock.RLock() + defer em.modeLock.RUnlock() + + keys := make([]AnsiMode, 0, len(em.ansiModes)) + for am := range em.ansiModes { + keys = append(keys, am) + } + return keys +} + +func (em *emulator) privateModeKeys() []PrivateMode { + em.modeLock.RLock() + defer em.modeLock.RUnlock() + + keys := make([]PrivateMode, 0, len(em.localModes)) + for pm := range em.localModes { + keys = append(keys, pm) + } + return keys +} + +// sendDA ends the primary device attributes. +func (em *emulator) sendDA() { + buf := &bytes.Buffer{} + _, _ = fmt.Fprintf(buf, "\x1b[?63") + if em.be.Colors() > 0 { + _, _ = fmt.Fprintf(buf, ";22") + } + if _, ok := em.be.(Clipboard); ok { + _, _ = fmt.Fprintf(buf, ";52") + } + // 9 for NRC? + // 15 for graphics? + buf.WriteRune('c') + em.SendRaw(buf.Bytes()) +} + +// setAnsiMode sets the ANSI mode. +func (em *emulator) setAnsiMode(mode AnsiMode, ms ModeStatus) { + if !ms.Changeable() { + return + } + em.modeLock.Lock() + defer em.modeLock.Unlock() + if old, ok := em.ansiModes[mode]; ok && old.Changeable() { + em.ansiModes[mode] = ms + } +} + +func (em *emulator) getAnsiMode(mode AnsiMode) ModeStatus { + em.modeLock.RLock() + defer em.modeLock.RUnlock() + return em.ansiModes[mode] +} + +// getPrivateMode returns the value of a DEC private mode. +func (em *emulator) getPrivateMode(pm PrivateMode) ModeStatus { + em.modeLock.RLock() + if ms, ok := em.localModes[pm]; ok { + em.modeLock.RUnlock() + return ms + } + em.modeLock.RUnlock() + return em.be.GetPrivateMode(pm) +} + +func (em *emulator) updateMouseReporting() { + mi, ok := em.be.(Mouser) + if !ok { + return + } + em.modeLock.RLock() + report := em.mouseReportingLocked() + em.modeLock.RUnlock() + mi.SetMouse(report) +} + +// setPrivateMode sets the DEC private mode. +func (em *emulator) setPrivateMode(pm PrivateMode, ms ModeStatus) { + if !ms.Changeable() { + return + } + em.modeLock.Lock() + old, ok := em.localModes[pm] + if ok && old.Changeable() { + em.localModes[pm] = ms + + var ( + setMouse bool + report MouseReporting + setCursor bool + cursor CursorStyle + ) + + switch pm { + case PmMouseButton, PmMouseDrag, PmMouseMotion, PmMouseSgr, PmMouseSgrPixel, PmMouseX10: + report = em.mouseReportingLocked() + setMouse = true + case PmShowCursor: + if ms == ModeOn { + em.cursor = em.cursor.Show() + } else { + em.cursor = em.cursor.Hide() + } + cursor = em.cursor + setCursor = true + case PmBlinkCursor: + if ms == ModeOn { + em.cursor = em.cursor.Blink() + } else { + em.cursor = em.cursor.Steady() + + } + cursor = em.cursor + setCursor = true + } + em.modeLock.Unlock() + + if setMouse { + if mi, ok := em.be.(Mouser); ok { + mi.SetMouse(report) + } + } + if setCursor { + em.be.SetCursor(cursor) + } + return + } + em.modeLock.Unlock() + + if em.be.GetPrivateMode(pm).Changeable() { + _ = em.be.SetPrivateMode(pm, ms) + } +} + +func (em *emulator) mouseReportingLocked() MouseReporting { + switch { + case em.localModes[PmMouseButton] == ModeOn: + em.mouseReports = MouseButtons + if em.localModes[PmMouseMotion] == ModeOn { + em.mouseReports = MouseMotion + } else if em.localModes[PmMouseDrag] == ModeOn { + em.mouseReports = MouseDrag + } + case em.localModes[PmMouseX10] == ModeOn: + em.mouseReports = MouseButtons + default: + em.mouseReports = MouseDisabled + } + return em.mouseReports +} + +// SendRaw allows raw data to be sent to the application. +// This is done in a thread-safe way, so that content is not intermingled. +func (em *emulator) SendRaw(b []byte) { + em.sendLock.Lock() + defer em.sendLock.Unlock() + + // Do not attempt to send *anything* if we are stopped. + select { + case <-em.stopQ: + return + default: + } + + // Try to write to the readQ, but if we cannot, then wait until + // either we can, or the stopQ is fired. This ensures that we avoid + // breaking up content if at all possible. + for _, ch := range b { + select { + case em.readQ <- ch: + default: + select { + case em.readQ <- ch: + case <-em.stopQ: + return + } + } + } +} + +// KeyEvent injects a keyboard event into the emulator +func (em *emulator) KeyEvent(ev KeyEvent) { + + if em.getPrivateMode(PmWin32Input) == ModeOn { + em.keyWin32IM(ev) + } else { + // eliminate "control" keys (which keyboard maps provide) from consideration. + // (We handle control keys explicitly.) + if ev.Utf != "" && ev.Utf[0] < ' ' { + ev.Utf = "" + } + // TODO: more add support for kitty, and maybe modify other keys + em.keyLegacy(ev) + } +} + +// ResizeEvent is called by the backend when a resize occurs. A real backend with a child +// process (essentially a "real emulator") should probably also fire SIGWINCH if appropriate. +// That would be the job of something other than this code. +func (em *emulator) ResizeEvent(size Coord) { + select { + case em.writeQ <- size: + case <-em.stopQ: + } +} + +func (em *emulator) applyResize(size Coord) { + // resize clobbers our content, until it is redrawn + em.size = size + // resizing resets the margins + em.topMargin = 0 + em.botMargin = em.size.Y - 1 + em.ltMargin = 0 + em.rtMargin = em.size.X - 1 + em.cells = make([]Cell, int(em.size.X)*int(em.size.Y)) + for i := range em.cells { + em.cells[i].S = em.defaultStyle + } + + em.pos = em.getPosition() + if em.getPrivateMode(PmResizeReports) == ModeOn { // NB: we never support "ModeOnLocked" + // NB: for now we do not support pixel sizes + em.SendRaw(fmt.Appendf(nil, "\x1b[48;%d;%d;0;0t", em.size.Y, em.size.X)) + } + + // Send a SIGWINCH or similar. + em.be.RaiseResize() +} + +var legacyKeys = map[Key]struct { + K string // unmodified key + A string // unmodified in application cursor mode (smkx) + S string // with shift (if empty use regular modifier) + C string // with control (if empty use regular modifier) + CS string // with ctrl-shift +}{ + KeyF1: {K: "\x1bOP"}, // SS3 P + KeyF2: {K: "\x1bOQ"}, // SS3 Q + KeyF3: {K: "\x1bOR"}, // SS3 R + KeyF4: {K: "\x1bOS"}, // SS3 S + KeyF5: {K: "\x1b[15~"}, + KeyF6: {K: "\x1b[17~"}, + KeyF7: {K: "\x1b[18~"}, + KeyF8: {K: "\x1b[19~"}, + KeyF9: {K: "\x1b[20~"}, + KeyF10: {K: "\x1b[21~"}, + KeyF11: {K: "\x1b[23~"}, + KeyF12: {K: "\x1b[24~"}, + KeyF13: {K: "\x1b[25~"}, + KeyF14: {K: "\x1b[26~"}, + KeyF15: {K: "\x1b[28~"}, + KeyF16: {K: "\x1b[29~"}, + KeyF17: {K: "\x1b[31~"}, + KeyF18: {K: "\x1b[32~"}, + KeyF19: {K: "\x1b[33~"}, + KeyF20: {K: "\x1b[34~"}, + KeyUp: {K: "\x1b[A", A: "\x1bOA"}, + KeyDown: {K: "\x1b[B", A: "\x1bOB"}, + KeyRight: {K: "\x1b[C", A: "\x1bOC"}, + KeyLeft: {K: "\x1b[D", A: "\x1bOD"}, + KeyHome: {K: "\x1b[H", A: "\x1bOH"}, + KeyEnd: {K: "\x1b[F", A: "\x1bOF"}, + KeyPgUp: {K: "\x1b[5~"}, + KeyPgDn: {K: "\x1b[6~"}, + KeyDelete: {K: "\x1b[3~"}, + KeyInsert: {K: "\x1b[2~"}, + KeyMenu: {K: "\x1b[29~"}, // also F16 + KeyTab: {K: "\t", S: "\x1b[Z", CS: "\x1b[Z"}, + KeyBackspace: {K: "\x7f", S: "\x7f", C: "\x08", CS: "\x08"}, + KeySpace: {K: " ", S: " ", C: "\x00", CS: "\x00"}, + KeyEnter: {K: "\r", S: "\r", CS: "\r"}, // NB: consider using kitty encoding here + KeyPadEnter: {K: "\r", S: "\r", CS: "\r"}, // NB: consider using kitty encoding here + KeyEsc: {K: "\x1b", S: "\x1b", C: "\x1b"}, +} + +var legacyControls = map[Key]string{ + // These ones are weird legacy control sequences that we mostly + // do not care about. We don't include shifted variants. + Key2: "\x00", + Key3: "\x1b", + Key4: "\x1c", + Key5: "\x1d", + Key6: "\x1e", + Key7: "\x1f", + Key8: "\x7f", + KeyLBrace: "\x1b", + KeySlash: "\x1c", + KeyRBrace: "\x1d", +} + +// legacyPadKeys are keys that are on the keypad, when not in numeric keypad mode. +// Note that num lock overrides this. +var legacyPadKeys = map[Key]struct { + app string + num string +}{ + KeyPadEnter: {"\x1bOM", "\r"}, + KeyPadMul: {"\x1bOj", "*"}, + KeyPadAdd: {"\x1bOk", "+"}, + KeyPadSub: {"\x1bOm", "-"}, + KeyPadDiv: {"\x1bOo", "/"}, + KeyPadDec: {"\x1b[3~", "."}, // Del + KeyPad0: {"\x1b[2~", "0"}, // Ins + KeyPad1: {"\x1bOF", "1"}, // End + KeyPad2: {"\x1b[B", "2"}, // Down + KeyPad3: {"\x1b[6~", "3"}, // PgDn + KeyPad4: {"\x1b[D", "4"}, // Left + KeyPad5: {"\x1b[E", "5"}, // Clear/Begin + KeyPad6: {"\x1b[C", "6"}, // Right + KeyPad7: {"\x1bOH", "7"}, // Home + KeyPad8: {"\x1b[A", "8"}, // Up + KeyPad9: {"\x1b[5~", "9"}, // PgUp + KeyPadEqual: {"\x1bOX", "="}, +} + +// repeatRaw is called to provide key repeat. We limit key repeating to just 40, +// and we ensure that at least one is included. We only repeat if key repeat is enabled. +func (em *emulator) repeatRaw(ev KeyEvent, data []byte) { + if pm := em.getPrivateMode(PmAutoRepeat); pm == ModeOn || pm == ModeOnLocked { + for range min(max(1, ev.Repeat), 40) { + em.SendRaw(data) + } + } else { + if ev.Repeat == 0 { + em.SendRaw(data) + } + } +} + +// noRepeatRaw is used to send a key that should never repeat. +// It will only send if the repeat count is zero. +func (em *emulator) noRepeatRaw(ev KeyEvent, data []byte) { + if ev.Repeat == 0 { + em.SendRaw(data) + } +} + +// keyLegacy handles a keyboard event when in legacy vt220 style mode. +func (em *emulator) keyLegacy(ev KeyEvent) { + if !ev.Down { // legacy protocol does not support key release + return + } + if ev.Mod.IsMeta() || ev.Mod.IsHyper() { // legacy protocol does not support these + return + } + + // Shift-Ctrl keys are never sent in the legacy protocol. We do have to ensure + // that if we are sending other Utf (for example with AltGr), then we still might + // send it, but this is only an issue for non-ASCII runes. Also, this filter only + // applies for "regular" keys (i.e. not function keys, cursor keys, etc.) + if ev.Mod.IsShift() && ev.Mod.IsCtrl() && (ev.Utf == "" || ev.Utf[0] < 0x80) { + if base := ev.Key.KittyBase(); base >= ' ' && base < 0x80 { + return + } + } + + // keypad sequences + if v, ok := legacyPadKeys[ev.Key]; ok { + if ev.Mod&ModNumLock == 0 { + if em.appKeyPad { + em.repeatRaw(ev, []byte(v.app)) + } else { + em.repeatRaw(ev, []byte(v.num)) + } + return + } else { + ev.Utf = v.num + } + } + + // For control keys (e.g. control-J) we never emit a rune directly -- but we might later + // add after decoding the key accordingly. + if ev.Utf != "" && (ev.Mod == ModLCtrl || ev.Mod == ModRCtrl || ev.Utf[0] < ' ') { + ev.Utf = "" + } + + if ev.Utf != "" { + if ev.Utf[0] < 0x80 && ev.Mod.IsAlt() { // ASCII might get alt + em.noRepeatRaw(ev, fmt.Appendf(nil, "\x1b%s", ev.Utf)) + } else { // otherwise send the UTF as-is + em.repeatRaw(ev, []byte(ev.Utf)) + } + return + } + + // some weird number control sequences - legacy compatibility + // We do not repeat these. + if v, ok := legacyControls[ev.Key]; ok && (ev.Mod == ModLCtrl || ev.Mod == ModRCtrl) { + em.noRepeatRaw(ev, []byte(v)) + return + } + + if v, ok := legacyKeys[ev.Key]; ok { + str := "" + match := false + if !ev.Mod.IsShift() && !ev.Mod.IsCtrl() { + if em.getPrivateMode(PmAppCursor) == ModeOn && v.A != "" { + str = v.A + } else { + str = v.K + } + // AnsiMode 20 sends newline, but only in legacy mode. + if str == "\r" && em.getAnsiMode(AmNewLineMode) == ModeOn { + str = "\r\n" + } + match = true + } else if ev.Mod.IsShift() && !ev.Mod.IsCtrl() { + if str = v.S; str != "" { + match = true + } + } else if ev.Mod.IsCtrl() && !ev.Mod.IsShift() { + if str = v.C; str != "" { + match = true + } + } else { // IsCtrl & IsShift + if str = v.CS; str != "" { + match = true + } + } + if !match { + // No specific modifiers present, lets add them. There are two cases, + // one for SS3 based keys and another for CSI based keys. SS3 based + // keys are converted to CSI - 1 ; mod ; final + // Note: legacy encoding does not use modifiers for alt or super - alt will be + // determined by sending an escape prefix. + mod := 0 + if ev.Mod.IsShift() { + mod |= 1 + } + if ev.Mod.IsCtrl() { + mod |= 4 + } + if strings.HasPrefix(v.K, "\x1bO") { + str = fmt.Sprintf("\x1b[1;%d%c", mod+1, v.K[len(v.K)-1]) + } else { + str = fmt.Sprintf("%s;%d%c", v.K[:len(v.K)-1], mod+1, v.K[len(v.K)-1]) + } + } + if ev.Mod.IsAlt() { + // no repeating ALT sequences + em.noRepeatRaw(ev, append([]byte{'\x1b'}, []byte(str)...)) // alt sends leading escape + } else if ev.Mod.IsCtrl() { + // no repeating CTRL sequences + em.noRepeatRaw(ev, []byte(str)) + } else { + // but other sequences (should just be shifted or unmodified) + // are fine. (E.g. we want to allow repeats of cursor keys) + em.repeatRaw(ev, []byte(str)) + } + return + } + + // fallback control key handling + if ev.Key >= KeyA && ev.Key <= KeyZ && ev.Mod.IsCtrl() { + b := byte(ev.Key-KeyA) + 1 /* ctrl-A */ + if ev.Mod.IsAlt() { + em.noRepeatRaw(ev, []byte{'\x1b', b}) + } else { + em.noRepeatRaw(ev, []byte{b}) + } + return + } +} + +var win32NoRepeat = map[Key]bool{ + KeyLShift: true, + KeyRShift: true, + KeyLCtrl: true, + KeyRCtrl: true, + KeyLAlt: true, + KeyRAlt: true, + KeyLMeta: true, + KeyRMeta: true, + KeyCapsLock: true, + KeyNumLock: true, + KeyEnter: true, + KeyScrLock: true, + KeyPause: true, + KeyPrtScr: true, +} + +// keyWin32IM generates the sequence for a key event when in Win32 input mode. +// Win32 input mode is ESC [ Vk ; Sc ; Uc ; Kd ; Cs ; Rc _ +// Note that we specifically do NOT doubly encode non-keyboard events -- those +// are already unambiguously handled within the protocol. (Windows Terminal behaves +// the same way, but most 3rd party terminals do doubly encode.) +func (em *emulator) keyWin32IM(ev KeyEvent) { + // Some keys that never repeat + if pm := em.getPrivateMode(PmAutoRepeat); pm == ModeOff || pm == ModeOffLocked { + if ev.Repeat != 0 { + return + } + } + r := rune(0) + if ev.Utf != "" { + runes := []rune(ev.Utf) + if len(runes) == 1 { + r = runes[0] + } + } + kd := 0 + if ev.Down { + kd = 1 + } + cs := 0 + // Modifiers + if ev.Mod&ModRAlt != 0 { + cs |= 0x01 + } + if ev.Mod&ModLAlt != 0 { + cs |= 0x02 + } + if ev.Mod&ModRCtrl != 0 { + cs |= 0x04 + } + if ev.Mod&ModLCtrl != 0 { + cs |= 0x08 + } + if ev.Mod.IsShift() { + cs |= 0x10 + } + if ev.Mod.IsNumLock() { + cs |= 0x20 + } + // NB: 0x40 is for scroll lock, we don't support it for now + if ev.Mod.IsCapsLock() { + cs |= 0x80 + } + switch ev.Key { + case KeyPadEnter: + case KeyPadDiv: + case KeyInsert: + case KeyDelete: + case KeyHome: + case KeyEnd: + case KeyPgUp: + case KeyPgDn: + cs |= 0x100 // enhanced + } + if win32NoRepeat[ev.Key] { + if ev.Repeat > 0 { + return + } + ev.Repeat = 1 + } + em.SendRaw(fmt.Appendf(nil, "\x1b[%d;%d;%d;%d;%d;%d_", ev.VK, ev.SC, r, kd, cs, max(1, ev.Repeat))) +} + +func (em *emulator) MouseEvent(ev MouseEvent) { + if pm := em.getPrivateMode(PmMouseButton); pm == ModeOn { + + if em.getPrivateMode(PmMouseDrag) != ModeOn && em.getPrivateMode(PmMouseMotion) != ModeOn { + // suppress motion events if the user didn't request + if ev.Button == NoButton { + return // if entire event was just motion, bail + } + ev.Motion = false + } + + if pm = em.getPrivateMode(PmMouseSgr); pm == ModeOn { + btn := ev.encodeButton() + if ev.Down { + em.SendRaw(fmt.Appendf(nil, "\x1b[<%d;%d;%dM", btn, ev.Position.X+1, ev.Position.Y+1)) + } else { + em.SendRaw(fmt.Appendf(nil, "\x1b[<%d;%d;%dm", btn, ev.Position.X+1, ev.Position.Y+1)) + } + } else { + // Old style reporting (via 1000h). + // Limitations of legacy VT200 reporting are that the coordinates must be between + // 1 and 223 inclusive, and that once any release occurs all buttons are assumed + // to be released. (Please use SGR mode if at all possible.) + // Further, this mode is not CSI compliant as the encoded values that arrive ahead of + // the final character may be within the range of technically legal CSI final bytes. + if !ev.Down { + ev.Button = NoButton + } + btn := ev.encodeButton() + data := append([]byte{'\x1b', '[', 'M', btn + 32}, + byte(min(ev.Position.X+1, 223)+32), + byte(min(ev.Position.Y+1, 223)+32)) + em.SendRaw(data) + } + + } else if pm := em.getPrivateMode(PmMouseX10); pm == ModeOn && ev.Down { + // legacy X10 reporting only + x := byte(min(ev.Position.X+1, 223)) + 32 + y := byte(min(ev.Position.Y+1, 223)) + 32 + // NB: we intentionally reverse buttons 2 & 3 (for xterm compatibility) + switch ev.Button { + case Button1: + em.SendRaw([]byte{'\x1b', '[', 'M', ' ', x, y}) + case Button2: + em.SendRaw([]byte{'\x1b', '[', 'M', '"', x, y}) + case Button3: + em.SendRaw([]byte{'\x1b', '[', 'M', '!', x, y}) + } + } +} + +func (em *emulator) FocusEvent(focused bool) { + if pm := em.getPrivateMode(PmFocusReports); pm == ModeOn { + if focused { + em.SendRaw([]byte{'\x1b', '[', 'I'}) + } else { + em.SendRaw([]byte{'\x1b', '[', 'O'}) + } + } +} + +// SetId sets the terminal name and version. +func (em *emulator) SetId(name string, version string) { + em.name = name + em.vers = version +} + +// Start the terminal emulator. +func (em *emulator) Start() error { + select { + case <-em.stopQ: + default: + // already running + return errors.New("terminal already started") + } + stopQ := make(chan bool) + em.stopQ = stopQ + go em.run(stopQ) + return nil +} + +// Stop the terminal emulator. This also wakes any blocked +// Read or Write calls, which will return an error. +func (em *emulator) Stop() error { + select { + case <-em.stopQ: + default: + close(em.stopQ) + } + return nil +} + +// Drain pending output to the terminal emulator. +func (em *emulator) Drain() error { + q := make(chan bool) + select { + case em.writeQ <- q: + case <-em.stopQ: + } + select { + case <-q: + case <-em.stopQ: + } + // make sure to wake the reader + select { + case em.readQ <- true: + default: + } + return nil +} + +// Write data to the emulator (commands). +func (em *emulator) Write(data []byte) (n int, err error) { + stopQ := em.stopQ + writeQ := em.writeQ + drainQ := make(chan bool) + select { + case writeQ <- data: + // we add the drainQ for synchronization, so that we only + // return after the the emulator has processed this. + select { + case <-stopQ: + return 0, errors.New("terminal emulator stopped") + case writeQ <- drainQ: + } + select { + case <-stopQ: + return 0, errors.New("terminal emulator stopped") + case <-drainQ: + return len(data), nil + } + case <-stopQ: + return 0, errors.New("terminal emulator stopped") + } +} + +// Read data (key events, etc.) from the emulator. +func (em *emulator) Read(data []byte) (n int, err error) { + stopQ := em.stopQ + readQ := em.readQ + + n = 0 + if len(data) < 1 { + return 0, nil + } + select { + case <-stopQ: + return 0, errors.New("terminal emulator stopped") + case v := <-readQ: + // The data arriving in the channel may be a byte, or it might be a bool + // trying to force a wake up. Note that the bool may be intermingled with other + // bytes, so we check it. Also data may have arrived since the bool was posted, + // so make sure we don't terminate until we have collected all the relevant data + // that we can (up to the limit of what was requested.) + if ch, ok := v.(byte); ok { + data[n] = ch + n++ + } + for n < len(data) { + select { + case v = <-readQ: + if ch, ok := v.(byte); ok { + data[n] = ch + n++ + } + default: + return n, nil + } + } + return n, nil + } +} + +func (em *emulator) run(stopQ <-chan bool) { + for { + select { + case item := <-em.writeQ: + switch d := item.(type) { + case byte: + em.inb(d) + case []byte: + for _, ch := range d { + em.inb(ch) + } + case chan bool: + close(d) + + case Coord: // resize notification + em.applyResize(d) + } + case <-stopQ: + return + } + } +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/event.go b/vendor/github.com/gdamore/tcell/v3/vt/event.go new file mode 100644 index 000000000..bdab43593 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/event.go @@ -0,0 +1,133 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +// KeyEvent is a key event. +type KeyEvent struct { + Down bool // true if event is for key down event + Repeat int // if > 1, a repeat count + Key Key // Key symbol. + Base BaseKey // base key code (physical key, e.g 'a'), may be zero if same as code + VK WinVK // Windows virtual key. 0 for none, or if not known. + SC ScanCode // Windows scan code. 0 for none, or if not known. + Mod Modifier // modifiers + Utf string // if non-empty, the unicode content for this +} + +type Modifier int + +const ( + ModNone = Modifier(0) + ModLShift = Modifier(1 << iota) + ModRShift + ModLCtrl + ModRCtrl + ModLAlt + ModRAlt + ModLMeta + ModRMeta + ModLHyper + ModRHyper + ModCapsLock + ModNumLock +) + +func (m Modifier) IsShift() bool { return (m & (ModLShift | ModRShift)) != 0 } +func (m Modifier) IsCtrl() bool { return (m & (ModLCtrl | ModRCtrl)) != 0 } +func (m Modifier) IsAlt() bool { return (m & (ModLAlt | ModRAlt)) != 0 } +func (m Modifier) IsMeta() bool { return (m & (ModLMeta | ModRMeta)) != 0 } +func (m Modifier) IsHyper() bool { return (m & (ModLHyper | ModRHyper)) != 0 } +func (m Modifier) IsNumLock() bool { return m&ModNumLock != 0 } +func (m Modifier) IsCapsLock() bool { return m&ModCapsLock != 0 } +func (m Modifier) IsCapitals() bool { return m.IsCapsLock() != m.IsShift() } +func (m Modifier) IsAltGr() bool { return m.IsCtrl() && m.IsAlt() } + +// Button is the mouse button pressed or released. +type Button int + +const ( + NoButton = Button(0) // No buttons are pressed. + Button1 = Button(1 << iota) // Usually left most button. + Button2 // Usually right most button. + Button3 // Usually middle button. + Button4 + Button5 + Button6 + Button7 + Button8 + WheelUp // Wheel motion up/away from user. + WheelDown // Wheel motion down/towards user. + WheelLeft // Wheel motion to left. + WheelRight // Wheel motion to right. +) + +// MouseEvent reports a single mouse event. Only a single button +// may be reported for a given event. The application will have +// to keep state. As buttons are never pressed exactly simultaneously, +// the backend will send chords as a series of presses followed by a series +// of releases. +type MouseEvent struct { + Position Coord // Location of pointer. + Button Button // Buttons pressed. + Down bool // True on press, false on release. + Motion bool // True if mouse moved at least once cell. + Mod Modifier // Modifiers (for modified click). +} + +// encodeButton just encodes the XTerm style button details into a byte +func (ev MouseEvent) encodeButton() byte { + var btn byte + switch ev.Button { + case NoButton: + btn = 3 + case Button1: + btn = 0 + case Button2: // intentionally reversed with button 3 + btn = 2 + case Button3: + btn = 1 + case WheelUp: + btn = 0x40 + case WheelDown: + btn = 0x41 + case WheelLeft: + btn = 0x42 + case WheelRight: + btn = 0x43 + case Button4: + btn = 0x80 + case Button5: + btn = 0x81 + case Button6: + btn = 0x82 + case Button7: + btn = 0x83 + default: + btn = 3 + } + if ev.Motion { + btn += 0x20 + } + if ev.Mod.IsShift() { + btn += 4 + } + if ev.Mod.IsAlt() || ev.Mod.IsMeta() { + btn += 8 + } + if ev.Mod.IsCtrl() { + btn += 16 + } + return btn +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/key.go b/vendor/github.com/gdamore/tcell/v3/vt/key.go new file mode 100644 index 000000000..9b36e9d48 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/key.go @@ -0,0 +1,629 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +// BaseKey is the Kitty protocol base key. These are kitty's representation of a scan code. +// As the Kitty protocol is likely the extended keyboard protocol we care about, we use +// this as the primary reporting mechanism. (It also helps that this may provide an easier +// fallback for implementations that don't have raw scan codes and are willing to assume an +// ANSI layout.) +type BaseKey rune + +var shiftedBaseKeys map[BaseKey]rune + +func (bk BaseKey) Shifted() rune { + + if s, ok := shiftedBaseKeys[bk]; ok { + return s + } + if bk >= 'a' && bk <= 'z' { + return rune(bk - 32) + } + return rune(bk) +} + +// ScanCode is the scan code used by Windows for a key. These are physical key locations, +// and every physical should have a exactly one mapping here. +type ScanCode uint16 + +// Key represents the key code for a key. These are largely taken from the HID specification page 0x07, +// although there are gaps and some inconsistencies. We chose this specification because it covers all +// keyboards we are likely to see in practice. Note that the zero value is reserved and will never be +// assigned a valid key. A number of keys are from UNIX keyboards (e.g. Sun type 6 keyboards), and we do not +// explicitly support these because none of the common reporting protocols have a way to report them. +// Instead these should probably be mapped higher functions (F13 and up), if you're facing this. +// These are key locations on a US keyboard. For example on AZERTY layout KeyQ corresponds to a key +// that has a printed "A", but is in the upper left position (below the digits.) +type Key uint16 + +const ( + KeyUTF = Key(0x01) // virtual UTF-8 content + KeyA = Key(0x04) + KeyB = Key(0x05) + KeyC = Key(0x06) + KeyD = Key(0x07) + KeyE = Key(0x08) + KeyF = Key(0x09) + KeyG = Key(0x0A) + KeyH = Key(0x0B) + KeyI = Key(0x0C) + KeyJ = Key(0x0D) + KeyK = Key(0x0E) + KeyL = Key(0x0F) + KeyM = Key(0x10) + KeyN = Key(0x11) + KeyO = Key(0x12) + KeyP = Key(0x13) + KeyQ = Key(0x14) + KeyR = Key(0x15) + KeyS = Key(0x16) + KeyT = Key(0x17) + KeyU = Key(0x18) + KeyV = Key(0x19) + KeyW = Key(0x1A) + KeyX = Key(0x1B) + KeyY = Key(0x1C) + KeyZ = Key(0x1D) + Key1 = Key(0x1E) + Key2 = Key(0x1F) + Key3 = Key(0x20) + Key4 = Key(0x21) + Key5 = Key(0x22) + Key6 = Key(0x23) + Key7 = Key(0x24) + Key8 = Key(0x25) + Key9 = Key(0x26) + Key0 = Key(0x27) + KeyEnter = Key(0x28) + KeyEsc = Key(0x29) + KeyBackspace = Key(0x2a) // sometimes called delete + KeyTab = Key(0x2b) + KeySpace = Key(0x2c) + KeyMinus = Key(0x2d) // - and _ + KeyEqual = Key(0x2e) // = and + + KeyLBrace = Key(0x2f) // [ and { + KeyRBrace = Key(0x30) // ] and } + KeyBackslash = Key(0x31) // \ + KeyIsoHash = Key(0x32) // international only + KeySemi = Key(0x33) // ; + KeyQuote = Key(0x34) // ' and " aka apostrophe + KeyGrave = Key(0x35) // ` and ~ + KeyComma = Key(0x36) // , and < + KeyPeriod = Key(0x37) // . and > + KeySlash = Key(0x38) // / and ? + KeyCapsLock = Key(0x39) + KeyF1 = Key(0x3a) + KeyF2 = Key(0x3b) + KeyF3 = Key(0x3c) + KeyF4 = Key(0x3d) + KeyF5 = Key(0x3e) + KeyF6 = Key(0x3f) + KeyF7 = Key(0x40) + KeyF8 = Key(0x41) + KeyF9 = Key(0x42) + KeyF10 = Key(0x43) + KeyF11 = Key(0x44) + KeyF12 = Key(0x45) + KeyPrtScr = Key(0x46) + KeyScrLock = Key(0x47) + KeyPause = Key(0x48) + KeyInsert = Key(0x49) + KeyHome = Key(0x4a) + KeyPgUp = Key(0x4b) + KeyDelete = Key(0x4c) // forward delete (DEL) + KeyEnd = Key(0x4d) + KeyPgDn = Key(0x4e) + KeyRight = Key(0x4f) + KeyLeft = Key(0x50) + KeyDown = Key(0x51) + KeyUp = Key(0x52) + KeyNumLock = Key(0x53) // also clear + KeyPadDiv = Key(0x54) + KeyPadMul = Key(0x55) + KeyPadSub = Key(0x56) + KeyPadAdd = Key(0x57) + KeyPadEnter = Key(0x58) + KeyPad1 = Key(0x59) // also pad end + KeyPad2 = Key(0x5a) // also pad down + KeyPad3 = Key(0x5b) // also pad page down + KeyPad4 = Key(0x5c) // also pad left + KeyPad5 = Key(0x5d) + KeyPad6 = Key(0x5e) // also pad right + KeyPad7 = Key(0x5f) // also pad home + KeyPad8 = Key(0x60) // also pad up + KeyPad9 = Key(0x61) // also pad page up + KeyPad0 = Key(0x62) // also pad insert + KeyPadDec = Key(0x63) // also pad delete + KeyIsoBackSlash = Key(0x64) // international keyboards only + KeyPadEqual = Key(0x67) + KeyF13 = Key(0x68) + KeyF14 = Key(0x69) + KeyF15 = Key(0x6a) + KeyF16 = Key(0x6b) + KeyF17 = Key(0x6c) + KeyF18 = Key(0x6d) + KeyF19 = Key(0x6e) + KeyF20 = Key(0x6f) + KeyF21 = Key(0x70) + KeyF22 = Key(0x71) + KeyF23 = Key(0x72) + KeyF24 = Key(0x73) + KeyMenu = Key(0x76) // might also be 0x65, KeyApplication + KeyPadComma = Key(0x85) + KeyPadEqSign = Key(0x86) + KeyIsoSlash = Key(0x87) // also International 1 + KeyHiragana = Key(0x88) // also International 2 + KeyYen = Key(0x89) // found on JIS keyboards + KeyConvert = Key(0x8a) + KeyNonConvert = Key(0x8b) + KeyAltErase = Key(0x99) // e.g split space-erase bar + KeySysReq = Key(0x9a) + KeyCancel = Key(0x9b) + KeyLCtrl = Key(0xe0) + KeyLShift = Key(0xe1) + KeyLAlt = Key(0xe2) + KeyLMeta = Key(0xe3) + KeyRCtrl = Key(0xe4) + KeyRShift = Key(0xe5) + KeyRAlt = Key(0xe6) + KeyRMeta = Key(0xe7) + KeyLHyper = Key(0xff01) // software only, in reserved space + KeyRHyper = Key(0xff02) // software only, in reserved space +) + +// scanCodes is a list of Windows scan codes for physical keys. +var scanCodes map[Key]ScanCode + +// ScanCode returns the corresponding Windows Scan Code (not a VK!) +// for the given key. (Virtual keys should be determined by the +// host OS using the current keyboard layout.) +func (k Key) ScanCode() ScanCode { + + if w, ok := scanCodes[k]; ok { + return w + } + return 0 +} + +// WinVK represents a windows virtual key code. +// These are similar to base keys, but a multiple scanned key codes +// may result in the same virtual key. This can also be sensitive to +// the keyboard layout. +type WinVK rune + +const ( + VkBack = WinVK(0x08) // backspace + VkTab = WinVK(0x09) + VkClear = WinVK(0x0c) + VkReturn = WinVK(0x0d) + VkShift = WinVK(0x10) + VkControl = WinVK(0x11) + VkMenu = WinVK(0x12) + VkPause = WinVK(0x13) + VkCapital = WinVK(0x14) // caps lock + VkKana = WinVK(0x15) + VkHangul = WinVK(0x15) + VkImeOn = WinVK(0x16) + VkJunja = WinVK(0x17) + VkFinal = WinVK(0x18) + VkKanji = WinVK(0x19) + VkImeOff = WinVK(0x1a) + VkEscape = WinVK(0x1b) + VkConvert = WinVK(0x1c) + VkNonConvert = WinVK(0x1d) + VkAccept = WinVK(0x1e) + VkModeChange = WinVK(0x1f) + VkSpace = WinVK(0x20) + VkPrior = WinVK(0x21) // page up + VkNext = WinVK(0x22) // page down + VkEnd = WinVK(0x23) + VkHome = WinVK(0x24) + VkLeft = WinVK(0x25) + VkUp = WinVK(0x26) + VkRight = WinVK(0x27) + VkDown = WinVK(0x28) + VkSelect = WinVK(0x29) + VkPrint = WinVK(0x2a) + VkExecute = WinVK(0x2b) + VkSnapshot = WinVK(0x2c) // print screen + VkInsert = WinVK(0x2D) + VkDelete = WinVK(0x2E) + VkHelp = WinVK(0x2F) + Vk0 = WinVK(0x30) + Vk1 = WinVK(0x31) + Vk2 = WinVK(0x32) + Vk3 = WinVK(0x33) + Vk4 = WinVK(0x34) + Vk5 = WinVK(0x35) + Vk6 = WinVK(0x36) + Vk7 = WinVK(0x37) + Vk8 = WinVK(0x38) + Vk9 = WinVK(0x39) + VkA = WinVK(0x41) + VkB = WinVK(0x42) + VkC = WinVK(0x43) + VkD = WinVK(0x44) + VkE = WinVK(0x45) + VkF = WinVK(0x46) + VkG = WinVK(0x47) + VkH = WinVK(0x48) + VkI = WinVK(0x49) + VkJ = WinVK(0x4a) + VkK = WinVK(0x4b) + VkL = WinVK(0x4c) + VkM = WinVK(0x4d) + VkN = WinVK(0x4e) + VkO = WinVK(0x4f) + VkP = WinVK(0x50) + VkQ = WinVK(0x51) + VkR = WinVK(0x52) + VkS = WinVK(0x53) + VkT = WinVK(0x54) + VkU = WinVK(0x55) + VkV = WinVK(0x56) + VkW = WinVK(0x57) + VkX = WinVK(0x58) + VkY = WinVK(0x59) + VkZ = WinVK(0x5a) + VkLWin = WinVK(0x5b) // left meta + VkRWin = WinVK(0x5c) // right meta + VkApps = WinVK(0x5d) // menu key + VkNumPad0 = WinVK(0x60) + VkNumPad1 = WinVK(0x61) + VkNumPad2 = WinVK(0x62) + VkNumPad3 = WinVK(0x63) + VkNumPad4 = WinVK(0x64) + VkNumPad5 = WinVK(0x65) + VkNumPad6 = WinVK(0x66) + VkNumPad7 = WinVK(0x67) + VkNumPad8 = WinVK(0x68) + VkNumPad9 = WinVK(0x69) + VkMultiply = WinVK(0x6a) // pad multiply + VkAdd = WinVK(0x6b) // pad add + VkSeparator = WinVK(0x6c) // separator + VkSubtract = WinVK(0x6d) // pad subtract + VkDecimal = WinVK(0x6e) // pad decimal point + VkDivide = WinVK(0x6f) // pad divide + VkF1 = WinVK(0x70) + VkF2 = WinVK(0x71) + VkF3 = WinVK(0x72) + VkF4 = WinVK(0x73) + VkF5 = WinVK(0x74) + VkF6 = WinVK(0x75) + VkF7 = WinVK(0x76) + VkF8 = WinVK(0x77) + VkF9 = WinVK(0x78) + VkF10 = WinVK(0x79) + VkF11 = WinVK(0x7a) + VkF12 = WinVK(0x7b) + VkF13 = WinVK(0x7c) + VkF14 = WinVK(0x7d) + VkF15 = WinVK(0x7e) + VkF16 = WinVK(0x7f) + VkF17 = WinVK(0x80) + VkF18 = WinVK(0x81) + VkF19 = WinVK(0x82) + VkF20 = WinVK(0x83) + VkF21 = WinVK(0x84) + VkF22 = WinVK(0x85) + VkF23 = WinVK(0x86) + VkF24 = WinVK(0x87) + VkNumLock = WinVK(0x90) + VkScroll = WinVK(0x91) // scroll lock + VkLShift = WinVK(0xa0) + VkRShift = WinVK(0xa1) + VkLControl = WinVK(0xa2) + VkRControl = WinVK(0xa3) + VkLMenu = WinVK(0xa4) // left alt + VkRMenu = WinVK(0xa5) // right alt + VkOem1 = WinVK(0xba) // ; and : + VkOemPlus = WinVK(0xbb) // = and + + VkOemComma = WinVK(0xbc) // , and < + VkOemMinus = WinVK(0xbd) // - and _ + VkOemPeriod = WinVK(0xbe) // . and > + VkOem2 = WinVK(0xbf) // / and ? + VkOem3 = WinVK(0xc0) // ` and ~ + VkOem4 = WinVK(0xdb) // [ and { + VkOem5 = WinVK(0xdc) // \ and | + VkOem6 = WinVK(0xdd) // ] and } + VkOem7 = WinVK(0xde) // ' and " + VkOem8 = WinVK(0xdf) // right control for Canadian CSA + VkOem102 = WinVK(0xe2) // ISO backslash + VkPacket = WinVK(0xe7) +) + +var baseKeys map[Key]BaseKey + +// KittyBase returns the corresponding Kitty "base" key for the given USB cod. +// If no corresponding value can be found, then zero is returned. Note that +// some keys (such as F1) are valid, and recognized by Kitty, but do not use the +// base key encoding because they use another reporting format. +func (k Key) KittyBase() BaseKey { + if w, ok := baseKeys[k]; ok { + return w + } + return 0 +} + +func init() { + // we place them in init to avoid incorrect processing in coverage checks. + + baseKeys = map[Key]BaseKey{ + KeyA: 'a', + KeyB: 'b', + KeyC: 'c', + KeyD: 'd', + KeyE: 'e', + KeyF: 'f', + KeyG: 'g', + KeyH: 'h', + KeyI: 'i', + KeyJ: 'j', + KeyK: 'k', + KeyL: 'l', + KeyM: 'm', + KeyN: 'n', + KeyO: 'o', + KeyP: 'p', + KeyQ: 'q', + KeyR: 'r', + KeyS: 's', + KeyT: 't', + KeyU: 'u', + KeyV: 'v', + KeyW: 'w', + KeyX: 'x', + KeyY: 'y', + KeyZ: 'z', + Key1: '1', + Key2: '2', + Key3: '3', + Key4: '4', + Key5: '5', + Key6: '6', + Key7: '7', + Key8: '8', + Key9: '9', + Key0: '0', + KeyEnter: '\r', + KeyEsc: '\x1b', + KeyBackspace: '\x7f', + KeyTab: '\t', + KeySpace: ' ', + KeyMinus: '-', + KeyEqual: '=', + KeyLBrace: '[', + KeyRBrace: ']', + KeyBackslash: '\\', + KeyIsoHash: '#', + KeySemi: ';', + KeyQuote: '\'', + KeyGrave: '`', + KeyComma: ',', + KeyPeriod: '.', + KeySlash: '/', + KeyCapsLock: 57357, + KeyPrtScr: 57361, + KeyScrLock: 57359, + KeyPause: 57362, + KeyNumLock: 57360, + KeyPadDiv: 57410, + KeyPadMul: 57411, + KeyPadSub: 57412, + KeyPadAdd: 57413, + KeyPadEnter: 57414, + KeyPad1: 57400, + KeyPad2: 57401, + KeyPad3: 57402, + KeyPad4: 57403, + KeyPad5: 57404, + KeyPad6: 57405, + KeyPad7: 57406, + KeyPad8: 57407, + KeyPad9: 57408, + KeyPad0: 57399, + KeyPadDec: 57409, + KeyIsoBackSlash: '\\', // TODO: does kitty have another mapping for this? + KeyMenu: 57363, + KeyPadEqual: 57415, + KeyF13: 57376, + KeyF14: 57377, + KeyF15: 57378, + KeyF16: 57379, + KeyF17: 57380, + KeyF18: 57381, + KeyF19: 57382, + KeyF20: 57383, + KeyF21: 57384, + KeyF22: 57385, + KeyF23: 57386, + KeyF24: 57387, // NB: F25 up through 35 are notionally supported by Kitty, but not by us + KeyPadComma: 57416, + KeyIsoSlash: '/', // Kitty cannot discriminate? + KeyYen: 'Β₯', + KeyLCtrl: 57442, + KeyLShift: 57441, + KeyLAlt: 57443, + KeyLMeta: 57444, + KeyRCtrl: 57448, + KeyRShift: 57447, + KeyRAlt: 57449, + KeyRMeta: 57450, + + // KeyHiragana: 0, // TBD + // KeyConvert: 0, // TBD + // KeyNonConvert: 0, // TD + + // Windows uses a bunch of HID usages from + // the consumer page (0x0c) for media playback, and + // other applications. We just ignore them. + } + + scanCodes = map[Key]ScanCode{ + KeyA: 0x1e, + KeyB: 0x30, + KeyC: 0x2e, + KeyD: 0x20, + KeyE: 0x12, + KeyF: 0x21, + KeyG: 0x22, + KeyH: 0x23, + KeyI: 0x17, + KeyJ: 0x24, + KeyK: 0x25, + KeyL: 0x26, + KeyM: 0x32, + KeyN: 0x31, + KeyO: 0x18, + KeyP: 0x19, + KeyQ: 0x10, + KeyR: 0x13, + KeyS: 0x1f, + KeyT: 0x14, + KeyU: 0x16, + KeyV: 0x2f, + KeyW: 0x11, + KeyX: 0x2d, + KeyY: 0x15, + KeyZ: 0x2c, + Key1: 0x02, + Key2: 0x03, + Key3: 0x04, + Key4: 0x05, + Key5: 0x06, + Key6: 0x07, + Key7: 0x08, + Key8: 0x09, + Key9: 0x0a, + Key0: 0x0b, + KeyEnter: 0x1c, + KeyEsc: 0x01, + KeyBackspace: 0x0e, + KeyTab: 0x0f, + KeySpace: 0x39, + KeyMinus: 0x0c, + KeyEqual: 0x0d, + KeyLBrace: 0x1a, + KeyRBrace: 0x1b, + KeyBackslash: 0x2b, + KeySemi: 0x27, + KeyQuote: 0x28, + KeyGrave: 0x29, + KeyComma: 0x33, + KeyPeriod: 0x34, + KeySlash: 0x35, + KeyCapsLock: 0x3a, + KeyF1: 0x3b, + KeyF2: 0x3c, + KeyF3: 0x3d, + KeyF4: 0x3e, + KeyF5: 0x3f, + KeyF6: 0x40, + KeyF7: 0x41, + KeyF8: 0x42, + KeyF9: 0x43, + KeyF10: 0x44, + KeyF11: 0x57, + KeyF12: 0x58, + KeyPrtScr: 0x54, + KeyScrLock: 0x46, + KeyPause: 0xe046, + KeyInsert: 0xe052, + KeyHome: 0xe047, + KeyPgUp: 0xe049, + KeyDelete: 0xe053, + KeyEnd: 0xe04f, + KeyPgDn: 0xe051, + KeyRight: 0xe04d, + KeyLeft: 0xe04b, + KeyDown: 0xe050, + KeyUp: 0xe048, + KeyNumLock: 0x45, + KeyPadDiv: 0xe035, + KeyPadMul: 0x37, + KeyPadSub: 0x4a, + KeyPadAdd: 0x4e, + KeyPadEnter: 0xe01c, + KeyPad1: 0x4f, + KeyPad2: 0x50, + KeyPad3: 0x51, + KeyPad4: 0x4b, + KeyPad5: 0x4c, + KeyPad6: 0x4d, + KeyPad7: 0x47, + KeyPad8: 0x48, + KeyPad9: 0x49, + KeyPad0: 0x52, + KeyPadDec: 0x53, + KeyIsoBackSlash: 0x56, + KeyPadEqual: 0x59, + KeyF13: 0x64, + KeyF14: 0x65, + KeyF15: 0x66, + KeyF16: 0x67, + KeyF17: 0x68, + KeyF18: 0x69, + KeyF19: 0x6a, + KeyF20: 0x6b, + KeyF21: 0x6c, + KeyF22: 0x6d, + KeyF23: 0x6e, + KeyF24: 0x76, + KeyPadComma: 0x7e, + KeyIsoSlash: 0x73, + KeyHiragana: 0x70, + KeyYen: 0x7d, + KeyConvert: 0x79, + KeyNonConvert: 0x7b, + KeyLCtrl: 0x1d, + KeyLShift: 0x2a, + KeyLAlt: 0x38, + KeyLMeta: 0xe05b, + KeyRCtrl: 0xe01d, + KeyRShift: 0x36, + KeyRAlt: 0xe038, + KeyRMeta: 0xe05c, + KeyMenu: 0xe05d, + + // Windows uses a bunch of HID usages from + // the consumer page (0x0c) for media playback, and + // other applications. We just ignore them. + } + + shiftedBaseKeys = map[BaseKey]rune{ + '`': '~', + '1': '!', + '2': '@', + '3': '#', + '4': '$', + '5': '%', + '6': '^', + '7': '&', + '8': '*', + '9': '(', + '0': ')', + '-': '_', + '=': '+', + 'Β₯': '|', + '[': '{', + ']': '}', + '\\': '|', + ';': ':', + '\'': '"', + ',': '<', + '.': '>', + '/': '?', + } +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/layout.go b/vendor/github.com/gdamore/tcell/v3/vt/layout.go new file mode 100644 index 000000000..7e8deb585 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/layout.go @@ -0,0 +1,713 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +import ( + "sort" + "sync" + "time" +) + +// This file defines the layout mechanism for keyboards. +// All keyboards are assumed to pass "codes" that are mapped to one of +// the Key values (this is easy for USB because the codes are mostly the +// same as USB already!), and then we look up values. This can be done +// using a simple map, and we allow inheritance so we don't have to redefine +// too many things. For complex scenarios you'll probably want to make use +// of operating system facilities or supply your own tables (for example for +// Japanese keyboards.) + +// ModifierMap is a map that represents keys that generate runes in various +// shift states (modifier states). A layout may have many of these, and they +// are searched until a match is fine. +type ModifierMap struct { + When func(Modifier) bool // Map only applies if this returns true + Map map[Key]rune // Map is the mapping from Key to specific rune when this map matches. +} + +// KeyboardState represents the current state of the keyboard. +// A zero initialized value is ready for use. Note that emulators that +// get the associated events from their operating system do not need to +// make use of this, but this structure makes it possible to build an emulator +// with a keyboard layout that is not known to the operating system. +// +// The keyboard state is assumed to be "single threaded", meaning only a single +// caller will operate on it at any given time. Typically there is just a single +// keyboard polling thread or goroutine. +type KeyboardState struct { + deadKey map[rune]DeadKey // current dead key state + mod Modifier + layout *Layout + lastKey Key // last key pressed + lastRune rune // last rune for last key + repeating bool // true if we are repeating + repeatStart time.Time // when we started repeating + repeatTime time.Time // last time we checked + repeatDelay time.Duration // delay before starting repeat + repeatInterval time.Duration // duration between repeats + pressed map[Key]bool + initialized bool +} + +// initialize the keyboard, lazily. +func (ks *KeyboardState) initialize() { + if !ks.initialized { + ks.pressed = make(map[Key]bool) + if ks.layout == nil { + ks.layout = KeyboardANSI + } + ks.repeatDelay = time.Millisecond * 250 + ks.repeatInterval = time.Millisecond * 30 + ks.initialized = true + } +} + +// reset the keyboard state. +func (ks *KeyboardState) reset() { + ks.clearRepeat() + ks.mod = 0 + ks.deadKey = nil + ks.pressed = make(map[Key]bool) +} + +// clear repeat clears any repeating key. +func (ks *KeyboardState) clearRepeat() { + ks.repeating = false + ks.repeatStart = time.Time{} + ks.repeatTime = time.Time{} + ks.lastRune = 0 + ks.lastKey = 0 +} + +// SetRepeat sets the repeat parameters. Note that this will only have any meaningful +// impact if the caller calls the Pressed function repeatedly (periodically) while +// a key is depressed. +// +// The repeat starts after a key has been held for for delay, with a new repeat +// added every interval. +// +// The caller should usually call this before processing keyboard events. It must +// not be called concurrently with either of the Pressed or Release functions. +func (ks *KeyboardState) SetRepeat(delay time.Duration, interval time.Duration) { + ks.initialize() + ks.repeatDelay = delay + ks.repeatInterval = interval + ks.clearRepeat() +} + +// SetLayout sets the layout this keyboard should use. +// This also resets the keyboard state. +func (ks *KeyboardState) SetLayout(km *Layout) { + ks.initialize() + ks.reset() + ks.layout = km +} + +// Pressed should be called when a given key is depressed. +func (ks *KeyboardState) Pressed(k Key) *KeyEvent { + ks.initialize() + event := &KeyEvent{ + Down: true, + Key: k, + SC: k.ScanCode(), + Base: k.KittyBase(), + Mod: ks.mod, + } + // if another key was pressed, then clear the repeat state + lastKey := ks.lastKey + if lastKey != k && ks.repeatInterval != 0 { + ks.clearRepeat() + ks.repeatStart = time.Now().Add(ks.repeatDelay) + ks.repeatTime = ks.repeatStart + } + wasPressed := ks.pressed[k] + ks.pressed[k] = true + ks.lastKey = k + + l := ks.layout + event.VK = l.Virtual[k] + if mod, ok := l.Locking[k]; ok { + // locking modifiers never repeat + if wasPressed { + return nil + } + if ks.mod&mod == 0 { + ks.mod |= mod + } else { + ks.mod &^= mod + } + ks.pressed[k] = true + event.Mod = ks.mod + return event + } + if mod, ok := l.Modifiers[k]; ok { + if wasPressed { + return nil + } + ks.mod |= mod + event.Mod = ks.mod + return event + } + + // attempt to look up the rune for this + r := l.KeyToUTF(k, ks.mod) + if ks.deadKey == nil && l.DeadKeys != nil && r != 0 { + if dk, ok := l.DeadKeys[r]; ok { + ks.deadKey = dk.Next + return event + } + } + + if dk := ks.deadKey; dk != nil { + if n, ok := dk[r]; ok { + if n.U != 0 { + event.Utf = string(n.U) + ks.lastRune = n.U + ks.deadKey = nil + } else { + ks.deadKey = n.Next + } + return event + } + // failed lookup - ignore it + ks.deadKey = nil + } + + if r != 0 { + event.Utf = string(r) + } + + if lastKey == k && wasPressed && ks.repeatInterval > 0 { + ks.repeating = true + if time.Now().After(ks.repeatStart) { + deltaT := time.Since(ks.repeatTime).Truncate(ks.repeatInterval) + event.Repeat = int(deltaT / ks.repeatInterval) + if ks.repeatTime == ks.repeatStart { + // fence post - count the first one! + event.Repeat++ + } + ks.repeatTime = ks.repeatTime.Add(deltaT) + // if we polled before the repeat interval then report nothing + if event.Repeat == 0 { + return nil + } + } + } + + return event +} + +// Released should be called when a given key is Released. +func (ks *KeyboardState) Released(k Key) *KeyEvent { + ks.initialize() + event := &KeyEvent{ + Down: false, + Key: k, + SC: k.ScanCode(), + Base: k.KittyBase(), + Mod: ks.mod, + } + if ks.lastKey == k { + ks.clearRepeat() + } + wasPressed := ks.pressed[k] + delete(ks.pressed, k) + + l := ks.layout + event.VK = l.Virtual[k] + + if mod, ok := ks.layout.Modifiers[k]; ok { + if !wasPressed { + // something weird + return nil + } + ks.mod &^= mod + + event.Mod = ks.mod + return event + } + + if _, ok := ks.layout.Locking[k]; !ok { + if r := l.KeyToUTF(k, ks.mod); r != 0 { + event.Utf = string(r) + } + } + + // no real point in looking up UTF for key release, so we don't + + return event +} + +// DeadKey is what happens when a dead key is pressed. Either it starts an unresolved sequence, +// (in which case Next will be non-nil), or it resolves to a final rune (in which case U will be non-zero) +// This is also sometimes called a composed key sequence. +type DeadKey struct { + Next map[rune]DeadKey // Next corresponds to the next key in the sequence for dead keys + U rune // U is the rune that should be emitted on completion of the sequence. +} + +// DeadRune is used internally to create a rune to represent a dead key. +// While any numbers can be used from this point on, the expectation is +// that this will be added to a smaller rune (such as an ASCII character) +// This rune value a bit inside the supplementary private use area B, +// in an attempt to minimize the chance of any conflicting use (for +// example nerd fonts.) +const DeadRune = 0x101000 + +// Layout is a structure that represents a keyboard layout. +// Applications or users may implement their own layouts by +// registering an instance of this. +type Layout struct { + // Name is the name of the keyboard layout. + // We prefer to use the same names that Microsoft uses for keyboard layouts. + Name string + + // Base is a base keyboard layout, so that we can simplify by only + // overriding keys we are are handling differently. + Base *Layout + + // DeadKeys maps specific starting keys, to an emitted rune. + // The keys should a rune value starting with DeadRune. + DeadKeys map[rune]DeadKey + + // Locking are modifiers that toggle a locked state like NumLock or CapsLock. + Locking map[Key]Modifier + + // Modifiers toggle a state, but only while the key is depressed. + Modifiers map[Key]Modifier + + // Virtual maps keys to virtual keys. + Virtual map[Key]WinVK + + // Maps is the list of key maps by modifier and mask. + // Use more specific masks first - for example NumLock + // mask might contain only the masks for the number keypad, + // and that should be listed before the maps for the rest + // of the keyboard. The algorithm searches for the first + // match, not the best match. + Maps []ModifierMap +} + +func (km *Layout) KeyToUTF(k Key, m Modifier) rune { + for _, mm := range km.Maps { + if mm.When != nil && !mm.When(m) { + continue + } + if u, ok := mm.Map[k]; ok { + return u + } + } + if km.Base != nil { + return km.Base.KeyToUTF(k, m) + } + return 0 +} + +// KeysUsLower is a list of lower case key maps. +var KeysUsLower = map[Key]rune{ + KeyA: 'a', + KeyB: 'b', + KeyC: 'c', + KeyD: 'd', + KeyE: 'e', + KeyF: 'f', + KeyG: 'g', + KeyH: 'h', + KeyI: 'i', + KeyJ: 'j', + KeyK: 'k', + KeyL: 'l', + KeyM: 'm', + KeyN: 'n', + KeyO: 'o', + KeyP: 'p', + KeyQ: 'q', + KeyR: 'r', + KeyS: 's', + KeyT: 't', + KeyU: 'u', + KeyV: 'v', + KeyW: 'w', + KeyX: 'x', + KeyY: 'y', + KeyZ: 'z', +} + +// KeysUsUpper is a list of upper case key maps. +var KeysUsUpper = map[Key]rune{ + KeyA: 'A', + KeyB: 'B', + KeyC: 'C', + KeyD: 'D', + KeyE: 'E', + KeyF: 'F', + KeyG: 'G', + KeyH: 'H', + KeyI: 'I', + KeyJ: 'J', + KeyK: 'K', + KeyL: 'L', + KeyM: 'M', + KeyN: 'N', + KeyO: 'O', + KeyP: 'P', + KeyQ: 'Q', + KeyR: 'R', + KeyS: 'S', + KeyT: 'T', + KeyU: 'U', + KeyV: 'V', + KeyW: 'W', + KeyX: 'X', + KeyY: 'Y', + KeyZ: 'Z', +} + +// KeysDigits is a map of number keys to corresponding digits. +var KeysDigits = map[Key]rune{ + Key1: '1', + Key2: '2', + Key3: '3', + Key4: '4', + Key5: '5', + Key6: '6', + Key7: '7', + Key8: '8', + Key9: '9', + Key0: '0', +} + +// KeysPadDigits is a map of the digits on the numeric keypad, +// when num lock is engaged. +var KeysPadDigits = map[Key]rune{ + KeyPad0: '0', + KeyPad1: '1', + KeyPad2: '2', + KeyPad3: '3', + KeyPad4: '4', + KeyPad5: '5', + KeyPad6: '6', + KeyPad7: '7', + KeyPad8: '8', + KeyPad9: '9', + KeyPadDec: '.', +} + +var KeysPadOps = map[Key]rune{ + KeyPadMul: '*', + KeyPadAdd: '+', + KeyPadSub: '-', + KeyPadDiv: '/', +} + +// KeyboardANSI is the base PC keyboard used in ANSI (US) systems. +var KeyboardANSI = &Layout{ + Name: "US", + + Base: nil, + + // Virtual maps physical keys to virtual keys. + Virtual: map[Key]WinVK{ + KeyEsc: VkEscape, + KeyF1: VkF1, + KeyF2: VkF2, + KeyF3: VkF3, + KeyF4: VkF4, + KeyF5: VkF5, + KeyF6: VkF6, + KeyF7: VkF7, + KeyF8: VkF8, + KeyF9: VkF9, + KeyF10: VkF10, + KeyF11: VkF11, + KeyF12: VkF12, + KeyF13: VkF13, + KeyF14: VkF14, + KeyF15: VkF15, + KeyF16: VkF16, + KeyF17: VkF17, + KeyF18: VkF18, + KeyF19: VkF19, + KeyF20: VkF20, + KeyF21: VkF21, + KeyF22: VkF22, + KeyF23: VkF23, + KeyF24: VkF24, + KeyPrtScr: VkSnapshot, + KeyScrLock: VkScroll, + KeyPause: VkPause, + KeyInsert: VkInsert, + KeyDelete: VkDelete, + KeyHome: VkHome, + KeyEnd: VkEnd, + KeyPgUp: VkPrior, + KeyPgDn: VkNext, + KeyLeft: VkLeft, + KeyRight: VkRight, + KeyUp: VkUp, + KeyDown: VkDown, + KeyNumLock: VkNumLock, + KeyCapsLock: VkCapital, + KeyLShift: VkLShift, + KeyLCtrl: VkLControl, + KeyLMeta: VkLWin, + KeyLAlt: VkLMenu, + KeyRShift: VkRShift, + KeyRCtrl: VkRControl, + KeyRMeta: VkRWin, + KeyRAlt: VkRMenu, + KeyMenu: VkApps, + KeyConvert: VkConvert, + KeyNonConvert: VkNonConvert, + KeyBackspace: VkBack, + KeyEnter: VkReturn, + KeySpace: VkSpace, + KeyTab: VkTab, + Key1: Vk1, + Key2: Vk2, + Key3: Vk3, + Key4: Vk4, + Key5: Vk5, + Key6: Vk6, + Key7: Vk7, + Key8: Vk8, + Key9: Vk9, + Key0: Vk0, + KeyA: VkA, + KeyB: VkB, + KeyC: VkC, + KeyD: VkD, + KeyE: VkE, + KeyF: VkF, + KeyG: VkG, + KeyH: VkH, + KeyI: VkI, + KeyJ: VkJ, + KeyK: VkK, + KeyL: VkL, + KeyM: VkM, + KeyN: VkN, + KeyO: VkO, + KeyP: VkP, + KeyQ: VkQ, + KeyR: VkR, + KeyS: VkS, + KeyT: VkT, + KeyU: VkU, + KeyV: VkV, + KeyW: VkW, + KeyX: VkX, + KeyY: VkY, + KeyZ: VkZ, + KeyPadMul: VkMultiply, + KeyPadAdd: VkAdd, + KeyPadSub: VkSubtract, + KeyPadDiv: VkDivide, + KeyEqual: VkOemPlus, + KeyComma: VkOemComma, + KeyMinus: VkOemMinus, + KeyPeriod: VkOemPeriod, + KeySlash: VkOem2, + KeyGrave: VkOem3, + KeyLBrace: VkOem4, + KeyBackslash: VkOem5, + KeyRBrace: VkOem6, + KeyQuote: VkOem7, + KeyIsoBackSlash: VkOem102, + KeyPad0: VkInsert, + KeyPad1: VkEnd, + KeyPad2: VkDown, + KeyPad3: VkNext, + KeyPad4: VkLeft, + KeyPad5: VkClear, + KeyPad6: VkRight, + KeyPad7: VkHome, + KeyPad8: VkUp, + KeyPad9: VkPrior, + KeyPadDec: VkDelete, + }, + Maps: []ModifierMap{ + // Specials - without control + { + When: func(m Modifier) bool { return !m.IsCtrl() }, + Map: map[Key]rune{ + KeyTab: '\t', + KeyEnter: '\r', + KeyBackspace: '\b', + KeyEsc: '\x1b', + KeySpace: ' ', + KeyPadEnter: '\r', + }, + }, + // Specials - with control (but without shift) + { + When: func(m Modifier) bool { return m.IsCtrl() && !m.IsShift() }, + Map: map[Key]rune{ + KeyTab: '\t', + KeyEnter: '\n', + KeyBackspace: '\x7f', + KeyEsc: '\x1b', + KeySpace: ' ', + KeyPadEnter: '\n', + }, + }, + // Key pad operators + { + When: func(m Modifier) bool { return !m.IsAlt() }, + Map: KeysPadOps, + }, + // Numeric keypad when num lock is engaged + { + When: func(m Modifier) bool { return m.IsNumLock() }, + Map: KeysPadDigits, + }, + // Numbers - without shift + { + When: func(m Modifier) bool { return !m.IsShift() && !m.IsCtrl() }, + Map: KeysDigits, + }, + // Numbers - with shift - this is locale sensitive usually + { + When: func(m Modifier) bool { return m.IsShift() && !m.IsCtrl() }, + Map: map[Key]rune{ + Key1: '!', + Key2: '@', + Key3: '#', + Key4: '$', + Key5: '%', + Key6: '^', + Key7: '&', + Key8: '*', + Key9: '(', + Key0: ')', + }, + }, + // Special shift-control cases + { + When: func(m Modifier) bool { return m.IsCtrl() && m.IsShift() }, + Map: map[Key]rune{ + Key2: 0, + Key6: '\x1e', + KeyMinus: '\x1f', + }, + }, + // Letters - base (lower case) + { + When: func(m Modifier) bool { return !m.IsCtrl() && !m.IsCapitals() }, + Map: KeysUsLower, + }, + // Letters - capitals (either caps lock or shift, but not both) + { + When: func(m Modifier) bool { return !m.IsCtrl() && m.IsCapitals() }, + Map: KeysUsUpper, + }, + // OEM keys - base + { + When: func(m Modifier) bool { return !m.IsShift() && !m.IsCtrl() }, + Map: map[Key]rune{ + KeySemi: ';', + KeyEqual: '=', + KeyComma: ',', + KeyMinus: '-', + KeyPeriod: '.', + KeySlash: '/', + KeyGrave: '`', + KeyLBrace: '[', + KeyBackslash: '\\', + KeyRBrace: ']', + KeyQuote: '\'', + KeyIsoBackSlash: '\\', + }, + }, + // OEM keys - shift + { + When: func(m Modifier) bool { return m.IsShift() && !m.IsCtrl() }, + Map: map[Key]rune{ + KeySemi: ':', + KeyEqual: '+', + KeyComma: '<', + KeyMinus: '_', + KeyPeriod: '>', + KeySlash: '?', + KeyGrave: '~', + KeyLBrace: '{', + KeyBackslash: '|', + KeyRBrace: '}', + KeyQuote: '"', + KeyIsoBackSlash: '|', + }, + }, + // OEM keys - control (odd balls) + { + When: func(m Modifier) bool { return m.IsCtrl() && !m.IsShift() }, + Map: map[Key]rune{ + KeyLBrace: '\x1b', + KeyBackslash: '\x1c', + KeyRBrace: '\x1d', + KeyIsoBackSlash: '\x1c', + }, + }, + }, + Modifiers: map[Key]Modifier{ + KeyLShift: ModLShift, + KeyRShift: ModRShift, + KeyLCtrl: ModLCtrl, + KeyRCtrl: ModRCtrl, + KeyLAlt: ModLAlt, + KeyRAlt: ModRAlt, + KeyRMeta: ModRMeta, + KeyLMeta: ModLMeta, + KeyRHyper: ModRHyper, + KeyLHyper: ModLHyper, + }, + Locking: map[Key]Modifier{ + KeyNumLock: ModNumLock, + KeyCapsLock: ModCapsLock, + }, +} + +var allLayouts = map[string]*Layout{ + KeyboardANSI.Name: KeyboardANSI, +} + +var layoutsLock sync.Mutex + +// RegisterLayout registers the given layout. +func RegisterLayout(km *Layout) { + layoutsLock.Lock() + allLayouts[km.Name] = km + layoutsLock.Unlock() +} + +// GetLayout returns a keyboard layout for the given name. +// The layout must have been previously registered with RegisterLayout. +// (Builtin layouts do this as a consequence of importing the layout.) +func GetLayout(name string) *Layout { + layoutsLock.Lock() + defer layoutsLock.Unlock() + return allLayouts[name] +} + +// Layouts returns a list of all known layout names. +func Layouts() []string { + layoutsLock.Lock() + defer layoutsLock.Unlock() + res := make([]string, 0, len(allLayouts)) + for k := range allLayouts { + res = append(res, k) + } + sort.Strings(res) + return res +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/mock.go b/vendor/github.com/gdamore/tcell/v3/vt/mock.go new file mode 100644 index 000000000..156013ea1 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/mock.go @@ -0,0 +1,676 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt + +import ( + "slices" + "sync" + "time" + + "github.com/gdamore/tcell/v3/color" + "github.com/gdamore/tcell/v3/tty" +) + +// mockTerm implements MockTerm. +type mockTerm struct { + mb MockBackend + em Emulator + ks *KeyboardState +} + +// Stop the terminal. +func (mt *mockTerm) Stop() error { + return mt.em.Stop() +} + +// Start the terminal. +func (mt *mockTerm) Start() error { + return mt.em.Start() +} + +// Drain all output from the terminal, ensuring +// any queued commands are processed. +func (mt *mockTerm) Drain() error { + return mt.em.Drain() +} + +// Read data from the terminal. This is called by a terminal +// application (e.g. via tcell Tty.) Read data will include +// key strokes, mouse events, and responses to terminal queries. +func (mt *mockTerm) Read(data []byte) (int, error) { + return mt.em.Read(data) +} + +// Write data to the terminal, typically either commands or data +// that should be displayed on the virtual screen. +func (mt *mockTerm) Write(b []byte) (n int, err error) { + return mt.em.Write(b) +} + +// WindowSize obtains the dimensions of the window. +func (mt *mockTerm) WindowSize() (tty.WindowSize, error) { + sz := mt.mb.GetSize() + // No pixel sizes for now + return tty.WindowSize{Width: int(sz.X), Height: int(sz.Y)}, nil +} + +// NotifyResize registers a channel to be signaled when a resize has occurred. +// In real terminal emulators this would be posted (non-blocking) by a signal handler. +func (mt *mockTerm) NotifyResize(resizeq chan<- bool) { + if rs, ok := mt.mb.(Resizer); ok { + rs.NotifyResize(resizeq) + } +} + +// Close closes the terminal, after which it should no longer be used. Stop is implied. +func (mt *mockTerm) Close() error { + return mt.Stop() +} + +// Pos returns the cursor position. +func (mt *mockTerm) Pos() Coord { + return mt.mb.GetPosition() +} + +// GetCell returns the contents of the cell at the given coordinates, or a zero value +// if the coordinates are out of range. +func (mt *mockTerm) GetCell(pos Coord) Cell { + return mt.mb.GetCell(pos) +} + +// Bells counts the number of times the bell has rung. +func (mt *mockTerm) Bells() int { + return mt.mb.Bells() +} + +// KeyEvent is used to inject a key event. Call this to inject +// a synthetic, fully specified key event. Most uses should just use +// the KeyPress, KeyRelease, or even simpler KeyTap APIs. +func (mt *mockTerm) KeyEvent(ev KeyEvent) { + mt.em.KeyEvent(ev) + if ev.Key == KeyEsc { + // Inject a delay to simulate human typing. + // Necessary to disambiguate Escape from other sequences. + time.Sleep(time.Millisecond * 150) + } +} + +// KeyPress implements MockTerm.KeyPress. +func (mt *mockTerm) KeyPress(k Key) { + if event := mt.ks.Pressed(k); event != nil { + mt.KeyEvent(*event) + } +} + +// KeyRelease implements MockTerm.KeyRelease. +func (mt *mockTerm) KeyRelease(k Key) { + if event := mt.ks.Released(k); event != nil { + mt.KeyEvent(*event) + } +} + +// KeyTap implements MockTerm.KeyTap. +func (mt *mockTerm) KeyTap(keys ...Key) { + for _, k := range keys { + mt.KeyPress(k) + } + for _, k := range slices.Backward(keys) { + mt.KeyRelease(k) + } +} + +// SetRepeat sets the repeat interval for the keyboard. +// Set the interval to zero to disable repeat. +func (mt *mockTerm) SetRepeat(delay, interval time.Duration) { + mt.ks.SetRepeat(delay, interval) +} + +// MouseEvent implements MockTerm.MouseEvent. +func (mt *mockTerm) MouseEvent(ev MouseEvent) { + mt.em.MouseEvent(ev) +} + +// FocusEvent implements MockTerm.FocusEvent. +func (mt *mockTerm) FocusEvent(focused bool) { + mt.em.FocusEvent(focused) +} + +// GetTitle returns the current window title. +func (mt *mockTerm) GetTitle() string { + return mt.mb.GetTitle() +} + +// SetSize is used to change the terminal size. +func (mt *mockTerm) SetSize(size Coord) { + mt.mb.SetSize(size) + mt.em.ResizeEvent(size) +} + +// Backend returns the backend for testing. +func (mt *mockTerm) Backend() MockBackend { + return mt.mb +} + +// SendRaw is used to inject raw bytes to the read stream of the app. +// Use this for fuzz testing. +func (mt *mockTerm) SendRaw(data []byte) { + mt.em.SendRaw(data) +} + +// SetLayout sets the keyboard layout. +func (mt *mockTerm) SetLayout(km *Layout) { + mt.ks.SetLayout(km) +} + +// MockTerm is a mock terminal (emulator). It can be used to +// test the emulator itself, or to test applications (or tcell) that +// uses the terminal. It also implements the Tty interface used +// by tcell itself. +type MockTerm interface { + tty.Tty + + // Pos reports the current cursor position. + Pos() Coord + + // GetCell returns the cell at the given coordinates. + // The coordinates must be valid. + GetCell(Coord) Cell + + // Bells returns the number of times the bell has been rung. + Bells() int + + // Inject a keyboard event - this is a full event, and bypasses + // the layout and keyboard state processor. + KeyEvent(KeyEvent) + + // Inject a key press. + KeyPress(Key) + + // Inject a key release. + KeyRelease(Key) + + // SetRepeat configures keyboard repeating. Repeat keystrokes + // will be assumed after the key has been held for at least delay, + // with new keys added each interval. + SetRepeat(delay, interval time.Duration) + + // Inject one or more key press and releases. + // The keys are pressed in the order, and released in reverse order. + // Thus modifiers should be listed first. This should not be used + // to simulate typing a sequence (e.g. a word), but if you wanted to + // test say N-Key rollover you could do that here. + KeyTap(...Key) + + // Inject a mouse event. + MouseEvent(MouseEvent) + + // Inject a focus event. + FocusEvent(bool) + + // GetTitle obtains the current window title. + GetTitle() string + + // SetSize is used to resize the terminal. + SetSize(Coord) + + // SendRaw is used to send raw data to the application. + // This is mostly intended to facilitate fuzz testing the application. + SendRaw([]byte) + + // Backend returns the backend (used for testing). + Backend() MockBackend + + // SetLayout sets the keyboard layout to use. + // If not specified, a US standard ANSI keyboard will be assumed. + SetLayout(*Layout) +} + +type noMockBlit struct { + MockBackend + Blit struct{} // prevents use as Blitter +} + +// NewMockTerm gives a mock terminal emulator. +func NewMockTerm(opts ...MockOpt) MockTerm { + mt := &mockTerm{} + mt.mb = NewMockBackend(opts...) + var be MockBackend = mt.mb + for _, o := range opts { + switch o.(type) { + case MockOptNoBlit: + be = &noMockBlit{be, struct{}{}} + } + } + mt.em = NewEmulator(be) + mt.em.SetId("TCellMock", "1.0") + mt.ks = &KeyboardState{} + return mt +} + +// MockBackend provides additional mock-specific capabilities on top of Backend. +// This is meant to facilitate test cases +type MockBackend interface { + Backend + + // GetCell returns the cell at the given position, or an empty cell if the + // position is out of the bounds of the window. + GetCell(Coord) Cell + + // Bells counts the number of bells rung. + Bells() int + + // GetTitle gets the current window title. + GetTitle() string + + // SetSize is used to resize the window. + // Newly added cells are empty, and content in old cells that out of range is lost. + SetSize(Coord) + + // GetCursor is used to obtain the current cursor style. + GetCursor() CursorStyle + + // SetClipboard sets the clipboard contents (copy buffer). + SetClipboard([]byte) + + // GetClipboard returns the clipboard (copy buffer). + GetClipboard() []byte + + // IsAdvancedKeyboard returns true, as we always support the full keyboard protocol. + IsAdvancedKeyboard() bool +} + +// mockBackend is a mock of a backend device for use with the emulator. +// It implements the following interfaces: +// vt.Backend, vt.Beeper, vt.Colorer, vt.Titler, vt.Resizer, vt.Blitter +type mockBackend struct { + cells []Cell // Content of cells + size Coord + pos Coord + colors int + style Style + defaultStyle Style + notifyQ chan<- bool + resized bool + newSize Coord + modes map[PrivateMode]ModeStatus + bells int + errs int + title string + clipboard []byte + cursor CursorStyle + lock sync.Mutex +} + +func (mb *mockBackend) GetSize() Coord { + mb.lock.Lock() + defer mb.lock.Unlock() + mb.checkSize() + return mb.size +} + +func (mb *mockBackend) Beep() { + mb.lock.Lock() + mb.bells++ + mb.lock.Unlock() +} + +func (mb *mockBackend) SetMouse(MouseReporting) {} + +func (mb *mockBackend) GetPrivateMode(pm PrivateMode) ModeStatus { + mb.lock.Lock() + defer mb.lock.Unlock() + // note default (zero) value is ModeNA + return mb.modes[pm] +} + +func (mb *mockBackend) SetPrivateMode(pm PrivateMode, status ModeStatus) error { + mb.lock.Lock() + defer mb.lock.Unlock() + if old := mb.modes[pm]; old == ModeOn || old == ModeOff { + if status == ModeOn || status == ModeOff { + mb.modes[pm] = status + } else { + mb.errs++ + } + } else { + mb.errs++ + } + return nil +} + +func (mb *mockBackend) Put(pos Coord, cell Cell) { // grapheme string, width int, style Style) { + mb.lock.Lock() + defer mb.lock.Unlock() + mb.checkSize() + + if index := mb.index(pos); index >= 0 { + mb.cells[index] = cell + + // writing to a cell right after a wide + // character clears that wide character (but leaves style/attributes) + if cell.W > 0 && pos.X > 0 && mb.cells[index-1].W > 1 { + mb.cells[index-1].C = "" + mb.cells[index-1].W = 0 + } + + // wide characters delete the next cell + if cell.W == 2 && pos.X < mb.size.X-1 { + mb.cells[index+1].C = "" + mb.cells[index+1].W = 0 + mb.cells[index+1].S = cell.S + } + } else { + mb.errs++ + } +} + +func (mb *mockBackend) isPositionValid(pos Coord) bool { + mb.checkSize() + + return pos.X < mb.size.X && pos.Y < mb.size.Y && pos.X >= 0 && pos.Y >= 0 +} + +// index calculates the index in the cells array. If the coordinates are invalid, +// -1 will be returned. +func (mb *mockBackend) index(pos Coord) int { + mb.checkSize() + + if !mb.isPositionValid(pos) { + return -1 + } + return int(pos.X) + int(pos.Y)*int(mb.size.X) +} + +func (mb *mockBackend) GetCell(pos Coord) Cell { + mb.lock.Lock() + defer mb.lock.Unlock() + + if index := mb.index(pos); index >= 0 { + return mb.cells[index] + } + return Cell{S: BaseStyle} +} + +func (mb *mockBackend) Bells() int { + mb.lock.Lock() + defer mb.lock.Unlock() + return mb.bells +} + +func (mb *mockBackend) GetPosition() Coord { + mb.lock.Lock() + defer mb.lock.Unlock() + mb.checkSize() + return mb.pos +} + +func (mb *mockBackend) SetPosition(pos Coord) { + mb.lock.Lock() + defer mb.lock.Unlock() + mb.checkSize() + pos.X = min(mb.size.X-1, max(0, pos.X)) + pos.Y = min(mb.size.Y-1, max(0, pos.Y)) + mb.pos = pos +} + +func (mb *mockBackend) Colors() int { + return mb.colors +} + +func (mb *mockBackend) SetStyle(style Style) { + mb.lock.Lock() + defer mb.lock.Unlock() + + mb.style = style +} + +// SetWindowTitle implements the Titler interface. +func (mb *mockBackend) SetWindowTitle(title string) { + mb.lock.Lock() + defer mb.lock.Unlock() + + mb.title = title +} + +// GetTitle allows test code to observe what was set with SetWindowTitle. +func (mb *mockBackend) GetTitle() string { + mb.lock.Lock() + defer mb.lock.Unlock() + + return mb.title +} + +// NotifyResize registers a channel to be written to (non-blocking) if the +// backend changes size. +func (mb *mockBackend) NotifyResize(rq chan<- bool) { + mb.lock.Lock() + defer mb.lock.Unlock() + + mb.notifyQ = rq +} + +// checkSize performs a possible terminal resize. Cells that are +// added are treated as empty, while cells that are removed are just lost. +// (Note that at least one other emulator erases content on a resize. There is no +// standard for what to do here.) This is done inline when calculating the index. +// The caller is expected to hold mb.lock. +func (mb *mockBackend) checkSize() { + if !mb.resized { + return + } + size := mb.newSize + old := mb.cells + ox := int(mb.size.X) + oy := int(mb.size.Y) + nx := int(size.X) + ny := int(size.Y) + cells := make([]Cell, int(size.Y)*int(size.X)) + for i := range cells { + cells[i].S = BaseStyle + } + for y := range min(ny, oy) { + for x := range min(nx, ox) { + cells[y*nx+x] = old[y*ox+x] + } + } + mb.cells = cells + mb.size = size + mb.pos.X = min(mb.pos.X, size.X-1) + mb.pos.Y = min(mb.pos.Y, size.Y-1) + mb.resized = false +} + +func (mb *mockBackend) RaiseResize() { + mb.lock.Lock() + defer mb.lock.Unlock() + + if rq := mb.notifyQ; rq != nil { + select { + case rq <- true: + default: + } + } +} + +// SetSize is used to change the size of the virtual terminal. +func (mb *mockBackend) SetSize(size Coord) { + mb.lock.Lock() + mb.resized = true + mb.newSize = size + mb.lock.Unlock() +} + +// Reset the terminal to startup defaults. +func (mb *mockBackend) Reset() { + mb.lock.Lock() + defer mb.lock.Unlock() + + mb.style = mb.defaultStyle + + mb.title = "" + mb.errs = 0 + mb.bells = 0 + mb.pos = Coord{X: 0, Y: 0} + mb.modes[PmShowCursor] = ModeOn + mb.modes[PmBlinkCursor] = ModeOn + mb.modes[PmGraphemeClusters] = ModeOff +} + +func (mb *mockBackend) Blit(src, dst, dim Coord) { + mb.lock.Lock() + defer mb.lock.Unlock() + + mb.checkSize() + + // clip to visible source + if dim.X+src.X > mb.size.X { + dim.X = mb.size.X - src.X + } + if dim.Y+src.Y > mb.size.Y { + dim.Y = mb.size.Y - src.Y + } + // and clip to final destination + if dim.X+dst.X > mb.size.X { + dim.X = mb.size.X - dst.X + } + if dim.Y+dst.Y > mb.size.Y { + dim.Y = mb.size.Y - dst.Y + } + + // gap represents decrement when shifting to the next row -- + // skipping over the irrelevant cells. (The increment in the + // index when going from last cell of row to first cell of next row, + // or vice versa.) + gap := int(mb.size.X - dim.X) + + // the following logic is carefully constructed to avoid expensive + // operations in the loops (only addition or subtraction) + if mb.index(src) > mb.index(dst) { // source appears later, so we can forward copy + si := mb.index(src) + di := mb.index(dst) + for range dim.Y { + for range dim.X { + mb.cells[di] = mb.cells[si] + di++ + si++ + } + // advance to next row + si += gap + di += gap + } + } else { // source appears earlier, so we have to reverse copy + src.Y += dim.Y - 1 + dst.Y += dim.Y - 1 + src.X += dim.X - 1 + dst.X += dim.X - 1 + si := mb.index(src) + di := mb.index(dst) + + for range dim.Y { + for range dim.X { + mb.cells[di] = mb.cells[si] + si-- + di-- + } + si -= gap + di -= gap + } + } +} + +// Buffering is not supported by the mockBackend, and there is little point in it. +func (mb *mockBackend) Buffering(bool) {} + +// SetCursor is used to set how the cursor is displayed. +func (mb *mockBackend) SetCursor(cs CursorStyle) { + mb.lock.Lock() + defer mb.lock.Unlock() + mb.cursor = cs +} + +// GetCursor returns the current cursor style. +func (mb *mockBackend) GetCursor() CursorStyle { + mb.lock.Lock() + defer mb.lock.Unlock() + return mb.cursor +} + +// SetClipboard sets the current clipboard contents. +func (mb *mockBackend) SetClipboard(data []byte) { + mb.lock.Lock() + defer mb.lock.Unlock() + mb.clipboard = data +} + +// GetClipboard gets the current clipboard contents. +func (mb *mockBackend) GetClipboard() []byte { + mb.lock.Lock() + defer mb.lock.Unlock() + return mb.clipboard +} + +// IsAdvancedKeyboard returns true - we always implement +// the raw keyboard protocol. +func (mb *mockBackend) IsAdvancedKeyboard() bool { return true } + +// MockOpt is an interface by which options can change the behavior of the mocked terminal. +// This is intended to permit easier testing. +type MockOpt interface{ SetMockOpt(mb *mockBackend) } + +// MockOptSize changes the default terminal size, which is normally 80x24. +type MockOptSize Coord + +func (o MockOptSize) SetMockOpt(mb *mockBackend) { mb.size = Coord(o) } + +// MockOptColors changes the number of colors the terminal supports. +type MockOptColors int + +func (o MockOptColors) SetMockOpt(mb *mockBackend) { mb.colors = int(o) } + +// MockOptNoBlit suppresses the blitter interface. +type MockOptNoBlit struct{} + +func (MockOptNoBlit) SetMockOpt(mb *mockBackend) {} + +// NewMockBackend returns a MockBackend modified by the given options. +// The default is a fully featured 256-color backend with initial size 80x24. +func NewMockBackend(options ...MockOpt) MockBackend { + mb := &mockBackend{ + size: Coord{X: 80, Y: 24}, + colors: 256, + style: BaseStyle, + defaultStyle: BaseStyle.WithFg(color.Silver).WithBg(color.Black), + cursor: BlinkingBlock, + } + + for _, opt := range options { + opt.SetMockOpt(mb) + } + + if mb.colors > 0 { + mb.style = mb.defaultStyle + } + mb.cells = make([]Cell, int(mb.size.X)*int(mb.size.Y)) + for i := range mb.cells { + mb.cells[i].S = BaseStyle + } + + mb.modes = make(map[PrivateMode]ModeStatus) + mb.modes[PmShowCursor] = ModeOn + mb.modes[PmBlinkCursor] = ModeOn + mb.modes[PmGraphemeClusters] = ModeOff + mb.modes[PmSyncOutput] = ModeOff + return mb +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/mode.go b/vendor/github.com/gdamore/tcell/v3/vt/mode.go new file mode 100644 index 000000000..9d143fec4 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/mode.go @@ -0,0 +1,120 @@ +// Copyright 2026 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt provides common definitions for VT derived terminals and applications. +// This includes the venerable VT100, XTerm, and newer emulators such as Kitty and +// the Windows Terminal. +package vt + +import "fmt" + +// PrivateMode describes a DEC Private Mode. +type PrivateMode int + +const ( + PmAppCursor PrivateMode = 1 // Application cursor keys. + PmVT52 PrivateMode = 2 // Clear to enable VT52 compatibility (not supported). + PmColumns PrivateMode = 3 // Set to enable 132 columns, reset for 80 columns. + PmScrolling PrivateMode = 4 // Smooth scrolling (jump by default). + PmScreen PrivateMode = 5 // Set to reverse dark and light on screen. + PmOrigin PrivateMode = 6 // Coordinates are relative to margins. + PmAutoMargin PrivateMode = 7 // Automatically wrap at margin. + PmAutoRepeat PrivateMode = 8 // Enable automatic key repeat. + PmMouseX10 PrivateMode = 9 // Legacy (X10) mouse reporting. + PmBlinkCursor PrivateMode = 12 // Blinking (on) or steady (off) cursor. + PmPrintFF PrivateMode = 18 // Print form feed after printing screen. + PmPrintExtent PrivateMode = 19 // Print full screen (on) or scrolling region (off). + PmShowCursor PrivateMode = 25 // Show the cursor (default on). + PmCharSet PrivateMode = 42 // Enable national (on) or multinational (off) character sets. + PmLeftRightMargin PrivateMode = 69 // Enable left and right margins + PmMouseButton PrivateMode = 1000 // Report mouse button events. + PmMouseDrag PrivateMode = 1002 // Report mouse motion events when button depressed, requires PmMouseButton. + PmMouseMotion PrivateMode = 1003 // Report mouse motion events, requires PmMouseButton. + PmFocusReports PrivateMode = 1004 // Send focus gained or lost reports. + PmMouseSgr PrivateMode = 1006 // Use SGR sequences for mouse reports. + PmMouseSgrPixel PrivateMode = 1016 // Use SGR sequences for mouse reports, using pixel-level coordinates. + PmAltScreen PrivateMode = 1049 // 47 and 1047 are alternates, but we use 1049 + PmBracketedPaste PrivateMode = 2004 // Bracket pasted text with bracketed paste escape sequences. + PmSyncOutput PrivateMode = 2026 // Buffer output when enabled, updating screen when reset. + PmGraphemeClusters PrivateMode = 2027 // Support for grapheme cluster handling. + PmResizeReports PrivateMode = 2048 // Send in-band resize reports. + PmWin32Input PrivateMode = 9001 // Use Win32-Input-Mode for keyboard reports +) + +// Enable returns the string used to enable this private mode. +func (pm PrivateMode) Enable() string { + return fmt.Sprintf("\x1b[?%dh", pm) +} + +// Disable returns the string used to disable this private mode. +func (pm PrivateMode) Disable() string { + return fmt.Sprintf("\x1b[?%dl", pm) +} + +// Query returns the string used to query the state of this private mode. +func (pm PrivateMode) Query() string { + return fmt.Sprintf("\x1b[?%d$p", pm) +} + +// Reply returns a string representing a query reply for the given mode and status. +func (pm PrivateMode) Reply(status ModeStatus) string { + return fmt.Sprintf("\x1b[?%d;%d$y", pm, status) +} + +// ModeStatus represents the status of the mode. +type ModeStatus int + +// AnsiMode are modes standardized in ECMA-48. +// They use CSI-h and CSI-l (no question mark). +type AnsiMode int + +// Enable returns the string used to enable this ANSI mode. +func (pm AnsiMode) Enable() string { + return fmt.Sprintf("\x1b[%dh", pm) +} + +// Disable returns the string used to disable this ANSI mode. +func (pm AnsiMode) Disable() string { + return fmt.Sprintf("\x1b[%dl", pm) +} + +// Query returns the string used to query the state of this ANSI mode. +func (pm AnsiMode) Query() string { + return fmt.Sprintf("\x1b[%d$p", pm) +} + +// Reply returns a string representing a query reply for the given mode and status. +func (pm AnsiMode) Reply(status ModeStatus) string { + return fmt.Sprintf("\x1b[%d;%d$y", pm, status) +} + +const ( + AmKeyboardAction AnsiMode = 2 // Lock the keyboard. + AmInsertReplace AnsiMode = 4 // Insert or replace characters when a new character is added. + AmSendReceive AnsiMode = 12 // XON or XOFF. + AmNewLineMode AnsiMode = 20 // If true, LF emits CR as well, and Return sends both CR and LF. +) + +const ( + ModeNA ModeStatus = 0 // Mode is not supported (or unknown) + ModeOn ModeStatus = 1 // Mode is on (e.g. via CSI-h) + ModeOff ModeStatus = 2 // Mode is off (e.g. via CSI-l) + ModeOnLocked ModeStatus = 3 // Mode is hardwired on + ModeOffLocked ModeStatus = 4 // Mode is hardwired off +) + +// Changeable indicates that the mode may be changed. +func (ms ModeStatus) Changeable() bool { + return ms == ModeOn || ms == ModeOff +} diff --git a/vendor/github.com/gdamore/tcell/v3/vt/vt.go b/vendor/github.com/gdamore/tcell/v3/vt/vt.go new file mode 100644 index 000000000..838a02bdb --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v3/vt/vt.go @@ -0,0 +1,21 @@ +// Copyright 2025 The TCell Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this 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 vt provides common definitions for VT derived terminals and applications. +// This includes the venerable VT100, XTerm, and newer emulators such as Kitty and +// the Windows Terminal. +// +// This package is still under development and direct access to any of the interfaces +// here is not guaranteed to be stable yet. Caveat emptor. +package vt diff --git a/vendor/github.com/gdamore/tcell/v2/terms_default.go b/vendor/github.com/gdamore/tcell/v3/vt/width.go similarity index 55% rename from vendor/github.com/gdamore/tcell/v2/terms_default.go rename to vendor/github.com/gdamore/tcell/v3/vt/width.go index fefcf8938..5097b1ef7 100644 --- a/vendor/github.com/gdamore/tcell/v2/terms_default.go +++ b/vendor/github.com/gdamore/tcell/v3/vt/width.go @@ -1,11 +1,8 @@ -//go:build !tcell_minimal -// +build !tcell_minimal - -// Copyright 2019 The TCell Authors +// Copyright 2026 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -15,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -package tcell +package vt -import ( - // This imports the default terminal entries. To disable, use the - // tcell_minimal build tag. - _ "github.com/gdamore/tcell/v2/terminfo/extended" -) +import "github.com/gdamore/tcell/v3/internal/widthutil" + +var textWidthOptions = widthutil.Options() diff --git a/vendor/github.com/gdamore/tcell/v2/wscreen.go b/vendor/github.com/gdamore/tcell/v3/wscreen.go similarity index 88% rename from vendor/github.com/gdamore/tcell/v2/wscreen.go rename to vendor/github.com/gdamore/tcell/v3/wscreen.go index 4c866d1e8..53dbfc064 100644 --- a/vendor/github.com/gdamore/tcell/v2/wscreen.go +++ b/vendor/github.com/gdamore/tcell/v3/wscreen.go @@ -1,8 +1,8 @@ // Copyright 2025 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 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // @@ -24,16 +24,33 @@ import ( "syscall/js" "unicode/utf8" - "github.com/gdamore/tcell/v2/terminfo" + "github.com/gdamore/tcell/v3/tty" ) -func NewTerminfoScreen() (Screen, error) { +// NewTerminfoScreen gets a screen. The options are ignored for this platform. +func NewTerminfoScreen(_ ...TerminfoScreenOption) (Screen, error) { t := &wScreen{} t.fallback = make(map[rune]string) return &baseScreen{screenImpl: t}, nil } +func NewTerminfoScreenFromTty(_ tty.Tty, _ ...TerminfoScreenOption) (Screen, error) { + // TODO: When we want to support testing webasm, we'll have to change this + // to use a MockTerm. That will be appropriate when we switch to xterm.js. + // The options are ignored for this platform. + return nil, errors.New("not implemented") +} + +type TerminfoScreenOption interface{ apply(*wScreen) } +type OptColors int +type OptTerm string +type OptAltScreen bool + +func (OptColors) apply(*wScreen) {} +func (OptTerm) apply(*wScreen) {} +func (OptAltScreen) apply(*wScreen) {} + type wScreen struct { w, h int style Style @@ -272,6 +289,10 @@ func (s *wScreen) GetClipboard() { func (s *wScreen) SetClipboard(_ []byte) { } +func (s *wScreen) HasClipboard() bool { + return false +} + func (t *wScreen) Size() (int, int) { t.Lock() w, h := t.w, t.h @@ -311,7 +332,7 @@ func (t *wScreen) postEvent(ev Event) { } } -func (t *wScreen) onMouseEvent(this js.Value, args []js.Value) interface{} { +func (t *wScreen) onMouseEvent(this js.Value, args []js.Value) any { mod := ModNone button := ButtonNone @@ -346,7 +367,7 @@ func (t *wScreen) onMouseEvent(this js.Value, args []js.Value) interface{} { return nil } -func (t *wScreen) onKeyEvent(this js.Value, args []js.Value) interface{} { +func (t *wScreen) onKeyEvent(this js.Value, args []js.Value) any { key := args[0].String() // don't accept any modifier keys as their own @@ -373,22 +394,22 @@ func (t *wScreen) onKeyEvent(this js.Value, args []js.Value) interface{} { // next try function keys if k, ok := WebKeyNames[key]; ok { - t.postEvent(NewEventKey(k, 0, mod)) + t.postEvent(NewEventKey(k, "", mod)) return nil } // finally try normal, printable chars r, _ := utf8.DecodeRuneInString(key) - t.postEvent(NewEventKey(KeyRune, r, mod)) + t.postEvent(NewEventKey(KeyRune, string(r), mod)) return nil } -func (t *wScreen) onPaste(this js.Value, args []js.Value) interface{} { +func (t *wScreen) onPaste(this js.Value, args []js.Value) any { t.postEvent(NewEventPaste(args[0].Bool())) return nil } -func (t *wScreen) onFocus(this js.Value, args []js.Value) interface{} { +func (t *wScreen) onFocus(this js.Value, args []js.Value) any { t.postEvent(NewEventFocus(args[0].Bool())) return nil } @@ -397,7 +418,7 @@ func (t *wScreen) onFocus(this js.Value, args []js.Value) interface{} { // happen when javascript calls a function (for example, when // mouse input is disabled, when onMouseEvent() is called from // js, it redirects here and does nothing). -func (t *wScreen) unset(this js.Value, args []js.Value) interface{} { +func (t *wScreen) unset(this js.Value, args []js.Value) any { return nil } @@ -426,27 +447,6 @@ func (t *wScreen) UnregisterRuneFallback(orig rune) { t.Unlock() } -func (t *wScreen) CanDisplay(r rune, checkFallbacks bool) bool { - if utf8.ValidRune(r) { - return true - } - if !checkFallbacks { - return false - } - if _, ok := t.fallback[r]; ok { - return true - } - return false -} - -func (t *wScreen) HasMouse() bool { - return true -} - -func (t *wScreen) HasKey(k Key) bool { - return true -} - func (t *wScreen) SetSize(w, h int) { if w == t.w && h == t.h { return @@ -473,7 +473,7 @@ func (t *wScreen) Suspend() error { t.clearScreen() t.enableMouse(0) t.enablePasting(false) - js.Global().Set("onKeyEvent", js.FuncOf(t.unset)) // stop keypresses + js.Global().Set("onKeyEvent", js.FuncOf(t.unset)) // stop key presses return nil } @@ -519,6 +519,8 @@ func (t *wScreen) SetTitle(title string) { js.Global().Call("setTitle", title) } +func (*wScreen) ShowNotification(title string, body string) {} + // WebKeyNames maps string names reported from HTML // (KeyboardEvent.key) to tcell accepted keys. var WebKeyNames = map[string]Key{ @@ -624,6 +626,4 @@ var curStyleClasses = map[CursorStyle]string{ CursorStyleSteadyBar: "cursor-steady-bar", } -func LookupTerminfo(name string) (ti *terminfo.Terminfo, e error) { - return nil, errors.New("LookupTermInfo not supported") -} +func (*wScreen) Terminal() (string, string) { return "Tcell-WebASM", "" } diff --git a/vendor/modules.txt b/vendor/modules.txt index 73ad86ab5..c44cb0e50 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -27,6 +27,12 @@ github.com/cli/go-gh/v2/pkg/config # github.com/cli/safeexec v1.0.1 ## explicit; go 1.15 github.com/cli/safeexec +# github.com/clipperhouse/displaywidth v0.11.0 +## explicit; go 1.18 +github.com/clipperhouse/displaywidth +# github.com/clipperhouse/uax29/v2 v2.7.0 +## explicit; go 1.18 +github.com/clipperhouse/uax29/v2/graphemes # github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 ## explicit github.com/cloudfoundry/jibber_jabber @@ -42,40 +48,13 @@ github.com/fatih/color # github.com/gdamore/encoding v1.0.1 ## explicit; go 1.9 github.com/gdamore/encoding -# github.com/gdamore/tcell/v2 v2.13.8 -## explicit; go 1.24.0 -github.com/gdamore/tcell/v2 -github.com/gdamore/tcell/v2/terminfo -github.com/gdamore/tcell/v2/terminfo/a/aixterm -github.com/gdamore/tcell/v2/terminfo/a/alacritty -github.com/gdamore/tcell/v2/terminfo/a/ansi -github.com/gdamore/tcell/v2/terminfo/base -github.com/gdamore/tcell/v2/terminfo/c/cygwin -github.com/gdamore/tcell/v2/terminfo/d/dtterm -github.com/gdamore/tcell/v2/terminfo/dynamic -github.com/gdamore/tcell/v2/terminfo/e/emacs -github.com/gdamore/tcell/v2/terminfo/extended -github.com/gdamore/tcell/v2/terminfo/f/foot -github.com/gdamore/tcell/v2/terminfo/g/gnome -github.com/gdamore/tcell/v2/terminfo/k/konsole -github.com/gdamore/tcell/v2/terminfo/k/kterm -github.com/gdamore/tcell/v2/terminfo/l/linux -github.com/gdamore/tcell/v2/terminfo/p/pcansi -github.com/gdamore/tcell/v2/terminfo/r/rxvt -github.com/gdamore/tcell/v2/terminfo/s/screen -github.com/gdamore/tcell/v2/terminfo/s/simpleterm -github.com/gdamore/tcell/v2/terminfo/s/sun -github.com/gdamore/tcell/v2/terminfo/t/tmux -github.com/gdamore/tcell/v2/terminfo/v/vt100 -github.com/gdamore/tcell/v2/terminfo/v/vt102 -github.com/gdamore/tcell/v2/terminfo/v/vt220 -github.com/gdamore/tcell/v2/terminfo/v/vt320 -github.com/gdamore/tcell/v2/terminfo/v/vt400 -github.com/gdamore/tcell/v2/terminfo/v/vt420 -github.com/gdamore/tcell/v2/terminfo/x/xfce -github.com/gdamore/tcell/v2/terminfo/x/xterm -github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty -github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty +# github.com/gdamore/tcell/v3 v3.3.0 +## explicit; go 1.25.0 +github.com/gdamore/tcell/v3 +github.com/gdamore/tcell/v3/color +github.com/gdamore/tcell/v3/internal/widthutil +github.com/gdamore/tcell/v3/tty +github.com/gdamore/tcell/v3/vt # github.com/go-errors/errors v1.5.1 ## explicit; go 1.14 github.com/go-errors/errors @@ -207,7 +186,7 @@ golang.org/x/sync/errgroup golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/term v0.41.0 +# golang.org/x/term v0.42.0 ## explicit; go 1.25.0 golang.org/x/term # golang.org/x/text v0.36.0