1 /* searchtextstorage.cc
2 * This file belongs to Worker, a file manager for UN*X/X11.
3 * Copyright (C) 2008-2015 Ralf Hoffmann.
4 * You can contact me at: ralf@boomerangsworld.de
5 * or http://www.boomerangsworld.de/worker
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "searchtextstorage.hh"
23 #include "textstorage.h"
24 #include "textview.h"
25 #include <cctype>
26
SearchTextStorage(TextStorage & ts)27 SearchTextStorage::SearchTextStorage( TextStorage &ts ) :
28 m_ts( ts ),
29 m_start_search( std::pair<int, int>( -1, -1 ) )
30 {
31 m_cur_match.line = -1;
32 m_cur_match.start_offset = -1;
33 m_cur_match.end_offset = -1;
34 }
35
~SearchTextStorage()36 SearchTextStorage::~SearchTextStorage()
37 {
38 }
39
search(const std::string & search_string)40 void SearchTextStorage::search( const std::string &search_string )
41 {
42 if ( search_string.length() < 1 ) {
43 m_cur_match.line = -1;
44 return;
45 }
46
47 std::pair<int, int> start;
48 bool ignore_case = true;
49
50 if ( search_string == m_last_search_string && m_cur_match.line >= 0 ) {
51 start = std::pair<int, int>( m_cur_match.line, m_cur_match.end_offset );
52 start.second++;
53 } else {
54 start = m_start_search;
55 }
56
57 if ( start.first >= m_ts.getNrOfUnwrappedLines() )
58 start.first = -1;
59
60 m_cur_match.line = -1;
61
62 if ( start.first >= 0 ) {
63 std::string l;
64 if ( m_ts.getUnwrappedLine( start.first, 0, l ) == 0 ) {
65
66 if ( start.second >= (int)l.length() ) {
67 start.first++;
68 start.second = 0;
69 }
70 }
71 }
72
73 m_cur_match.line = -1;
74
75 if ( start.first < 0 ) {
76 start.first = 0;
77 start.second = 0;
78 }
79
80 for ( std::string::const_iterator it1 = search_string.begin();
81 it1 != search_string.end();
82 it1++ ) {
83 //TODO not utf8 safe
84 if ( std::isupper( *it1 ) ) {
85 ignore_case = false;
86 break;
87 }
88 }
89
90 if ( start.first >= 0 ) {
91 for ( ; start.first < m_ts.getNrOfUnwrappedLines(); start.first++, start.second = 0 ) {
92 std::string l;
93 if ( m_ts.getUnwrappedLine( start.first, 0, l ) == 0 ) {
94 int so = -1, eo = -1;
95
96 if ( start.second >= 0 && start.second < (int)l.length() ) {
97 if ( m_cre.match( search_string.c_str(), l.c_str() + start.second, ignore_case, &so, &eo ) == true ) {
98 m_cur_match.line = start.first;
99 m_cur_match.start_offset = so + start.second;
100 m_cur_match.end_offset = eo + start.second;
101 break;
102 }
103 }
104 } else {
105 break;
106 }
107 }
108 if ( m_cur_match.line == -1 ) {
109 // no match so start over next time
110 m_start_search.first = -1;
111 m_start_search.second = -1;
112 }
113 }
114
115 m_last_search_string = search_string;
116 }
117
searchBackwards(const std::string & search_string)118 void SearchTextStorage::searchBackwards( const std::string &search_string )
119 {
120 if ( search_string.length() < 1 ) {
121 m_cur_match.line = -1;
122 return;
123 }
124
125 std::pair<int, int> start;
126 bool ignore_case = true;
127
128 if ( search_string == m_last_search_string && m_cur_match.line >= 0 ) {
129 start = std::pair<int, int>( m_cur_match.line, m_cur_match.start_offset );
130
131 prevPos( start );
132 } else {
133 start = m_start_search;
134 }
135
136 if ( start.first >= m_ts.getNrOfUnwrappedLines() ) {
137 start.first = -1;
138 }
139
140 m_cur_match.line = -1;
141
142 m_cur_match.line = -1;
143
144 if ( start.first < 0 ) {
145 start.first = 0;
146 start.second = 0;
147
148 prevPos( start );
149 }
150
151 for ( std::string::const_iterator it1 = search_string.begin();
152 it1 != search_string.end();
153 it1++ ) {
154 //TODO not utf8 safe
155 if ( std::isupper( *it1 ) ) {
156 ignore_case = false;
157 break;
158 }
159 }
160
161 if ( start.first >= 0 ) {
162 for ( ; start.first >= 0; start.first--, start.second = -1 ) {
163 std::string l;
164 if ( m_ts.getUnwrappedLine( start.first, 0, l ) == 0 ) {
165 if ( l.length() < 1 ) continue;
166
167 if ( start.second == -1 ) {
168 start.second = l.length() - 1;
169 }
170
171 int match_candidate_so = -1;
172 int match_candidate_eo = -1;
173 int pos = 0;
174
175 for (;;) {
176 // search match, if lower than start.second, store as candidate
177 // otherwise take possible candidate
178 // repeat from match position + 1
179 if ( pos >= (int)l.length() ) break;
180
181 int so = -1, eo = -1;
182
183 if ( m_cre.match( search_string.c_str(), l.c_str() + pos, ignore_case, &so, &eo ) == true ) {
184
185 if ( so + pos < start.second ) {
186 match_candidate_so = so + pos;
187 match_candidate_eo = eo + pos;
188
189 pos += so + 1;
190
191 continue;
192 }
193 }
194
195 break;
196 }
197
198 if ( match_candidate_so >= 0 ) {
199 m_cur_match.line = start.first;
200 m_cur_match.start_offset = match_candidate_so;
201 m_cur_match.end_offset = match_candidate_eo;
202 break;
203 }
204 } else {
205 break;
206 }
207 }
208 if ( m_cur_match.line == -1 ) {
209 // no match so start over next time
210 m_start_search.first = -1;
211 m_start_search.second = -1;
212 }
213 }
214
215 m_last_search_string = search_string;
216 }
217
highlightCurMatch(TextView & tv)218 void SearchTextStorage::highlightCurMatch( TextView &tv )
219 {
220 if ( m_cur_match.line >= 0 ) {
221 tv.setSelectionStart( m_cur_match.line, m_cur_match.start_offset );
222 tv.setSelectionEnd( m_cur_match.line, m_cur_match.end_offset );
223 } else {
224 tv.clearSelection();
225 }
226 }
227
setSearchStartLine(int line)228 void SearchTextStorage::setSearchStartLine( int line )
229 {
230 if ( line < 0 || line >= m_ts.getNrOfUnwrappedLines() ) return;
231
232 m_start_search.first = line;
233 m_start_search.second = 0;
234 m_cur_match.line = -1;
235 }
236
getCurMatchLine() const237 int SearchTextStorage::getCurMatchLine() const
238 {
239 return m_cur_match.line;
240 }
241
prevPos(std::pair<int,int> & pos)242 int SearchTextStorage::prevPos( std::pair< int, int > &pos )
243 {
244 if ( pos.second > 0 ) {
245 pos.second--;
246 return 0;
247 }
248
249 bool wrapped = false;
250
251 if ( pos.first > 0 ) {
252 pos.first--;
253 } else {
254 pos.first = m_ts.getNrOfUnwrappedLines() - 1;
255 wrapped = true;
256 }
257
258 if ( pos.first >= 0 ) {
259 std::string l;
260 if ( m_ts.getUnwrappedLine( pos.first, 0, l ) == 0 ) {
261 pos.second = l.length();
262 } else {
263 pos.first = -1;
264 pos.second = -1;
265 return -1;
266 }
267 }
268
269 return wrapped == true ? 1 : 0;
270 }
271