actions.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package readline
  3. import (
  4. "fmt"
  5. "io"
  6. "strings"
  7. "unicode"
  8. "kitty/tools/utils"
  9. "kitty/tools/wcswidth"
  10. )
  11. var _ = fmt.Print
  12. func (self *Readline) text_upto_cursor_pos() string {
  13. buf := strings.Builder{}
  14. buf.Grow(1024)
  15. for i, line := range self.input_state.lines {
  16. if i == self.input_state.cursor.Y {
  17. buf.WriteString(line[:min(len(line), self.input_state.cursor.X)])
  18. break
  19. } else {
  20. buf.WriteString(line)
  21. buf.WriteString("\n")
  22. }
  23. }
  24. return buf.String()
  25. }
  26. func (self *Readline) text_after_cursor_pos() string {
  27. buf := strings.Builder{}
  28. buf.Grow(1024)
  29. for i, line := range self.input_state.lines {
  30. if i == self.input_state.cursor.Y {
  31. buf.WriteString(line[min(len(line), self.input_state.cursor.X):])
  32. buf.WriteString("\n")
  33. } else if i > self.input_state.cursor.Y {
  34. buf.WriteString(line)
  35. buf.WriteString("\n")
  36. }
  37. }
  38. ans := buf.String()
  39. if ans != "" {
  40. ans = ans[:len(ans)-1]
  41. }
  42. return ans
  43. }
  44. func (self *Readline) all_text() string {
  45. return strings.Join(self.input_state.lines, "\n")
  46. }
  47. func (self *Readline) set_text(text string) {
  48. self.move_to_start()
  49. self.erase_chars_after_cursor(123456789, true)
  50. if text != "" {
  51. self.add_text(text)
  52. }
  53. self.move_to_end()
  54. }
  55. func (self *Readline) add_text(text string) {
  56. new_lines := make([]string, 0, len(self.input_state.lines)+4)
  57. new_lines = append(new_lines, self.input_state.lines[:self.input_state.cursor.Y]...)
  58. var lines_after []string
  59. if len(self.input_state.lines) > self.input_state.cursor.Y+1 {
  60. lines_after = self.input_state.lines[self.input_state.cursor.Y+1:]
  61. }
  62. has_trailing_newline := strings.HasSuffix(text, "\n")
  63. add_line_break := func(line string) {
  64. new_lines = append(new_lines, line)
  65. self.input_state.cursor.X = len(line)
  66. self.input_state.cursor.Y += 1
  67. }
  68. cline := self.input_state.lines[self.input_state.cursor.Y]
  69. before_first_line := cline[:self.input_state.cursor.X]
  70. after_first_line := ""
  71. if self.input_state.cursor.X < len(cline) {
  72. after_first_line = cline[self.input_state.cursor.X:]
  73. }
  74. for i, line := range utils.Splitlines(text) {
  75. if i > 0 {
  76. add_line_break(line)
  77. } else {
  78. line := before_first_line + line
  79. self.input_state.cursor.X = len(line)
  80. new_lines = append(new_lines, line)
  81. }
  82. }
  83. if has_trailing_newline {
  84. add_line_break("")
  85. }
  86. if after_first_line != "" {
  87. if len(new_lines) == 0 {
  88. new_lines = append(new_lines, "")
  89. }
  90. new_lines[len(new_lines)-1] += after_first_line
  91. }
  92. if len(lines_after) > 0 {
  93. new_lines = append(new_lines, lines_after...)
  94. }
  95. self.input_state.lines = new_lines
  96. }
  97. func (self *Readline) move_cursor_left(amt uint, traverse_line_breaks bool) (amt_moved uint) {
  98. for amt_moved < amt {
  99. if self.input_state.cursor.X == 0 {
  100. if !traverse_line_breaks || self.input_state.cursor.Y == 0 {
  101. return amt_moved
  102. }
  103. self.input_state.cursor.Y -= 1
  104. self.input_state.cursor.X = len(self.input_state.lines[self.input_state.cursor.Y])
  105. amt_moved++
  106. continue
  107. }
  108. line := self.input_state.lines[self.input_state.cursor.Y]
  109. for ci := wcswidth.NewCellIterator(line[:self.input_state.cursor.X]).GotoEnd(); amt_moved < amt && ci.Backward(); amt_moved++ {
  110. self.input_state.cursor.X -= len(ci.Current())
  111. }
  112. }
  113. return amt_moved
  114. }
  115. func (self *Readline) move_cursor_right(amt uint, traverse_line_breaks bool) (amt_moved uint) {
  116. for amt_moved < amt {
  117. line := self.input_state.lines[self.input_state.cursor.Y]
  118. if self.input_state.cursor.X >= len(line) {
  119. if !traverse_line_breaks || self.input_state.cursor.Y == len(self.input_state.lines)-1 {
  120. return amt_moved
  121. }
  122. self.input_state.cursor.Y += 1
  123. self.input_state.cursor.X = 0
  124. amt_moved++
  125. continue
  126. }
  127. for ci := wcswidth.NewCellIterator(line[self.input_state.cursor.X:]); amt_moved < amt && ci.Forward(); amt_moved++ {
  128. self.input_state.cursor.X += len(ci.Current())
  129. }
  130. }
  131. return amt_moved
  132. }
  133. func (self *Readline) move_cursor_to_target_line(source_line, target_line *ScreenLine) {
  134. if source_line != target_line {
  135. visual_distance_into_text := source_line.CursorCell - source_line.Prompt.Length
  136. self.input_state.cursor.Y = target_line.ParentLineNumber
  137. tp := wcswidth.TruncateToVisualLength(target_line.Text, visual_distance_into_text)
  138. self.input_state.cursor.X = target_line.OffsetInParentLine + len(tp)
  139. }
  140. }
  141. func (self *Readline) move_cursor_vertically(amt int) (ans int) {
  142. if self.screen_width == 0 {
  143. self.update_current_screen_size()
  144. }
  145. screen_lines := self.get_screen_lines()
  146. cursor_line_num := 0
  147. for i, sl := range screen_lines {
  148. if sl.CursorCell > -1 {
  149. cursor_line_num = i
  150. break
  151. }
  152. }
  153. target_line_num := min(max(0, cursor_line_num+amt), len(screen_lines)-1)
  154. ans = target_line_num - cursor_line_num
  155. if ans != 0 {
  156. self.move_cursor_to_target_line(screen_lines[cursor_line_num], screen_lines[target_line_num])
  157. }
  158. return ans
  159. }
  160. func (self *Readline) move_cursor_down(amt uint) uint {
  161. ans := uint(0)
  162. if self.screen_width == 0 {
  163. self.update_current_screen_size()
  164. }
  165. return ans
  166. }
  167. func (self *Readline) move_to_start_of_line() bool {
  168. if self.input_state.cursor.X > 0 {
  169. self.input_state.cursor.X = 0
  170. return true
  171. }
  172. return false
  173. }
  174. func (self *Readline) move_to_end_of_line() bool {
  175. line := self.input_state.lines[self.input_state.cursor.Y]
  176. if self.input_state.cursor.X >= len(line) {
  177. return false
  178. }
  179. self.input_state.cursor.X = len(line)
  180. return true
  181. }
  182. func (self *Readline) move_to_start() bool {
  183. if self.input_state.cursor.Y == 0 && self.input_state.cursor.X == 0 {
  184. return false
  185. }
  186. self.input_state.cursor.Y = 0
  187. self.move_to_start_of_line()
  188. return true
  189. }
  190. func (self *Readline) move_to_end() bool {
  191. line := self.input_state.lines[self.input_state.cursor.Y]
  192. if self.input_state.cursor.Y == len(self.input_state.lines)-1 && self.input_state.cursor.X >= len(line) {
  193. return false
  194. }
  195. self.input_state.cursor.Y = len(self.input_state.lines) - 1
  196. self.move_to_end_of_line()
  197. return true
  198. }
  199. func (self *Readline) erase_between(start, end Position) string {
  200. if end.Less(start) {
  201. start, end = end, start
  202. }
  203. buf := strings.Builder{}
  204. if start.Y == end.Y {
  205. line := self.input_state.lines[start.Y]
  206. buf.WriteString(line[start.X:end.X])
  207. self.input_state.lines[start.Y] = line[:start.X] + line[end.X:]
  208. if self.input_state.cursor.Y == start.Y && self.input_state.cursor.X >= start.X {
  209. if self.input_state.cursor.X < end.X {
  210. self.input_state.cursor.X = start.X
  211. } else {
  212. self.input_state.cursor.X -= end.X - start.X
  213. }
  214. }
  215. return buf.String()
  216. }
  217. lines := make([]string, 0, len(self.input_state.lines))
  218. for i, line := range self.input_state.lines {
  219. if i < start.Y || i > end.Y {
  220. lines = append(lines, line)
  221. } else if i == start.Y {
  222. lines = append(lines, line[:start.X])
  223. buf.WriteString(line[start.X:])
  224. if self.input_state.cursor.Y == i && self.input_state.cursor.X > start.X {
  225. self.input_state.cursor.X = start.X
  226. }
  227. } else if i == end.Y {
  228. lines[len(lines)-1] += line[end.X:]
  229. buf.WriteString(line[:end.X])
  230. if i == self.input_state.cursor.Y {
  231. self.input_state.cursor.Y = start.Y
  232. if self.input_state.cursor.X < end.X {
  233. self.input_state.cursor.X = start.X
  234. } else {
  235. self.input_state.cursor.X -= end.X - start.X
  236. }
  237. }
  238. } else {
  239. if i == self.input_state.cursor.Y {
  240. self.input_state.cursor = start
  241. }
  242. buf.WriteString(line)
  243. buf.WriteString("\n")
  244. }
  245. }
  246. self.input_state.lines = lines
  247. return buf.String()
  248. }
  249. func (self *Readline) erase_chars_before_cursor(amt uint, traverse_line_breaks bool) uint {
  250. pos := self.input_state.cursor
  251. num := self.move_cursor_left(amt, traverse_line_breaks)
  252. if num == 0 {
  253. return num
  254. }
  255. self.erase_between(self.input_state.cursor, pos)
  256. return num
  257. }
  258. func (self *Readline) erase_chars_after_cursor(amt uint, traverse_line_breaks bool) uint {
  259. pos := self.input_state.cursor
  260. num := self.move_cursor_right(amt, traverse_line_breaks)
  261. if num == 0 {
  262. return num
  263. }
  264. self.erase_between(pos, self.input_state.cursor)
  265. return num
  266. }
  267. func has_word_chars(text string) bool {
  268. for _, ch := range text {
  269. if unicode.IsLetter(ch) || unicode.IsDigit(ch) {
  270. return true
  271. }
  272. }
  273. return false
  274. }
  275. func (self *Readline) move_to_end_of_word(amt uint, traverse_line_breaks bool, is_part_of_word func(string) bool) (num_of_words_moved uint) {
  276. if amt == 0 {
  277. return 0
  278. }
  279. line := self.input_state.lines[self.input_state.cursor.Y]
  280. in_word := false
  281. ci := wcswidth.NewCellIterator(line[self.input_state.cursor.X:])
  282. sz := 0
  283. for ci.Forward() {
  284. current_is_word_char := is_part_of_word(ci.Current())
  285. plen := sz
  286. sz += len(ci.Current())
  287. if current_is_word_char {
  288. in_word = true
  289. } else if in_word {
  290. self.input_state.cursor.X += plen
  291. amt--
  292. num_of_words_moved++
  293. if amt == 0 {
  294. return
  295. }
  296. in_word = false
  297. }
  298. }
  299. if self.move_to_end_of_line() {
  300. amt--
  301. num_of_words_moved++
  302. }
  303. if amt > 0 {
  304. if traverse_line_breaks && self.input_state.cursor.Y < len(self.input_state.lines)-1 {
  305. self.input_state.cursor.Y++
  306. self.input_state.cursor.X = 0
  307. num_of_words_moved += self.move_to_end_of_word(amt, traverse_line_breaks, is_part_of_word)
  308. }
  309. }
  310. return
  311. }
  312. func (self *Readline) move_to_start_of_word(amt uint, traverse_line_breaks bool, is_part_of_word func(string) bool) (num_of_words_moved uint) {
  313. if amt == 0 {
  314. return 0
  315. }
  316. line := self.input_state.lines[self.input_state.cursor.Y]
  317. in_word := false
  318. ci := wcswidth.NewCellIterator(line[:self.input_state.cursor.X]).GotoEnd()
  319. sz := 0
  320. for ci.Backward() {
  321. current_is_word_char := is_part_of_word(ci.Current())
  322. plen := sz
  323. sz += len(ci.Current())
  324. if current_is_word_char {
  325. in_word = true
  326. } else if in_word {
  327. self.input_state.cursor.X -= plen
  328. amt--
  329. num_of_words_moved++
  330. if amt == 0 {
  331. return
  332. }
  333. in_word = false
  334. }
  335. }
  336. if self.move_to_start_of_line() {
  337. amt--
  338. num_of_words_moved++
  339. }
  340. if amt > 0 {
  341. if traverse_line_breaks && self.input_state.cursor.Y > 0 {
  342. self.input_state.cursor.Y--
  343. self.input_state.cursor.X = len(self.input_state.lines[self.input_state.cursor.Y])
  344. num_of_words_moved += self.move_to_start_of_word(amt, traverse_line_breaks, has_word_chars)
  345. }
  346. }
  347. return
  348. }
  349. func (self *Readline) kill_text(text string) {
  350. if ActionStartKillActions < self.last_action && self.last_action < ActionEndKillActions {
  351. self.kill_ring.append_to_existing_item(text)
  352. } else {
  353. self.kill_ring.add_new_item(text)
  354. }
  355. }
  356. func (self *Readline) kill_to_end_of_line() bool {
  357. line := self.input_state.lines[self.input_state.cursor.Y]
  358. if self.input_state.cursor.X >= len(line) {
  359. return false
  360. }
  361. self.input_state.lines[self.input_state.cursor.Y] = line[:self.input_state.cursor.X]
  362. self.kill_text(line[self.input_state.cursor.X:])
  363. return true
  364. }
  365. func (self *Readline) kill_to_start_of_line() bool {
  366. line := self.input_state.lines[self.input_state.cursor.Y]
  367. if self.input_state.cursor.X <= 0 {
  368. return false
  369. }
  370. self.input_state.lines[self.input_state.cursor.Y] = line[self.input_state.cursor.X:]
  371. self.kill_text(line[:self.input_state.cursor.X])
  372. self.input_state.cursor.X = 0
  373. return true
  374. }
  375. func (self *Readline) kill_next_word(amt uint, traverse_line_breaks bool) (num_killed uint) {
  376. before := self.input_state.cursor
  377. num_killed = self.move_to_end_of_word(amt, traverse_line_breaks, has_word_chars)
  378. if num_killed > 0 {
  379. self.kill_text(self.erase_between(before, self.input_state.cursor))
  380. }
  381. return num_killed
  382. }
  383. func (self *Readline) kill_previous_word(amt uint, traverse_line_breaks bool) (num_killed uint) {
  384. before := self.input_state.cursor
  385. num_killed = self.move_to_start_of_word(amt, traverse_line_breaks, has_word_chars)
  386. if num_killed > 0 {
  387. self.kill_text(self.erase_between(self.input_state.cursor, before))
  388. }
  389. return num_killed
  390. }
  391. func has_no_space_chars(text string) bool {
  392. for _, r := range text {
  393. if unicode.IsSpace(r) {
  394. return false
  395. }
  396. }
  397. return true
  398. }
  399. func (self *Readline) kill_previous_space_delimited_word(amt uint, traverse_line_breaks bool) (num_killed uint) {
  400. before := self.input_state.cursor
  401. num_killed = self.move_to_start_of_word(amt, traverse_line_breaks, has_no_space_chars)
  402. if num_killed > 0 {
  403. self.kill_text(self.erase_between(self.input_state.cursor, before))
  404. }
  405. return num_killed
  406. }
  407. func (self *Readline) ensure_position_in_bounds(pos *Position) *Position {
  408. pos.Y = max(0, min(pos.Y, len(self.input_state.lines)-1))
  409. line := self.input_state.lines[pos.Y]
  410. pos.X = max(0, min(pos.X, len(line)))
  411. return pos
  412. }
  413. func (self *Readline) yank(repeat_count uint, pop bool) bool {
  414. if pop && self.last_action != ActionYank && self.last_action != ActionPopYank {
  415. return false
  416. }
  417. text := ""
  418. if pop {
  419. text = self.kill_ring.pop_yank()
  420. } else {
  421. text = self.kill_ring.yank()
  422. }
  423. if text == "" {
  424. return false
  425. }
  426. before := self.input_state.cursor
  427. if pop {
  428. self.ensure_position_in_bounds(&self.last_yank_extent.start)
  429. self.ensure_position_in_bounds(&self.last_yank_extent.end)
  430. self.erase_between(self.last_yank_extent.start, self.last_yank_extent.end)
  431. self.input_state.cursor = self.last_yank_extent.start
  432. before = self.input_state.cursor
  433. }
  434. self.add_text(text)
  435. self.last_yank_extent.start = before
  436. self.last_yank_extent.end = self.input_state.cursor
  437. return true
  438. }
  439. func (self *Readline) history_first() bool {
  440. self.create_history_matches()
  441. return self.history_matches.first(self)
  442. }
  443. func (self *Readline) history_last() bool {
  444. self.create_history_matches()
  445. return self.history_matches.last(self)
  446. }
  447. func (self *Readline) history_prev(repeat_count uint) bool {
  448. self.create_history_matches()
  449. return self.history_matches.previous(repeat_count, self)
  450. }
  451. func (self *Readline) history_next(repeat_count uint) bool {
  452. self.create_history_matches()
  453. return self.history_matches.next(repeat_count, self)
  454. }
  455. func (self *Readline) _perform_action(ac Action, repeat_count uint) (err error, dont_set_last_action bool) {
  456. switch ac {
  457. case ActionBackspace:
  458. if self.history_search != nil {
  459. if self.remove_text_from_history_search(repeat_count) > 0 {
  460. return
  461. }
  462. } else {
  463. if self.erase_chars_before_cursor(repeat_count, true) > 0 {
  464. return
  465. }
  466. }
  467. case ActionDelete:
  468. if self.erase_chars_after_cursor(repeat_count, true) > 0 {
  469. return
  470. }
  471. case ActionMoveToStartOfLine:
  472. if self.move_to_start_of_line() {
  473. return
  474. }
  475. case ActionMoveToEndOfLine:
  476. if self.move_to_end_of_line() {
  477. return
  478. }
  479. case ActionMoveToEndOfWord:
  480. if self.move_to_end_of_word(repeat_count, true, has_word_chars) > 0 {
  481. return
  482. }
  483. case ActionMoveToStartOfWord:
  484. if self.move_to_start_of_word(repeat_count, true, has_word_chars) > 0 {
  485. return
  486. }
  487. case ActionMoveToStartOfDocument:
  488. if self.move_to_start() {
  489. return
  490. }
  491. case ActionMoveToEndOfDocument:
  492. if self.move_to_end() {
  493. return
  494. }
  495. case ActionCursorLeft:
  496. if self.move_cursor_left(repeat_count, true) > 0 {
  497. return
  498. }
  499. case ActionCursorRight:
  500. if self.move_cursor_right(repeat_count, true) > 0 {
  501. return
  502. }
  503. case ActionEndInput:
  504. line := self.input_state.lines[self.input_state.cursor.Y]
  505. if line == "" {
  506. err = io.EOF
  507. } else {
  508. err = self.perform_action(ActionAcceptInput, 1)
  509. }
  510. return
  511. case ActionAcceptInput:
  512. err = ErrAcceptInput
  513. return
  514. case ActionCursorUp:
  515. if self.move_cursor_vertically(-int(repeat_count)) != 0 {
  516. return
  517. }
  518. case ActionCursorDown:
  519. if self.move_cursor_vertically(int(repeat_count)) != 0 {
  520. return
  521. }
  522. case ActionHistoryPreviousOrCursorUp:
  523. dont_set_last_action = true
  524. if self.perform_action(ActionCursorUp, repeat_count) == ErrCouldNotPerformAction {
  525. err = self.perform_action(ActionHistoryPrevious, repeat_count)
  526. }
  527. return
  528. case ActionHistoryNextOrCursorDown:
  529. dont_set_last_action = true
  530. if self.perform_action(ActionCursorDown, repeat_count) == ErrCouldNotPerformAction {
  531. err = self.perform_action(ActionHistoryNext, repeat_count)
  532. }
  533. return
  534. case ActionHistoryFirst:
  535. if self.history_first() {
  536. return
  537. }
  538. case ActionHistoryPrevious:
  539. if self.history_prev(repeat_count) {
  540. return
  541. }
  542. case ActionHistoryNext:
  543. if self.history_next(repeat_count) {
  544. return
  545. }
  546. case ActionHistoryLast:
  547. if self.history_last() {
  548. return
  549. }
  550. case ActionClearScreen:
  551. self.loop.StartAtomicUpdate()
  552. self.loop.ClearScreen()
  553. self.RedrawNonAtomic()
  554. self.loop.EndAtomicUpdate()
  555. return
  556. case ActionKillToEndOfLine:
  557. if self.kill_to_end_of_line() {
  558. return
  559. }
  560. case ActionKillToStartOfLine:
  561. if self.kill_to_start_of_line() {
  562. return
  563. }
  564. case ActionKillNextWord:
  565. if self.kill_next_word(repeat_count, true) > 0 {
  566. return
  567. }
  568. case ActionKillPreviousWord:
  569. if self.kill_previous_word(repeat_count, true) > 0 {
  570. return
  571. }
  572. case ActionKillPreviousSpaceDelimitedWord:
  573. if self.kill_previous_space_delimited_word(repeat_count, true) > 0 {
  574. return
  575. }
  576. case ActionYank:
  577. if self.yank(repeat_count, false) {
  578. return
  579. }
  580. case ActionPopYank:
  581. if self.yank(repeat_count, true) {
  582. return
  583. }
  584. case ActionAbortCurrentLine:
  585. self.loop.QueueWriteString("\r\n")
  586. self.ResetText()
  587. return
  588. case ActionHistoryIncrementalSearchForwards:
  589. if self.history_search == nil {
  590. self.create_history_search(false, repeat_count)
  591. return
  592. }
  593. if self.next_history_search(false, repeat_count) {
  594. return
  595. }
  596. case ActionHistoryIncrementalSearchBackwards:
  597. if self.history_search == nil {
  598. self.create_history_search(true, repeat_count)
  599. return
  600. }
  601. if self.next_history_search(true, repeat_count) {
  602. return
  603. }
  604. case ActionAddText:
  605. text := strings.Repeat(self.text_to_be_added, int(repeat_count))
  606. self.text_to_be_added = ""
  607. if self.history_search != nil {
  608. self.add_text_to_history_search(text)
  609. } else {
  610. self.add_text(text)
  611. }
  612. return
  613. case ActionTerminateHistorySearchAndRestore:
  614. if self.history_search != nil {
  615. self.end_history_search(false)
  616. return
  617. }
  618. case ActionTerminateHistorySearchAndApply:
  619. if self.history_search != nil {
  620. self.end_history_search(true)
  621. return
  622. }
  623. case ActionCompleteForward:
  624. if self.complete(true, repeat_count) {
  625. return
  626. }
  627. case ActionCompleteBackward:
  628. if self.complete(false, repeat_count) {
  629. return
  630. }
  631. }
  632. err = ErrCouldNotPerformAction
  633. return
  634. }
  635. func (self *Readline) perform_action(ac Action, repeat_count uint) error {
  636. err, dont_set_last_action := self._perform_action(ac, repeat_count)
  637. if err == nil && !dont_set_last_action {
  638. self.last_action = ac
  639. if self.completions.current.results != nil && ac != ActionCompleteForward && ac != ActionCompleteBackward {
  640. self.completions.current = completion{}
  641. }
  642. }
  643. return err
  644. }