From 1fe18eecb7286e9a31103ff6dad3c63a46ad9f4d Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sat, 28 May 2016 18:41:53 -0400 Subject: [PATCH] Add history navigation with up and down arrows Fixes #145 --- cmd/micro/bindings.go | 10 +++++----- cmd/micro/messenger.go | 31 ++++++++++++++++++++++++++++--- cmd/micro/micro.go | 1 + cmd/micro/search.go | 8 +++++++- cmd/micro/view.go | 2 +- 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/cmd/micro/bindings.go b/cmd/micro/bindings.go index cc0e07ed..3749343f 100644 --- a/cmd/micro/bindings.go +++ b/cmd/micro/bindings.go @@ -643,7 +643,7 @@ func (v *View) Save() bool { } // If this is an empty buffer, ask for a filename if v.Buf.Path == "" { - filename, canceled := messenger.Prompt("Filename: ") + filename, canceled := messenger.Prompt("Filename: ", "Save") if !canceled { v.Buf.Path = filename v.Buf.Name = filename @@ -793,7 +793,7 @@ func (v *View) SelectAll() bool { // OpenFile opens a new file in the buffer func (v *View) OpenFile() bool { if v.CanClose("Continue? (yes, no, save) ") { - filename, canceled := messenger.Prompt("File to open: ") + filename, canceled := messenger.Prompt("File to open: ", "Open") if canceled { return true } @@ -884,7 +884,7 @@ func (v *View) ToggleRuler() bool { // JumpLine jumps to a line and moves the view accordingly. func (v *View) JumpLine() bool { // Prompt for line number - linestring, canceled := messenger.Prompt("Jump to line # ") + linestring, canceled := messenger.Prompt("Jump to line # ", "LineNumber") if canceled { return false } @@ -927,7 +927,7 @@ func (v *View) ToggleHelp() bool { // ShellMode opens a terminal to run a shell command func (v *View) ShellMode() bool { - input, canceled := messenger.Prompt("$ ") + input, canceled := messenger.Prompt("$ ", "Shell") if !canceled { // The true here is for openTerm to make the command interactive HandleShellCommand(input, true) @@ -937,7 +937,7 @@ func (v *View) ShellMode() bool { // CommandMode lets the user enter a command func (v *View) CommandMode() bool { - input, canceled := messenger.Prompt("> ") + input, canceled := messenger.Prompt("> ", "Command") if !canceled { HandleCommand(input) } diff --git a/cmd/micro/messenger.go b/cmd/micro/messenger.go index 27f55691..24964ea0 100644 --- a/cmd/micro/messenger.go +++ b/cmd/micro/messenger.go @@ -57,6 +57,11 @@ type Messenger struct { // We have to keep track of the cursor for prompting cursorx int + // This map stores the history for all the different kinds of uses Prompt has + // It's a map of history type -> history array + history map[string][]string + historyNum int + // Is the current message a message from the gutter gutterMessage bool } @@ -117,9 +122,15 @@ func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) { // Prompt sends the user a message and waits for a response to be typed in // This function blocks the main loop while waiting for input -func (m *Messenger) Prompt(prompt string) (string, bool) { +func (m *Messenger) Prompt(prompt, historyType string) (string, bool) { m.hasPrompt = true m.Message(prompt) + if _, ok := m.history[historyType]; !ok { + m.history[historyType] = []string{""} + } else { + m.history[historyType] = append(m.history[historyType], "") + } + m.historyNum = len(m.history[historyType]) - 1 response, canceled := "", true @@ -139,10 +150,11 @@ func (m *Messenger) Prompt(prompt string) (string, bool) { // User is done entering their response m.hasPrompt = false response, canceled = m.response, false + m.history[historyType][len(m.history[historyType])-1] = response } } - m.HandleEvent(event) + m.HandleEvent(event, m.history[historyType]) if m.cursorx < 0 { // Cancel @@ -155,10 +167,22 @@ func (m *Messenger) Prompt(prompt string) (string, bool) { } // HandleEvent handles an event for the prompter -func (m *Messenger) HandleEvent(event tcell.Event) { +func (m *Messenger) HandleEvent(event tcell.Event, history []string) { switch e := event.(type) { case *tcell.EventKey: switch e.Key() { + case tcell.KeyUp: + if m.historyNum > 0 { + m.historyNum-- + m.response = history[m.historyNum] + m.cursorx = len(m.response) + } + case tcell.KeyDown: + if m.historyNum < len(history)-1 { + m.historyNum++ + m.response = history[m.historyNum] + m.cursorx = len(m.response) + } case tcell.KeyLeft: if m.cursorx > 0 { m.cursorx-- @@ -176,6 +200,7 @@ func (m *Messenger) HandleEvent(event tcell.Event) { m.response = Insert(m.response, m.cursorx, string(e.Rune())) m.cursorx++ } + history[m.historyNum] = m.response } } diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index ab84834c..bfeae5a5 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -227,6 +227,7 @@ func main() { }() messenger = new(Messenger) + messenger.history = make(map[string][]string) views = make([]*View, 1) views[0] = NewView(buf) diff --git a/cmd/micro/search.go b/cmd/micro/search.go index 98e80758..bef2936e 100644 --- a/cmd/micro/search.go +++ b/cmd/micro/search.go @@ -15,10 +15,15 @@ var ( // Is there currently a search in progress searching bool + + // Stores the history for searching + searchHistory []string ) // BeginSearch starts a search func BeginSearch() { + searchHistory = append(searchHistory, "") + messenger.historyNum = len(searchHistory) - 1 searching = true messenger.hasPrompt = true messenger.Message("Find: ") @@ -26,6 +31,7 @@ func BeginSearch() { // EndSearch stops the current search func EndSearch() { + searchHistory[len(searchHistory)-1] = messenger.response searching = false messenger.hasPrompt = false messenger.Clear() @@ -48,7 +54,7 @@ func HandleSearchEvent(event tcell.Event, v *View) { } } - messenger.HandleEvent(event) + messenger.HandleEvent(event, searchHistory) if messenger.cursorx < 0 { // Done diff --git a/cmd/micro/view.go b/cmd/micro/view.go index eb0ec52e..70fa5aa9 100644 --- a/cmd/micro/view.go +++ b/cmd/micro/view.go @@ -148,7 +148,7 @@ func (v *View) ScrollDown(n int) { // The message is what to print after saying "You have unsaved changes. " func (v *View) CanClose(msg string) bool { if v.Buf.IsModified { - quit, canceled := messenger.Prompt("You have unsaved changes. " + msg) + quit, canceled := messenger.Prompt("You have unsaved changes. "+msg, "Unsaved") if !canceled { if strings.ToLower(quit) == "yes" || strings.ToLower(quit) == "y" { return true