1// Copyright 2019 The TCell Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use file except in compliance with the License.
5// You may obtain a copy of the license at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package tcell
16
17import (
18	"bytes"
19	"io"
20	"os"
21	"strconv"
22	"sync"
23	"time"
24	"unicode/utf8"
25
26	"golang.org/x/text/transform"
27
28	"github.com/gdamore/tcell/terminfo"
29
30	// import the stock terminals
31	_ "github.com/gdamore/tcell/terminfo/base"
32)
33
34// NewTerminfoScreen returns a Screen that uses the stock TTY interface
35// and POSIX termios, combined with a terminfo description taken from
36// the $TERM environment variable.  It returns an error if the terminal
37// is not supported for any reason.
38//
39// For terminals that do not support dynamic resize events, the $LINES
40// $COLUMNS environment variables can be set to the actual window size,
41// otherwise defaults taken from the terminal database are used.
42func NewTerminfoScreen() (Screen, error) {
43	ti, e := terminfo.LookupTerminfo(os.Getenv("TERM"))
44	if e != nil {
45		ti, e = loadDynamicTerminfo(os.Getenv("TERM"))
46		if e != nil {
47			return nil, e
48		}
49		terminfo.AddTerminfo(ti)
50	}
51	t := &tScreen{ti: ti}
52
53	t.keyexist = make(map[Key]bool)
54	t.keycodes = make(map[string]*tKeyCode)
55	if len(ti.Mouse) > 0 {
56		t.mouse = []byte(ti.Mouse)
57	}
58	t.prepareKeys()
59	t.buildAcsMap()
60	t.sigwinch = make(chan os.Signal, 10)
61	t.fallback = make(map[rune]string)
62	for k, v := range RuneFallbacks {
63		t.fallback[k] = v
64	}
65
66	return t, nil
67}
68
69// tKeyCode represents a combination of a key code and modifiers.
70type tKeyCode struct {
71	key Key
72	mod ModMask
73}
74
75// tScreen represents a screen backed by a terminfo implementation.
76type tScreen struct {
77	ti        *terminfo.Terminfo
78	h         int
79	w         int
80	fini      bool
81	cells     CellBuffer
82	in        *os.File
83	out       *os.File
84	buffering bool // true if we are collecting writes to buf instead of sending directly to out
85	buf       bytes.Buffer
86	curstyle  Style
87	style     Style
88	evch      chan Event
89	sigwinch  chan os.Signal
90	quit      chan struct{}
91	indoneq   chan struct{}
92	keyexist  map[Key]bool
93	keycodes  map[string]*tKeyCode
94	keychan   chan []byte
95	keytimer  *time.Timer
96	keyexpire time.Time
97	cx        int
98	cy        int
99	mouse     []byte
100	clear     bool
101	cursorx   int
102	cursory   int
103	tiosp     *termiosPrivate
104	wasbtn    bool
105	acs       map[rune]string
106	charset   string
107	encoder   transform.Transformer
108	decoder   transform.Transformer
109	fallback  map[rune]string
110	colors    map[Color]Color
111	palette   []Color
112	truecolor bool
113	escaped   bool
114	buttondn  bool
115
116	sync.Mutex
117}
118
119func (t *tScreen) Init() error {
120	t.evch = make(chan Event, 10)
121	t.indoneq = make(chan struct{})
122	t.keychan = make(chan []byte, 10)
123	t.keytimer = time.NewTimer(time.Millisecond * 50)
124	t.charset = "UTF-8"
125
126	t.charset = getCharset()
127	if enc := GetEncoding(t.charset); enc != nil {
128		t.encoder = enc.NewEncoder()
129		t.decoder = enc.NewDecoder()
130	} else {
131		return ErrNoCharset
132	}
133	ti := t.ti
134
135	// environment overrides
136	w := ti.Columns
137	h := ti.Lines
138	if i, _ := strconv.Atoi(os.Getenv("LINES")); i != 0 {
139		h = i
140	}
141	if i, _ := strconv.Atoi(os.Getenv("COLUMNS")); i != 0 {
142		w = i
143	}
144	if e := t.termioInit(); e != nil {
145		return e
146	}
147
148	if t.ti.SetFgBgRGB != "" || t.ti.SetFgRGB != "" || t.ti.SetBgRGB != "" {
149		t.truecolor = true
150	}
151	// A user who wants to have his themes honored can
152	// set this environment variable.
153	if os.Getenv("TCELL_TRUECOLOR") == "disable" {
154		t.truecolor = false
155	}
156	if !t.truecolor {
157		t.colors = make(map[Color]Color)
158		t.palette = make([]Color, t.Colors())
159		for i := 0; i < t.Colors(); i++ {
160			t.palette[i] = Color(i)
161			// identity map for our builtin colors
162			t.colors[Color(i)] = Color(i)
163		}
164	}
165
166	t.TPuts(ti.EnterCA)
167	t.TPuts(ti.HideCursor)
168	t.TPuts(ti.EnableAcs)
169	t.TPuts(ti.Clear)
170
171	t.quit = make(chan struct{})
172
173	t.Lock()
174	t.cx = -1
175	t.cy = -1
176	t.style = StyleDefault
177	t.cells.Resize(w, h)
178	t.cursorx = -1
179	t.cursory = -1
180	t.resize()
181	t.Unlock()
182
183	go t.mainLoop()
184	go t.inputLoop()
185
186	return nil
187}
188
189func (t *tScreen) prepareKeyMod(key Key, mod ModMask, val string) {
190	if val != "" {
191		// Do not overrride codes that already exist
192		if _, exist := t.keycodes[val]; !exist {
193			t.keyexist[key] = true
194			t.keycodes[val] = &tKeyCode{key: key, mod: mod}
195		}
196	}
197}
198
199func (t *tScreen) prepareKey(key Key, val string) {
200	t.prepareKeyMod(key, ModNone, val)
201}
202
203func (t *tScreen) prepareKeys() {
204	ti := t.ti
205	t.prepareKey(KeyBackspace, ti.KeyBackspace)
206	t.prepareKey(KeyF1, ti.KeyF1)
207	t.prepareKey(KeyF2, ti.KeyF2)
208	t.prepareKey(KeyF3, ti.KeyF3)
209	t.prepareKey(KeyF4, ti.KeyF4)
210	t.prepareKey(KeyF5, ti.KeyF5)
211	t.prepareKey(KeyF6, ti.KeyF6)
212	t.prepareKey(KeyF7, ti.KeyF7)
213	t.prepareKey(KeyF8, ti.KeyF8)
214	t.prepareKey(KeyF9, ti.KeyF9)
215	t.prepareKey(KeyF10, ti.KeyF10)
216	t.prepareKey(KeyF11, ti.KeyF11)
217	t.prepareKey(KeyF12, ti.KeyF12)
218	t.prepareKey(KeyF13, ti.KeyF13)
219	t.prepareKey(KeyF14, ti.KeyF14)
220	t.prepareKey(KeyF15, ti.KeyF15)
221	t.prepareKey(KeyF16, ti.KeyF16)
222	t.prepareKey(KeyF17, ti.KeyF17)
223	t.prepareKey(KeyF18, ti.KeyF18)
224	t.prepareKey(KeyF19, ti.KeyF19)
225	t.prepareKey(KeyF20, ti.KeyF20)
226	t.prepareKey(KeyF21, ti.KeyF21)
227	t.prepareKey(KeyF22, ti.KeyF22)
228	t.prepareKey(KeyF23, ti.KeyF23)
229	t.prepareKey(KeyF24, ti.KeyF24)
230	t.prepareKey(KeyF25, ti.KeyF25)
231	t.prepareKey(KeyF26, ti.KeyF26)
232	t.prepareKey(KeyF27, ti.KeyF27)
233	t.prepareKey(KeyF28, ti.KeyF28)
234	t.prepareKey(KeyF29, ti.KeyF29)
235	t.prepareKey(KeyF30, ti.KeyF30)
236	t.prepareKey(KeyF31, ti.KeyF31)
237	t.prepareKey(KeyF32, ti.KeyF32)
238	t.prepareKey(KeyF33, ti.KeyF33)
239	t.prepareKey(KeyF34, ti.KeyF34)
240	t.prepareKey(KeyF35, ti.KeyF35)
241	t.prepareKey(KeyF36, ti.KeyF36)
242	t.prepareKey(KeyF37, ti.KeyF37)
243	t.prepareKey(KeyF38, ti.KeyF38)
244	t.prepareKey(KeyF39, ti.KeyF39)
245	t.prepareKey(KeyF40, ti.KeyF40)
246	t.prepareKey(KeyF41, ti.KeyF41)
247	t.prepareKey(KeyF42, ti.KeyF42)
248	t.prepareKey(KeyF43, ti.KeyF43)
249	t.prepareKey(KeyF44, ti.KeyF44)
250	t.prepareKey(KeyF45, ti.KeyF45)
251	t.prepareKey(KeyF46, ti.KeyF46)
252	t.prepareKey(KeyF47, ti.KeyF47)
253	t.prepareKey(KeyF48, ti.KeyF48)
254	t.prepareKey(KeyF49, ti.KeyF49)
255	t.prepareKey(KeyF50, ti.KeyF50)
256	t.prepareKey(KeyF51, ti.KeyF51)
257	t.prepareKey(KeyF52, ti.KeyF52)
258	t.prepareKey(KeyF53, ti.KeyF53)
259	t.prepareKey(KeyF54, ti.KeyF54)
260	t.prepareKey(KeyF55, ti.KeyF55)
261	t.prepareKey(KeyF56, ti.KeyF56)
262	t.prepareKey(KeyF57, ti.KeyF57)
263	t.prepareKey(KeyF58, ti.KeyF58)
264	t.prepareKey(KeyF59, ti.KeyF59)
265	t.prepareKey(KeyF60, ti.KeyF60)
266	t.prepareKey(KeyF61, ti.KeyF61)
267	t.prepareKey(KeyF62, ti.KeyF62)
268	t.prepareKey(KeyF63, ti.KeyF63)
269	t.prepareKey(KeyF64, ti.KeyF64)
270	t.prepareKey(KeyInsert, ti.KeyInsert)
271	t.prepareKey(KeyDelete, ti.KeyDelete)
272	t.prepareKey(KeyHome, ti.KeyHome)
273	t.prepareKey(KeyEnd, ti.KeyEnd)
274	t.prepareKey(KeyUp, ti.KeyUp)
275	t.prepareKey(KeyDown, ti.KeyDown)
276	t.prepareKey(KeyLeft, ti.KeyLeft)
277	t.prepareKey(KeyRight, ti.KeyRight)
278	t.prepareKey(KeyPgUp, ti.KeyPgUp)
279	t.prepareKey(KeyPgDn, ti.KeyPgDn)
280	t.prepareKey(KeyHelp, ti.KeyHelp)
281	t.prepareKey(KeyPrint, ti.KeyPrint)
282	t.prepareKey(KeyCancel, ti.KeyCancel)
283	t.prepareKey(KeyExit, ti.KeyExit)
284	t.prepareKey(KeyBacktab, ti.KeyBacktab)
285
286	t.prepareKeyMod(KeyRight, ModShift, ti.KeyShfRight)
287	t.prepareKeyMod(KeyLeft, ModShift, ti.KeyShfLeft)
288	t.prepareKeyMod(KeyUp, ModShift, ti.KeyShfUp)
289	t.prepareKeyMod(KeyDown, ModShift, ti.KeyShfDown)
290	t.prepareKeyMod(KeyHome, ModShift, ti.KeyShfHome)
291	t.prepareKeyMod(KeyEnd, ModShift, ti.KeyShfEnd)
292
293	t.prepareKeyMod(KeyRight, ModCtrl, ti.KeyCtrlRight)
294	t.prepareKeyMod(KeyLeft, ModCtrl, ti.KeyCtrlLeft)
295	t.prepareKeyMod(KeyUp, ModCtrl, ti.KeyCtrlUp)
296	t.prepareKeyMod(KeyDown, ModCtrl, ti.KeyCtrlDown)
297	t.prepareKeyMod(KeyHome, ModCtrl, ti.KeyCtrlHome)
298	t.prepareKeyMod(KeyEnd, ModCtrl, ti.KeyCtrlEnd)
299
300	t.prepareKeyMod(KeyRight, ModAlt, ti.KeyAltRight)
301	t.prepareKeyMod(KeyLeft, ModAlt, ti.KeyAltLeft)
302	t.prepareKeyMod(KeyUp, ModAlt, ti.KeyAltUp)
303	t.prepareKeyMod(KeyDown, ModAlt, ti.KeyAltDown)
304	t.prepareKeyMod(KeyHome, ModAlt, ti.KeyAltHome)
305	t.prepareKeyMod(KeyEnd, ModAlt, ti.KeyAltEnd)
306
307	t.prepareKeyMod(KeyRight, ModAlt, ti.KeyMetaRight)
308	t.prepareKeyMod(KeyLeft, ModAlt, ti.KeyMetaLeft)
309	t.prepareKeyMod(KeyUp, ModAlt, ti.KeyMetaUp)
310	t.prepareKeyMod(KeyDown, ModAlt, ti.KeyMetaDown)
311	t.prepareKeyMod(KeyHome, ModAlt, ti.KeyMetaHome)
312	t.prepareKeyMod(KeyEnd, ModAlt, ti.KeyMetaEnd)
313
314	t.prepareKeyMod(KeyRight, ModAlt|ModShift, ti.KeyAltShfRight)
315	t.prepareKeyMod(KeyLeft, ModAlt|ModShift, ti.KeyAltShfLeft)
316	t.prepareKeyMod(KeyUp, ModAlt|ModShift, ti.KeyAltShfUp)
317	t.prepareKeyMod(KeyDown, ModAlt|ModShift, ti.KeyAltShfDown)
318	t.prepareKeyMod(KeyHome, ModAlt|ModShift, ti.KeyAltShfHome)
319	t.prepareKeyMod(KeyEnd, ModAlt|ModShift, ti.KeyAltShfEnd)
320
321	t.prepareKeyMod(KeyRight, ModAlt|ModShift, ti.KeyMetaShfRight)
322	t.prepareKeyMod(KeyLeft, ModAlt|ModShift, ti.KeyMetaShfLeft)
323	t.prepareKeyMod(KeyUp, ModAlt|ModShift, ti.KeyMetaShfUp)
324	t.prepareKeyMod(KeyDown, ModAlt|ModShift, ti.KeyMetaShfDown)
325	t.prepareKeyMod(KeyHome, ModAlt|ModShift, ti.KeyMetaShfHome)
326	t.prepareKeyMod(KeyEnd, ModAlt|ModShift, ti.KeyMetaShfEnd)
327
328	t.prepareKeyMod(KeyRight, ModCtrl|ModShift, ti.KeyCtrlShfRight)
329	t.prepareKeyMod(KeyLeft, ModCtrl|ModShift, ti.KeyCtrlShfLeft)
330	t.prepareKeyMod(KeyUp, ModCtrl|ModShift, ti.KeyCtrlShfUp)
331	t.prepareKeyMod(KeyDown, ModCtrl|ModShift, ti.KeyCtrlShfDown)
332	t.prepareKeyMod(KeyHome, ModCtrl|ModShift, ti.KeyCtrlShfHome)
333	t.prepareKeyMod(KeyEnd, ModCtrl|ModShift, ti.KeyCtrlShfEnd)
334
335	// Sadly, xterm handling of keycodes is somewhat erratic.  In
336	// particular, different codes are sent depending on application
337	// mode is in use or not, and the entries for many of these are
338	// simply absent from terminfo on many systems.  So we insert
339	// a number of escape sequences if they are not already used, in
340	// order to have the widest correct usage.  Note that prepareKey
341	// will not inject codes if the escape sequence is already known.
342	// We also only do this for terminals that have the application
343	// mode present.
344
345	// Cursor mode
346	if ti.EnterKeypad != "" {
347		t.prepareKey(KeyUp, "\x1b[A")
348		t.prepareKey(KeyDown, "\x1b[B")
349		t.prepareKey(KeyRight, "\x1b[C")
350		t.prepareKey(KeyLeft, "\x1b[D")
351		t.prepareKey(KeyEnd, "\x1b[F")
352		t.prepareKey(KeyHome, "\x1b[H")
353		t.prepareKey(KeyDelete, "\x1b[3~")
354		t.prepareKey(KeyHome, "\x1b[1~")
355		t.prepareKey(KeyEnd, "\x1b[4~")
356		t.prepareKey(KeyPgUp, "\x1b[5~")
357		t.prepareKey(KeyPgDn, "\x1b[6~")
358
359		// Application mode
360		t.prepareKey(KeyUp, "\x1bOA")
361		t.prepareKey(KeyDown, "\x1bOB")
362		t.prepareKey(KeyRight, "\x1bOC")
363		t.prepareKey(KeyLeft, "\x1bOD")
364		t.prepareKey(KeyHome, "\x1bOH")
365	}
366
367outer:
368	// Add key mappings for control keys.
369	for i := 0; i < ' '; i++ {
370		// Do not insert direct key codes for ambiguous keys.
371		// For example, ESC is used for lots of other keys, so
372		// when parsing this we don't want to fast path handling
373		// of it, but instead wait a bit before parsing it as in
374		// isolation.
375		for esc := range t.keycodes {
376			if []byte(esc)[0] == byte(i) {
377				continue outer
378			}
379		}
380
381		t.keyexist[Key(i)] = true
382
383		mod := ModCtrl
384		switch Key(i) {
385		case KeyBS, KeyTAB, KeyESC, KeyCR:
386			// directly typeable- no control sequence
387			mod = ModNone
388		}
389		t.keycodes[string(rune(i))] = &tKeyCode{key: Key(i), mod: mod}
390	}
391}
392
393func (t *tScreen) Fini() {
394	t.Lock()
395	defer t.Unlock()
396
397	ti := t.ti
398	t.cells.Resize(0, 0)
399	t.TPuts(ti.ShowCursor)
400	t.TPuts(ti.AttrOff)
401	t.TPuts(ti.Clear)
402	t.TPuts(ti.ExitCA)
403	t.TPuts(ti.ExitKeypad)
404	t.TPuts(ti.TParm(ti.MouseMode, 0))
405	t.curstyle = Style(-1)
406	t.clear = false
407	t.fini = true
408
409	select {
410	case <-t.quit:
411		// do nothing, already closed
412
413	default:
414		close(t.quit)
415	}
416
417	t.termioFini()
418}
419
420func (t *tScreen) SetStyle(style Style) {
421	t.Lock()
422	if !t.fini {
423		t.style = style
424	}
425	t.Unlock()
426}
427
428func (t *tScreen) Clear() {
429	t.Fill(' ', t.style)
430}
431
432func (t *tScreen) Fill(r rune, style Style) {
433	t.Lock()
434	if !t.fini {
435		t.cells.Fill(r, style)
436	}
437	t.Unlock()
438}
439
440func (t *tScreen) SetContent(x, y int, mainc rune, combc []rune, style Style) {
441	t.Lock()
442	if !t.fini {
443		t.cells.SetContent(x, y, mainc, combc, style)
444	}
445	t.Unlock()
446}
447
448func (t *tScreen) GetContent(x, y int) (rune, []rune, Style, int) {
449	t.Lock()
450	mainc, combc, style, width := t.cells.GetContent(x, y)
451	t.Unlock()
452	return mainc, combc, style, width
453}
454
455func (t *tScreen) SetCell(x, y int, style Style, ch ...rune) {
456	if len(ch) > 0 {
457		t.SetContent(x, y, ch[0], ch[1:], style)
458	} else {
459		t.SetContent(x, y, ' ', nil, style)
460	}
461}
462
463func (t *tScreen) encodeRune(r rune, buf []byte) []byte {
464
465	nb := make([]byte, 6)
466	ob := make([]byte, 6)
467	num := utf8.EncodeRune(ob, r)
468	ob = ob[:num]
469	dst := 0
470	var err error
471	if enc := t.encoder; enc != nil {
472		enc.Reset()
473		dst, _, err = enc.Transform(nb, ob, true)
474	}
475	if err != nil || dst == 0 || nb[0] == '\x1a' {
476		// Combining characters are elided
477		if len(buf) == 0 {
478			if acs, ok := t.acs[r]; ok {
479				buf = append(buf, []byte(acs)...)
480			} else if fb, ok := t.fallback[r]; ok {
481				buf = append(buf, []byte(fb)...)
482			} else {
483				buf = append(buf, '?')
484			}
485		}
486	} else {
487		buf = append(buf, nb[:dst]...)
488	}
489
490	return buf
491}
492
493func (t *tScreen) sendFgBg(fg Color, bg Color) {
494	ti := t.ti
495	if ti.Colors == 0 {
496		return
497	}
498	if t.truecolor {
499		if ti.SetFgBgRGB != "" &&
500			fg != ColorDefault && bg != ColorDefault {
501			r1, g1, b1 := fg.RGB()
502			r2, g2, b2 := bg.RGB()
503			t.TPuts(ti.TParm(ti.SetFgBgRGB,
504				int(r1), int(g1), int(b1),
505				int(r2), int(g2), int(b2)))
506		} else {
507			if fg != ColorDefault && ti.SetFgRGB != "" {
508				r, g, b := fg.RGB()
509				t.TPuts(ti.TParm(ti.SetFgRGB,
510					int(r), int(g), int(b)))
511			}
512			if bg != ColorDefault && ti.SetBgRGB != "" {
513				r, g, b := bg.RGB()
514				t.TPuts(ti.TParm(ti.SetBgRGB,
515					int(r), int(g), int(b)))
516			}
517		}
518		return
519	}
520
521	if fg != ColorDefault {
522		if v, ok := t.colors[fg]; ok {
523			fg = v
524		} else {
525			v = FindColor(fg, t.palette)
526			t.colors[fg] = v
527			fg = v
528		}
529	}
530
531	if bg != ColorDefault {
532		if v, ok := t.colors[bg]; ok {
533			bg = v
534		} else {
535			v = FindColor(bg, t.palette)
536			t.colors[bg] = v
537			bg = v
538		}
539	}
540
541	if ti.SetFgBg != "" && fg != ColorDefault && bg != ColorDefault {
542		t.TPuts(ti.TParm(ti.SetFgBg, int(fg), int(bg)))
543	} else {
544		if fg != ColorDefault && ti.SetFg != "" {
545			t.TPuts(ti.TParm(ti.SetFg, int(fg)))
546		}
547		if bg != ColorDefault && ti.SetBg != "" {
548			t.TPuts(ti.TParm(ti.SetBg, int(bg)))
549		}
550	}
551}
552
553func (t *tScreen) drawCell(x, y int) int {
554
555	ti := t.ti
556
557	mainc, combc, style, width := t.cells.GetContent(x, y)
558	if !t.cells.Dirty(x, y) {
559		return width
560	}
561
562	if t.cy != y || t.cx != x {
563		t.TPuts(ti.TGoto(x, y))
564		t.cx = x
565		t.cy = y
566	}
567
568	if style == StyleDefault {
569		style = t.style
570	}
571	if style != t.curstyle {
572		fg, bg, attrs := style.Decompose()
573
574		t.TPuts(ti.AttrOff)
575
576		t.sendFgBg(fg, bg)
577		if attrs&AttrBold != 0 {
578			t.TPuts(ti.Bold)
579		}
580		if attrs&AttrUnderline != 0 {
581			t.TPuts(ti.Underline)
582		}
583		if attrs&AttrReverse != 0 {
584			t.TPuts(ti.Reverse)
585		}
586		if attrs&AttrBlink != 0 {
587			t.TPuts(ti.Blink)
588		}
589		if attrs&AttrDim != 0 {
590			t.TPuts(ti.Dim)
591		}
592		t.curstyle = style
593	}
594	// now emit runes - taking care to not overrun width with a
595	// wide character, and to ensure that we emit exactly one regular
596	// character followed up by any residual combing characters
597
598	if width < 1 {
599		width = 1
600	}
601
602	var str string
603
604	buf := make([]byte, 0, 6)
605
606	buf = t.encodeRune(mainc, buf)
607	for _, r := range combc {
608		buf = t.encodeRune(r, buf)
609	}
610
611	str = string(buf)
612	if width > 1 && str == "?" {
613		// No FullWidth character support
614		str = "? "
615		t.cx = -1
616	}
617
618	// XXX: check for hazeltine not being able to display ~
619
620	if x > t.w-width {
621		// too wide to fit; emit a single space instead
622		width = 1
623		str = " "
624	}
625	t.writeString(str)
626	t.cx += width
627	t.cells.SetDirty(x, y, false)
628	if width > 1 {
629		t.cx = -1
630	}
631
632	return width
633}
634
635func (t *tScreen) ShowCursor(x, y int) {
636	t.Lock()
637	t.cursorx = x
638	t.cursory = y
639	t.Unlock()
640}
641
642func (t *tScreen) HideCursor() {
643	t.ShowCursor(-1, -1)
644}
645
646func (t *tScreen) showCursor() {
647
648	x, y := t.cursorx, t.cursory
649	w, h := t.cells.Size()
650	if x < 0 || y < 0 || x >= w || y >= h {
651		t.hideCursor()
652		return
653	}
654	t.TPuts(t.ti.TGoto(x, y))
655	t.TPuts(t.ti.ShowCursor)
656	t.cx = x
657	t.cy = y
658}
659
660// writeString sends a string to the terminal. The string is sent as-is and
661// this function does not expand inline padding indications (of the form
662// $<[delay]> where [delay] is msec). In order to have these expanded, use
663// TPuts. If the screen is "buffering", the string is collected in a buffer,
664// with the intention that the entire buffer be sent to the terminal in one
665// write operation at some point later.
666func (t *tScreen) writeString(s string) {
667	if t.buffering {
668		io.WriteString(&t.buf, s)
669	} else {
670		io.WriteString(t.out, s)
671	}
672}
673
674func (t *tScreen) TPuts(s string) {
675	if t.buffering {
676		t.ti.TPuts(&t.buf, s)
677	} else {
678		t.ti.TPuts(t.out, s)
679	}
680}
681
682func (t *tScreen) Show() {
683	t.Lock()
684	if !t.fini {
685		t.resize()
686		t.draw()
687	}
688	t.Unlock()
689}
690
691func (t *tScreen) clearScreen() {
692	fg, bg, _ := t.style.Decompose()
693	t.sendFgBg(fg, bg)
694	t.TPuts(t.ti.Clear)
695	t.clear = false
696}
697
698func (t *tScreen) hideCursor() {
699	// does not update cursor position
700	if t.ti.HideCursor != "" {
701		t.TPuts(t.ti.HideCursor)
702	} else {
703		// No way to hide cursor, stick it
704		// at bottom right of screen
705		t.cx, t.cy = t.cells.Size()
706		t.TPuts(t.ti.TGoto(t.cx, t.cy))
707	}
708}
709
710func (t *tScreen) draw() {
711	// clobber cursor position, because we're gonna change it all
712	t.cx = -1
713	t.cy = -1
714
715	t.buf.Reset()
716	t.buffering = true
717	defer func() {
718		t.buffering = false
719	}()
720
721	// hide the cursor while we move stuff around
722	t.hideCursor()
723
724	if t.clear {
725		t.clearScreen()
726	}
727
728	for y := 0; y < t.h; y++ {
729		for x := 0; x < t.w; x++ {
730			width := t.drawCell(x, y)
731			if width > 1 {
732				if x+1 < t.w {
733					// this is necessary so that if we ever
734					// go back to drawing that cell, we
735					// actually will *draw* it.
736					t.cells.SetDirty(x+1, y, true)
737				}
738			}
739			x += width - 1
740		}
741	}
742
743	// restore the cursor
744	t.showCursor()
745
746	t.buf.WriteTo(t.out)
747}
748
749func (t *tScreen) EnableMouse() {
750	if len(t.mouse) != 0 {
751		t.TPuts(t.ti.TParm(t.ti.MouseMode, 1))
752	}
753}
754
755func (t *tScreen) DisableMouse() {
756	if len(t.mouse) != 0 {
757		t.TPuts(t.ti.TParm(t.ti.MouseMode, 0))
758	}
759}
760
761func (t *tScreen) Size() (int, int) {
762	t.Lock()
763	w, h := t.w, t.h
764	t.Unlock()
765	return w, h
766}
767
768func (t *tScreen) resize() {
769	if w, h, e := t.getWinSize(); e == nil {
770		if w != t.w || h != t.h {
771			t.cx = -1
772			t.cy = -1
773
774			t.cells.Resize(w, h)
775			t.cells.Invalidate()
776			t.h = h
777			t.w = w
778			ev := NewEventResize(w, h)
779			t.PostEvent(ev)
780		}
781	}
782}
783
784func (t *tScreen) Colors() int {
785	// this doesn't change, no need for lock
786	if t.truecolor {
787		return 1 << 24
788	}
789	return t.ti.Colors
790}
791
792func (t *tScreen) PollEvent() Event {
793	select {
794	case <-t.quit:
795		return nil
796	case ev := <-t.evch:
797		return ev
798	}
799}
800
801// vtACSNames is a map of bytes defined by terminfo that are used in
802// the terminals Alternate Character Set to represent other glyphs.
803// For example, the upper left corner of the box drawing set can be
804// displayed by printing "l" while in the alternate character set.
805// Its not quite that simple, since the "l" is the terminfo name,
806// and it may be necessary to use a different character based on
807// the terminal implementation (or the terminal may lack support for
808// this altogether).  See buildAcsMap below for detail.
809var vtACSNames = map[byte]rune{
810	'+': RuneRArrow,
811	',': RuneLArrow,
812	'-': RuneUArrow,
813	'.': RuneDArrow,
814	'0': RuneBlock,
815	'`': RuneDiamond,
816	'a': RuneCkBoard,
817	'b': '␉', // VT100, Not defined by terminfo
818	'c': '␌', // VT100, Not defined by terminfo
819	'd': '␋', // VT100, Not defined by terminfo
820	'e': '␊', // VT100, Not defined by terminfo
821	'f': RuneDegree,
822	'g': RunePlMinus,
823	'h': RuneBoard,
824	'i': RuneLantern,
825	'j': RuneLRCorner,
826	'k': RuneURCorner,
827	'l': RuneULCorner,
828	'm': RuneLLCorner,
829	'n': RunePlus,
830	'o': RuneS1,
831	'p': RuneS3,
832	'q': RuneHLine,
833	'r': RuneS7,
834	's': RuneS9,
835	't': RuneLTee,
836	'u': RuneRTee,
837	'v': RuneBTee,
838	'w': RuneTTee,
839	'x': RuneVLine,
840	'y': RuneLEqual,
841	'z': RuneGEqual,
842	'{': RunePi,
843	'|': RuneNEqual,
844	'}': RuneSterling,
845	'~': RuneBullet,
846}
847
848// buildAcsMap builds a map of characters that we translate from Unicode to
849// alternate character encodings.  To do this, we use the standard VT100 ACS
850// maps.  This is only done if the terminal lacks support for Unicode; we
851// always prefer to emit Unicode glyphs when we are able.
852func (t *tScreen) buildAcsMap() {
853	acsstr := t.ti.AltChars
854	t.acs = make(map[rune]string)
855	for len(acsstr) > 2 {
856		srcv := acsstr[0]
857		dstv := string(acsstr[1])
858		if r, ok := vtACSNames[srcv]; ok {
859			t.acs[r] = t.ti.EnterAcs + dstv + t.ti.ExitAcs
860		}
861		acsstr = acsstr[2:]
862	}
863}
864
865func (t *tScreen) PostEventWait(ev Event) {
866	t.evch <- ev
867}
868
869func (t *tScreen) PostEvent(ev Event) error {
870	select {
871	case t.evch <- ev:
872		return nil
873	default:
874		return ErrEventQFull
875	}
876}
877
878func (t *tScreen) clip(x, y int) (int, int) {
879	w, h := t.cells.Size()
880	if x < 0 {
881		x = 0
882	}
883	if y < 0 {
884		y = 0
885	}
886	if x > w-1 {
887		x = w - 1
888	}
889	if y > h-1 {
890		y = h - 1
891	}
892	return x, y
893}
894
895// buildMouseEvent returns an event based on the supplied coordinates and button
896// state. Note that the screen's mouse button state is updated based on the
897// input to this function (i.e. it mutates the receiver).
898func (t *tScreen) buildMouseEvent(x, y, btn int) *EventMouse {
899
900	// XTerm mouse events only report at most one button at a time,
901	// which may include a wheel button.  Wheel motion events are
902	// reported as single impulses, while other button events are reported
903	// as separate press & release events.
904
905	button := ButtonNone
906	mod := ModNone
907
908	// Mouse wheel has bit 6 set, no release events.  It should be noted
909	// that wheel events are sometimes misdelivered as mouse button events
910	// during a click-drag, so we debounce these, considering them to be
911	// button press events unless we see an intervening release event.
912	switch btn & 0x43 {
913	case 0:
914		button = Button1
915		t.wasbtn = true
916	case 1:
917		button = Button2
918		t.wasbtn = true
919	case 2:
920		button = Button3
921		t.wasbtn = true
922	case 3:
923		button = ButtonNone
924		t.wasbtn = false
925	case 0x40:
926		if !t.wasbtn {
927			button = WheelUp
928		} else {
929			button = Button1
930		}
931	case 0x41:
932		if !t.wasbtn {
933			button = WheelDown
934		} else {
935			button = Button2
936		}
937	}
938
939	if btn&0x4 != 0 {
940		mod |= ModShift
941	}
942	if btn&0x8 != 0 {
943		mod |= ModAlt
944	}
945	if btn&0x10 != 0 {
946		mod |= ModCtrl
947	}
948
949	// Some terminals will report mouse coordinates outside the
950	// screen, especially with click-drag events.  Clip the coordinates
951	// to the screen in that case.
952	x, y = t.clip(x, y)
953
954	return NewEventMouse(x, y, button, mod)
955}
956
957// parseSgrMouse attempts to locate an SGR mouse record at the start of the
958// buffer.  It returns true, true if it found one, and the associated bytes
959// be removed from the buffer.  It returns true, false if the buffer might
960// contain such an event, but more bytes are necessary (partial match), and
961// false, false if the content is definitely *not* an SGR mouse record.
962func (t *tScreen) parseSgrMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
963
964	b := buf.Bytes()
965
966	var x, y, btn, state int
967	dig := false
968	neg := false
969	motion := false
970	i := 0
971	val := 0
972
973	for i = range b {
974		switch b[i] {
975		case '\x1b':
976			if state != 0 {
977				return false, false
978			}
979			state = 1
980
981		case '\x9b':
982			if state != 0 {
983				return false, false
984			}
985			state = 2
986
987		case '[':
988			if state != 1 {
989				return false, false
990			}
991			state = 2
992
993		case '<':
994			if state != 2 {
995				return false, false
996			}
997			val = 0
998			dig = false
999			neg = false
1000			state = 3
1001
1002		case '-':
1003			if state != 3 && state != 4 && state != 5 {
1004				return false, false
1005			}
1006			if dig || neg {
1007				return false, false
1008			}
1009			neg = true // stay in state
1010
1011		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
1012			if state != 3 && state != 4 && state != 5 {
1013				return false, false
1014			}
1015			val *= 10
1016			val += int(b[i] - '0')
1017			dig = true // stay in state
1018
1019		case ';':
1020			if neg {
1021				val = -val
1022			}
1023			switch state {
1024			case 3:
1025				btn, val = val, 0
1026				neg, dig, state = false, false, 4
1027			case 4:
1028				x, val = val-1, 0
1029				neg, dig, state = false, false, 5
1030			default:
1031				return false, false
1032			}
1033
1034		case 'm', 'M':
1035			if state != 5 {
1036				return false, false
1037			}
1038			if neg {
1039				val = -val
1040			}
1041			y = val - 1
1042
1043			motion = (btn & 32) != 0
1044			btn &^= 32
1045			if b[i] == 'm' {
1046				// mouse release, clear all buttons
1047				btn |= 3
1048				btn &^= 0x40
1049				t.buttondn = false
1050			} else if motion {
1051				/*
1052				 * Some broken terminals appear to send
1053				 * mouse button one motion events, instead of
1054				 * encoding 35 (no buttons) into these events.
1055				 * We resolve these by looking for a non-motion
1056				 * event first.
1057				 */
1058				if !t.buttondn {
1059					btn |= 3
1060					btn &^= 0x40
1061				}
1062			} else {
1063				t.buttondn = true
1064			}
1065			// consume the event bytes
1066			for i >= 0 {
1067				buf.ReadByte()
1068				i--
1069			}
1070			*evs = append(*evs, t.buildMouseEvent(x, y, btn))
1071			return true, true
1072		}
1073	}
1074
1075	// incomplete & inconclusve at this point
1076	return true, false
1077}
1078
1079// parseXtermMouse is like parseSgrMouse, but it parses a legacy
1080// X11 mouse record.
1081func (t *tScreen) parseXtermMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
1082
1083	b := buf.Bytes()
1084
1085	state := 0
1086	btn := 0
1087	x := 0
1088	y := 0
1089
1090	for i := range b {
1091		switch state {
1092		case 0:
1093			switch b[i] {
1094			case '\x1b':
1095				state = 1
1096			case '\x9b':
1097				state = 2
1098			default:
1099				return false, false
1100			}
1101		case 1:
1102			if b[i] != '[' {
1103				return false, false
1104			}
1105			state = 2
1106		case 2:
1107			if b[i] != 'M' {
1108				return false, false
1109			}
1110			state++
1111		case 3:
1112			btn = int(b[i])
1113			state++
1114		case 4:
1115			x = int(b[i]) - 32 - 1
1116			state++
1117		case 5:
1118			y = int(b[i]) - 32 - 1
1119			for i >= 0 {
1120				buf.ReadByte()
1121				i--
1122			}
1123			*evs = append(*evs, t.buildMouseEvent(x, y, btn))
1124			return true, true
1125		}
1126	}
1127	return true, false
1128}
1129
1130func (t *tScreen) parseFunctionKey(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
1131	b := buf.Bytes()
1132	partial := false
1133	for e, k := range t.keycodes {
1134		esc := []byte(e)
1135		if (len(esc) == 1) && (esc[0] == '\x1b') {
1136			continue
1137		}
1138		if bytes.HasPrefix(b, esc) {
1139			// matched
1140			var r rune
1141			if len(esc) == 1 {
1142				r = rune(b[0])
1143			}
1144			mod := k.mod
1145			if t.escaped {
1146				mod |= ModAlt
1147				t.escaped = false
1148			}
1149			*evs = append(*evs, NewEventKey(k.key, r, mod))
1150			for i := 0; i < len(esc); i++ {
1151				buf.ReadByte()
1152			}
1153			return true, true
1154		}
1155		if bytes.HasPrefix(esc, b) {
1156			partial = true
1157		}
1158	}
1159	return partial, false
1160}
1161
1162func (t *tScreen) parseRune(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
1163	b := buf.Bytes()
1164	if b[0] >= ' ' && b[0] <= 0x7F {
1165		// printable ASCII easy to deal with -- no encodings
1166		mod := ModNone
1167		if t.escaped {
1168			mod = ModAlt
1169			t.escaped = false
1170		}
1171		*evs = append(*evs, NewEventKey(KeyRune, rune(b[0]), mod))
1172		buf.ReadByte()
1173		return true, true
1174	}
1175
1176	if b[0] < 0x80 {
1177		// Low numbered values are control keys, not runes.
1178		return false, false
1179	}
1180
1181	utfb := make([]byte, 12)
1182	for l := 1; l <= len(b); l++ {
1183		t.decoder.Reset()
1184		nout, nin, e := t.decoder.Transform(utfb, b[:l], true)
1185		if e == transform.ErrShortSrc {
1186			continue
1187		}
1188		if nout != 0 {
1189			r, _ := utf8.DecodeRune(utfb[:nout])
1190			if r != utf8.RuneError {
1191				mod := ModNone
1192				if t.escaped {
1193					mod = ModAlt
1194					t.escaped = false
1195				}
1196				*evs = append(*evs, NewEventKey(KeyRune, r, mod))
1197			}
1198			for nin > 0 {
1199				buf.ReadByte()
1200				nin--
1201			}
1202			return true, true
1203		}
1204	}
1205	// Looks like potential escape
1206	return true, false
1207}
1208
1209func (t *tScreen) scanInput(buf *bytes.Buffer, expire bool) {
1210	evs := t.collectEventsFromInput(buf, expire)
1211
1212	for _, ev := range evs {
1213		t.PostEventWait(ev)
1214	}
1215}
1216
1217// Return an array of Events extracted from the supplied buffer. This is done
1218// while holding the screen's lock - the events can then be queued for
1219// application processing with the lock released.
1220func (t *tScreen) collectEventsFromInput(buf *bytes.Buffer, expire bool) []Event {
1221
1222	res := make([]Event, 0, 20)
1223
1224	t.Lock()
1225	defer t.Unlock()
1226
1227	for {
1228		b := buf.Bytes()
1229		if len(b) == 0 {
1230			buf.Reset()
1231			return res
1232		}
1233
1234		partials := 0
1235
1236		if part, comp := t.parseRune(buf, &res); comp {
1237			continue
1238		} else if part {
1239			partials++
1240		}
1241
1242		if part, comp := t.parseFunctionKey(buf, &res); comp {
1243			continue
1244		} else if part {
1245			partials++
1246		}
1247
1248		// Only parse mouse records if this term claims to have
1249		// mouse support
1250
1251		if t.ti.Mouse != "" {
1252			if part, comp := t.parseXtermMouse(buf, &res); comp {
1253				continue
1254			} else if part {
1255				partials++
1256			}
1257
1258			if part, comp := t.parseSgrMouse(buf, &res); comp {
1259				continue
1260			} else if part {
1261				partials++
1262			}
1263		}
1264
1265		if partials == 0 || expire {
1266			if b[0] == '\x1b' {
1267				if len(b) == 1 {
1268					res = append(res, NewEventKey(KeyEsc, 0, ModNone))
1269					t.escaped = false
1270				} else {
1271					t.escaped = true
1272				}
1273				buf.ReadByte()
1274				continue
1275			}
1276			// Nothing was going to match, or we timed out
1277			// waiting for more data -- just deliver the characters
1278			// to the app & let them sort it out.  Possibly we
1279			// should only do this for control characters like ESC.
1280			by, _ := buf.ReadByte()
1281			mod := ModNone
1282			if t.escaped {
1283				t.escaped = false
1284				mod = ModAlt
1285			}
1286			res = append(res, NewEventKey(KeyRune, rune(by), mod))
1287			continue
1288		}
1289
1290		// well we have some partial data, wait until we get
1291		// some more
1292		break
1293	}
1294
1295	return res
1296}
1297
1298func (t *tScreen) mainLoop() {
1299	buf := &bytes.Buffer{}
1300	for {
1301		select {
1302		case <-t.quit:
1303			close(t.indoneq)
1304			return
1305		case <-t.sigwinch:
1306			t.Lock()
1307			t.cx = -1
1308			t.cy = -1
1309			t.resize()
1310			t.cells.Invalidate()
1311			t.draw()
1312			t.Unlock()
1313			continue
1314		case <-t.keytimer.C:
1315			// If the timer fired, and the current time
1316			// is after the expiration of the escape sequence,
1317			// then we assume the escape sequence reached it's
1318			// conclusion, and process the chunk independently.
1319			// This lets us detect conflicts such as a lone ESC.
1320			if buf.Len() > 0 {
1321				if time.Now().After(t.keyexpire) {
1322					t.scanInput(buf, true)
1323				}
1324			}
1325			if buf.Len() > 0 {
1326				if !t.keytimer.Stop() {
1327					select {
1328					case <-t.keytimer.C:
1329					default:
1330					}
1331				}
1332				t.keytimer.Reset(time.Millisecond * 50)
1333			}
1334		case chunk := <-t.keychan:
1335			buf.Write(chunk)
1336			t.keyexpire = time.Now().Add(time.Millisecond * 50)
1337			t.scanInput(buf, false)
1338			if !t.keytimer.Stop() {
1339				select {
1340				case <-t.keytimer.C:
1341				default:
1342				}
1343			}
1344			if buf.Len() > 0 {
1345				t.keytimer.Reset(time.Millisecond * 50)
1346			}
1347		}
1348	}
1349}
1350
1351func (t *tScreen) inputLoop() {
1352
1353	for {
1354		chunk := make([]byte, 128)
1355		n, e := t.in.Read(chunk)
1356		switch e {
1357		case io.EOF:
1358		case nil:
1359		default:
1360			t.PostEvent(NewEventError(e))
1361			return
1362		}
1363		t.keychan <- chunk[:n]
1364	}
1365}
1366
1367func (t *tScreen) Sync() {
1368	t.Lock()
1369	t.cx = -1
1370	t.cy = -1
1371	if !t.fini {
1372		t.resize()
1373		t.clear = true
1374		t.cells.Invalidate()
1375		t.draw()
1376	}
1377	t.Unlock()
1378}
1379
1380func (t *tScreen) CharacterSet() string {
1381	return t.charset
1382}
1383
1384func (t *tScreen) RegisterRuneFallback(orig rune, fallback string) {
1385	t.Lock()
1386	t.fallback[orig] = fallback
1387	t.Unlock()
1388}
1389
1390func (t *tScreen) UnregisterRuneFallback(orig rune) {
1391	t.Lock()
1392	delete(t.fallback, orig)
1393	t.Unlock()
1394}
1395
1396func (t *tScreen) CanDisplay(r rune, checkFallbacks bool) bool {
1397
1398	if enc := t.encoder; enc != nil {
1399		nb := make([]byte, 6)
1400		ob := make([]byte, 6)
1401		num := utf8.EncodeRune(ob, r)
1402
1403		enc.Reset()
1404		dst, _, err := enc.Transform(nb, ob[:num], true)
1405		if dst != 0 && err == nil && nb[0] != '\x1A' {
1406			return true
1407		}
1408	}
1409	// Terminal fallbacks always permitted, since we assume they are
1410	// basically nearly perfect renditions.
1411	if _, ok := t.acs[r]; ok {
1412		return true
1413	}
1414	if !checkFallbacks {
1415		return false
1416	}
1417	if _, ok := t.fallback[r]; ok {
1418		return true
1419	}
1420	return false
1421}
1422
1423func (t *tScreen) HasMouse() bool {
1424	return len(t.mouse) != 0
1425}
1426
1427func (t *tScreen) HasKey(k Key) bool {
1428	if k == KeyRune {
1429		return true
1430	}
1431	return t.keyexist[k]
1432}
1433
1434func (t *tScreen) Resize(int, int, int, int) {}
1435