This repository has been archived by the owner on Jun 13, 2022. It is now read-only.
forked from rgburke/grv
/
view_search.go
155 lines (122 loc) · 3.84 KB
/
view_search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package main
import (
"sync"
log "github.com/Sirupsen/logrus"
)
// SearchableView is a view that supports searching functionality
type SearchableView interface {
SearchInputProvidor
ViewPos() ViewPos
OnSearchMatch(startPos ViewPos, matchLineIndex uint)
}
// ViewSearch manages search functionality for a view
type ViewSearch struct {
search *Search
searchableView SearchableView
channels Channels
lastSearchFoundMatch bool
lock sync.Mutex
}
// NewViewSearch creates a new instance
func NewViewSearch(searchableView SearchableView, channels Channels) *ViewSearch {
return &ViewSearch{
searchableView: searchableView,
channels: channels,
}
}
// SearchActive returns the state of the most recent search (if one has been performed)
func (viewSearch *ViewSearch) SearchActive() (active bool, pattern string, lastSearchFoundMatch bool) {
viewSearch.lock.Lock()
defer viewSearch.lock.Unlock()
return viewSearch.searchActive()
}
func (viewSearch *ViewSearch) searchActive() (active bool, pattern string, lastSearchFoundMatch bool) {
if viewSearch.search != nil {
active = true
pattern = viewSearch.search.pattern
lastSearchFoundMatch = viewSearch.lastSearchFoundMatch
}
return
}
// HandleAction handles all actions relating to search that a view receives
func (viewSearch *ViewSearch) HandleAction(action Action) (handled bool, err error) {
viewSearch.lock.Lock()
defer viewSearch.lock.Unlock()
handled = true
switch action.ActionType {
case ActionSearch, ActionReverseSearch:
err = viewSearch.doSearch(action)
case ActionSearchFindNext:
err = viewSearch.findNextMatch()
case ActionSearchFindPrev:
err = viewSearch.findPrevMatch()
case ActionClearSearch:
err = viewSearch.clearSearch()
default:
handled = false
}
return
}
func (viewSearch *ViewSearch) doSearch(action Action) (err error) {
search, err := CreateSearchFromAction(action, viewSearch.searchableView)
if err != nil {
return
}
viewSearch.search = search
return viewSearch.findNextMatch()
}
func (viewSearch *ViewSearch) findNextMatch() (err error) {
active, pattern, _ := viewSearch.searchActive()
if !active {
return
}
viewSearch.channels.ReportStatus("Searching...")
go func() {
viewPos := viewSearch.searchableView.ViewPos()
log.Debugf("Searching for next occurrence of pattern %v starting from row index :%v",
pattern, viewPos.ActiveRowIndex())
matchLineIndex, found := viewSearch.search.FindNext(viewPos.ActiveRowIndex())
viewSearch.lock.Lock()
viewSearch.lastSearchFoundMatch = found
viewSearch.lock.Unlock()
if found {
viewSearch.searchableView.OnSearchMatch(viewPos, matchLineIndex)
viewSearch.channels.ReportStatus("Match found")
} else {
viewSearch.channels.ReportStatus("No matches found")
}
}()
return
}
func (viewSearch *ViewSearch) findPrevMatch() (err error) {
active, pattern, _ := viewSearch.searchActive()
if !active {
return
}
viewSearch.channels.ReportStatus("Searching...")
go func() {
viewPos := viewSearch.searchableView.ViewPos()
log.Debugf("Searching for previous occurrence of pattern %v starting from row index :%v",
pattern, viewPos.ActiveRowIndex())
matchLineIndex, found := viewSearch.search.FindPrev(viewPos.ActiveRowIndex())
viewSearch.lock.Lock()
viewSearch.lastSearchFoundMatch = found
viewSearch.lock.Unlock()
if found {
viewSearch.searchableView.OnSearchMatch(viewPos, matchLineIndex)
viewSearch.channels.ReportStatus("Match found")
} else {
viewSearch.channels.ReportStatus("No matches found")
}
}()
return
}
func (viewSearch *ViewSearch) clearSearch() (err error) {
if active, pattern, _ := viewSearch.searchActive(); active {
viewSearch.channels.ReportStatus("Cleared search")
log.Debugf("Clearing search with pattern %v", pattern)
viewSearch.search = nil
viewSearch.lastSearchFoundMatch = false
}
return
}