Tim Culverhouse: 9 buffer: use tcell.StyleDefault as default cursorAttr csi: try to split params by colon theme: use tcell.StyleDefault for Default fg|bg chore: gofumpt csi: use default fg|bg on error for code 38|48 draw: clear terminal on draw render: debounce render requests to 4ms theme: return palette color instead of named color example: add simple terminal example 13 files changed, 180 insertions(+), 113 deletions(-)
Great work, thanks. I hope that it will then be integrated to aerc :)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~ghost08/tcell-term/patches/35070/mbox | git am -3Learn more about email & git
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- termutil/buffer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/termutil/buffer.go b/termutil/buffer.go index 015b33becbce..c2595b5b0fd6 100644 --- a/termutil/buffer.go +++ b/termutil/buffer.go @@ -75,7 +75,7 @@ func NewBuffer(width, height uint16, maxLines uint64, fg tcell.Color, bg tcell.C maxLines: maxLines, topMargin: 0, bottomMargin: uint(height - 1), - cursorAttr: tcell.StyleDefault.Foreground(fg).Background(bg), + cursorAttr: tcell.StyleDefault, charsets: []*map[rune]rune{nil, nil}, modes: Modes{ LineFeedMode: true, -- 2.37.3
"The ITU's T.416 Information technology - Open Document Architecture (ODA) and interchange format: Character content architectures[47] uses ':' as separator characters instead" Reference: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- termutil/csi.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/termutil/csi.go b/termutil/csi.go index fb700c9895e3..4cccdc8e4208 100644 --- a/termutil/csi.go +++ b/termutil/csi.go @@ -29,7 +29,12 @@ CSI: } } - unprocessed := strings.Split(param, ";") + unprocessed := []string{} + if strings.Contains(param, ":") { + unprocessed = strings.Split(param, ":") + } else { + unprocessed = strings.Split(param, ";") + } for _, par := range unprocessed { if par != "" { par = strings.TrimLeft(par, "0") -- 2.37.3
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- termutil/theme.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/termutil/theme.go b/termutil/theme.go index ca2083315735..ad426827c942 100644 --- a/termutil/theme.go +++ b/termutil/theme.go @@ -85,19 +85,13 @@ func (t *Theme) ColourFrom4Bit(code uint8) tcell.Color { } func (t *Theme) DefaultBackground() tcell.Color { - c, ok := t.colourMap[ColourBackground] - if !ok { - return tcell.ColorBlack - } - return c + _, bg, _ := tcell.StyleDefault.Decompose() + return bg } func (t *Theme) DefaultForeground() tcell.Color { - c, ok := t.colourMap[ColourForeground] - if !ok { - return tcell.ColorWhite - } - return c + fg, _, _ := tcell.StyleDefault.Decompose() + return fg } func (t *Theme) CursorBackground() tcell.Color { -- 2.37.3
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- terminal.go | 5 +++- termutil/buffer.go | 22 -------------- termutil/csi.go | 23 ++++---------- termutil/terminal.go | 22 +++++++------- termutil/theme.go | 71 +++++++++++++++++++++----------------------- 5 files changed, 54 insertions(+), 89 deletions(-) diff --git a/terminal.go b/terminal.go index da5f32ee8fc9..2d1d9edb240a 100644 --- a/terminal.go +++ b/terminal.go @@ -59,7 +59,7 @@ func (t *Terminal) Draw(s tcell.Screen, X, Y uint16) { for viewX := uint16(0); viewX < buf.ViewWidth(); viewX++ { cell := buf.GetCell(viewX, uint16(viewY)) if cell == nil { - //s.SetContent(int(viewX+X), viewY+int(Y), ' ', nil, tcell.StyleDefault.Background(tcell.ColorBlack)) + // s.SetContent(int(viewX+X), viewY+int(Y), ' ', nil, tcell.StyleDefault.Background(tcell.ColorBlack)) continue } s.SetContent(int(viewX+X), viewY+int(Y), cell.Rune().Rune, nil, cell.Style()) @@ -107,10 +107,12 @@ func (w *windowManipulator) SizeInPixels() (int, int) { sz, _ := GetWinSize() return int(sz.XPixel), int(sz.YPixel) } + func (w *windowManipulator) CellSizeInPixels() (int, int) { sz, _ := GetWinSize() return int(sz.Cols / sz.XPixel), int(sz.Rows / sz.YPixel) } + func (w *windowManipulator) SizeInChars() (int, int) { sz, _ := GetWinSize() return int(sz.Cols), int(sz.Rows) @@ -120,6 +122,7 @@ func (w *windowManipulator) ResizeInChars(int, int) {} func (w *windowManipulator) ScreenSizeInPixels() (int, int) { return w.SizeInPixels() } + func (w *windowManipulator) ScreenSizeInChars() (int, int) { return w.SizeInChars() } diff --git a/termutil/buffer.go b/termutil/buffer.go index c2595b5b0fd6..0d24044b837c 100644 --- a/termutil/buffer.go +++ b/termutil/buffer.go @@ -123,7 +123,6 @@ func (buffer *Buffer) getAreaScrollRange() (top uint64, bottom uint64) { } func (buffer *Buffer) areaScrollDown(lines uint16) { - // NOTE: bottom is exclusive top, bottom := buffer.getAreaScrollRange() @@ -138,7 +137,6 @@ func (buffer *Buffer) areaScrollDown(lines uint16) { } func (buffer *Buffer) areaScrollUp(lines uint16) { - // NOTE: bottom is exclusive top, bottom := buffer.getAreaScrollRange() @@ -278,7 +276,6 @@ func (buffer *Buffer) deleteLine() { } func (buffer *Buffer) insertLine() { - if !buffer.InScrollableRegion() { pos := buffer.RawLine() maxLines := buffer.GetMaxLines() @@ -319,7 +316,6 @@ func (buffer *Buffer) insertLine() { } func (buffer *Buffer) insertBlankCharacters(count int) { - index := int(buffer.RawLine()) for i := 0; i < count; i++ { cells := buffer.lines[index].cells @@ -328,7 +324,6 @@ func (buffer *Buffer) insertBlankCharacters(count int) { } func (buffer *Buffer) insertLines(count int) { - if buffer.HasScrollableRegion() && !buffer.InScrollableRegion() { // should have no effect outside of scrollable region return @@ -339,11 +334,9 @@ func (buffer *Buffer) insertLines(count int) { for i := 0; i < count; i++ { buffer.insertLine() } - } func (buffer *Buffer) deleteLines(count int) { - if buffer.HasScrollableRegion() && !buffer.InScrollableRegion() { // should have no effect outside of scrollable region return @@ -354,11 +347,9 @@ func (buffer *Buffer) deleteLines(count int) { for i := 0; i < count; i++ { buffer.deleteLine() } - } func (buffer *Buffer) index() { - // This sequence causes the active position to move downward one line without changing the column position. // If the active position is at the bottom margin, a scroll up is performed." @@ -387,7 +378,6 @@ func (buffer *Buffer) index() { } func (buffer *Buffer) reverseIndex() { - cursorVY := buffer.convertRawLineToViewLine(buffer.cursorPosition.Line) if uint(cursorVY) == buffer.topMargin { @@ -399,7 +389,6 @@ func (buffer *Buffer) reverseIndex() { // write will write a rune to the terminal at the position of the cursor, and increment the cursor position func (buffer *Buffer) write(runes ...MeasuredRune) { - // scroll to bottom on input buffer.scrollLinesFromBottom = 0 @@ -448,7 +437,6 @@ func (buffer *Buffer) write(runes ...MeasuredRune) { // no more room on line and wrapping is disabled return } - } else { for int(buffer.CursorColumn()) >= len(line.cells) { @@ -480,7 +468,6 @@ func (buffer *Buffer) inDoWrap() bool { } func (buffer *Buffer) backspace() { - if buffer.cursorPosition.Col == 0 { line := buffer.getCurrentLine() if line.wrapped { @@ -495,7 +482,6 @@ func (buffer *Buffer) backspace() { } func (buffer *Buffer) carriageReturn() { - cursorVY := buffer.convertRawLineToViewLine(buffer.cursorPosition.Line) for { @@ -514,7 +500,6 @@ func (buffer *Buffer) carriageReturn() { } func (buffer *Buffer) tab() { - tabStop := buffer.getNextTabStopAfter(buffer.cursorPosition.Col) for buffer.cursorPosition.Col < tabStop && buffer.cursorPosition.Col < buffer.viewWidth-1 { // @todo rightMargin buffer.write(MeasuredRune{Rune: ' ', Width: 1}) @@ -523,7 +508,6 @@ func (buffer *Buffer) tab() { // return next tab stop x pos func (buffer *Buffer) getNextTabStopAfter(col uint16) uint16 { - defaultStop := col + (TabSize - (col % TabSize)) if defaultStop == col { defaultStop += TabSize @@ -562,7 +546,6 @@ func (buffer *Buffer) verticalTab() { } func (buffer *Buffer) newLineEx(forceCursorToMargin bool) { - if buffer.IsNewLineMode() || forceCursorToMargin { buffer.cursorPosition.Col = 0 } @@ -578,7 +561,6 @@ func (buffer *Buffer) newLineEx(forceCursorToMargin bool) { } func (buffer *Buffer) movePosition(x int16, y int16) { - var toX uint16 var toY uint16 @@ -599,7 +581,6 @@ func (buffer *Buffer) movePosition(x int16, y int16) { } func (buffer *Buffer) setPosition(col uint16, line uint16) { - useCol := col useLine := line maxLine := buffer.ViewHeight() - 1 @@ -649,7 +630,6 @@ func (buffer *Buffer) getCurrentLine() *Line { } func (buffer *Buffer) getViewLine(index uint16) *Line { - if index >= buffer.ViewHeight() { return &buffer.lines[len(buffer.lines)-1] } @@ -712,7 +692,6 @@ func (buffer *Buffer) eraseDisplay() { } func (buffer *Buffer) deleteChars(n int) { - line := buffer.getCurrentLine() if int(buffer.cursorPosition.Col) >= len(line.cells) { return @@ -726,7 +705,6 @@ func (buffer *Buffer) deleteChars(n int) { } func (buffer *Buffer) eraseCharacters(n int) { - line := buffer.getCurrentLine() max := int(buffer.cursorPosition.Col) + n diff --git a/termutil/csi.go b/termutil/csi.go index 4cccdc8e4208..53d135528ce7 100644 --- a/termutil/csi.go +++ b/termutil/csi.go @@ -130,7 +130,6 @@ func (t *Terminal) handleCSI(readChan chan MeasuredRune) (renderRequired bool) { _ = raw log.Printf("UNKNOWN CSI P(%s) I(%s) %c", strings.Join(params, ";"), string(intermediate), final) return false - } type WindowState uint8 @@ -166,7 +165,6 @@ type WindowManipulator interface { } func (t *Terminal) csiWindowManipulation(params []string) (renderRequired bool) { - if t.windowManipulator == nil { return false } @@ -177,7 +175,7 @@ func (t *Terminal) csiWindowManipulation(params []string) (renderRequired bool) t.windowManipulator.Restore() case "2": t.windowManipulator.Minimise() - case "3": //move window + case "3": // move window if i+2 >= len(params) { return false } @@ -185,7 +183,7 @@ func (t *Terminal) csiWindowManipulation(params []string) (renderRequired bool) y, _ := strconv.Atoi(params[i+2]) i += 2 t.windowManipulator.Move(x, y) - case "4": //resize h,w + case "4": // resize h,w w, h := t.windowManipulator.SizeInPixels() if i+1 < len(params) { h, _ = strconv.Atoi(params[i+1]) @@ -309,7 +307,6 @@ func (t *Terminal) csiWindowManipulation(params []string) (renderRequired bool) // CSI c // Send Device Attributes (Primary/Secondary/Tertiary DA) func (t *Terminal) csiSendDeviceAttributesHandler(params []string) (renderRequired bool) { - // we are VT100 // for DA1 we'll respond ?1;2 // for DA2 we'll respond >0;0;0 @@ -326,7 +323,6 @@ func (t *Terminal) csiSendDeviceAttributesHandler(params []string) (renderRequir // CSI n // Device Status Report (DSR) func (t *Terminal) csiDeviceStatusReportHandler(params []string) (renderRequired bool) { - if len(params) == 0 { return false } @@ -411,7 +407,6 @@ func (t *Terminal) csiCursorBackwardHandler(params []string) (renderRequired boo // CSI E // Cursor Next Line Ps Times (default = 1) (CNL) func (t *Terminal) csiCursorNextLineHandler(params []string) (renderRequired bool) { - distance := 1 if len(params) > 0 { var err error @@ -429,7 +424,6 @@ func (t *Terminal) csiCursorNextLineHandler(params []string) (renderRequired boo // CSI F // Cursor Preceding Line Ps Times (default = 1) (CPL) func (t *Terminal) csiCursorPrecedingLineHandler(params []string) (renderRequired bool) { - distance := 1 if len(params) > 0 { var err error @@ -673,7 +667,6 @@ func (t *Terminal) csiSetModes(modes []string, enabled bool) bool { } func parseModes(mode string) []string { - var output []string if mode == "" { @@ -695,9 +688,7 @@ func parseModes(mode string) []string { } func (t *Terminal) csiSetMode(modes string, enabled bool) bool { - for _, modeStr := range parseModes(modes) { - switch modeStr { case "4": t.activeBuffer.modes.ReplaceMode = !enabled @@ -723,7 +714,7 @@ func (t *Terminal) csiSetMode(modes string, enabled bool) bool { t.activeBuffer.modes.OriginMode = enabled case "?7": // auto-wrap mode - //DECAWM + // DECAWM t.activeBuffer.modes.AutoWrap = enabled case "?9": if enabled { @@ -795,7 +786,7 @@ func (t *Terminal) csiSetMode(modes string, enabled bool) bool { case "?2004": t.activeBuffer.modes.BracketedPasteMode = enabled case "?80": - //t.activeBuffer.modes.SixelScrolling = enabled + // t.activeBuffer.modes.SixelScrolling = enabled default: log.Printf("Unsupported CSI mode %s = %t", modeStr, enabled) } @@ -880,14 +871,13 @@ func (t *Terminal) csiEraseInDisplayHandler(params []string) (renderRequired boo // CSI K // Erase in Line (EL), VT100 func (t *Terminal) csiEraseInLineHandler(params []string) (renderRequired bool) { - n := "0" if len(params) > 0 { n = params[0] } switch n { - case "0", "": //erase adter cursor + case "0", "": // erase adter cursor t.GetActiveBuffer().eraseLineFromCursor() case "1": // erase to cursor inclusive t.GetActiveBuffer().eraseLineToCursor() @@ -902,7 +892,6 @@ func (t *Terminal) csiEraseInLineHandler(params []string) (renderRequired bool) // CSI m // Character Attributes (SGR) func (t *Terminal) sgrSequenceHandler(params []string) bool { - if len(params) == 0 { params = []string{"0"} } @@ -928,7 +917,7 @@ func (t *Terminal) sgrSequenceHandler(params []string) bool { case "7", "07": *attr = attr.Reverse(true) case "8", "08": - //*attr = attr.Hidden( true) + // *attr = attr.Hidden(true) case "9", "09": *attr = attr.StrikeThrough(true) case "21": diff --git a/termutil/terminal.go b/termutil/terminal.go index c96ae6f1cede..edebf9683566 100644 --- a/termutil/terminal.go +++ b/termutil/terminal.go @@ -175,33 +175,31 @@ func (t *Terminal) process() { } func (t *Terminal) processRunes(runes ...MeasuredRune) (renderRequired bool) { - for _, r := range runes { - switch r.Rune { - case 0x05: //enq + case 0x05: // enq continue - case 0x07: //bell - //DING DING DING + case 0x07: // bell + // DING DING DING continue - case 0x8: //backspace + case 0x8: // backspace t.GetActiveBuffer().backspace() renderRequired = true - case 0x9: //tab + case 0x9: // tab t.GetActiveBuffer().tab() renderRequired = true - case 0xa, 0xc: //newLine/form feed + case 0xa, 0xc: // newLine/form feed t.GetActiveBuffer().newLine() renderRequired = true - case 0xb: //vertical tab + case 0xb: // vertical tab t.GetActiveBuffer().verticalTab() renderRequired = true - case 0xd: //carriageReturn + case 0xd: // carriageReturn t.GetActiveBuffer().carriageReturn() renderRequired = true - case 0xe: //shiftOut + case 0xe: // shiftOut t.GetActiveBuffer().currentCharset = 1 - case 0xf: //shiftIn + case 0xf: // shiftIn t.GetActiveBuffer().currentCharset = 0 default: if r.Rune < 0x20 { diff --git a/termutil/theme.go b/termutil/theme.go index ad426827c942..57025a67b293 100644 --- a/termutil/theme.go +++ b/termutil/theme.go @@ -39,42 +39,40 @@ type Theme struct { colourMap map[Colour]tcell.Color } -var ( - map4Bit = map[uint8]Colour{ - 30: ColourBlack, - 31: ColourRed, - 32: ColourGreen, - 33: ColourYellow, - 34: ColourBlue, - 35: ColourMagenta, - 36: ColourCyan, - 37: ColourWhite, - 90: ColourBrightBlack, - 91: ColourBrightRed, - 92: ColourBrightGreen, - 93: ColourBrightYellow, - 94: ColourBrightBlue, - 95: ColourBrightMagenta, - 96: ColourBrightCyan, - 97: ColourBrightWhite, - 40: ColourBlack, - 41: ColourRed, - 42: ColourGreen, - 43: ColourYellow, - 44: ColourBlue, - 45: ColourMagenta, - 46: ColourCyan, - 47: ColourWhite, - 100: ColourBrightBlack, - 101: ColourBrightRed, - 102: ColourBrightGreen, - 103: ColourBrightYellow, - 104: ColourBrightBlue, - 105: ColourBrightMagenta, - 106: ColourBrightCyan, - 107: ColourBrightWhite, - } -) +var map4Bit = map[uint8]Colour{ + 30: ColourBlack, + 31: ColourRed, + 32: ColourGreen, + 33: ColourYellow, + 34: ColourBlue, + 35: ColourMagenta, + 36: ColourCyan, + 37: ColourWhite, + 90: ColourBrightBlack, + 91: ColourBrightRed, + 92: ColourBrightGreen, + 93: ColourBrightYellow, + 94: ColourBrightBlue, + 95: ColourBrightMagenta, + 96: ColourBrightCyan, + 97: ColourBrightWhite, + 40: ColourBlack, + 41: ColourRed, + 42: ColourGreen, + 43: ColourYellow, + 44: ColourBlue, + 45: ColourMagenta, + 46: ColourCyan, + 47: ColourWhite, + 100: ColourBrightBlack, + 101: ColourBrightRed, + 102: ColourBrightGreen, + 103: ColourBrightYellow, + 104: ColourBrightBlue, + 105: ColourBrightMagenta, + 106: ColourBrightCyan, + 107: ColourBrightWhite, +} func (t *Theme) ColourFrom4Bit(code uint8) tcell.Color { colour, ok := map4Bit[code] @@ -135,7 +133,6 @@ func (t *Theme) ColourFrom24Bit(r, g, b string) (tcell.Color, error) { } func (t *Theme) ColourFromAnsi(ansi []string) (tcell.Color, error) { - if len(ansi) == 0 { return tcell.ColorDefault, fmt.Errorf("invalid ansi colour code") } -- 2.37.3
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- termutil/csi.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/termutil/csi.go b/termutil/csi.go index 53d135528ce7..377146dc3d6a 100644 --- a/termutil/csi.go +++ b/termutil/csi.go @@ -896,10 +896,7 @@ func (t *Terminal) sgrSequenceHandler(params []string) bool { params = []string{"0"} } - for i := range params { - - p := strings.Replace(strings.Replace(params[i], "[", "", -1), "]", "", -1) - + for i, p := range params { attr := t.GetActiveBuffer().getCursorAttr() switch p { case "00", "0", "": @@ -937,12 +934,20 @@ func (t *Terminal) sgrSequenceHandler(params []string) bool { case "29": *attr = attr.StrikeThrough(false) case "38": // set foreground - fg, _ := t.theme.ColourFromAnsi(params[i+1:]) - *attr = attr.Foreground(fg) + fg, err := t.theme.ColourFromAnsi(params[i+1:]) + if err != nil { + *attr = attr.Foreground(t.theme.DefaultForeground()) + } else { + *attr = attr.Foreground(fg) + } return false case "48": // set background - bg, _ := t.theme.ColourFromAnsi(params[i+1:]) - *attr = attr.Background(bg) + bg, err := t.theme.ColourFromAnsi(params[i+1:]) + if err != nil { + *attr = attr.Background(t.theme.DefaultBackground()) + } else { + *attr = attr.Background(bg) + } return false case "39": *attr = attr.Foreground(t.theme.DefaultForeground()) -- 2.37.3
Calls to draw redraw the entire terminal. Clear it first. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- terminal.go | 1 + 1 file changed, 1 insertion(+) diff --git a/terminal.go b/terminal.go index 2d1d9edb240a..11cd9c8fe746 100644 --- a/terminal.go +++ b/terminal.go @@ -54,6 +54,7 @@ func (t *Terminal) Event(e tcell.Event) { } func (t *Terminal) Draw(s tcell.Screen, X, Y uint16) { + s.Clear() buf := t.term.GetActiveBuffer() for viewY := int(buf.ViewHeight()) - 1; viewY >= 0; viewY-- { for viewX := uint16(0); viewX < buf.ViewWidth(); viewX++ { -- 2.37.3
The requestRender method sends to a channel and requests the host app to redraw the terminal and call screen.Show. The requests are very frequent, and are easily dropped if not using a large buffered channel. Minimal testing showed that reaching 1000 in-queue requests was not uncommon. Debounce the requests to a reasonable refresh rate. 4 milliseconds is 250hz which should be plenty for TUIs. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- termutil/terminal.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/termutil/terminal.go b/termutil/terminal.go index edebf9683566..3e7dc7493d4c 100644 --- a/termutil/terminal.go +++ b/termutil/terminal.go @@ -7,6 +7,7 @@ import ( "io" "os" "os/exec" + "time" "github.com/creack/pty" "golang.org/x/term" @@ -30,6 +31,7 @@ type Terminal struct { mouseMode MouseMode mouseExtMode MouseExtMode theme *Theme + renderDebounce *time.Timer } // NewTerminal creates a new terminal instance @@ -151,10 +153,14 @@ func (t *Terminal) Run(c *exec.Cmd, updateChan chan struct{}, rows uint16, cols } func (t *Terminal) requestRender() { - select { - case t.updateChan <- struct{}{}: - default: + if t.renderDebounce != nil { + t.renderDebounce.Stop() } + // 4 milliseconds = 250Hz. Probably don't need to render faster than + // that + t.renderDebounce = time.AfterFunc(4*time.Millisecond, func() { + t.updateChan <- struct{}{} + }) } func (t *Terminal) process() { -- 2.37.3
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- termutil/theme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/termutil/theme.go b/termutil/theme.go index 57025a67b293..48b1086dd74f 100644 --- a/termutil/theme.go +++ b/termutil/theme.go @@ -79,7 +79,7 @@ func (t *Theme) ColourFrom4Bit(code uint8) tcell.Color { if !ok { return tcell.ColorBlack } - return t.colourMap[colour] + return tcell.PaletteColor(int(colour)) } func (t *Theme) DefaultBackground() tcell.Color { -- 2.37.3
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> --- example_simple/simple.go | 91 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 example_simple/simple.go diff --git a/example_simple/simple.go b/example_simple/simple.go new file mode 100644 index 000000000000..4f91ae226879 --- /dev/null +++ b/example_simple/simple.go @@ -0,0 +1,91 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "log" + "os" + "os/exec" + + tcellterm "git.sr.ht/~ghost08/tcell-term" + "github.com/gdamore/tcell/v2" +) + +func main() { + f, _ := os.Create("meh.log") + defer f.Close() + logbuf := bytes.NewBuffer(nil) + log.SetOutput(io.MultiWriter(f, logbuf)) + log.SetFlags(log.LstdFlags | log.Lshortfile) + + s, err := tcell.NewScreen() + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } + if err = s.Init(); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } + + s.Clear() + + quit := make(chan struct{}) + redraw := make(chan struct{}, 10) + var term *tcellterm.Terminal + if term == nil { + term = tcellterm.New() + + cmd := exec.Command("zsh") + go func() { + w, h := s.Size() + lh := h + lw := w + if err := term.Run(cmd, redraw, uint16(lw), uint16(lh)); err != nil { + log.Println(err) + } + s.HideCursor() + term = nil + close(quit) + }() + } + go func() { + for { + ev := s.PollEvent() + switch ev := ev.(type) { + case *tcell.EventKey: + switch ev.Key() { + case tcell.KeyCtrlC: + close(quit) + return + } + if term != nil { + term.Event(ev) + } + case *tcell.EventResize: + if term != nil { + w, h := s.Size() + lh := h + lw := w + term.Resize(lw, lh) + } + s.Sync() + } + } + }() + +loop: + for { + select { + case <-quit: + break loop + case <-redraw: + term.Draw(s, 0, 0) + s.Show() + } + } + + s.Fini() + os.Stdout.Write(logbuf.Bytes()) +} -- 2.37.3
Great work, thanks. I hope that it will then be integrated to aerc :)