Add basic history operations
This commit is contained in:
parent
f77d07259a
commit
e1ab2383b3
@ -121,7 +121,7 @@ func exec_command(rl *readline.Readline, cmdline string) bool {
|
||||
return true
|
||||
}
|
||||
cwd, _ := os.Getwd()
|
||||
hi := readline.HistoryItem{Timestamp: time.Now(), Cmd: cmdline, ExitCode: -1, Cwd: cwd}
|
||||
hi := readline.HistoryItem{Timestamp: time.Now(), Cmd: rl.AllText(), ExitCode: -1, Cwd: cwd}
|
||||
switch parsed_cmdline[0] {
|
||||
case "exit":
|
||||
hi.ExitCode = 0
|
||||
|
||||
@ -463,6 +463,62 @@ func (self *Readline) yank(repeat_count uint, pop bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *Readline) apply_history_text(text string) {
|
||||
self.lines = utils.Splitlines(text)
|
||||
}
|
||||
|
||||
func (self *Readline) history_first() bool {
|
||||
prefix := self.text_upto_cursor_pos()
|
||||
if self.history_matches == nil || self.history_matches.prefix != prefix {
|
||||
return false
|
||||
}
|
||||
item := self.history_matches.first()
|
||||
if item == nil {
|
||||
return false
|
||||
}
|
||||
self.apply_history_text(item.Cmd)
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *Readline) history_last() bool {
|
||||
prefix := self.text_upto_cursor_pos()
|
||||
if self.history_matches == nil || self.history_matches.prefix != prefix {
|
||||
return false
|
||||
}
|
||||
item := self.history_matches.last()
|
||||
if item == nil {
|
||||
return false
|
||||
}
|
||||
self.apply_history_text(item.Cmd)
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *Readline) history_prev(repeat_count uint) bool {
|
||||
prefix := self.text_upto_cursor_pos()
|
||||
if self.history_matches == nil || self.history_matches.prefix != prefix {
|
||||
self.history_matches = self.history.FindPrefixMatches(prefix, self.AllText())
|
||||
}
|
||||
item := self.history_matches.previous(repeat_count)
|
||||
if item == nil {
|
||||
return false
|
||||
}
|
||||
self.apply_history_text(item.Cmd)
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *Readline) history_next(repeat_count uint) bool {
|
||||
prefix := self.text_upto_cursor_pos()
|
||||
if self.history_matches == nil || self.history_matches.prefix != prefix {
|
||||
return false
|
||||
}
|
||||
item := self.history_matches.next(repeat_count)
|
||||
if item == nil {
|
||||
return false
|
||||
}
|
||||
self.apply_history_text(item.Cmd)
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *Readline) perform_action(ac Action, repeat_count uint) error {
|
||||
defer func() { self.last_action = ac }()
|
||||
switch ac {
|
||||
@ -523,21 +579,31 @@ func (self *Readline) perform_action(ac Action, repeat_count uint) error {
|
||||
return nil
|
||||
}
|
||||
case ActionHistoryPreviousOrCursorUp:
|
||||
if self.cursor.Y == 0 {
|
||||
r := self.perform_action(ActionHistoryPrevious, repeat_count)
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if self.perform_action(ActionCursorUp, repeat_count) != nil {
|
||||
return self.perform_action(ActionHistoryPrevious, repeat_count)
|
||||
}
|
||||
return self.perform_action(ActionCursorUp, repeat_count)
|
||||
return nil
|
||||
case ActionHistoryNextOrCursorDown:
|
||||
if self.cursor.Y == 0 {
|
||||
r := self.perform_action(ActionHistoryNext, repeat_count)
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if self.perform_action(ActionCursorDown, repeat_count) != nil {
|
||||
return self.perform_action(ActionHistoryNext, repeat_count)
|
||||
}
|
||||
return nil
|
||||
case ActionHistoryFirst:
|
||||
if self.history_first() {
|
||||
return nil
|
||||
}
|
||||
case ActionHistoryPrevious:
|
||||
if self.history_prev(repeat_count) {
|
||||
return nil
|
||||
}
|
||||
case ActionHistoryNext:
|
||||
if self.history_next(repeat_count) {
|
||||
return nil
|
||||
}
|
||||
case ActionHistoryLast:
|
||||
if self.history_last() {
|
||||
return nil
|
||||
}
|
||||
return self.perform_action(ActionCursorDown, repeat_count)
|
||||
case ActionClearScreen:
|
||||
self.loop.StartAtomicUpdate()
|
||||
self.loop.ClearScreen()
|
||||
|
||||
@ -56,6 +56,8 @@ const (
|
||||
ActionHistoryNextOrCursorDown
|
||||
ActionHistoryNext
|
||||
ActionHistoryPrevious
|
||||
ActionHistoryFirst
|
||||
ActionHistoryLast
|
||||
ActionClearScreen
|
||||
ActionAddText
|
||||
|
||||
@ -132,6 +134,7 @@ type Readline struct {
|
||||
}
|
||||
bracketed_paste_buffer strings.Builder
|
||||
last_action Action
|
||||
history_matches *HistoryMatches
|
||||
}
|
||||
|
||||
func New(loop *loop.Loop, r RlInit) *Readline {
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kitty/tools/utils"
|
||||
@ -22,6 +23,12 @@ type HistoryItem struct {
|
||||
ExitCode int `json:"exit_code"`
|
||||
}
|
||||
|
||||
type HistoryMatches struct {
|
||||
items []HistoryItem
|
||||
prefix string
|
||||
current_idx int
|
||||
}
|
||||
|
||||
type History struct {
|
||||
file_path string
|
||||
file *os.File
|
||||
@ -148,3 +155,45 @@ func NewHistory(path string, max_items int) *History {
|
||||
ans.Read()
|
||||
return &ans
|
||||
}
|
||||
|
||||
func (self *History) FindPrefixMatches(prefix, current_command string) *HistoryMatches {
|
||||
ans := HistoryMatches{items: make([]HistoryItem, 0, len(self.items)+1), prefix: prefix}
|
||||
if prefix == "" {
|
||||
copy(ans.items, self.items)
|
||||
} else {
|
||||
for _, x := range self.items {
|
||||
if strings.HasPrefix(x.Cmd, prefix) {
|
||||
ans.items = append(ans.items, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
ans.items = append(ans.items, HistoryItem{Cmd: current_command})
|
||||
ans.current_idx = len(ans.items) - 1
|
||||
return &ans
|
||||
}
|
||||
|
||||
func (self *HistoryMatches) first() (ans *HistoryItem) {
|
||||
self.current_idx = 0
|
||||
return &self.items[self.current_idx]
|
||||
}
|
||||
|
||||
func (self *HistoryMatches) last() (ans *HistoryItem) {
|
||||
self.current_idx = len(self.items) - 1
|
||||
return &self.items[self.current_idx]
|
||||
}
|
||||
|
||||
func (self *HistoryMatches) previous(num uint) (ans *HistoryItem) {
|
||||
if self.current_idx > 0 {
|
||||
self.current_idx = utils.Max(0, self.current_idx-int(num))
|
||||
ans = &self.items[self.current_idx]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *HistoryMatches) next(num uint) (ans *HistoryItem) {
|
||||
if self.current_idx+1 < len(self.items) {
|
||||
self.current_idx = utils.Min(len(self.items)-1, self.current_idx+int(num))
|
||||
ans = &self.items[self.current_idx]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -48,6 +48,11 @@ var default_shortcuts = map[string]Action{
|
||||
"ctrl+w": ActionKillPreviousSpaceDelimitedWord,
|
||||
"ctrl+y": ActionYank,
|
||||
"alt+y": ActionPopYank,
|
||||
|
||||
"ctrl+p": ActionHistoryPrevious,
|
||||
"ctrl+n": ActionHistoryNext,
|
||||
"alt+<": ActionHistoryFirst,
|
||||
"alt+>": ActionHistoryLast,
|
||||
}
|
||||
|
||||
func action_for_key_event(event *loop.KeyEvent, shortcuts map[string]Action) Action {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user