]> git.lizzy.rs Git - micro.git/blob - cmd/micro/search.go
0ac0cbd3472371987919c4bf7edebac100fe3a25
[micro.git] / cmd / micro / search.go
1 package main
2
3 import (
4         "regexp"
5
6         "github.com/zyedidia/tcell"
7 )
8
9 var (
10         // What was the last search
11         lastSearch string
12
13         // Where should we start the search down from (or up from)
14         searchStart int
15
16         // Is there currently a search in progress
17         searching bool
18
19         // Stores the history for searching
20         searchHistory []string
21 )
22
23 // BeginSearch starts a search
24 func BeginSearch(searchStr string) {
25         searchHistory = append(searchHistory, "")
26         messenger.historyNum = len(searchHistory) - 1
27         searching = true
28         messenger.response = searchStr
29         messenger.cursorx = Count(searchStr)
30         messenger.Message("Find: ")
31         messenger.hasPrompt = true
32 }
33
34 // EndSearch stops the current search
35 func EndSearch() {
36         searchHistory[len(searchHistory)-1] = messenger.response
37         searching = false
38         messenger.hasPrompt = false
39         messenger.Clear()
40         messenger.Reset()
41         if lastSearch != "" {
42                 messenger.Message("^P Previous ^N Next")
43         }
44 }
45
46 // exit the search mode, reset active search phrase, and clear status bar
47 func ExitSearch(v *View) {
48         lastSearch = ""
49         searching = false
50         messenger.hasPrompt = false
51         messenger.Clear()
52         messenger.Reset()
53         v.Cursor.ResetSelection()
54 }
55
56 // HandleSearchEvent takes an event and a view and will do a real time match from the messenger's output
57 // to the current buffer. It searches down the buffer.
58 func HandleSearchEvent(event tcell.Event, v *View) {
59         switch e := event.(type) {
60         case *tcell.EventKey:
61                 switch e.Key() {
62                 case tcell.KeyEscape:
63                         // Exit the search mode
64                         ExitSearch(v)
65                         return
66                 case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEnter:
67                         // Done
68                         EndSearch()
69                         return
70                 }
71         }
72
73         messenger.HandleEvent(event, searchHistory)
74
75         if messenger.cursorx < 0 {
76                 // Done
77                 EndSearch()
78                 return
79         }
80
81         if messenger.response == "" {
82                 v.Cursor.ResetSelection()
83                 // We don't end the search though
84                 return
85         }
86
87         Search(messenger.response, v, true)
88
89         return
90 }
91
92 // Search searches in the view for the given regex. The down bool
93 // specifies whether it should search down from the searchStart position
94 // or up from there
95 func Search(searchStr string, v *View, down bool) {
96         if searchStr == "" {
97                 return
98         }
99         var str string
100         var charPos int
101         text := v.Buf.String()
102         if down {
103                 str = string([]rune(text)[searchStart:])
104                 charPos = searchStart
105         } else {
106                 str = string([]rune(text)[:searchStart])
107         }
108         r, err := regexp.Compile(searchStr)
109         if v.Buf.Settings["ignorecase"].(bool) {
110                 r, err = regexp.Compile("(?i)" + searchStr)
111         }
112         if err != nil {
113                 return
114         }
115         matches := r.FindAllStringIndex(str, -1)
116         var match []int
117         if matches == nil {
118                 // Search the entire buffer now
119                 matches = r.FindAllStringIndex(text, -1)
120                 charPos = 0
121                 if matches == nil {
122                         v.Cursor.ResetSelection()
123                         return
124                 }
125
126                 if !down {
127                         match = matches[len(matches)-1]
128                 } else {
129                         match = matches[0]
130                 }
131                 str = text
132         }
133
134         if !down {
135                 match = matches[len(matches)-1]
136         } else {
137                 match = matches[0]
138         }
139
140         if match[0] == match[1] {
141                 return
142         }
143
144         v.Cursor.SetSelectionStart(FromCharPos(charPos+runePos(match[0], str), v.Buf))
145         v.Cursor.SetSelectionEnd(FromCharPos(charPos+runePos(match[1], str), v.Buf))
146         v.Cursor.Loc = v.Cursor.CurSelection[1]
147         lastSearch = searchStr
148 }