terminal.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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. "io"
  7. "sync"
  8. "unicode/utf8"
  9. )
  10. // EscapeCodes contains escape sequences that can be written to the terminal in
  11. // order to achieve different styles of text.
  12. type EscapeCodes struct {
  13. // Foreground colors
  14. Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
  15. // Reset all attributes
  16. Reset []byte
  17. }
  18. var vt100EscapeCodes = EscapeCodes{
  19. Black: []byte{keyEscape, '[', '3', '0', 'm'},
  20. Red: []byte{keyEscape, '[', '3', '1', 'm'},
  21. Green: []byte{keyEscape, '[', '3', '2', 'm'},
  22. Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
  23. Blue: []byte{keyEscape, '[', '3', '4', 'm'},
  24. Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
  25. Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
  26. White: []byte{keyEscape, '[', '3', '7', 'm'},
  27. Reset: []byte{keyEscape, '[', '0', 'm'},
  28. }
  29. // Terminal contains the state for running a VT100 terminal that is capable of
  30. // reading lines of input.
  31. type Terminal struct {
  32. // AutoCompleteCallback, if non-null, is called for each keypress with
  33. // the full input line and the current position of the cursor (in
  34. // bytes, as an index into |line|). If it returns ok=false, the key
  35. // press is processed normally. Otherwise it returns a replacement line
  36. // and the new cursor position.
  37. AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
  38. // Escape contains a pointer to the escape codes for this terminal.
  39. // It's always a valid pointer, although the escape codes themselves
  40. // may be empty if the terminal doesn't support them.
  41. Escape *EscapeCodes
  42. // lock protects the terminal and the state in this object from
  43. // concurrent processing of a key press and a Write() call.
  44. lock sync.Mutex
  45. c io.ReadWriter
  46. prompt string
  47. // line is the current line being entered.
  48. line []rune
  49. // pos is the logical position of the cursor in line
  50. pos int
  51. // echo is true if local echo is enabled
  52. echo bool
  53. // cursorX contains the current X value of the cursor where the left
  54. // edge is 0. cursorY contains the row number where the first row of
  55. // the current line is 0.
  56. cursorX, cursorY int
  57. // maxLine is the greatest value of cursorY so far.
  58. maxLine int
  59. termWidth, termHeight int
  60. // outBuf contains the terminal data to be sent.
  61. outBuf []byte
  62. // remainder contains the remainder of any partial key sequences after
  63. // a read. It aliases into inBuf.
  64. remainder []byte
  65. inBuf [256]byte
  66. // history contains previously entered commands so that they can be
  67. // accessed with the up and down keys.
  68. history stRingBuffer
  69. // historyIndex stores the currently accessed history entry, where zero
  70. // means the immediately previous entry.
  71. historyIndex int
  72. // When navigating up and down the history it's possible to return to
  73. // the incomplete, initial line. That value is stored in
  74. // historyPending.
  75. historyPending string
  76. }
  77. // NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
  78. // a local terminal, that terminal must first have been put into raw mode.
  79. // prompt is a string that is written at the start of each input line (i.e.
  80. // "> ").
  81. func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
  82. return &Terminal{
  83. Escape: &vt100EscapeCodes,
  84. c: c,
  85. prompt: prompt,
  86. termWidth: 80,
  87. termHeight: 24,
  88. echo: true,
  89. historyIndex: -1,
  90. }
  91. }
  92. const (
  93. keyCtrlD = 4
  94. keyEnter = '\r'
  95. keyEscape = 27
  96. keyBackspace = 127
  97. keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
  98. keyUp
  99. keyDown
  100. keyLeft
  101. keyRight
  102. keyAltLeft
  103. keyAltRight
  104. keyHome
  105. keyEnd
  106. keyDeleteWord
  107. keyDeleteLine
  108. )
  109. // bytesToKey tries to parse a key sequence from b. If successful, it returns
  110. // the key and the remainder of the input. Otherwise it returns utf8.RuneError.
  111. func bytesToKey(b []byte) (rune, []byte) {
  112. if len(b) == 0 {
  113. return utf8.RuneError, nil
  114. }
  115. switch b[0] {
  116. case 8: // ^H
  117. return keyBackspace, b[1:]
  118. case 11: // ^K
  119. return keyDeleteLine, b[1:]
  120. case 23: // ^W
  121. return keyDeleteWord, b[1:]
  122. }
  123. if b[0] != keyEscape {
  124. if !utf8.FullRune(b) {
  125. return utf8.RuneError, b
  126. }
  127. r, l := utf8.DecodeRune(b)
  128. return r, b[l:]
  129. }
  130. if len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
  131. switch b[2] {
  132. case 'A':
  133. return keyUp, b[3:]
  134. case 'B':
  135. return keyDown, b[3:]
  136. case 'C':
  137. return keyRight, b[3:]
  138. case 'D':
  139. return keyLeft, b[3:]
  140. }
  141. }
  142. if len(b) >= 3 && b[0] == keyEscape && b[1] == 'O' {
  143. switch b[2] {
  144. case 'H':
  145. return keyHome, b[3:]
  146. case 'F':
  147. return keyEnd, b[3:]
  148. }
  149. }
  150. if len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
  151. switch b[5] {
  152. case 'C':
  153. return keyAltRight, b[6:]
  154. case 'D':
  155. return keyAltLeft, b[6:]
  156. }
  157. }
  158. // If we get here then we have a key that we don't recognise, or a
  159. // partial sequence. It's not clear how one should find the end of a
  160. // sequence without knowing them all, but it seems that [a-zA-Z] only
  161. // appears at the end of a sequence.
  162. for i, c := range b[0:] {
  163. if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
  164. return keyUnknown, b[i+1:]
  165. }
  166. }
  167. return utf8.RuneError, b
  168. }
  169. // queue appends data to the end of t.outBuf
  170. func (t *Terminal) queue(data []rune) {
  171. t.outBuf = append(t.outBuf, []byte(string(data))...)
  172. }
  173. var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
  174. var space = []rune{' '}
  175. func isPrintable(key rune) bool {
  176. isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
  177. return key >= 32 && !isInSurrogateArea
  178. }
  179. // moveCursorToPos appends data to t.outBuf which will move the cursor to the
  180. // given, logical position in the text.
  181. func (t *Terminal) moveCursorToPos(pos int) {
  182. if !t.echo {
  183. return
  184. }
  185. x := len(t.prompt) + pos
  186. y := x / t.termWidth
  187. x = x % t.termWidth
  188. up := 0
  189. if y < t.cursorY {
  190. up = t.cursorY - y
  191. }
  192. down := 0
  193. if y > t.cursorY {
  194. down = y - t.cursorY
  195. }
  196. left := 0
  197. if x < t.cursorX {
  198. left = t.cursorX - x
  199. }
  200. right := 0
  201. if x > t.cursorX {
  202. right = x - t.cursorX
  203. }
  204. t.cursorX = x
  205. t.cursorY = y
  206. t.move(up, down, left, right)
  207. }
  208. func (t *Terminal) move(up, down, left, right int) {
  209. movement := make([]rune, 3*(up+down+left+right))
  210. m := movement
  211. for i := 0; i < up; i++ {
  212. m[0] = keyEscape
  213. m[1] = '['
  214. m[2] = 'A'
  215. m = m[3:]
  216. }
  217. for i := 0; i < down; i++ {
  218. m[0] = keyEscape
  219. m[1] = '['
  220. m[2] = 'B'
  221. m = m[3:]
  222. }
  223. for i := 0; i < left; i++ {
  224. m[0] = keyEscape
  225. m[1] = '['
  226. m[2] = 'D'
  227. m = m[3:]
  228. }
  229. for i := 0; i < right; i++ {
  230. m[0] = keyEscape
  231. m[1] = '['
  232. m[2] = 'C'
  233. m = m[3:]
  234. }
  235. t.queue(movement)
  236. }
  237. func (t *Terminal) clearLineToRight() {
  238. op := []rune{keyEscape, '[', 'K'}
  239. t.queue(op)
  240. }
  241. const maxLineLength = 4096
  242. func (t *Terminal) setLine(newLine []rune, newPos int) {
  243. if t.echo {
  244. t.moveCursorToPos(0)
  245. t.writeLine(newLine)
  246. for i := len(newLine); i < len(t.line); i++ {
  247. t.writeLine(space)
  248. }
  249. t.moveCursorToPos(newPos)
  250. }
  251. t.line = newLine
  252. t.pos = newPos
  253. }
  254. func (t *Terminal) eraseNPreviousChars(n int) {
  255. if n == 0 {
  256. return
  257. }
  258. if t.pos < n {
  259. n = t.pos
  260. }
  261. t.pos -= n
  262. t.moveCursorToPos(t.pos)
  263. copy(t.line[t.pos:], t.line[n+t.pos:])
  264. t.line = t.line[:len(t.line)-n]
  265. if t.echo {
  266. t.writeLine(t.line[t.pos:])
  267. for i := 0; i < n; i++ {
  268. t.queue(space)
  269. }
  270. t.cursorX += n
  271. t.moveCursorToPos(t.pos)
  272. }
  273. }
  274. // countToLeftWord returns then number of characters from the cursor to the
  275. // start of the previous word.
  276. func (t *Terminal) countToLeftWord() int {
  277. if t.pos == 0 {
  278. return 0
  279. }
  280. pos := t.pos - 1
  281. for pos > 0 {
  282. if t.line[pos] != ' ' {
  283. break
  284. }
  285. pos--
  286. }
  287. for pos > 0 {
  288. if t.line[pos] == ' ' {
  289. pos++
  290. break
  291. }
  292. pos--
  293. }
  294. return t.pos - pos
  295. }
  296. // countToRightWord returns then number of characters from the cursor to the
  297. // start of the next word.
  298. func (t *Terminal) countToRightWord() int {
  299. pos := t.pos
  300. for pos < len(t.line) {
  301. if t.line[pos] == ' ' {
  302. break
  303. }
  304. pos++
  305. }
  306. for pos < len(t.line) {
  307. if t.line[pos] != ' ' {
  308. break
  309. }
  310. pos++
  311. }
  312. return pos - t.pos
  313. }
  314. // handleKey processes the given key and, optionally, returns a line of text
  315. // that the user has entered.
  316. func (t *Terminal) handleKey(key rune) (line string, ok bool) {
  317. switch key {
  318. case keyBackspace:
  319. if t.pos == 0 {
  320. return
  321. }
  322. t.eraseNPreviousChars(1)
  323. case keyAltLeft:
  324. // move left by a word.
  325. t.pos -= t.countToLeftWord()
  326. t.moveCursorToPos(t.pos)
  327. case keyAltRight:
  328. // move right by a word.
  329. t.pos += t.countToRightWord()
  330. t.moveCursorToPos(t.pos)
  331. case keyLeft:
  332. if t.pos == 0 {
  333. return
  334. }
  335. t.pos--
  336. t.moveCursorToPos(t.pos)
  337. case keyRight:
  338. if t.pos == len(t.line) {
  339. return
  340. }
  341. t.pos++
  342. t.moveCursorToPos(t.pos)
  343. case keyHome:
  344. if t.pos == 0 {
  345. return
  346. }
  347. t.pos = 0
  348. t.moveCursorToPos(t.pos)
  349. case keyEnd:
  350. if t.pos == len(t.line) {
  351. return
  352. }
  353. t.pos = len(t.line)
  354. t.moveCursorToPos(t.pos)
  355. case keyUp:
  356. entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
  357. if !ok {
  358. return "", false
  359. }
  360. if t.historyIndex == -1 {
  361. t.historyPending = string(t.line)
  362. }
  363. t.historyIndex++
  364. t.setLine([]rune(entry), len(entry))
  365. case keyDown:
  366. switch t.historyIndex {
  367. case -1:
  368. return
  369. case 0:
  370. t.setLine([]rune(t.historyPending), len(t.historyPending))
  371. t.historyIndex--
  372. default:
  373. entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
  374. if ok {
  375. t.historyIndex--
  376. t.setLine([]rune(entry), len(entry))
  377. }
  378. }
  379. case keyEnter:
  380. t.moveCursorToPos(len(t.line))
  381. t.queue([]rune("\r\n"))
  382. line = string(t.line)
  383. ok = true
  384. t.line = t.line[:0]
  385. t.pos = 0
  386. t.cursorX = 0
  387. t.cursorY = 0
  388. t.maxLine = 0
  389. case keyDeleteWord:
  390. // Delete zero or more spaces and then one or more characters.
  391. t.eraseNPreviousChars(t.countToLeftWord())
  392. case keyDeleteLine:
  393. // Delete everything from the current cursor position to the
  394. // end of line.
  395. for i := t.pos; i < len(t.line); i++ {
  396. t.queue(space)
  397. t.cursorX++
  398. }
  399. t.line = t.line[:t.pos]
  400. t.moveCursorToPos(t.pos)
  401. default:
  402. if t.AutoCompleteCallback != nil {
  403. prefix := string(t.line[:t.pos])
  404. suffix := string(t.line[t.pos:])
  405. t.lock.Unlock()
  406. newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
  407. t.lock.Lock()
  408. if completeOk {
  409. t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
  410. return
  411. }
  412. }
  413. if !isPrintable(key) {
  414. return
  415. }
  416. if len(t.line) == maxLineLength {
  417. return
  418. }
  419. if len(t.line) == cap(t.line) {
  420. newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
  421. copy(newLine, t.line)
  422. t.line = newLine
  423. }
  424. t.line = t.line[:len(t.line)+1]
  425. copy(t.line[t.pos+1:], t.line[t.pos:])
  426. t.line[t.pos] = key
  427. if t.echo {
  428. t.writeLine(t.line[t.pos:])
  429. }
  430. t.pos++
  431. t.moveCursorToPos(t.pos)
  432. }
  433. return
  434. }
  435. func (t *Terminal) writeLine(line []rune) {
  436. for len(line) != 0 {
  437. remainingOnLine := t.termWidth - t.cursorX
  438. todo := len(line)
  439. if todo > remainingOnLine {
  440. todo = remainingOnLine
  441. }
  442. t.queue(line[:todo])
  443. t.cursorX += todo
  444. line = line[todo:]
  445. if t.cursorX == t.termWidth {
  446. t.cursorX = 0
  447. t.cursorY++
  448. if t.cursorY > t.maxLine {
  449. t.maxLine = t.cursorY
  450. }
  451. }
  452. }
  453. }
  454. func (t *Terminal) Write(buf []byte) (n int, err error) {
  455. t.lock.Lock()
  456. defer t.lock.Unlock()
  457. if t.cursorX == 0 && t.cursorY == 0 {
  458. // This is the easy case: there's nothing on the screen that we
  459. // have to move out of the way.
  460. return t.c.Write(buf)
  461. }
  462. // We have a prompt and possibly user input on the screen. We
  463. // have to clear it first.
  464. t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
  465. t.cursorX = 0
  466. t.clearLineToRight()
  467. for t.cursorY > 0 {
  468. t.move(1 /* up */, 0, 0, 0)
  469. t.cursorY--
  470. t.clearLineToRight()
  471. }
  472. if _, err = t.c.Write(t.outBuf); err != nil {
  473. return
  474. }
  475. t.outBuf = t.outBuf[:0]
  476. if n, err = t.c.Write(buf); err != nil {
  477. return
  478. }
  479. t.queue([]rune(t.prompt))
  480. chars := len(t.prompt)
  481. if t.echo {
  482. t.queue(t.line)
  483. chars += len(t.line)
  484. }
  485. t.cursorX = chars % t.termWidth
  486. t.cursorY = chars / t.termWidth
  487. t.moveCursorToPos(t.pos)
  488. if _, err = t.c.Write(t.outBuf); err != nil {
  489. return
  490. }
  491. t.outBuf = t.outBuf[:0]
  492. return
  493. }
  494. // ReadPassword temporarily changes the prompt and reads a password, without
  495. // echo, from the terminal.
  496. func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
  497. t.lock.Lock()
  498. defer t.lock.Unlock()
  499. oldPrompt := t.prompt
  500. t.prompt = prompt
  501. t.echo = false
  502. line, err = t.readLine()
  503. t.prompt = oldPrompt
  504. t.echo = true
  505. return
  506. }
  507. // ReadLine returns a line of input from the terminal.
  508. func (t *Terminal) ReadLine() (line string, err error) {
  509. t.lock.Lock()
  510. defer t.lock.Unlock()
  511. return t.readLine()
  512. }
  513. func (t *Terminal) readLine() (line string, err error) {
  514. // t.lock must be held at this point
  515. if t.cursorX == 0 && t.cursorY == 0 {
  516. t.writeLine([]rune(t.prompt))
  517. t.c.Write(t.outBuf)
  518. t.outBuf = t.outBuf[:0]
  519. }
  520. for {
  521. rest := t.remainder
  522. lineOk := false
  523. for !lineOk {
  524. var key rune
  525. key, rest = bytesToKey(rest)
  526. if key == utf8.RuneError {
  527. break
  528. }
  529. if key == keyCtrlD {
  530. return "", io.EOF
  531. }
  532. line, lineOk = t.handleKey(key)
  533. }
  534. if len(rest) > 0 {
  535. n := copy(t.inBuf[:], rest)
  536. t.remainder = t.inBuf[:n]
  537. } else {
  538. t.remainder = nil
  539. }
  540. t.c.Write(t.outBuf)
  541. t.outBuf = t.outBuf[:0]
  542. if lineOk {
  543. if t.echo {
  544. t.historyIndex = -1
  545. t.history.Add(line)
  546. }
  547. return
  548. }
  549. // t.remainder is a slice at the beginning of t.inBuf
  550. // containing a partial key sequence
  551. readBuf := t.inBuf[len(t.remainder):]
  552. var n int
  553. t.lock.Unlock()
  554. n, err = t.c.Read(readBuf)
  555. t.lock.Lock()
  556. if err != nil {
  557. return
  558. }
  559. t.remainder = t.inBuf[:n+len(t.remainder)]
  560. }
  561. panic("unreachable") // for Go 1.0.
  562. }
  563. // SetPrompt sets the prompt to be used when reading subsequent lines.
  564. func (t *Terminal) SetPrompt(prompt string) {
  565. t.lock.Lock()
  566. defer t.lock.Unlock()
  567. t.prompt = prompt
  568. }
  569. func (t *Terminal) SetSize(width, height int) {
  570. t.lock.Lock()
  571. defer t.lock.Unlock()
  572. t.termWidth, t.termHeight = width, height
  573. }
  574. // stRingBuffer is a ring buffer of strings.
  575. type stRingBuffer struct {
  576. // entries contains max elements.
  577. entries []string
  578. max int
  579. // head contains the index of the element most recently added to the ring.
  580. head int
  581. // size contains the number of elements in the ring.
  582. size int
  583. }
  584. func (s *stRingBuffer) Add(a string) {
  585. if s.entries == nil {
  586. const defaultNumEntries = 100
  587. s.entries = make([]string, defaultNumEntries)
  588. s.max = defaultNumEntries
  589. }
  590. s.head = (s.head + 1) % s.max
  591. s.entries[s.head] = a
  592. if s.size < s.max {
  593. s.size++
  594. }
  595. }
  596. // NthPreviousEntry returns the value passed to the nth previous call to Add.
  597. // If n is zero then the immediately prior value is returned, if one, then the
  598. // next most recent, and so on. If such an element doesn't exist then ok is
  599. // false.
  600. func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
  601. if n >= s.size {
  602. return "", false
  603. }
  604. index := s.head - n
  605. if index < 0 {
  606. index += s.max
  607. }
  608. return s.entries[index], true
  609. }