1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package term
6
7import (
8	"bytes"
9	"io"
10	"runtime"
11	"strconv"
12	"sync"
13	"unicode/utf8"
14)
15
16// EscapeCodes contains escape sequences that can be written to the terminal in
17// order to achieve different styles of text.
18type EscapeCodes struct {
19	// Foreground colors
20	Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
21
22	// Reset all attributes
23	Reset []byte
24}
25
26var vt100EscapeCodes = EscapeCodes{
27	Black:   []byte{keyEscape, '[', '3', '0', 'm'},
28	Red:     []byte{keyEscape, '[', '3', '1', 'm'},
29	Green:   []byte{keyEscape, '[', '3', '2', 'm'},
30	Yellow:  []byte{keyEscape, '[', '3', '3', 'm'},
31	Blue:    []byte{keyEscape, '[', '3', '4', 'm'},
32	Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
33	Cyan:    []byte{keyEscape, '[', '3', '6', 'm'},
34	White:   []byte{keyEscape, '[', '3', '7', 'm'},
35
36	Reset: []byte{keyEscape, '[', '0', 'm'},
37}
38
39// Terminal contains the state for running a VT100 terminal that is capable of
40// reading lines of input.
41type Terminal struct {
42	// AutoCompleteCallback, if non-null, is called for each keypress with
43	// the full input line and the current position of the cursor (in
44	// bytes, as an index into |line|). If it returns ok=false, the key
45	// press is processed normally. Otherwise it returns a replacement line
46	// and the new cursor position.
47	AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
48
49	// Escape contains a pointer to the escape codes for this terminal.
50	// It's always a valid pointer, although the escape codes themselves
51	// may be empty if the terminal doesn't support them.
52	Escape *EscapeCodes
53
54	// lock protects the terminal and the state in this object from
55	// concurrent processing of a key press and a Write() call.
56	lock sync.Mutex
57
58	c      io.ReadWriter
59	prompt []rune
60
61	// line is the current line being entered.
62	line []rune
63	// pos is the logical position of the cursor in line
64	pos int
65	// echo is true if local echo is enabled
66	echo bool
67	// pasteActive is true iff there is a bracketed paste operation in
68	// progress.
69	pasteActive bool
70
71	// cursorX contains the current X value of the cursor where the left
72	// edge is 0. cursorY contains the row number where the first row of
73	// the current line is 0.
74	cursorX, cursorY int
75	// maxLine is the greatest value of cursorY so far.
76	maxLine int
77
78	termWidth, termHeight int
79
80	// outBuf contains the terminal data to be sent.
81	outBuf []byte
82	// remainder contains the remainder of any partial key sequences after
83	// a read. It aliases into inBuf.
84	remainder []byte
85	inBuf     [256]byte
86
87	// history contains previously entered commands so that they can be
88	// accessed with the up and down keys.
89	history stRingBuffer
90	// historyIndex stores the currently accessed history entry, where zero
91	// means the immediately previous entry.
92	historyIndex int
93	// When navigating up and down the history it's possible to return to
94	// the incomplete, initial line. That value is stored in
95	// historyPending.
96	historyPending string
97}
98
99// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
100// a local terminal, that terminal must first have been put into raw mode.
101// prompt is a string that is written at the start of each input line (i.e.
102// "> ").
103func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
104	return &Terminal{
105		Escape:       &vt100EscapeCodes,
106		c:            c,
107		prompt:       []rune(prompt),
108		termWidth:    80,
109		termHeight:   24,
110		echo:         true,
111		historyIndex: -1,
112	}
113}
114
115const (
116	keyCtrlC     = 3
117	keyCtrlD     = 4
118	keyCtrlU     = 21
119	keyEnter     = '\r'
120	keyEscape    = 27
121	keyBackspace = 127
122	keyUnknown   = 0xd800 /* UTF-16 surrogate area */ + iota
123	keyUp
124	keyDown
125	keyLeft
126	keyRight
127	keyAltLeft
128	keyAltRight
129	keyHome
130	keyEnd
131	keyDeleteWord
132	keyDeleteLine
133	keyClearScreen
134	keyPasteStart
135	keyPasteEnd
136)
137
138var (
139	crlf       = []byte{'\r', '\n'}
140	pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
141	pasteEnd   = []byte{keyEscape, '[', '2', '0', '1', '~'}
142)
143
144// bytesToKey tries to parse a key sequence from b. If successful, it returns
145// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
146func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
147	if len(b) == 0 {
148		return utf8.RuneError, nil
149	}
150
151	if !pasteActive {
152		switch b[0] {
153		case 1: // ^A
154			return keyHome, b[1:]
155		case 2: // ^B
156			return keyLeft, b[1:]
157		case 5: // ^E
158			return keyEnd, b[1:]
159		case 6: // ^F
160			return keyRight, b[1:]
161		case 8: // ^H
162			return keyBackspace, b[1:]
163		case 11: // ^K
164			return keyDeleteLine, b[1:]
165		case 12: // ^L
166			return keyClearScreen, b[1:]
167		case 23: // ^W
168			return keyDeleteWord, b[1:]
169		case 14: // ^N
170			return keyDown, b[1:]
171		case 16: // ^P
172			return keyUp, b[1:]
173		}
174	}
175
176	if b[0] != keyEscape {
177		if !utf8.FullRune(b) {
178			return utf8.RuneError, b
179		}
180		r, l := utf8.DecodeRune(b)
181		return r, b[l:]
182	}
183
184	if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
185		switch b[2] {
186		case 'A':
187			return keyUp, b[3:]
188		case 'B':
189			return keyDown, b[3:]
190		case 'C':
191			return keyRight, b[3:]
192		case 'D':
193			return keyLeft, b[3:]
194		case 'H':
195			return keyHome, b[3:]
196		case 'F':
197			return keyEnd, b[3:]
198		}
199	}
200
201	if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
202		switch b[5] {
203		case 'C':
204			return keyAltRight, b[6:]
205		case 'D':
206			return keyAltLeft, b[6:]
207		}
208	}
209
210	if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
211		return keyPasteStart, b[6:]
212	}
213
214	if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
215		return keyPasteEnd, b[6:]
216	}
217
218	// If we get here then we have a key that we don't recognise, or a
219	// partial sequence. It's not clear how one should find the end of a
220	// sequence without knowing them all, but it seems that [a-zA-Z~] only
221	// appears at the end of a sequence.
222	for i, c := range b[0:] {
223		if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
224			return keyUnknown, b[i+1:]
225		}
226	}
227
228	return utf8.RuneError, b
229}
230
231// queue appends data to the end of t.outBuf
232func (t *Terminal) queue(data []rune) {
233	t.outBuf = append(t.outBuf, []byte(string(data))...)
234}
235
236var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
237var space = []rune{' '}
238
239func isPrintable(key rune) bool {
240	isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
241	return key >= 32 && !isInSurrogateArea
242}
243
244// moveCursorToPos appends data to t.outBuf which will move the cursor to the
245// given, logical position in the text.
246func (t *Terminal) moveCursorToPos(pos int) {
247	if !t.echo {
248		return
249	}
250
251	x := visualLength(t.prompt) + pos
252	y := x / t.termWidth
253	x = x % t.termWidth
254
255	up := 0
256	if y < t.cursorY {
257		up = t.cursorY - y
258	}
259
260	down := 0
261	if y > t.cursorY {
262		down = y - t.cursorY
263	}
264
265	left := 0
266	if x < t.cursorX {
267		left = t.cursorX - x
268	}
269
270	right := 0
271	if x > t.cursorX {
272		right = x - t.cursorX
273	}
274
275	t.cursorX = x
276	t.cursorY = y
277	t.move(up, down, left, right)
278}
279
280func (t *Terminal) move(up, down, left, right int) {
281	m := []rune{}
282
283	// 1 unit up can be expressed as ^[[A or ^[A
284	// 5 units up can be expressed as ^[[5A
285
286	if up == 1 {
287		m = append(m, keyEscape, '[', 'A')
288	} else if up > 1 {
289		m = append(m, keyEscape, '[')
290		m = append(m, []rune(strconv.Itoa(up))...)
291		m = append(m, 'A')
292	}
293
294	if down == 1 {
295		m = append(m, keyEscape, '[', 'B')
296	} else if down > 1 {
297		m = append(m, keyEscape, '[')
298		m = append(m, []rune(strconv.Itoa(down))...)
299		m = append(m, 'B')
300	}
301
302	if right == 1 {
303		m = append(m, keyEscape, '[', 'C')
304	} else if right > 1 {
305		m = append(m, keyEscape, '[')
306		m = append(m, []rune(strconv.Itoa(right))...)
307		m = append(m, 'C')
308	}
309
310	if left == 1 {
311		m = append(m, keyEscape, '[', 'D')
312	} else if left > 1 {
313		m = append(m, keyEscape, '[')
314		m = append(m, []rune(strconv.Itoa(left))...)
315		m = append(m, 'D')
316	}
317
318	t.queue(m)
319}
320
321func (t *Terminal) clearLineToRight() {
322	op := []rune{keyEscape, '[', 'K'}
323	t.queue(op)
324}
325
326const maxLineLength = 4096
327
328func (t *Terminal) setLine(newLine []rune, newPos int) {
329	if t.echo {
330		t.moveCursorToPos(0)
331		t.writeLine(newLine)
332		for i := len(newLine); i < len(t.line); i++ {
333			t.writeLine(space)
334		}
335		t.moveCursorToPos(newPos)
336	}
337	t.line = newLine
338	t.pos = newPos
339}
340
341func (t *Terminal) advanceCursor(places int) {
342	t.cursorX += places
343	t.cursorY += t.cursorX / t.termWidth
344	if t.cursorY > t.maxLine {
345		t.maxLine = t.cursorY
346	}
347	t.cursorX = t.cursorX % t.termWidth
348
349	if places > 0 && t.cursorX == 0 {
350		// Normally terminals will advance the current position
351		// when writing a character. But that doesn't happen
352		// for the last character in a line. However, when
353		// writing a character (except a new line) that causes
354		// a line wrap, the position will be advanced two
355		// places.
356		//
357		// So, if we are stopping at the end of a line, we
358		// need to write a newline so that our cursor can be
359		// advanced to the next line.
360		t.outBuf = append(t.outBuf, '\r', '\n')
361	}
362}
363
364func (t *Terminal) eraseNPreviousChars(n int) {
365	if n == 0 {
366		return
367	}
368
369	if t.pos < n {
370		n = t.pos
371	}
372	t.pos -= n
373	t.moveCursorToPos(t.pos)
374
375	copy(t.line[t.pos:], t.line[n+t.pos:])
376	t.line = t.line[:len(t.line)-n]
377	if t.echo {
378		t.writeLine(t.line[t.pos:])
379		for i := 0; i < n; i++ {
380			t.queue(space)
381		}
382		t.advanceCursor(n)
383		t.moveCursorToPos(t.pos)
384	}
385}
386
387// countToLeftWord returns then number of characters from the cursor to the
388// start of the previous word.
389func (t *Terminal) countToLeftWord() int {
390	if t.pos == 0 {
391		return 0
392	}
393
394	pos := t.pos - 1
395	for pos > 0 {
396		if t.line[pos] != ' ' {
397			break
398		}
399		pos--
400	}
401	for pos > 0 {
402		if t.line[pos] == ' ' {
403			pos++
404			break
405		}
406		pos--
407	}
408
409	return t.pos - pos
410}
411
412// countToRightWord returns then number of characters from the cursor to the
413// start of the next word.
414func (t *Terminal) countToRightWord() int {
415	pos := t.pos
416	for pos < len(t.line) {
417		if t.line[pos] == ' ' {
418			break
419		}
420		pos++
421	}
422	for pos < len(t.line) {
423		if t.line[pos] != ' ' {
424			break
425		}
426		pos++
427	}
428	return pos - t.pos
429}
430
431// visualLength returns the number of visible glyphs in s.
432func visualLength(runes []rune) int {
433	inEscapeSeq := false
434	length := 0
435
436	for _, r := range runes {
437		switch {
438		case inEscapeSeq:
439			if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
440				inEscapeSeq = false
441			}
442		case r == '\x1b':
443			inEscapeSeq = true
444		default:
445			length++
446		}
447	}
448
449	return length
450}
451
452// handleKey processes the given key and, optionally, returns a line of text
453// that the user has entered.
454func (t *Terminal) handleKey(key rune) (line string, ok bool) {
455	if t.pasteActive && key != keyEnter {
456		t.addKeyToLine(key)
457		return
458	}
459
460	switch key {
461	case keyBackspace:
462		if t.pos == 0 {
463			return
464		}
465		t.eraseNPreviousChars(1)
466	case keyAltLeft:
467		// move left by a word.
468		t.pos -= t.countToLeftWord()
469		t.moveCursorToPos(t.pos)
470	case keyAltRight:
471		// move right by a word.
472		t.pos += t.countToRightWord()
473		t.moveCursorToPos(t.pos)
474	case keyLeft:
475		if t.pos == 0 {
476			return
477		}
478		t.pos--
479		t.moveCursorToPos(t.pos)
480	case keyRight:
481		if t.pos == len(t.line) {
482			return
483		}
484		t.pos++
485		t.moveCursorToPos(t.pos)
486	case keyHome:
487		if t.pos == 0 {
488			return
489		}
490		t.pos = 0
491		t.moveCursorToPos(t.pos)
492	case keyEnd:
493		if t.pos == len(t.line) {
494			return
495		}
496		t.pos = len(t.line)
497		t.moveCursorToPos(t.pos)
498	case keyUp:
499		entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
500		if !ok {
501			return "", false
502		}
503		if t.historyIndex == -1 {
504			t.historyPending = string(t.line)
505		}
506		t.historyIndex++
507		runes := []rune(entry)
508		t.setLine(runes, len(runes))
509	case keyDown:
510		switch t.historyIndex {
511		case -1:
512			return
513		case 0:
514			runes := []rune(t.historyPending)
515			t.setLine(runes, len(runes))
516			t.historyIndex--
517		default:
518			entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
519			if ok {
520				t.historyIndex--
521				runes := []rune(entry)
522				t.setLine(runes, len(runes))
523			}
524		}
525	case keyEnter:
526		t.moveCursorToPos(len(t.line))
527		t.queue([]rune("\r\n"))
528		line = string(t.line)
529		ok = true
530		t.line = t.line[:0]
531		t.pos = 0
532		t.cursorX = 0
533		t.cursorY = 0
534		t.maxLine = 0
535	case keyDeleteWord:
536		// Delete zero or more spaces and then one or more characters.
537		t.eraseNPreviousChars(t.countToLeftWord())
538	case keyDeleteLine:
539		// Delete everything from the current cursor position to the
540		// end of line.
541		for i := t.pos; i < len(t.line); i++ {
542			t.queue(space)
543			t.advanceCursor(1)
544		}
545		t.line = t.line[:t.pos]
546		t.moveCursorToPos(t.pos)
547	case keyCtrlD:
548		// Erase the character under the current position.
549		// The EOF case when the line is empty is handled in
550		// readLine().
551		if t.pos < len(t.line) {
552			t.pos++
553			t.eraseNPreviousChars(1)
554		}
555	case keyCtrlU:
556		t.eraseNPreviousChars(t.pos)
557	case keyClearScreen:
558		// Erases the screen and moves the cursor to the home position.
559		t.queue([]rune("\x1b[2J\x1b[H"))
560		t.queue(t.prompt)
561		t.cursorX, t.cursorY = 0, 0
562		t.advanceCursor(visualLength(t.prompt))
563		t.setLine(t.line, t.pos)
564	default:
565		if t.AutoCompleteCallback != nil {
566			prefix := string(t.line[:t.pos])
567			suffix := string(t.line[t.pos:])
568
569			t.lock.Unlock()
570			newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
571			t.lock.Lock()
572
573			if completeOk {
574				t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
575				return
576			}
577		}
578		if !isPrintable(key) {
579			return
580		}
581		if len(t.line) == maxLineLength {
582			return
583		}
584		t.addKeyToLine(key)
585	}
586	return
587}
588
589// addKeyToLine inserts the given key at the current position in the current
590// line.
591func (t *Terminal) addKeyToLine(key rune) {
592	if len(t.line) == cap(t.line) {
593		newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
594		copy(newLine, t.line)
595		t.line = newLine
596	}
597	t.line = t.line[:len(t.line)+1]
598	copy(t.line[t.pos+1:], t.line[t.pos:])
599	t.line[t.pos] = key
600	if t.echo {
601		t.writeLine(t.line[t.pos:])
602	}
603	t.pos++
604	t.moveCursorToPos(t.pos)
605}
606
607func (t *Terminal) writeLine(line []rune) {
608	for len(line) != 0 {
609		remainingOnLine := t.termWidth - t.cursorX
610		todo := len(line)
611		if todo > remainingOnLine {
612			todo = remainingOnLine
613		}
614		t.queue(line[:todo])
615		t.advanceCursor(visualLength(line[:todo]))
616		line = line[todo:]
617	}
618}
619
620// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
621func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
622	for len(buf) > 0 {
623		i := bytes.IndexByte(buf, '\n')
624		todo := len(buf)
625		if i >= 0 {
626			todo = i
627		}
628
629		var nn int
630		nn, err = w.Write(buf[:todo])
631		n += nn
632		if err != nil {
633			return n, err
634		}
635		buf = buf[todo:]
636
637		if i >= 0 {
638			if _, err = w.Write(crlf); err != nil {
639				return n, err
640			}
641			n++
642			buf = buf[1:]
643		}
644	}
645
646	return n, nil
647}
648
649func (t *Terminal) Write(buf []byte) (n int, err error) {
650	t.lock.Lock()
651	defer t.lock.Unlock()
652
653	if t.cursorX == 0 && t.cursorY == 0 {
654		// This is the easy case: there's nothing on the screen that we
655		// have to move out of the way.
656		return writeWithCRLF(t.c, buf)
657	}
658
659	// We have a prompt and possibly user input on the screen. We
660	// have to clear it first.
661	t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
662	t.cursorX = 0
663	t.clearLineToRight()
664
665	for t.cursorY > 0 {
666		t.move(1 /* up */, 0, 0, 0)
667		t.cursorY--
668		t.clearLineToRight()
669	}
670
671	if _, err = t.c.Write(t.outBuf); err != nil {
672		return
673	}
674	t.outBuf = t.outBuf[:0]
675
676	if n, err = writeWithCRLF(t.c, buf); err != nil {
677		return
678	}
679
680	t.writeLine(t.prompt)
681	if t.echo {
682		t.writeLine(t.line)
683	}
684
685	t.moveCursorToPos(t.pos)
686
687	if _, err = t.c.Write(t.outBuf); err != nil {
688		return
689	}
690	t.outBuf = t.outBuf[:0]
691	return
692}
693
694// ReadPassword temporarily changes the prompt and reads a password, without
695// echo, from the terminal.
696func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
697	t.lock.Lock()
698	defer t.lock.Unlock()
699
700	oldPrompt := t.prompt
701	t.prompt = []rune(prompt)
702	t.echo = false
703
704	line, err = t.readLine()
705
706	t.prompt = oldPrompt
707	t.echo = true
708
709	return
710}
711
712// ReadLine returns a line of input from the terminal.
713func (t *Terminal) ReadLine() (line string, err error) {
714	t.lock.Lock()
715	defer t.lock.Unlock()
716
717	return t.readLine()
718}
719
720func (t *Terminal) readLine() (line string, err error) {
721	// t.lock must be held at this point
722
723	if t.cursorX == 0 && t.cursorY == 0 {
724		t.writeLine(t.prompt)
725		t.c.Write(t.outBuf)
726		t.outBuf = t.outBuf[:0]
727	}
728
729	lineIsPasted := t.pasteActive
730
731	for {
732		rest := t.remainder
733		lineOk := false
734		for !lineOk {
735			var key rune
736			key, rest = bytesToKey(rest, t.pasteActive)
737			if key == utf8.RuneError {
738				break
739			}
740			if !t.pasteActive {
741				if key == keyCtrlD {
742					if len(t.line) == 0 {
743						return "", io.EOF
744					}
745				}
746				if key == keyCtrlC {
747					return "", io.EOF
748				}
749				if key == keyPasteStart {
750					t.pasteActive = true
751					if len(t.line) == 0 {
752						lineIsPasted = true
753					}
754					continue
755				}
756			} else if key == keyPasteEnd {
757				t.pasteActive = false
758				continue
759			}
760			if !t.pasteActive {
761				lineIsPasted = false
762			}
763			line, lineOk = t.handleKey(key)
764		}
765		if len(rest) > 0 {
766			n := copy(t.inBuf[:], rest)
767			t.remainder = t.inBuf[:n]
768		} else {
769			t.remainder = nil
770		}
771		t.c.Write(t.outBuf)
772		t.outBuf = t.outBuf[:0]
773		if lineOk {
774			if t.echo {
775				t.historyIndex = -1
776				t.history.Add(line)
777			}
778			if lineIsPasted {
779				err = ErrPasteIndicator
780			}
781			return
782		}
783
784		// t.remainder is a slice at the beginning of t.inBuf
785		// containing a partial key sequence
786		readBuf := t.inBuf[len(t.remainder):]
787		var n int
788
789		t.lock.Unlock()
790		n, err = t.c.Read(readBuf)
791		t.lock.Lock()
792
793		if err != nil {
794			return
795		}
796
797		t.remainder = t.inBuf[:n+len(t.remainder)]
798	}
799}
800
801// SetPrompt sets the prompt to be used when reading subsequent lines.
802func (t *Terminal) SetPrompt(prompt string) {
803	t.lock.Lock()
804	defer t.lock.Unlock()
805
806	t.prompt = []rune(prompt)
807}
808
809func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
810	// Move cursor to column zero at the start of the line.
811	t.move(t.cursorY, 0, t.cursorX, 0)
812	t.cursorX, t.cursorY = 0, 0
813	t.clearLineToRight()
814	for t.cursorY < numPrevLines {
815		// Move down a line
816		t.move(0, 1, 0, 0)
817		t.cursorY++
818		t.clearLineToRight()
819	}
820	// Move back to beginning.
821	t.move(t.cursorY, 0, 0, 0)
822	t.cursorX, t.cursorY = 0, 0
823
824	t.queue(t.prompt)
825	t.advanceCursor(visualLength(t.prompt))
826	t.writeLine(t.line)
827	t.moveCursorToPos(t.pos)
828}
829
830func (t *Terminal) SetSize(width, height int) error {
831	t.lock.Lock()
832	defer t.lock.Unlock()
833
834	if width == 0 {
835		width = 1
836	}
837
838	oldWidth := t.termWidth
839	t.termWidth, t.termHeight = width, height
840
841	switch {
842	case width == oldWidth:
843		// If the width didn't change then nothing else needs to be
844		// done.
845		return nil
846	case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
847		// If there is nothing on current line and no prompt printed,
848		// just do nothing
849		return nil
850	case width < oldWidth:
851		// Some terminals (e.g. xterm) will truncate lines that were
852		// too long when shinking. Others, (e.g. gnome-terminal) will
853		// attempt to wrap them. For the former, repainting t.maxLine
854		// works great, but that behaviour goes badly wrong in the case
855		// of the latter because they have doubled every full line.
856
857		// We assume that we are working on a terminal that wraps lines
858		// and adjust the cursor position based on every previous line
859		// wrapping and turning into two. This causes the prompt on
860		// xterms to move upwards, which isn't great, but it avoids a
861		// huge mess with gnome-terminal.
862		if t.cursorX >= t.termWidth {
863			t.cursorX = t.termWidth - 1
864		}
865		t.cursorY *= 2
866		t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
867	case width > oldWidth:
868		// If the terminal expands then our position calculations will
869		// be wrong in the future because we think the cursor is
870		// |t.pos| chars into the string, but there will be a gap at
871		// the end of any wrapped line.
872		//
873		// But the position will actually be correct until we move, so
874		// we can move back to the beginning and repaint everything.
875		t.clearAndRepaintLinePlusNPrevious(t.maxLine)
876	}
877
878	_, err := t.c.Write(t.outBuf)
879	t.outBuf = t.outBuf[:0]
880	return err
881}
882
883type pasteIndicatorError struct{}
884
885func (pasteIndicatorError) Error() string {
886	return "terminal: ErrPasteIndicator not correctly handled"
887}
888
889// ErrPasteIndicator may be returned from ReadLine as the error, in addition
890// to valid line data. It indicates that bracketed paste mode is enabled and
891// that the returned line consists only of pasted data. Programs may wish to
892// interpret pasted data more literally than typed data.
893var ErrPasteIndicator = pasteIndicatorError{}
894
895// SetBracketedPasteMode requests that the terminal bracket paste operations
896// with markers. Not all terminals support this but, if it is supported, then
897// enabling this mode will stop any autocomplete callback from running due to
898// pastes. Additionally, any lines that are completely pasted will be returned
899// from ReadLine with the error set to ErrPasteIndicator.
900func (t *Terminal) SetBracketedPasteMode(on bool) {
901	if on {
902		io.WriteString(t.c, "\x1b[?2004h")
903	} else {
904		io.WriteString(t.c, "\x1b[?2004l")
905	}
906}
907
908// stRingBuffer is a ring buffer of strings.
909type stRingBuffer struct {
910	// entries contains max elements.
911	entries []string
912	max     int
913	// head contains the index of the element most recently added to the ring.
914	head int
915	// size contains the number of elements in the ring.
916	size int
917}
918
919func (s *stRingBuffer) Add(a string) {
920	if s.entries == nil {
921		const defaultNumEntries = 100
922		s.entries = make([]string, defaultNumEntries)
923		s.max = defaultNumEntries
924	}
925
926	s.head = (s.head + 1) % s.max
927	s.entries[s.head] = a
928	if s.size < s.max {
929		s.size++
930	}
931}
932
933// NthPreviousEntry returns the value passed to the nth previous call to Add.
934// If n is zero then the immediately prior value is returned, if one, then the
935// next most recent, and so on. If such an element doesn't exist then ok is
936// false.
937func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
938	if n >= s.size {
939		return "", false
940	}
941	index := s.head - n
942	if index < 0 {
943		index += s.max
944	}
945	return s.entries[index], true
946}
947
948// readPasswordLine reads from reader until it finds \n or io.EOF.
949// The slice returned does not include the \n.
950// readPasswordLine also ignores any \r it finds.
951// Windows uses \r as end of line. So, on Windows, readPasswordLine
952// reads until it finds \r and ignores any \n it finds during processing.
953func readPasswordLine(reader io.Reader) ([]byte, error) {
954	var buf [1]byte
955	var ret []byte
956
957	for {
958		n, err := reader.Read(buf[:])
959		if n > 0 {
960			switch buf[0] {
961			case '\b':
962				if len(ret) > 0 {
963					ret = ret[:len(ret)-1]
964				}
965			case '\n':
966				if runtime.GOOS != "windows" {
967					return ret, nil
968				}
969				// otherwise ignore \n
970			case '\r':
971				if runtime.GOOS == "windows" {
972					return ret, nil
973				}
974				// otherwise ignore \r
975			default:
976				ret = append(ret, buf[0])
977			}
978			continue
979		}
980		if err != nil {
981			if err == io.EOF && len(ret) > 0 {
982				return ret, nil
983			}
984			return ret, err
985		}
986	}
987}
988