7 "github.com/zyedidia/tcell"
11 // What was the last search
14 // Where should we start the search down from (or up from)
17 // Is there currently a search in progress
20 // Stores the history for searching
21 searchHistory []string
24 // BeginSearch starts a search
25 func BeginSearch(searchStr string) {
26 searchHistory = append(searchHistory, "")
27 messenger.historyNum = len(searchHistory) - 1
29 messenger.response = searchStr
30 messenger.cursorx = Count(searchStr)
31 messenger.Message("Find: ")
32 messenger.hasPrompt = true
35 // EndSearch stops the current search
37 searchHistory[len(searchHistory)-1] = messenger.response
39 messenger.hasPrompt = false
43 messenger.Message("^P Previous ^N Next")
47 // ExitSearch exits the search mode, reset active search phrase, and clear status bar
48 func ExitSearch(v *View) {
51 messenger.hasPrompt = false
54 v.Cursor.ResetSelection()
57 // HandleSearchEvent takes an event and a view and will do a real time match from the messenger's output
58 // to the current buffer. It searches down the buffer.
59 func HandleSearchEvent(event tcell.Event, v *View) {
60 switch e := event.(type) {
64 // Exit the search mode
68 // If the user has pressed Enter, they want this to be the lastSearch
69 lastSearch = messenger.response
72 case tcell.KeyCtrlQ, tcell.KeyCtrlC:
79 messenger.HandleEvent(event, searchHistory)
81 if messenger.cursorx < 0 {
87 if messenger.response == "" {
88 v.Cursor.ResetSelection()
89 // We don't end the search though
93 Search(messenger.response, v, true)
100 func searchDown(r *regexp.Regexp, v *View, start, end Loc) bool {
101 for i := start.Y; i <= end.Y; i++ {
105 runes := []rune(string(v.Buf.lines[i].data))
106 l = []byte(string(runes[start.X:]))
109 if strings.Contains(r.String(), "^") && start.X != 0 {
113 l = v.Buf.lines[i].data
116 match := r.FindIndex(l)
119 v.Cursor.SetSelectionStart(Loc{charPos + runePos(match[0], string(l)), i})
120 v.Cursor.SetSelectionEnd(Loc{charPos + runePos(match[1], string(l)), i})
121 v.Cursor.OrigSelection[0] = v.Cursor.CurSelection[0]
122 v.Cursor.OrigSelection[1] = v.Cursor.CurSelection[1]
123 v.Cursor.Loc = v.Cursor.CurSelection[1]
131 func searchUp(r *regexp.Regexp, v *View, start, end Loc) bool {
132 for i := start.Y; i >= end.Y; i-- {
135 runes := []rune(string(v.Buf.lines[i].data))
136 l = []byte(string(runes[:start.X]))
138 if strings.Contains(r.String(), "$") && start.X != Count(string(l)) {
142 l = v.Buf.lines[i].data
145 match := r.FindIndex(l)
148 v.Cursor.SetSelectionStart(Loc{runePos(match[0], string(l)), i})
149 v.Cursor.SetSelectionEnd(Loc{runePos(match[1], string(l)), i})
150 v.Cursor.OrigSelection[0] = v.Cursor.CurSelection[0]
151 v.Cursor.OrigSelection[1] = v.Cursor.CurSelection[1]
152 v.Cursor.Loc = v.Cursor.CurSelection[1]
160 // Search searches in the view for the given regex. The down bool
161 // specifies whether it should search down from the searchStart position
163 func Search(searchStr string, v *View, down bool) {
167 r, err := regexp.Compile(searchStr)
168 if v.Buf.Settings["ignorecase"].(bool) {
169 r, err = regexp.Compile("(?i)" + searchStr)
177 found = searchDown(r, v, searchStart, v.Buf.End())
179 found = searchDown(r, v, v.Buf.Start(), searchStart)
182 found = searchUp(r, v, searchStart, v.Buf.Start())
184 found = searchUp(r, v, v.Buf.End(), searchStart)
188 v.Cursor.ResetSelection()