X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=cmd%2Fmicro%2Fsearch.go;h=7139f844888021615102f6bae94ac0180fa8bff1;hb=2a0d78b86d175fa6666380e17c9f672c3e6a06f3;hp=966184715e355505b9605bf9da0c6eccd974c15f;hpb=0a534767f02f1ec72cda0f42b48370cec858e999;p=micro.git diff --git a/cmd/micro/search.go b/cmd/micro/search.go index 96618471..7139f844 100644 --- a/cmd/micro/search.go +++ b/cmd/micro/search.go @@ -2,6 +2,7 @@ package main import ( "regexp" + "strings" "github.com/zyedidia/tcell" ) @@ -11,7 +12,7 @@ var ( lastSearch string // Where should we start the search down from (or up from) - searchStart int + searchStart Loc // Is there currently a search in progress searching bool @@ -21,12 +22,14 @@ var ( ) // BeginSearch starts a search -func BeginSearch() { +func BeginSearch(searchStr string) { searchHistory = append(searchHistory, "") messenger.historyNum = len(searchHistory) - 1 searching = true - messenger.hasPrompt = true + messenger.response = searchStr + messenger.cursorx = Count(searchStr) messenger.Message("Find: ") + messenger.hasPrompt = true } // EndSearch stops the current search @@ -41,13 +44,32 @@ func EndSearch() { } } +// ExitSearch exits the search mode, reset active search phrase, and clear status bar +func ExitSearch(v *View) { + lastSearch = "" + searching = false + messenger.hasPrompt = false + messenger.Clear() + messenger.Reset() + v.Cursor.ResetSelection() +} + // HandleSearchEvent takes an event and a view and will do a real time match from the messenger's output // to the current buffer. It searches down the buffer. func HandleSearchEvent(event tcell.Event, v *View) { switch e := event.(type) { case *tcell.EventKey: switch e.Key() { - case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape, tcell.KeyEnter: + case tcell.KeyEscape: + // Exit the search mode + ExitSearch(v) + return + case tcell.KeyEnter: + // If the user has pressed Enter, they want this to be the lastSearch + lastSearch = messenger.response + EndSearch() + return + case tcell.KeyCtrlQ, tcell.KeyCtrlC: // Done EndSearch() return @@ -70,9 +92,95 @@ func HandleSearchEvent(event tcell.Event, v *View) { Search(messenger.response, v, true) + v.Relocate() + return } +func searchDown(r *regexp.Regexp, v *View, start, end Loc) bool { + if start.Y >= v.Buf.NumLines { + start.Y = v.Buf.NumLines - 1 + } + if start.Y < 0 { + start.Y = 0 + } + for i := start.Y; i <= end.Y; i++ { + var l []byte + var charPos int + if i == start.Y { + runes := []rune(string(v.Buf.lines[i].data)) + if start.X >= len(runes) { + start.X = len(runes) - 1 + } + if start.X < 0 { + start.X = 0 + } + l = []byte(string(runes[start.X:])) + charPos = start.X + + if strings.Contains(r.String(), "^") && start.X != 0 { + continue + } + } else { + l = v.Buf.lines[i].data + } + + match := r.FindIndex(l) + + if match != nil { + v.Cursor.SetSelectionStart(Loc{charPos + runePos(match[0], string(l)), i}) + v.Cursor.SetSelectionEnd(Loc{charPos + runePos(match[1], string(l)), i}) + v.Cursor.OrigSelection[0] = v.Cursor.CurSelection[0] + v.Cursor.OrigSelection[1] = v.Cursor.CurSelection[1] + v.Cursor.Loc = v.Cursor.CurSelection[1] + + return true + } + } + return false +} + +func searchUp(r *regexp.Regexp, v *View, start, end Loc) bool { + if start.Y >= v.Buf.NumLines { + start.Y = v.Buf.NumLines - 1 + } + if start.Y < 0 { + start.Y = 0 + } + for i := start.Y; i >= end.Y; i-- { + var l []byte + if i == start.Y { + runes := []rune(string(v.Buf.lines[i].data)) + if start.X >= len(runes) { + start.X = len(runes) - 1 + } + if start.X < 0 { + start.X = 0 + } + l = []byte(string(runes[:start.X])) + + if strings.Contains(r.String(), "$") && start.X != Count(string(l)) { + continue + } + } else { + l = v.Buf.lines[i].data + } + + match := r.FindIndex(l) + + if match != nil { + v.Cursor.SetSelectionStart(Loc{runePos(match[0], string(l)), i}) + v.Cursor.SetSelectionEnd(Loc{runePos(match[1], string(l)), i}) + v.Cursor.OrigSelection[0] = v.Cursor.CurSelection[0] + v.Cursor.OrigSelection[1] = v.Cursor.CurSelection[1] + v.Cursor.Loc = v.Cursor.CurSelection[1] + + return true + } + } + return false +} + // Search searches in the view for the given regex. The down bool // specifies whether it should search down from the searchStart position // or up from there @@ -80,15 +188,6 @@ func Search(searchStr string, v *View, down bool) { if searchStr == "" { return } - var str string - var charPos int - text := v.Buf.String() - if down { - str = string([]rune(text)[searchStart:]) - charPos = searchStart - } else { - str = string([]rune(text)[:searchStart]) - } r, err := regexp.Compile(searchStr) if v.Buf.Settings["ignorecase"].(bool) { r, err = regexp.Compile("(?i)" + searchStr) @@ -96,40 +195,20 @@ func Search(searchStr string, v *View, down bool) { if err != nil { return } - matches := r.FindAllStringIndex(str, -1) - var match []int - if matches == nil { - // Search the entire buffer now - matches = r.FindAllStringIndex(text, -1) - charPos = 0 - if matches == nil { - v.Cursor.ResetSelection() - return - } - if !down { - match = matches[len(matches)-1] - } else { - match = matches[0] + var found bool + if down { + found = searchDown(r, v, searchStart, v.Buf.End()) + if !found { + found = searchDown(r, v, v.Buf.Start(), searchStart) } - str = text - } - - if !down { - match = matches[len(matches)-1] } else { - match = matches[0] - } - - if match[0] == match[1] { - return + found = searchUp(r, v, searchStart, v.Buf.Start()) + if !found { + found = searchUp(r, v, v.Buf.End(), searchStart) + } } - - v.Cursor.SetSelectionStart(FromCharPos(charPos+runePos(match[0], str), v.Buf)) - v.Cursor.SetSelectionEnd(FromCharPos(charPos+runePos(match[1], str), v.Buf)) - v.Cursor.Loc = v.Cursor.CurSelection[1] - if v.Relocate() { - v.matches = Match(v) + if !found { + v.Cursor.ResetSelection() } - lastSearch = searchStr }