mirror of https://github.com/miguelmota/cointop
Merge branch 'cointop-sh:master' into feature/better-resample
commit
f37499a381
@ -0,0 +1,40 @@
|
|||||||
|
version: 2.1
|
||||||
|
|
||||||
|
orbs:
|
||||||
|
base: dmx-io/base@2.0.88
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_push:
|
||||||
|
working_directory: /app
|
||||||
|
docker:
|
||||||
|
- image: docker:17.09.0-ce-git
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- setup_remote_docker
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
apk update
|
||||||
|
apk upgrade
|
||||||
|
apk add --no-cache make
|
||||||
|
- run:
|
||||||
|
name: Build application Docker image
|
||||||
|
command: |
|
||||||
|
make docker-build
|
||||||
|
- deploy:
|
||||||
|
name: Push Docker image to Docker Hub
|
||||||
|
command: |
|
||||||
|
make docker-login-ci
|
||||||
|
make docker-tag-ci
|
||||||
|
make docker-push-ci
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
main:
|
||||||
|
jobs:
|
||||||
|
- build_and_push:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
ignore: /.*/
|
@ -1,39 +0,0 @@
|
|||||||
package color
|
|
||||||
|
|
||||||
import "github.com/fatih/color"
|
|
||||||
|
|
||||||
// Color struct
|
|
||||||
type Color color.Color
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Bold color
|
|
||||||
Bold = color.New(color.Bold).SprintFunc()
|
|
||||||
// Black color
|
|
||||||
Black = color.New(color.FgBlack).SprintFunc()
|
|
||||||
// BlackBg color
|
|
||||||
BlackBg = color.New(color.BgBlack, color.FgWhite).SprintFunc()
|
|
||||||
// White color
|
|
||||||
White = color.New(color.FgWhite).SprintFunc()
|
|
||||||
// WhiteBold bold
|
|
||||||
WhiteBold = color.New(color.FgWhite, color.Bold).SprintFunc()
|
|
||||||
// Yellow color
|
|
||||||
Yellow = color.New(color.FgYellow).SprintFunc()
|
|
||||||
// YellowBold color
|
|
||||||
YellowBold = color.New(color.FgYellow, color.Bold).SprintFunc()
|
|
||||||
// YellowBg color
|
|
||||||
YellowBg = color.New(color.BgYellow, color.FgBlack).SprintFunc()
|
|
||||||
// Green color
|
|
||||||
Green = color.New(color.FgGreen).SprintFunc()
|
|
||||||
// GreenBg color
|
|
||||||
GreenBg = color.New(color.BgGreen, color.FgBlack).SprintFunc()
|
|
||||||
// Red color
|
|
||||||
Red = color.New(color.FgRed).SprintFunc()
|
|
||||||
// Cyan color
|
|
||||||
Cyan = color.New(color.FgCyan).SprintFunc()
|
|
||||||
// CyanBg color
|
|
||||||
CyanBg = color.New(color.BgCyan, color.FgBlack).SprintFunc()
|
|
||||||
// Blue color
|
|
||||||
Blue = color.New(color.FgBlue).SprintFunc()
|
|
||||||
// BlueBg color
|
|
||||||
BlueBg = color.New(color.BgBlue).SprintFunc()
|
|
||||||
)
|
|
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2014 The gocui Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gocui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// eventBinding are used to link a given key-press event with a handler.
|
||||||
|
type eventBinding struct {
|
||||||
|
viewName string
|
||||||
|
ev tcell.Event // ignore the Time
|
||||||
|
handler func(*Gui, *View) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// newKeybinding returns a new eventBinding object for a key event.
|
||||||
|
func newKeybinding(viewname string, key tcell.Key, ch rune, mod tcell.ModMask, handler func(*Gui, *View) error) (kb *eventBinding) {
|
||||||
|
kb = &eventBinding{
|
||||||
|
viewName: viewname,
|
||||||
|
ev: tcell.NewEventKey(key, ch, mod),
|
||||||
|
handler: handler,
|
||||||
|
}
|
||||||
|
return kb
|
||||||
|
}
|
||||||
|
|
||||||
|
// newKeybinding returns a new eventBinding object for a mouse event.
|
||||||
|
func newMouseBinding(viewname string, btn tcell.ButtonMask, mod tcell.ModMask, handler func(*Gui, *View) error) (kb *eventBinding) {
|
||||||
|
kb = &eventBinding{
|
||||||
|
viewName: viewname,
|
||||||
|
ev: tcell.NewEventMouse(0, 0, btn, mod),
|
||||||
|
handler: handler,
|
||||||
|
}
|
||||||
|
return kb
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *eventBinding) matchEvent(e tcell.Event) bool {
|
||||||
|
// TODO: check mask not ==mod?
|
||||||
|
switch tev := e.(type) {
|
||||||
|
case *tcell.EventKey:
|
||||||
|
if kbe, ok := kb.ev.(*tcell.EventKey); ok {
|
||||||
|
if tev.Key() == tcell.KeyRune {
|
||||||
|
return tev.Key() == kbe.Key() && tev.Rune() == kbe.Rune() && tev.Modifiers() == kbe.Modifiers()
|
||||||
|
}
|
||||||
|
return tev.Key() == kbe.Key() && tev.Modifiers() == kbe.Modifiers()
|
||||||
|
}
|
||||||
|
|
||||||
|
case *tcell.EventMouse:
|
||||||
|
if kbe, ok := kb.ev.(*tcell.EventMouse); ok {
|
||||||
|
return kbe.Buttons() == tev.Buttons() && kbe.Modifiers() == tev.Modifiers()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchView returns if the eventBinding matches the current view.
|
||||||
|
func (kb *eventBinding) matchView(v *View) bool {
|
||||||
|
if kb.viewName == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return v != nil && kb.viewName == v.name
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
version: 1.0.{build}
|
||||||
|
clone_folder: c:\gopath\src\github.com\gdamore\encoding
|
||||||
|
environment:
|
||||||
|
GOPATH: c:\gopath
|
||||||
|
build_script:
|
||||||
|
- go version
|
||||||
|
- go env
|
||||||
|
- SET PATH=%LOCALAPPDATA%\atom\bin;%GOPATH%\bin;%PATH%
|
||||||
|
- go get -t ./...
|
||||||
|
- go build
|
||||||
|
- go install ./...
|
||||||
|
test_script:
|
||||||
|
- go test ./...
|
@ -0,0 +1,7 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
|
- tip
|
@ -0,0 +1,19 @@
|
|||||||
|
## encoding
|
||||||
|
|
||||||
|
[![Linux Status](https://img.shields.io/travis/gdamore/encoding.svg?label=linux)](https://travis-ci.org/gdamore/encoding)
|
||||||
|
[![Windows Status](https://img.shields.io/appveyor/ci/gdamore/encoding.svg?label=windows)](https://ci.appveyor.com/project/gdamore/encoding)
|
||||||
|
[![Apache License](https://img.shields.io/badge/license-APACHE2-blue.svg)](https://github.com/gdamore/encoding/blob/master/LICENSE)
|
||||||
|
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/gdamore/encoding)
|
||||||
|
[![Go Report Card](http://goreportcard.com/badge/gdamore/encoding)](http://goreportcard.com/report/gdamore/encoding)
|
||||||
|
|
||||||
|
Package encoding provides a number of encodings that are missing from the
|
||||||
|
standard Go [encoding]("https://godoc.org/golang.org/x/text/encoding") package.
|
||||||
|
|
||||||
|
We hope that we can contribute these to the standard Go library someday. It
|
||||||
|
turns out that some of these are useful for dealing with I/O streams coming
|
||||||
|
from non-UTF friendly sources.
|
||||||
|
|
||||||
|
The UTF8 Encoder is also useful for situations where valid UTF-8 might be
|
||||||
|
carried in streams that contain non-valid UTF; in particular I use it for
|
||||||
|
helping me cope with terminals that embed escape sequences in otherwise
|
||||||
|
valid UTF-8.
|
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2015 Garrett D'Amore
|
||||||
|
//
|
||||||
|
// 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 encoding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ASCII represents the 7-bit US-ASCII scheme. It decodes directly to
|
||||||
|
// UTF-8 without change, as all ASCII values are legal UTF-8.
|
||||||
|
// Unicode values less than 128 (i.e. 7 bits) map 1:1 with ASCII.
|
||||||
|
// It encodes runes outside of that to 0x1A, the ASCII substitution character.
|
||||||
|
var ASCII encoding.Encoding
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
amap := make(map[byte]rune)
|
||||||
|
for i := 128; i <= 255; i++ {
|
||||||
|
amap[byte(i)] = RuneError
|
||||||
|
}
|
||||||
|
|
||||||
|
cm := &Charmap{Map: amap}
|
||||||
|
cm.Init()
|
||||||
|
ASCII = cm
|
||||||
|
}
|
@ -0,0 +1,196 @@
|
|||||||
|
// Copyright 2015 Garrett D'Amore
|
||||||
|
//
|
||||||
|
// 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 encoding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
"golang.org/x/text/transform"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RuneError is an alias for the UTF-8 replacement rune, '\uFFFD'.
|
||||||
|
RuneError = '\uFFFD'
|
||||||
|
|
||||||
|
// RuneSelf is the rune below which UTF-8 and the Unicode values are
|
||||||
|
// identical. Its also the limit for ASCII.
|
||||||
|
RuneSelf = 0x80
|
||||||
|
|
||||||
|
// ASCIISub is the ASCII substitution character.
|
||||||
|
ASCIISub = '\x1a'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Charmap is a structure for setting up encodings for 8-bit character sets,
|
||||||
|
// for transforming between UTF8 and that other character set. It has some
|
||||||
|
// ideas borrowed from golang.org/x/text/encoding/charmap, but it uses a
|
||||||
|
// different implementation. This implementation uses maps, and supports
|
||||||
|
// user-defined maps.
|
||||||
|
//
|
||||||
|
// We do assume that a character map has a reasonable substitution character,
|
||||||
|
// and that valid encodings are stable (exactly a 1:1 map) and stateless
|
||||||
|
// (that is there is no shift character or anything like that.) Hence this
|
||||||
|
// approach will not work for many East Asian character sets.
|
||||||
|
//
|
||||||
|
// Measurement shows little or no measurable difference in the performance of
|
||||||
|
// the two approaches. The difference was down to a couple of nsec/op, and
|
||||||
|
// no consistent pattern as to which ran faster. With the conversion to
|
||||||
|
// UTF-8 the code takes about 25 nsec/op. The conversion in the reverse
|
||||||
|
// direction takes about 100 nsec/op. (The larger cost for conversion
|
||||||
|
// from UTF-8 is most likely due to the need to convert the UTF-8 byte stream
|
||||||
|
// to a rune before conversion.
|
||||||
|
//
|
||||||
|
type Charmap struct {
|
||||||
|
transform.NopResetter
|
||||||
|
bytes map[rune]byte
|
||||||
|
runes [256][]byte
|
||||||
|
once sync.Once
|
||||||
|
|
||||||
|
// The map between bytes and runes. To indicate that a specific
|
||||||
|
// byte value is invalid for a charcter set, use the rune
|
||||||
|
// utf8.RuneError. Values that are absent from this map will
|
||||||
|
// be assumed to have the identity mapping -- that is the default
|
||||||
|
// is to assume ISO8859-1, where all 8-bit characters have the same
|
||||||
|
// numeric value as their Unicode runes. (Not to be confused with
|
||||||
|
// the UTF-8 values, which *will* be different for non-ASCII runes.)
|
||||||
|
//
|
||||||
|
// If no values less than RuneSelf are changed (or have non-identity
|
||||||
|
// mappings), then the character set is assumed to be an ASCII
|
||||||
|
// superset, and certain assumptions and optimizations become
|
||||||
|
// available for ASCII bytes.
|
||||||
|
Map map[byte]rune
|
||||||
|
|
||||||
|
// The ReplacementChar is the byte value to use for substitution.
|
||||||
|
// It should normally be ASCIISub for ASCII encodings. This may be
|
||||||
|
// unset (left to zero) for mappings that are strictly ASCII supersets.
|
||||||
|
// In that case ASCIISub will be assumed instead.
|
||||||
|
ReplacementChar byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type cmapDecoder struct {
|
||||||
|
transform.NopResetter
|
||||||
|
runes [256][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type cmapEncoder struct {
|
||||||
|
transform.NopResetter
|
||||||
|
bytes map[rune]byte
|
||||||
|
replace byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes internal values of a character map. This should
|
||||||
|
// be done early, to minimize the cost of allocation of transforms
|
||||||
|
// later. It is not strictly necessary however, as the allocation
|
||||||
|
// functions will arrange to call it if it has not already been done.
|
||||||
|
func (c *Charmap) Init() {
|
||||||
|
c.once.Do(c.initialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Charmap) initialize() {
|
||||||
|
c.bytes = make(map[rune]byte)
|
||||||
|
ascii := true
|
||||||
|
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
r, ok := c.Map[byte(i)]
|
||||||
|
if !ok {
|
||||||
|
r = rune(i)
|
||||||
|
}
|
||||||
|
if r < 128 && r != rune(i) {
|
||||||
|
ascii = false
|
||||||
|
}
|
||||||
|
if r != RuneError {
|
||||||
|
c.bytes[r] = byte(i)
|
||||||
|
}
|
||||||
|
utf := make([]byte, utf8.RuneLen(r))
|
||||||
|
utf8.EncodeRune(utf, r)
|
||||||
|
c.runes[i] = utf
|
||||||
|
}
|
||||||
|
if ascii && c.ReplacementChar == '\x00' {
|
||||||
|
c.ReplacementChar = ASCIISub
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a Decoder the converts from the 8-bit
|
||||||
|
// character set to UTF-8. Unknown mappings, if any, are mapped
|
||||||
|
// to '\uFFFD'.
|
||||||
|
func (c *Charmap) NewDecoder() *encoding.Decoder {
|
||||||
|
c.Init()
|
||||||
|
return &encoding.Decoder{Transformer: &cmapDecoder{runes: c.runes}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a Transformer that converts from UTF8 to the
|
||||||
|
// 8-bit character set. Unknown mappings are mapped to 0x1A.
|
||||||
|
func (c *Charmap) NewEncoder() *encoding.Encoder {
|
||||||
|
c.Init()
|
||||||
|
return &encoding.Encoder{
|
||||||
|
Transformer: &cmapEncoder{
|
||||||
|
bytes: c.bytes,
|
||||||
|
replace: c.ReplacementChar,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *cmapDecoder) Transform(dst, src []byte, atEOF bool) (int, int, error) {
|
||||||
|
var e error
|
||||||
|
var ndst, nsrc int
|
||||||
|
|
||||||
|
for _, c := range src {
|
||||||
|
b := d.runes[c]
|
||||||
|
l := len(b)
|
||||||
|
|
||||||
|
if ndst+l > len(dst) {
|
||||||
|
e = transform.ErrShortDst
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
dst[ndst] = b[i]
|
||||||
|
ndst++
|
||||||
|
}
|
||||||
|
nsrc++
|
||||||
|
}
|
||||||
|
return ndst, nsrc, e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *cmapEncoder) Transform(dst, src []byte, atEOF bool) (int, int, error) {
|
||||||
|
var e error
|
||||||
|
var ndst, nsrc int
|
||||||
|
for nsrc < len(src) {
|
||||||
|
if ndst >= len(dst) {
|
||||||
|
e = transform.ErrShortDst
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
r, sz := utf8.DecodeRune(src[nsrc:])
|
||||||
|
if r == utf8.RuneError && sz == 1 {
|
||||||
|
// If its inconclusive due to insufficient data in
|
||||||
|
// in the source, report it
|
||||||
|
if !atEOF && !utf8.FullRune(src[nsrc:]) {
|
||||||
|
e = transform.ErrShortSrc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c, ok := d.bytes[r]; ok {
|
||||||
|
dst[ndst] = c
|
||||||
|
} else {
|
||||||
|
dst[ndst] = d.replace
|
||||||
|
}
|
||||||
|
nsrc += sz
|
||||||
|
ndst++
|
||||||
|
}
|
||||||
|
|
||||||
|
return ndst, nsrc, e
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015 Garrett D'Amore
|
||||||
|
//
|
||||||
|
// 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 encoding provides a few of the encoding structures that are
|
||||||
|
// missing from the Go x/text/encoding tree.
|
||||||
|
package encoding
|
@ -0,0 +1,273 @@
|
|||||||
|
// Copyright 2015 Garrett D'Amore
|
||||||
|
//
|
||||||
|
// 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 encoding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EBCDIC represents the 8-bit EBCDIC scheme, found in some mainframe
|
||||||
|
// environments. If you don't know what this is, consider yourself lucky.
|
||||||
|
var EBCDIC encoding.Encoding
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cm := &Charmap{
|
||||||
|
ReplacementChar: '\x3f',
|
||||||
|
Map: map[byte]rune{
|
||||||
|
// 0x00-0x03 match
|
||||||
|
0x04: RuneError,
|
||||||
|
0x05: '\t',
|
||||||
|
0x06: RuneError,
|
||||||
|
0x07: '\x7f',
|
||||||
|
0x08: RuneError,
|
||||||
|
0x09: RuneError,
|
||||||
|
0x0a: RuneError,
|
||||||
|
// 0x0b-0x13 match
|
||||||
|
0x14: RuneError,
|
||||||
|
0x15: '\x85', // Not in any ISO code
|
||||||
|
0x16: '\x08',
|
||||||
|
0x17: RuneError,
|
||||||
|
// 0x18-0x19 match
|
||||||
|
0x1a: RuneError,
|
||||||
|
0x1b: RuneError,
|
||||||
|
// 0x1c-0x1f match
|
||||||
|
0x20: RuneError,
|
||||||
|
0x21: RuneError,
|
||||||
|
0x22: RuneError,
|
||||||
|
0x23: RuneError,
|
||||||
|
0x24: RuneError,
|
||||||
|
0x25: '\n',
|
||||||
|
0x26: '\x17',
|
||||||
|
0x27: '\x1b',
|
||||||
|
0x28: RuneError,
|
||||||
|
0x29: RuneError,
|
||||||
|
0x2a: RuneError,
|
||||||
|
0x2b: RuneError,
|
||||||
|
0x2c: RuneError,
|
||||||
|
0x2d: '\x05',
|
||||||
|
0x2e: '\x06',
|
||||||
|
0x2f: '\x07',
|
||||||
|
0x30: RuneError,
|
||||||
|
0x31: RuneError,
|
||||||
|
0x32: '\x16',
|
||||||
|
0x33: RuneError,
|
||||||
|
0x34: RuneError,
|
||||||
|
0x35: RuneError,
|
||||||
|
0x36: RuneError,
|
||||||
|
0x37: '\x04',
|
||||||
|
0x38: RuneError,
|
||||||
|
0x39: RuneError,
|
||||||
|
0x3a: RuneError,
|
||||||
|
0x3b: RuneError,
|
||||||
|
0x3c: '\x14',
|
||||||
|
0x3d: '\x15',
|
||||||
|
0x3e: RuneError,
|
||||||
|
0x3f: '\x1a', // also replacement char
|
||||||
|
0x40: ' ',
|
||||||
|
0x41: '\xa0',
|
||||||
|
0x42: RuneError,
|
||||||
|
0x43: RuneError,
|
||||||
|
0x44: RuneError,
|
||||||
|
0x45: RuneError,
|
||||||
|
0x46: RuneError,
|
||||||
|
0x47: RuneError,
|
||||||
|
0x48: RuneError,
|
||||||
|
0x49: RuneError,
|
||||||
|
0x4a: RuneError,
|
||||||
|
0x4b: '.',
|
||||||
|
0x4c: '<',
|
||||||
|
0x4d: '(',
|
||||||
|
0x4e: '+',
|
||||||
|
0x4f: '|',
|
||||||
|
0x50: '&',
|
||||||
|
0x51: RuneError,
|
||||||
|
0x52: RuneError,
|
||||||
|
0x53: RuneError,
|
||||||
|
0x54: RuneError,
|
||||||
|
0x55: RuneError,
|
||||||
|
0x56: RuneError,
|
||||||
|
0x57: RuneError,
|
||||||
|
0x58: RuneError,
|
||||||
|
0x59: RuneError,
|
||||||
|
0x5a: '!',
|
||||||
|
0x5b: '$',
|
||||||
|
0x5c: '*',
|
||||||
|
0x5d: ')',
|
||||||
|
0x5e: ';',
|
||||||
|
0x5f: '¬',
|
||||||
|
0x60: '-',
|
||||||
|
0x61: '/',
|
||||||
|
0x62: RuneError,
|
||||||
|
0x63: RuneError,
|
||||||
|
0x64: RuneError,
|
||||||
|
0x65: RuneError,
|
||||||
|
0x66: RuneError,
|
||||||
|
0x67: RuneError,
|
||||||
|
0x68: RuneError,
|
||||||
|
0x69: RuneError,
|
||||||
|
0x6a: '¦',
|
||||||
|
0x6b: ',',
|
||||||
|
0x6c: '%',
|
||||||
|
0x6d: '_',
|
||||||
|
0x6e: '>',
|
||||||
|
0x6f: '?',
|
||||||
|
0x70: RuneError,
|
||||||
|
0x71: RuneError,
|
||||||
|
0x72: RuneError,
|
||||||
|
0x73: RuneError,
|
||||||
|
0x74: RuneError,
|
||||||
|
0x75: RuneError,
|
||||||
|
0x76: RuneError,
|
||||||
|
0x77: RuneError,
|
||||||
|
0x78: RuneError,
|
||||||
|
0x79: '`',
|
||||||
|
0x7a: ':',
|
||||||
|
0x7b: '#',
|
||||||
|
0x7c: '@',
|
||||||
|
0x7d: '\'',
|
||||||
|
0x7e: '=',
|
||||||
|
0x7f: '"',
|
||||||
|
0x80: RuneError,
|
||||||
|
0x81: 'a',
|
||||||
|
0x82: 'b',
|
||||||
|
0x83: 'c',
|
||||||
|
0x84: 'd',
|
||||||
|
0x85: 'e',
|
||||||
|
0x86: 'f',
|
||||||
|
0x87: 'g',
|
||||||
|
0x88: 'h',
|
||||||
|
0x89: 'i',
|
||||||
|
0x8a: RuneError,
|
||||||
|
0x8b: RuneError,
|
||||||
|
0x8c: RuneError,
|
||||||
|
0x8d: RuneError,
|
||||||
|
0x8e: RuneError,
|
||||||
|
0x8f: '±',
|
||||||
|
0x90: RuneError,
|
||||||
|
0x91: 'j',
|
||||||
|
0x92: 'k',
|
||||||
|
0x93: 'l',
|
||||||
|
0x94: 'm',
|
||||||
|
0x95: 'n',
|
||||||
|
0x96: 'o',
|
||||||
|
0x97: 'p',
|
||||||
|
0x98: 'q',
|
||||||
|
0x99: 'r',
|
||||||
|
0x9a: RuneError,
|
||||||
|
0x9b: RuneError,
|
||||||
|
0x9c: RuneError,
|
||||||
|
0x9d: RuneError,
|
||||||
|
0x9e: RuneError,
|
||||||
|
0x9f: RuneError,
|
||||||
|
0xa0: RuneError,
|
||||||
|
0xa1: '~',
|
||||||
|
0xa2: 's',
|
||||||
|
0xa3: 't',
|
||||||
|
0xa4: 'u',
|
||||||
|
0xa5: 'v',
|
||||||
|
0xa6: 'w',
|
||||||
|
0xa7: 'x',
|
||||||
|
0xa8: 'y',
|
||||||
|
0xa9: 'z',
|
||||||
|
0xaa: RuneError,
|
||||||
|
0xab: RuneError,
|
||||||
|
0xac: RuneError,
|
||||||
|
0xad: RuneError,
|
||||||
|
0xae: RuneError,
|
||||||
|
0xaf: RuneError,
|
||||||
|
0xb0: '^',
|
||||||
|
0xb1: RuneError,
|
||||||
|
0xb2: RuneError,
|
||||||
|
0xb3: RuneError,
|
||||||
|
0xb4: RuneError,
|
||||||
|
0xb5: RuneError,
|
||||||
|
0xb6: RuneError,
|
||||||
|
0xb7: RuneError,
|
||||||
|
0xb8: RuneError,
|
||||||
|
0xb9: RuneError,
|
||||||
|
0xba: '[',
|
||||||
|
0xbb: ']',
|
||||||
|
0xbc: RuneError,
|
||||||
|
0xbd: RuneError,
|
||||||
|
0xbe: RuneError,
|
||||||
|
0xbf: RuneError,
|
||||||
|
0xc0: '{',
|
||||||
|
0xc1: 'A',
|
||||||
|
0xc2: 'B',
|
||||||
|
0xc3: 'C',
|
||||||
|
0xc4: 'D',
|
||||||
|
0xc5: 'E',
|
||||||
|
0xc6: 'F',
|
||||||
|
0xc7: 'G',
|
||||||
|
0xc8: 'H',
|
||||||
|
0xc9: 'I',
|
||||||
|
0xca: '\xad', // NB: soft hyphen
|
||||||
|
0xcb: RuneError,
|
||||||
|
0xcc: RuneError,
|
||||||
|
0xcd: RuneError,
|
||||||
|
0xce: RuneError,
|
||||||
|
0xcf: RuneError,
|
||||||
|
0xd0: '}',
|
||||||
|
0xd1: 'J',
|
||||||
|
0xd2: 'K',
|
||||||
|
0xd3: 'L',
|
||||||
|
0xd4: 'M',
|
||||||
|
0xd5: 'N',
|
||||||
|
0xd6: 'O',
|
||||||
|
0xd7: 'P',
|
||||||
|
0xd8: 'Q',
|
||||||
|
0xd9: 'R',
|
||||||
|
0xda: RuneError,
|
||||||
|
0xdb: RuneError,
|
||||||
|
0xdc: RuneError,
|
||||||
|
0xdd: RuneError,
|
||||||
|
0xde: RuneError,
|
||||||
|
0xdf: RuneError,
|
||||||
|
0xe0: '\\',
|
||||||
|
0xe1: '\u2007', // Non-breaking space
|
||||||
|
0xe2: 'S',
|
||||||
|
0xe3: 'T',
|
||||||
|
0xe4: 'U',
|
||||||
|
0xe5: 'V',
|
||||||
|
0xe6: 'W',
|
||||||
|
0xe7: 'X',
|
||||||
|
0xe8: 'Y',
|
||||||
|
0xe9: 'Z',
|
||||||
|
0xea: RuneError,
|
||||||
|
0xeb: RuneError,
|
||||||
|
0xec: RuneError,
|
||||||
|
0xed: RuneError,
|
||||||
|
0xee: RuneError,
|
||||||
|
0xef: RuneError,
|
||||||
|
0xf0: '0',
|
||||||
|
0xf1: '1',
|
||||||
|
0xf2: '2',
|
||||||
|
0xf3: '3',
|
||||||
|
0xf4: '4',
|
||||||
|
0xf5: '5',
|
||||||
|
0xf6: '6',
|
||||||
|
0xf7: '7',
|
||||||
|
0xf8: '8',
|
||||||
|
0xf9: '9',
|
||||||
|
0xfa: RuneError,
|
||||||
|
0xfb: RuneError,
|
||||||
|
0xfc: RuneError,
|
||||||
|
0xfd: RuneError,
|
||||||
|
0xfe: RuneError,
|
||||||
|
0xff: RuneError,
|
||||||
|
}}
|
||||||
|
cm.Init()
|
||||||
|
EBCDIC = cm
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2015 Garrett D'Amore
|
||||||
|
//
|
||||||
|
// 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 encoding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ISO8859_1 represents the 8-bit ISO8859-1 scheme. It decodes directly to
|
||||||
|
// UTF-8 without change, as all ISO8859-1 values are legal UTF-8.
|
||||||
|
// Unicode values less than 256 (i.e. 8 bits) map 1:1 with 8859-1.
|
||||||
|
// It encodes runes outside of that to 0x1A, the ASCII substitution character.
|
||||||
|
var ISO8859_1 encoding.Encoding
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cm := &Charmap{}
|
||||||
|
cm.Init()
|
||||||
|
|
||||||
|
// 8859-1 is the 8-bit identity map for Unicode.
|
||||||
|
ISO8859_1 = cm
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2015 Garrett D'Amore
|
||||||
|
//
|
||||||
|
// 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 encoding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
)
|
||||||
|
|
||||||
|
type validUtf8 struct{}
|
||||||
|
|
||||||
|
// UTF8 is an encoding for UTF-8. All it does is verify that the UTF-8
|
||||||
|
// in is valid. The main reason for its existence is that it will detect
|
||||||
|
// and report ErrSrcShort or ErrDstShort, whereas the Nop encoding just
|
||||||
|
// passes every byte, blithely.
|
||||||
|
var UTF8 encoding.Encoding = validUtf8{}
|
||||||
|
|
||||||
|
func (validUtf8) NewDecoder() *encoding.Decoder {
|
||||||
|
return &encoding.Decoder{Transformer: encoding.UTF8Validator}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (validUtf8) NewEncoder() *encoding.Encoder {
|
||||||
|
return &encoding.Encoder{Transformer: encoding.UTF8Validator}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
version: 1.0.{build}
|
||||||
|
clone_folder: c:\gopath\src\github.com\gdamore\tcell
|
||||||
|
environment:
|
||||||
|
GOPATH: c:\gopath
|
||||||
|
build_script:
|
||||||
|
- go version
|
||||||
|
- go env
|
||||||
|
- SET PATH=%LOCALAPPDATA%\atom\bin;%GOPATH%\bin;%PATH%
|
||||||
|
- go get -t ./...
|
||||||
|
- go build
|
||||||
|
- go install ./...
|
||||||
|
test_script:
|
||||||
|
- go test ./...
|
@ -0,0 +1 @@
|
|||||||
|
coverage.txt
|
@ -0,0 +1,18 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.15.x
|
||||||
|
- master
|
||||||
|
|
||||||
|
arch:
|
||||||
|
- amd64
|
||||||
|
- ppc64le
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- go get -t -v ./...
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -race -coverprofile=coverage.txt -covermode=atomic
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
@ -0,0 +1,4 @@
|
|||||||
|
Garrett D'Amore <garrett@damore.org>
|
||||||
|
Zachary Yedidia <zyedidia@gmail.com>
|
||||||
|
Junegunn Choi <junegunn.c@gmail.com>
|
||||||
|
Staysail Systems, Inc. <info@staysail.tech>
|
@ -0,0 +1,82 @@
|
|||||||
|
## Breaking Changes in _Tcell_ v2
|
||||||
|
|
||||||
|
A number of changes were made to _Tcell_ for version two, and some of these are breaking.
|
||||||
|
|
||||||
|
### Import Path
|
||||||
|
|
||||||
|
The import path for tcell has changed to `github.com/gdamore/tcell/v2` to reflect a new major version.
|
||||||
|
|
||||||
|
### Style Is Not Numeric
|
||||||
|
|
||||||
|
The type `Style` has changed to a structure, to allow us to add additional data such as flags for color setting,
|
||||||
|
more attribute bits, and so forth.
|
||||||
|
Applications that relied on this being a number will need to be updated to use the accessor methods.
|
||||||
|
|
||||||
|
### Mouse Event Changes
|
||||||
|
|
||||||
|
The middle mouse button was reported as button 2 on Linux, but as button 3 on Windows,
|
||||||
|
and the right mouse button was reported the reverse way.
|
||||||
|
_Tcell_ now always reports the right mouse button as button 2, and the middle button as button 3.
|
||||||
|
To help make this clearer, new symbols `ButtonPrimary`, `ButtonSecondary`, and
|
||||||
|
`ButtonMiddle` are provided.
|
||||||
|
(Note that which button is right vs. left may be impacted by user preferences.
|
||||||
|
Usually the left button will be considered the Primary, and the right will be the Secondary.)
|
||||||
|
Applications may need to adjust their handling of mouse buttons 2 and 3 accordingly.
|
||||||
|
|
||||||
|
### Terminals Removed
|
||||||
|
|
||||||
|
A number of terminals have been removed.
|
||||||
|
These are mostly ancient definitions unlikely to be used by anyone, such as `adm3a`.
|
||||||
|
|
||||||
|
### High Number Function Keys
|
||||||
|
|
||||||
|
Historically terminfo reported function keys with modifiers set as a different
|
||||||
|
function key altogether. For example, Shift-F1 was reported as F13 on XTerm.
|
||||||
|
_Tcell_ now prefers to report these using the base key (such as F1) with modifiers added.
|
||||||
|
This works on XTerm and VTE based emulators, but some emulators may not support this.
|
||||||
|
The new behavior more closely aligns with behavior on Windows platforms.
|
||||||
|
|
||||||
|
## New Features in _Tcell_ v2
|
||||||
|
|
||||||
|
These features are not breaking, but are introduced in version 2.
|
||||||
|
|
||||||
|
### Improved Modifier Support
|
||||||
|
|
||||||
|
For terminals that appear to behave like the venerable XTerm, _tcell_
|
||||||
|
automatically adds modifier reporting for ALT, CTRL, SHIFT, and META keys
|
||||||
|
when the terminal reports them.
|
||||||
|
|
||||||
|
### Better Support for Palettes (Themes)
|
||||||
|
|
||||||
|
When using a color by its name or palette entry, _Tcell_ now tries to
|
||||||
|
use that palette entry as is; this should avoid some inconsistency and respect
|
||||||
|
terminal themes correctly.
|
||||||
|
|
||||||
|
When true fidelity to RGB values is needed, the new `TrueColor()` API can be used
|
||||||
|
to create a direct color, which bypasses the palette altogether.
|
||||||
|
|
||||||
|
### Automatic TrueColor Detection
|
||||||
|
|
||||||
|
For some terminals, if the `Tc` or `RGB` properties are present in terminfo,
|
||||||
|
_Tcell_ will automatically assume the terminal supports 24-bit color.
|
||||||
|
|
||||||
|
### ColorReset
|
||||||
|
|
||||||
|
A new color value, `ColorReset` can be used on the foreground or background
|
||||||
|
to reset the color the default used by the terminal.
|
||||||
|
|
||||||
|
### tmux Support
|
||||||
|
|
||||||
|
_Tcell_ now has improved support for tmux, when the `$TERM` variable is set to "tmux".
|
||||||
|
|
||||||
|
### Strikethrough Support
|
||||||
|
|
||||||
|
_Tcell_ has support for strikethrough when the terminal supports it, using the new `StrikeThrough()` API.
|
||||||
|
|
||||||
|
### Bracketed Paste Support
|
||||||
|
|
||||||
|
_Tcell_ provides the long requested capability to discriminate paste event by using the
|
||||||
|
bracketed-paste capability present in some terminals. This is automatically available on
|
||||||
|
terminals that support XTerm style mouse handling, but applications must opt-in to this
|
||||||
|
by using the new `EnablePaste()` function. A new `EventPaste` type of event will be
|
||||||
|
delivered when starting and finishing a paste operation.
|
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
@ -0,0 +1,272 @@
|
|||||||
|
|
||||||
|
# ![Tcell](logos/tcell.png)
|
||||||
|
|
||||||
|
_Tcell_ is a _Go_ package that provides a cell based view for text terminals, like _XTerm_.
|
||||||
|
It was inspired by _termbox_, but includes many additional improvements.
|
||||||
|
|
||||||
|
[![Linux Status](https://img.shields.io/travis/gdamore/tcell.svg?label=linux)](https://travis-ci.org/gdamore/tcell)
|
||||||
|
[![Windows Status](https://img.shields.io/appveyor/ci/gdamore/tcell.svg?label=windows)](https://ci.appveyor.com/project/gdamore/tcell)
|
||||||
|
[![Apache License](https://img.shields.io/badge/license-APACHE2-blue.svg)](https://github.com/gdamore/tcell/blob/master/LICENSE)
|
||||||
|
[![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/gdamore/tcell/v2)
|
||||||
|
[![Report Card](https://goreportcard.com/badge/gdamore/tcell)](http://goreportcard.com/report/gdamore/tcell/v2)
|
||||||
|
[![Discord](https://img.shields.io/discord/639503822733180969?label=discord)](https://discord.gg/urTTxDN)
|
||||||
|
[![Coverage](https://codecov.io/gh/gdamore/tcell/branch/master/graph/badge.svg)](https://codecov.io/gh/gdamore/tcell)
|
||||||
|
|
||||||
|
|
||||||
|
NOTE: This is version 2 of _Tcell_. There are breaking changes relative to version 1.
|
||||||
|
Version 1.x remains available using the import `github.com/gdamore/tcell`.
|
||||||
|
|
||||||
|
## Tutorial
|
||||||
|
|
||||||
|
A brief, and still somewhat rough, [tutorial](TUTORIAL.md) is available.
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
* [proxima5](https://github.com/gdamore/proxima5) - space shooter ([video](https://youtu.be/jNxKTCmY_bQ))
|
||||||
|
* [govisor](https://github.com/gdamore/govisor) - service management UI ([screenshot](http://2.bp.blogspot.com/--OsvnfzSNow/Vf7aqMw3zXI/AAAAAAAAARo/uOMtOvw4Sbg/s1600/Screen%2BShot%2B2015-09-20%2Bat%2B9.08.41%2BAM.png))
|
||||||
|
* mouse demo - included mouse test ([screenshot](http://2.bp.blogspot.com/-fWvW5opT0es/VhIdItdKqJI/AAAAAAAAATE/7Ojc0L1SpB0/s1600/Screen%2BShot%2B2015-10-04%2Bat%2B11.47.13%2BPM.png))
|
||||||
|
* [gomatrix](https://github.com/gdamore/gomatrix) - converted from Termbox
|
||||||
|
* [micro](https://github.com/zyedidia/micro/) - lightweight text editor with syntax-highlighting and themes
|
||||||
|
* [godu](https://github.com/viktomas/godu) - utility to discover large files/folders
|
||||||
|
* [tview](https://github.com/rivo/tview/) - rich interactive widgets
|
||||||
|
* [cview](https://code.rocketnine.space/tslocum/cview) - user interface toolkit (fork of _tview_)
|
||||||
|
* [awsome gocui](https://github.com/awesome-gocui/gocui) - Go Console User Interface
|
||||||
|
* [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
|
||||||
|
* [WTF](https://github.com/senorprogrammer/wtf) - personal information dashboard
|
||||||
|
* [browsh](https://github.com/browsh-org/browsh) - modern web browser ([video](https://www.youtube.com/watch?v=HZq86XfBoRo))
|
||||||
|
* [go-life](https://github.com/sachaos/go-life) - Conway's Game of Life
|
||||||
|
* [gowid](https://github.com/gcla/gowid) - compositional widgets for terminal UIs, inspired by _urwid_
|
||||||
|
* [termshark](https://termshark.io) - interface for _tshark_, inspired by Wireshark, built on _gowid_
|
||||||
|
* [go-tetris](https://github.com/MichaelS11/go-tetris) - Go Tetris with AI option
|
||||||
|
* [fzf](https://github.com/junegunn/fzf) - command-line fuzzy finder
|
||||||
|
* [ascii-fluid](https://github.com/esimov/ascii-fluid) - fluid simulation controlled by webcam
|
||||||
|
* [cbind](https://code.rocketnine.space/tslocum/cbind) - key event encoding, decoding and handling
|
||||||
|
* [tpong](https://github.com/spinzed/tpong) - old-school Pong
|
||||||
|
* [aerc](https://git.sr.ht/~sircmpwn/aerc) - email client
|
||||||
|
* [tblogs](https://github.com/ezeoleaf/tblogs) - development blogs reader
|
||||||
|
* [spinc](https://github.com/lallassu/spinc) - _irssi_ inspired chat application for Cisco Spark/WebEx
|
||||||
|
* [gorss](https://github.com/lallassu/gorss) - RSS/Atom feed reader
|
||||||
|
* [memoryalike](https://github.com/Bios-Marcel/memoryalike) - memorization game
|
||||||
|
* [lf](https://github.com/gokcehan/lf) - file manager
|
||||||
|
* [gokeybr](https://github.com/bunyk/gokeybr) - deliberately practice your typing
|
||||||
|
* [gonano](https://github.com/jbaramidze/gonano) - editor, mimics _nano_
|
||||||
|
* [uchess](https://github.com/tmountain/uchess) - UCI chess client
|
||||||
|
* [min](https://github.com/a-h/min) - Gemini browser
|
||||||
|
* [ov](https://github.com/noborus/ov) - file pager
|
||||||
|
* [tmux-wormhole](https://github.com/gcla/tmux-wormhole) - _tmux_ plugin to transfer files
|
||||||
|
* [gruid-tcell](https://github.com/anaseto/gruid-tcell) - driver for the grid based UI and game framework
|
||||||
|
* [aretext](https://github.com/aretext/aretext) - minimalist text editor with _vim_ key bindings
|
||||||
|
|
||||||
|
## Pure Go Terminfo Database
|
||||||
|
|
||||||
|
_Tcell_ includes a full parser and expander for terminfo capability strings,
|
||||||
|
so that it can avoid hard coding escape strings for formatting. It also favors
|
||||||
|
portability, and includes support for all POSIX systems.
|
||||||
|
|
||||||
|
The database is also flexible & extensible, and can be modified by either running
|
||||||
|
a program to build the entire database, or an entry for just a single terminal.
|
||||||
|
|
||||||
|
## More Portable
|
||||||
|
|
||||||
|
_Tcell_ is portable to a wide variety of systems, and is pure Go, without
|
||||||
|
any need for CGO.
|
||||||
|
_Tcell_ is believed to work with mainstream systems officially supported by golang.
|
||||||
|
|
||||||
|
## No Async IO
|
||||||
|
|
||||||
|
_Tcell_ is able to operate without requiring `SIGIO` signals (unlike _termbox_),
|
||||||
|
or asynchronous I/O, and can instead use standard Go file 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.
|
||||||
|
|
||||||
|
## Rich Unicode & non-Unicode support
|
||||||
|
|
||||||
|
_Tcell_ includes enhanced support for Unicode, including wide characters and
|
||||||
|
combining characters, provided your terminal can support them.
|
||||||
|
Note that
|
||||||
|
Windows terminals generally don't support the full Unicode repertoire.
|
||||||
|
|
||||||
|
It will also convert to and from Unicode locales, so that the program
|
||||||
|
can work with UTF-8 internally, and get reasonable output in other locales.
|
||||||
|
_Tcell_ tries hard to convert to native characters on both input and output.
|
||||||
|
On output _Tcell_ even makes use of the alternate character set to facilitate
|
||||||
|
drawing certain characters.
|
||||||
|
|
||||||
|
## More Function Keys
|
||||||
|
|
||||||
|
_Tcell_ also has richer support for a larger number of special keys that some
|
||||||
|
terminals can send.
|
||||||
|
|
||||||
|
## Better Color Handling
|
||||||
|
|
||||||
|
_Tcell_ will respect your terminal's color space as specified within your terminfo entries.
|
||||||
|
For example attempts to emit color sequences on VT100 terminals
|
||||||
|
won't result in unintended consequences.
|
||||||
|
|
||||||
|
In legacy Windows mode, _Tcell_ supports 16 colors, bold, dim, and reverse,
|
||||||
|
instead of just termbox's 8 colors with reverse. (Note that there is some
|
||||||
|
conflation with bold/dim and colors.)
|
||||||
|
Modern Windows 10 can benefit from much richer colors however.
|
||||||
|
|
||||||
|
_Tcell_ maps 16 colors down to 8, for terminals that need it.
|
||||||
|
(The upper 8 colors are just brighter versions of the lower 8.)
|
||||||
|
|
||||||
|
## Better Mouse Support
|
||||||
|
|
||||||
|
_Tcell_ supports enhanced mouse tracking mode, so your application can receive
|
||||||
|
regular mouse motion events, and wheel events, if your terminal supports it.
|
||||||
|
|
||||||
|
(Note: The Windows 10 Terminal application suffers from a flaw in this regard,
|
||||||
|
and does not support mouse interaction. The stock Windows 10 console host
|
||||||
|
fired up with cmd.exe or PowerShell works fine however.)
|
||||||
|
|
||||||
|
## _Termbox_ Compatibility
|
||||||
|
|
||||||
|
A compatibility layer for _termbox_ is provided in the `compat` directory.
|
||||||
|
To use it, try importing `github.com/gdamore/tcell/termbox` instead.
|
||||||
|
Most _termbox-go_ programs will probably work without further modification.
|
||||||
|
|
||||||
|
## Working With Unicode
|
||||||
|
|
||||||
|
Internally _Tcell_ uses UTF-8, just like Go.
|
||||||
|
However, _Tcell_ understands how to
|
||||||
|
convert to and from other character sets, using the capabilities of
|
||||||
|
the `golang.org/x/text/encoding packages`.
|
||||||
|
Your application must supply
|
||||||
|
them, as the full set of the most common ones bloats the program by about 2 MB.
|
||||||
|
If you're lazy, and want them all anyway, see the `encoding` sub-directory.
|
||||||
|
|
||||||
|
## Wide & Combining Characters
|
||||||
|
|
||||||
|
The `SetContent()` API takes a primary rune, and an optional list of combining runes.
|
||||||
|
If any of the runes is a wide (East Asian) rune occupying two cells,
|
||||||
|
then the library will skip output from the following cell. Care must be
|
||||||
|
taken in the application to avoid explicitly attempting to set content in the
|
||||||
|
next cell, otherwise the results are undefined. (Normally the wide character
|
||||||
|
is displayed, and the other character is not; do not depend on that behavior.)
|
||||||
|
|
||||||
|
Older terminal applications (especially on systems like Windows 8) lack support
|
||||||
|
for advanced Unicode, and thus may not fare well.
|
||||||
|
|
||||||
|
## Colors
|
||||||
|
|
||||||
|
_Tcell_ assumes the ANSI/XTerm color model, including the 256 color map that
|
||||||
|
XTerm uses when it supports 256 colors. The terminfo guidance will be
|
||||||
|
honored, with respect to the number of colors supported. Also, only
|
||||||
|
terminals which expose ANSI style `setaf` and `setab` will support color;
|
||||||
|
if you have a color terminal that only has `setf` and `setb`, please submit
|
||||||
|
a ticket.
|
||||||
|
|
||||||
|
## 24-bit Color
|
||||||
|
|
||||||
|
_Tcell_ _supports 24-bit color!_ (That is, if your terminal can support it.)
|
||||||
|
|
||||||
|
NOTE: Technically the approach of using 24-bit RGB values for color is more
|
||||||
|
accurately described as "direct color", but most people use the term "true color".
|
||||||
|
We follow the (inaccurate) common convention.
|
||||||
|
|
||||||
|
There are a few ways you can enable (or disable) true color.
|
||||||
|
|
||||||
|
* For many terminals, we can detect it automatically if your terminal
|
||||||
|
includes the `RGB` or `Tc` capabilities (or rather it did when the database
|
||||||
|
was updated.)
|
||||||
|
|
||||||
|
* You can force this one by setting the `COLORTERM` environment variable to
|
||||||
|
`24-bit`, `truecolor` or `24bit`. This is the same method used
|
||||||
|
by most other terminal applications that support 24-bit color.
|
||||||
|
|
||||||
|
* If you set your `TERM` environment variable to a value with the suffix `-truecolor`
|
||||||
|
then 24-bit color compatible with XTerm and ECMA-48 will be assumed.
|
||||||
|
(This feature is deprecated.
|
||||||
|
It is recommended to use one of other methods listed above.)
|
||||||
|
|
||||||
|
* You can disable 24-bit color by setting `TCELL_TRUECOLOR=disable` in your
|
||||||
|
environment.
|
||||||
|
|
||||||
|
When using TrueColor, programs will display the colors that the programmer
|
||||||
|
intended, overriding any "`themes`" you may have set in your terminal
|
||||||
|
emulator. (For some cases, accurate color fidelity is more important
|
||||||
|
than respecting themes. For other cases, such as typical text apps that
|
||||||
|
only use a few colors, its more desirable to respect the themes that
|
||||||
|
the user has established.)
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Reasonable attempts have been made to minimize sending data to terminals,
|
||||||
|
avoiding repeated sequences or drawing the same cell on refresh updates.
|
||||||
|
|
||||||
|
## Terminfo
|
||||||
|
|
||||||
|
(Not relevant for Windows users.)
|
||||||
|
|
||||||
|
The Terminfo implementation operates with a built-in database.
|
||||||
|
This should satisfy most users. However, it can also (on systems
|
||||||
|
with ncurses installed), dynamically parse the output from `infocmp`
|
||||||
|
for terminals it does not already know about.
|
||||||
|
|
||||||
|
See the `terminfo/` directory for more information about generating
|
||||||
|
new entries for the built-in database.
|
||||||
|
|
||||||
|
_Tcell_ requires that the terminal support the `cup` mode of cursor addressing.
|
||||||
|
Ancient terminals without the ability to position the cursor directly
|
||||||
|
are not supported.
|
||||||
|
This is unlikely to be a problem; such terminals have not been mass-produced
|
||||||
|
since the early 1970s.
|
||||||
|
|
||||||
|
## Mouse Support
|
||||||
|
|
||||||
|
Mouse support is detected via the `kmous` terminfo variable, however,
|
||||||
|
enablement/disablement and decoding mouse events is done using hard coded
|
||||||
|
sequences based on the XTerm X11 model. All popular
|
||||||
|
terminals with mouse tracking support this model. (Full terminfo support
|
||||||
|
is not possible as terminfo sequences are not defined.)
|
||||||
|
|
||||||
|
On Windows, the mouse works normally.
|
||||||
|
|
||||||
|
Mouse wheel buttons on various terminals are known to work, but the support
|
||||||
|
in terminal emulators, as well as support for various buttons and
|
||||||
|
live mouse tracking, varies widely.
|
||||||
|
Modern _xterm_, macOS _Terminal_, and _iTerm_ all work well.
|
||||||
|
|
||||||
|
## Bracketed Paste
|
||||||
|
|
||||||
|
Terminals that appear to support the XTerm mouse model also can support
|
||||||
|
bracketed paste, for applications that opt-in. See `EnablePaste()` for details.
|
||||||
|
|
||||||
|
## Testability
|
||||||
|
|
||||||
|
There is a `SimulationScreen`, that can be used to simulate a real screen
|
||||||
|
for automated testing. The supplied tests do this. The simulation contains
|
||||||
|
event delivery, screen resizing support, and capabilities to inject events
|
||||||
|
and examine "`physical`" screen contents.
|
||||||
|
|
||||||
|
## Platforms
|
||||||
|
|
||||||
|
### POSIX (Linux, FreeBSD, macOS, Solaris, etc.)
|
||||||
|
|
||||||
|
Everything works using pure Go on mainstream platforms. Some more esoteric
|
||||||
|
platforms (e.g., AIX) may need to be added. Pull requests are welcome!
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
Windows console mode applications are supported.
|
||||||
|
|
||||||
|
Modern console applications like ConEmu and the Windows 10 terminal,
|
||||||
|
support all the good features (resize, mouse tracking, etc.)
|
||||||
|
|
||||||
|
### Plan9, WASM, and others
|
||||||
|
|
||||||
|
These platforms won't work, but compilation stubs are supplied
|
||||||
|
for folks that want to include parts of this in software for those
|
||||||
|
platforms. The Simulation screen works, but as _Tcell_ doesn't know how to
|
||||||
|
allocate a real screen object on those platforms, `NewScreen()` will fail.
|
||||||
|
|
||||||
|
If anyone has wisdom about how to improve support for these,
|
||||||
|
please let me know. PRs are especially welcome.
|
||||||
|
|
||||||
|
### Commercial Support
|
||||||
|
|
||||||
|
_Tcell_ is absolutely free, but if you want to obtain commercial, professional support, there are options.
|
||||||
|
|
||||||
|
* [TideLift](https://tidelift.com/) subscriptions include support for _Tcell_, as well as many other open source packages.
|
||||||
|
* [Staysail Systems Inc.](mailto:info@staysail.tech) offers direct support, and custom development around _Tcell_ on an hourly basis.
|
@ -0,0 +1,293 @@
|
|||||||
|
# _Tcell_ Tutorial
|
||||||
|
|
||||||
|
_Tcell_ provides a low-level, portable API for building terminal-based programs.
|
||||||
|
A [terminal emulator](https://en.wikipedia.org/wiki/Terminal_emulator)
|
||||||
|
(or a real terminal such as a DEC VT-220) is used to interact with such a program.
|
||||||
|
|
||||||
|
_Tcell_'s interface is fairly low-level.
|
||||||
|
While it provides a reasonably portable way of dealing with all the usual terminal
|
||||||
|
features, it may be easier to utilize a higher level framework.
|
||||||
|
A number of such frameworks are listed on the _Tcell_ main [README](README.md).
|
||||||
|
|
||||||
|
This tutorial provides the details of _Tcell_, and is appropriate for developers
|
||||||
|
wishing to create their own application frameworks or needing more direct access
|
||||||
|
to the terminal capabilities.
|
||||||
|
|
||||||
|
## Resize events
|
||||||
|
|
||||||
|
Applications receive an event of type `EventResize` when they are first initialized and each time the terminal is resized.
|
||||||
|
The new size is available as `Size`.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
switch ev := ev.(type) {
|
||||||
|
case *tcell.EventResize:
|
||||||
|
w, h := ev.Size()
|
||||||
|
logMessage(fmt.Sprintf("Resized to %dx%d", w, h))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key events
|
||||||
|
|
||||||
|
When a key is pressed, applications receive an event of type `EventKey`.
|
||||||
|
This event describes the modifier keys pressed (if any) and the pressed key or rune.
|
||||||
|
|
||||||
|
When a rune key is pressed, an event with its `Key` set to `KeyRune` is dispatched.
|
||||||
|
|
||||||
|
When a non-rune key is pressed, it is available as the `Key` of the event.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
switch ev := ev.(type) {
|
||||||
|
case *tcell.EventKey:
|
||||||
|
mod, key, ch := ev.Mod(), ev.Key(), ev.Rune()
|
||||||
|
logMessage(fmt.Sprintf("EventKey Modifiers: %d Key: %d Rune: %d", mod, key, ch))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key event restrictions
|
||||||
|
|
||||||
|
Terminal-based programs have less visibility into keyboard activity than graphical applications.
|
||||||
|
|
||||||
|
When a key is pressed and held, additional key press events are sent by the terminal emulator.
|
||||||
|
The rate of these repeated events depends on the emulator's configuration.
|
||||||
|
Key release events are not available.
|
||||||
|
|
||||||
|
It is not possible to distinguish runes typed while holding shift and runes typed using caps lock.
|
||||||
|
Capital letters are reported without the Shift modifier.
|
||||||
|
|
||||||
|
## Mouse events
|
||||||
|
|
||||||
|
Applications receive an event of type `EventMouse` when the mouse moves, or a mouse button is pressed or released.
|
||||||
|
Mouse events are only delivered if
|
||||||
|
`EnableMouse` has been called.
|
||||||
|
|
||||||
|
The mouse buttons being pressed (if any) are available as `Buttons`, and the position of the mouse is available as `Position`.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
switch ev := ev.(type) {
|
||||||
|
case *tcell.EventMouse:
|
||||||
|
mod := ev.Modifiers()
|
||||||
|
btns := ev.Buttons()
|
||||||
|
x, y := ev.Position()
|
||||||
|
logMessage(fmt.Sprintf("EventMouse Modifiers: %d Buttons: %d Position: %d,%d", mod, btns, x, y))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mouse buttons
|
||||||
|
|
||||||
|
Identifier | Alias | Description
|
||||||
|
-----------|-----------------|-----------
|
||||||
|
Button1 | ButtonPrimary | Left button
|
||||||
|
Button2 | ButtonSecondary | Right button
|
||||||
|
Button3 | ButtonMiddle | Middle button
|
||||||
|
Button4 | | Side button (thumb/next)
|
||||||
|
Button5 | | Side button (thumb/prev)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To create a tcell application, first initialize a screen to hold it.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
s, err := tcell.NewScreen()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%+v", err)
|
||||||
|
}
|
||||||
|
if err := s.Init(); err != nil {
|
||||||
|
log.Fatalf("%+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default text style
|
||||||
|
defStyle := tcell.StyleDefault.Background(tcell.ColorReset).Foreground(tcell.ColorReset)
|
||||||
|
s.SetStyle(defStyle)
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
s.Clear()
|
||||||
|
```
|
||||||
|
|
||||||
|
Text may be drawn on the screen using `SetContent`.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
s.SetContent(0, 0, 'H', nil, defStyle)
|
||||||
|
s.SetContent(1, 0, 'i', nil, defStyle)
|
||||||
|
s.SetContent(2, 0, '!', nil, defStyle)
|
||||||
|
```
|
||||||
|
|
||||||
|
To draw text more easily, define a render function.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
func drawText(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, text string) {
|
||||||
|
row := y1
|
||||||
|
col := x1
|
||||||
|
for _, r := range []rune(text) {
|
||||||
|
s.SetContent(col, row, r, nil, style)
|
||||||
|
col++
|
||||||
|
if col >= x2 {
|
||||||
|
row++
|
||||||
|
col = x1
|
||||||
|
}
|
||||||
|
if row > y2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Lastly, define an event loop to handle user input and update application state.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
quit := func() {
|
||||||
|
s.Fini()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
// Update screen
|
||||||
|
s.Show()
|
||||||
|
|
||||||
|
// Poll event
|
||||||
|
ev := s.PollEvent()
|
||||||
|
|
||||||
|
// Process event
|
||||||
|
switch ev := ev.(type) {
|
||||||
|
case *tcell.EventResize:
|
||||||
|
s.Sync()
|
||||||
|
case *tcell.EventKey:
|
||||||
|
if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC {
|
||||||
|
quit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Demo application
|
||||||
|
|
||||||
|
The following demonstrates how to initialize a screen, draw text/graphics and handle user input.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func drawText(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, text string) {
|
||||||
|
row := y1
|
||||||
|
col := x1
|
||||||
|
for _, r := range []rune(text) {
|
||||||
|
s.SetContent(col, row, r, nil, style)
|
||||||
|
col++
|
||||||
|
if col >= x2 {
|
||||||
|
row++
|
||||||
|
col = x1
|
||||||
|
}
|
||||||
|
if row > y2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawBox(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, text string) {
|
||||||
|
if y2 < y1 {
|
||||||
|
y1, y2 = y2, y1
|
||||||
|
}
|
||||||
|
if x2 < x1 {
|
||||||
|
x1, x2 = x2, x1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill background
|
||||||
|
for row := y1; row <= y2; row++ {
|
||||||
|
for col := x1; col <= x2; col++ {
|
||||||
|
s.SetContent(col, row, ' ', nil, style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw borders
|
||||||
|
for col := x1; col <= x2; col++ {
|
||||||
|
s.SetContent(col, y1, tcell.RuneHLine, nil, style)
|
||||||
|
s.SetContent(col, y2, tcell.RuneHLine, nil, style)
|
||||||
|
}
|
||||||
|
for row := y1 + 1; row < y2; row++ {
|
||||||
|
s.SetContent(x1, row, tcell.RuneVLine, nil, style)
|
||||||
|
s.SetContent(x2, row, tcell.RuneVLine, nil, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only draw corners if necessary
|
||||||
|
if y1 != y2 && x1 != x2 {
|
||||||
|
s.SetContent(x1, y1, tcell.RuneULCorner, nil, style)
|
||||||
|
s.SetContent(x2, y1, tcell.RuneURCorner, nil, style)
|
||||||
|
s.SetContent(x1, y2, tcell.RuneLLCorner, nil, style)
|
||||||
|
s.SetContent(x2, y2, tcell.RuneLRCorner, nil, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
drawText(s, x1+1, y1+1, x2-1, y2-1, style, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defStyle := tcell.StyleDefault.Background(tcell.ColorReset).Foreground(tcell.ColorReset)
|
||||||
|
boxStyle := tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorPurple)
|
||||||
|
|
||||||
|
// Initialize screen
|
||||||
|
s, err := tcell.NewScreen()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%+v", err)
|
||||||
|
}
|
||||||
|
if err := s.Init(); err != nil {
|
||||||
|
log.Fatalf("%+v", err)
|
||||||
|
}
|
||||||
|
s.SetStyle(defStyle)
|
||||||
|
s.EnableMouse()
|
||||||
|
s.EnablePaste()
|
||||||
|
s.Clear()
|
||||||
|
|
||||||
|
// Draw initial boxes
|
||||||
|
drawBox(s, 1, 1, 42, 7, boxStyle, "Click and drag to draw a box")
|
||||||
|
drawBox(s, 5, 9, 32, 14, boxStyle, "Press C to reset")
|
||||||
|
|
||||||
|
// Event loop
|
||||||
|
ox, oy := -1, -1
|
||||||
|
quit := func() {
|
||||||
|
s.Fini()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
// Update screen
|
||||||
|
s.Show()
|
||||||
|
|
||||||
|
// Poll event
|
||||||
|
ev := s.PollEvent()
|
||||||
|
|
||||||
|
// Process event
|
||||||
|
switch ev := ev.(type) {
|
||||||
|
case *tcell.EventResize:
|
||||||
|
s.Sync()
|
||||||
|
case *tcell.EventKey:
|
||||||
|
if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC {
|
||||||
|
quit()
|
||||||
|
} else if ev.Key() == tcell.KeyCtrlL {
|
||||||
|
s.Sync()
|
||||||
|
} else if ev.Rune() == 'C' || ev.Rune() == 'c' {
|
||||||
|
s.Clear()
|
||||||
|
}
|
||||||
|
case *tcell.EventMouse:
|
||||||
|
x, y := ev.Position()
|
||||||
|
button := ev.Buttons()
|
||||||
|
// Only process button events, not wheel events
|
||||||
|
button &= tcell.ButtonMask(0xff)
|
||||||
|
|
||||||
|
if button != tcell.ButtonNone && ox < 0 {
|
||||||
|
ox, oy = x, y
|
||||||
|
}
|
||||||
|
switch ev.Buttons() {
|
||||||
|
case tcell.ButtonNone:
|
||||||
|
if ox >= 0 {
|
||||||
|
label := fmt.Sprintf("%d,%d to %d,%d", ox, oy, x, y)
|
||||||
|
drawBox(s, ox, oy, x, y, boxStyle, label)
|
||||||
|
ox, oy = -1, -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2020 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
// AttrMask represents a mask of text attributes, apart from color.
|
||||||
|
// Note that support for attributes may vary widely across terminals.
|
||||||
|
type AttrMask int
|
||||||
|
|
||||||
|
// Attributes are not colors, but affect the display of text. They can
|
||||||
|
// be combined.
|
||||||
|
const (
|
||||||
|
AttrBold AttrMask = 1 << iota
|
||||||
|
AttrBlink
|
||||||
|
AttrReverse
|
||||||
|
AttrUnderline
|
||||||
|
AttrDim
|
||||||
|
AttrItalic
|
||||||
|
AttrStrikeThrough
|
||||||
|
AttrInvalid // Mark the style or attributes invalid
|
||||||
|
AttrNone AttrMask = 0 // Just normal text.
|
||||||
|
)
|
@ -0,0 +1,177 @@
|
|||||||
|
// Copyright 2019 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
import (
|
||||||
|
runewidth "github.com/mattn/go-runewidth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cell struct {
|
||||||
|
currMain rune
|
||||||
|
currComb []rune
|
||||||
|
currStyle Style
|
||||||
|
lastMain rune
|
||||||
|
lastStyle Style
|
||||||
|
lastComb []rune
|
||||||
|
width int
|
||||||
|
}
|
||||||
|
|
||||||
|
// CellBuffer represents a two dimensional array of character cells.
|
||||||
|
// This is primarily intended for use by Screen implementors; it
|
||||||
|
// contains much of the common code they need. To create one, just
|
||||||
|
// declare a variable of its type; no explicit initialization is necessary.
|
||||||
|
//
|
||||||
|
// CellBuffer is not thread safe.
|
||||||
|
type CellBuffer struct {
|
||||||
|
w int
|
||||||
|
h int
|
||||||
|
cells []cell
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContent sets the contents (primary rune, combining runes,
|
||||||
|
// and style) for a cell at a given location.
|
||||||
|
func (cb *CellBuffer) SetContent(x int, y int,
|
||||||
|
mainc rune, combc []rune, style Style) {
|
||||||
|
|
||||||
|
if x >= 0 && y >= 0 && x < cb.w && y < cb.h {
|
||||||
|
c := &cb.cells[(y*cb.w)+x]
|
||||||
|
|
||||||
|
c.currComb = append([]rune{}, combc...)
|
||||||
|
|
||||||
|
if c.currMain != mainc {
|
||||||
|
c.width = runewidth.RuneWidth(mainc)
|
||||||
|
}
|
||||||
|
c.currMain = mainc
|
||||||
|
c.currStyle = style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContent returns the contents of a character cell, including the
|
||||||
|
// primary rune, any combining character runes (which will usually be
|
||||||
|
// nil), the style, and the display width in cells. (The width can be
|
||||||
|
// either 1, normally, or 2 for East Asian full-width characters.)
|
||||||
|
func (cb *CellBuffer) GetContent(x, y int) (rune, []rune, Style, int) {
|
||||||
|
var mainc rune
|
||||||
|
var combc []rune
|
||||||
|
var style Style
|
||||||
|
var width int
|
||||||
|
if x >= 0 && y >= 0 && x < cb.w && y < cb.h {
|
||||||
|
c := &cb.cells[(y*cb.w)+x]
|
||||||
|
mainc, combc, style = c.currMain, c.currComb, c.currStyle
|
||||||
|
if width = c.width; width == 0 || mainc < ' ' {
|
||||||
|
width = 1
|
||||||
|
mainc = ' '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mainc, combc, style, width
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the (width, height) in cells of the buffer.
|
||||||
|
func (cb *CellBuffer) Size() (int, int) {
|
||||||
|
return cb.w, cb.h
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate marks all characters within the buffer as dirty.
|
||||||
|
func (cb *CellBuffer) Invalidate() {
|
||||||
|
for i := range cb.cells {
|
||||||
|
cb.cells[i].lastMain = rune(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dirty checks if a character at the given location needs an
|
||||||
|
// to be refreshed on the physical display. This returns true
|
||||||
|
// if the cell content is different since the last time it was
|
||||||
|
// marked clean.
|
||||||
|
func (cb *CellBuffer) Dirty(x, y int) bool {
|
||||||
|
if x >= 0 && y >= 0 && x < cb.w && y < cb.h {
|
||||||
|
c := &cb.cells[(y*cb.w)+x]
|
||||||
|
if c.lastMain == rune(0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if c.lastMain != c.currMain {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if c.lastStyle != c.currStyle {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(c.lastComb) != len(c.currComb) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for i := range c.lastComb {
|
||||||
|
if c.lastComb[i] != c.currComb[i] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDirty is normally used to indicate that a cell has
|
||||||
|
// been displayed (in which case dirty is false), or to manually
|
||||||
|
// force a cell to be marked dirty.
|
||||||
|
func (cb *CellBuffer) SetDirty(x, y int, dirty bool) {
|
||||||
|
if x >= 0 && y >= 0 && x < cb.w && y < cb.h {
|
||||||
|
c := &cb.cells[(y*cb.w)+x]
|
||||||
|
if dirty {
|
||||||
|
c.lastMain = rune(0)
|
||||||
|
} else {
|
||||||
|
if c.currMain == rune(0) {
|
||||||
|
c.currMain = ' '
|
||||||
|
}
|
||||||
|
c.lastMain = c.currMain
|
||||||
|
c.lastComb = c.currComb
|
||||||
|
c.lastStyle = c.currStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize is used to resize the cells array, with different dimensions,
|
||||||
|
// while preserving the original contents. The cells will be invalidated
|
||||||
|
// so that they can be redrawn.
|
||||||
|
func (cb *CellBuffer) Resize(w, h int) {
|
||||||
|
|
||||||
|
if cb.h == h && cb.w == w {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newc := make([]cell, w*h)
|
||||||
|
for y := 0; y < h && y < cb.h; y++ {
|
||||||
|
for x := 0; x < w && x < cb.w; x++ {
|
||||||
|
oc := &cb.cells[(y*cb.w)+x]
|
||||||
|
nc := &newc[(y*w)+x]
|
||||||
|
nc.currMain = oc.currMain
|
||||||
|
nc.currComb = oc.currComb
|
||||||
|
nc.currStyle = oc.currStyle
|
||||||
|
nc.width = oc.width
|
||||||
|
nc.lastMain = rune(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb.cells = newc
|
||||||
|
cb.h = h
|
||||||
|
cb.w = w
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill fills the entire cell buffer array with the specified character
|
||||||
|
// and style. Normally choose ' ' to clear the screen. This API doesn't
|
||||||
|
// support combining characters, or characters with a width larger than one.
|
||||||
|
func (cb *CellBuffer) Fill(r rune, style Style) {
|
||||||
|
for i := range cb.cells {
|
||||||
|
c := &cb.cells[i]
|
||||||
|
c.currMain = r
|
||||||
|
c.currComb = nil
|
||||||
|
c.currStyle = style
|
||||||
|
c.width = 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
// +build plan9 nacl
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
func getCharset() string {
|
||||||
|
return ""
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// +build !windows,!nacl,!plan9
|
||||||
|
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getCharset() string {
|
||||||
|
// Determine the character set. This can help us later.
|
||||||
|
// Per POSIX, we search for LC_ALL first, then LC_CTYPE, and
|
||||||
|
// finally LANG. First one set wins.
|
||||||
|
locale := ""
|
||||||
|
if locale = os.Getenv("LC_ALL"); locale == "" {
|
||||||
|
if locale = os.Getenv("LC_CTYPE"); locale == "" {
|
||||||
|
locale = os.Getenv("LANG")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if locale == "POSIX" || locale == "C" {
|
||||||
|
return "US-ASCII"
|
||||||
|
}
|
||||||
|
if i := strings.IndexRune(locale, '@'); i >= 0 {
|
||||||
|
locale = locale[:i]
|
||||||
|
}
|
||||||
|
if i := strings.IndexRune(locale, '.'); i >= 0 {
|
||||||
|
locale = locale[i+1:]
|
||||||
|
} else {
|
||||||
|
// Default assumption, and on Linux we can see LC_ALL
|
||||||
|
// without a character set, which we assume implies UTF-8.
|
||||||
|
return "UTF-8"
|
||||||
|
}
|
||||||
|
// XXX: add support for aliases
|
||||||
|
return locale
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
// Copyright 2015 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
func getCharset() string {
|
||||||
|
return "UTF-16"
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2016 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/lucasb-eyer/go-colorful"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FindColor attempts to find a given color, or the best match possible for it,
|
||||||
|
// from the palette given. This is an expensive operation, so results should
|
||||||
|
// be cached by the caller.
|
||||||
|
func FindColor(c Color, palette []Color) Color {
|
||||||
|
match := ColorDefault
|
||||||
|
dist := float64(0)
|
||||||
|
r, g, b := c.RGB()
|
||||||
|
c1 := colorful.Color{
|
||||||
|
R: float64(r) / 255.0,
|
||||||
|
G: float64(g) / 255.0,
|
||||||
|
B: float64(b) / 255.0,
|
||||||
|
}
|
||||||
|
for _, d := range palette {
|
||||||
|
r, g, b = d.RGB()
|
||||||
|
c2 := colorful.Color{
|
||||||
|
R: float64(r) / 255.0,
|
||||||
|
G: float64(g) / 255.0,
|
||||||
|
B: float64(b) / 255.0,
|
||||||
|
}
|
||||||
|
// CIE94 is more accurate, but really really expensive.
|
||||||
|
nd := c1.DistanceCIE76(c2)
|
||||||
|
if math.IsNaN(nd) {
|
||||||
|
nd = math.Inf(1)
|
||||||
|
}
|
||||||
|
if match == ColorDefault || nd < dist {
|
||||||
|
match = d
|
||||||
|
dist = nd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
// Copyright 2015 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
// NewConsoleScreen returns a console based screen. This platform
|
||||||
|
// doesn't have support for any, so it returns nil and a suitable error.
|
||||||
|
func NewConsoleScreen() (Screen, error) {
|
||||||
|
return nil, ErrNoScreen
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2018 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package tcell provides a lower-level, portable API for building
|
||||||
|
// programs that interact with terminals or consoles. It works with
|
||||||
|
// both common (and many uncommon!) terminals or terminal emulators,
|
||||||
|
// and Windows console implementations.
|
||||||
|
//
|
||||||
|
// It provides support for up to 256 colors, text attributes, and box drawing
|
||||||
|
// elements. A database of terminals built from a real terminfo database
|
||||||
|
// is provided, along with code to generate new database entries.
|
||||||
|
//
|
||||||
|
// Tcell offers very rich support for mice, dependent upon the terminal
|
||||||
|
// of course. (Windows, XTerm, and iTerm 2 are known to work very well.)
|
||||||
|
//
|
||||||
|
// If the environment is not Unicode by default, such as an ISO8859 based
|
||||||
|
// locale or GB18030, Tcell can convert input and output, so that your
|
||||||
|
// terminal can operate in whatever locale is most convenient, while the
|
||||||
|
// application program can just assume "everything is UTF-8". Reasonable
|
||||||
|
// defaults are used for updating characters to something suitable for
|
||||||
|
// display. Unicode box drawing characters will be converted to use the
|
||||||
|
// alternate character set of your terminal, if native conversions are
|
||||||
|
// not available. If no ACS is available, then some ASCII fallbacks will
|
||||||
|
// be used.
|
||||||
|
//
|
||||||
|
// Note that support for non-UTF-8 locales (other than C) must be enabled
|
||||||
|
// by the application using RegisterEncoding() -- we don't have them all
|
||||||
|
// enabled by default to avoid bloating the application unneccessarily.
|
||||||
|
// (These days UTF-8 is good enough for almost everyone, and nobody should
|
||||||
|
// be using legacy locales anymore.) Also, actual glyphs for various code
|
||||||
|
// point will only be displayed if your terminal or emulator (or the font
|
||||||
|
// the emulator is using) supports them.
|
||||||
|
//
|
||||||
|
// A rich set of keycodes is supported, with support for up to 65 function
|
||||||
|
// keys, and various other special keys.
|
||||||
|
//
|
||||||
|
package tcell
|
@ -0,0 +1,139 @@
|
|||||||
|
// 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 (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
|
||||||
|
gencoding "github.com/gdamore/encoding"
|
||||||
|
)
|
||||||
|
|
||||||
|
var encodings map[string]encoding.Encoding
|
||||||
|
var encodingLk sync.Mutex
|
||||||
|
var encodingFallback EncodingFallback = EncodingFallbackFail
|
||||||
|
|
||||||
|
// RegisterEncoding may be called by the application to register an encoding.
|
||||||
|
// The presence of additional encodings will facilitate application usage with
|
||||||
|
// terminal environments where the I/O subsystem does not support Unicode.
|
||||||
|
//
|
||||||
|
// Windows systems use Unicode natively, and do not need any of the encoding
|
||||||
|
// subsystem when using Windows Console screens.
|
||||||
|
//
|
||||||
|
// Please see the Go documentation for golang.org/x/text/encoding -- most of
|
||||||
|
// the common ones exist already as stock variables. For example, ISO8859-15
|
||||||
|
// can be registered using the following code:
|
||||||
|
//
|
||||||
|
// import "golang.org/x/text/encoding/charmap"
|
||||||
|
//
|
||||||
|
// ...
|
||||||
|
// RegisterEncoding("ISO8859-15", charmap.ISO8859_15)
|
||||||
|
//
|
||||||
|
// Aliases can be registered as well, for example "8859-15" could be an alias
|
||||||
|
// for "ISO8859-15".
|
||||||
|
//
|
||||||
|
// For POSIX systems, the tcell package will check the environment variables
|
||||||
|
// LC_ALL, LC_CTYPE, and LANG (in that order) to determine the character set.
|
||||||
|
// These are expected to have the following pattern:
|
||||||
|
//
|
||||||
|
// $language[.$codeset[@$variant]
|
||||||
|
//
|
||||||
|
// We extract only the $codeset part, which will usually be something like
|
||||||
|
// UTF-8 or ISO8859-15 or KOI8-R. Note that if the locale is either "POSIX"
|
||||||
|
// or "C", then we assume US-ASCII (the POSIX 'portable character set'
|
||||||
|
// and assume all other characters are somehow invalid.)
|
||||||
|
//
|
||||||
|
// Modern POSIX systems and terminal emulators may use UTF-8, and for those
|
||||||
|
// systems, this API is also unnecessary. For example, Darwin (MacOS X) and
|
||||||
|
// modern Linux running modern xterm generally will out of the box without
|
||||||
|
// any of this. Use of UTF-8 is recommended when possible, as it saves
|
||||||
|
// quite a lot processing overhead.
|
||||||
|
//
|
||||||
|
// Note that some encodings are quite large (for example GB18030 which is a
|
||||||
|
// superset of Unicode) and so the application size can be expected ot
|
||||||
|
// increase quite a bit as each encoding is added. The East Asian encodings
|
||||||
|
// have been seen to add 100-200K per encoding to the application size.
|
||||||
|
//
|
||||||
|
func RegisterEncoding(charset string, enc encoding.Encoding) {
|
||||||
|
encodingLk.Lock()
|
||||||
|
charset = strings.ToLower(charset)
|
||||||
|
encodings[charset] = enc
|
||||||
|
encodingLk.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodingFallback describes how the system behavees when the locale
|
||||||
|
// requires a character set that we do not support. The system always
|
||||||
|
// supports UTF-8 and US-ASCII. On Windows consoles, UTF-16LE is also
|
||||||
|
// supported automatically. Other character sets must be added using the
|
||||||
|
// RegisterEncoding API. (A large group of nearly all of them can be
|
||||||
|
// added using the RegisterAll function in the encoding sub package.)
|
||||||
|
type EncodingFallback int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// EncodingFallbackFail behavior causes GetEncoding to fail
|
||||||
|
// when it cannot find an encoding.
|
||||||
|
EncodingFallbackFail = iota
|
||||||
|
|
||||||
|
// EncodingFallbackASCII behaviore causes GetEncoding to fall back
|
||||||
|
// to a 7-bit ASCII encoding, if no other encoding can be found.
|
||||||
|
EncodingFallbackASCII
|
||||||
|
|
||||||
|
// EncodingFallbackUTF8 behavior causes GetEncoding to assume
|
||||||
|
// UTF8 can pass unmodified upon failure. Note that this behavior
|
||||||
|
// is not recommended, unless you are sure your terminal can cope
|
||||||
|
// with real UTF8 sequences.
|
||||||
|
EncodingFallbackUTF8
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetEncodingFallback changes the behavior of GetEncoding when a suitable
|
||||||
|
// encoding is not found. The default is EncodingFallbackFail, which
|
||||||
|
// causes GetEncoding to simply return nil.
|
||||||
|
func SetEncodingFallback(fb EncodingFallback) {
|
||||||
|
encodingLk.Lock()
|
||||||
|
encodingFallback = fb
|
||||||
|
encodingLk.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEncoding is used by Screen implementors who want to locate an encoding
|
||||||
|
// for the given character set name. Note that this will return nil for
|
||||||
|
// either the Unicode (UTF-8) or ASCII encodings, since we don't use
|
||||||
|
// encodings for them but instead have our own native methods.
|
||||||
|
func GetEncoding(charset string) encoding.Encoding {
|
||||||
|
charset = strings.ToLower(charset)
|
||||||
|
encodingLk.Lock()
|
||||||
|
defer encodingLk.Unlock()
|
||||||
|
if enc, ok := encodings[charset]; ok {
|
||||||
|
return enc
|
||||||
|
}
|
||||||
|
switch encodingFallback {
|
||||||
|
case EncodingFallbackASCII:
|
||||||
|
return gencoding.ASCII
|
||||||
|
case EncodingFallbackUTF8:
|
||||||
|
return encoding.Nop
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// We always support UTF-8 and ASCII.
|
||||||
|
encodings = make(map[string]encoding.Encoding)
|
||||||
|
encodings["utf-8"] = gencoding.UTF8
|
||||||
|
encodings["utf8"] = gencoding.UTF8
|
||||||
|
encodings["us-ascii"] = gencoding.ASCII
|
||||||
|
encodings["ascii"] = gencoding.ASCII
|
||||||
|
encodings["iso646"] = gencoding.ASCII
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
// 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 (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2/terminfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrTermNotFound indicates that a suitable terminal entry could
|
||||||
|
// not be found. This can result from either not having TERM set,
|
||||||
|
// or from the TERM failing to support certain minimal functionality,
|
||||||
|
// in particular absolute cursor addressability (the cup capability)
|
||||||
|
// is required. For example, legacy "adm3" lacks this capability,
|
||||||
|
// whereas the slightly newer "adm3a" supports it. This failure
|
||||||
|
// occurs most often with "dumb".
|
||||||
|
ErrTermNotFound = terminfo.ErrTermNotFound
|
||||||
|
|
||||||
|
// ErrNoScreen indicates that no suitable screen could be found.
|
||||||
|
// This may result from attempting to run on a platform where there
|
||||||
|
// is no support for either termios or console I/O (such as nacl),
|
||||||
|
// or from running in an environment where there is no access to
|
||||||
|
// a suitable console/terminal device. (For example, running on
|
||||||
|
// without a controlling TTY or with no /dev/tty on POSIX platforms.)
|
||||||
|
ErrNoScreen = errors.New("no suitable screen available")
|
||||||
|
|
||||||
|
// ErrNoCharset indicates that the locale environment the
|
||||||
|
// program is not supported by the program, because no suitable
|
||||||
|
// encoding was found for it. This problem never occurs if
|
||||||
|
// the environment is UTF-8 or UTF-16.
|
||||||
|
ErrNoCharset = errors.New("character set not supported")
|
||||||
|
|
||||||
|
// ErrEventQFull indicates that the event queue is full, and
|
||||||
|
// cannot accept more events.
|
||||||
|
ErrEventQFull = errors.New("event queue full")
|
||||||
|
)
|
||||||
|
|
||||||
|
// An EventError is an event representing some sort of error, and carries
|
||||||
|
// an error payload.
|
||||||
|
type EventError struct {
|
||||||
|
t time.Time
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// When returns the time when the event was created.
|
||||||
|
func (ev *EventError) When() time.Time {
|
||||||
|
return ev.t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error.
|
||||||
|
func (ev *EventError) Error() string {
|
||||||
|
return ev.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventError creates an ErrorEvent with the given error payload.
|
||||||
|
func NewEventError(err error) *EventError {
|
||||||
|
return &EventError{t: time.Now(), err: err}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
// 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 (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event is a generic interface used for passing around Events.
|
||||||
|
// Concrete types follow.
|
||||||
|
type Event interface {
|
||||||
|
// When reports the time when the event was generated.
|
||||||
|
When() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventTime is a simple base event class, suitable for easy reuse.
|
||||||
|
// It can be used to deliver actual timer events as well.
|
||||||
|
type EventTime struct {
|
||||||
|
when time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// When returns the time stamp when the event occurred.
|
||||||
|
func (e *EventTime) When() time.Time {
|
||||||
|
return e.when
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEventTime sets the time of occurrence for the event.
|
||||||
|
func (e *EventTime) SetEventTime(t time.Time) {
|
||||||
|
e.when = t
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEventNow sets the time of occurrence for the event to the current time.
|
||||||
|
func (e *EventTime) SetEventNow() {
|
||||||
|
e.SetEventTime(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventHandler is anything that handles events. If the handler has
|
||||||
|
// consumed the event, it should return true. False otherwise.
|
||||||
|
type EventHandler interface {
|
||||||
|
HandleEvent(Event) bool
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
// 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 (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventInterrupt is a generic wakeup event. Its can be used to
|
||||||
|
// to request a redraw. It can carry an arbitrary payload, as well.
|
||||||
|
type EventInterrupt struct {
|
||||||
|
t time.Time
|
||||||
|
v interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When returns the time when this event was created.
|
||||||
|
func (ev *EventInterrupt) When() time.Time {
|
||||||
|
return ev.t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data is used to obtain the opaque event payload.
|
||||||
|
func (ev *EventInterrupt) Data() interface{} {
|
||||||
|
return ev.v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventInterrupt creates an EventInterrupt with the given payload.
|
||||||
|
func NewEventInterrupt(data interface{}) *EventInterrupt {
|
||||||
|
return &EventInterrupt{t: time.Now(), v: data}
|
||||||
|
}
|
@ -0,0 +1,470 @@
|
|||||||
|
// Copyright 2016 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventKey represents a key press. Usually this is a key press followed
|
||||||
|
// by a key release, but since terminal programs don't have a way to report
|
||||||
|
// key release events, we usually get just one event. If a key is held down
|
||||||
|
// then the terminal may synthesize repeated key presses at some predefined
|
||||||
|
// rate. We have no control over that, nor visibility into it.
|
||||||
|
//
|
||||||
|
// In some cases, we can have a modifier key, such as ModAlt, that can be
|
||||||
|
// generated with a key press. (This usually is represented by having the
|
||||||
|
// high bit set, or in some cases, by sending an ESC prior to the rune.)
|
||||||
|
//
|
||||||
|
// If the value of Key() is KeyRune, then the actual key value will be
|
||||||
|
// available with the Rune() method. This will be the case for most keys.
|
||||||
|
// In most situations, the modifiers will not be set. For example, if the
|
||||||
|
// rune is 'A', this will be reported without the ModShift bit set, since
|
||||||
|
// really can't tell if the Shift key was pressed (it might have been CAPSLOCK,
|
||||||
|
// or a terminal that only can send capitals, or keyboard with separate
|
||||||
|
// capital letters from lower case letters).
|
||||||
|
//
|
||||||
|
// Generally, terminal applications have far less visibility into keyboard
|
||||||
|
// activity than graphical applications. Hence, they should avoid depending
|
||||||
|
// overly much on availability of modifiers, or the availability of any
|
||||||
|
// specific keys.
|
||||||
|
type EventKey struct {
|
||||||
|
t time.Time
|
||||||
|
mod ModMask
|
||||||
|
key Key
|
||||||
|
ch rune
|
||||||
|
}
|
||||||
|
|
||||||
|
// When returns the time when this Event was created, which should closely
|
||||||
|
// match the time when the key was pressed.
|
||||||
|
func (ev *EventKey) When() time.Time {
|
||||||
|
return ev.t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rune returns the rune corresponding to the key press, if it makes sense.
|
||||||
|
// The result is only defined if the value of Key() is KeyRune.
|
||||||
|
func (ev *EventKey) Rune() rune {
|
||||||
|
return ev.ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key returns a virtual key code. We use this to identify specific key
|
||||||
|
// codes, such as KeyEnter, etc. Most control and function keys are reported
|
||||||
|
// with unique Key values. Normal alphanumeric and punctuation keys will
|
||||||
|
// generally return KeyRune here; the specific key can be further decoded
|
||||||
|
// using the Rune() function.
|
||||||
|
func (ev *EventKey) Key() Key {
|
||||||
|
return ev.key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifiers returns the modifiers that were present with the key press. Note
|
||||||
|
// that not all platforms and terminals support this equally well, and some
|
||||||
|
// cases we will not not know for sure. Hence, applications should avoid
|
||||||
|
// using this in most circumstances.
|
||||||
|
func (ev *EventKey) Modifiers() ModMask {
|
||||||
|
return ev.mod
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyNames holds the written names of special keys. Useful to echo back a key
|
||||||
|
// name, or to look up a key from a string value.
|
||||||
|
var KeyNames = map[Key]string{
|
||||||
|
KeyEnter: "Enter",
|
||||||
|
KeyBackspace: "Backspace",
|
||||||
|
KeyTab: "Tab",
|
||||||
|
KeyBacktab: "Backtab",
|
||||||
|
KeyEsc: "Esc",
|
||||||
|
KeyBackspace2: "Backspace2",
|
||||||
|
KeyDelete: "Delete",
|
||||||
|
KeyInsert: "Insert",
|
||||||
|
KeyUp: "Up",
|
||||||
|
KeyDown: "Down",
|
||||||
|
KeyLeft: "Left",
|
||||||
|
KeyRight: "Right",
|
||||||
|
KeyHome: "Home",
|
||||||
|
KeyEnd: "End",
|
||||||
|
KeyUpLeft: "UpLeft",
|
||||||
|
KeyUpRight: "UpRight",
|
||||||
|
KeyDownLeft: "DownLeft",
|
||||||
|
KeyDownRight: "DownRight",
|
||||||
|
KeyCenter: "Center",
|
||||||
|
KeyPgDn: "PgDn",
|
||||||
|
KeyPgUp: "PgUp",
|
||||||
|
KeyClear: "Clear",
|
||||||
|
KeyExit: "Exit",
|
||||||
|
KeyCancel: "Cancel",
|
||||||
|
KeyPause: "Pause",
|
||||||
|
KeyPrint: "Print",
|
||||||
|
KeyF1: "F1",
|
||||||
|
KeyF2: "F2",
|
||||||
|
KeyF3: "F3",
|
||||||
|
KeyF4: "F4",
|
||||||
|
KeyF5: "F5",
|
||||||
|
KeyF6: "F6",
|
||||||
|
KeyF7: "F7",
|
||||||
|
KeyF8: "F8",
|
||||||
|
KeyF9: "F9",
|
||||||
|
KeyF10: "F10",
|
||||||
|
KeyF11: "F11",
|
||||||
|
KeyF12: "F12",
|
||||||
|
KeyF13: "F13",
|
||||||
|
KeyF14: "F14",
|
||||||
|
KeyF15: "F15",
|
||||||
|
KeyF16: "F16",
|
||||||
|
KeyF17: "F17",
|
||||||
|
KeyF18: "F18",
|
||||||
|
KeyF19: "F19",
|
||||||
|
KeyF20: "F20",
|
||||||
|
KeyF21: "F21",
|
||||||
|
KeyF22: "F22",
|
||||||
|
KeyF23: "F23",
|
||||||
|
KeyF24: "F24",
|
||||||
|
KeyF25: "F25",
|
||||||
|
KeyF26: "F26",
|
||||||
|
KeyF27: "F27",
|
||||||
|
KeyF28: "F28",
|
||||||
|
KeyF29: "F29",
|
||||||
|
KeyF30: "F30",
|
||||||
|
KeyF31: "F31",
|
||||||
|
KeyF32: "F32",
|
||||||
|
KeyF33: "F33",
|
||||||
|
KeyF34: "F34",
|
||||||
|
KeyF35: "F35",
|
||||||
|
KeyF36: "F36",
|
||||||
|
KeyF37: "F37",
|
||||||
|
KeyF38: "F38",
|
||||||
|
KeyF39: "F39",
|
||||||
|
KeyF40: "F40",
|
||||||
|
KeyF41: "F41",
|
||||||
|
KeyF42: "F42",
|
||||||
|
KeyF43: "F43",
|
||||||
|
KeyF44: "F44",
|
||||||
|
KeyF45: "F45",
|
||||||
|
KeyF46: "F46",
|
||||||
|
KeyF47: "F47",
|
||||||
|
KeyF48: "F48",
|
||||||
|
KeyF49: "F49",
|
||||||
|
KeyF50: "F50",
|
||||||
|
KeyF51: "F51",
|
||||||
|
KeyF52: "F52",
|
||||||
|
KeyF53: "F53",
|
||||||
|
KeyF54: "F54",
|
||||||
|
KeyF55: "F55",
|
||||||
|
KeyF56: "F56",
|
||||||
|
KeyF57: "F57",
|
||||||
|
KeyF58: "F58",
|
||||||
|
KeyF59: "F59",
|
||||||
|
KeyF60: "F60",
|
||||||
|
KeyF61: "F61",
|
||||||
|
KeyF62: "F62",
|
||||||
|
KeyF63: "F63",
|
||||||
|
KeyF64: "F64",
|
||||||
|
KeyCtrlA: "Ctrl-A",
|
||||||
|
KeyCtrlB: "Ctrl-B",
|
||||||
|
KeyCtrlC: "Ctrl-C",
|
||||||
|
KeyCtrlD: "Ctrl-D",
|
||||||
|
KeyCtrlE: "Ctrl-E",
|
||||||
|
KeyCtrlF: "Ctrl-F",
|
||||||
|
KeyCtrlG: "Ctrl-G",
|
||||||
|
KeyCtrlJ: "Ctrl-J",
|
||||||
|
KeyCtrlK: "Ctrl-K",
|
||||||
|
KeyCtrlL: "Ctrl-L",
|
||||||
|
KeyCtrlN: "Ctrl-N",
|
||||||
|
KeyCtrlO: "Ctrl-O",
|
||||||
|
KeyCtrlP: "Ctrl-P",
|
||||||
|
KeyCtrlQ: "Ctrl-Q",
|
||||||
|
KeyCtrlR: "Ctrl-R",
|
||||||
|
KeyCtrlS: "Ctrl-S",
|
||||||
|
KeyCtrlT: "Ctrl-T",
|
||||||
|
KeyCtrlU: "Ctrl-U",
|
||||||
|
KeyCtrlV: "Ctrl-V",
|
||||||
|
KeyCtrlW: "Ctrl-W",
|
||||||
|
KeyCtrlX: "Ctrl-X",
|
||||||
|
KeyCtrlY: "Ctrl-Y",
|
||||||
|
KeyCtrlZ: "Ctrl-Z",
|
||||||
|
KeyCtrlSpace: "Ctrl-Space",
|
||||||
|
KeyCtrlUnderscore: "Ctrl-_",
|
||||||
|
KeyCtrlRightSq: "Ctrl-]",
|
||||||
|
KeyCtrlBackslash: "Ctrl-\\",
|
||||||
|
KeyCtrlCarat: "Ctrl-^",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns a printable value or the key stroke. This can be used
|
||||||
|
// when printing the event, for example.
|
||||||
|
func (ev *EventKey) Name() string {
|
||||||
|
s := ""
|
||||||
|
m := []string{}
|
||||||
|
if ev.mod&ModShift != 0 {
|
||||||
|
m = append(m, "Shift")
|
||||||
|
}
|
||||||
|
if ev.mod&ModAlt != 0 {
|
||||||
|
m = append(m, "Alt")
|
||||||
|
}
|
||||||
|
if ev.mod&ModMeta != 0 {
|
||||||
|
m = append(m, "Meta")
|
||||||
|
}
|
||||||
|
if ev.mod&ModCtrl != 0 {
|
||||||
|
m = append(m, "Ctrl")
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := false
|
||||||
|
if s, ok = KeyNames[ev.key]; !ok {
|
||||||
|
if ev.key == KeyRune {
|
||||||
|
s = "Rune[" + string(ev.ch) + "]"
|
||||||
|
} else {
|
||||||
|
s = fmt.Sprintf("Key[%d,%d]", ev.key, int(ev.ch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(m) != 0 {
|
||||||
|
if ev.mod&ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") {
|
||||||
|
s = s[5:]
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s+%s", strings.Join(m, "+"), s)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventKey attempts to create a suitable event. It parses the various
|
||||||
|
// ASCII control sequences if KeyRune is passed for Key, but if the caller
|
||||||
|
// has more precise information it should set that specifically. Callers
|
||||||
|
// that aren't sure about modifier state (most) should just pass ModNone.
|
||||||
|
func NewEventKey(k Key, ch rune, mod ModMask) *EventKey {
|
||||||
|
if k == KeyRune && (ch < ' ' || ch == 0x7f) {
|
||||||
|
// Turn specials into proper key codes. This is for
|
||||||
|
// control characters and the DEL.
|
||||||
|
k = Key(ch)
|
||||||
|
if mod == ModNone && ch < ' ' {
|
||||||
|
switch Key(ch) {
|
||||||
|
case KeyBackspace, KeyTab, KeyEsc, KeyEnter:
|
||||||
|
// these keys are directly typeable without CTRL
|
||||||
|
default:
|
||||||
|
// most likely entered with a CTRL keypress
|
||||||
|
mod = ModCtrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &EventKey{t: time.Now(), key: k, ch: ch, mod: mod}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModMask is a mask of modifier keys. Note that it will not always be
|
||||||
|
// possible to report modifier keys.
|
||||||
|
type ModMask int16
|
||||||
|
|
||||||
|
// These are the modifiers keys that can be sent either with a key press,
|
||||||
|
// or a mouse event. Note that as of now, due to the confusion associated
|
||||||
|
// with Meta, and the lack of support for it on many/most platforms, the
|
||||||
|
// current implementations never use it. Instead, they use ModAlt, even for
|
||||||
|
// events that could possibly have been distinguished from ModAlt.
|
||||||
|
const (
|
||||||
|
ModShift ModMask = 1 << iota
|
||||||
|
ModCtrl
|
||||||
|
ModAlt
|
||||||
|
ModMeta
|
||||||
|
ModNone ModMask = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key is a generic value for representing keys, and especially special
|
||||||
|
// keys (function keys, cursor movement keys, etc.) For normal keys, like
|
||||||
|
// ASCII letters, we use KeyRune, and then expect the application to
|
||||||
|
// inspect the Rune() member of the EventKey.
|
||||||
|
type Key int16
|
||||||
|
|
||||||
|
// This is the list of named keys. KeyRune is special however, in that it is
|
||||||
|
// a place holder key indicating that a printable character was sent. The
|
||||||
|
// actual value of the rune will be transported in the Rune of the associated
|
||||||
|
// EventKey.
|
||||||
|
const (
|
||||||
|
KeyRune Key = iota + 256
|
||||||
|
KeyUp
|
||||||
|
KeyDown
|
||||||
|
KeyRight
|
||||||
|
KeyLeft
|
||||||
|
KeyUpLeft
|
||||||
|
KeyUpRight
|
||||||
|
KeyDownLeft
|
||||||
|
KeyDownRight
|
||||||
|
KeyCenter
|
||||||
|
KeyPgUp
|
||||||
|
KeyPgDn
|
||||||
|
KeyHome
|
||||||
|
KeyEnd
|
||||||
|
KeyInsert
|
||||||
|
KeyDelete
|
||||||
|
KeyHelp
|
||||||
|
KeyExit
|
||||||
|
KeyClear
|
||||||
|
KeyCancel
|
||||||
|
KeyPrint
|
||||||
|
KeyPause
|
||||||
|
KeyBacktab
|
||||||
|
KeyF1
|
||||||
|
KeyF2
|
||||||
|
KeyF3
|
||||||
|
KeyF4
|
||||||
|
KeyF5
|
||||||
|
KeyF6
|
||||||
|
KeyF7
|
||||||
|
KeyF8
|
||||||
|
KeyF9
|
||||||
|
KeyF10
|
||||||
|
KeyF11
|
||||||
|
KeyF12
|
||||||
|
KeyF13
|
||||||
|
KeyF14
|
||||||
|
KeyF15
|
||||||
|
KeyF16
|
||||||
|
KeyF17
|
||||||
|
KeyF18
|
||||||
|
KeyF19
|
||||||
|
KeyF20
|
||||||
|
KeyF21
|
||||||
|
KeyF22
|
||||||
|
KeyF23
|
||||||
|
KeyF24
|
||||||
|
KeyF25
|
||||||
|
KeyF26
|
||||||
|
KeyF27
|
||||||
|
KeyF28
|
||||||
|
KeyF29
|
||||||
|
KeyF30
|
||||||
|
KeyF31
|
||||||
|
KeyF32
|
||||||
|
KeyF33
|
||||||
|
KeyF34
|
||||||
|
KeyF35
|
||||||
|
KeyF36
|
||||||
|
KeyF37
|
||||||
|
KeyF38
|
||||||
|
KeyF39
|
||||||
|
KeyF40
|
||||||
|
KeyF41
|
||||||
|
KeyF42
|
||||||
|
KeyF43
|
||||||
|
KeyF44
|
||||||
|
KeyF45
|
||||||
|
KeyF46
|
||||||
|
KeyF47
|
||||||
|
KeyF48
|
||||||
|
KeyF49
|
||||||
|
KeyF50
|
||||||
|
KeyF51
|
||||||
|
KeyF52
|
||||||
|
KeyF53
|
||||||
|
KeyF54
|
||||||
|
KeyF55
|
||||||
|
KeyF56
|
||||||
|
KeyF57
|
||||||
|
KeyF58
|
||||||
|
KeyF59
|
||||||
|
KeyF60
|
||||||
|
KeyF61
|
||||||
|
KeyF62
|
||||||
|
KeyF63
|
||||||
|
KeyF64
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// These key codes are used internally, and will never appear to applications.
|
||||||
|
keyPasteStart Key = iota + 16384
|
||||||
|
keyPasteEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
// These are the control keys. Note that they overlap with other keys,
|
||||||
|
// perhaps. For example, KeyCtrlH is the same as KeyBackspace.
|
||||||
|
const (
|
||||||
|
KeyCtrlSpace Key = iota
|
||||||
|
KeyCtrlA
|
||||||
|
KeyCtrlB
|
||||||
|
KeyCtrlC
|
||||||
|
KeyCtrlD
|
||||||
|
KeyCtrlE
|
||||||
|
KeyCtrlF
|
||||||
|
KeyCtrlG
|
||||||
|
KeyCtrlH
|
||||||
|
KeyCtrlI
|
||||||
|
KeyCtrlJ
|
||||||
|
KeyCtrlK
|
||||||
|
KeyCtrlL
|
||||||
|
KeyCtrlM
|
||||||
|
KeyCtrlN
|
||||||
|
KeyCtrlO
|
||||||
|
KeyCtrlP
|
||||||
|
KeyCtrlQ
|
||||||
|
KeyCtrlR
|
||||||
|
KeyCtrlS
|
||||||
|
KeyCtrlT
|
||||||
|
KeyCtrlU
|
||||||
|
KeyCtrlV
|
||||||
|
KeyCtrlW
|
||||||
|
KeyCtrlX
|
||||||
|
KeyCtrlY
|
||||||
|
KeyCtrlZ
|
||||||
|
KeyCtrlLeftSq // Escape
|
||||||
|
KeyCtrlBackslash
|
||||||
|
KeyCtrlRightSq
|
||||||
|
KeyCtrlCarat
|
||||||
|
KeyCtrlUnderscore
|
||||||
|
)
|
||||||
|
|
||||||
|
// Special values - these are fixed in an attempt to make it more likely
|
||||||
|
// that aliases will encode the same way.
|
||||||
|
|
||||||
|
// These are the defined ASCII values for key codes. They generally match
|
||||||
|
// with KeyCtrl values.
|
||||||
|
const (
|
||||||
|
KeyNUL Key = iota
|
||||||
|
KeySOH
|
||||||
|
KeySTX
|
||||||
|
KeyETX
|
||||||
|
KeyEOT
|
||||||
|
KeyENQ
|
||||||
|
KeyACK
|
||||||
|
KeyBEL
|
||||||
|
KeyBS
|
||||||
|
KeyTAB
|
||||||
|
KeyLF
|
||||||
|
KeyVT
|
||||||
|
KeyFF
|
||||||
|
KeyCR
|
||||||
|
KeySO
|
||||||
|
KeySI
|
||||||
|
KeyDLE
|
||||||
|
KeyDC1
|
||||||
|
KeyDC2
|
||||||
|
KeyDC3
|
||||||
|
KeyDC4
|
||||||
|
KeyNAK
|
||||||
|
KeySYN
|
||||||
|
KeyETB
|
||||||
|
KeyCAN
|
||||||
|
KeyEM
|
||||||
|
KeySUB
|
||||||
|
KeyESC
|
||||||
|
KeyFS
|
||||||
|
KeyGS
|
||||||
|
KeyRS
|
||||||
|
KeyUS
|
||||||
|
KeyDEL Key = 0x7F
|
||||||
|
)
|
||||||
|
|
||||||
|
// These keys are aliases for other names.
|
||||||
|
const (
|
||||||
|
KeyBackspace = KeyBS
|
||||||
|
KeyTab = KeyTAB
|
||||||
|
KeyEsc = KeyESC
|
||||||
|
KeyEscape = KeyESC
|
||||||
|
KeyEnter = KeyCR
|
||||||
|
KeyBackspace2 = KeyDEL
|
||||||
|
)
|
@ -0,0 +1,103 @@
|
|||||||
|
// Copyright 2020 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventMouse is a mouse event. It is sent on either mouse up or mouse down
|
||||||
|
// events. It is also sent on mouse motion events - if the terminal supports
|
||||||
|
// it. We make every effort to ensure that mouse release events are delivered.
|
||||||
|
// Hence, click drag can be identified by a motion event with the mouse down,
|
||||||
|
// without any intervening button release. On some terminals only the initiating
|
||||||
|
// press and terminating release event will be delivered.
|
||||||
|
//
|
||||||
|
// Mouse wheel events, when reported, may appear on their own as individual
|
||||||
|
// impulses; that is, there will normally not be a release event delivered
|
||||||
|
// for mouse wheel movements.
|
||||||
|
//
|
||||||
|
// Most terminals cannot report the state of more than one button at a time --
|
||||||
|
// and some cannot report motion events unless a button is pressed.
|
||||||
|
//
|
||||||
|
// Applications can inspect the time between events to resolve double or
|
||||||
|
// triple clicks.
|
||||||
|
type EventMouse struct {
|
||||||
|
t time.Time
|
||||||
|
btn ButtonMask
|
||||||
|
mod ModMask
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
// When returns the time when this EventMouse was created.
|
||||||
|
func (ev *EventMouse) When() time.Time {
|
||||||
|
return ev.t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buttons returns the list of buttons that were pressed or wheel motions.
|
||||||
|
func (ev *EventMouse) Buttons() ButtonMask {
|
||||||
|
return ev.btn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifiers returns a list of keyboard modifiers that were pressed
|
||||||
|
// with the mouse button(s).
|
||||||
|
func (ev *EventMouse) Modifiers() ModMask {
|
||||||
|
return ev.mod
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position returns the mouse position in character cells. The origin
|
||||||
|
// 0, 0 is at the upper left corner.
|
||||||
|
func (ev *EventMouse) Position() (int, int) {
|
||||||
|
return ev.x, ev.y
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventMouse is used to create a new mouse event. Applications
|
||||||
|
// shouldn't need to use this; its mostly for screen implementors.
|
||||||
|
func NewEventMouse(x, y int, btn ButtonMask, mod ModMask) *EventMouse {
|
||||||
|
return &EventMouse{t: time.Now(), x: x, y: y, btn: btn, mod: mod}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ButtonMask is a mask of mouse buttons and wheel events. Mouse button presses
|
||||||
|
// are normally delivered as both press and release events. Mouse wheel events
|
||||||
|
// are normally just single impulse events. Windows supports up to eight
|
||||||
|
// separate buttons plus all four wheel directions, but XTerm can only support
|
||||||
|
// mouse buttons 1-3 and wheel up/down. Its not unheard of for terminals
|
||||||
|
// to support only one or two buttons (think Macs). Old terminals, and true
|
||||||
|
// emulations (such as vt100) won't support mice at all, of course.
|
||||||
|
type ButtonMask int16
|
||||||
|
|
||||||
|
// These are the actual button values. Note that tcell version 1.x reversed buttons
|
||||||
|
// two and three on *nix based terminals. We use button 1 as the primary, and
|
||||||
|
// button 2 as the secondary, and button 3 (which is often missing) as the middle.
|
||||||
|
const (
|
||||||
|
Button1 ButtonMask = 1 << iota // Usually the left (primary) mouse button.
|
||||||
|
Button2 // Usually the right (secondary) mouse button.
|
||||||
|
Button3 // Usually the middle mouse button.
|
||||||
|
Button4 // Often a side button (thumb/next).
|
||||||
|
Button5 // Often a side button (thumb/prev).
|
||||||
|
Button6
|
||||||
|
Button7
|
||||||
|
Button8
|
||||||
|
WheelUp // Wheel motion up/away from user.
|
||||||
|
WheelDown // Wheel motion down/towards user.
|
||||||
|
WheelLeft // Wheel motion to left.
|
||||||
|
WheelRight // Wheel motion to right.
|
||||||
|
ButtonNone ButtonMask = 0 // No button or wheel events.
|
||||||
|
|
||||||
|
ButtonPrimary = Button1
|
||||||
|
ButtonSecondary = Button2
|
||||||
|
ButtonMiddle = Button3
|
||||||
|
)
|
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2021 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build darwin dragonfly freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BSD systems use TIOC style ioctls.
|
||||||
|
|
||||||
|
// tcSetBufParams is used by the tty driver on UNIX systems to configure the
|
||||||
|
// buffering parameters (minimum character count and minimum wait time in msec.)
|
||||||
|
// This also waits for output to drain first.
|
||||||
|
func tcSetBufParams(fd int, vMin uint8, vTime uint8) error {
|
||||||
|
_ = syscall.SetNonblock(fd, true)
|
||||||
|
tio, err := unix.IoctlGetTermios(fd, unix.TIOCGETA)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tio.Cc[unix.VMIN] = vMin
|
||||||
|
tio.Cc[unix.VTIME] = vTime
|
||||||
|
if err = unix.IoctlSetTermios(fd, unix.TIOCSETAW, tio); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2021 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build linux aix zos solaris
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tcSetBufParams is used by the tty driver on UNIX systems to configure the
|
||||||
|
// buffering parameters (minimum character count and minimum wait time in msec.)
|
||||||
|
// This also waits for output to drain first.
|
||||||
|
func tcSetBufParams(fd int, vMin uint8, vTime uint8) error {
|
||||||
|
_ = syscall.SetNonblock(fd, true)
|
||||||
|
tio, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tio.Cc[unix.VMIN] = vMin
|
||||||
|
tio.Cc[unix.VTIME] = vTime
|
||||||
|
if err = unix.IoctlSetTermios(fd, unix.TCSETSW, tio); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue