keys.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package readline
  3. import (
  4. "errors"
  5. "fmt"
  6. "strconv"
  7. "kitty/tools/tui/loop"
  8. "kitty/tools/tui/shortcuts"
  9. )
  10. var _ = fmt.Print
  11. type ShortcutMap = shortcuts.ShortcutMap[Action]
  12. type KeyboardState struct {
  13. active_shortcut_maps []*ShortcutMap
  14. current_pending_keys []string
  15. current_numeric_argument string
  16. }
  17. var _default_shortcuts *ShortcutMap
  18. func default_shortcuts() *ShortcutMap {
  19. if _default_shortcuts == nil {
  20. sm := shortcuts.New[Action]()
  21. sm.AddOrPanic(ActionBackspace, "backspace")
  22. sm.AddOrPanic(ActionBackspace, "shift+backspace")
  23. sm.AddOrPanic(ActionBackspace, "ctrl+h")
  24. sm.AddOrPanic(ActionDelete, "delete")
  25. sm.AddOrPanic(ActionMoveToStartOfLine, "home")
  26. sm.AddOrPanic(ActionMoveToStartOfLine, "ctrl+a")
  27. sm.AddOrPanic(ActionMoveToEndOfLine, "end")
  28. sm.AddOrPanic(ActionMoveToEndOfLine, "ctrl+e")
  29. sm.AddOrPanic(ActionMoveToStartOfDocument, "ctrl+home")
  30. sm.AddOrPanic(ActionMoveToEndOfDocument, "ctrl+end")
  31. sm.AddOrPanic(ActionMoveToEndOfWord, "alt+f")
  32. sm.AddOrPanic(ActionMoveToEndOfWord, "ctrl+right")
  33. sm.AddOrPanic(ActionMoveToEndOfWord, "alt+right")
  34. sm.AddOrPanic(ActionMoveToStartOfWord, "ctrl+left")
  35. sm.AddOrPanic(ActionMoveToStartOfWord, "alt+left")
  36. sm.AddOrPanic(ActionMoveToStartOfWord, "alt+b")
  37. sm.AddOrPanic(ActionCursorLeft, "left")
  38. sm.AddOrPanic(ActionCursorLeft, "ctrl+b")
  39. sm.AddOrPanic(ActionCursorRight, "right")
  40. sm.AddOrPanic(ActionCursorRight, "ctrl+f")
  41. sm.AddOrPanic(ActionClearScreen, "ctrl+l")
  42. sm.AddOrPanic(ActionAbortCurrentLine, "ctrl+c")
  43. sm.AddOrPanic(ActionAbortCurrentLine, "ctrl+g")
  44. sm.AddOrPanic(ActionEndInput, "ctrl+d")
  45. sm.AddOrPanic(ActionAcceptInput, "enter")
  46. sm.AddOrPanic(ActionKillToEndOfLine, "ctrl+k")
  47. sm.AddOrPanic(ActionKillToStartOfLine, "ctrl+x")
  48. sm.AddOrPanic(ActionKillToStartOfLine, "ctrl+u")
  49. sm.AddOrPanic(ActionKillNextWord, "alt+d")
  50. sm.AddOrPanic(ActionKillPreviousWord, "alt+backspace")
  51. sm.AddOrPanic(ActionKillPreviousSpaceDelimitedWord, "ctrl+w")
  52. sm.AddOrPanic(ActionYank, "ctrl+y")
  53. sm.AddOrPanic(ActionPopYank, "alt+y")
  54. sm.AddOrPanic(ActionHistoryPreviousOrCursorUp, "up")
  55. sm.AddOrPanic(ActionHistoryNextOrCursorDown, "down")
  56. sm.AddOrPanic(ActionHistoryPrevious, "ctrl+p")
  57. sm.AddOrPanic(ActionHistoryNext, "ctrl+n")
  58. sm.AddOrPanic(ActionHistoryFirst, "alt+<")
  59. sm.AddOrPanic(ActionHistoryLast, "alt+>")
  60. sm.AddOrPanic(ActionHistoryIncrementalSearchBackwards, "ctrl+r")
  61. sm.AddOrPanic(ActionHistoryIncrementalSearchBackwards, "ctrl+?")
  62. sm.AddOrPanic(ActionHistoryIncrementalSearchForwards, "ctrl+s")
  63. sm.AddOrPanic(ActionHistoryIncrementalSearchForwards, "ctrl+/")
  64. sm.AddOrPanic(ActionNumericArgumentDigit0, "alt+0")
  65. sm.AddOrPanic(ActionNumericArgumentDigit1, "alt+1")
  66. sm.AddOrPanic(ActionNumericArgumentDigit2, "alt+2")
  67. sm.AddOrPanic(ActionNumericArgumentDigit3, "alt+3")
  68. sm.AddOrPanic(ActionNumericArgumentDigit4, "alt+4")
  69. sm.AddOrPanic(ActionNumericArgumentDigit5, "alt+5")
  70. sm.AddOrPanic(ActionNumericArgumentDigit6, "alt+6")
  71. sm.AddOrPanic(ActionNumericArgumentDigit7, "alt+7")
  72. sm.AddOrPanic(ActionNumericArgumentDigit8, "alt+8")
  73. sm.AddOrPanic(ActionNumericArgumentDigit9, "alt+9")
  74. sm.AddOrPanic(ActionNumericArgumentDigitMinus, "alt+-")
  75. sm.AddOrPanic(ActionCompleteForward, "Tab")
  76. sm.AddOrPanic(ActionCompleteBackward, "Shift+Tab")
  77. _default_shortcuts = sm
  78. }
  79. return _default_shortcuts
  80. }
  81. var _history_search_shortcuts *shortcuts.ShortcutMap[Action]
  82. func history_search_shortcuts() *shortcuts.ShortcutMap[Action] {
  83. if _history_search_shortcuts == nil {
  84. sm := shortcuts.New[Action]()
  85. sm.AddOrPanic(ActionBackspace, "backspace")
  86. sm.AddOrPanic(ActionBackspace, "ctrl+h")
  87. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "home")
  88. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+a")
  89. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "end")
  90. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+e")
  91. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+home")
  92. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+end")
  93. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "alt+f")
  94. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+right")
  95. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+left")
  96. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "alt+b")
  97. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "left")
  98. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+b")
  99. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "right")
  100. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+f")
  101. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "up")
  102. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "down")
  103. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+c")
  104. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+g")
  105. sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "escape")
  106. sm.AddOrPanic(ActionTerminateHistorySearchAndApply, "ctrl+d")
  107. sm.AddOrPanic(ActionTerminateHistorySearchAndApply, "enter")
  108. sm.AddOrPanic(ActionTerminateHistorySearchAndApply, "ctrl+j")
  109. _history_search_shortcuts = sm
  110. }
  111. return _history_search_shortcuts
  112. }
  113. var ErrCouldNotPerformAction = errors.New("Could not perform the specified action")
  114. var ErrAcceptInput = errors.New("Accept input")
  115. func (self *Readline) push_keyboard_map(m *ShortcutMap) {
  116. maps := self.keyboard_state.active_shortcut_maps
  117. self.keyboard_state = KeyboardState{}
  118. if maps == nil {
  119. maps = make([]*ShortcutMap, 0, 2)
  120. }
  121. self.keyboard_state.active_shortcut_maps = append(maps, m)
  122. }
  123. func (self *Readline) pop_keyboard_map() {
  124. maps := self.keyboard_state.active_shortcut_maps
  125. self.keyboard_state = KeyboardState{}
  126. if len(maps) > 0 {
  127. maps = maps[:len(maps)-1]
  128. self.keyboard_state.active_shortcut_maps = maps
  129. }
  130. }
  131. func (self *Readline) handle_numeric_arg(ac Action) {
  132. t := "-"
  133. num := int(ac - ActionNumericArgumentDigit0)
  134. if num < 10 {
  135. t = strconv.Itoa(num)
  136. }
  137. cna := self.keyboard_state.current_numeric_argument
  138. if (cna == "" && t == "0") || (cna != "" && t == "-") {
  139. self.add_text(t)
  140. self.keyboard_state.current_numeric_argument = ""
  141. self.last_action = ActionAddText
  142. } else {
  143. self.keyboard_state.current_numeric_argument += t
  144. self.last_action = ac
  145. }
  146. }
  147. func (self *Readline) dispatch_key_action(ac Action) error {
  148. self.keyboard_state.current_pending_keys = nil
  149. if ActionNumericArgumentDigit0 <= ac && ac <= ActionNumericArgumentDigitMinus {
  150. if self.history_search != nil {
  151. return ErrCouldNotPerformAction
  152. }
  153. self.handle_numeric_arg(ac)
  154. return nil
  155. }
  156. cna := self.keyboard_state.current_numeric_argument
  157. self.keyboard_state.current_numeric_argument = ""
  158. if cna == "" {
  159. cna = "1"
  160. }
  161. repeat_count, err := strconv.Atoi(cna)
  162. if err != nil || repeat_count <= 0 {
  163. repeat_count = 1
  164. }
  165. return self.perform_action(ac, uint(repeat_count))
  166. }
  167. func (self *Readline) handle_key_event(event *loop.KeyEvent) error {
  168. if event.Text != "" {
  169. return nil
  170. }
  171. sm := default_shortcuts()
  172. if len(self.keyboard_state.active_shortcut_maps) > 0 {
  173. sm = self.keyboard_state.active_shortcut_maps[len(self.keyboard_state.active_shortcut_maps)-1]
  174. }
  175. ac, pending := sm.ResolveKeyEvent(event, self.keyboard_state.current_pending_keys...)
  176. if pending != "" {
  177. event.Handled = true
  178. if self.keyboard_state.current_pending_keys == nil {
  179. self.keyboard_state.current_pending_keys = []string{}
  180. }
  181. self.keyboard_state.current_pending_keys = append(self.keyboard_state.current_pending_keys, pending)
  182. } else {
  183. self.keyboard_state.current_pending_keys = nil
  184. if ac != ActionNil {
  185. event.Handled = true
  186. return self.dispatch_key_action(ac)
  187. }
  188. }
  189. return nil
  190. }