1 /* Copyright (c) 2006-2015 Jonas Fonseca <jonas.fonseca@gmail.com>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include "tig/search.h"
15 #include "tig/prompt.h"
16 #include "tig/display.h"
19 DEFINE_ALLOCATOR(realloc_unsigned_ints
, unsigned int, 32)
22 grep_text(struct view
*view
, const char *text
[])
27 for (i
= 0; text
[i
]; i
++)
28 if (*text
[i
] && !regexec(view
->regex
, text
[i
], 1, &pmatch
, 0))
34 find_matches(struct view
*view
)
38 /* Note, lineno is unsigned long so will wrap around in which case it
39 * will become bigger than view->lines. */
40 for (lineno
= 0; lineno
< view
->lines
; lineno
++) {
41 if (!view
->ops
->grep(view
, &view
->line
[lineno
]))
44 if (!realloc_unsigned_ints(&view
->matched_line
, view
->matched_lines
, 1))
47 view
->matched_line
[view
->matched_lines
++] = lineno
;
54 setup_and_find_next(struct view
*view
, enum request request
)
57 int regex_flags
= opt_ignore_case
? REG_ICASE
: 0;
63 view
->regex
= calloc(1, sizeof(*view
->regex
));
68 regex_err
= regcomp(view
->regex
, view
->env
->search
, REG_EXTENDED
| regex_flags
);
70 char buf
[SIZEOF_STR
] = "unknown error";
72 regerror(regex_err
, view
->regex
, buf
, sizeof(buf
));
73 report("Search failed: %s", buf
);
77 string_copy(view
->grep
, view
->env
->search
);
81 find_next(view
, request
);
85 find_next(struct view
*view
, enum request request
)
91 if (!*view
->env
->search
)
92 report("No previous search");
94 setup_and_find_next(view
, request
);
104 case REQ_SEARCH_BACK
:
113 if (!view
->matched_lines
&& !find_matches(view
)) {
114 report("Allocation failure");
118 /* Note, `i` is unsigned and will wrap around in which case it
119 * will become bigger than view->matched_lines. */
120 i
= direction
> 0 ? 0 : view
->matched_lines
- 1;
121 for (; i
< view
->matched_lines
; i
+= direction
) {
122 size_t lineno
= view
->matched_line
[i
];
124 if (direction
> 0 && lineno
<= view
->pos
.lineno
)
127 if (direction
< 0 && lineno
>= view
->pos
.lineno
)
130 select_view_line(view
, lineno
);
131 report("Line %zu matches '%s' (%zu of %zu)", lineno
+ 1, view
->grep
, i
+ 1, view
->matched_lines
);
135 report("No match found for '%s'", view
->grep
);
139 reset_search(struct view
*view
)
141 free(view
->matched_line
);
142 view
->matched_line
= NULL
;
143 view
->matched_lines
= 0;
147 search_view(struct view
*view
, enum request request
)
149 const char *prompt
= request
== REQ_SEARCH
? "/" : "?";
150 char *search
= read_prompt(prompt
);
153 string_ncopy(argv_env
.search
, search
, strlen(search
));
154 setup_and_find_next(view
, request
);
155 } else if (*argv_env
.search
) {
156 find_next(view
, request
);
162 /* vim: set ts=8 sw=8 noexpandtab: */