From 90772e1eaac00314cfb45b8a2216aca28ef91105 Mon Sep 17 00:00:00 2001 From: Ryooooooga Date: Tue, 21 Feb 2023 21:53:55 +0900 Subject: [PATCH] build: bump tcell version --- go.mod | 5 +- go.sum | 8 + .../gdamore/tcell/v2/README-wasm.md | 61 ++ vendor/github.com/gdamore/tcell/v2/README.md | 8 +- vendor/github.com/gdamore/tcell/v2/cell.go | 9 +- vendor/github.com/gdamore/tcell/v2/color.go | 6 +- .../tcell/v2/terminfo/a/alacritty/direct.go | 69 ++ .../gdamore/tcell/v2/terms_static.go | 4 +- vendor/github.com/gdamore/tcell/v2/tscreen.go | 8 + .../gdamore/tcell/v2/tscreen_stub.go | 4 +- vendor/github.com/gdamore/tcell/v2/wscreen.go | 678 ++++++++++++++++++ vendor/github.com/rivo/uniseg/grapheme.go | 6 +- .../github.com/rivo/uniseg/graphemerules.go | 2 +- vendor/github.com/rivo/uniseg/line.go | 7 +- vendor/github.com/rivo/uniseg/sentence.go | 4 +- vendor/github.com/rivo/uniseg/step.go | 4 +- vendor/github.com/rivo/uniseg/word.go | 4 +- vendor/modules.txt | 6 +- 18 files changed, 870 insertions(+), 23 deletions(-) create mode 100644 vendor/github.com/gdamore/tcell/v2/README-wasm.md create mode 100644 vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/direct.go create mode 100644 vendor/github.com/gdamore/tcell/v2/wscreen.go diff --git a/go.mod b/go.mod index 39f3968ea..8a24e093e 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/creack/pty v1.1.11 github.com/fsmiamoto/git-todo-parser v0.0.2 github.com/fsnotify/fsnotify v1.4.7 - github.com/gdamore/tcell/v2 v2.5.4 + github.com/gdamore/tcell/v2 v2.6.0 github.com/go-errors/errors v1.4.2 github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 @@ -46,6 +46,7 @@ require ( github.com/emirpasic/gods v1.12.0 // indirect github.com/fatih/color v1.9.0 // indirect github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/tcell v1.4.0 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/go-billy/v5 v5.0.0 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect @@ -62,7 +63,7 @@ require ( github.com/onsi/ginkgo v1.10.3 // indirect github.com/onsi/gomega v1.7.1 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect - github.com/rivo/uniseg v0.4.3 // indirect + github.com/rivo/uniseg v0.4.4 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/xanzy/ssh-agent v0.2.1 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect diff --git a/go.sum b/go.sum index 7b8d82222..d4c892dd5 100644 --- a/go.sum +++ b/go.sum @@ -34,9 +34,13 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU= +github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0= github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= github.com/gdamore/tcell/v2 v2.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw= +github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg= +github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= @@ -113,6 +117,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -138,6 +143,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM= @@ -196,6 +203,7 @@ golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/gdamore/tcell/v2/README-wasm.md b/vendor/github.com/gdamore/tcell/v2/README-wasm.md new file mode 100644 index 000000000..faf96856f --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v2/README-wasm.md @@ -0,0 +1,61 @@ +# WASM for _Tcell_ + +You can build _Tcell_ project into a webpage by compiling it slightly differently. This will result in a _Tcell_ project you can embed into another html page, or use as a standalone page. + +## Building your project + +WASM needs special build flags in order to work. You can build it by executing +```sh +GOOS=js GOARCH=wasm go build -o yourfile.wasm +``` + +## Additional files + +You also need 5 other files in the same directory as the wasm. Four (`tcell.html`, `tcell.js`, `termstyle.css`, and `beep.wav`) are provided in the `webfiles` directory. The last one, `wasm_exec.js`, can be copied from GOROOT into the current directory by executing +```sh +cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./ +``` + +In `tcell.js`, you also need to change the constant +```js +const wasmFilePath = "yourfile.wasm" +``` +to the file you outputed to when building. + +## Displaying your project + +### Standalone + +You can see the project (with an white background around the terminal) by serving the directory. You can do this using any framework, including another golang project: + +```golang +// server.go + +package main + +import ( + "log" + "net/http" +) + +func main() { + log.Fatal(http.ListenAndServe(":8080", + http.FileServer(http.Dir("/path/to/dir/to/serve")), + )) +} + +``` + +To see the webpage with this example, you can type in `localhost:8080/tcell.html` into your browser while `server.go` is running. + +### Embedding +It is recomended to use an iframe if you want to embed the app into a webpage: +```html + +``` + +## Other considerations + +### Accessing files + +`io.Open(filename)` and other related functions for reading file systems do not work; use `http.Get(filename)` instead. \ No newline at end of file diff --git a/vendor/github.com/gdamore/tcell/v2/README.md b/vendor/github.com/gdamore/tcell/v2/README.md index 13e6e0cd5..347e274a2 100644 --- a/vendor/github.com/gdamore/tcell/v2/README.md +++ b/vendor/github.com/gdamore/tcell/v2/README.md @@ -264,7 +264,11 @@ Windows console mode applications are supported. Modern console applications like ConEmu and the Windows 10 terminal, support all the good features (resize, mouse tracking, etc.) -### Plan9, WASM, and others +### WASM + +WASM is supported, but needs additional setup detailed in [README-wasm](README-wasm.md). + +### Plan9 and others These platforms won't work, but compilation stubs are supplied for folks that want to include parts of this in software for those @@ -279,4 +283,4 @@ please let me know. PRs are especially welcome. _Tcell_ is absolutely free, but if you want to obtain commercial, professional support, there are options. - [TideLift](https://tidelift.com/) subscriptions include support for _Tcell_, as well as many other open source packages. -- [Staysail Systems Inc.](mailto:info@staysail.tech) offers direct support, and custom development around _Tcell_ on an hourly basis. +- [Staysail Systems Inc.](mailto:info@staysail.tech) offers direct support, and custom development around _Tcell_ on an hourly basis. \ No newline at end of file diff --git a/vendor/github.com/gdamore/tcell/v2/cell.go b/vendor/github.com/gdamore/tcell/v2/cell.go index c33900495..756a5068d 100644 --- a/vendor/github.com/gdamore/tcell/v2/cell.go +++ b/vendor/github.com/gdamore/tcell/v2/cell.go @@ -50,6 +50,10 @@ func (cb *CellBuffer) SetContent(x int, y int, if x >= 0 && y >= 0 && x < cb.w && y < cb.h { c := &cb.cells[(y*cb.w)+x] + for i := 1; i < c.width; i++ { + cb.SetDirty(x+i, y, true) + } + c.currComb = append([]rune{}, combc...) if c.currMain != mainc { @@ -178,13 +182,14 @@ func (cb *CellBuffer) Fill(r rune, style Style) { } } -var runeConfig *runewidth.Condition; +var runeConfig *runewidth.Condition + func init() { // The defaults for the runewidth package are poorly chosen for terminal // applications. We however will honor the setting in the environment if // it is set. if os.Getenv("RUNEWIDTH_EASTASIAN") == "" { - runewidth.DefaultCondition.EastAsianWidth = false; + runewidth.DefaultCondition.EastAsianWidth = false } // For performance reasons, we create a lookup table. However some users diff --git a/vendor/github.com/gdamore/tcell/v2/color.go b/vendor/github.com/gdamore/tcell/v2/color.go index 8e50fa302..e6581b0f6 100644 --- a/vendor/github.com/gdamore/tcell/v2/color.go +++ b/vendor/github.com/gdamore/tcell/v2/color.go @@ -1002,14 +1002,14 @@ func (c Color) IsRGB() bool { } // Hex returns the color's hexadecimal RGB 24-bit value with each component -// consisting of a single byte, ala R << 16 | G << 8 | B. If the color +// 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 + return int32(c & 0xffffff) } if v, ok := ColorValues[c]; ok { return v @@ -1036,7 +1036,7 @@ func (c Color) TrueColor() Color { return ColorDefault } if c&ColorIsRGB != 0 { - return c + return c | ColorValid } return Color(c.Hex()) | ColorIsRGB | ColorValid } 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 new file mode 100644 index 000000000..db6351af2 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/direct.go @@ -0,0 +1,69 @@ +// 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, + Bell: "\a", + 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", + CursorBack1: "\b", + CursorUp1: "\x1b[A", + KeyUp: "\x1bOA", + KeyDown: "\x1bOB", + KeyRight: "\x1bOC", + KeyLeft: "\x1bOD", + KeyInsert: "\x1b[2~", + KeyDelete: "\x1b[3~", + KeyBackspace: "\x7f", + KeyHome: "\x1bOH", + KeyEnd: "\x1bOF", + KeyPgUp: "\x1b[5~", + KeyPgDn: "\x1b[6~", + KeyF1: "\x1bOP", + KeyF2: "\x1bOQ", + KeyF3: "\x1bOR", + KeyF4: "\x1bOS", + KeyF5: "\x1b[15~", + KeyF6: "\x1b[17~", + KeyF7: "\x1b[18~", + KeyF8: "\x1b[19~", + KeyF9: "\x1b[20~", + KeyF10: "\x1b[21~", + KeyF11: "\x1b[23~", + KeyF12: "\x1b[24~", + KeyBacktab: "\x1b[Z", + Modifiers: 1, + TrueColor: true, + AutoMargin: true, + }) +} diff --git a/vendor/github.com/gdamore/tcell/v2/terms_static.go b/vendor/github.com/gdamore/tcell/v2/terms_static.go index d0c57d919..6d725cbcc 100644 --- a/vendor/github.com/gdamore/tcell/v2/terms_static.go +++ b/vendor/github.com/gdamore/tcell/v2/terms_static.go @@ -1,5 +1,5 @@ -//go:build tcell_minimal || nacl || js || zos || plan9 || windows || android -// +build tcell_minimal nacl js zos plan9 windows android +//go:build tcell_minimal || nacl || zos || plan9 || windows || android || js +// +build tcell_minimal nacl zos plan9 windows android js // Copyright 2019 The TCell Authors // diff --git a/vendor/github.com/gdamore/tcell/v2/tscreen.go b/vendor/github.com/gdamore/tcell/v2/tscreen.go index e07dea4e7..e36e6e41f 100644 --- a/vendor/github.com/gdamore/tcell/v2/tscreen.go +++ b/vendor/github.com/gdamore/tcell/v2/tscreen.go @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build !(js && wasm) +// +build !js !wasm + package tcell import ( @@ -341,6 +344,11 @@ func (t *tScreen) prepareBracketedPaste() { } 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. diff --git a/vendor/github.com/gdamore/tcell/v2/tscreen_stub.go b/vendor/github.com/gdamore/tcell/v2/tscreen_stub.go index 9e3cdaa02..0e4deae02 100644 --- a/vendor/github.com/gdamore/tcell/v2/tscreen_stub.go +++ b/vendor/github.com/gdamore/tcell/v2/tscreen_stub.go @@ -1,5 +1,5 @@ -//go:build js || plan9 || windows -// +build js plan9 windows +//go:build plan9 || windows +// +build plan9 windows // Copyright 2022 The TCell Authors // diff --git a/vendor/github.com/gdamore/tcell/v2/wscreen.go b/vendor/github.com/gdamore/tcell/v2/wscreen.go new file mode 100644 index 000000000..080472065 --- /dev/null +++ b/vendor/github.com/gdamore/tcell/v2/wscreen.go @@ -0,0 +1,678 @@ +// 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. + +//go:build js && wasm +// +build js,wasm + +package tcell + +import ( + "errors" + "strings" + "sync" + "syscall/js" + "unicode/utf8" +) + +func NewTerminfoScreen() (Screen, error) { + t := &wScreen{} + t.fallback = make(map[rune]string) + + return t, nil +} + +type wScreen struct { + w, h int + style Style + cells CellBuffer + + running bool + clear bool + flagsPresent bool + pasteEnabled bool + mouseFlags MouseFlags + + cursorStyle CursorStyle + + quit chan struct{} + evch chan Event + fallback map[rune]string + + sync.Mutex +} + +func (t *wScreen) Init() error { + t.w, t.h = 80, 24 // default for html as of now + t.evch = make(chan Event, 10) + t.quit = make(chan struct{}) + + t.Lock() + t.running = true + t.style = StyleDefault + t.cells.Resize(t.w, t.h) + t.Unlock() + + js.Global().Set("onKeyEvent", js.FuncOf(t.onKeyEvent)) + + return nil +} + +func (t *wScreen) Fini() { + close(t.quit) +} + +func (t *wScreen) SetStyle(style Style) { + t.Lock() + t.style = style + t.Unlock() +} + +func (t *wScreen) Clear() { + t.Fill(' ', t.style) +} + +func (t *wScreen) Fill(r rune, style Style) { + t.Lock() + t.cells.Fill(r, style) + t.Unlock() +} + +func (t *wScreen) SetContent(x, y int, mainc rune, combc []rune, style Style) { + t.Lock() + t.cells.SetContent(x, y, mainc, combc, style) + t.Unlock() +} + +func (t *wScreen) GetContent(x, y int) (rune, []rune, Style, int) { + t.Lock() + mainc, combc, style, width := t.cells.GetContent(x, y) + t.Unlock() + return mainc, combc, style, width +} + +func (t *wScreen) SetCell(x, y int, style Style, ch ...rune) { + if len(ch) > 0 { + t.SetContent(x, y, ch[0], ch[1:], style) + } else { + t.SetContent(x, y, ' ', nil, style) + } +} + +// paletteColor gives a more natural palette color actually matching +// typical XTerm. We might in the future want to permit styling these +// via CSS. + +var palette = map[Color]int32{ + ColorBlack: 0x000000, + ColorMaroon: 0xcd0000, + ColorGreen: 0x00cd00, + ColorOlive: 0xcdcd00, + ColorNavy: 0x0000ee, + ColorPurple: 0xcd00cd, + ColorTeal: 0x00cdcd, + ColorSilver: 0xe5e5e5, + ColorGray: 0x7f7f7f, + ColorRed: 0xff0000, + ColorLime: 0x00ff00, + ColorYellow: 0xffff00, + ColorBlue: 0x5c5cff, + ColorFuchsia: 0xff00ff, + ColorAqua: 0x00ffff, + ColorWhite: 0xffffff, +} + +func paletteColor(c Color) int32 { + if (c.IsRGB()) { + return int32(c & 0xffffff); + } + if (c >= ColorBlack && c <= ColorWhite) { + return palette[c] + } + return c.Hex() +} + +func (t *wScreen) drawCell(x, y int) int { + mainc, combc, style, width := t.cells.GetContent(x, y) + + if !t.cells.Dirty(x, y) { + return width + } + + if style == StyleDefault { + style = t.style + } + + fg, bg := paletteColor(style.fg), paletteColor(style.bg) + if (fg == -1) { + fg = 0xe5e5e5; + } + if (bg == -1) { + bg = 0x000000; + } + + var combcarr []interface{} = make([]interface{}, len(combc)) + for i, c := range combc { + combcarr[i] = c + } + + t.cells.SetDirty(x, y, false) + js.Global().Call("drawCell", x, y, mainc, combcarr, fg, bg, int(style.attrs)) + + return width +} + +func (t *wScreen) ShowCursor(x, y int) { + t.Lock() + js.Global().Call("showCursor", x, y) + t.Unlock() +} + +func (t *wScreen) SetCursorStyle(cs CursorStyle) { + t.Lock() + js.Global().Call("setCursorStyle", curStyleClasses[cs]) + t.Unlock() +} + +func (t *wScreen) HideCursor() { + t.ShowCursor(-1, -1) +} + +func (t *wScreen) Show() { + t.Lock() + t.resize() + t.draw() + t.Unlock() +} + +func (t *wScreen) clearScreen() { + js.Global().Call("clearScreen", t.style.fg.Hex(), t.style.bg.Hex()) + t.clear = false +} + +func (t *wScreen) draw() { + if t.clear { + t.clearScreen() + } + + for y := 0; y < t.h; y++ { + for x := 0; x < t.w; x++ { + width := t.drawCell(x, y) + x += width - 1 + } + } + + js.Global().Call("show") +} + +func (t *wScreen) 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 *wScreen) enableMouse(f MouseFlags) { + if f&MouseButtonEvents != 0 { + js.Global().Set("onMouseClick", js.FuncOf(t.onMouseEvent)) + } else { + js.Global().Set("onMouseClick", js.FuncOf(t.unset)) + } + + if f&MouseDragEvents != 0 || f&MouseMotionEvents != 0 { + js.Global().Set("onMouseMove", js.FuncOf(t.onMouseEvent)) + } else { + js.Global().Set("onMouseMove", js.FuncOf(t.unset)) + } +} + +func (t *wScreen) DisableMouse() { + t.Lock() + t.mouseFlags = 0 + t.enableMouse(0) + t.Unlock() +} + +func (t *wScreen) EnablePaste() { + t.Lock() + t.pasteEnabled = true + t.enablePasting(true) + t.Unlock() +} + +func (t *wScreen) DisablePaste() { + t.Lock() + t.pasteEnabled = false + t.enablePasting(false) + t.Unlock() +} + +func (t *wScreen) enablePasting(on bool) { + if on { + js.Global().Set("onPaste", js.FuncOf(t.onPaste)) + } else { + js.Global().Set("onPaste", js.FuncOf(t.unset)) + } +} + +func (t *wScreen) Size() (int, int) { + t.Lock() + w, h := t.w, t.h + t.Unlock() + return w, h +} + +// resize does nothing, as asking the web window to resize +// without a specified width or height will cause no change. +func (t *wScreen) resize() {} + +func (t *wScreen) Colors() int { + return 16777216 // 256 ^ 3 +} + +func (t *wScreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) { + defer close(ch) + for { + select { + case <-quit: + return + case <-t.quit: + return + case ev := <-t.evch: + select { + case <-quit: + return + case <-t.quit: + return + case ch <- ev: + } + } + } +} + +func (t *wScreen) PollEvent() Event { + select { + case <-t.quit: + return nil + case ev := <-t.evch: + return ev + } +} + +func (t *wScreen) HasPendingEvent() bool { + return len(t.evch) > 0 +} + +func (t *wScreen) PostEventWait(ev Event) { + t.evch <- ev +} + +func (t *wScreen) PostEvent(ev Event) error { + select { + case t.evch <- ev: + return nil + default: + return ErrEventQFull + } +} + +func (t *wScreen) clip(x, y int) (int, int) { + w, h := t.cells.Size() + if x < 0 { + x = 0 + } + if y < 0 { + y = 0 + } + if x > w-1 { + x = w - 1 + } + if y > h-1 { + y = h - 1 + } + return x, y +} + +func (t *wScreen) onMouseEvent(this js.Value, args []js.Value) interface{} { + mod := ModNone + button := ButtonNone + + switch args[2].Int() { + case 0: + if t.mouseFlags&MouseMotionEvents == 0 { + // don't want this event! is a mouse motion event, but user has asked not. + return nil + } + button = ButtonNone + case 1: + button = Button1 + case 2: + button = Button3 // Note we prefer to treat right as button 2 + case 3: + button = Button2 // And the middle button as button 3 + } + + if args[3].Bool() { // mod shift + mod |= ModShift + } + + if args[4].Bool() { // mod alt + mod |= ModAlt + } + + if args[5].Bool() { // mod ctrl + mod |= ModCtrl + } + + t.PostEventWait(NewEventMouse(args[0].Int(), args[1].Int(), button, mod)) + return nil +} + +func (t *wScreen) onKeyEvent(this js.Value, args []js.Value) interface{} { + key := args[0].String() + + // don't accept any modifier keys as their own + if key == "Control" || key == "Alt" || key == "Meta" || key == "Shift" { + return nil + } + + mod := ModNone + if args[1].Bool() { // mod shift + mod |= ModShift + } + + if args[2].Bool() { // mod alt + mod |= ModAlt + } + + if args[3].Bool() { // mod ctrl + mod |= ModCtrl + } + + if args[4].Bool() { // mod meta + mod |= ModMeta + } + + // check for special case of Ctrl + key + if mod == ModCtrl { + if k, ok := WebKeyNames["Ctrl-"+strings.ToLower(key)]; ok { + t.PostEventWait(NewEventKey(k, 0, mod)) + return nil + } + } + + // next try function keys + if k, ok := WebKeyNames[key]; ok { + t.PostEventWait(NewEventKey(k, 0, mod)) + return nil + } + + // finally try normal, printable chars + r, _ := utf8.DecodeRuneInString(key) + t.PostEventWait(NewEventKey(KeyRune, r, mod)) + return nil +} + +func (t *wScreen) onPaste(this js.Value, args []js.Value) interface{} { + t.PostEventWait(NewEventPaste(args[0].Bool())) + return nil +} + +// unset is a dummy function for js when we want nothing to +// 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{} { + return nil +} + +func (t *wScreen) Sync() { + t.Lock() + t.resize() + t.clear = true + t.cells.Invalidate() + t.draw() + t.Unlock() +} + +func (t *wScreen) CharacterSet() string { + return "UTF-8" +} + +func (t *wScreen) RegisterRuneFallback(orig rune, fallback string) { + t.Lock() + t.fallback[orig] = fallback + t.Unlock() +} + +func (t *wScreen) UnregisterRuneFallback(orig rune) { + t.Lock() + delete(t.fallback, orig) + 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 + } + + t.cells.Invalidate() + t.cells.Resize(w, h) + js.Global().Call("resize", w, h) + t.w, t.h = w, h + t.PostEvent(NewEventResize(w, h)) +} + +func (t *wScreen) Resize(int, int, int, int) {} + +// Suspend simply pauses all input and output, and clears the screen. +// There isn't a "default terminal" to go back to. +func (t *wScreen) Suspend() error { + t.Lock() + if !t.running { + t.Unlock() + return nil + } + t.running = false + t.clearScreen() + t.enableMouse(0) + t.enablePasting(false) + js.Global().Set("onKeyEvent", js.FuncOf(t.unset)) // stop keypresses + return nil +} + +func (t *wScreen) Resume() error { + t.Lock() + + if t.running { + return errors.New("already engaged") + } + t.running = true + + t.enableMouse(t.mouseFlags) + t.enablePasting(t.pasteEnabled) + + js.Global().Set("onKeyEvent", js.FuncOf(t.onKeyEvent)) + + t.Unlock() + return nil +} + +func (t *wScreen) Beep() error { + js.Global().Call("beep") + return nil +} + +// WebKeyNames maps string names reported from HTML +// (KeyboardEvent.key) to tcell accepted keys. +var WebKeyNames = map[string]Key{ + "Enter": KeyEnter, + "Backspace": KeyBackspace, + "Tab": KeyTab, + "Backtab": KeyBacktab, + "Escape": KeyEsc, + "Backspace2": KeyBackspace2, + "Delete": KeyDelete, + "Insert": KeyInsert, + "ArrowUp": KeyUp, + "ArrowDown": KeyDown, + "ArrowLeft": KeyLeft, + "ArrowRight": KeyRight, + "Home": KeyHome, + "End": KeyEnd, + "UpLeft": KeyUpLeft, // not supported by HTML + "UpRight": KeyUpRight, // not supported by HTML + "DownLeft": KeyDownLeft, // not supported by HTML + "DownRight": KeyDownRight, // not supported by HTML + "Center": KeyCenter, + "PgDn": KeyPgDn, + "PgUp": KeyPgUp, + "Clear": KeyClear, + "Exit": KeyExit, + "Cancel": KeyCancel, + "Pause": KeyPause, + "Print": KeyPrint, + "F1": KeyF1, + "F2": KeyF2, + "F3": KeyF3, + "F4": KeyF4, + "F5": KeyF5, + "F6": KeyF6, + "F7": KeyF7, + "F8": KeyF8, + "F9": KeyF9, + "F10": KeyF10, + "F11": KeyF11, + "F12": KeyF12, + "F13": KeyF13, + "F14": KeyF14, + "F15": KeyF15, + "F16": KeyF16, + "F17": KeyF17, + "F18": KeyF18, + "F19": KeyF19, + "F20": KeyF20, + "F21": KeyF21, + "F22": KeyF22, + "F23": KeyF23, + "F24": KeyF24, + "F25": KeyF25, + "F26": KeyF26, + "F27": KeyF27, + "F28": KeyF28, + "F29": KeyF29, + "F30": KeyF30, + "F31": KeyF31, + "F32": KeyF32, + "F33": KeyF33, + "F34": KeyF34, + "F35": KeyF35, + "F36": KeyF36, + "F37": KeyF37, + "F38": KeyF38, + "F39": KeyF39, + "F40": KeyF40, + "F41": KeyF41, + "F42": KeyF42, + "F43": KeyF43, + "F44": KeyF44, + "F45": KeyF45, + "F46": KeyF46, + "F47": KeyF47, + "F48": KeyF48, + "F49": KeyF49, + "F50": KeyF50, + "F51": KeyF51, + "F52": KeyF52, + "F53": KeyF53, + "F54": KeyF54, + "F55": KeyF55, + "F56": KeyF56, + "F57": KeyF57, + "F58": KeyF58, + "F59": KeyF59, + "F60": KeyF60, + "F61": KeyF61, + "F62": KeyF62, + "F63": KeyF63, + "F64": KeyF64, + "Ctrl-a": KeyCtrlA, // not reported by HTML- need to do special check + "Ctrl-b": KeyCtrlB, // not reported by HTML- need to do special check + "Ctrl-c": KeyCtrlC, // not reported by HTML- need to do special check + "Ctrl-d": KeyCtrlD, // not reported by HTML- need to do special check + "Ctrl-e": KeyCtrlE, // not reported by HTML- need to do special check + "Ctrl-f": KeyCtrlF, // not reported by HTML- need to do special check + "Ctrl-g": KeyCtrlG, // not reported by HTML- need to do special check + "Ctrl-j": KeyCtrlJ, // not reported by HTML- need to do special check + "Ctrl-k": KeyCtrlK, // not reported by HTML- need to do special check + "Ctrl-l": KeyCtrlL, // not reported by HTML- need to do special check + "Ctrl-n": KeyCtrlN, // not reported by HTML- need to do special check + "Ctrl-o": KeyCtrlO, // not reported by HTML- need to do special check + "Ctrl-p": KeyCtrlP, // not reported by HTML- need to do special check + "Ctrl-q": KeyCtrlQ, // not reported by HTML- need to do special check + "Ctrl-r": KeyCtrlR, // not reported by HTML- need to do special check + "Ctrl-s": KeyCtrlS, // not reported by HTML- need to do special check + "Ctrl-t": KeyCtrlT, // not reported by HTML- need to do special check + "Ctrl-u": KeyCtrlU, // not reported by HTML- need to do special check + "Ctrl-v": KeyCtrlV, // not reported by HTML- need to do special check + "Ctrl-w": KeyCtrlW, // not reported by HTML- need to do special check + "Ctrl-x": KeyCtrlX, // not reported by HTML- need to do special check + "Ctrl-y": KeyCtrlY, // not reported by HTML- need to do special check + "Ctrl-z": KeyCtrlZ, // not reported by HTML- need to do special check + "Ctrl- ": KeyCtrlSpace, // not reported by HTML- need to do special check + "Ctrl-_": KeyCtrlUnderscore, // not reported by HTML- need to do special check + "Ctrl-]": KeyCtrlRightSq, // not reported by HTML- need to do special check + "Ctrl-\\": KeyCtrlBackslash, // not reported by HTML- need to do special check + "Ctrl-^": KeyCtrlCarat, // not reported by HTML- need to do special check +} + +var curStyleClasses = map[CursorStyle]string{ + CursorStyleDefault: "cursor-blinking-block", + CursorStyleBlinkingBlock: "cursor-blinking-block", + CursorStyleSteadyBlock: "cursor-steady-block", + CursorStyleBlinkingUnderline: "cursor-blinking-underline", + CursorStyleSteadyUnderline: "cursor-steady-underline", + CursorStyleBlinkingBar: "cursor-blinking-bar", + CursorStyleSteadyBar: "cursor-steady-bar", +} diff --git a/vendor/github.com/rivo/uniseg/grapheme.go b/vendor/github.com/rivo/uniseg/grapheme.go index d5d4c09e5..0086fc1b2 100644 --- a/vendor/github.com/rivo/uniseg/grapheme.go +++ b/vendor/github.com/rivo/uniseg/grapheme.go @@ -187,8 +187,8 @@ func ReverseString(s string) string { const shiftGraphemePropState = 4 // FirstGraphemeCluster returns the first grapheme cluster found in the given -// byte slice according to the rules of Unicode Standard Annex #29, Grapheme -// Cluster Boundaries. This function can be called continuously to extract all +// byte slice according to the rules of [Unicode Standard Annex #29, Grapheme +// Cluster Boundaries]. This function can be called continuously to extract all // grapheme clusters from a byte slice, as illustrated in the example below. // // If you don't know the current state, for example when calling the function @@ -209,6 +209,8 @@ const shiftGraphemePropState = 4 // While slightly less convenient than using the Graphemes class, this function // has much better performance and makes no allocations. It lends itself well to // large byte slices. +// +// [Unicode Standard Annex #29, Grapheme Cluster Boundaries]: http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { diff --git a/vendor/github.com/rivo/uniseg/graphemerules.go b/vendor/github.com/rivo/uniseg/graphemerules.go index 907b30bd0..9f46b575b 100644 --- a/vendor/github.com/rivo/uniseg/graphemerules.go +++ b/vendor/github.com/rivo/uniseg/graphemerules.go @@ -48,7 +48,7 @@ var grTransitions = map[[2]int][3]int{ {grControlLF, prAny}: {grAny, grBoundary, 40}, // GB3. - {grCR, prLF}: {grAny, grNoBoundary, 30}, + {grCR, prLF}: {grControlLF, grNoBoundary, 30}, // GB6. {grAny, prL}: {grL, grBoundary, 9990}, diff --git a/vendor/github.com/rivo/uniseg/line.go b/vendor/github.com/rivo/uniseg/line.go index c0398cacf..87f28503f 100644 --- a/vendor/github.com/rivo/uniseg/line.go +++ b/vendor/github.com/rivo/uniseg/line.go @@ -4,7 +4,7 @@ import "unicode/utf8" // FirstLineSegment returns the prefix of the given byte slice after which a // decision to break the string over to the next line can or must be made, -// according to the rules of Unicode Standard Annex #14. This is used to +// according to the rules of [Unicode Standard Annex #14]. This is used to // implement line breaking. // // Line breaking, also known as word wrapping, is the process of breaking a @@ -35,7 +35,7 @@ import "unicode/utf8" // // Given an empty byte slice "b", the function returns nil values. // -// Note that in accordance with UAX #14 LB3, the final segment will end with +// Note that in accordance with [UAX #14 LB3], the final segment will end with // "mustBreak" set to true. You can choose to ignore this by checking if the // length of the "rest" slice is 0 and calling [HasTrailingLineBreak] or // [HasTrailingLineBreakInString] on the last rune. @@ -43,6 +43,9 @@ import "unicode/utf8" // Note also that this algorithm may break within grapheme clusters. This is // addressed in Section 8.2 Example 6 of UAX #14. To avoid this, you can use // the [Step] function instead. +// +// [Unicode Standard Annex #14]: https://www.unicode.org/reports/tr14/ +// [UAX #14 LB3]: https://www.unicode.org/reports/tr14/#Algorithm func FirstLineSegment(b []byte, state int) (segment, rest []byte, mustBreak bool, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { diff --git a/vendor/github.com/rivo/uniseg/sentence.go b/vendor/github.com/rivo/uniseg/sentence.go index b7fc70996..adc2a3577 100644 --- a/vendor/github.com/rivo/uniseg/sentence.go +++ b/vendor/github.com/rivo/uniseg/sentence.go @@ -3,7 +3,7 @@ package uniseg import "unicode/utf8" // FirstSentence returns the first sentence found in the given byte slice -// according to the rules of Unicode Standard Annex #29, Sentence Boundaries. +// according to the rules of [Unicode Standard Annex #29, Sentence Boundaries]. // This function can be called continuously to extract all sentences from a byte // slice, as illustrated in the example below. // @@ -17,6 +17,8 @@ import "unicode/utf8" // slice is the sub-slice of the input slice containing the identified sentence. // // Given an empty byte slice "b", the function returns nil values. +// +// [Unicode Standard Annex #29, Sentence Boundaries]: http://unicode.org/reports/tr29/#Sentence_Boundaries func FirstSentence(b []byte, state int) (sentence, rest []byte, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { diff --git a/vendor/github.com/rivo/uniseg/step.go b/vendor/github.com/rivo/uniseg/step.go index 55e7f1219..6eca4b5dc 100644 --- a/vendor/github.com/rivo/uniseg/step.go +++ b/vendor/github.com/rivo/uniseg/step.go @@ -83,10 +83,12 @@ const ( // has much better performance and makes no allocations. It lends itself well to // large byte slices. // -// Note that in accordance with UAX #14 LB3, the final segment will end with +// Note that in accordance with [UAX #14 LB3], the final segment will end with // a mandatory line break (boundaries&MaskLine == LineMustBreak). You can choose // to ignore this by checking if the length of the "rest" slice is 0 and calling // [HasTrailingLineBreak] or [HasTrailingLineBreakInString] on the last rune. +// +// [UAX #14 LB3]: https://www.unicode.org/reports/tr14/#Algorithm func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { diff --git a/vendor/github.com/rivo/uniseg/word.go b/vendor/github.com/rivo/uniseg/word.go index 785af1e87..34fba7f29 100644 --- a/vendor/github.com/rivo/uniseg/word.go +++ b/vendor/github.com/rivo/uniseg/word.go @@ -3,7 +3,7 @@ package uniseg import "unicode/utf8" // FirstWord returns the first word found in the given byte slice according to -// the rules of Unicode Standard Annex #29, Word Boundaries. This function can +// the rules of [Unicode Standard Annex #29, Word Boundaries]. This function can // be called continuously to extract all words from a byte slice, as illustrated // in the example below. // @@ -17,6 +17,8 @@ import "unicode/utf8" // the sub-slice of the input slice containing the identified word. // // Given an empty byte slice "b", the function returns nil values. +// +// [Unicode Standard Annex #29, Word Boundaries]: http://unicode.org/reports/tr29/#Word_Boundaries func FirstWord(b []byte, state int) (word, rest []byte, newState int) { // An empty byte slice returns nothing. if len(b) == 0 { diff --git a/vendor/modules.txt b/vendor/modules.txt index 0f2fbc274..feb7fcd98 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -39,7 +39,9 @@ github.com/fsnotify/fsnotify # github.com/gdamore/encoding v1.0.0 ## explicit; go 1.9 github.com/gdamore/encoding -# github.com/gdamore/tcell/v2 v2.5.4 +# github.com/gdamore/tcell v1.4.0 +## explicit; go 1.12 +# github.com/gdamore/tcell/v2 v2.6.0 ## explicit; go 1.12 github.com/gdamore/tcell/v2 github.com/gdamore/tcell/v2/terminfo @@ -233,7 +235,7 @@ github.com/petermattis/goid # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib -# github.com/rivo/uniseg v0.4.3 +# github.com/rivo/uniseg v0.4.4 ## explicit; go 1.18 github.com/rivo/uniseg # github.com/sahilm/fuzzy v0.1.0