]> git.lizzy.rs Git - micro.git/blob - cmd/micro/search.go
Copy to primary clipboard for any change in selection
[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() {
25         searchHistory = append(searchHistory, "")
26         messenger.historyNum = len(searchHistory) - 1
27         searching = true
28         messenger.hasPrompt = true
29         messenger.Message("Find: ")
30 }
31
32 // EndSearch stops the current search
33 func EndSearch() {
34         searchHistory[len(searchHistory)-1] = messenger.response
35         searching = false
36         messenger.hasPrompt = false
37         messenger.Clear()
38         messenger.Reset()
39         if lastSearch != "" {
40                 messenger.Message("^P Previous ^N Next")
41         }
42 }
43
44 // HandleSearchEvent takes an event and a view and will do a real time match from the messenger's output
45 // to the current buffer. It searches down the buffer.
46 func HandleSearchEvent(event tcell.Event, v *View) {
47         switch e := event.(type) {
48         case *tcell.EventKey:
49                 switch e.Key() {
50                 case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape, tcell.KeyEnter:
51                         // Done
52                         EndSearch()
53                         return
54                 }
55         }
56
57         messenger.HandleEvent(event, searchHistory)
58
59         if messenger.cursorx < 0 {
60                 // Done
61                 EndSearch()
62                 return
63         }
64
65         if messenger.response == "" {
66                 v.Cursor.ResetSelection()
67                 // We don't end the search though
68                 return
69         }
70
71         Search(messenger.response, v, true)
72
73         return
74 }
75
76 // Search searches in the view for the given regex. The down bool
77 // specifies whether it should search down from the searchStart position
78 // or up from there
79 func Search(searchStr string, v *View, down bool) {
80         if searchStr == "" {
81                 return
82         }
83         var str string
84         var charPos int
85         text := v.Buf.String()
86         if down {
87                 str = string([]rune(text)[searchStart:])
88                 charPos = searchStart
89         } else {
90                 str = string([]rune(text)[:searchStart])
91         }
92         r, err := regexp.Compile(searchStr)
93         if v.Buf.Settings["ignorecase"].(bool) {
94                 r, err = regexp.Compile("(?i)" + searchStr)
95         }
96         if err != nil {
97                 return
98         }
99         matches := r.FindAllStringIndex(str, -1)
100         var match []int
101         if matches == nil {
102                 // Search the entire buffer now
103                 matches = r.FindAllStringIndex(text, -1)
104                 charPos = 0
105                 if matches == nil {
106                         v.Cursor.ResetSelection()
107                         return
108                 }
109
110                 if !down {
111                         match = matches[len(matches)-1]
112                 } else {
113                         match = matches[0]
114                 }
115                 str = text
116         }
117
118         if !down {
119                 match = matches[len(matches)-1]
120         } else {
121                 match = matches[0]
122         }
123
124         if match[0] == match[1] {
125                 return
126         }
127
128         v.Cursor.SetSelectionStart(FromCharPos(charPos+runePos(match[0], str), v.Buf))
129         v.Cursor.SetSelectionEnd(FromCharPos(charPos+runePos(match[1], str), v.Buf))
130         v.Cursor.Loc = v.Cursor.CurSelection[1]
131         if v.Relocate() {
132                 v.matches = Match(v)
133         }
134         lastSearch = searchStr
135 }