terminal.go 25 KB

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