diff --git a/attr.go b/attr.go index f833ccb..d92a6fc 100644 --- a/attr.go +++ b/attr.go @@ -14,7 +14,8 @@ package tcell -// AttrMask represents a mask of text attributes. +// AttrMask represents a mask of text attributes, apart from color. +// Note that support for attributes may vary widely across terminals. type AttrMask int // NB: the colors listed here are in the order that ANSI terminals expect. @@ -25,5 +26,7 @@ const ( AttrReverse AttrUnderline AttrDim + + // AttrNone is just normal text. AttrNone AttrMask = 0 ) diff --git a/cell.go b/cell.go index 568b4c4..901f608 100644 --- a/cell.go +++ b/cell.go @@ -81,6 +81,9 @@ func (c *Cell) SetCell(ch []rune, style Style) { c.PutStyle(style) } +// PutChars is a handy way to write runes to the Cell, without changing its +// style. The first rune should be a printable non-zero width value, and +// subsequent values may be combining marks. func (c *Cell) PutChars(ch []rune) { var mainc rune @@ -120,10 +123,14 @@ func (c *Cell) PutChars(ch []rune) { c.Width = width } +// PutChar writes a single rune into the cells location. The rune should be a +// a normal (not combining) printable character. func (c *Cell) PutChar(ch rune) { c.PutChars([]rune{ch}) } +// PutStyle changes the style of the given Cell, without altering the character +// content. func (c *Cell) PutStyle(style Style) { if c.Style != style { c.Style = style diff --git a/color.go b/color.go index 776c9ad..65a0a4e 100644 --- a/color.go +++ b/color.go @@ -20,6 +20,8 @@ package tcell type Color int16 const ( + // ColorDefault is used to leave the Color unchanged from whatever + // system or teminal default may exist. ColorDefault Color = iota ColorBlack ColorRed diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..93ebecf --- /dev/null +++ b/doc.go @@ -0,0 +1,40 @@ +// 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 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 outupt, 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. +// +// A rich set of keycodes is supported, with support for up to 65 function +// keys, and various other special keys. +// +package tcell diff --git a/encoding.go b/encoding.go index 25a6b07..37b3002 100644 --- a/encoding.go +++ b/encoding.go @@ -23,38 +23,46 @@ import ( var encodings map[string]encoding.Encoding var encodingLk sync.Mutex -// 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. Please see the -// Go documentation for encodings -- most of the common ones exist already as stock -// variables. For example, ISO8859-15 can be registered using the following code: +// 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. +// 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". +// Aliases can be registered as well, for example "8859-15" could be an alias +// for "ISO8859-15". // -// For POSIX systems, the tcell pacakge 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' +// For POSIX systems, the tcell pacakge 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.) // -// On Windows systems, the Console is assumed to be UTF-16LE. As we communicate with the -// console subsystem using UTF-16LE, no conversions are necessary. So none of this is required -// for Windows systems. +// On Windows systems, the Console is assumed to be UTF-16LE. As we +// communicate with the console subsystem using UTF-16LE, no conversions are +// necessary. So none of this is required for Windows systems. // -// 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. +// 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. +// 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(name string, enc encoding.Encoding) { encodingLk.Lock() @@ -65,6 +73,10 @@ func RegisterEncoding(name string, enc encoding.Encoding) { 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(name string) encoding.Encoding { encodingLk.Lock() defer encodingLk.Unlock() diff --git a/key.go b/key.go index 76ebe40..b9d91d1 100644 --- a/key.go +++ b/key.go @@ -40,7 +40,8 @@ import ( // // Generally, terminal applications have far less visibility into keyboard // activity than graphical applications. Hence, they should avoid depending -// overly much on availability of such details. +// overly much on availability of modifiers, or the availability of any +// specific keys. type EventKey struct { t time.Time mod ModMask @@ -48,22 +49,37 @@ type EventKey struct { ch rune } +// When returns the time when this Event was created, which should closely +// match the time when the key was pressed. func (*EventKey) When() time.Time { return time.Now() } +// 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 } +// ModMask 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) Mod() ModMask { return ev.mod } +// 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{} diff --git a/mouse.go b/mouse.go index bc82015..151a1d8 100644 --- a/mouse.go +++ b/mouse.go @@ -25,10 +25,12 @@ import ( // without any intervening button release. // // Mouse wheel events, when reported, may appear on their own as individual -// impulses. +// 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 few can report motion events. +// and many cannot report motion events. (Windows consoles, modern XTerm, and +// modern emulators like iTerm2, are known to support this well, though.) // // Applications can inspect the time between events to figure out double clicks // and such. @@ -44,18 +46,25 @@ func (ev *EventMouse) When() time.Time { return ev.t } +// ButtonMask returns the list of buttons that were pressed. 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} } @@ -64,15 +73,20 @@ func NewEventMouse(x, y int, btn ButtonMask, mod ModMask) *EventMouse { type ButtonMask int16 const ( + // Button1 is usually the left mouse button. Button1 ButtonMask = 1 << iota + // Button2 is usually the middle mouse button, for three button mice. Button2 + // Button3 is usually the right mouse button on 2 or 3 button mice. Button3 Button4 Button5 Button6 Button7 Button8 + // WheelUp indicates the wheel being moved up, away from the user. WheelUp + // WheelDown indicates the wheel being moved down, towards the user. WheelDown WheelLeft WheelRight diff --git a/screen.go b/screen.go index 16adadf..93bf5df 100644 --- a/screen.go +++ b/screen.go @@ -14,10 +14,9 @@ package tcell -// Screen represents the physical (or emulated) screen, without any buffering. +// Screen represents the physical (or emulated) screen. // This can be a terminal window or a physical console. Platforms implement -// this differerently. Applications are unlikely to interface directly with -// this. +// this differerently. type Screen interface { // Init initializes the screen for use. Init() error @@ -25,7 +24,9 @@ type Screen interface { // Fini finalizes the screen also releasing resources. Fini() - // Clear erases the screen. + // Clear erases the screen. The contents of any screen buffers + // will also be cleared. This has the logical effect of + // filling the screen with spaces, using the global default style. Clear() // SetCell sets the cell at the given location. @@ -61,7 +62,7 @@ type Screen interface { GetCell(x, y int) *Cell // SetStyle sets the default style to use when clearing the screen - // or when StyleDefault is specified. If it is also STyleDefault, + // or when StyleDefault is specified. If it is also StyleDefault, // then whatever system/terminal default is relevant will be used. SetStyle(style Style) @@ -93,13 +94,13 @@ type Screen interface { DisableMouse() // Colors returns the number of colors. All colors are assumed to - // use the ANSI color map. + // use the ANSI color map. If a terminal is monochrome, it will + // return 0. Colors() int // Show takes any output that was deferred due to buffering, and - // flushes it to the physical display. It does so in the least - // expensive and disruptive manner possible, only making writes that - // are believed to actually be necessary. + // flushes it to the physical display. It does so in the most + // efficient and least visually disruptive manner possible. Show() // Sync works like Show(), but it updates every visible cell on the @@ -119,6 +120,8 @@ type Screen interface { CharacterSet() string } +// NewScreen returns a default Screen suitable for the user's terminal +// environment. func NewScreen() (Screen, error) { // First we attempt to obtain a terminfo screen. This should work // in most places if $TERM is set. diff --git a/style.go b/style.go index c053dc4..001a6d3 100644 --- a/style.go +++ b/style.go @@ -14,10 +14,15 @@ package tcell -// Color represents a color. We encode it in a 64-bit int for efficiency. +// Style represents a complete text style, including both foreground +// and background color. We encode it in a 64-bit int for efficiency. // The coding is (MSB): <16b rsvd><16b attr><16b fgcolor><16b bgcolor>. // This gives 16bit color options, if it ever becomes truly necessary. -// I can't see a need to get beyond 256 colors. +// However, applications must not rely on this encoding. +// +// Note that not all terminals can display all colors or attributes, and +// many might have specific incompatibilities between specific attributes +// and color combinations. type Style int64 func NewStyle() Style { @@ -26,15 +31,21 @@ func NewStyle() Style { const StyleDefault Style = 0 +// Foreground returns a new style based on s, with the foreground color set +// as requested. ColorDefault can be used to select the global default. func (s Style) Foreground(c Color) Style { return (s &^ Style(0xffff0000)) | (Style(c) << 16) } +// Background returns a new style based on s, with the background color set +// as requested. ColorDefault can be used to select the global default. func (s Style) Background(c Color) Style { return (s &^ (0xffff)) | Style(c) } -func (s Style) Decompose() (Color, Color, AttrMask) { +// Decompose breaks a style up, returning the foreground, background, +// and other attributes. +func (s Style) Decompose() (fg Color, bg Color, attr AttrMask) { return Color((s >> 16) & 0xffff), Color(s & 0xfffff), AttrMask((s >> 32) & 0xffff) @@ -53,22 +64,33 @@ func (s Style) Normal() Style { return s &^ (Style(0xfffff) << 32) } +// Bold returns a new style based on s, with the bold attribute set +// as requested. func (s Style) Bold(on bool) Style { return s.setAttrs(Style(AttrBold), on) } +// Blink returns a new style based on s, with the blink attribute set +// as requested. func (s Style) Blink(on bool) Style { return s.setAttrs(Style(AttrBlink), on) } +// Dim returns a new style based on s, with the dim attribute set +// as requested. func (s Style) Dim(on bool) Style { return s.setAttrs(Style(AttrDim), on) } +// Reverse returns a new style based on s, with the reverse attribute set +// as requested. (Reverse usually changes the foreground and background +// colors.) func (s Style) Reverse(on bool) Style { return s.setAttrs(Style(AttrReverse), on) } +// Reverse returns a new style based on s, with the underline attribute set +// as requested. func (s Style) Underline(on bool) Style { return s.setAttrs(Style(AttrUnderline), on) } diff --git a/tscreen.go b/tscreen.go index af36762..22b66e4 100644 --- a/tscreen.go +++ b/tscreen.go @@ -26,6 +26,14 @@ import ( "golang.org/x/text/transform" ) +// NewTerminfoScreen returns a Screen that uses the stock TTY interface +// and POSIX termios, combined with a terminfo description taken from +// the $TERM environment variable. It returns an error if the terminal +// is not supported for any reason. +// +// For terminals that do not support dynamic resize events, the $LINES +// $COLUMNS environment variables can be set to the actual window size, +// otherwise defaults taken from the terminal database are used. func NewTerminfoScreen() (Screen, error) { ti, e := LookupTerminfo(os.Getenv("TERM")) if e != nil { @@ -285,7 +293,6 @@ func (t *tScreen) GetCell(x, y int) *Cell { return &cell } - func (t *tScreen) encodeRune(r rune, buf []byte) []byte { // all the character sets we care about are ASCII supersets @@ -323,7 +330,7 @@ func (t *tScreen) encodeRune(r rune, buf []byte) []byte { buf = append(buf, '?') } } - } else { + } else { buf = append(buf, nb...) } } else if len(buf) == 0 { @@ -925,7 +932,7 @@ func (t *tScreen) parseRune(buf *bytes.Buffer) (bool, bool) { ev := NewEventKey(KeyRune, r, ModNone) t.PostEvent(ev) } - for eat := 0; eat < nin; eat++ { + for eat := 0; eat < nin; eat++ { buf.ReadByte() } return true, true diff --git a/tscreen_stub.go b/tscreen_stub.go index 91673bd..116d74c 100644 --- a/tscreen_stub.go +++ b/tscreen_stub.go @@ -20,6 +20,8 @@ import ( "errors" ) +// This stub file is for systems that have no termios. + type termiosPrivate struct{} func (t *tScreen) termioInit() error {