terminal.go 22 KB

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