nt

A sensible note-taking program
git clone git://git.laack.co/nt.git
Log | Files | Refs | README

terminal.go (23022B)


      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 
      5 package term
      6 
      7 import (
      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.
     18 type 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 
     26 var 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.
     41 type 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 // "> ").
    103 func 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 
    115 const (
    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 
    138 var (
    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.
    146 func 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
    232 func (t *Terminal) queue(data []rune) {
    233 	t.outBuf = append(t.outBuf, []byte(string(data))...)
    234 }
    235 
    236 var space = []rune{' '}
    237 
    238 func isPrintable(key rune) bool {
    239 	isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
    240 	return key >= 32 && !isInSurrogateArea
    241 }
    242 
    243 // moveCursorToPos appends data to t.outBuf which will move the cursor to the
    244 // given, logical position in the text.
    245 func (t *Terminal) moveCursorToPos(pos int) {
    246 	if !t.echo {
    247 		return
    248 	}
    249 
    250 	x := visualLength(t.prompt) + pos
    251 	y := x / t.termWidth
    252 	x = x % t.termWidth
    253 
    254 	up := 0
    255 	if y < t.cursorY {
    256 		up = t.cursorY - y
    257 	}
    258 
    259 	down := 0
    260 	if y > t.cursorY {
    261 		down = y - t.cursorY
    262 	}
    263 
    264 	left := 0
    265 	if x < t.cursorX {
    266 		left = t.cursorX - x
    267 	}
    268 
    269 	right := 0
    270 	if x > t.cursorX {
    271 		right = x - t.cursorX
    272 	}
    273 
    274 	t.cursorX = x
    275 	t.cursorY = y
    276 	t.move(up, down, left, right)
    277 }
    278 
    279 func (t *Terminal) move(up, down, left, right int) {
    280 	m := []rune{}
    281 
    282 	// 1 unit up can be expressed as ^[[A or ^[A
    283 	// 5 units up can be expressed as ^[[5A
    284 
    285 	if up == 1 {
    286 		m = append(m, keyEscape, '[', 'A')
    287 	} else if up > 1 {
    288 		m = append(m, keyEscape, '[')
    289 		m = append(m, []rune(strconv.Itoa(up))...)
    290 		m = append(m, 'A')
    291 	}
    292 
    293 	if down == 1 {
    294 		m = append(m, keyEscape, '[', 'B')
    295 	} else if down > 1 {
    296 		m = append(m, keyEscape, '[')
    297 		m = append(m, []rune(strconv.Itoa(down))...)
    298 		m = append(m, 'B')
    299 	}
    300 
    301 	if right == 1 {
    302 		m = append(m, keyEscape, '[', 'C')
    303 	} else if right > 1 {
    304 		m = append(m, keyEscape, '[')
    305 		m = append(m, []rune(strconv.Itoa(right))...)
    306 		m = append(m, 'C')
    307 	}
    308 
    309 	if left == 1 {
    310 		m = append(m, keyEscape, '[', 'D')
    311 	} else if left > 1 {
    312 		m = append(m, keyEscape, '[')
    313 		m = append(m, []rune(strconv.Itoa(left))...)
    314 		m = append(m, 'D')
    315 	}
    316 
    317 	t.queue(m)
    318 }
    319 
    320 func (t *Terminal) clearLineToRight() {
    321 	op := []rune{keyEscape, '[', 'K'}
    322 	t.queue(op)
    323 }
    324 
    325 const maxLineLength = 4096
    326 
    327 func (t *Terminal) setLine(newLine []rune, newPos int) {
    328 	if t.echo {
    329 		t.moveCursorToPos(0)
    330 		t.writeLine(newLine)
    331 		for i := len(newLine); i < len(t.line); i++ {
    332 			t.writeLine(space)
    333 		}
    334 		t.moveCursorToPos(newPos)
    335 	}
    336 	t.line = newLine
    337 	t.pos = newPos
    338 }
    339 
    340 func (t *Terminal) advanceCursor(places int) {
    341 	t.cursorX += places
    342 	t.cursorY += t.cursorX / t.termWidth
    343 	if t.cursorY > t.maxLine {
    344 		t.maxLine = t.cursorY
    345 	}
    346 	t.cursorX = t.cursorX % t.termWidth
    347 
    348 	if places > 0 && t.cursorX == 0 {
    349 		// Normally terminals will advance the current position
    350 		// when writing a character. But that doesn't happen
    351 		// for the last character in a line. However, when
    352 		// writing a character (except a new line) that causes
    353 		// a line wrap, the position will be advanced two
    354 		// places.
    355 		//
    356 		// So, if we are stopping at the end of a line, we
    357 		// need to write a newline so that our cursor can be
    358 		// advanced to the next line.
    359 		t.outBuf = append(t.outBuf, '\r', '\n')
    360 	}
    361 }
    362 
    363 func (t *Terminal) eraseNPreviousChars(n int) {
    364 	if n == 0 {
    365 		return
    366 	}
    367 
    368 	if t.pos < n {
    369 		n = t.pos
    370 	}
    371 	t.pos -= n
    372 	t.moveCursorToPos(t.pos)
    373 
    374 	copy(t.line[t.pos:], t.line[n+t.pos:])
    375 	t.line = t.line[:len(t.line)-n]
    376 	if t.echo {
    377 		t.writeLine(t.line[t.pos:])
    378 		for i := 0; i < n; i++ {
    379 			t.queue(space)
    380 		}
    381 		t.advanceCursor(n)
    382 		t.moveCursorToPos(t.pos)
    383 	}
    384 }
    385 
    386 // countToLeftWord returns then number of characters from the cursor to the
    387 // start of the previous word.
    388 func (t *Terminal) countToLeftWord() int {
    389 	if t.pos == 0 {
    390 		return 0
    391 	}
    392 
    393 	pos := t.pos - 1
    394 	for pos > 0 {
    395 		if t.line[pos] != ' ' {
    396 			break
    397 		}
    398 		pos--
    399 	}
    400 	for pos > 0 {
    401 		if t.line[pos] == ' ' {
    402 			pos++
    403 			break
    404 		}
    405 		pos--
    406 	}
    407 
    408 	return t.pos - pos
    409 }
    410 
    411 // countToRightWord returns then number of characters from the cursor to the
    412 // start of the next word.
    413 func (t *Terminal) countToRightWord() int {
    414 	pos := t.pos
    415 	for pos < len(t.line) {
    416 		if t.line[pos] == ' ' {
    417 			break
    418 		}
    419 		pos++
    420 	}
    421 	for pos < len(t.line) {
    422 		if t.line[pos] != ' ' {
    423 			break
    424 		}
    425 		pos++
    426 	}
    427 	return pos - t.pos
    428 }
    429 
    430 // visualLength returns the number of visible glyphs in s.
    431 func visualLength(runes []rune) int {
    432 	inEscapeSeq := false
    433 	length := 0
    434 
    435 	for _, r := range runes {
    436 		switch {
    437 		case inEscapeSeq:
    438 			if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
    439 				inEscapeSeq = false
    440 			}
    441 		case r == '\x1b':
    442 			inEscapeSeq = true
    443 		default:
    444 			length++
    445 		}
    446 	}
    447 
    448 	return length
    449 }
    450 
    451 // handleKey processes the given key and, optionally, returns a line of text
    452 // that the user has entered.
    453 func (t *Terminal) handleKey(key rune) (line string, ok bool) {
    454 	if t.pasteActive && key != keyEnter {
    455 		t.addKeyToLine(key)
    456 		return
    457 	}
    458 
    459 	switch key {
    460 	case keyBackspace:
    461 		if t.pos == 0 {
    462 			return
    463 		}
    464 		t.eraseNPreviousChars(1)
    465 	case keyAltLeft:
    466 		// move left by a word.
    467 		t.pos -= t.countToLeftWord()
    468 		t.moveCursorToPos(t.pos)
    469 	case keyAltRight:
    470 		// move right by a word.
    471 		t.pos += t.countToRightWord()
    472 		t.moveCursorToPos(t.pos)
    473 	case keyLeft:
    474 		if t.pos == 0 {
    475 			return
    476 		}
    477 		t.pos--
    478 		t.moveCursorToPos(t.pos)
    479 	case keyRight:
    480 		if t.pos == len(t.line) {
    481 			return
    482 		}
    483 		t.pos++
    484 		t.moveCursorToPos(t.pos)
    485 	case keyHome:
    486 		if t.pos == 0 {
    487 			return
    488 		}
    489 		t.pos = 0
    490 		t.moveCursorToPos(t.pos)
    491 	case keyEnd:
    492 		if t.pos == len(t.line) {
    493 			return
    494 		}
    495 		t.pos = len(t.line)
    496 		t.moveCursorToPos(t.pos)
    497 	case keyUp:
    498 		entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
    499 		if !ok {
    500 			return "", false
    501 		}
    502 		if t.historyIndex == -1 {
    503 			t.historyPending = string(t.line)
    504 		}
    505 		t.historyIndex++
    506 		runes := []rune(entry)
    507 		t.setLine(runes, len(runes))
    508 	case keyDown:
    509 		switch t.historyIndex {
    510 		case -1:
    511 			return
    512 		case 0:
    513 			runes := []rune(t.historyPending)
    514 			t.setLine(runes, len(runes))
    515 			t.historyIndex--
    516 		default:
    517 			entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
    518 			if ok {
    519 				t.historyIndex--
    520 				runes := []rune(entry)
    521 				t.setLine(runes, len(runes))
    522 			}
    523 		}
    524 	case keyEnter:
    525 		t.moveCursorToPos(len(t.line))
    526 		t.queue([]rune("\r\n"))
    527 		line = string(t.line)
    528 		ok = true
    529 		t.line = t.line[:0]
    530 		t.pos = 0
    531 		t.cursorX = 0
    532 		t.cursorY = 0
    533 		t.maxLine = 0
    534 	case keyDeleteWord:
    535 		// Delete zero or more spaces and then one or more characters.
    536 		t.eraseNPreviousChars(t.countToLeftWord())
    537 	case keyDeleteLine:
    538 		// Delete everything from the current cursor position to the
    539 		// end of line.
    540 		for i := t.pos; i < len(t.line); i++ {
    541 			t.queue(space)
    542 			t.advanceCursor(1)
    543 		}
    544 		t.line = t.line[:t.pos]
    545 		t.moveCursorToPos(t.pos)
    546 	case keyCtrlD:
    547 		// Erase the character under the current position.
    548 		// The EOF case when the line is empty is handled in
    549 		// readLine().
    550 		if t.pos < len(t.line) {
    551 			t.pos++
    552 			t.eraseNPreviousChars(1)
    553 		}
    554 	case keyCtrlU:
    555 		t.eraseNPreviousChars(t.pos)
    556 	case keyClearScreen:
    557 		// Erases the screen and moves the cursor to the home position.
    558 		t.queue([]rune("\x1b[2J\x1b[H"))
    559 		t.queue(t.prompt)
    560 		t.cursorX, t.cursorY = 0, 0
    561 		t.advanceCursor(visualLength(t.prompt))
    562 		t.setLine(t.line, t.pos)
    563 	default:
    564 		if t.AutoCompleteCallback != nil {
    565 			prefix := string(t.line[:t.pos])
    566 			suffix := string(t.line[t.pos:])
    567 
    568 			t.lock.Unlock()
    569 			newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
    570 			t.lock.Lock()
    571 
    572 			if completeOk {
    573 				t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
    574 				return
    575 			}
    576 		}
    577 		if !isPrintable(key) {
    578 			return
    579 		}
    580 		if len(t.line) == maxLineLength {
    581 			return
    582 		}
    583 		t.addKeyToLine(key)
    584 	}
    585 	return
    586 }
    587 
    588 // addKeyToLine inserts the given key at the current position in the current
    589 // line.
    590 func (t *Terminal) addKeyToLine(key rune) {
    591 	if len(t.line) == cap(t.line) {
    592 		newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
    593 		copy(newLine, t.line)
    594 		t.line = newLine
    595 	}
    596 	t.line = t.line[:len(t.line)+1]
    597 	copy(t.line[t.pos+1:], t.line[t.pos:])
    598 	t.line[t.pos] = key
    599 	if t.echo {
    600 		t.writeLine(t.line[t.pos:])
    601 	}
    602 	t.pos++
    603 	t.moveCursorToPos(t.pos)
    604 }
    605 
    606 func (t *Terminal) writeLine(line []rune) {
    607 	for len(line) != 0 {
    608 		remainingOnLine := t.termWidth - t.cursorX
    609 		todo := len(line)
    610 		if todo > remainingOnLine {
    611 			todo = remainingOnLine
    612 		}
    613 		t.queue(line[:todo])
    614 		t.advanceCursor(visualLength(line[:todo]))
    615 		line = line[todo:]
    616 	}
    617 }
    618 
    619 // writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
    620 func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
    621 	for len(buf) > 0 {
    622 		i := bytes.IndexByte(buf, '\n')
    623 		todo := len(buf)
    624 		if i >= 0 {
    625 			todo = i
    626 		}
    627 
    628 		var nn int
    629 		nn, err = w.Write(buf[:todo])
    630 		n += nn
    631 		if err != nil {
    632 			return n, err
    633 		}
    634 		buf = buf[todo:]
    635 
    636 		if i >= 0 {
    637 			if _, err = w.Write(crlf); err != nil {
    638 				return n, err
    639 			}
    640 			n++
    641 			buf = buf[1:]
    642 		}
    643 	}
    644 
    645 	return n, nil
    646 }
    647 
    648 func (t *Terminal) Write(buf []byte) (n int, err error) {
    649 	t.lock.Lock()
    650 	defer t.lock.Unlock()
    651 
    652 	if t.cursorX == 0 && t.cursorY == 0 {
    653 		// This is the easy case: there's nothing on the screen that we
    654 		// have to move out of the way.
    655 		return writeWithCRLF(t.c, buf)
    656 	}
    657 
    658 	// We have a prompt and possibly user input on the screen. We
    659 	// have to clear it first.
    660 	t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
    661 	t.cursorX = 0
    662 	t.clearLineToRight()
    663 
    664 	for t.cursorY > 0 {
    665 		t.move(1 /* up */, 0, 0, 0)
    666 		t.cursorY--
    667 		t.clearLineToRight()
    668 	}
    669 
    670 	if _, err = t.c.Write(t.outBuf); err != nil {
    671 		return
    672 	}
    673 	t.outBuf = t.outBuf[:0]
    674 
    675 	if n, err = writeWithCRLF(t.c, buf); err != nil {
    676 		return
    677 	}
    678 
    679 	t.writeLine(t.prompt)
    680 	if t.echo {
    681 		t.writeLine(t.line)
    682 	}
    683 
    684 	t.moveCursorToPos(t.pos)
    685 
    686 	if _, err = t.c.Write(t.outBuf); err != nil {
    687 		return
    688 	}
    689 	t.outBuf = t.outBuf[:0]
    690 	return
    691 }
    692 
    693 // ReadPassword temporarily changes the prompt and reads a password, without
    694 // echo, from the terminal.
    695 func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
    696 	t.lock.Lock()
    697 	defer t.lock.Unlock()
    698 
    699 	oldPrompt := t.prompt
    700 	t.prompt = []rune(prompt)
    701 	t.echo = false
    702 
    703 	line, err = t.readLine()
    704 
    705 	t.prompt = oldPrompt
    706 	t.echo = true
    707 
    708 	return
    709 }
    710 
    711 // ReadLine returns a line of input from the terminal.
    712 func (t *Terminal) ReadLine() (line string, err error) {
    713 	t.lock.Lock()
    714 	defer t.lock.Unlock()
    715 
    716 	return t.readLine()
    717 }
    718 
    719 func (t *Terminal) readLine() (line string, err error) {
    720 	// t.lock must be held at this point
    721 
    722 	if t.cursorX == 0 && t.cursorY == 0 {
    723 		t.writeLine(t.prompt)
    724 		t.c.Write(t.outBuf)
    725 		t.outBuf = t.outBuf[:0]
    726 	}
    727 
    728 	lineIsPasted := t.pasteActive
    729 
    730 	for {
    731 		rest := t.remainder
    732 		lineOk := false
    733 		for !lineOk {
    734 			var key rune
    735 			key, rest = bytesToKey(rest, t.pasteActive)
    736 			if key == utf8.RuneError {
    737 				break
    738 			}
    739 			if !t.pasteActive {
    740 				if key == keyCtrlD {
    741 					if len(t.line) == 0 {
    742 						return "", io.EOF
    743 					}
    744 				}
    745 				if key == keyCtrlC {
    746 					return "", io.EOF
    747 				}
    748 				if key == keyPasteStart {
    749 					t.pasteActive = true
    750 					if len(t.line) == 0 {
    751 						lineIsPasted = true
    752 					}
    753 					continue
    754 				}
    755 			} else if key == keyPasteEnd {
    756 				t.pasteActive = false
    757 				continue
    758 			}
    759 			if !t.pasteActive {
    760 				lineIsPasted = false
    761 			}
    762 			line, lineOk = t.handleKey(key)
    763 		}
    764 		if len(rest) > 0 {
    765 			n := copy(t.inBuf[:], rest)
    766 			t.remainder = t.inBuf[:n]
    767 		} else {
    768 			t.remainder = nil
    769 		}
    770 		t.c.Write(t.outBuf)
    771 		t.outBuf = t.outBuf[:0]
    772 		if lineOk {
    773 			if t.echo {
    774 				t.historyIndex = -1
    775 				t.history.Add(line)
    776 			}
    777 			if lineIsPasted {
    778 				err = ErrPasteIndicator
    779 			}
    780 			return
    781 		}
    782 
    783 		// t.remainder is a slice at the beginning of t.inBuf
    784 		// containing a partial key sequence
    785 		readBuf := t.inBuf[len(t.remainder):]
    786 		var n int
    787 
    788 		t.lock.Unlock()
    789 		n, err = t.c.Read(readBuf)
    790 		t.lock.Lock()
    791 
    792 		if err != nil {
    793 			return
    794 		}
    795 
    796 		t.remainder = t.inBuf[:n+len(t.remainder)]
    797 	}
    798 }
    799 
    800 // SetPrompt sets the prompt to be used when reading subsequent lines.
    801 func (t *Terminal) SetPrompt(prompt string) {
    802 	t.lock.Lock()
    803 	defer t.lock.Unlock()
    804 
    805 	t.prompt = []rune(prompt)
    806 }
    807 
    808 func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
    809 	// Move cursor to column zero at the start of the line.
    810 	t.move(t.cursorY, 0, t.cursorX, 0)
    811 	t.cursorX, t.cursorY = 0, 0
    812 	t.clearLineToRight()
    813 	for t.cursorY < numPrevLines {
    814 		// Move down a line
    815 		t.move(0, 1, 0, 0)
    816 		t.cursorY++
    817 		t.clearLineToRight()
    818 	}
    819 	// Move back to beginning.
    820 	t.move(t.cursorY, 0, 0, 0)
    821 	t.cursorX, t.cursorY = 0, 0
    822 
    823 	t.queue(t.prompt)
    824 	t.advanceCursor(visualLength(t.prompt))
    825 	t.writeLine(t.line)
    826 	t.moveCursorToPos(t.pos)
    827 }
    828 
    829 func (t *Terminal) SetSize(width, height int) error {
    830 	t.lock.Lock()
    831 	defer t.lock.Unlock()
    832 
    833 	if width == 0 {
    834 		width = 1
    835 	}
    836 
    837 	oldWidth := t.termWidth
    838 	t.termWidth, t.termHeight = width, height
    839 
    840 	switch {
    841 	case width == oldWidth:
    842 		// If the width didn't change then nothing else needs to be
    843 		// done.
    844 		return nil
    845 	case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
    846 		// If there is nothing on current line and no prompt printed,
    847 		// just do nothing
    848 		return nil
    849 	case width < oldWidth:
    850 		// Some terminals (e.g. xterm) will truncate lines that were
    851 		// too long when shinking. Others, (e.g. gnome-terminal) will
    852 		// attempt to wrap them. For the former, repainting t.maxLine
    853 		// works great, but that behaviour goes badly wrong in the case
    854 		// of the latter because they have doubled every full line.
    855 
    856 		// We assume that we are working on a terminal that wraps lines
    857 		// and adjust the cursor position based on every previous line
    858 		// wrapping and turning into two. This causes the prompt on
    859 		// xterms to move upwards, which isn't great, but it avoids a
    860 		// huge mess with gnome-terminal.
    861 		if t.cursorX >= t.termWidth {
    862 			t.cursorX = t.termWidth - 1
    863 		}
    864 		t.cursorY *= 2
    865 		t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
    866 	case width > oldWidth:
    867 		// If the terminal expands then our position calculations will
    868 		// be wrong in the future because we think the cursor is
    869 		// |t.pos| chars into the string, but there will be a gap at
    870 		// the end of any wrapped line.
    871 		//
    872 		// But the position will actually be correct until we move, so
    873 		// we can move back to the beginning and repaint everything.
    874 		t.clearAndRepaintLinePlusNPrevious(t.maxLine)
    875 	}
    876 
    877 	_, err := t.c.Write(t.outBuf)
    878 	t.outBuf = t.outBuf[:0]
    879 	return err
    880 }
    881 
    882 type pasteIndicatorError struct{}
    883 
    884 func (pasteIndicatorError) Error() string {
    885 	return "terminal: ErrPasteIndicator not correctly handled"
    886 }
    887 
    888 // ErrPasteIndicator may be returned from ReadLine as the error, in addition
    889 // to valid line data. It indicates that bracketed paste mode is enabled and
    890 // that the returned line consists only of pasted data. Programs may wish to
    891 // interpret pasted data more literally than typed data.
    892 var ErrPasteIndicator = pasteIndicatorError{}
    893 
    894 // SetBracketedPasteMode requests that the terminal bracket paste operations
    895 // with markers. Not all terminals support this but, if it is supported, then
    896 // enabling this mode will stop any autocomplete callback from running due to
    897 // pastes. Additionally, any lines that are completely pasted will be returned
    898 // from ReadLine with the error set to ErrPasteIndicator.
    899 func (t *Terminal) SetBracketedPasteMode(on bool) {
    900 	if on {
    901 		io.WriteString(t.c, "\x1b[?2004h")
    902 	} else {
    903 		io.WriteString(t.c, "\x1b[?2004l")
    904 	}
    905 }
    906 
    907 // stRingBuffer is a ring buffer of strings.
    908 type stRingBuffer struct {
    909 	// entries contains max elements.
    910 	entries []string
    911 	max     int
    912 	// head contains the index of the element most recently added to the ring.
    913 	head int
    914 	// size contains the number of elements in the ring.
    915 	size int
    916 }
    917 
    918 func (s *stRingBuffer) Add(a string) {
    919 	if s.entries == nil {
    920 		const defaultNumEntries = 100
    921 		s.entries = make([]string, defaultNumEntries)
    922 		s.max = defaultNumEntries
    923 	}
    924 
    925 	s.head = (s.head + 1) % s.max
    926 	s.entries[s.head] = a
    927 	if s.size < s.max {
    928 		s.size++
    929 	}
    930 }
    931 
    932 // NthPreviousEntry returns the value passed to the nth previous call to Add.
    933 // If n is zero then the immediately prior value is returned, if one, then the
    934 // next most recent, and so on. If such an element doesn't exist then ok is
    935 // false.
    936 func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
    937 	if n < 0 || n >= s.size {
    938 		return "", false
    939 	}
    940 	index := s.head - n
    941 	if index < 0 {
    942 		index += s.max
    943 	}
    944 	return s.entries[index], true
    945 }
    946 
    947 // readPasswordLine reads from reader until it finds \n or io.EOF.
    948 // The slice returned does not include the \n.
    949 // readPasswordLine also ignores any \r it finds.
    950 // Windows uses \r as end of line. So, on Windows, readPasswordLine
    951 // reads until it finds \r and ignores any \n it finds during processing.
    952 func readPasswordLine(reader io.Reader) ([]byte, error) {
    953 	var buf [1]byte
    954 	var ret []byte
    955 
    956 	for {
    957 		n, err := reader.Read(buf[:])
    958 		if n > 0 {
    959 			switch buf[0] {
    960 			case '\b':
    961 				if len(ret) > 0 {
    962 					ret = ret[:len(ret)-1]
    963 				}
    964 			case '\n':
    965 				if runtime.GOOS != "windows" {
    966 					return ret, nil
    967 				}
    968 				// otherwise ignore \n
    969 			case '\r':
    970 				if runtime.GOOS == "windows" {
    971 					return ret, nil
    972 				}
    973 				// otherwise ignore \r
    974 			default:
    975 				ret = append(ret, buf[0])
    976 			}
    977 			continue
    978 		}
    979 		if err != nil {
    980 			if err == io.EOF && len(ret) > 0 {
    981 				return ret, nil
    982 			}
    983 			return ret, err
    984 		}
    985 	}
    986 }