terminal.go 22 KB

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