mirror of
https://github.com/gdamore/tcell.git
synced 2025-04-29 13:49:10 +08:00
fixes #10 Eliminate separate buffered implementation
fixes #9 Various API enhancements fixes #8 Mouse demo improvements fixes #7 Add support for handling $<delay> delays fixes #6 mkinfo doesn't honor terminfo LINES and COLUMNS fixes #5 Add better mouse tracking fixes #3 Windows performance improvements
This commit is contained in:
parent
385072b4a8
commit
434fc57169
90
README.md
90
README.md
@ -8,28 +8,62 @@
|
|||||||
[](https://godoc.org/github.com/gdamore/tcell)
|
[](https://godoc.org/github.com/gdamore/tcell)
|
||||||
|
|
||||||
> _Tcell is a work in progress (Beta).
|
> _Tcell is a work in progress (Beta).
|
||||||
> Please use with caution; interfaces may change in before final release._
|
> Please use with caution; interfaces may change in before final release.
|
||||||
|
> That said, our confidence in Tcell's stability is increasing. If you
|
||||||
|
> would like to use it in your own application, it is recommended that
|
||||||
|
> you drop a message to garrett@damore.org before commitment._
|
||||||
|
|
||||||
Package tcell provides a cell based view for text terminals, like xterm.
|
Package tcell provides a cell based view for text terminals, like xterm.
|
||||||
It was inspired by termbox, but differs from termbox in some important
|
It was inspired by termbox, but differs from termbox in some important
|
||||||
ways.
|
ways. It also adds signficant functionality beyond termbox.
|
||||||
|
|
||||||
|
## Pure Go Terminfo Database
|
||||||
|
|
||||||
First, it includes a full parser and expander for terminfo capability strings,
|
First, it includes a full parser and expander for terminfo capability strings,
|
||||||
so that it can avoid hard coding escape strings for formatting. It also favors
|
so that it can avoid hard coding escape strings for formatting. It also favors
|
||||||
portability, and includes support for all POSIX systems, at the slight expense
|
portability, and includes support for all POSIX systems, at the slight expense
|
||||||
of needing cgo support for terminal initializations. (This will be corrected
|
of needing cgo support for terminal initializations. (This may be corrected
|
||||||
when Go provides standard support for terminal handling via termio ioctls on
|
when Go provides standard support for terminal handling via termio ioctls on
|
||||||
all POSIX platforms.)
|
all POSIX platforms.) The database itself, while built using CGO, as well
|
||||||
|
as the parser for it, is implemented in Pure Go.
|
||||||
|
|
||||||
Also, this code is able to operate without requiring
|
The database is also flexible & extensibel, and can modified by either running a
|
||||||
|
program to build the database, or hand editing of simple JSON files.
|
||||||
|
|
||||||
|
## More Portable
|
||||||
|
|
||||||
|
Tcell is portable to a wider variety of systems. It relies on standard
|
||||||
|
POSIX supported function calls (on POSIX platforms) for setting terminal
|
||||||
|
modes, which leads to improved support for a broader array of platforms.
|
||||||
|
This does come at the cost of requiring your code to be able to use CGO, but
|
||||||
|
we believe that the vastly improved portability justifies this
|
||||||
|
requirement. Note that the functions called are part of the standard C
|
||||||
|
library, so there shouldn't be any additional external requirements beyond
|
||||||
|
that required for every POSIX program.
|
||||||
|
|
||||||
|
## No async IO
|
||||||
|
|
||||||
|
Termbox code is able to operate without requiring
|
||||||
SIGIO signals, or asynchronous I/O, and can instead use standard Go file
|
SIGIO signals, or asynchronous I/O, and can instead use standard Go file
|
||||||
objects and Go routines.
|
objects and Go routines. This means it should be safe, especially for
|
||||||
|
use with programs that use exec, or otherwise need to manipulate the
|
||||||
|
tty streams. This model is also much closer to idiomatic Go, leading
|
||||||
|
to fewer surprises.
|
||||||
|
|
||||||
It also includes enhanced support for Unicode, include wide characters and
|
## Richer Unicode support
|
||||||
combining characters. It also has richer support for a larger number of
|
|
||||||
|
Tcell includes enhanced support for Unicode, include wide characters and
|
||||||
|
combining characters, provided your terminal can support them. Note that
|
||||||
|
Windows terminals generally don't support the full Unicode repertoire.
|
||||||
|
|
||||||
|
## More Function Keys
|
||||||
|
|
||||||
|
It also has richer support for a larger number of
|
||||||
special keys that some terminals can send.
|
special keys that some terminals can send.
|
||||||
|
|
||||||
It will respect your terminal's color space as specified within your terminfo
|
## Better color handling
|
||||||
|
|
||||||
|
Tcell will respect your terminal's color space as specified within your terminfo
|
||||||
entries, so that for example attempts to emit color sequences on VT100 terminals
|
entries, so that for example attempts to emit color sequences on VT100 terminals
|
||||||
won't result in unintended consequences.
|
won't result in unintended consequences.
|
||||||
|
|
||||||
@ -37,6 +71,13 @@ In Windows mode, we support 16 colors, underline, bold, dim, and reverse,
|
|||||||
instead of just termbox's 8 colors with reverse. (Note that there is some
|
instead of just termbox's 8 colors with reverse. (Note that there is some
|
||||||
conflation with bold/dim and colors.)
|
conflation with bold/dim and colors.)
|
||||||
|
|
||||||
|
## Better mouse support
|
||||||
|
|
||||||
|
It supports enhanced mouse tracking mode, so your application can receive
|
||||||
|
regular mouse motion events, and wheel events, if your terminal supports it.
|
||||||
|
|
||||||
|
## Why not just patch termbox-go?
|
||||||
|
|
||||||
I started this project originally by submitting patches to the author of
|
I started this project originally by submitting patches to the author of
|
||||||
go-termbox, but due to some fundamental differences of opinion, I thought
|
go-termbox, but due to some fundamental differences of opinion, I thought
|
||||||
it might be simpler just to start from scratch.
|
it might be simpler just to start from scratch.
|
||||||
@ -124,12 +165,17 @@ is not possible as terminfo sequences are not defined.)
|
|||||||
|
|
||||||
On Windows, the mouse works normally.
|
On Windows, the mouse works normally.
|
||||||
|
|
||||||
Mouse wheels are unlikely to work, and I have made no effort to support them,
|
Mouse wheel buttons on various terminals are known to work, but the support
|
||||||
given the lack of portability across emulation packages.
|
in terminal emulators, as well as support for various buttons and
|
||||||
|
live mouse tracking, varies widely. As a particular datum, MacOS X Terminal
|
||||||
|
does not support Mouse events at all (as of MacOS 10.10, aka Yosemite.) The
|
||||||
|
excellent iTerm application is fully supported, as is vanilla XTerm.
|
||||||
|
|
||||||
Only button press and release events are reported at this time. In the
|
Mouse tracking with live tracking also varies widely. Current XTerm
|
||||||
future we can easily add full tracking for Windows, and for "genuine" XTerm,
|
implementations, as well as current Screen and iTerm2, and Windows
|
||||||
but most alternatives don't have support for the full mouse motion events.
|
consoles, all support this quite nicely. On other platforms you might
|
||||||
|
find that only mouse click and release events are reported, with
|
||||||
|
no intervening motion events. It really depends on your terminal.
|
||||||
|
|
||||||
## Platforms
|
## Platforms
|
||||||
|
|
||||||
@ -138,12 +184,16 @@ It also requires functional cgo to run. As of this writing, Cgo is available
|
|||||||
on all POSIX Go 1.5 platforms.
|
on all POSIX Go 1.5 platforms.
|
||||||
|
|
||||||
Windows console mode applications are supported. Unfortunately mintty
|
Windows console mode applications are supported. Unfortunately mintty
|
||||||
and other cygwin style applications are not supported; modern console
|
and other cygwin style applications are not supported.
|
||||||
applications like ConEmu support all the good features (resize, mouse, etc.)
|
|
||||||
The Windows version is a bit inefficient in its drawing, as it performs
|
Modern console applications like ConEmu support all the good features
|
||||||
a single WriteConsoleOutput call for each on screen cell that is changed,
|
(resize, mouse tracking, etc.)
|
||||||
but experimentally I wasn't able to notice the inefficiency.
|
|
||||||
|
|
||||||
I haven't figured out how to cleanly resolve the dichotomy between cygwin
|
I haven't figured out how to cleanly resolve the dichotomy between cygwin
|
||||||
style termios and the Windows Console API; it seems that perhaps nobody else
|
style termios and the Windows Console API; it seems that perhaps nobody else
|
||||||
has either. If anyone has suggestions, let me know!
|
has either. If anyone has suggestions, let me know! Really, if you're
|
||||||
|
using a Windows application, you should use the native Windows console or a
|
||||||
|
fully compatible consule implementation. We expect that Windows 10
|
||||||
|
ships with a less crippled implementation than prior releases -- we haven't
|
||||||
|
tested that, lacking Windows 10 ourselves.
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
@ -24,44 +25,62 @@ import (
|
|||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makebox(s tcell.BufferedScreen) {
|
func makebox(s tcell.Screen) {
|
||||||
w, h := s.Size()
|
w, h := s.Size()
|
||||||
|
|
||||||
if w == 0 || h == 0 {
|
if w == 0 || h == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glyphs := []rune { '@', '#', '&', '*', '=', '%', 'Z', 'A' }
|
||||||
|
|
||||||
lx := rand.Int() % w
|
lx := rand.Int() % w
|
||||||
ly := rand.Int() % h
|
ly := rand.Int() % h
|
||||||
lw := rand.Int() % (w-lx)
|
lw := rand.Int() % (w - lx)
|
||||||
lh := rand.Int() % (h-ly)
|
lh := rand.Int() % (h - ly)
|
||||||
st := tcell.StyleDefault.Background(tcell.Color(rand.Int() % s.Colors()))
|
st := tcell.StyleDefault
|
||||||
|
gl := ' '
|
||||||
|
if s.Colors() > 1 {
|
||||||
|
st = st.Background(tcell.Color(rand.Int() % s.Colors()))
|
||||||
|
} else {
|
||||||
|
st = st.Reverse(rand.Int() % 2 == 0)
|
||||||
|
gl = glyphs[rand.Int() % len(glyphs)]
|
||||||
|
}
|
||||||
|
|
||||||
for row := 0; row < lh; row++ {
|
for row := 0; row < lh; row++ {
|
||||||
for col := 0; col < lw; col++ {
|
for col := 0; col < lw; col++ {
|
||||||
s.SetCell(lx + col, ly + row, st, ' ')
|
s.SetCell(lx+col, ly+row, st, gl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.Show()
|
s.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s, e := tcell.NewBufferedScreen()
|
s, e := tcell.NewScreen()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
panic(e.Error())
|
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if e = s.Init(); e != nil {
|
if e = s.Init(); e != nil {
|
||||||
panic(e.Error())
|
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.SetStyle(tcell.StyleDefault.
|
||||||
|
Foreground(tcell.ColorBlack).
|
||||||
|
Background(tcell.ColorWhite))
|
||||||
|
s.Clear()
|
||||||
|
|
||||||
|
quit := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
ev := s.PollEvent()
|
ev := s.PollEvent()
|
||||||
switch ev := ev.(type) {
|
switch ev := ev.(type) {
|
||||||
case *tcell.EventKey:
|
case *tcell.EventKey:
|
||||||
switch ev.Key() {
|
switch ev.Key() {
|
||||||
case tcell.KeyEscape:
|
case tcell.KeyEscape, tcell.KeyEnter:
|
||||||
s.Fini()
|
close(quit)
|
||||||
os.Exit(0)
|
return
|
||||||
case tcell.KeyCtrlL:
|
case tcell.KeyCtrlL:
|
||||||
s.Sync()
|
s.Sync()
|
||||||
}
|
}
|
||||||
@ -71,8 +90,22 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
cnt := 0
|
||||||
|
dur := time.Duration(0)
|
||||||
|
loop:
|
||||||
for {
|
for {
|
||||||
|
select {
|
||||||
|
case <-quit:
|
||||||
|
break loop
|
||||||
|
case <-time.After(time.Millisecond * 50):
|
||||||
|
}
|
||||||
|
start := time.Now()
|
||||||
makebox(s)
|
makebox(s)
|
||||||
time.Sleep(time.Millisecond*10)
|
cnt++
|
||||||
|
dur += time.Now().Sub(start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.Fini()
|
||||||
|
fmt.Printf("Finished %d boxes in %s\n", cnt, dur)
|
||||||
|
fmt.Printf("Average is %0.3f ms / box\n", (float64(dur)/float64(cnt))/1000000.0)
|
||||||
}
|
}
|
||||||
|
228
_demos/mouse.go
228
_demos/mouse.go
@ -25,60 +25,186 @@ import (
|
|||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This program just shows simple mouse and keyboard events. Press ESC to
|
var defStyle tcell.Style
|
||||||
// exit.
|
|
||||||
func main() {
|
|
||||||
s, e := tcell.NewBufferedScreen()
|
|
||||||
if e != nil {
|
|
||||||
fmt.Printf("oops: %v", e)
|
|
||||||
}
|
|
||||||
s.Init()
|
|
||||||
s.EnableMouse()
|
|
||||||
s.Clear()
|
|
||||||
|
|
||||||
i := 1
|
func emitStr(s tcell.Screen, x, y int, style tcell.Style, str string) {
|
||||||
for _, c := range "Press ESC to exit." {
|
for _, c := range str {
|
||||||
s.SetCell(i, 1, tcell.StyleDefault, c)
|
s.SetCell(x, y, style, c)
|
||||||
i++
|
x++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawBox(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, r rune) {
|
||||||
|
if y2 < y1 {
|
||||||
|
y1, y2 = y2, y1
|
||||||
|
}
|
||||||
|
if x2 < x1 {
|
||||||
|
x1, x2 = x2, x1
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for row := y1; row <= y2; row++ {
|
||||||
s.Show()
|
for col := x1; col <= x2; col++ {
|
||||||
ev := s.PollEvent()
|
s.SetCell(col, row, style, r)
|
||||||
st := tcell.StyleDefault.Background(tcell.ColorBrightRed)
|
}
|
||||||
up := tcell.StyleDefault.Background(tcell.ColorBlue)
|
}
|
||||||
switch ev := ev.(type) {
|
}
|
||||||
case *tcell.EventResize:
|
|
||||||
s.Sync()
|
func drawSelect(s tcell.Screen, x1, y1, x2, y2 int, sel bool) {
|
||||||
x, y := ev.Size()
|
|
||||||
s.SetCell(x-1, y-1, st, 'R')
|
if y2 < y1 {
|
||||||
case *tcell.EventKey:
|
y1, y2 = y2, y1
|
||||||
x, y := s.Size()
|
}
|
||||||
s.SetCell(x-2, y-2, st, ev.Rune())
|
if x2 < x1 {
|
||||||
s.SetCell(x-1, y-1, st, 'K')
|
x1, x2 = x2, x1
|
||||||
if ev.Key() == tcell.KeyEscape {
|
}
|
||||||
s.Fini()
|
for row := y1; row <= y2; row++ {
|
||||||
os.Exit(0)
|
for col := x1; col <= x2; col++ {
|
||||||
}
|
if cp := s.GetCell(col, row); cp != nil {
|
||||||
case *tcell.EventMouse:
|
st := cp.Style
|
||||||
x, y := ev.Position()
|
if st == tcell.StyleDefault {
|
||||||
switch ev.Buttons() {
|
st = defStyle
|
||||||
case tcell.ButtonNone:
|
}
|
||||||
s.SetCell(x, y, up, '-')
|
st = st.Reverse(sel)
|
||||||
case tcell.Button1:
|
cp.Style = st
|
||||||
s.SetCell(x, y, st, '1')
|
s.PutCell(col, row, cp)
|
||||||
case tcell.Button2:
|
}
|
||||||
s.SetCell(x, y, st, '2')
|
}
|
||||||
case tcell.Button3:
|
}
|
||||||
s.SetCell(x, y, st, '3')
|
}
|
||||||
default:
|
|
||||||
s.SetCell(x, y, st, '*')
|
// This program just shows simple mouse and keyboard events. Press ESC to
|
||||||
}
|
// exit.
|
||||||
x, y = s.Size()
|
func main() {
|
||||||
s.SetCell(x-1, y-1, st, 'M')
|
s, e := tcell.NewScreen()
|
||||||
default:
|
if e != nil {
|
||||||
x, y := s.Size()
|
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||||
s.SetCell(x-1, y-1, st, 'X')
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if e := s.Init(); e != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defStyle = tcell.StyleDefault.
|
||||||
|
Background(tcell.ColorBlack).
|
||||||
|
Foreground(tcell.ColorWhite)
|
||||||
|
s.SetStyle(defStyle)
|
||||||
|
s.EnableMouse()
|
||||||
|
s.Clear()
|
||||||
|
|
||||||
|
posfmt := "Mouse: %d, %d "
|
||||||
|
btnfmt := "Buttons: %-20s"
|
||||||
|
white := tcell.StyleDefault.
|
||||||
|
Foreground(tcell.ColorBrightWhite).Background(tcell.ColorRed)
|
||||||
|
|
||||||
|
mx, my := -1, -1
|
||||||
|
ox, oy := -1, -1
|
||||||
|
bx, by := -1, -1
|
||||||
|
w, h := s.Size()
|
||||||
|
lchar := '*'
|
||||||
|
bstr := ""
|
||||||
|
|
||||||
|
for {
|
||||||
|
drawBox(s, 1, 1, 31, 3, white, ' ')
|
||||||
|
emitStr(s, 1, 1, white, "Press ESC to exit, C to clear.")
|
||||||
|
emitStr(s, 1, 2, white, fmt.Sprintf(posfmt, mx, my))
|
||||||
|
emitStr(s, 1, 3, white, fmt.Sprintf(btnfmt, bstr))
|
||||||
|
|
||||||
|
s.Show()
|
||||||
|
bstr = ""
|
||||||
|
ev := s.PollEvent()
|
||||||
|
st := tcell.StyleDefault.Background(tcell.ColorBrightRed)
|
||||||
|
up := tcell.StyleDefault.
|
||||||
|
Background(tcell.ColorBrightBlue).
|
||||||
|
Foreground(tcell.ColorBrightGreen)
|
||||||
|
w, h = s.Size()
|
||||||
|
|
||||||
|
// always clear any old selection box
|
||||||
|
if ox >= 0 && oy >= 0 && bx >= 0 {
|
||||||
|
drawSelect(s, ox, oy, bx, by, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ev := ev.(type) {
|
||||||
|
case *tcell.EventResize:
|
||||||
|
s.Sync()
|
||||||
|
s.SetCell(w-1, h-1, st, 'R')
|
||||||
|
case *tcell.EventKey:
|
||||||
|
s.SetCell(w-2, h-2, st, ev.Rune())
|
||||||
|
s.SetCell(w-1, h-1, st, 'K')
|
||||||
|
if ev.Key() == tcell.KeyEscape {
|
||||||
|
s.Fini()
|
||||||
|
os.Exit(0)
|
||||||
|
} else if ev.Rune() == 'C' || ev.Rune() == 'c' {
|
||||||
|
s.Clear()
|
||||||
|
}
|
||||||
|
case *tcell.EventMouse:
|
||||||
|
x, y := ev.Position()
|
||||||
|
button := ev.Buttons()
|
||||||
|
for i := uint(0); i < 8; i++ {
|
||||||
|
if int(button) & (1 << i) != 0 {
|
||||||
|
bstr += fmt.Sprintf(" Button%d", i+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if button & tcell.WheelUp != 0 {
|
||||||
|
bstr += " WheelUp"
|
||||||
|
}
|
||||||
|
if button & tcell.WheelDown != 0 {
|
||||||
|
bstr += " WheelDown"
|
||||||
|
}
|
||||||
|
if button & tcell.WheelLeft != 0 {
|
||||||
|
bstr += " WheelLeft"
|
||||||
|
}
|
||||||
|
if button & tcell.WheelRight != 0 {
|
||||||
|
bstr += " WheelRight"
|
||||||
|
}
|
||||||
|
// Only buttons, not wheel events
|
||||||
|
button &= tcell.ButtonMask(0xff)
|
||||||
|
ch := '*'
|
||||||
|
|
||||||
|
if button != tcell.ButtonNone && ox < 0 {
|
||||||
|
ox, oy = x, y
|
||||||
|
}
|
||||||
|
switch ev.Buttons() {
|
||||||
|
case tcell.ButtonNone:
|
||||||
|
if ox >= 0 {
|
||||||
|
bg := tcell.Color((lchar - '0')*2+1)
|
||||||
|
drawBox(s, ox, oy, x, y,
|
||||||
|
up.Background(bg),
|
||||||
|
lchar)
|
||||||
|
ox, oy = -1, -1
|
||||||
|
bx, by = -1, -1
|
||||||
|
}
|
||||||
|
case tcell.Button1:
|
||||||
|
ch = '1'
|
||||||
|
case tcell.Button2:
|
||||||
|
ch = '2'
|
||||||
|
case tcell.Button3:
|
||||||
|
ch = '3'
|
||||||
|
case tcell.Button4:
|
||||||
|
ch = '4'
|
||||||
|
case tcell.Button5:
|
||||||
|
ch = '5'
|
||||||
|
case tcell.Button6:
|
||||||
|
ch = '6'
|
||||||
|
case tcell.Button7:
|
||||||
|
ch = '7'
|
||||||
|
case tcell.Button8:
|
||||||
|
ch = '8'
|
||||||
|
default:
|
||||||
|
ch = '*'
|
||||||
|
|
||||||
|
}
|
||||||
|
if button != tcell.ButtonNone {
|
||||||
|
bx, by = x, y
|
||||||
|
}
|
||||||
|
lchar = ch
|
||||||
|
s.SetCell(w-1, h-1, st, 'M')
|
||||||
|
mx, my = x, y
|
||||||
|
default:
|
||||||
|
s.SetCell(w-1, h-1, st, 'X')
|
||||||
|
}
|
||||||
|
|
||||||
|
if ox >= 0 && bx >= 0 {
|
||||||
|
drawSelect(s, ox, oy, bx, by, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
316
buffered.go
316
buffered.go
@ -1,316 +0,0 @@
|
|||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/mattn/go-runewidth"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BufferedScreen is like the base screen, but is buffered. Each screen
|
|
||||||
// represents the root window that applications interface with.
|
|
||||||
type BufferedScreen interface {
|
|
||||||
// Init initializes the screen for use.
|
|
||||||
Init() error
|
|
||||||
|
|
||||||
// Fini finazlizes the screen also releasing resources.
|
|
||||||
Fini()
|
|
||||||
|
|
||||||
// Clear erases the screen.
|
|
||||||
Clear()
|
|
||||||
|
|
||||||
// SetCell sets the cell at the given location.
|
|
||||||
// The ch array contains at most one rune of width > 0, and the
|
|
||||||
// runes with zero width (combining marks) must follow the first
|
|
||||||
// non-zero width character. (If only combining marks are present,
|
|
||||||
// a space character will be filled in.)
|
|
||||||
//
|
|
||||||
// Note that double wide runes occupy two cells, and attempts to
|
|
||||||
// place a character at the immediately adjacent cell will have
|
|
||||||
// undefined effects. Double wide runes that are printed in the
|
|
||||||
// last column will be replaced with a single width space on output.
|
|
||||||
SetCell(x int, y int, style Style, ch ...rune)
|
|
||||||
|
|
||||||
// ShowCursor is used to display the cursor at a given location.
|
|
||||||
ShowCursor(x int, y int)
|
|
||||||
|
|
||||||
// HideCursor is used to hide the cursor.
|
|
||||||
HideCursor()
|
|
||||||
|
|
||||||
// Size returns the screen size as width, height. This changes in
|
|
||||||
// response to a call to Clear or Flush.
|
|
||||||
Size() (int, int)
|
|
||||||
|
|
||||||
// PollEvent waits for events to arrive. Main application loops
|
|
||||||
// can generally spin on this.
|
|
||||||
PollEvent() Event
|
|
||||||
|
|
||||||
// PostEvent posts an event into the event stream.
|
|
||||||
PostEvent(Event)
|
|
||||||
|
|
||||||
// Colors returns the number of colors. All colors are assumed to
|
|
||||||
// use the ANSI color map.
|
|
||||||
Colors() int
|
|
||||||
|
|
||||||
// EnableMouse enables mouse events, if your terminal has support
|
|
||||||
// for them.
|
|
||||||
EnableMouse()
|
|
||||||
|
|
||||||
// DisableMouse disables mouse events.
|
|
||||||
DisableMouse()
|
|
||||||
|
|
||||||
// Sync synchronizes the buffered content with the screen, without
|
|
||||||
// making any assumptions about the content that is displayed.
|
|
||||||
// This is most often useful when some other program has altered the
|
|
||||||
// screen state. Because this is a full redraw, it can be visually
|
|
||||||
// jarring & expensive, and should only be done when truly needed.
|
|
||||||
Sync()
|
|
||||||
|
|
||||||
// Show writes the contents of the buffer to the physical screen.
|
|
||||||
// Only the contents that have changed will be written. This is what
|
|
||||||
// applications call to redraw the screen.
|
|
||||||
Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
type cell struct {
|
|
||||||
ch []rune
|
|
||||||
dirty bool
|
|
||||||
width uint8
|
|
||||||
style Style
|
|
||||||
}
|
|
||||||
|
|
||||||
type bScreen struct {
|
|
||||||
s Screen
|
|
||||||
cells []cell
|
|
||||||
w int
|
|
||||||
h int
|
|
||||||
cursorx int
|
|
||||||
cursory int
|
|
||||||
clear bool
|
|
||||||
|
|
||||||
sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) Init() error {
|
|
||||||
if e := b.s.Init(); e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate cells
|
|
||||||
b.w, b.h = b.s.Size()
|
|
||||||
b.cells = make([]cell, b.w*b.h)
|
|
||||||
b.cursorx = -1
|
|
||||||
b.cursory = -1
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) Fini() {
|
|
||||||
b.Lock()
|
|
||||||
b.cells = nil
|
|
||||||
b.w = 0
|
|
||||||
b.h = 0
|
|
||||||
b.clear = false
|
|
||||||
b.cursorx = -1
|
|
||||||
b.cursory = -1
|
|
||||||
b.Unlock()
|
|
||||||
b.s.Fini()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) Colors() int {
|
|
||||||
return b.s.Colors()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) Size() (int, int) {
|
|
||||||
b.Lock()
|
|
||||||
w, h := b.w, b.h
|
|
||||||
b.Unlock()
|
|
||||||
return w, h
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) PollEvent() Event {
|
|
||||||
ev := b.s.PollEvent()
|
|
||||||
|
|
||||||
// We need to capture resize events from the bottom screen, so that
|
|
||||||
// we can readjust our buffer. This is important since the we need to
|
|
||||||
// do any adjustment before the application starts drawing in response,
|
|
||||||
// or coordinates may be erroneously believed out of range and results
|
|
||||||
// discarded.
|
|
||||||
if _, ok := ev.(*EventResize); ok {
|
|
||||||
b.Lock()
|
|
||||||
b.checkResize()
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
return ev
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) PostEvent(ev Event) {
|
|
||||||
// See comment in PollEvent for why we do this. Note that normally
|
|
||||||
// events are posted directly into the screen below, so these are only
|
|
||||||
// application supplied events.
|
|
||||||
if _, ok := ev.(*EventResize); ok {
|
|
||||||
b.Lock()
|
|
||||||
b.checkResize()
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
b.s.PostEvent(ev)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) Clear() {
|
|
||||||
b.Lock()
|
|
||||||
for i := range b.cells {
|
|
||||||
b.cells[i].dirty = true
|
|
||||||
b.cells[i].style = StyleDefault
|
|
||||||
b.cells[i].ch = nil
|
|
||||||
}
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) HideCursor() {
|
|
||||||
b.Lock()
|
|
||||||
b.cursorx = -1
|
|
||||||
b.cursory = -1
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) ShowCursor(x, y int) {
|
|
||||||
b.Lock()
|
|
||||||
b.cursorx = x
|
|
||||||
b.cursory = y
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) checkResize() {
|
|
||||||
// Must be called with lock held!
|
|
||||||
w, h := b.s.Size()
|
|
||||||
if w == b.w && h == b.h {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// We could reuse the cells, if we knew that both the row size did not
|
|
||||||
// increase, and the total size did not increase. For now we just
|
|
||||||
// take the lazy approach and grow a new cells structure. It would be
|
|
||||||
// bad if the window size changes very frequently, but that shouldn't
|
|
||||||
// happen.
|
|
||||||
newc := make([]cell, w*h)
|
|
||||||
for row := 0; row < h && row < b.h; row++ {
|
|
||||||
for col := 0; col < w && col < b.w; col++ {
|
|
||||||
newc[(row*w)+col] = b.cells[(row*b.w)+col]
|
|
||||||
newc[(row*w)+col].dirty = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.w = w
|
|
||||||
b.h = h
|
|
||||||
b.cells = newc
|
|
||||||
// force a full screen redraw - just to be sure
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) SetCell(x int, y int, style Style, ch ...rune) {
|
|
||||||
// compare ch, compare style
|
|
||||||
b.Lock()
|
|
||||||
if x < 0 || y < 0 || x >= b.w || y >= b.h {
|
|
||||||
b.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cell := &b.cells[(y*b.w)+x]
|
|
||||||
|
|
||||||
// check to see if its the same value, if it is, don't mark it dirty
|
|
||||||
match := false
|
|
||||||
if len(ch) == len(cell.ch) && style == cell.style {
|
|
||||||
match = true
|
|
||||||
for i, r := range cell.ch {
|
|
||||||
if ch[i] != r {
|
|
||||||
match = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !match {
|
|
||||||
cell.dirty = true
|
|
||||||
cell.ch = ch
|
|
||||||
cell.style = style
|
|
||||||
cell.width = 1
|
|
||||||
for i := range cell.ch {
|
|
||||||
if runewidth.RuneWidth(ch[i]) == 2 {
|
|
||||||
cell.width = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) Show() {
|
|
||||||
b.Lock()
|
|
||||||
|
|
||||||
b.checkResize()
|
|
||||||
|
|
||||||
b.s.HideCursor()
|
|
||||||
|
|
||||||
if b.clear {
|
|
||||||
b.s.Clear()
|
|
||||||
b.clear = false
|
|
||||||
}
|
|
||||||
|
|
||||||
for row := 0; row < b.h; row++ {
|
|
||||||
for col := 0; col < b.w; col++ {
|
|
||||||
c := &b.cells[(row*b.w)+col]
|
|
||||||
if !c.dirty {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
b.s.SetCell(col, row, c.style, c.ch...)
|
|
||||||
c.dirty = false
|
|
||||||
if c.width == 2 {
|
|
||||||
col++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.s.ShowCursor(b.cursorx, b.cursory)
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) Sync() {
|
|
||||||
b.Lock()
|
|
||||||
// do a clear screen and also mark everything dirty
|
|
||||||
b.clear = true
|
|
||||||
for i := range b.cells {
|
|
||||||
b.cells[i].dirty = true
|
|
||||||
}
|
|
||||||
b.Unlock()
|
|
||||||
b.Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) EnableMouse() {
|
|
||||||
b.Lock()
|
|
||||||
b.s.EnableMouse()
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bScreen) DisableMouse() {
|
|
||||||
b.Lock()
|
|
||||||
b.s.DisableMouse()
|
|
||||||
b.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBufferedScreen() (BufferedScreen, error) {
|
|
||||||
s, e := NewScreen()
|
|
||||||
if e != nil {
|
|
||||||
return nil, e
|
|
||||||
}
|
|
||||||
return MakeBufferedScreen(s), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeBufferedScreen(s Screen) BufferedScreen {
|
|
||||||
return &bScreen{s: s}
|
|
||||||
}
|
|
170
cell.go
Normal file
170
cell.go
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattn/go-runewidth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cell represents a single character cell. This is primarily intended for
|
||||||
|
// use by Screen implementors.
|
||||||
|
type Cell struct {
|
||||||
|
Ch []rune
|
||||||
|
Dirty bool
|
||||||
|
Width uint8
|
||||||
|
Style Style
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearCells clears the entire set of cells, making them all whitespace with
|
||||||
|
// the provided attribute.
|
||||||
|
func ClearCells(c []Cell, style Style) {
|
||||||
|
for i := range c {
|
||||||
|
c[i].Ch = nil
|
||||||
|
c[i].Style = style
|
||||||
|
c[i].Width = 1
|
||||||
|
c[i].Dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidateCells marks all cells in the array dirty.
|
||||||
|
func InvalidateCells(c []Cell) {
|
||||||
|
for i := range c {
|
||||||
|
c[i].Dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResizeCells is used to create a new cells array, with different dimensions,
|
||||||
|
// while preserving the original contents. The returned array may be the same
|
||||||
|
// as the original, if we can reuse it. Hence, the old array should no longer
|
||||||
|
// be used by the caller after this call. The cells will be marked dirty so
|
||||||
|
// that they can be redrawn.
|
||||||
|
func ResizeCells(oldc []Cell, oldw, oldh, neww, newh int) []Cell {
|
||||||
|
|
||||||
|
if oldh == newh && oldw == neww {
|
||||||
|
return oldc
|
||||||
|
}
|
||||||
|
newc := oldc
|
||||||
|
|
||||||
|
// Probably are other conditions where we could reuse, but if there is
|
||||||
|
// any doubt at all, its easier & safest to just realloc the window.
|
||||||
|
if newh > oldh || neww > oldw {
|
||||||
|
newc = make([]Cell, neww*newh)
|
||||||
|
}
|
||||||
|
for row := 0; row < newh && row < oldh; row++ {
|
||||||
|
for col := 0; col < oldw && col < neww; col++ {
|
||||||
|
newc[(row*neww)+col] = oldc[(row*oldw)+col]
|
||||||
|
newc[(row*neww)+col].Dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCell writes the contents into the cell. It ensures that at most one
|
||||||
|
// nonzero width rune is present in the Ch array (and if any zero width runes
|
||||||
|
// are present without a non-zero one, then a space is inserted), and updates
|
||||||
|
// the Dirty bit if the contents are different than they were.
|
||||||
|
func (c *Cell) SetCell(ch []rune, style Style) {
|
||||||
|
|
||||||
|
c.PutChars(ch)
|
||||||
|
c.PutStyle(style)
|
||||||
|
/*
|
||||||
|
var mainc rune
|
||||||
|
var width uint8
|
||||||
|
var compc []rune
|
||||||
|
|
||||||
|
width = 1
|
||||||
|
mainc = ' '
|
||||||
|
for _, r := range ch {
|
||||||
|
if r < ' ' {
|
||||||
|
// skip over non-printable control characters
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch runewidth.RuneWidth(r) {
|
||||||
|
case 1:
|
||||||
|
mainc = r
|
||||||
|
width = 1
|
||||||
|
case 2:
|
||||||
|
mainc = r
|
||||||
|
width = 2
|
||||||
|
case 0:
|
||||||
|
compc = append(compc, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newch := append([]rune{mainc}, compc...)
|
||||||
|
if len(newch) != len(c.Ch) || style != c.Style || c.Dirty {
|
||||||
|
c.Dirty = true
|
||||||
|
} else {
|
||||||
|
for i := range newch {
|
||||||
|
if newch[i] != c.Ch[i] {
|
||||||
|
c.Dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Ch = newch
|
||||||
|
c.Style = style
|
||||||
|
c.Width = width
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cell) PutChars(ch []rune) {
|
||||||
|
|
||||||
|
var mainc rune
|
||||||
|
var width uint8
|
||||||
|
var compc []rune
|
||||||
|
|
||||||
|
width = 1
|
||||||
|
mainc = ' '
|
||||||
|
for _, r := range ch {
|
||||||
|
if r < ' ' {
|
||||||
|
// skip over non-printable control characters
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch runewidth.RuneWidth(r) {
|
||||||
|
case 1:
|
||||||
|
mainc = r
|
||||||
|
width = 1
|
||||||
|
case 2:
|
||||||
|
mainc = r
|
||||||
|
width = 2
|
||||||
|
case 0:
|
||||||
|
compc = append(compc, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newch := append([]rune{mainc}, compc...)
|
||||||
|
if len(newch) != len(c.Ch) {
|
||||||
|
c.Dirty = true
|
||||||
|
} else {
|
||||||
|
for i := range newch {
|
||||||
|
if newch[i] != c.Ch[i] {
|
||||||
|
c.Dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Ch = newch
|
||||||
|
c.Width = width
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cell) PutChar(ch rune) {
|
||||||
|
c.PutChars([]rune{ch})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cell) PutStyle(style Style) {
|
||||||
|
if c.Style != style {
|
||||||
|
c.Style = style
|
||||||
|
c.Dirty = true
|
||||||
|
}
|
||||||
|
}
|
327
console_win.go
327
console_win.go
@ -17,11 +17,10 @@
|
|||||||
package tcell
|
package tcell
|
||||||
|
|
||||||
import (
|
import (
|
||||||
// "fmt"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/mattn/go-runewidth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type cScreen struct {
|
type cScreen struct {
|
||||||
@ -30,13 +29,21 @@ type cScreen struct {
|
|||||||
mbtns uint32 // debounce mouse buttons
|
mbtns uint32 // debounce mouse buttons
|
||||||
evch chan Event
|
evch chan Event
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
|
curx int
|
||||||
|
cury int
|
||||||
|
style Style
|
||||||
|
clear bool
|
||||||
|
|
||||||
w int
|
w int
|
||||||
h int
|
h int
|
||||||
|
|
||||||
oscreen consoleInfo
|
oscreen consoleInfo
|
||||||
ocursor cursorInfo
|
ocursor cursorInfo
|
||||||
omode uint32
|
oimode uint32
|
||||||
|
oomode uint32
|
||||||
|
cells []Cell
|
||||||
|
|
||||||
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// all Windows systems are little endian
|
// all Windows systems are little endian
|
||||||
@ -46,19 +53,18 @@ var k32 = syscall.NewLazyDLL("kernel32.dll")
|
|||||||
// characters (Unicode) are in use. The documentation refers to them
|
// characters (Unicode) are in use. The documentation refers to them
|
||||||
// without this suffix, as the resolution is made via preprocessor.
|
// without this suffix, as the resolution is made via preprocessor.
|
||||||
var (
|
var (
|
||||||
procReadConsoleInput = k32.NewProc("ReadConsoleInputW")
|
procReadConsoleInput = k32.NewProc("ReadConsoleInputW")
|
||||||
procGetConsoleCursorInfo = k32.NewProc("GetConsoleCursorInfo")
|
procGetConsoleCursorInfo = k32.NewProc("GetConsoleCursorInfo")
|
||||||
procSetConsoleCursorInfo = k32.NewProc("SetConsoleCursorInfo")
|
procSetConsoleCursorInfo = k32.NewProc("SetConsoleCursorInfo")
|
||||||
procSetConsoleCursorPosition = k32.NewProc("SetConsoleCursorPosition")
|
procSetConsoleCursorPosition = k32.NewProc("SetConsoleCursorPosition")
|
||||||
procSetConsoleMode = k32.NewProc("SetConsoleMode")
|
procSetConsoleMode = k32.NewProc("SetConsoleMode")
|
||||||
procGetConsoleMode = k32.NewProc("GetConsoleMode")
|
procGetConsoleMode = k32.NewProc("GetConsoleMode")
|
||||||
procWriteConsoleOutput = k32.NewProc("WriteConsoleOutputW")
|
procGetConsoleScreenBufferInfo = k32.NewProc("GetConsoleScreenBufferInfo")
|
||||||
procGetConsoleScreenBufferInfo = k32.NewProc("GetConsoleScreenBufferInfo")
|
procFillConsoleOutputAttribute = k32.NewProc("FillConsoleOutputAttribute")
|
||||||
procFillConsoleOutputAttribute = k32.NewProc("FillConsoleOutputAttribute")
|
procFillConsoleOutputCharacter = k32.NewProc("FillConsoleOutputCharacterW")
|
||||||
procFillConsoleOutputCharacter = k32.NewProc("FillConsoleOutputCharacterW")
|
procSetConsoleWindowInfo = k32.NewProc("SetConsoleWindowInfo")
|
||||||
procSetConsoleWindowInfo = k32.NewProc("SetConsoleWindowInfo")
|
procSetConsoleScreenBufferSize = k32.NewProc("SetConsoleScreenBufferSize")
|
||||||
procSetConsoleScreenBufferSize = k32.NewProc("SetConsoleScreenBufferSize")
|
procSetConsoleTextAttribute = k32.NewProc("SetConsoleTextAttribute")
|
||||||
procSetConsoleActiveScreenBuffer = k32.NewProc("SetConsoleActiveScreenBuffer")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// We have to bring in the kernel32.dll directly, so we can get access to some
|
// We have to bring in the kernel32.dll directly, so we can get access to some
|
||||||
@ -85,38 +91,45 @@ func (s *cScreen) Init() error {
|
|||||||
s.out = out
|
s.out = out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.curx = -1
|
||||||
|
s.cury = -1
|
||||||
s.getCursorInfo(&s.ocursor)
|
s.getCursorInfo(&s.ocursor)
|
||||||
s.getConsoleInfo(&s.oscreen)
|
s.getConsoleInfo(&s.oscreen)
|
||||||
s.getMode(&s.omode)
|
s.getOutMode(&s.oomode)
|
||||||
|
s.getInMode(&s.oimode)
|
||||||
if err := s.setMode(modeResizeEn); err != nil {
|
|
||||||
syscall.Close(s.in)
|
|
||||||
syscall.Close(s.out)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.resize()
|
s.resize()
|
||||||
s.Clear()
|
|
||||||
s.HideCursor()
|
s.setInMode(modeResizeEn)
|
||||||
//procSetConsoleActiveScreenBuffer.Call(uintptr(s.out))
|
s.setOutMode(0)
|
||||||
|
s.clearScreen(s.style)
|
||||||
|
s.hideCursor()
|
||||||
go s.scanInput()
|
go s.scanInput()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) EnableMouse() {
|
func (s *cScreen) EnableMouse() {
|
||||||
s.setMode(modeResizeEn | modeMouseEn)
|
s.setInMode(modeResizeEn | modeMouseEn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) DisableMouse() {
|
func (s *cScreen) DisableMouse() {
|
||||||
s.setMode(modeResizeEn)
|
s.setInMode(modeResizeEn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) Fini() {
|
func (s *cScreen) Fini() {
|
||||||
s.setCursorPos(0, 0)
|
s.style = StyleDefault
|
||||||
|
s.curx = -1
|
||||||
|
s.cury = -1
|
||||||
|
|
||||||
s.setCursorInfo(&s.ocursor)
|
s.setCursorInfo(&s.ocursor)
|
||||||
s.setMode(s.omode)
|
s.setInMode(s.oimode)
|
||||||
|
s.setOutMode(s.oomode)
|
||||||
s.setBufferSize(int(s.oscreen.size.x), int(s.oscreen.size.y))
|
s.setBufferSize(int(s.oscreen.size.x), int(s.oscreen.size.y))
|
||||||
s.Clear()
|
s.clearScreen(StyleDefault)
|
||||||
|
s.setCursorPos(0, 0)
|
||||||
|
procSetConsoleTextAttribute.Call(
|
||||||
|
uintptr(s.out),
|
||||||
|
uintptr(mapStyle(StyleDefault)))
|
||||||
|
|
||||||
close(s.quit)
|
close(s.quit)
|
||||||
syscall.Close(s.in)
|
syscall.Close(s.in)
|
||||||
@ -161,25 +174,35 @@ type rect struct {
|
|||||||
bottom int16
|
bottom int16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) ShowCursor(x, y int) {
|
func (s *cScreen) showCursor() {
|
||||||
var curinfo cursorInfo
|
s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
|
||||||
|
}
|
||||||
|
|
||||||
s.getCursorInfo(&curinfo)
|
func (s *cScreen) hideCursor() {
|
||||||
if x < 0 || y < 0 {
|
s.setCursorInfo(&cursorInfo{size: 1, visible: 0})
|
||||||
if curinfo.visible == 0 {
|
}
|
||||||
return
|
|
||||||
}
|
func (s *cScreen) ShowCursor(x, y int) {
|
||||||
curinfo.visible = 0
|
s.Lock()
|
||||||
s.setCursorInfo(&curinfo)
|
s.curx = x
|
||||||
|
s.cury = y
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) doCursor() {
|
||||||
|
x, y := s.curx, s.cury
|
||||||
|
|
||||||
|
if x < 0 || y < 0 || x >= s.w || y >= s.h {
|
||||||
|
s.setCursorPos(0, 0)
|
||||||
|
s.hideCursor()
|
||||||
} else {
|
} else {
|
||||||
curinfo.visible = 1
|
|
||||||
s.setCursorPos(x, y)
|
s.setCursorPos(x, y)
|
||||||
s.setCursorInfo(&curinfo)
|
s.showCursor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cScreen) HideCursor() {
|
func (c *cScreen) HideCursor() {
|
||||||
c.ShowCursor(10, 5)
|
c.ShowCursor(-1, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
type charInfo struct {
|
type charInfo struct {
|
||||||
@ -208,6 +231,12 @@ type mouseRecord struct {
|
|||||||
mod uint32
|
mod uint32
|
||||||
flags uint32
|
flags uint32
|
||||||
}
|
}
|
||||||
|
const (
|
||||||
|
mouseDoubleClick uint32 = 0x2
|
||||||
|
mouseHWheeled uint32 = 0x8
|
||||||
|
mouseVWheeled uint32 = 0x4
|
||||||
|
mouseMoved uint32 = 0x1
|
||||||
|
)
|
||||||
|
|
||||||
type resizeRecord struct {
|
type resizeRecord struct {
|
||||||
x int16
|
x int16
|
||||||
@ -422,7 +451,8 @@ func (s *cScreen) getConsoleInput() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for krec.repeat > 0 {
|
for krec.repeat > 0 {
|
||||||
s.PostEvent(NewEventKey(key, rune(krec.ch), mod2mask(krec.mod)))
|
s.PostEvent(NewEventKey(key, rune(krec.ch),
|
||||||
|
mod2mask(krec.mod)))
|
||||||
krec.repeat--
|
krec.repeat--
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,13 +465,6 @@ func (s *cScreen) getConsoleInput() error {
|
|||||||
mrec.flags = getu32(rec.data[12:]) // not using yet
|
mrec.flags = getu32(rec.data[12:]) // not using yet
|
||||||
btns := ButtonNone
|
btns := ButtonNone
|
||||||
|
|
||||||
if mrec.btns == s.mbtns {
|
|
||||||
// If the buttons have not changed,
|
|
||||||
// then don't report the event. We aren't
|
|
||||||
// reporting motion events at this time.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mbtns = mrec.btns
|
s.mbtns = mrec.btns
|
||||||
if mrec.btns&0x1 != 0 {
|
if mrec.btns&0x1 != 0 {
|
||||||
btns |= Button1
|
btns |= Button1
|
||||||
@ -459,7 +482,23 @@ func (s *cScreen) getConsoleInput() error {
|
|||||||
btns |= Button5
|
btns |= Button5
|
||||||
}
|
}
|
||||||
|
|
||||||
s.PostEvent(NewEventMouse(int(mrec.x), int(mrec.y), btns, mod2mask(mrec.mod)))
|
if mrec.flags & mouseVWheeled != 0 {
|
||||||
|
if mrec.btns & 0x80000000 == 0 {
|
||||||
|
btns |= WheelUp
|
||||||
|
} else {
|
||||||
|
btns |= WheelDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mrec.flags & mouseHWheeled != 0 {
|
||||||
|
if mrec.btns & 0x80000000 == 0 {
|
||||||
|
btns |= WheelRight
|
||||||
|
} else {
|
||||||
|
btns |= WheelLeft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we ignore double click, events are delivered normally
|
||||||
|
s.PostEvent(NewEventMouse(int(mrec.x), int(mrec.y), btns,
|
||||||
|
mod2mask(mrec.mod)))
|
||||||
|
|
||||||
case resizeEvent:
|
case resizeEvent:
|
||||||
var rrec resizeRecord
|
var rrec resizeRecord
|
||||||
@ -554,32 +593,120 @@ func mapStyle(style Style) uint16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) SetCell(x, y int, style Style, ch ...rune) {
|
func (s *cScreen) SetCell(x, y int, style Style, ch ...rune) {
|
||||||
r := ' '
|
|
||||||
w := 0
|
s.Lock()
|
||||||
for i := range ch {
|
if x < 0 || y < 0 || x >= int(s.w) || y >= int(s.h) {
|
||||||
if w = runewidth.RuneWidth(ch[i]); w != 0 {
|
s.Unlock()
|
||||||
r = ch[i]
|
return
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Windows console lacks support for combining chars
|
cell := &s.cells[(y*int(s.w))+x]
|
||||||
if w == 0 {
|
cell.SetCell(ch, style)
|
||||||
r = ' '
|
s.Unlock()
|
||||||
w = 1
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) PutCell(x, y int, cell *Cell) {
|
||||||
|
s.Lock()
|
||||||
|
if x < 0 || y < 0 || x >= int(s.w) || y >= int(s.h) {
|
||||||
|
s.Unlock()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
cptr := &s.cells[(y*int(s.w))+x]
|
||||||
|
cptr.PutChars(cell.Ch)
|
||||||
|
cptr.PutStyle(cell.Style)
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
rec := rect{left: int16(x), right: int16(x), top: int16(y), bottom: int16(y)}
|
func (s *cScreen) GetCell(x, y int) *Cell {
|
||||||
pos := coord{x: int16(0), y: int16(0)}
|
s.Lock()
|
||||||
siz := coord{x: 1, y: 1}
|
if x < 0 || y < 0 || x >= int(s.w) || y >= int(s.h) {
|
||||||
dat := charInfo{ch: uint16(r), attr: mapStyle(style)}
|
s.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cell := s.cells[(y*int(s.w))+x]
|
||||||
|
s.Unlock()
|
||||||
|
return &cell
|
||||||
|
}
|
||||||
|
|
||||||
procWriteConsoleOutput.Call(
|
func (s *cScreen) writeString(x, y int, style Style, ch []uint16) {
|
||||||
|
// we assume the caller has hidden the cursor
|
||||||
|
if len(ch) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nw := uint32(len(ch))
|
||||||
|
procSetConsoleTextAttribute.Call(
|
||||||
uintptr(s.out),
|
uintptr(s.out),
|
||||||
uintptr(unsafe.Pointer(&dat)),
|
uintptr(mapStyle(style)))
|
||||||
siz.uintptr(),
|
s.setCursorPos(x, y)
|
||||||
pos.uintptr(),
|
syscall.WriteConsole(s.out, &ch[0], nw, &nw, nil)
|
||||||
uintptr(unsafe.Pointer(&rec)))
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) draw() {
|
||||||
|
// allocate a scratch line bit enough for no combining chars.
|
||||||
|
// if you have combining characters, you may pay for extra allocs.
|
||||||
|
if s.clear {
|
||||||
|
s.clearScreen(s.style)
|
||||||
|
s.clear = false
|
||||||
|
}
|
||||||
|
buf := make([]uint16, 0, s.w)
|
||||||
|
wcs := buf[:]
|
||||||
|
style := Style(-1) // invalid attribute
|
||||||
|
|
||||||
|
x, y := -1, -1
|
||||||
|
|
||||||
|
for row := 0; row < int(s.h); row++ {
|
||||||
|
width := 1
|
||||||
|
for col := 0; col < int(s.w); col += width {
|
||||||
|
|
||||||
|
cell := &s.cells[(row*s.w)+col]
|
||||||
|
width = int(cell.Width)
|
||||||
|
if width < 1 {
|
||||||
|
width = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cell.Dirty || style != cell.Style {
|
||||||
|
s.writeString(x, y, style, wcs)
|
||||||
|
wcs = buf[0:0]
|
||||||
|
style = Style(-1)
|
||||||
|
if !cell.Dirty {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(wcs) == 0 {
|
||||||
|
style = cell.Style
|
||||||
|
x = col
|
||||||
|
y = row
|
||||||
|
}
|
||||||
|
if len(cell.Ch) < 1 {
|
||||||
|
wcs = append(wcs, uint16(' '))
|
||||||
|
} else {
|
||||||
|
wcs = append(wcs, utf16.Encode(cell.Ch)...)
|
||||||
|
}
|
||||||
|
cell.Dirty = false
|
||||||
|
}
|
||||||
|
s.writeString(x, y, style, wcs)
|
||||||
|
wcs = buf[0:0]
|
||||||
|
style = Style(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) Show() {
|
||||||
|
s.Lock()
|
||||||
|
s.hideCursor()
|
||||||
|
s.resize()
|
||||||
|
s.draw()
|
||||||
|
s.doCursor()
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) Sync() {
|
||||||
|
s.Lock()
|
||||||
|
InvalidateCells(s.cells)
|
||||||
|
s.hideCursor()
|
||||||
|
s.resize()
|
||||||
|
s.draw()
|
||||||
|
s.doCursor()
|
||||||
|
s.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
type consoleInfo struct {
|
type consoleInfo struct {
|
||||||
@ -622,10 +749,9 @@ func (s *cScreen) setBufferSize(x, y int) {
|
|||||||
|
|
||||||
func (s *cScreen) Size() (int, int) {
|
func (s *cScreen) Size() (int, int) {
|
||||||
|
|
||||||
info := consoleInfo{}
|
s.Lock()
|
||||||
s.getConsoleInfo(&info)
|
w, h := s.w, s.h
|
||||||
w := int((info.win.right - info.win.left) + 1)
|
s.Unlock()
|
||||||
h := int((info.win.bottom - info.win.top) + 1)
|
|
||||||
|
|
||||||
return w, h
|
return w, h
|
||||||
}
|
}
|
||||||
@ -637,9 +763,15 @@ func (s *cScreen) resize() {
|
|||||||
|
|
||||||
w := int((info.win.right - info.win.left) + 1)
|
w := int((info.win.right - info.win.left) + 1)
|
||||||
h := int((info.win.bottom - info.win.top) + 1)
|
h := int((info.win.bottom - info.win.top) + 1)
|
||||||
|
|
||||||
if s.w == w && s.h == h {
|
if s.w == w && s.h == h {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.cells = ResizeCells(s.cells, s.w, s.h, w, h)
|
||||||
|
s.w = w
|
||||||
|
s.h = h
|
||||||
|
|
||||||
r := rect{0, 0, int16(w - 1), int16(h - 1)}
|
r := rect{0, 0, int16(w - 1), int16(h - 1)}
|
||||||
procSetConsoleWindowInfo.Call(
|
procSetConsoleWindowInfo.Call(
|
||||||
uintptr(s.out),
|
uintptr(s.out),
|
||||||
@ -647,12 +779,21 @@ func (s *cScreen) resize() {
|
|||||||
uintptr(unsafe.Pointer(&r)))
|
uintptr(unsafe.Pointer(&r)))
|
||||||
|
|
||||||
s.setBufferSize(w, h)
|
s.setBufferSize(w, h)
|
||||||
|
|
||||||
|
s.PostEvent(NewEventResize(w, h))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) Clear() {
|
func (s *cScreen) Clear() {
|
||||||
|
s.Lock()
|
||||||
|
ClearCells(s.cells, s.style)
|
||||||
|
s.clear = true
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) clearScreen(style Style) {
|
||||||
pos := coord{0, 0}
|
pos := coord{0, 0}
|
||||||
attr := uint16(0x7) // default white fg, black bg)
|
attr := mapStyle(style)
|
||||||
x, y := s.Size()
|
x, y := s.w, s.h
|
||||||
scratch := uint32(0)
|
scratch := uint32(0)
|
||||||
count := uint32(x * y)
|
count := uint32(x * y)
|
||||||
|
|
||||||
@ -673,9 +814,11 @@ func (s *cScreen) Clear() {
|
|||||||
const (
|
const (
|
||||||
modeMouseEn uint32 = 0x0010
|
modeMouseEn uint32 = 0x0010
|
||||||
modeResizeEn uint32 = 0x0008
|
modeResizeEn uint32 = 0x0008
|
||||||
|
modeWrapEOL uint32 = 0x0002
|
||||||
|
modeCooked uint32 = 0x0001
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *cScreen) setMode(mode uint32) error {
|
func (s *cScreen) setInMode(mode uint32) error {
|
||||||
rv, _, err := procSetConsoleMode.Call(
|
rv, _, err := procSetConsoleMode.Call(
|
||||||
uintptr(s.in),
|
uintptr(s.in),
|
||||||
uintptr(mode))
|
uintptr(mode))
|
||||||
@ -685,8 +828,30 @@ func (s *cScreen) setMode(mode uint32) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) getMode(v *uint32) {
|
func (s *cScreen) setOutMode(mode uint32) error {
|
||||||
|
rv, _, err := procSetConsoleMode.Call(
|
||||||
|
uintptr(s.out),
|
||||||
|
uintptr(mode))
|
||||||
|
if rv == 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) getInMode(v *uint32) {
|
||||||
procGetConsoleMode.Call(
|
procGetConsoleMode.Call(
|
||||||
uintptr(s.in),
|
uintptr(s.in),
|
||||||
uintptr(unsafe.Pointer(v)))
|
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()
|
||||||
|
}
|
||||||
|
359
database.go
359
database.go
@ -1,27 +1,28 @@
|
|||||||
// Generated by ./mkinfo (darwin/amd64) on Sat Sep 26 22:40:41 PDT 2015.
|
// Generated by ./mkinfo (darwin/amd64) on Fri Oct 2 21:03:12 PDT 2015.
|
||||||
// DO NOT HAND-EDIT
|
// DO NOT HAND-EDIT
|
||||||
|
|
||||||
package tcell
|
package tcell
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "adm3a",
|
Name: "adm3a",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1a$<1/>",
|
Clear: "\x1a$<1/>",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
PadChar: "\x00",
|
||||||
CursorBack1: "\b",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorUp1: "\v",
|
CursorBack1: "\b",
|
||||||
KeyUp: "\v",
|
CursorUp1: "\v",
|
||||||
KeyDown: "\n",
|
KeyUp: "\v",
|
||||||
KeyRight: "\f",
|
KeyDown: "\n",
|
||||||
KeyLeft: "\b",
|
KeyRight: "\f",
|
||||||
|
KeyLeft: "\b",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "aixterm",
|
Name: "aixterm",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 25,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J",
|
Clear: "\x1b[H\x1b[J",
|
||||||
@ -31,6 +32,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -72,6 +74,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\x1b[D",
|
CursorBack1: "\x1b[D",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -103,9 +106,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b>",
|
ExitKeypad: "\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -136,7 +140,7 @@ func init() {
|
|||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "beterm",
|
Name: "beterm",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 25,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J",
|
Clear: "\x1b[H\x1b[J",
|
||||||
@ -148,6 +152,7 @@ func init() {
|
|||||||
ExitKeypad: "\x1b[?4l",
|
ExitKeypad: "\x1b[?4l",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -178,7 +183,7 @@ func init() {
|
|||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "bsdos-pc",
|
Name: "bsdos-pc",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 25,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1bc",
|
Clear: "\x1bc",
|
||||||
@ -189,6 +194,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -204,8 +210,8 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "cygwin",
|
Name: "cygwin",
|
||||||
Columns: 80,
|
Columns: -1,
|
||||||
Lines: 24,
|
Lines: -1,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J",
|
Clear: "\x1b[H\x1b[J",
|
||||||
@ -217,6 +223,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -245,72 +252,74 @@ func init() {
|
|||||||
KeyF12: "\x1b[24~",
|
KeyF12: "\x1b[24~",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "d200",
|
Name: "d200",
|
||||||
Aliases: []string{"d200-dg"},
|
Aliases: []string{ "d200-dg" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\f",
|
Clear: "\f",
|
||||||
AttrOff: "\x0f\x15\x1d\x1eE",
|
AttrOff: "\x0f\x15\x1d\x1eE",
|
||||||
Underline: "\x14",
|
Underline: "\x14",
|
||||||
Bold: "\x1eD\x14",
|
Bold: "\x1eD\x14",
|
||||||
Dim: "\x1c",
|
Dim: "\x1c",
|
||||||
Blink: "\x0e",
|
Blink: "\x0e",
|
||||||
Reverse: "\x1eD",
|
Reverse: "\x1eD",
|
||||||
SetCursor: "\x10%p2%c%p1%c",
|
PadChar: "\x00",
|
||||||
CursorBack1: "\x19",
|
SetCursor: "\x10%p2%c%p1%c",
|
||||||
CursorUp1: "\x17",
|
CursorBack1: "\x19",
|
||||||
KeyUp: "\x17",
|
CursorUp1: "\x17",
|
||||||
KeyDown: "\x1a",
|
KeyUp: "\x17",
|
||||||
KeyRight: "\x18",
|
KeyDown: "\x1a",
|
||||||
KeyLeft: "\x19",
|
KeyRight: "\x18",
|
||||||
KeyHome: "\b",
|
KeyLeft: "\x19",
|
||||||
KeyF1: "\x1eq",
|
KeyHome: "\b",
|
||||||
KeyF2: "\x1er",
|
KeyF1: "\x1eq",
|
||||||
KeyF3: "\x1es",
|
KeyF2: "\x1er",
|
||||||
KeyF4: "\x1et",
|
KeyF3: "\x1es",
|
||||||
KeyF5: "\x1eu",
|
KeyF4: "\x1et",
|
||||||
KeyF6: "\x1ev",
|
KeyF5: "\x1eu",
|
||||||
KeyF7: "\x1ew",
|
KeyF6: "\x1ev",
|
||||||
KeyF8: "\x1ex",
|
KeyF7: "\x1ew",
|
||||||
KeyF9: "\x1ey",
|
KeyF8: "\x1ex",
|
||||||
KeyF10: "\x1ez",
|
KeyF9: "\x1ey",
|
||||||
KeyF11: "\x1e{",
|
KeyF10: "\x1ez",
|
||||||
KeyF12: "\x1e|",
|
KeyF11: "\x1e{",
|
||||||
|
KeyF12: "\x1e|",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "d210",
|
Name: "d210",
|
||||||
Aliases: []string{"d214"},
|
Aliases: []string{ "d214" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[2J",
|
Clear: "\x1b[2J",
|
||||||
AttrOff: "\x1b[m",
|
AttrOff: "\x1b[m",
|
||||||
Underline: "\x1b[4m",
|
Underline: "\x1b[4m",
|
||||||
Bold: "\x1b[4;7m",
|
Bold: "\x1b[4;7m",
|
||||||
Dim: "\x1b[2m",
|
Dim: "\x1b[2m",
|
||||||
Blink: "\x1b[5m",
|
Blink: "\x1b[5m",
|
||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
PadChar: "\x00",
|
||||||
CursorBack1: "\b",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorUp1: "\x1b[A",
|
CursorBack1: "\b",
|
||||||
KeyUp: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
KeyDown: "\x1b[B",
|
KeyUp: "\x1b[A",
|
||||||
KeyRight: "\x1b[C",
|
KeyDown: "\x1b[B",
|
||||||
KeyLeft: "\x1b[D",
|
KeyRight: "\x1b[C",
|
||||||
KeyHome: "\x1b[H",
|
KeyLeft: "\x1b[D",
|
||||||
KeyF1: "\x1b[001z",
|
KeyHome: "\x1b[H",
|
||||||
KeyF2: "\x1b[002z",
|
KeyF1: "\x1b[001z",
|
||||||
KeyF3: "\x1b[003z",
|
KeyF2: "\x1b[002z",
|
||||||
KeyF4: "\x1b[004z",
|
KeyF3: "\x1b[003z",
|
||||||
KeyF5: "\x1b[005z",
|
KeyF4: "\x1b[004z",
|
||||||
KeyF6: "\x1b[006z",
|
KeyF5: "\x1b[005z",
|
||||||
KeyF7: "\x1b[007z",
|
KeyF6: "\x1b[006z",
|
||||||
KeyF8: "\x1b[008z",
|
KeyF7: "\x1b[007z",
|
||||||
KeyF9: "\x1b[009z",
|
KeyF8: "\x1b[008z",
|
||||||
KeyF10: "\x1b[010z",
|
KeyF9: "\x1b[009z",
|
||||||
KeyF11: "\x1b[011z",
|
KeyF10: "\x1b[010z",
|
||||||
KeyF12: "\x1b[012z",
|
KeyF11: "\x1b[011z",
|
||||||
|
KeyF12: "\x1b[012z",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "dtterm",
|
Name: "dtterm",
|
||||||
@ -329,6 +338,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -356,7 +366,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "Eterm",
|
Name: "Eterm",
|
||||||
Aliases: []string{"Eterm-color"},
|
Aliases: []string{ "Eterm-color" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
@ -373,9 +383,10 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -421,9 +432,10 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
|
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",
|
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -452,20 +464,21 @@ func init() {
|
|||||||
KeyF12: "\x1b[24~",
|
KeyF12: "\x1b[24~",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "eterm",
|
Name: "eterm",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J",
|
Clear: "\x1b[H\x1b[J",
|
||||||
EnterCA: "\x1b7\x1b[?47h",
|
EnterCA: "\x1b7\x1b[?47h",
|
||||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||||
AttrOff: "\x1b[m",
|
AttrOff: "\x1b[m",
|
||||||
Underline: "\x1b[4m",
|
Underline: "\x1b[4m",
|
||||||
Bold: "\x1b[1m",
|
Bold: "\x1b[1m",
|
||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
PadChar: "\x00",
|
||||||
CursorBack1: "\b",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorUp1: "\x1b[A",
|
CursorBack1: "\b",
|
||||||
|
CursorUp1: "\x1b[A",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "gnome",
|
Name: "gnome",
|
||||||
@ -486,9 +499,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -535,9 +549,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
|
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",
|
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -567,7 +582,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "hpterm",
|
Name: "hpterm",
|
||||||
Aliases: []string{"X-hpterm"},
|
Aliases: []string{ "X-hpterm" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
@ -579,6 +594,7 @@ func init() {
|
|||||||
Reverse: "\x1b&dB",
|
Reverse: "\x1b&dB",
|
||||||
EnterKeypad: "\x1b&s1A",
|
EnterKeypad: "\x1b&s1A",
|
||||||
ExitKeypad: "\x1b&s0A",
|
ExitKeypad: "\x1b&s0A",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b&a%p1%dy%p2%dC",
|
SetCursor: "\x1b&a%p1%dy%p2%dC",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1bA",
|
CursorUp1: "\x1bA",
|
||||||
@ -602,19 +618,20 @@ func init() {
|
|||||||
KeyF8: "\x1bw",
|
KeyF8: "\x1bw",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "hz1500",
|
Name: "hz1500",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "~\x1c",
|
Clear: "~\x1c",
|
||||||
SetCursor: "~\x11%p2%p2%?%{30}%>%t%' '%+%;%'`'%+%c%p1%'`'%+%c",
|
PadChar: "\x00",
|
||||||
CursorBack1: "\b",
|
SetCursor: "~\x11%p2%p2%?%{30}%>%t%' '%+%;%'`'%+%c%p1%'`'%+%c",
|
||||||
CursorUp1: "~\f",
|
CursorBack1: "\b",
|
||||||
KeyUp: "~\f",
|
CursorUp1: "~\f",
|
||||||
KeyDown: "\n",
|
KeyUp: "~\f",
|
||||||
KeyRight: "\x10",
|
KeyDown: "\n",
|
||||||
KeyLeft: "\b",
|
KeyRight: "\x10",
|
||||||
KeyHome: "~\x12",
|
KeyLeft: "\b",
|
||||||
|
KeyHome: "~\x12",
|
||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "konsole",
|
Name: "konsole",
|
||||||
@ -636,8 +653,8 @@ func init() {
|
|||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -682,9 +699,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -712,8 +730,8 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "linux",
|
Name: "linux",
|
||||||
Columns: 80,
|
Columns: -1,
|
||||||
Lines: 24,
|
Lines: -1,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J",
|
Clear: "\x1b[H\x1b[J",
|
||||||
@ -727,9 +745,10 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -771,6 +790,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\x1b[D",
|
CursorBack1: "\x1b[D",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -801,9 +821,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b>",
|
ExitKeypad: "\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -851,9 +872,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b>",
|
ExitKeypad: "\x1b>",
|
||||||
SetFg: "\x1b[%?%p1%{8}%<%t%p1%{30}%+%e%p1%'R'%+%;%dm",
|
SetFg: "\x1b[%?%p1%{8}%<%t%p1%{30}%+%e%p1%'R'%+%;%dm",
|
||||||
SetBg: "\x1b[%?%p1%{8}%<%t%p1%'('%+%e%p1%{92}%+%;%dm",
|
SetBg: "\x1b[%?%p1%{8}%<%t%p1%'('%+%e%p1%{92}%+%;%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -901,9 +923,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b>",
|
ExitKeypad: "\x1b>",
|
||||||
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
|
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",
|
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -951,9 +974,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1bM",
|
CursorUp1: "\x1bM",
|
||||||
@ -983,13 +1007,14 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "sun",
|
Name: "sun",
|
||||||
Aliases: []string{"sun1", "sun2"},
|
Aliases: []string{ "sun1", "sun2" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 34,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\f",
|
Clear: "\f",
|
||||||
AttrOff: "\x1b[m",
|
AttrOff: "\x1b[m",
|
||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1019,7 +1044,7 @@ func init() {
|
|||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "sun-color",
|
Name: "sun-color",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 34,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\f",
|
Clear: "\f",
|
||||||
@ -1027,6 +1052,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1062,6 +1088,7 @@ func init() {
|
|||||||
AttrOff: "\x1bG0",
|
AttrOff: "\x1bG0",
|
||||||
Underline: "\x1bG8",
|
Underline: "\x1bG8",
|
||||||
Reverse: "\x1bG4",
|
Reverse: "\x1bG4",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\v",
|
CursorUp1: "\v",
|
||||||
@ -1083,12 +1110,13 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "tvi912",
|
Name: "tvi912",
|
||||||
Aliases: []string{"tvi920", "tvi914"},
|
Aliases: []string{ "tvi920", "tvi914" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1a",
|
Clear: "\x1a",
|
||||||
Underline: "\x1bl",
|
Underline: "\x1bl",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\v",
|
CursorUp1: "\v",
|
||||||
@ -1117,6 +1145,7 @@ func init() {
|
|||||||
AttrOff: "\x1bG0",
|
AttrOff: "\x1bG0",
|
||||||
Underline: "\x1bG8",
|
Underline: "\x1bG8",
|
||||||
Reverse: "\x1bG4",
|
Reverse: "\x1bG4",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c$<3/>",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c$<3/>",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\v",
|
CursorUp1: "\v",
|
||||||
@ -1138,6 +1167,7 @@ func init() {
|
|||||||
AttrOff: "\x1bG0",
|
AttrOff: "\x1bG0",
|
||||||
Underline: "\x1bG8",
|
Underline: "\x1bG8",
|
||||||
Reverse: "\x1bG4",
|
Reverse: "\x1bG4",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\v",
|
CursorUp1: "\v",
|
||||||
@ -1168,6 +1198,7 @@ func init() {
|
|||||||
AttrOff: "\x1bG0",
|
AttrOff: "\x1bG0",
|
||||||
Underline: "\x1bG8",
|
Underline: "\x1bG8",
|
||||||
Reverse: "\x1bG4",
|
Reverse: "\x1bG4",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\v",
|
CursorUp1: "\v",
|
||||||
@ -1197,6 +1228,7 @@ func init() {
|
|||||||
EnterCA: "\x1b[?20l\x1b[?7h\x1b[1Q",
|
EnterCA: "\x1b[?20l\x1b[?7h\x1b[1Q",
|
||||||
AttrOff: "\x1b[m",
|
AttrOff: "\x1b[m",
|
||||||
Underline: "\x1b[4m",
|
Underline: "\x1b[4m",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%df",
|
SetCursor: "\x1b[%i%p1%d;%p2%df",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1bM",
|
CursorUp1: "\x1bM",
|
||||||
@ -1222,6 +1254,7 @@ func init() {
|
|||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1bH\x1bJ",
|
Clear: "\x1bH\x1bJ",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1bY%p1%' '%+%c%p2%' '%+%c",
|
SetCursor: "\x1bY%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorBack1: "\x1bD",
|
CursorBack1: "\x1bD",
|
||||||
CursorUp1: "\x1bA",
|
CursorUp1: "\x1bA",
|
||||||
@ -1233,7 +1266,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "vt100",
|
Name: "vt100",
|
||||||
Aliases: []string{"vt100-am"},
|
Aliases: []string{ "vt100-am" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
@ -1245,6 +1278,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m$<2>",
|
Reverse: "\x1b[7m$<2>",
|
||||||
EnterKeypad: "\x1b[?1h\x1b=",
|
EnterKeypad: "\x1b[?1h\x1b=",
|
||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH$<5>",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH$<5>",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A$<2>",
|
CursorUp1: "\x1b[A$<2>",
|
||||||
@ -1277,6 +1311,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m$<2>",
|
Reverse: "\x1b[7m$<2>",
|
||||||
EnterKeypad: "\x1b[?1h\x1b=",
|
EnterKeypad: "\x1b[?1h\x1b=",
|
||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH$<5>",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH$<5>",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A$<2>",
|
CursorUp1: "\x1b[A$<2>",
|
||||||
@ -1298,7 +1333,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "vt220",
|
Name: "vt220",
|
||||||
Aliases: []string{"vt200"},
|
Aliases: []string{ "vt200" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
@ -1308,6 +1343,7 @@ func init() {
|
|||||||
Bold: "\x1b[1m",
|
Bold: "\x1b[1m",
|
||||||
Blink: "\x1b[5m",
|
Blink: "\x1b[5m",
|
||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1333,7 +1369,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "vt320",
|
Name: "vt320",
|
||||||
Aliases: []string{"vt300"},
|
Aliases: []string{ "vt300" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
@ -1347,6 +1383,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
EnterKeypad: "\x1b[?1h\x1b=",
|
EnterKeypad: "\x1b[?1h\x1b=",
|
||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1374,7 +1411,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "vt400",
|
Name: "vt400",
|
||||||
Aliases: []string{"vt400-24", "dec-vt400"},
|
Aliases: []string{ "vt400-24", "dec-vt400" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Clear: "\x1b[H\x1b[J$<10/>",
|
Clear: "\x1b[H\x1b[J$<10/>",
|
||||||
@ -1387,6 +1424,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
EnterKeypad: "\x1b[?1h\x1b=",
|
EnterKeypad: "\x1b[?1h\x1b=",
|
||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1417,6 +1455,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m$<2>",
|
Reverse: "\x1b[7m$<2>",
|
||||||
EnterKeypad: "\x1b=",
|
EnterKeypad: "\x1b=",
|
||||||
ExitKeypad: "\x1b>",
|
ExitKeypad: "\x1b>",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH$<10>",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH$<10>",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1442,7 +1481,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "wy50",
|
Name: "wy50",
|
||||||
Aliases: []string{"wyse50"},
|
Aliases: []string{ "wyse50" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
@ -1452,6 +1491,7 @@ func init() {
|
|||||||
AttrOff: "\x1b(\x1bH\x03",
|
AttrOff: "\x1b(\x1bH\x03",
|
||||||
Dim: "\x1b`7\x1b)",
|
Dim: "\x1b`7\x1b)",
|
||||||
Reverse: "\x1b`6\x1b)",
|
Reverse: "\x1b`6\x1b)",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\v",
|
CursorUp1: "\v",
|
||||||
@ -1480,7 +1520,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "wy60",
|
Name: "wy60",
|
||||||
Aliases: []string{"wyse60"},
|
Aliases: []string{ "wyse60" },
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
@ -1494,6 +1534,7 @@ func init() {
|
|||||||
Dim: "\x1bGp",
|
Dim: "\x1bGp",
|
||||||
Blink: "\x1bG2",
|
Blink: "\x1bG2",
|
||||||
Reverse: "\x1bG4",
|
Reverse: "\x1bG4",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
SetCursor: "\x1b=%p1%' '%+%c%p2%' '%+%c",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\v",
|
CursorUp1: "\v",
|
||||||
@ -1523,7 +1564,7 @@ func init() {
|
|||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "wy99-ansi",
|
Name: "wy99-ansi",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 25,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J$<200>",
|
Clear: "\x1b[H\x1b[J$<200>",
|
||||||
ShowCursor: "\x1b[34h\x1b[?25h",
|
ShowCursor: "\x1b[34h\x1b[?25h",
|
||||||
@ -1536,6 +1577,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
EnterKeypad: "\x1b[?1h",
|
EnterKeypad: "\x1b[?1h",
|
||||||
ExitKeypad: "\x1b[?1l",
|
ExitKeypad: "\x1b[?1l",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b$<1>",
|
CursorBack1: "\b$<1>",
|
||||||
CursorUp1: "\x1bM",
|
CursorUp1: "\x1bM",
|
||||||
@ -1560,7 +1602,7 @@ func init() {
|
|||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "wy99a-ansi",
|
Name: "wy99a-ansi",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 25,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J$<200>",
|
Clear: "\x1b[H\x1b[J$<200>",
|
||||||
ShowCursor: "\x1b[34h\x1b[?25h",
|
ShowCursor: "\x1b[34h\x1b[?25h",
|
||||||
@ -1573,6 +1615,7 @@ func init() {
|
|||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
EnterKeypad: "\x1b[?1h",
|
EnterKeypad: "\x1b[?1h",
|
||||||
ExitKeypad: "\x1b[?1l",
|
ExitKeypad: "\x1b[?1l",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b$<1>",
|
CursorBack1: "\b$<1>",
|
||||||
CursorUp1: "\x1bM",
|
CursorUp1: "\x1bM",
|
||||||
@ -1613,9 +1656,10 @@ func init() {
|
|||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1645,8 +1689,8 @@ func init() {
|
|||||||
})
|
})
|
||||||
AddTerminfo(&Terminfo{
|
AddTerminfo(&Terminfo{
|
||||||
Name: "xnuppc",
|
Name: "xnuppc",
|
||||||
Columns: 80,
|
Columns: -1,
|
||||||
Lines: 24,
|
Lines: -1,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Clear: "\x1b[H\x1b[J",
|
Clear: "\x1b[H\x1b[J",
|
||||||
AttrOff: "\x1b[m\x0f",
|
AttrOff: "\x1b[m\x0f",
|
||||||
@ -1657,6 +1701,7 @@ func init() {
|
|||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
|
PadChar: "\x00",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\x1b[D",
|
CursorBack1: "\x1b[D",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1687,8 +1732,8 @@ func init() {
|
|||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
@ -1737,8 +1782,8 @@ func init() {
|
|||||||
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
|
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",
|
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
EnterMouse: "\x1b[?1000h",
|
EnterMouse: "\x1b[?1000h\x1b[?1003h\x1b[?1006h",
|
||||||
ExitMouse: "\x1b[?1000l",
|
ExitMouse: "\x1b[?1006l\x1b[?1003l\x1b[?1000l",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1b[A",
|
CursorUp1: "\x1b[A",
|
||||||
|
2694
database.json
2694
database.json
File diff suppressed because it is too large
Load Diff
35
mkinfo.go
35
mkinfo.go
@ -46,6 +46,10 @@ import (
|
|||||||
// #include <curses.h>
|
// #include <curses.h>
|
||||||
// #include <term.h>
|
// #include <term.h>
|
||||||
// #cgo LDFLAGS: -lcurses
|
// #cgo LDFLAGS: -lcurses
|
||||||
|
//
|
||||||
|
// void noenv() {
|
||||||
|
// use_env(FALSE);
|
||||||
|
// }
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func tigetnum(s string) int {
|
func tigetnum(s string) int {
|
||||||
@ -53,6 +57,11 @@ func tigetnum(s string) int {
|
|||||||
return int(n)
|
return int(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tigetflag(s string) bool {
|
||||||
|
n := C.tigetflag(C.CString(s))
|
||||||
|
return n != 0
|
||||||
|
}
|
||||||
|
|
||||||
func tigetstr(s string) string {
|
func tigetstr(s string) string {
|
||||||
// NB: If the string is invalid, we'll get back -1, which causes
|
// NB: If the string is invalid, we'll get back -1, which causes
|
||||||
// no end of grief. So make sure your capability strings are correct!
|
// no end of grief. So make sure your capability strings are correct!
|
||||||
@ -70,7 +79,8 @@ func tigetstr(s string) string {
|
|||||||
// terminal types.
|
// terminal types.
|
||||||
func getinfo(name string) (*tcell.Terminfo, error) {
|
func getinfo(name string) (*tcell.Terminfo, error) {
|
||||||
rsn := C.int(0)
|
rsn := C.int(0)
|
||||||
rv, e := C.setupterm(C.CString(name), 1, &rsn)
|
C.noenv()
|
||||||
|
rv, _ := C.setupterm(C.CString(name), 1, &rsn)
|
||||||
if rv == C.ERR {
|
if rv == C.ERR {
|
||||||
switch rsn {
|
switch rsn {
|
||||||
case 1:
|
case 1:
|
||||||
@ -83,9 +93,6 @@ func getinfo(name string) (*tcell.Terminfo, error) {
|
|||||||
return nil, errors.New("setupterm failed (other)")
|
return nil, errors.New("setupterm failed (other)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if e != nil {
|
|
||||||
return nil, e
|
|
||||||
}
|
|
||||||
t := &tcell.Terminfo{}
|
t := &tcell.Terminfo{}
|
||||||
t.Name = name
|
t.Name = name
|
||||||
t.Colors = tigetnum("colors")
|
t.Colors = tigetnum("colors")
|
||||||
@ -141,8 +148,13 @@ func getinfo(name string) (*tcell.Terminfo, error) {
|
|||||||
// manual, and all terminals that have kmous are expected to
|
// manual, and all terminals that have kmous are expected to
|
||||||
// use these same codes.
|
// use these same codes.
|
||||||
if t.Mouse != "" {
|
if t.Mouse != "" {
|
||||||
t.EnterMouse = "\x1b[?1000h"
|
// we anticipate that all xterm mouse tracking compatible
|
||||||
t.ExitMouse = "\x1b[?1000l"
|
// terminals understand mouse tracking (1000), but we hope
|
||||||
|
// that those that don't understand any-event tracking (1003)
|
||||||
|
// will at least ignore it. Likewise we hope that terminals
|
||||||
|
// that don't understand SGR reporting (1006) just ignore it.
|
||||||
|
t.EnterMouse = "\x1b[?1000h\x1b[?1003h\x1b[?1006h"
|
||||||
|
t.ExitMouse = "\x1b[?1006l\x1b[?1003l\x1b[?1000l"
|
||||||
}
|
}
|
||||||
// We only support colors in ANSI 8 or 256 color mode.
|
// We only support colors in ANSI 8 or 256 color mode.
|
||||||
if t.Colors < 8 || t.SetFg == "" {
|
if t.Colors < 8 || t.SetFg == "" {
|
||||||
@ -151,6 +163,16 @@ func getinfo(name string) (*tcell.Terminfo, error) {
|
|||||||
if t.SetCursor == "" {
|
if t.SetCursor == "" {
|
||||||
return nil, errors.New("terminal not cursor addressable")
|
return nil, errors.New("terminal not cursor addressable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 = tigetstr("pad")
|
||||||
|
if t.PadChar == "" {
|
||||||
|
if !tigetflag("npc") {
|
||||||
|
t.PadChar = "\u0000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +245,7 @@ func dotGoInfo(w io.Writer, t *tcell.Terminfo) {
|
|||||||
dotGoAddStr(w, "ExitKeypad", t.ExitKeypad)
|
dotGoAddStr(w, "ExitKeypad", t.ExitKeypad)
|
||||||
dotGoAddStr(w, "SetFg", t.SetFg)
|
dotGoAddStr(w, "SetFg", t.SetFg)
|
||||||
dotGoAddStr(w, "SetBg", t.SetBg)
|
dotGoAddStr(w, "SetBg", t.SetBg)
|
||||||
|
dotGoAddStr(w, "PadChar", t.PadChar)
|
||||||
dotGoAddStr(w, "Mouse", t.Mouse)
|
dotGoAddStr(w, "Mouse", t.Mouse)
|
||||||
dotGoAddStr(w, "EnterMouse", t.EnterMouse)
|
dotGoAddStr(w, "EnterMouse", t.EnterMouse)
|
||||||
dotGoAddStr(w, "ExitMouse", t.ExitMouse)
|
dotGoAddStr(w, "ExitMouse", t.ExitMouse)
|
||||||
|
19
mouse.go
19
mouse.go
@ -19,10 +19,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// EventMouse is a mouse event. It is sent on either mouse up or mouse down
|
// EventMouse is a mouse event. It is sent on either mouse up or mouse down
|
||||||
// events. (Eventually we can also arrange for mouse motion events, but only
|
// events. It is also sent on mouse motion events - if the terminal supports
|
||||||
// with genuine xterm -- other emulators lack support for tracking this.)
|
// it. We make every effort to ensure that mouse release events are delivered.
|
||||||
|
// Hence, click drag can be identified by a motion event with the mouse down,
|
||||||
|
// without any intervening button release.
|
||||||
|
//
|
||||||
|
// Mouse wheel events, when reported, may appear on their own as individual
|
||||||
|
// impulses.
|
||||||
|
//
|
||||||
// Most terminals cannot report the state of more than one button at a time --
|
// Most terminals cannot report the state of more than one button at a time --
|
||||||
// that is buttons are seen together.
|
// and few can report motion events.
|
||||||
|
//
|
||||||
|
// Applications can inspect the time between events to figure out double clicks
|
||||||
|
// and such.
|
||||||
type EventMouse struct {
|
type EventMouse struct {
|
||||||
t time.Time
|
t time.Time
|
||||||
btn ButtonMask
|
btn ButtonMask
|
||||||
@ -63,5 +72,9 @@ const (
|
|||||||
Button6
|
Button6
|
||||||
Button7
|
Button7
|
||||||
Button8
|
Button8
|
||||||
|
WheelUp
|
||||||
|
WheelDown
|
||||||
|
WheelLeft
|
||||||
|
WheelRight
|
||||||
)
|
)
|
||||||
const ButtonNone ButtonMask = 0
|
const ButtonNone ButtonMask = 0
|
||||||
|
40
screen.go
40
screen.go
@ -29,7 +29,7 @@ type Screen interface {
|
|||||||
Clear()
|
Clear()
|
||||||
|
|
||||||
// SetCell sets the cell at the given location.
|
// SetCell sets the cell at the given location.
|
||||||
// The ch array contains at most one rune of width > 0, and the
|
// The ch list contains at most one rune of width > 0, and the
|
||||||
// runes with zero width (combining marks) must follow the first
|
// runes with zero width (combining marks) must follow the first
|
||||||
// non-zero width character. (If only combining marks are present,
|
// non-zero width character. (If only combining marks are present,
|
||||||
// a space character will be filled in.)
|
// a space character will be filled in.)
|
||||||
@ -39,15 +39,32 @@ type Screen interface {
|
|||||||
// undefined effects. Double wide runes that are printed in the
|
// undefined effects. Double wide runes that are printed in the
|
||||||
// last column will be replaced with a single width space on output.
|
// last column will be replaced with a single width space on output.
|
||||||
//
|
//
|
||||||
// Note that unlike the higher level interfaces, this operates
|
|
||||||
// immediately, without any buffering.
|
|
||||||
//
|
|
||||||
// SetCell may change the cursor location. Callers should explictly
|
// SetCell may change the cursor location. Callers should explictly
|
||||||
// save and restore cursor state if neccesary. The cursor visibility
|
// save and restore cursor state if neccesary. The cursor visibility
|
||||||
// is not affected, so callers probably should hide the cursor when
|
// is not affected, so callers probably should hide the cursor when
|
||||||
// calling this.
|
// calling this.
|
||||||
|
//
|
||||||
|
// Note that the results will not be visible until either Show() or
|
||||||
|
// Sync() are called.
|
||||||
SetCell(x int, y int, style Style, ch ...rune)
|
SetCell(x int, y int, style Style, ch ...rune)
|
||||||
|
|
||||||
|
// PutCell stores the contents of the given cell at the given location.
|
||||||
|
// The Dirty flag on the stored cell is set to true if the contents
|
||||||
|
// do not match.
|
||||||
|
PutCell(x, y int, cell *Cell)
|
||||||
|
|
||||||
|
// GetCell returns the contents of the given cell. If the coordinates
|
||||||
|
// are out of range, then nil will be returned for the rune array.
|
||||||
|
// This will also be the case if no content has been written to that
|
||||||
|
// location. Note that the returned Cell object is a copy, and
|
||||||
|
// modifications made will not change the display.
|
||||||
|
GetCell(x, y int) *Cell
|
||||||
|
|
||||||
|
// SetStyle sets the default style to use when clearing the screen
|
||||||
|
// or when StyleDefault is specified. If it is also STyleDefault,
|
||||||
|
// then whatever system/terminal default is relevant will be used.
|
||||||
|
SetStyle(style Style)
|
||||||
|
|
||||||
// ShowCursor is used to display the cursor at a given location.
|
// ShowCursor is used to display the cursor at a given location.
|
||||||
// If the coordinates -1, -1 are given or are otherwise outside the
|
// If the coordinates -1, -1 are given or are otherwise outside the
|
||||||
// dimensions of the screen, the cursor will be hidden.
|
// dimensions of the screen, the cursor will be hidden.
|
||||||
@ -78,6 +95,21 @@ type Screen interface {
|
|||||||
// Colors returns the number of colors. All colors are assumed to
|
// Colors returns the number of colors. All colors are assumed to
|
||||||
// use the ANSI color map.
|
// use the ANSI color map.
|
||||||
Colors() int
|
Colors() int
|
||||||
|
|
||||||
|
// Show takes any output that was deferred due to buffering, and
|
||||||
|
// flushes it to the physical display. It does so in the least
|
||||||
|
// expensive and disruptive manner possible, only making writes that
|
||||||
|
// are believed to actually be necessary.
|
||||||
|
Show()
|
||||||
|
|
||||||
|
// Sync works like Show(), but it updates every visible cell on the
|
||||||
|
// physical display, assuming that it is not synchronized with any
|
||||||
|
// internal model. This may be both expensive and visually jarring,
|
||||||
|
// so it should only be used when believed to actually be necessary.
|
||||||
|
// Typically this is called as a result of a user-requested redraw
|
||||||
|
// (e.g. to clear up on screen corruption caused by some other program),
|
||||||
|
// or during a resize event.
|
||||||
|
Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewScreen() (Screen, error) {
|
func NewScreen() (Screen, error) {
|
||||||
|
@ -22,12 +22,12 @@ import (
|
|||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
var screen tcell.BufferedScreen
|
var screen tcell.Screen
|
||||||
var outMode OutputMode
|
var outMode OutputMode
|
||||||
|
|
||||||
func Init() error {
|
func Init() error {
|
||||||
outMode = OutputNormal
|
outMode = OutputNormal
|
||||||
if s, e := tcell.NewBufferedScreen(); e != nil {
|
if s, e := tcell.NewScreen(); e != nil {
|
||||||
return e
|
return e
|
||||||
} else if e = s.Init(); e != nil {
|
} else if e = s.Init(); e != nil {
|
||||||
return e
|
return e
|
||||||
@ -59,6 +59,7 @@ func Size() (int, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Attribute uint16
|
type Attribute uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ColorDefault Attribute = iota
|
ColorDefault Attribute = iota
|
||||||
ColorBlack
|
ColorBlack
|
||||||
@ -71,7 +72,7 @@ const (
|
|||||||
ColorWhite
|
ColorWhite
|
||||||
)
|
)
|
||||||
const (
|
const (
|
||||||
AttrBold Attribute = 1 << (9+iota)
|
AttrBold Attribute = 1 << (9 + iota)
|
||||||
AttrUnderline
|
AttrUnderline
|
||||||
AttrReverse
|
AttrReverse
|
||||||
)
|
)
|
||||||
@ -113,13 +114,13 @@ func mkStyle(fg, bg Attribute) tcell.Style {
|
|||||||
}
|
}
|
||||||
st = st.Foreground(tcell.Color(f))
|
st = st.Foreground(tcell.Color(f))
|
||||||
st = st.Background(tcell.Color(b))
|
st = st.Background(tcell.Color(b))
|
||||||
if (fg & AttrBold != 0 ) || (bg & AttrBold != 0) {
|
if (fg&AttrBold != 0) || (bg&AttrBold != 0) {
|
||||||
st = st.Bold(true)
|
st = st.Bold(true)
|
||||||
}
|
}
|
||||||
if (fg & AttrUnderline != 0 ) || (bg & AttrUnderline != 0) {
|
if (fg&AttrUnderline != 0) || (bg&AttrUnderline != 0) {
|
||||||
st = st.Underline(true)
|
st = st.Underline(true)
|
||||||
}
|
}
|
||||||
if (fg & AttrReverse != 0 ) || (bg & AttrReverse != 0) {
|
if (fg&AttrReverse != 0) || (bg&AttrReverse != 0) {
|
||||||
st = st.Reverse(true)
|
st = st.Reverse(true)
|
||||||
}
|
}
|
||||||
return st
|
return st
|
||||||
@ -137,6 +138,7 @@ func Clear(fg, bg Attribute) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InputMode int
|
type InputMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
InputCurrent InputMode = iota
|
InputCurrent InputMode = iota
|
||||||
InputEsc
|
InputEsc
|
||||||
@ -150,6 +152,7 @@ func SetInputMode(mode InputMode) InputMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OutputMode int
|
type OutputMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OutputCurrent OutputMode = iota
|
OutputCurrent OutputMode = iota
|
||||||
OutputNormal
|
OutputNormal
|
||||||
@ -159,6 +162,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func SetOutputMode(mode OutputMode) OutputMode {
|
func SetOutputMode(mode OutputMode) OutputMode {
|
||||||
|
if screen.Colors() < 256 {
|
||||||
|
mode = OutputNormal
|
||||||
|
}
|
||||||
switch mode {
|
switch mode {
|
||||||
case OutputCurrent:
|
case OutputCurrent:
|
||||||
return outMode
|
return outMode
|
||||||
@ -185,16 +191,16 @@ type Modifier tcell.ModMask
|
|||||||
type Key tcell.Key
|
type Key tcell.Key
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Type EventType
|
Type EventType
|
||||||
Mod Modifier
|
Mod Modifier
|
||||||
Key Key
|
Key Key
|
||||||
Ch rune
|
Ch rune
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
Err error
|
Err error
|
||||||
MouseX int
|
MouseX int
|
||||||
MouseY int
|
MouseY int
|
||||||
N int
|
N int
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -208,68 +214,68 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
KeyF1 = Key(tcell.KeyF1)
|
KeyF1 = Key(tcell.KeyF1)
|
||||||
KeyF2 = Key(tcell.KeyF2)
|
KeyF2 = Key(tcell.KeyF2)
|
||||||
KeyF3 = Key(tcell.KeyF3)
|
KeyF3 = Key(tcell.KeyF3)
|
||||||
KeyF4 = Key(tcell.KeyF4)
|
KeyF4 = Key(tcell.KeyF4)
|
||||||
KeyF5 = Key(tcell.KeyF5)
|
KeyF5 = Key(tcell.KeyF5)
|
||||||
KeyF6 = Key(tcell.KeyF6)
|
KeyF6 = Key(tcell.KeyF6)
|
||||||
KeyF7 = Key(tcell.KeyF7)
|
KeyF7 = Key(tcell.KeyF7)
|
||||||
KeyF8 = Key(tcell.KeyF8)
|
KeyF8 = Key(tcell.KeyF8)
|
||||||
KeyF9 = Key(tcell.KeyF9)
|
KeyF9 = Key(tcell.KeyF9)
|
||||||
KeyF10 = Key(tcell.KeyF10)
|
KeyF10 = Key(tcell.KeyF10)
|
||||||
KeyF11 = Key(tcell.KeyF11)
|
KeyF11 = Key(tcell.KeyF11)
|
||||||
KeyF12 = Key(tcell.KeyF12)
|
KeyF12 = Key(tcell.KeyF12)
|
||||||
KeyInsert = Key(tcell.KeyInsert)
|
KeyInsert = Key(tcell.KeyInsert)
|
||||||
KeyDelete = Key(tcell.KeyDelete)
|
KeyDelete = Key(tcell.KeyDelete)
|
||||||
KeyHome = Key(tcell.KeyHome)
|
KeyHome = Key(tcell.KeyHome)
|
||||||
KeyEnd = Key(tcell.KeyEnd)
|
KeyEnd = Key(tcell.KeyEnd)
|
||||||
KeyArrowUp = Key(tcell.KeyUp)
|
KeyArrowUp = Key(tcell.KeyUp)
|
||||||
KeyArrowDown = Key(tcell.KeyDown)
|
KeyArrowDown = Key(tcell.KeyDown)
|
||||||
KeyArrowRight = Key(tcell.KeyRight)
|
KeyArrowRight = Key(tcell.KeyRight)
|
||||||
KeyArrowLeft = Key(tcell.KeyLeft)
|
KeyArrowLeft = Key(tcell.KeyLeft)
|
||||||
KeyCtrlA = Key(tcell.KeyCtrlA)
|
KeyCtrlA = Key(tcell.KeyCtrlA)
|
||||||
KeyCtrlB = Key(tcell.KeyCtrlB)
|
KeyCtrlB = Key(tcell.KeyCtrlB)
|
||||||
KeyCtrlC = Key(tcell.KeyCtrlC)
|
KeyCtrlC = Key(tcell.KeyCtrlC)
|
||||||
KeyCtrlD = Key(tcell.KeyCtrlD)
|
KeyCtrlD = Key(tcell.KeyCtrlD)
|
||||||
KeyCtrlE = Key(tcell.KeyCtrlE)
|
KeyCtrlE = Key(tcell.KeyCtrlE)
|
||||||
KeyCtrlF = Key(tcell.KeyCtrlF)
|
KeyCtrlF = Key(tcell.KeyCtrlF)
|
||||||
KeyCtrlG = Key(tcell.KeyCtrlG)
|
KeyCtrlG = Key(tcell.KeyCtrlG)
|
||||||
KeyCtrlH = Key(tcell.KeyCtrlH)
|
KeyCtrlH = Key(tcell.KeyCtrlH)
|
||||||
KeyCtrlI = Key(tcell.KeyCtrlI)
|
KeyCtrlI = Key(tcell.KeyCtrlI)
|
||||||
KeyCtrlJ = Key(tcell.KeyCtrlJ)
|
KeyCtrlJ = Key(tcell.KeyCtrlJ)
|
||||||
KeyCtrlK = Key(tcell.KeyCtrlK)
|
KeyCtrlK = Key(tcell.KeyCtrlK)
|
||||||
KeyCtrlL = Key(tcell.KeyCtrlL)
|
KeyCtrlL = Key(tcell.KeyCtrlL)
|
||||||
KeyCtrlM = Key(tcell.KeyCtrlM)
|
KeyCtrlM = Key(tcell.KeyCtrlM)
|
||||||
KeyCtrlN = Key(tcell.KeyCtrlN)
|
KeyCtrlN = Key(tcell.KeyCtrlN)
|
||||||
KeyCtrlO = Key(tcell.KeyCtrlO)
|
KeyCtrlO = Key(tcell.KeyCtrlO)
|
||||||
KeyCtrlP = Key(tcell.KeyCtrlP)
|
KeyCtrlP = Key(tcell.KeyCtrlP)
|
||||||
KeyCtrlQ = Key(tcell.KeyCtrlQ)
|
KeyCtrlQ = Key(tcell.KeyCtrlQ)
|
||||||
KeyCtrlR = Key(tcell.KeyCtrlR)
|
KeyCtrlR = Key(tcell.KeyCtrlR)
|
||||||
KeyCtrlS = Key(tcell.KeyCtrlS)
|
KeyCtrlS = Key(tcell.KeyCtrlS)
|
||||||
KeyCtrlT = Key(tcell.KeyCtrlT)
|
KeyCtrlT = Key(tcell.KeyCtrlT)
|
||||||
KeyCtrlU = Key(tcell.KeyCtrlU)
|
KeyCtrlU = Key(tcell.KeyCtrlU)
|
||||||
KeyCtrlV = Key(tcell.KeyCtrlV)
|
KeyCtrlV = Key(tcell.KeyCtrlV)
|
||||||
KeyCtrlW = Key(tcell.KeyCtrlW)
|
KeyCtrlW = Key(tcell.KeyCtrlW)
|
||||||
KeyCtrlX = Key(tcell.KeyCtrlX)
|
KeyCtrlX = Key(tcell.KeyCtrlX)
|
||||||
KeyCtrlY = Key(tcell.KeyCtrlY)
|
KeyCtrlY = Key(tcell.KeyCtrlY)
|
||||||
KeyCtrlZ = Key(tcell.KeyCtrlZ)
|
KeyCtrlZ = Key(tcell.KeyCtrlZ)
|
||||||
KeyBackspace = Key(tcell.KeyBackspace)
|
KeyBackspace = Key(tcell.KeyBackspace)
|
||||||
KeyBackspace2 = Key(tcell.KeyBackspace2)
|
KeyBackspace2 = Key(tcell.KeyBackspace2)
|
||||||
KeyTab = Key(tcell.KeyTab)
|
KeyTab = Key(tcell.KeyTab)
|
||||||
KeyEnter = Key(tcell.KeyEnter)
|
KeyEnter = Key(tcell.KeyEnter)
|
||||||
KeySpace = Key(tcell.KeySpace)
|
KeySpace = Key(tcell.KeySpace)
|
||||||
KeyEsc = Key(tcell.KeyEscape)
|
KeyEsc = Key(tcell.KeyEscape)
|
||||||
MouseLeft = Key(tcell.KeyF63) // arbitrary assignments
|
MouseLeft = Key(tcell.KeyF63) // arbitrary assignments
|
||||||
MouseRight = Key(tcell.KeyF62)
|
MouseRight = Key(tcell.KeyF62)
|
||||||
MouseMiddle = Key(tcell.KeyF61)
|
MouseMiddle = Key(tcell.KeyF61)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ModAlt = Modifier(tcell.ModAlt)
|
ModAlt = Modifier(tcell.ModAlt)
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeEvent(tev tcell.Event) Event {
|
func makeEvent(tev tcell.Event) Event {
|
||||||
switch tev := tev.(type) {
|
switch tev := tev.(type) {
|
||||||
case *tcell.EventInterrupt:
|
case *tcell.EventInterrupt:
|
||||||
return Event{Type: EventInterrupt}
|
return Event{Type: EventInterrupt}
|
||||||
@ -282,9 +288,9 @@ func makeEvent(tev tcell.Event) Event {
|
|||||||
mod := tev.Mod()
|
mod := tev.Mod()
|
||||||
return Event{
|
return Event{
|
||||||
Type: EventKey,
|
Type: EventKey,
|
||||||
Key: Key(k),
|
Key: Key(k),
|
||||||
Ch: ch,
|
Ch: ch,
|
||||||
Mod: Modifier(mod),
|
Mod: Modifier(mod),
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return Event{Type: EventNone}
|
return Event{Type: EventNone}
|
||||||
|
50
terminfo.go
50
terminfo.go
@ -21,6 +21,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@ -53,6 +54,7 @@ type Terminfo struct {
|
|||||||
SetCursor string `json:"cup,omitempty"` // cup
|
SetCursor string `json:"cup,omitempty"` // cup
|
||||||
CursorBack1 string `json:"cub1,omitempty"` // cub1
|
CursorBack1 string `json:"cub1,omitempty"` // cub1
|
||||||
CursorUp1 string `json:"cuu1,omitempty"` // cuu1
|
CursorUp1 string `json:"cuu1,omitempty"` // cuu1
|
||||||
|
PadChar string `json:"pad,omitempty"` // pad
|
||||||
KeyBackspace string `json:"kbs,omitempty"` // kbs
|
KeyBackspace string `json:"kbs,omitempty"` // kbs
|
||||||
KeyF1 string `json:"kf1,omitempty"` // kf1
|
KeyF1 string `json:"kf1,omitempty"` // kf1
|
||||||
KeyF2 string `json:"kf2,omitempty"` // kf2
|
KeyF2 string `json:"kf2,omitempty"` // kf2
|
||||||
@ -408,6 +410,54 @@ func (t *Terminfo) TParm(s string, p ...int) string {
|
|||||||
return out.String()
|
return out.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminfo) TPuts(w io.Writer, s string, baud int) {
|
||||||
|
for {
|
||||||
|
beg := strings.Index(s, "$<")
|
||||||
|
if beg < 0 {
|
||||||
|
// Most strings don't need padding, which is good news!
|
||||||
|
io.WriteString(w, s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
io.WriteString(w, s[:beg])
|
||||||
|
s = s[beg+2:]
|
||||||
|
end := strings.Index(s, ">")
|
||||||
|
if end < 0 {
|
||||||
|
// unterminated.. just emit bytes unadulterated
|
||||||
|
io.WriteString(w, "$<" + s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val := s[:end]
|
||||||
|
s = s[end+1:]
|
||||||
|
padus := 0
|
||||||
|
unit := 1000
|
||||||
|
dot := false
|
||||||
|
loop:
|
||||||
|
for i := range val {
|
||||||
|
switch val[i] {
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
padus *= 10
|
||||||
|
padus += int(val[i] - '0')
|
||||||
|
if dot {
|
||||||
|
unit *= 10
|
||||||
|
}
|
||||||
|
case '.':
|
||||||
|
if !dot {
|
||||||
|
dot = true
|
||||||
|
} else {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cnt := int(((baud/8)*padus)/unit)
|
||||||
|
for cnt > 0 {
|
||||||
|
io.WriteString(w, t.PadChar)
|
||||||
|
cnt--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TGoto returns a string suitable for addressing the cursor at the given
|
// 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.
|
// row and column. The origin 0, 0 is in the upper left corner of the screen.
|
||||||
func (t *Terminfo) TGoto(col, row int) string {
|
func (t *Terminfo) TGoto(col, row int) string {
|
||||||
|
669
tscreen.go
669
tscreen.go
@ -21,8 +21,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/mattn/go-runewidth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTerminfoScreen() (Screen, error) {
|
func NewTerminfoScreen() (Screen, error) {
|
||||||
@ -58,37 +56,49 @@ type tScreen struct {
|
|||||||
h int
|
h int
|
||||||
in *os.File
|
in *os.File
|
||||||
out *os.File
|
out *os.File
|
||||||
cinvis bool
|
|
||||||
curstyle Style
|
curstyle Style
|
||||||
|
style Style
|
||||||
evch chan Event
|
evch chan Event
|
||||||
sigwinch chan os.Signal
|
sigwinch chan os.Signal
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
|
indoneq chan struct{}
|
||||||
keys map[Key][]byte
|
keys map[Key][]byte
|
||||||
cx int
|
cx int
|
||||||
cy int
|
cy int
|
||||||
mouse []byte
|
mouse []byte
|
||||||
|
cells []Cell
|
||||||
|
clear bool
|
||||||
|
cursorx int
|
||||||
|
cursory int
|
||||||
|
tiosp *termiosPrivate
|
||||||
|
baud int
|
||||||
|
wasbtn bool
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) Init() error {
|
func (t *tScreen) Init() error {
|
||||||
t.evch = make(chan Event, 2)
|
t.evch = make(chan Event, 2)
|
||||||
|
t.indoneq = make(chan struct{})
|
||||||
if e := t.termioInit(); e != nil {
|
if e := t.termioInit(); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
out := t.out
|
|
||||||
ti := t.ti
|
ti := t.ti
|
||||||
|
|
||||||
io.WriteString(out, ti.EnterCA)
|
t.TPuts(ti.EnterCA)
|
||||||
io.WriteString(out, ti.EnterKeypad)
|
t.TPuts(ti.EnterKeypad)
|
||||||
io.WriteString(out, ti.HideCursor)
|
t.TPuts(ti.HideCursor)
|
||||||
io.WriteString(out, ti.Clear)
|
t.TPuts(ti.Clear)
|
||||||
|
|
||||||
t.quit = make(chan struct{})
|
t.quit = make(chan struct{})
|
||||||
t.cx = -1
|
t.cx = -1
|
||||||
t.cy = -1
|
t.cy = -1
|
||||||
|
t.style = StyleDefault
|
||||||
|
|
||||||
|
t.cells = ResizeCells(nil, 0, 0, t.w, t.h)
|
||||||
|
t.cursorx = -1
|
||||||
|
t.cursory = -1
|
||||||
go t.inputLoop()
|
go t.inputLoop()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -138,129 +148,139 @@ func (t *tScreen) prepareKeys() {
|
|||||||
|
|
||||||
func (t *tScreen) Fini() {
|
func (t *tScreen) Fini() {
|
||||||
ti := t.ti
|
ti := t.ti
|
||||||
out := t.out
|
if t.quit != nil {
|
||||||
io.WriteString(out, ti.ShowCursor)
|
close(t.quit)
|
||||||
io.WriteString(out, ti.AttrOff)
|
}
|
||||||
io.WriteString(out, ti.Clear)
|
t.TPuts(ti.ShowCursor)
|
||||||
io.WriteString(out, ti.ExitCA)
|
t.TPuts(ti.AttrOff)
|
||||||
io.WriteString(out, ti.ExitKeypad)
|
t.TPuts(ti.Clear)
|
||||||
io.WriteString(out, ti.ExitMouse)
|
t.TPuts(ti.ExitCA)
|
||||||
|
t.TPuts(ti.ExitKeypad)
|
||||||
|
t.TPuts(ti.ExitMouse)
|
||||||
|
|
||||||
t.w = 0
|
t.w = 0
|
||||||
t.h = 0
|
t.h = 0
|
||||||
|
t.cells = nil
|
||||||
t.curstyle = Style(-1)
|
t.curstyle = Style(-1)
|
||||||
t.cinvis = false
|
t.clear = false
|
||||||
if t.quit != nil {
|
t.termioFini()
|
||||||
close(t.quit)
|
}
|
||||||
} else {
|
|
||||||
t.termioFini()
|
func (t *tScreen) SetStyle(style Style) {
|
||||||
}
|
t.Lock()
|
||||||
|
t.style = style
|
||||||
|
t.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) Clear() {
|
func (t *tScreen) Clear() {
|
||||||
return
|
|
||||||
t.Lock()
|
t.Lock()
|
||||||
t.curstyle = Style(-1)
|
ClearCells(t.cells, t.style)
|
||||||
t.cx = -1
|
|
||||||
t.cy = -1
|
|
||||||
io.WriteString(t.out, t.ti.Clear)
|
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) SetCell(x, y int, style Style, ch ...rune) {
|
func (t *tScreen) SetCell(x, y int, style Style, ch ...rune) {
|
||||||
// XXX: this would be a place to check for hazeltine not being able
|
|
||||||
// to display ~, or possibly non-UTF-8 locales, etc.
|
|
||||||
|
|
||||||
t.Lock()
|
t.Lock()
|
||||||
if x < 0 || y < 0 || x >= t.w || y >= t.h {
|
if x < 0 || y < 0 || x >= t.w || y >= t.h {
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cell := &t.cells[(y*t.w)+x]
|
||||||
|
cell.SetCell(ch, style)
|
||||||
|
t.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) PutCell(x, y int, cell *Cell) {
|
||||||
|
t.Lock()
|
||||||
|
if x < 0 || y < 0 || x >= t.w || y >= t.h {
|
||||||
|
t.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cp := &t.cells[(y*t.w)+x]
|
||||||
|
cp.PutStyle(cell.Style)
|
||||||
|
cp.PutChars(cell.Ch)
|
||||||
|
t.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) GetCell(x, y int) *Cell {
|
||||||
|
t.Lock()
|
||||||
|
if x < 0 || y < 0 || x >= t.w || y >= t.h {
|
||||||
|
t.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cell := t.cells[(y*t.w)+x]
|
||||||
|
t.Unlock()
|
||||||
|
return &cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) drawCell(x, y int, cell *Cell) {
|
||||||
|
// XXX: this would be a place to check for hazeltine not being able
|
||||||
|
// to display ~, or possibly non-UTF-8 locales, etc.
|
||||||
|
|
||||||
ti := t.ti
|
ti := t.ti
|
||||||
|
|
||||||
if t.cy != y || t.cx != x {
|
if t.cy != y || t.cx != x {
|
||||||
io.WriteString(t.out, ti.TGoto(x, y))
|
t.TPuts(ti.TGoto(x, y))
|
||||||
|
}
|
||||||
|
style := cell.Style
|
||||||
|
if style == StyleDefault {
|
||||||
|
style = t.style
|
||||||
}
|
}
|
||||||
if style != t.curstyle {
|
if style != t.curstyle {
|
||||||
fg, bg, attrs := style.Decompose()
|
fg, bg, attrs := style.Decompose()
|
||||||
|
|
||||||
io.WriteString(t.out, ti.AttrOff)
|
t.TPuts(ti.AttrOff)
|
||||||
if attrs&AttrBold != 0 {
|
if attrs&AttrBold != 0 {
|
||||||
io.WriteString(t.out, ti.Bold)
|
t.TPuts(ti.Bold)
|
||||||
}
|
}
|
||||||
if attrs&AttrUnderline != 0 {
|
if attrs&AttrUnderline != 0 {
|
||||||
io.WriteString(t.out, ti.Underline)
|
t.TPuts(ti.Underline)
|
||||||
}
|
}
|
||||||
if attrs&AttrReverse != 0 {
|
if attrs&AttrReverse != 0 {
|
||||||
io.WriteString(t.out, ti.Reverse)
|
t.TPuts(ti.Reverse)
|
||||||
}
|
}
|
||||||
if attrs&AttrBlink != 0 {
|
if attrs&AttrBlink != 0 {
|
||||||
io.WriteString(t.out, ti.Blink)
|
t.TPuts(ti.Blink)
|
||||||
}
|
}
|
||||||
if attrs&AttrDim != 0 {
|
if attrs&AttrDim != 0 {
|
||||||
io.WriteString(t.out, ti.Dim)
|
t.TPuts(ti.Dim)
|
||||||
}
|
}
|
||||||
if fg != ColorDefault {
|
if fg != ColorDefault {
|
||||||
c := int(fg) - 1
|
c := int(fg) - 1
|
||||||
io.WriteString(t.out, ti.TParm(ti.SetFg, c))
|
t.TPuts(ti.TParm(ti.SetFg, c))
|
||||||
}
|
}
|
||||||
if bg != ColorDefault {
|
if bg != ColorDefault {
|
||||||
c := int(bg) - 1
|
c := int(bg) - 1
|
||||||
io.WriteString(t.out, ti.TParm(ti.SetBg, c))
|
t.TPuts(ti.TParm(ti.SetBg, c))
|
||||||
}
|
}
|
||||||
t.curstyle = style
|
t.curstyle = style
|
||||||
}
|
}
|
||||||
// now emit a character - taking care to not overrun width with a
|
// now emit runes - taking care to not overrun width with a
|
||||||
// wide character, and to ensure that we emit exactly one regular
|
// wide character, and to ensure that we emit exactly one regular
|
||||||
// character followed up by any residual combing characters
|
// character followed up by any residual combing characters
|
||||||
mainc := ' '
|
|
||||||
combc := ""
|
|
||||||
width := 1
|
|
||||||
|
|
||||||
for _, c := range ch {
|
width := int(cell.Width)
|
||||||
if c < ' ' {
|
var str string
|
||||||
// no control charcters allowed
|
if len(cell.Ch) == 0 {
|
||||||
continue
|
str = " "
|
||||||
}
|
} else {
|
||||||
switch runewidth.RuneWidth(c) {
|
str = string(cell.Ch)
|
||||||
case 0:
|
|
||||||
combc = combc + string(c)
|
|
||||||
case 1:
|
|
||||||
mainc = c
|
|
||||||
width = 1
|
|
||||||
case 2:
|
|
||||||
mainc = c
|
|
||||||
width = 2
|
|
||||||
if x >= t.w-1 {
|
|
||||||
// too wide to fit; emit space instead
|
|
||||||
mainc = ' '
|
|
||||||
width = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
io.WriteString(t.out, string(mainc))
|
if width == 2 && x >= t.w-1 {
|
||||||
io.WriteString(t.out, combc)
|
// too wide to fit; emit space instead
|
||||||
|
width = 1
|
||||||
|
str = " "
|
||||||
|
}
|
||||||
|
io.WriteString(t.out, str)
|
||||||
t.cy = y
|
t.cy = y
|
||||||
t.cx = x + width
|
t.cx = x + width
|
||||||
t.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) ShowCursor(x, y int) {
|
func (t *tScreen) ShowCursor(x, y int) {
|
||||||
t.Lock()
|
t.Lock()
|
||||||
if x < 0 || y < 0 || x >= t.w || y >= t.h {
|
t.cursorx = x
|
||||||
t.cinvis = true
|
t.cursory = y
|
||||||
io.WriteString(t.out, t.ti.HideCursor)
|
|
||||||
t.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if t.cx != x || t.cy != y {
|
|
||||||
io.WriteString(t.out, t.ti.TGoto(x, y))
|
|
||||||
}
|
|
||||||
io.WriteString(t.out, t.ti.ShowCursor)
|
|
||||||
|
|
||||||
t.cinvis = false
|
|
||||||
t.cx = x
|
|
||||||
t.cy = y
|
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,20 +288,82 @@ func (t *tScreen) HideCursor() {
|
|||||||
t.ShowCursor(-1, -1)
|
t.ShowCursor(-1, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) showCursor() {
|
||||||
|
|
||||||
|
x, y := t.cursorx, t.cursory
|
||||||
|
if x < 0 || y < 0 || x >= t.w || y >= t.h {
|
||||||
|
t.TPuts(t.ti.HideCursor)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if t.cx != x || t.cy != y {
|
||||||
|
t.TPuts(t.ti.TGoto(x, y))
|
||||||
|
}
|
||||||
|
t.TPuts(t.ti.ShowCursor)
|
||||||
|
t.cx = x
|
||||||
|
t.cy = y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) TPuts(s string) {
|
||||||
|
t.ti.TPuts(t.out, s, t.baud)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) Show() {
|
||||||
|
t.Lock()
|
||||||
|
t.resize()
|
||||||
|
t.draw()
|
||||||
|
t.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) clearScreen() {
|
||||||
|
t.TPuts(t.ti.Clear)
|
||||||
|
t.clear = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) hideCursor() {
|
||||||
|
// does not update cursor position
|
||||||
|
t.TPuts(t.ti.HideCursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) draw() {
|
||||||
|
// clobber cursor position, because we're gonna change it all
|
||||||
|
t.cx = -1
|
||||||
|
t.cy = -1
|
||||||
|
|
||||||
|
// hide the cursor while we move stuff around
|
||||||
|
t.hideCursor()
|
||||||
|
|
||||||
|
if t.clear {
|
||||||
|
t.clearScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
for row := 0; row < t.h; row++ {
|
||||||
|
for col := 0; col < t.w; col++ {
|
||||||
|
cell := &t.cells[(row*t.w)+col]
|
||||||
|
if !cell.Dirty {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
t.drawCell(col, row, cell)
|
||||||
|
cell.Dirty = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the cursor
|
||||||
|
t.showCursor()
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tScreen) EnableMouse() {
|
func (t *tScreen) EnableMouse() {
|
||||||
if len(t.mouse) != 0 {
|
if len(t.mouse) != 0 {
|
||||||
io.WriteString(t.out, t.ti.EnterMouse)
|
t.TPuts(t.ti.EnterMouse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) DisableMouse() {
|
func (t *tScreen) DisableMouse() {
|
||||||
if len(t.mouse) != 0 {
|
if len(t.mouse) != 0 {
|
||||||
io.WriteString(t.out, t.ti.ExitMouse)
|
t.TPuts(t.ti.ExitMouse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) Size() (int, int) {
|
func (t *tScreen) Size() (int, int) {
|
||||||
// XXX: get underlying size
|
|
||||||
t.Lock()
|
t.Lock()
|
||||||
w, h := t.w, t.h
|
w, h := t.w, t.h
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
@ -290,17 +372,17 @@ func (t *tScreen) Size() (int, int) {
|
|||||||
|
|
||||||
func (t *tScreen) resize() {
|
func (t *tScreen) resize() {
|
||||||
var ev Event
|
var ev Event
|
||||||
t.Lock()
|
|
||||||
if w, h, e := t.getWinSize(); e == nil {
|
if w, h, e := t.getWinSize(); e == nil {
|
||||||
if w != t.w || h != t.h {
|
if w != t.w || h != t.h {
|
||||||
ev = NewEventResize(w, h)
|
ev = NewEventResize(w, h)
|
||||||
t.w = w
|
|
||||||
t.h = h
|
|
||||||
t.cx = -1
|
t.cx = -1
|
||||||
t.cy = -1
|
t.cy = -1
|
||||||
|
|
||||||
|
t.cells = ResizeCells(t.cells, t.w, t.h, w, h)
|
||||||
|
t.w = w
|
||||||
|
t.h = h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Unlock()
|
|
||||||
if ev != nil {
|
if ev != nil {
|
||||||
t.PostEvent(ev)
|
t.PostEvent(ev)
|
||||||
}
|
}
|
||||||
@ -324,6 +406,282 @@ func (t *tScreen) PostEvent(ev Event) {
|
|||||||
t.evch <- ev
|
t.evch <- ev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (t *tScreen) postMouseEvent(x, y, btn int) {
|
||||||
|
|
||||||
|
// XTerm mouse events only report at most one button at a time,
|
||||||
|
// which may include a wheel button. Wheel motion events are
|
||||||
|
// reported as single impulses, while other button events are reported
|
||||||
|
// as separate press & release events.
|
||||||
|
|
||||||
|
button := ButtonNone
|
||||||
|
mod := ModNone
|
||||||
|
|
||||||
|
// Mouse wheel has bit 6 set, no release events. It should be noted
|
||||||
|
// 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 {
|
||||||
|
case 0:
|
||||||
|
button = Button1
|
||||||
|
t.wasbtn = true
|
||||||
|
case 1:
|
||||||
|
button = Button2
|
||||||
|
t.wasbtn = true
|
||||||
|
case 2:
|
||||||
|
button = Button3
|
||||||
|
t.wasbtn = true
|
||||||
|
case 3:
|
||||||
|
button = ButtonNone
|
||||||
|
t.wasbtn = false
|
||||||
|
case 0x40:
|
||||||
|
if !t.wasbtn {
|
||||||
|
button = WheelUp
|
||||||
|
} else {
|
||||||
|
button = Button1
|
||||||
|
}
|
||||||
|
case 0x41:
|
||||||
|
if !t.wasbtn {
|
||||||
|
button = WheelDown
|
||||||
|
} else {
|
||||||
|
button = Button2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if btn & 0x4 != 0 {
|
||||||
|
mod |= ModShift
|
||||||
|
}
|
||||||
|
if btn & 0x8 != 0 {
|
||||||
|
mod |= ModMeta
|
||||||
|
}
|
||||||
|
if btn & 0x10 != 0 {
|
||||||
|
mod |= ModCtrl
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some terminals will report mouse coordinates outside the
|
||||||
|
// screen, especially with click-drag events. Clip the coordinates
|
||||||
|
// to the screen in that case.
|
||||||
|
if x < 0 {
|
||||||
|
x = 0
|
||||||
|
}
|
||||||
|
if x > t.w-1 {
|
||||||
|
x = t.w-1
|
||||||
|
}
|
||||||
|
if y < 0 {
|
||||||
|
y = 0
|
||||||
|
}
|
||||||
|
if y > t.h-1 {
|
||||||
|
y = t.h-1
|
||||||
|
}
|
||||||
|
ev := NewEventMouse(x, y, button, mod)
|
||||||
|
t.PostEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseSgrMouse attempts to locate an SGR mouse record at the start of the
|
||||||
|
// buffer. It returns true, true if it found one, and the associated bytes
|
||||||
|
// be removed from the buffer. It returns true, false if the buffer might
|
||||||
|
// contain such an event, but more bytes are necessary (partial match), and
|
||||||
|
// false, false if the content is definitely *not* an SGR mouse record.
|
||||||
|
func (t *tScreen) parseSgrMouse(buf *bytes.Buffer) (bool, bool) {
|
||||||
|
|
||||||
|
b := buf.Bytes()
|
||||||
|
|
||||||
|
var x, y, btn, state int
|
||||||
|
dig := false
|
||||||
|
neg := false
|
||||||
|
i := 0
|
||||||
|
val := 0
|
||||||
|
|
||||||
|
for i = range b {
|
||||||
|
switch b[i] {
|
||||||
|
case '\x1b':
|
||||||
|
if state != 0 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
state = 1
|
||||||
|
|
||||||
|
case '\x9b':
|
||||||
|
if state != 0 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
state = 2
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
if state != 1 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
state = 2
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
if state != 2 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
val = 0
|
||||||
|
dig = false
|
||||||
|
neg = false
|
||||||
|
state = 3
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
if state != 3 || state != 4 || state != 5 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
if dig || neg {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
neg = true // stay in state
|
||||||
|
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
if state != 3 && state != 4 && state != 5 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
val *= 10
|
||||||
|
val += int(b[i]-'0')
|
||||||
|
dig = true // stay in state
|
||||||
|
|
||||||
|
case ';':
|
||||||
|
if neg {
|
||||||
|
val = -val
|
||||||
|
}
|
||||||
|
switch state {
|
||||||
|
case 3:
|
||||||
|
btn, val = val, 0
|
||||||
|
neg, dig, state = false, false, 4
|
||||||
|
case 4:
|
||||||
|
x, val = val, 0
|
||||||
|
neg, dig, state = false, false, 5
|
||||||
|
default:
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'm', 'M':
|
||||||
|
if state != 5 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
if neg {
|
||||||
|
val = -val
|
||||||
|
}
|
||||||
|
y = val
|
||||||
|
|
||||||
|
// We don't care about the motion bit
|
||||||
|
btn &^= 32
|
||||||
|
if b[i] == 'm' {
|
||||||
|
// mouse release, clear all buttons
|
||||||
|
btn |= 3
|
||||||
|
btn &^= 0x40
|
||||||
|
}
|
||||||
|
// consume the event bytes
|
||||||
|
for i >= 0 {
|
||||||
|
buf.ReadByte()
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
t.postMouseEvent(x, y, btn)
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// incomplete & inconclusve at this point
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseXtermMouse is like parseSgrMouse, but it parses a legacy
|
||||||
|
// X11 mouse record.
|
||||||
|
func (t *tScreen) parseXtermMouse(buf *bytes.Buffer) (bool, bool) {
|
||||||
|
|
||||||
|
b := buf.Bytes()
|
||||||
|
|
||||||
|
state := 0
|
||||||
|
btn := 0
|
||||||
|
x := 0
|
||||||
|
y := 0
|
||||||
|
|
||||||
|
for i := range b {
|
||||||
|
switch state {
|
||||||
|
case 0:
|
||||||
|
switch b[i] {
|
||||||
|
case '\x1b':
|
||||||
|
state = 1
|
||||||
|
case '\x9b':
|
||||||
|
state = 2
|
||||||
|
default:
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if b[i] != '[' {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
state = 2
|
||||||
|
case 2:
|
||||||
|
if b[i] != 'M' {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
state++
|
||||||
|
case 3:
|
||||||
|
btn = int(b[i])
|
||||||
|
state++
|
||||||
|
case 4:
|
||||||
|
x = int(b[i]) - 32 - 1
|
||||||
|
state++
|
||||||
|
case 5:
|
||||||
|
y = int(b[i]) - 32 - 1
|
||||||
|
for i >= 0 {
|
||||||
|
buf.ReadByte()
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
t.postMouseEvent(x, y, btn)
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) parseFunctionKey(buf *bytes.Buffer) (bool, bool) {
|
||||||
|
b := buf.Bytes()
|
||||||
|
partial := false
|
||||||
|
for k, esc := range t.keys {
|
||||||
|
if bytes.HasPrefix(b, esc) {
|
||||||
|
// matched
|
||||||
|
var r rune
|
||||||
|
if len(esc) == 1 {
|
||||||
|
r = rune(b[0])
|
||||||
|
}
|
||||||
|
ev := NewEventKey(k, r, ModNone)
|
||||||
|
t.PostEvent(ev)
|
||||||
|
for i := 0; i < len(esc); i++ {
|
||||||
|
buf.ReadByte()
|
||||||
|
}
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
if bytes.HasPrefix(esc, b) {
|
||||||
|
partial = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return partial, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) parseRune(buf *bytes.Buffer) (bool, bool) {
|
||||||
|
b := buf.Bytes()
|
||||||
|
if b[0] >= ' ' && b[0] <= 0x7F {
|
||||||
|
// printable ASCII easy to deal with -- no encodings
|
||||||
|
buf.ReadByte()
|
||||||
|
ev := NewEventKey(KeyRune, rune(b[0]), ModNone)
|
||||||
|
t.PostEvent(ev)
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
if b[0] >= 0x80 {
|
||||||
|
if utf8.FullRune(b) {
|
||||||
|
r, _, e := buf.ReadRune()
|
||||||
|
if e == nil {
|
||||||
|
ev := NewEventKey(KeyRune, r, ModNone)
|
||||||
|
t.PostEvent(ev)
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Looks like potential escape
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tScreen) scanInput(buf *bytes.Buffer, expire bool) {
|
func (t *tScreen) scanInput(buf *bytes.Buffer, expire bool) {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -332,108 +690,46 @@ func (t *tScreen) scanInput(buf *bytes.Buffer, expire bool) {
|
|||||||
buf.Reset()
|
buf.Reset()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if b[0] >= ' ' && b[0] <= 0x7F {
|
|
||||||
// printable ASCII easy to deal with -- no encodings
|
|
||||||
buf.ReadByte()
|
|
||||||
ev := NewEventKey(KeyRune, rune(b[0]), ModNone)
|
|
||||||
t.PostEvent(ev)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// We assume that the first character of any terminal escape
|
|
||||||
// sequence will be in ASCII -- most often (by far) it is ESC.
|
|
||||||
if b[0] >= 0x80 && utf8.FullRune(b) {
|
|
||||||
r, _, e := buf.ReadRune()
|
|
||||||
if e == nil {
|
|
||||||
ev := NewEventKey(KeyRune, r, ModNone)
|
|
||||||
t.PostEvent(ev)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Now check the codes we know about
|
|
||||||
partials := 0
|
partials := 0
|
||||||
matched := false
|
|
||||||
for k, esc := range t.keys {
|
|
||||||
if bytes.HasPrefix(b, esc) {
|
|
||||||
// matched
|
|
||||||
var r rune
|
|
||||||
if len(esc) == 1 {
|
|
||||||
r = rune(b[0])
|
|
||||||
}
|
|
||||||
ev := NewEventKey(k, r, ModNone)
|
|
||||||
t.PostEvent(ev)
|
|
||||||
matched = true
|
|
||||||
for i := 0; i < len(esc); i++ {
|
|
||||||
buf.ReadByte()
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if bytes.HasPrefix(esc, b) {
|
|
||||||
partials++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse events are special, as they carry parameters
|
if part, comp := t.parseRune(buf); comp {
|
||||||
if !matched && len(t.mouse) != 0 &&
|
continue
|
||||||
bytes.HasPrefix(b, t.mouse) {
|
} else if part {
|
||||||
|
|
||||||
if len(b) >= len(t.mouse)+3 {
|
|
||||||
// mouse record
|
|
||||||
b = b[len(t.mouse):]
|
|
||||||
btns := ButtonNone
|
|
||||||
mod := ModNone
|
|
||||||
switch b[0] & 3 {
|
|
||||||
case 0:
|
|
||||||
btns = Button1
|
|
||||||
case 1:
|
|
||||||
btns = Button2
|
|
||||||
case 2:
|
|
||||||
btns = Button3
|
|
||||||
case 3:
|
|
||||||
btns = 0
|
|
||||||
}
|
|
||||||
if b[0]&4 != 0 {
|
|
||||||
mod |= ModShift
|
|
||||||
}
|
|
||||||
if b[0]&8 != 0 {
|
|
||||||
mod |= ModMeta
|
|
||||||
}
|
|
||||||
if b[0]&16 != 0 {
|
|
||||||
mod |= ModCtrl
|
|
||||||
}
|
|
||||||
x := int(b[1]) - 33
|
|
||||||
y := int(b[2]) - 33
|
|
||||||
for i := 0; i < len(t.mouse)+3; i++ {
|
|
||||||
buf.ReadByte()
|
|
||||||
}
|
|
||||||
matched = true
|
|
||||||
ev := NewEventMouse(x, y, btns, mod)
|
|
||||||
t.PostEvent(ev)
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
partials++
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
partials++
|
partials++
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we expired, we implicitly fail matches
|
if part, comp := t.parseFunctionKey(buf); comp {
|
||||||
if expire {
|
continue
|
||||||
partials = 0
|
} else if part {
|
||||||
}
|
partials++
|
||||||
// If we had no partial matches, just send first character as
|
|
||||||
// a rune. Others might still work.
|
|
||||||
if partials == 0 && !matched {
|
|
||||||
ev := NewEventKey(KeyRune, rune(b[0]), ModNone)
|
|
||||||
t.PostEvent(ev)
|
|
||||||
buf.ReadByte()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if partials > 0 {
|
if part, comp := t.parseXtermMouse(buf); comp {
|
||||||
// We had one or more partial matches, wait for more
|
continue
|
||||||
// data.
|
} else if part {
|
||||||
return
|
partials++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if part, comp := t.parseSgrMouse(buf); comp {
|
||||||
|
continue
|
||||||
|
} else if part {
|
||||||
|
partials++
|
||||||
|
}
|
||||||
|
|
||||||
|
if partials == 0 || expire {
|
||||||
|
// Nothing was going to match, or we timed out
|
||||||
|
// waiting for more data -- just deliver the characters
|
||||||
|
// to the app & let them sort it out.
|
||||||
|
by, _ := buf.ReadByte()
|
||||||
|
ev := NewEventKey(KeyRune, rune(by), ModNone)
|
||||||
|
t.PostEvent(ev)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// well we have some partial data, wait until we get
|
||||||
|
// some more
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,10 +739,12 @@ func (t *tScreen) inputLoop() {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.quit:
|
case <-t.quit:
|
||||||
t.termioFini()
|
close(t.indoneq)
|
||||||
return
|
return
|
||||||
case <-t.sigwinch:
|
case <-t.sigwinch:
|
||||||
|
t.Lock()
|
||||||
t.resize()
|
t.resize()
|
||||||
|
t.Unlock()
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
@ -462,7 +760,7 @@ func (t *tScreen) inputLoop() {
|
|||||||
continue
|
continue
|
||||||
case nil:
|
case nil:
|
||||||
default:
|
default:
|
||||||
// XXX: post error event?
|
close(t.indoneq)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buf.Write(chunk[:n])
|
buf.Write(chunk[:n])
|
||||||
@ -470,3 +768,12 @@ func (t *tScreen) inputLoop() {
|
|||||||
t.scanInput(buf, false)
|
t.scanInput(buf, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) Sync() {
|
||||||
|
t.Lock()
|
||||||
|
t.resize()
|
||||||
|
t.clear = true
|
||||||
|
InvalidateCells(t.cells)
|
||||||
|
t.draw()
|
||||||
|
t.Unlock()
|
||||||
|
}
|
||||||
|
102
tscreen_posix.go
102
tscreen_posix.go
@ -38,18 +38,93 @@ import (
|
|||||||
// return (-1);
|
// return (-1);
|
||||||
// #endif
|
// #endif
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
// int getbaud(struct termios *tios) {
|
||||||
|
// switch (cfgetospeed(tios)) {
|
||||||
|
// #ifdef B0
|
||||||
|
// case B0: return (0);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B50
|
||||||
|
// case B50: return (50);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B75
|
||||||
|
// case B75: return (75);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B110
|
||||||
|
// case B110: return (110);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B134
|
||||||
|
// case B134: return (134);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B150
|
||||||
|
// case B150: return (150);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B200
|
||||||
|
// case B200: return (200);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B300
|
||||||
|
// case B300: return (300);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B600
|
||||||
|
// case B600: return (600);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B1200
|
||||||
|
// case B1200: return (1200);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B1800
|
||||||
|
// case B1800: return (1800);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B2400
|
||||||
|
// case B2400: return (2400);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B4800
|
||||||
|
// case B4800: return (4800);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B9600
|
||||||
|
// case B9600: return (9600);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B19200
|
||||||
|
// case B19200: return (19200);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B38400
|
||||||
|
// case B38400: return (38400);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B57600
|
||||||
|
// case B57600: return (57600);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B76800
|
||||||
|
// case B76800: return (76800);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B115200
|
||||||
|
// case B115200: return (115200);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B153600
|
||||||
|
// case B153600: return (153600);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B230400
|
||||||
|
// case B230400: return (230400);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B307200
|
||||||
|
// case B307200: return (307200);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B460800
|
||||||
|
// case B460800: return (460800);
|
||||||
|
// #endif
|
||||||
|
// #ifdef B921600
|
||||||
|
// case B921600: return (921600);
|
||||||
|
// #endif
|
||||||
|
// }
|
||||||
|
// return (0);
|
||||||
|
// }
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var savedtios map[*tScreen]*C.struct_termios
|
type termiosPrivate struct {
|
||||||
|
tios C.struct_termios
|
||||||
func init() {
|
|
||||||
savedtios = make(map[*tScreen]*C.struct_termios)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) termioInit() error {
|
func (t *tScreen) termioInit() error {
|
||||||
var e error
|
var e error
|
||||||
var rv C.int
|
var rv C.int
|
||||||
var oldtios C.struct_termios
|
|
||||||
var newtios C.struct_termios
|
var newtios C.struct_termios
|
||||||
var fd C.int
|
var fd C.int
|
||||||
|
|
||||||
@ -60,11 +135,14 @@ func (t *tScreen) termioInit() error {
|
|||||||
goto failed
|
goto failed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.tiosp = &termiosPrivate{}
|
||||||
|
|
||||||
fd = C.int(t.out.Fd())
|
fd = C.int(t.out.Fd())
|
||||||
if rv, e = C.tcgetattr(fd, &oldtios); rv != 0 {
|
if rv, e = C.tcgetattr(fd, &t.tiosp.tios); rv != 0 {
|
||||||
goto failed
|
goto failed
|
||||||
}
|
}
|
||||||
newtios = oldtios
|
t.baud = int(C.getbaud(&t.tiosp.tios))
|
||||||
|
newtios = t.tiosp.tios
|
||||||
newtios.c_iflag &^= C.IGNBRK | C.BRKINT | C.PARMRK |
|
newtios.c_iflag &^= C.IGNBRK | C.BRKINT | C.PARMRK |
|
||||||
C.ISTRIP | C.INLCR | C.IGNCR |
|
C.ISTRIP | C.INLCR | C.IGNCR |
|
||||||
C.ICRNL | C.IXON
|
C.ICRNL | C.IXON
|
||||||
@ -86,7 +164,6 @@ func (t *tScreen) termioInit() error {
|
|||||||
goto failed
|
goto failed
|
||||||
}
|
}
|
||||||
|
|
||||||
savedtios[t] = &oldtios
|
|
||||||
signal.Notify(t.sigwinch, syscall.SIGWINCH)
|
signal.Notify(t.sigwinch, syscall.SIGWINCH)
|
||||||
|
|
||||||
if w, h, e := t.getWinSize(); e == nil && w != 0 && h != 0 {
|
if w, h, e := t.getWinSize(); e == nil && w != 0 && h != 0 {
|
||||||
@ -110,12 +187,11 @@ func (t *tScreen) termioFini() {
|
|||||||
|
|
||||||
signal.Stop(t.sigwinch)
|
signal.Stop(t.sigwinch)
|
||||||
|
|
||||||
|
<-t.indoneq
|
||||||
|
|
||||||
if t.out != nil {
|
if t.out != nil {
|
||||||
if oldtios, ok := savedtios[t]; ok {
|
fd := C.int(t.out.Fd())
|
||||||
fd := C.int(t.out.Fd())
|
C.tcsetattr(fd, C.TCSANOW|C.TCSAFLUSH, &t.tiosp.tios)
|
||||||
C.tcsetattr(fd, C.TCSANOW, oldtios)
|
|
||||||
delete(savedtios, t)
|
|
||||||
}
|
|
||||||
t.out.Close()
|
t.out.Close()
|
||||||
}
|
}
|
||||||
if t.in != nil {
|
if t.in != nil {
|
||||||
|
@ -37,3 +37,5 @@ func (t *tScreen) termioFini() {
|
|||||||
func (t *tScreen) getWinSize() (int, int, error) {
|
func (t *tScreen) getWinSize() (int, int, error) {
|
||||||
return 0, 0, errors.New("no temrios on Windows")
|
return 0, 0, errors.New("no temrios on Windows")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type termiosPrivate struct{}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user