123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
- package readline
- import (
- "errors"
- "fmt"
- "strconv"
- "kitty/tools/tui/loop"
- "kitty/tools/tui/shortcuts"
- )
- var _ = fmt.Print
- type ShortcutMap = shortcuts.ShortcutMap[Action]
- type KeyboardState struct {
- active_shortcut_maps []*ShortcutMap
- current_pending_keys []string
- current_numeric_argument string
- }
- var _default_shortcuts *ShortcutMap
- func default_shortcuts() *ShortcutMap {
- if _default_shortcuts == nil {
- sm := shortcuts.New[Action]()
- sm.AddOrPanic(ActionBackspace, "backspace")
- sm.AddOrPanic(ActionBackspace, "shift+backspace")
- sm.AddOrPanic(ActionBackspace, "ctrl+h")
- sm.AddOrPanic(ActionDelete, "delete")
- sm.AddOrPanic(ActionMoveToStartOfLine, "home")
- sm.AddOrPanic(ActionMoveToStartOfLine, "ctrl+a")
- sm.AddOrPanic(ActionMoveToEndOfLine, "end")
- sm.AddOrPanic(ActionMoveToEndOfLine, "ctrl+e")
- sm.AddOrPanic(ActionMoveToStartOfDocument, "ctrl+home")
- sm.AddOrPanic(ActionMoveToEndOfDocument, "ctrl+end")
- sm.AddOrPanic(ActionMoveToEndOfWord, "alt+f")
- sm.AddOrPanic(ActionMoveToEndOfWord, "ctrl+right")
- sm.AddOrPanic(ActionMoveToEndOfWord, "alt+right")
- sm.AddOrPanic(ActionMoveToStartOfWord, "ctrl+left")
- sm.AddOrPanic(ActionMoveToStartOfWord, "alt+left")
- sm.AddOrPanic(ActionMoveToStartOfWord, "alt+b")
- sm.AddOrPanic(ActionCursorLeft, "left")
- sm.AddOrPanic(ActionCursorLeft, "ctrl+b")
- sm.AddOrPanic(ActionCursorRight, "right")
- sm.AddOrPanic(ActionCursorRight, "ctrl+f")
- sm.AddOrPanic(ActionClearScreen, "ctrl+l")
- sm.AddOrPanic(ActionAbortCurrentLine, "ctrl+c")
- sm.AddOrPanic(ActionAbortCurrentLine, "ctrl+g")
- sm.AddOrPanic(ActionEndInput, "ctrl+d")
- sm.AddOrPanic(ActionAcceptInput, "enter")
- sm.AddOrPanic(ActionKillToEndOfLine, "ctrl+k")
- sm.AddOrPanic(ActionKillToStartOfLine, "ctrl+x")
- sm.AddOrPanic(ActionKillToStartOfLine, "ctrl+u")
- sm.AddOrPanic(ActionKillNextWord, "alt+d")
- sm.AddOrPanic(ActionKillPreviousWord, "alt+backspace")
- sm.AddOrPanic(ActionKillPreviousSpaceDelimitedWord, "ctrl+w")
- sm.AddOrPanic(ActionYank, "ctrl+y")
- sm.AddOrPanic(ActionPopYank, "alt+y")
- sm.AddOrPanic(ActionHistoryPreviousOrCursorUp, "up")
- sm.AddOrPanic(ActionHistoryNextOrCursorDown, "down")
- sm.AddOrPanic(ActionHistoryPrevious, "ctrl+p")
- sm.AddOrPanic(ActionHistoryNext, "ctrl+n")
- sm.AddOrPanic(ActionHistoryFirst, "alt+<")
- sm.AddOrPanic(ActionHistoryLast, "alt+>")
- sm.AddOrPanic(ActionHistoryIncrementalSearchBackwards, "ctrl+r")
- sm.AddOrPanic(ActionHistoryIncrementalSearchBackwards, "ctrl+?")
- sm.AddOrPanic(ActionHistoryIncrementalSearchForwards, "ctrl+s")
- sm.AddOrPanic(ActionHistoryIncrementalSearchForwards, "ctrl+/")
- sm.AddOrPanic(ActionNumericArgumentDigit0, "alt+0")
- sm.AddOrPanic(ActionNumericArgumentDigit1, "alt+1")
- sm.AddOrPanic(ActionNumericArgumentDigit2, "alt+2")
- sm.AddOrPanic(ActionNumericArgumentDigit3, "alt+3")
- sm.AddOrPanic(ActionNumericArgumentDigit4, "alt+4")
- sm.AddOrPanic(ActionNumericArgumentDigit5, "alt+5")
- sm.AddOrPanic(ActionNumericArgumentDigit6, "alt+6")
- sm.AddOrPanic(ActionNumericArgumentDigit7, "alt+7")
- sm.AddOrPanic(ActionNumericArgumentDigit8, "alt+8")
- sm.AddOrPanic(ActionNumericArgumentDigit9, "alt+9")
- sm.AddOrPanic(ActionNumericArgumentDigitMinus, "alt+-")
- sm.AddOrPanic(ActionCompleteForward, "Tab")
- sm.AddOrPanic(ActionCompleteBackward, "Shift+Tab")
- _default_shortcuts = sm
- }
- return _default_shortcuts
- }
- var _history_search_shortcuts *shortcuts.ShortcutMap[Action]
- func history_search_shortcuts() *shortcuts.ShortcutMap[Action] {
- if _history_search_shortcuts == nil {
- sm := shortcuts.New[Action]()
- sm.AddOrPanic(ActionBackspace, "backspace")
- sm.AddOrPanic(ActionBackspace, "ctrl+h")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "home")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+a")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "end")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+e")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+home")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+end")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "alt+f")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+right")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+left")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "alt+b")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "left")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+b")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "right")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+f")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "up")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "down")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+c")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "ctrl+g")
- sm.AddOrPanic(ActionTerminateHistorySearchAndRestore, "escape")
- sm.AddOrPanic(ActionTerminateHistorySearchAndApply, "ctrl+d")
- sm.AddOrPanic(ActionTerminateHistorySearchAndApply, "enter")
- sm.AddOrPanic(ActionTerminateHistorySearchAndApply, "ctrl+j")
- _history_search_shortcuts = sm
- }
- return _history_search_shortcuts
- }
- var ErrCouldNotPerformAction = errors.New("Could not perform the specified action")
- var ErrAcceptInput = errors.New("Accept input")
- func (self *Readline) push_keyboard_map(m *ShortcutMap) {
- maps := self.keyboard_state.active_shortcut_maps
- self.keyboard_state = KeyboardState{}
- if maps == nil {
- maps = make([]*ShortcutMap, 0, 2)
- }
- self.keyboard_state.active_shortcut_maps = append(maps, m)
- }
- func (self *Readline) pop_keyboard_map() {
- maps := self.keyboard_state.active_shortcut_maps
- self.keyboard_state = KeyboardState{}
- if len(maps) > 0 {
- maps = maps[:len(maps)-1]
- self.keyboard_state.active_shortcut_maps = maps
- }
- }
- func (self *Readline) handle_numeric_arg(ac Action) {
- t := "-"
- num := int(ac - ActionNumericArgumentDigit0)
- if num < 10 {
- t = strconv.Itoa(num)
- }
- cna := self.keyboard_state.current_numeric_argument
- if (cna == "" && t == "0") || (cna != "" && t == "-") {
- self.add_text(t)
- self.keyboard_state.current_numeric_argument = ""
- self.last_action = ActionAddText
- } else {
- self.keyboard_state.current_numeric_argument += t
- self.last_action = ac
- }
- }
- func (self *Readline) dispatch_key_action(ac Action) error {
- self.keyboard_state.current_pending_keys = nil
- if ActionNumericArgumentDigit0 <= ac && ac <= ActionNumericArgumentDigitMinus {
- if self.history_search != nil {
- return ErrCouldNotPerformAction
- }
- self.handle_numeric_arg(ac)
- return nil
- }
- cna := self.keyboard_state.current_numeric_argument
- self.keyboard_state.current_numeric_argument = ""
- if cna == "" {
- cna = "1"
- }
- repeat_count, err := strconv.Atoi(cna)
- if err != nil || repeat_count <= 0 {
- repeat_count = 1
- }
- return self.perform_action(ac, uint(repeat_count))
- }
- func (self *Readline) handle_key_event(event *loop.KeyEvent) error {
- if event.Text != "" {
- return nil
- }
- sm := default_shortcuts()
- if len(self.keyboard_state.active_shortcut_maps) > 0 {
- sm = self.keyboard_state.active_shortcut_maps[len(self.keyboard_state.active_shortcut_maps)-1]
- }
- ac, pending := sm.ResolveKeyEvent(event, self.keyboard_state.current_pending_keys...)
- if pending != "" {
- event.Handled = true
- if self.keyboard_state.current_pending_keys == nil {
- self.keyboard_state.current_pending_keys = []string{}
- }
- self.keyboard_state.current_pending_keys = append(self.keyboard_state.current_pending_keys, pending)
- } else {
- self.keyboard_state.current_pending_keys = nil
- if ac != ActionNil {
- event.Handled = true
- return self.dispatch_key_action(ac)
- }
- }
- return nil
- }
|