You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

892 lines
20 KiB

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