line.go 26 KB

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