line.go 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. // +build windows linux darwin openbsd freebsd netbsd
  2. package liner
  3. import (
  4. "container/ring"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "strings"
  9. "unicode"
  10. "unicode/utf8"
  11. )
  12. type action int
  13. const (
  14. left action = iota
  15. right
  16. up
  17. down
  18. home
  19. end
  20. insert
  21. del
  22. pageUp
  23. pageDown
  24. f1
  25. f2
  26. f3
  27. f4
  28. f5
  29. f6
  30. f7
  31. f8
  32. f9
  33. f10
  34. f11
  35. f12
  36. altB
  37. altF
  38. altY
  39. shiftTab
  40. wordLeft
  41. wordRight
  42. winch
  43. unknown
  44. )
  45. const (
  46. ctrlA = 1
  47. ctrlB = 2
  48. ctrlC = 3
  49. ctrlD = 4
  50. ctrlE = 5
  51. ctrlF = 6
  52. ctrlG = 7
  53. ctrlH = 8
  54. tab = 9
  55. lf = 10
  56. ctrlK = 11
  57. ctrlL = 12
  58. cr = 13
  59. ctrlN = 14
  60. ctrlO = 15
  61. ctrlP = 16
  62. ctrlQ = 17
  63. ctrlR = 18
  64. ctrlS = 19
  65. ctrlT = 20
  66. ctrlU = 21
  67. ctrlV = 22
  68. ctrlW = 23
  69. ctrlX = 24
  70. ctrlY = 25
  71. ctrlZ = 26
  72. esc = 27
  73. bs = 127
  74. )
  75. const (
  76. beep = "\a"
  77. )
  78. type tabDirection int
  79. const (
  80. tabForward tabDirection = iota
  81. tabReverse
  82. )
  83. func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
  84. s.needRefresh = false
  85. if s.multiLineMode {
  86. return s.refreshMultiLine(prompt, buf, pos)
  87. }
  88. return s.refreshSingleLine(prompt, buf, pos)
  89. }
  90. func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error {
  91. s.cursorPos(0)
  92. _, err := fmt.Print(string(prompt))
  93. if err != nil {
  94. return err
  95. }
  96. pLen := countGlyphs(prompt)
  97. bLen := countGlyphs(buf)
  98. pos = countGlyphs(buf[:pos])
  99. if pLen+bLen < s.columns {
  100. _, err = fmt.Print(string(buf))
  101. s.eraseLine()
  102. s.cursorPos(pLen + pos)
  103. } else {
  104. // Find space available
  105. space := s.columns - pLen
  106. space-- // space for cursor
  107. start := pos - space/2
  108. end := start + space
  109. if end > bLen {
  110. end = bLen
  111. start = end - space
  112. }
  113. if start < 0 {
  114. start = 0
  115. end = space
  116. }
  117. pos -= start
  118. // Leave space for markers
  119. if start > 0 {
  120. start++
  121. }
  122. if end < bLen {
  123. end--
  124. }
  125. startRune := len(getPrefixGlyphs(buf, start))
  126. line := getPrefixGlyphs(buf[startRune:], end-start)
  127. // Output
  128. if start > 0 {
  129. fmt.Print("{")
  130. }
  131. fmt.Print(string(line))
  132. if end < bLen {
  133. fmt.Print("}")
  134. }
  135. // Set cursor position
  136. s.eraseLine()
  137. s.cursorPos(pLen + pos)
  138. }
  139. return err
  140. }
  141. func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error {
  142. promptColumns := countMultiLineGlyphs(prompt, s.columns, 0)
  143. totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns)
  144. totalRows := (totalColumns + s.columns - 1) / s.columns
  145. maxRows := s.maxRows
  146. if totalRows > s.maxRows {
  147. s.maxRows = totalRows
  148. }
  149. cursorRows := s.cursorRows
  150. if cursorRows == 0 {
  151. cursorRows = 1
  152. }
  153. /* First step: clear all the lines used before. To do so start by
  154. * going to the last row. */
  155. if maxRows-cursorRows > 0 {
  156. s.moveDown(maxRows - cursorRows)
  157. }
  158. /* Now for every row clear it, go up. */
  159. for i := 0; i < maxRows-1; i++ {
  160. s.cursorPos(0)
  161. s.eraseLine()
  162. s.moveUp(1)
  163. }
  164. /* Clean the top line. */
  165. s.cursorPos(0)
  166. s.eraseLine()
  167. /* Write the prompt and the current buffer content */
  168. if _, err := fmt.Print(string(prompt)); err != nil {
  169. return err
  170. }
  171. if _, err := fmt.Print(string(buf)); err != nil {
  172. return err
  173. }
  174. /* If we are at the very end of the screen with our prompt, we need to
  175. * emit a newline and move the prompt to the first column. */
  176. cursorColumns := countMultiLineGlyphs(buf[:pos], s.columns, promptColumns)
  177. if cursorColumns == totalColumns && totalColumns%s.columns == 0 {
  178. s.emitNewLine()
  179. s.cursorPos(0)
  180. totalRows++
  181. if totalRows > s.maxRows {
  182. s.maxRows = totalRows
  183. }
  184. }
  185. /* Move cursor to right position. */
  186. cursorRows = (cursorColumns + s.columns) / s.columns
  187. if s.cursorRows > 0 && totalRows-cursorRows > 0 {
  188. s.moveUp(totalRows - cursorRows)
  189. }
  190. /* Set column. */
  191. s.cursorPos(cursorColumns % s.columns)
  192. s.cursorRows = cursorRows
  193. return nil
  194. }
  195. func (s *State) resetMultiLine(prompt []rune, buf []rune, pos int) {
  196. columns := countMultiLineGlyphs(prompt, s.columns, 0)
  197. columns = countMultiLineGlyphs(buf[:pos], s.columns, columns)
  198. columns += 2 // ^C
  199. cursorRows := (columns + s.columns) / s.columns
  200. if s.maxRows-cursorRows > 0 {
  201. for i := 0; i < s.maxRows-cursorRows; i++ {
  202. fmt.Println() // always moves the cursor down or scrolls the window up as needed
  203. }
  204. }
  205. s.maxRows = 1
  206. s.cursorRows = 0
  207. }
  208. func longestCommonPrefix(strs []string) string {
  209. if len(strs) == 0 {
  210. return ""
  211. }
  212. longest := strs[0]
  213. for _, str := range strs[1:] {
  214. for !strings.HasPrefix(str, longest) {
  215. longest = longest[:len(longest)-1]
  216. }
  217. }
  218. // Remove trailing partial runes
  219. longest = strings.TrimRight(longest, "\uFFFD")
  220. return longest
  221. }
  222. func (s *State) circularTabs(items []string) func(tabDirection) (string, error) {
  223. item := -1
  224. return func(direction tabDirection) (string, error) {
  225. if direction == tabForward {
  226. if item < len(items)-1 {
  227. item++
  228. } else {
  229. item = 0
  230. }
  231. } else if direction == tabReverse {
  232. if item > 0 {
  233. item--
  234. } else {
  235. item = len(items) - 1
  236. }
  237. }
  238. return items[item], nil
  239. }
  240. }
  241. func calculateColumns(screenWidth int, items []string) (numColumns, numRows, maxWidth int) {
  242. for _, item := range items {
  243. if len(item) >= screenWidth {
  244. return 1, len(items), screenWidth - 1
  245. }
  246. if len(item) >= maxWidth {
  247. maxWidth = len(item) + 1
  248. }
  249. }
  250. numColumns = screenWidth / maxWidth
  251. numRows = len(items) / numColumns
  252. if len(items)%numColumns > 0 {
  253. numRows++
  254. }
  255. if len(items) <= numColumns {
  256. maxWidth = 0
  257. }
  258. return
  259. }
  260. func (s *State) printedTabs(items []string) func(tabDirection) (string, error) {
  261. numTabs := 1
  262. prefix := longestCommonPrefix(items)
  263. return func(direction tabDirection) (string, error) {
  264. if len(items) == 1 {
  265. return items[0], nil
  266. }
  267. if numTabs == 2 {
  268. if len(items) > 100 {
  269. fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items))
  270. prompt:
  271. for {
  272. next, err := s.readNext()
  273. if err != nil {
  274. return prefix, err
  275. }
  276. if key, ok := next.(rune); ok {
  277. switch key {
  278. case 'n', 'N':
  279. return prefix, nil
  280. case 'y', 'Y':
  281. break prompt
  282. case ctrlC, ctrlD, cr, lf:
  283. s.restartPrompt()
  284. }
  285. }
  286. }
  287. }
  288. fmt.Println("")
  289. numColumns, numRows, maxWidth := calculateColumns(s.columns, items)
  290. for i := 0; i < numRows; i++ {
  291. for j := 0; j < numColumns*numRows; j += numRows {
  292. if i+j < len(items) {
  293. if maxWidth > 0 {
  294. fmt.Printf("%-*.[1]*s", maxWidth, items[i+j])
  295. } else {
  296. fmt.Printf("%v ", items[i+j])
  297. }
  298. }
  299. }
  300. fmt.Println("")
  301. }
  302. } else {
  303. numTabs++
  304. }
  305. return prefix, nil
  306. }
  307. }
  308. func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interface{}, error) {
  309. if s.completer == nil {
  310. return line, pos, rune(esc), nil
  311. }
  312. head, list, tail := s.completer(string(line), pos)
  313. if len(list) <= 0 {
  314. return line, pos, rune(esc), nil
  315. }
  316. hl := utf8.RuneCountInString(head)
  317. if len(list) == 1 {
  318. s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0]))
  319. return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil
  320. }
  321. direction := tabForward
  322. tabPrinter := s.circularTabs(list)
  323. if s.tabStyle == TabPrints {
  324. tabPrinter = s.printedTabs(list)
  325. }
  326. for {
  327. pick, err := tabPrinter(direction)
  328. if err != nil {
  329. return line, pos, rune(esc), err
  330. }
  331. s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick))
  332. next, err := s.readNext()
  333. if err != nil {
  334. return line, pos, rune(esc), err
  335. }
  336. if key, ok := next.(rune); ok {
  337. if key == tab {
  338. direction = tabForward
  339. continue
  340. }
  341. if key == esc {
  342. return line, pos, rune(esc), nil
  343. }
  344. }
  345. if a, ok := next.(action); ok && a == shiftTab {
  346. direction = tabReverse
  347. continue
  348. }
  349. return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil
  350. }
  351. }
  352. // reverse intelligent search, implements a bash-like history search.
  353. func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) {
  354. p := "(reverse-i-search)`': "
  355. s.refresh([]rune(p), origLine, origPos)
  356. line := []rune{}
  357. pos := 0
  358. foundLine := string(origLine)
  359. foundPos := origPos
  360. getLine := func() ([]rune, []rune, int) {
  361. search := string(line)
  362. prompt := "(reverse-i-search)`%s': "
  363. return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos
  364. }
  365. history, positions := s.getHistoryByPattern(string(line))
  366. historyPos := len(history) - 1
  367. for {
  368. next, err := s.readNext()
  369. if err != nil {
  370. return []rune(foundLine), foundPos, rune(esc), err
  371. }
  372. switch v := next.(type) {
  373. case rune:
  374. switch v {
  375. case ctrlR: // Search backwards
  376. if historyPos > 0 && historyPos < len(history) {
  377. historyPos--
  378. foundLine = history[historyPos]
  379. foundPos = positions[historyPos]
  380. } else {
  381. fmt.Print(beep)
  382. }
  383. case ctrlS: // Search forward
  384. if historyPos < len(history)-1 && historyPos >= 0 {
  385. historyPos++
  386. foundLine = history[historyPos]
  387. foundPos = positions[historyPos]
  388. } else {
  389. fmt.Print(beep)
  390. }
  391. case ctrlH, bs: // Backspace
  392. if pos <= 0 {
  393. fmt.Print(beep)
  394. } else {
  395. n := len(getSuffixGlyphs(line[:pos], 1))
  396. line = append(line[:pos-n], line[pos:]...)
  397. pos -= n
  398. // For each char deleted, display the last matching line of history
  399. history, positions := s.getHistoryByPattern(string(line))
  400. historyPos = len(history) - 1
  401. if len(history) > 0 {
  402. foundLine = history[historyPos]
  403. foundPos = positions[historyPos]
  404. } else {
  405. foundLine = ""
  406. foundPos = 0
  407. }
  408. }
  409. case ctrlG: // Cancel
  410. return origLine, origPos, rune(esc), err
  411. case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK,
  412. ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ:
  413. fallthrough
  414. case 0, ctrlC, esc, 28, 29, 30, 31:
  415. return []rune(foundLine), foundPos, next, err
  416. default:
  417. line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
  418. pos++
  419. // For each keystroke typed, display the last matching line of history
  420. history, positions = s.getHistoryByPattern(string(line))
  421. historyPos = len(history) - 1
  422. if len(history) > 0 {
  423. foundLine = history[historyPos]
  424. foundPos = positions[historyPos]
  425. } else {
  426. foundLine = ""
  427. foundPos = 0
  428. }
  429. }
  430. case action:
  431. return []rune(foundLine), foundPos, next, err
  432. }
  433. s.refresh(getLine())
  434. }
  435. }
  436. // addToKillRing adds some text to the kill ring. If mode is 0 it adds it to a
  437. // new node in the end of the kill ring, and move the current pointer to the new
  438. // node. If mode is 1 or 2 it appends or prepends the text to the current entry
  439. // of the killRing.
  440. func (s *State) addToKillRing(text []rune, mode int) {
  441. // Don't use the same underlying array as text
  442. killLine := make([]rune, len(text))
  443. copy(killLine, text)
  444. // Point killRing to a newNode, procedure depends on the killring state and
  445. // append mode.
  446. if mode == 0 { // Add new node to killRing
  447. if s.killRing == nil { // if killring is empty, create a new one
  448. s.killRing = ring.New(1)
  449. } else if s.killRing.Len() >= KillRingMax { // if killring is "full"
  450. s.killRing = s.killRing.Next()
  451. } else { // Normal case
  452. s.killRing.Link(ring.New(1))
  453. s.killRing = s.killRing.Next()
  454. }
  455. } else {
  456. if s.killRing == nil { // if killring is empty, create a new one
  457. s.killRing = ring.New(1)
  458. s.killRing.Value = []rune{}
  459. }
  460. if mode == 1 { // Append to last entry
  461. killLine = append(s.killRing.Value.([]rune), killLine...)
  462. } else if mode == 2 { // Prepend to last entry
  463. killLine = append(killLine, s.killRing.Value.([]rune)...)
  464. }
  465. }
  466. // Save text in the current killring node
  467. s.killRing.Value = killLine
  468. }
  469. func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{}, error) {
  470. if s.killRing == nil {
  471. return text, pos, rune(esc), nil
  472. }
  473. lineStart := text[:pos]
  474. lineEnd := text[pos:]
  475. var line []rune
  476. for {
  477. value := s.killRing.Value.([]rune)
  478. line = make([]rune, 0)
  479. line = append(line, lineStart...)
  480. line = append(line, value...)
  481. line = append(line, lineEnd...)
  482. pos = len(lineStart) + len(value)
  483. s.refresh(p, line, pos)
  484. next, err := s.readNext()
  485. if err != nil {
  486. return line, pos, next, err
  487. }
  488. switch v := next.(type) {
  489. case rune:
  490. return line, pos, next, nil
  491. case action:
  492. switch v {
  493. case altY:
  494. s.killRing = s.killRing.Prev()
  495. default:
  496. return line, pos, next, nil
  497. }
  498. }
  499. }
  500. }
  501. // Prompt displays p and returns a line of user input, not including a trailing
  502. // newline character. An io.EOF error is returned if the user signals end-of-file
  503. // by pressing Ctrl-D. Prompt allows line editing if the terminal supports it.
  504. func (s *State) Prompt(prompt string) (string, error) {
  505. return s.PromptWithSuggestion(prompt, "", 0)
  506. }
  507. // PromptWithSuggestion displays prompt and an editable text with cursor at
  508. // given position. The cursor will be set to the end of the line if given position
  509. // is negative or greater than length of text. Returns a line of user input, not
  510. // including a trailing newline character. An io.EOF error is returned if the user
  511. // signals end-of-file by pressing Ctrl-D.
  512. func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (string, error) {
  513. for _, r := range prompt {
  514. if unicode.Is(unicode.C, r) {
  515. return "", ErrInvalidPrompt
  516. }
  517. }
  518. if s.inputRedirected || !s.terminalSupported {
  519. return s.promptUnsupported(prompt)
  520. }
  521. if s.outputRedirected {
  522. return "", ErrNotTerminalOutput
  523. }
  524. s.historyMutex.RLock()
  525. defer s.historyMutex.RUnlock()
  526. fmt.Print(prompt)
  527. p := []rune(prompt)
  528. var line = []rune(text)
  529. historyEnd := ""
  530. var historyPrefix []string
  531. historyPos := 0
  532. historyStale := true
  533. historyAction := false // used to mark history related actions
  534. killAction := 0 // used to mark kill related actions
  535. defer s.stopPrompt()
  536. if pos < 0 || len(text) < pos {
  537. pos = len(text)
  538. }
  539. if len(line) > 0 {
  540. s.refresh(p, line, pos)
  541. }
  542. restart:
  543. s.startPrompt()
  544. s.getColumns()
  545. mainLoop:
  546. for {
  547. next, err := s.readNext()
  548. haveNext:
  549. if err != nil {
  550. if s.shouldRestart != nil && s.shouldRestart(err) {
  551. goto restart
  552. }
  553. return "", err
  554. }
  555. historyAction = false
  556. switch v := next.(type) {
  557. case rune:
  558. switch v {
  559. case cr, lf:
  560. if s.multiLineMode {
  561. s.resetMultiLine(p, line, pos)
  562. }
  563. fmt.Println()
  564. break mainLoop
  565. case ctrlA: // Start of line
  566. pos = 0
  567. s.needRefresh = true
  568. case ctrlE: // End of line
  569. pos = len(line)
  570. s.needRefresh = true
  571. case ctrlB: // left
  572. if pos > 0 {
  573. pos -= len(getSuffixGlyphs(line[:pos], 1))
  574. s.needRefresh = true
  575. } else {
  576. fmt.Print(beep)
  577. }
  578. case ctrlF: // right
  579. if pos < len(line) {
  580. pos += len(getPrefixGlyphs(line[pos:], 1))
  581. s.needRefresh = true
  582. } else {
  583. fmt.Print(beep)
  584. }
  585. case ctrlD: // del
  586. if pos == 0 && len(line) == 0 {
  587. // exit
  588. return "", io.EOF
  589. }
  590. // ctrlD is a potential EOF, so the rune reader shuts down.
  591. // Therefore, if it isn't actually an EOF, we must re-startPrompt.
  592. s.restartPrompt()
  593. if pos >= len(line) {
  594. fmt.Print(beep)
  595. } else {
  596. n := len(getPrefixGlyphs(line[pos:], 1))
  597. line = append(line[:pos], line[pos+n:]...)
  598. s.needRefresh = true
  599. }
  600. case ctrlK: // delete remainder of line
  601. if pos >= len(line) {
  602. fmt.Print(beep)
  603. } else {
  604. if killAction > 0 {
  605. s.addToKillRing(line[pos:], 1) // Add in apend mode
  606. } else {
  607. s.addToKillRing(line[pos:], 0) // Add in normal mode
  608. }
  609. killAction = 2 // Mark that there was a kill action
  610. line = line[:pos]
  611. s.needRefresh = true
  612. }
  613. case ctrlP: // up
  614. historyAction = true
  615. if historyStale {
  616. historyPrefix = s.getHistoryByPrefix(string(line))
  617. historyPos = len(historyPrefix)
  618. historyStale = false
  619. }
  620. if historyPos > 0 {
  621. if historyPos == len(historyPrefix) {
  622. historyEnd = string(line)
  623. }
  624. historyPos--
  625. line = []rune(historyPrefix[historyPos])
  626. pos = len(line)
  627. s.needRefresh = true
  628. } else {
  629. fmt.Print(beep)
  630. }
  631. case ctrlN: // down
  632. historyAction = true
  633. if historyStale {
  634. historyPrefix = s.getHistoryByPrefix(string(line))
  635. historyPos = len(historyPrefix)
  636. historyStale = false
  637. }
  638. if historyPos < len(historyPrefix) {
  639. historyPos++
  640. if historyPos == len(historyPrefix) {
  641. line = []rune(historyEnd)
  642. } else {
  643. line = []rune(historyPrefix[historyPos])
  644. }
  645. pos = len(line)
  646. s.needRefresh = true
  647. } else {
  648. fmt.Print(beep)
  649. }
  650. case ctrlT: // transpose prev glyph with glyph under cursor
  651. if len(line) < 2 || pos < 1 {
  652. fmt.Print(beep)
  653. } else {
  654. if pos == len(line) {
  655. pos -= len(getSuffixGlyphs(line, 1))
  656. }
  657. prev := getSuffixGlyphs(line[:pos], 1)
  658. next := getPrefixGlyphs(line[pos:], 1)
  659. scratch := make([]rune, len(prev))
  660. copy(scratch, prev)
  661. copy(line[pos-len(prev):], next)
  662. copy(line[pos-len(prev)+len(next):], scratch)
  663. pos += len(next)
  664. s.needRefresh = true
  665. }
  666. case ctrlL: // clear screen
  667. s.eraseScreen()
  668. s.needRefresh = true
  669. case ctrlC: // reset
  670. fmt.Println("^C")
  671. if s.multiLineMode {
  672. s.resetMultiLine(p, line, pos)
  673. }
  674. if s.ctrlCAborts {
  675. return "", ErrPromptAborted
  676. }
  677. line = line[:0]
  678. pos = 0
  679. fmt.Print(prompt)
  680. s.restartPrompt()
  681. case ctrlH, bs: // Backspace
  682. if pos <= 0 {
  683. fmt.Print(beep)
  684. } else {
  685. n := len(getSuffixGlyphs(line[:pos], 1))
  686. line = append(line[:pos-n], line[pos:]...)
  687. pos -= n
  688. s.needRefresh = true
  689. }
  690. case ctrlU: // Erase line before cursor
  691. if killAction > 0 {
  692. s.addToKillRing(line[:pos], 2) // Add in prepend mode
  693. } else {
  694. s.addToKillRing(line[:pos], 0) // Add in normal mode
  695. }
  696. killAction = 2 // Mark that there was some killing
  697. line = line[pos:]
  698. pos = 0
  699. s.needRefresh = true
  700. case ctrlW: // Erase word
  701. if pos == 0 {
  702. fmt.Print(beep)
  703. break
  704. }
  705. // Remove whitespace to the left
  706. var buf []rune // Store the deleted chars in a buffer
  707. for {
  708. if pos == 0 || !unicode.IsSpace(line[pos-1]) {
  709. break
  710. }
  711. buf = append(buf, line[pos-1])
  712. line = append(line[:pos-1], line[pos:]...)
  713. pos--
  714. }
  715. // Remove non-whitespace to the left
  716. for {
  717. if pos == 0 || unicode.IsSpace(line[pos-1]) {
  718. break
  719. }
  720. buf = append(buf, line[pos-1])
  721. line = append(line[:pos-1], line[pos:]...)
  722. pos--
  723. }
  724. // Invert the buffer and save the result on the killRing
  725. var newBuf []rune
  726. for i := len(buf) - 1; i >= 0; i-- {
  727. newBuf = append(newBuf, buf[i])
  728. }
  729. if killAction > 0 {
  730. s.addToKillRing(newBuf, 2) // Add in prepend mode
  731. } else {
  732. s.addToKillRing(newBuf, 0) // Add in normal mode
  733. }
  734. killAction = 2 // Mark that there was some killing
  735. s.needRefresh = true
  736. case ctrlY: // Paste from Yank buffer
  737. line, pos, next, err = s.yank(p, line, pos)
  738. goto haveNext
  739. case ctrlR: // Reverse Search
  740. line, pos, next, err = s.reverseISearch(line, pos)
  741. s.needRefresh = true
  742. goto haveNext
  743. case tab: // Tab completion
  744. line, pos, next, err = s.tabComplete(p, line, pos)
  745. goto haveNext
  746. // Catch keys that do nothing, but you don't want them to beep
  747. case esc:
  748. // DO NOTHING
  749. // Unused keys
  750. case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ:
  751. fallthrough
  752. // Catch unhandled control codes (anything <= 31)
  753. case 0, 28, 29, 30, 31:
  754. fmt.Print(beep)
  755. default:
  756. if pos == len(line) && !s.multiLineMode &&
  757. len(p)+len(line) < s.columns*4 && // Avoid countGlyphs on large lines
  758. countGlyphs(p)+countGlyphs(line) < s.columns-1 {
  759. line = append(line, v)
  760. fmt.Printf("%c", v)
  761. pos++
  762. } else {
  763. line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
  764. pos++
  765. s.needRefresh = true
  766. }
  767. }
  768. case action:
  769. switch v {
  770. case del:
  771. if pos >= len(line) {
  772. fmt.Print(beep)
  773. } else {
  774. n := len(getPrefixGlyphs(line[pos:], 1))
  775. line = append(line[:pos], line[pos+n:]...)
  776. }
  777. case left:
  778. if pos > 0 {
  779. pos -= len(getSuffixGlyphs(line[:pos], 1))
  780. } else {
  781. fmt.Print(beep)
  782. }
  783. case wordLeft, altB:
  784. if pos > 0 {
  785. var spaceHere, spaceLeft, leftKnown bool
  786. for {
  787. pos--
  788. if pos == 0 {
  789. break
  790. }
  791. if leftKnown {
  792. spaceHere = spaceLeft
  793. } else {
  794. spaceHere = unicode.IsSpace(line[pos])
  795. }
  796. spaceLeft, leftKnown = unicode.IsSpace(line[pos-1]), true
  797. if !spaceHere && spaceLeft {
  798. break
  799. }
  800. }
  801. } else {
  802. fmt.Print(beep)
  803. }
  804. case right:
  805. if pos < len(line) {
  806. pos += len(getPrefixGlyphs(line[pos:], 1))
  807. } else {
  808. fmt.Print(beep)
  809. }
  810. case wordRight, altF:
  811. if pos < len(line) {
  812. var spaceHere, spaceLeft, hereKnown bool
  813. for {
  814. pos++
  815. if pos == len(line) {
  816. break
  817. }
  818. if hereKnown {
  819. spaceLeft = spaceHere
  820. } else {
  821. spaceLeft = unicode.IsSpace(line[pos-1])
  822. }
  823. spaceHere, hereKnown = unicode.IsSpace(line[pos]), true
  824. if spaceHere && !spaceLeft {
  825. break
  826. }
  827. }
  828. } else {
  829. fmt.Print(beep)
  830. }
  831. case up:
  832. historyAction = true
  833. if historyStale {
  834. historyPrefix = s.getHistoryByPrefix(string(line))
  835. historyPos = len(historyPrefix)
  836. historyStale = false
  837. }
  838. if historyPos > 0 {
  839. if historyPos == len(historyPrefix) {
  840. historyEnd = string(line)
  841. }
  842. historyPos--
  843. line = []rune(historyPrefix[historyPos])
  844. pos = len(line)
  845. } else {
  846. fmt.Print(beep)
  847. }
  848. case down:
  849. historyAction = true
  850. if historyStale {
  851. historyPrefix = s.getHistoryByPrefix(string(line))
  852. historyPos = len(historyPrefix)
  853. historyStale = false
  854. }
  855. if historyPos < len(historyPrefix) {
  856. historyPos++
  857. if historyPos == len(historyPrefix) {
  858. line = []rune(historyEnd)
  859. } else {
  860. line = []rune(historyPrefix[historyPos])
  861. }
  862. pos = len(line)
  863. } else {
  864. fmt.Print(beep)
  865. }
  866. case home: // Start of line
  867. pos = 0
  868. case end: // End of line
  869. pos = len(line)
  870. case winch: // Window change
  871. if s.multiLineMode {
  872. if s.maxRows-s.cursorRows > 0 {
  873. s.moveDown(s.maxRows - s.cursorRows)
  874. }
  875. for i := 0; i < s.maxRows-1; i++ {
  876. s.cursorPos(0)
  877. s.eraseLine()
  878. s.moveUp(1)
  879. }
  880. s.maxRows = 1
  881. s.cursorRows = 1
  882. }
  883. }
  884. s.needRefresh = true
  885. }
  886. if s.needRefresh && !s.inputWaiting() {
  887. s.refresh(p, line, pos)
  888. }
  889. if !historyAction {
  890. historyStale = true
  891. }
  892. if killAction > 0 {
  893. killAction--
  894. }
  895. }
  896. return string(line), nil
  897. }
  898. // PasswordPrompt displays p, and then waits for user input. The input typed by
  899. // the user is not displayed in the terminal.
  900. func (s *State) PasswordPrompt(prompt string) (string, error) {
  901. for _, r := range prompt {
  902. if unicode.Is(unicode.C, r) {
  903. return "", ErrInvalidPrompt
  904. }
  905. }
  906. if !s.terminalSupported {
  907. return "", errors.New("liner: function not supported in this terminal")
  908. }
  909. if s.inputRedirected {
  910. return s.promptUnsupported(prompt)
  911. }
  912. if s.outputRedirected {
  913. return "", ErrNotTerminalOutput
  914. }
  915. defer s.stopPrompt()
  916. restart:
  917. s.startPrompt()
  918. s.getColumns()
  919. fmt.Print(prompt)
  920. p := []rune(prompt)
  921. var line []rune
  922. pos := 0
  923. mainLoop:
  924. for {
  925. next, err := s.readNext()
  926. if err != nil {
  927. if s.shouldRestart != nil && s.shouldRestart(err) {
  928. goto restart
  929. }
  930. return "", err
  931. }
  932. switch v := next.(type) {
  933. case rune:
  934. switch v {
  935. case cr, lf:
  936. if s.multiLineMode {
  937. s.resetMultiLine(p, line, pos)
  938. }
  939. fmt.Println()
  940. break mainLoop
  941. case ctrlD: // del
  942. if pos == 0 && len(line) == 0 {
  943. // exit
  944. return "", io.EOF
  945. }
  946. // ctrlD is a potential EOF, so the rune reader shuts down.
  947. // Therefore, if it isn't actually an EOF, we must re-startPrompt.
  948. s.restartPrompt()
  949. case ctrlL: // clear screen
  950. s.eraseScreen()
  951. s.refresh(p, []rune{}, 0)
  952. case ctrlH, bs: // Backspace
  953. if pos <= 0 {
  954. fmt.Print(beep)
  955. } else {
  956. n := len(getSuffixGlyphs(line[:pos], 1))
  957. line = append(line[:pos-n], line[pos:]...)
  958. pos -= n
  959. }
  960. case ctrlC:
  961. fmt.Println("^C")
  962. if s.multiLineMode {
  963. s.resetMultiLine(p, line, pos)
  964. }
  965. if s.ctrlCAborts {
  966. return "", ErrPromptAborted
  967. }
  968. line = line[:0]
  969. pos = 0
  970. fmt.Print(prompt)
  971. s.restartPrompt()
  972. // Unused keys
  973. case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS,
  974. ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ:
  975. fallthrough
  976. // Catch unhandled control codes (anything <= 31)
  977. case 0, 28, 29, 30, 31:
  978. fmt.Print(beep)
  979. default:
  980. line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
  981. pos++
  982. }
  983. }
  984. }
  985. return string(line), nil
  986. }