From e4751fd84cb71ba032bdcb4fa4e7777b24b9bc1e Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sat, 8 Jul 2017 15:03:35 -0400 Subject: [PATCH] Optimize search Fixes #722 --- cmd/micro/actions.go | 18 +++---- cmd/micro/command.go | 4 +- cmd/micro/search.go | 111 ++++++++++++++++++++++++++++--------------- 3 files changed, 83 insertions(+), 50 deletions(-) diff --git a/cmd/micro/actions.go b/cmd/micro/actions.go index 24b16d6c..04b8304b 100644 --- a/cmd/micro/actions.go +++ b/cmd/micro/actions.go @@ -933,11 +933,11 @@ func (v *View) Find(usePlugin bool) bool { searchStr := "" if v.Cursor.HasSelection() { - searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf) - searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf) + searchStart = v.Cursor.CurSelection[1] + searchStart = v.Cursor.CurSelection[1] searchStr = v.Cursor.GetSelection() } else { - searchStart = ToCharPos(v.Cursor.Loc, v.Buf) + searchStart = v.Cursor.Loc } BeginSearch(searchStr) @@ -955,10 +955,10 @@ func (v *View) FindNext(usePlugin bool) bool { } if v.Cursor.HasSelection() { - searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf) + searchStart = v.Cursor.CurSelection[1] // lastSearch = v.Cursor.GetSelection() } else { - searchStart = ToCharPos(v.Cursor.Loc, v.Buf) + searchStart = v.Cursor.Loc } if lastSearch == "" { return true @@ -979,9 +979,9 @@ func (v *View) FindPrevious(usePlugin bool) bool { } if v.Cursor.HasSelection() { - searchStart = ToCharPos(v.Cursor.CurSelection[0], v.Buf) + searchStart = v.Cursor.CurSelection[0] } else { - searchStart = ToCharPos(v.Cursor.Loc, v.Buf) + searchStart = v.Cursor.Loc } messenger.Message("Finding: " + lastSearch) Search(lastSearch, v, false) @@ -1915,7 +1915,7 @@ func (v *View) SpawnMultiCursor(usePlugin bool) bool { sel := spawner.GetSelection() - searchStart = ToCharPos(spawner.CurSelection[1], v.Buf) + searchStart = spawner.CurSelection[1] v.Cursor = c Search(sel, v, true) @@ -1976,7 +1976,7 @@ func (v *View) SkipMultiCursor(usePlugin bool) bool { } sel := cursor.GetSelection() - searchStart = ToCharPos(cursor.CurSelection[1], v.Buf) + searchStart = cursor.CurSelection[1] v.Cursor = cursor Search(sel, v, true) v.Relocate() diff --git a/cmd/micro/command.go b/cmd/micro/command.go index ece541cf..926e69ac 100644 --- a/cmd/micro/command.go +++ b/cmd/micro/command.go @@ -596,9 +596,9 @@ func Replace(args []string) { found++ } if view.Cursor.HasSelection() { - searchStart = ToCharPos(view.Cursor.CurSelection[1], view.Buf) + searchStart = view.Cursor.CurSelection[1] } else { - searchStart = ToCharPos(view.Cursor.Loc, view.Buf) + searchStart = view.Cursor.Loc } } } diff --git a/cmd/micro/search.go b/cmd/micro/search.go index 38bef0d9..91b86345 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 @@ -43,7 +44,7 @@ func EndSearch() { } } -// exit the search mode, reset active search phrase, and clear status bar +// ExitSearch exits the search mode, reset active search phrase, and clear status bar func ExitSearch(v *View) { lastSearch = "" searching = false @@ -91,6 +92,62 @@ func HandleSearchEvent(event tcell.Event, v *View) { return } +func searchDown(r *regexp.Regexp, v *View, start, end Loc) bool { + 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)) + 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.Loc = v.Cursor.CurSelection[1] + + return true + } + } + return false +} + +func searchUp(r *regexp.Regexp, v *View, start, end Loc) bool { + for i := start.Y; i >= end.Y; i-- { + var l []byte + if i == start.Y { + runes := []rune(string(v.Buf.lines[i].data)) + 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.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 @@ -98,15 +155,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) @@ -114,37 +162,22 @@ 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] + found = searchUp(r, v, searchStart, v.Buf.Start()) + if !found { + found = searchUp(r, v, v.Buf.End(), searchStart) + } } - - if match[0] == match[1] { - return + if found { + lastSearch = searchStr + } else { + v.Cursor.ResetSelection() } - - 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] - lastSearch = searchStr }