terminal.go raw

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