diff --git a/src/cursor.go b/src/cursor.go index b7c655cb..05c1a09f 100644 --- a/src/cursor.go +++ b/src/cursor.go @@ -76,13 +76,13 @@ func (c *Cursor) Loc() int { // ResetSelection resets the user's selection func (c *Cursor) ResetSelection() { - c.curSelection[0] = 0 - c.curSelection[1] = 0 + c.curSelection[0] = -1 + c.curSelection[1] = -1 } // HasSelection returns whether or not the user has selected anything func (c *Cursor) HasSelection() bool { - return c.curSelection[1] != c.curSelection[0] + return c.curSelection[1] != -1 || c.curSelection[0] != -1 } // DeleteSelection deletes the currently selected text diff --git a/src/messenger.go b/src/messenger.go index aeafea0d..ea3ddbdb 100644 --- a/src/messenger.go +++ b/src/messenger.go @@ -43,6 +43,8 @@ type Messenger struct { // style to use when drawing the message style tcell.Style + realtimePrompt bool + // We have to keep track of the cursor for prompting cursorx int } diff --git a/src/micro.go b/src/micro.go index 967e33da..e08aeec4 100644 --- a/src/micro.go +++ b/src/micro.go @@ -138,25 +138,69 @@ func main() { // Wait for the user's action event := screen.PollEvent() - // Check if we should quit - switch e := event.(type) { - case *tcell.EventKey: - switch e.Key() { - case tcell.KeyCtrlQ: - // Make sure not to quit if there are unsaved changes - if view.CanClose("Quit anyway? ") { - screen.Fini() - os.Exit(0) + if messenger.realtimePrompt { + switch e := event.(type) { + case *tcell.EventKey: + if e.Key() == tcell.KeyEscape { + // Cancel + messenger.hasPrompt = false + messenger.realtimePrompt = false + messenger.Clear() + messenger.Reset() + continue + } else if e.Key() == tcell.KeyCtrlC { + // Cancel + messenger.hasPrompt = false + messenger.realtimePrompt = false + messenger.Clear() + messenger.Reset() + continue + } else if e.Key() == tcell.KeyCtrlQ { + // Cancel + messenger.hasPrompt = false + messenger.realtimePrompt = false + messenger.Clear() + messenger.Reset() + continue + } else if e.Key() == tcell.KeyEnter { + // User is done entering their response + messenger.hasPrompt = false + messenger.realtimePrompt = false + messenger.Clear() + messenger.Reset() + continue } - case tcell.KeyCtrlE: - input, canceled := messenger.Prompt("> ") - if !canceled { - HandleCommand(input, view) + } + if messenger.cursorx < 0 { + // Cancel + messenger.realtimePrompt = false + messenger.hasPrompt = false + messenger.Clear() + messenger.Reset() + continue + } + messenger.HandleEvent(event) + } else { + // Check if we should quit + switch e := event.(type) { + case *tcell.EventKey: + switch e.Key() { + case tcell.KeyCtrlQ: + // Make sure not to quit if there are unsaved changes + if view.CanClose("Quit anyway? ") { + screen.Fini() + os.Exit(0) + } + case tcell.KeyCtrlE: + input, canceled := messenger.Prompt("> ") + if !canceled { + HandleCommand(input, view) + } + case tcell.KeyCtrlH: + DisplayHelp() + // Make sure to resize the view if the user resized the terminal while looking at the help text + view.Resize(screen.Size()) } - case tcell.KeyCtrlH: - DisplayHelp() - // Make sure to resize the view if the user resized the terminal while looking at the help text - view.Resize(screen.Size()) } } diff --git a/src/view.go b/src/view.go index c8e172f6..fbdd596e 100644 --- a/src/view.go +++ b/src/view.go @@ -4,6 +4,7 @@ import ( "github.com/atotto/clipboard" "github.com/gdamore/tcell" "io/ioutil" + "regexp" "strconv" "strings" "time" @@ -338,6 +339,26 @@ func (v *View) HandleEvent(event tcell.Event) { // This bool determines whether the view is relocated at the end of the function // By default it's true because most events should cause a relocate relocate := true + + if messenger.realtimePrompt { + str := strings.Join(v.buf.lines[v.cursor.y:], "\n") + charPos := ToCharPos(0, v.cursor.y, v.buf) + r, err := regexp.Compile(messenger.response) + if err != nil { + return + } + match := r.FindStringIndex(str) + if match == nil { + v.cursor.ResetSelection() + return + } + v.cursor.curSelection[0] = charPos + match[0] + v.cursor.curSelection[1] = charPos + match[1] - 1 + v.cursor.x, v.cursor.y = FromCharPos(charPos+match[1]-1, v.buf) + v.Relocate() + return + } + // By default we don't update and syntax highlighting v.UpdateLines(-2, 0) switch e := event.(type) { @@ -402,6 +423,10 @@ func (v *View) HandleEvent(event tcell.Event) { v.UpdateLines(v.cursor.y, v.cursor.y) case tcell.KeyCtrlS: v.Save() + case tcell.KeyCtrlF: + messenger.realtimePrompt = true + messenger.hasPrompt = true + messenger.Message("Find: ") case tcell.KeyCtrlZ: v.eh.Undo() // Rehighlight the entire buffer @@ -504,7 +529,7 @@ func (v *View) HandleEvent(event tcell.Event) { } else if v.doubleClick { v.cursor.AddWordToSelection() } else { - v.cursor.curSelection[1] = v.cursor.Loc() + v.cursor.curSelection[1] = v.cursor.Loc() - 1 } } v.mouseReleased = false @@ -569,6 +594,7 @@ func (v *View) DisplayView() { // } // The character number of the character in the top left of the screen + charNum := ToCharPos(0, v.topline, v.buf) // Convert the length of buffer to a string, and get the length of the string