aboutsummaryrefslogtreecommitdiff
path: root/examples/dte/search.c
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
commitdcacc00e3750300617ba6e16eb346713f91a783a (patch)
tree38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/dte/search.c
parent58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff)
downloadcrep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz
Remove testing data
Diffstat (limited to 'examples/dte/search.c')
-rw-r--r--examples/dte/search.c244
1 files changed, 0 insertions, 244 deletions
diff --git a/examples/dte/search.c b/examples/dte/search.c
deleted file mode 100644
index 80ad5c3..0000000
--- a/examples/dte/search.c
+++ /dev/null
@@ -1,244 +0,0 @@
1#include <stdlib.h>
2#include "search.h"
3#include "block-iter.h"
4#include "buffer.h"
5#include "error.h"
6#include "regexp.h"
7#include "util/ascii.h"
8#include "util/xmalloc.h"
9
10static bool do_search_fwd(View *view, regex_t *regex, BlockIter *bi, bool skip)
11{
12 int flags = block_iter_is_bol(bi) ? 0 : REG_NOTBOL;
13
14 do {
15 if (block_iter_is_eof(bi)) {
16 return false;
17 }
18
19 regmatch_t match;
20 StringView line;
21 fill_line_ref(bi, &line);
22
23 // NOTE: If this is the first iteration then line.data contains
24 // partial line (text starting from the cursor position) and
25 // if match.rm_so is 0 then match is at beginning of the text
26 // which is same as the cursor position.
27 if (regexp_exec(regex, line.data, line.length, 1, &match, flags)) {
28 if (skip && match.rm_so == 0) {
29 // Ignore match at current cursor position
30 regoff_t count = match.rm_eo;
31 if (count == 0) {
32 // It is safe to skip one byte because every line
33 // has one extra byte (newline) that is not in line.data
34 count = 1;
35 }
36 block_iter_skip_bytes(bi, (size_t)count);
37 return do_search_fwd(view, regex, bi, false);
38 }
39
40 block_iter_skip_bytes(bi, match.rm_so);
41 view->cursor = *bi;
42 view->center_on_scroll = true;
43 view_reset_preferred_x(view);
44 return true;
45 }
46
47 skip = false; // Not at cursor position any more
48 flags = 0;
49 } while (block_iter_next_line(bi));
50
51 return false;
52}
53
54static bool do_search_bwd(View *view, regex_t *regex, BlockIter *bi, ssize_t cx, bool skip)
55{
56 if (block_iter_is_eof(bi)) {
57 goto next;
58 }
59
60 do {
61 regmatch_t match;
62 StringView line;
63 int flags = 0;
64 regoff_t offset = -1;
65 regoff_t pos = 0;
66
67 fill_line_ref(bi, &line);
68 while (
69 pos <= line.length
70 && regexp_exec(regex, line.data + pos, line.length - pos, 1, &match, flags)
71 ) {
72 flags = REG_NOTBOL;
73 if (cx >= 0) {
74 if (pos + match.rm_so >= cx) {
75 // Ignore match at or after cursor
76 break;
77 }
78 if (skip && pos + match.rm_eo > cx) {
79 // Search -rw should not find word under cursor
80 break;
81 }
82 }
83
84 // This might be what we want (last match before cursor)
85 offset = pos + match.rm_so;
86 pos += match.rm_eo;
87
88 if (match.rm_so == match.rm_eo) {
89 // Zero length match
90 break;
91 }
92 }
93
94 if (offset >= 0) {
95 block_iter_skip_bytes(bi, offset);
96 view->cursor = *bi;
97 view->center_on_scroll = true;
98 view_reset_preferred_x(view);
99 return true;
100 }
101
102 next:
103 cx = -1;
104 } while (block_iter_prev_line(bi));
105
106 return false;
107}
108
109bool search_tag(View *view, const char *pattern)
110{
111 regex_t regex;
112 if (!regexp_compile_basic(&regex, pattern, REG_NEWLINE)) {
113 return false;
114 }
115
116 BlockIter bi = block_iter(view->buffer);
117 bool found = do_search_fwd(view, &regex, &bi, false);
118 regfree(&regex);
119
120 if (!found) {
121 // Don't center view to cursor unnecessarily
122 view->force_center = false;
123 return error_msg("Tag not found");
124 }
125
126 view->center_on_scroll = true;
127 return true;
128}
129
130static void free_regex(SearchState *search)
131{
132 if (search->re_flags) {
133 regfree(&search->regex);
134 search->re_flags = 0;
135 }
136}
137
138static bool has_upper(const char *str)
139{
140 for (size_t i = 0; str[i]; i++) {
141 if (ascii_isupper(str[i])) {
142 return true;
143 }
144 }
145 return false;
146}
147
148static bool update_regex(SearchState *search, SearchCaseSensitivity cs)
149{
150 int re_flags = REG_NEWLINE;
151 switch (cs) {
152 case CSS_TRUE:
153 break;
154 case CSS_FALSE:
155 re_flags |= REG_ICASE;
156 break;
157 case CSS_AUTO:
158 if (!has_upper(search->pattern)) {
159 re_flags |= REG_ICASE;
160 }
161 break;
162 default:
163 BUG("unhandled case sensitivity value");
164 }
165
166 if (re_flags == search->re_flags) {
167 return true;
168 }
169
170 free_regex(search);
171
172 search->re_flags = re_flags;
173 if (regexp_compile(&search->regex, search->pattern, search->re_flags)) {
174 return true;
175 }
176
177 free_regex(search);
178 return false;
179}
180
181void search_free_regexp(SearchState *search)
182{
183 free_regex(search);
184 free(search->pattern);
185}
186
187void search_set_regexp(SearchState *search, const char *pattern)
188{
189 search_free_regexp(search);
190 search->pattern = xstrdup(pattern);
191}
192
193static bool do_search_next(View *view, SearchState *search, SearchCaseSensitivity cs, bool skip)
194{
195 if (!search->pattern) {
196 return error_msg("No previous search pattern");
197 }
198 if (!update_regex(search, cs)) {
199 return false;
200 }
201
202 BlockIter bi = view->cursor;
203 regex_t *regex = &search->regex;
204 if (!search->reverse) {
205 if (do_search_fwd(view, regex, &bi, true)) {
206 return true;
207 }
208 block_iter_bof(&bi);
209 if (do_search_fwd(view, regex, &bi, false)) {
210 info_msg("Continuing at top");
211 return true;
212 }
213 } else {
214 size_t cursor_x = block_iter_bol(&bi);
215 if (do_search_bwd(view, regex, &bi, cursor_x, skip)) {
216 return true;
217 }
218 block_iter_eof(&bi);
219 if (do_search_bwd(view, regex, &bi, -1, false)) {
220 info_msg("Continuing at bottom");
221 return true;
222 }
223 }
224
225 return error_msg("Pattern '%s' not found", search->pattern);
226}
227
228bool search_prev(View *view, SearchState *search, SearchCaseSensitivity cs)
229{
230 toggle_search_direction(search);
231 bool r = search_next(view, search, cs);
232 toggle_search_direction(search);
233 return r;
234}
235
236bool search_next(View *view, SearchState *search, SearchCaseSensitivity cs)
237{
238 return do_search_next(view, search, cs, false);
239}
240
241bool search_next_word(View *view, SearchState *search, SearchCaseSensitivity cs)
242{
243 return do_search_next(view, search, cs, true);
244}