mirror of
https://github.com/rkd77/elinks.git
synced 2024-09-06 23:44:43 -04:00
Rewritten searching. Refs #21
Before only visible part of screen was searched for pattern. Now whole document is searched, and beginings of found text is remembered in document->search_points.
This commit is contained in:
parent
fd1ae61131
commit
7a006b6dd2
@ -244,6 +244,7 @@ done_document(struct document *document)
|
||||
mem_free_if(document->search);
|
||||
mem_free_if(document->slines1);
|
||||
mem_free_if(document->slines2);
|
||||
mem_free_if(document->search_points);
|
||||
|
||||
del_from_list(document);
|
||||
mem_free(document);
|
||||
|
@ -237,6 +237,7 @@ struct document {
|
||||
struct search *search;
|
||||
struct search **slines1;
|
||||
struct search **slines2;
|
||||
struct point *search_points;
|
||||
|
||||
#ifdef CONFIG_UTF8
|
||||
unsigned char buf[7];
|
||||
@ -256,6 +257,7 @@ struct document {
|
||||
int width, height; /**< size of document */
|
||||
int nlinks;
|
||||
int nsearch;
|
||||
int number_of_search_points;
|
||||
|
||||
struct {
|
||||
color_T background;
|
||||
|
@ -188,11 +188,11 @@ do_action(struct session *ses, enum main_action action_id, int verbose)
|
||||
break;
|
||||
|
||||
case ACT_MAIN_FIND_NEXT:
|
||||
status = find_next(ses, doc_view, 1);
|
||||
status = move_search_next(ses, doc_view);
|
||||
break;
|
||||
|
||||
case ACT_MAIN_FIND_NEXT_BACK:
|
||||
status = find_next(ses, doc_view, -1);
|
||||
status = move_search_prev(ses, doc_view);
|
||||
break;
|
||||
|
||||
case ACT_MAIN_FORGET_CREDENTIALS:
|
||||
|
@ -65,7 +65,7 @@ static INIT_INPUT_HISTORY(search_history);
|
||||
#endif
|
||||
|
||||
static UCHAR *memacpy_u(unsigned char *text, int textlen, int utf8);
|
||||
|
||||
static enum frame_event_status move_search_do(struct session *ses, struct document_view *doc_view, int direction);
|
||||
static inline void
|
||||
add_srch_chr(struct document *document, UCHAR c, int x, int y, int nn)
|
||||
{
|
||||
@ -153,13 +153,12 @@ get_srch(struct document *document)
|
||||
|
||||
foreachback (node, document->nodes) {
|
||||
int x, y;
|
||||
int height = int_min(node->box.y + node->box.height, document->height);
|
||||
int height = document->height;
|
||||
|
||||
for (y = node->box.y; y < height; y++) {
|
||||
int width = int_min(node->box.x + node->box.width,
|
||||
document->data[y].length);
|
||||
int width = document->data[y].length;
|
||||
|
||||
for (x = node->box.x;
|
||||
for (x = 0;
|
||||
x < width && document->data[y].chars[x].data <= ' ';
|
||||
x++);
|
||||
|
||||
@ -693,6 +692,52 @@ srch_failed:
|
||||
*pl = len;
|
||||
}
|
||||
|
||||
static void
|
||||
get_searched_plain_all(struct document_view *doc_view, struct point **pt, int *pl,
|
||||
int l, struct search *s1, struct search *s2, int utf8)
|
||||
{
|
||||
UCHAR *txt;
|
||||
struct point *points = NULL;
|
||||
int len = 0;
|
||||
int case_sensitive = get_opt_bool("document.browse.search.case", NULL);
|
||||
|
||||
txt = case_sensitive ? memacpy_u(*doc_view->search_word, l, utf8)
|
||||
: lowered_string(*doc_view->search_word, l, utf8);
|
||||
if (!txt) return;
|
||||
|
||||
#if defined(CONFIG_UTF8) && defined(HAVE_WCTYPE_H)
|
||||
#define maybe_tolower(c) (case_sensitive ? (c) : utf8 ? towlower(c) : tolower(c))
|
||||
#else
|
||||
#define maybe_tolower(c) (case_sensitive ? (c) : tolower(c))
|
||||
#endif
|
||||
|
||||
for (; s1 <= s2; s1++) {
|
||||
int i;
|
||||
|
||||
if (maybe_tolower(s1[0].c) != txt[0]) {
|
||||
srch_failed:
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 1; i < l; i++)
|
||||
if (maybe_tolower(s1[i].c) != txt[i])
|
||||
goto srch_failed;
|
||||
|
||||
if (!realloc_points(&points, len))
|
||||
continue;
|
||||
|
||||
points[len].x = s1[0].x;
|
||||
points[len++].y = s1[0].y;
|
||||
}
|
||||
|
||||
#undef maybe_tolower
|
||||
|
||||
mem_free(txt);
|
||||
*pt = points;
|
||||
*pl = len;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TRE
|
||||
struct get_searched_regex_context {
|
||||
int xoffset;
|
||||
@ -731,6 +776,18 @@ get_searched_regex_match(struct regex_match_context *common_ctx, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_searched_regex_match_all(struct regex_match_context *common_ctx, void *data)
|
||||
{
|
||||
struct get_searched_regex_context *ctx = data;
|
||||
|
||||
if (!realloc_points(&ctx->points, ctx->len))
|
||||
return;
|
||||
|
||||
ctx->points[ctx->len].x = common_ctx->s1[0].x;
|
||||
ctx->points[ctx->len++].y = common_ctx->s1[0].y;
|
||||
}
|
||||
|
||||
static void
|
||||
get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
||||
int textlen, struct search *s1, struct search *s2, int utf8)
|
||||
@ -761,6 +818,38 @@ get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
||||
*pt = ctx.points;
|
||||
*pl = ctx.len;
|
||||
}
|
||||
|
||||
static void
|
||||
get_searched_regex_all(struct document_view *doc_view, struct point **pt, int *pl,
|
||||
int textlen, struct search *s1, struct search *s2, int utf8)
|
||||
{
|
||||
struct regex_match_context common_ctx;
|
||||
struct get_searched_regex_context ctx;
|
||||
UCHAR *txt = memacpy_u(*doc_view->search_word, textlen, utf8);
|
||||
|
||||
if (!txt) return;
|
||||
|
||||
ctx.points = NULL;
|
||||
ctx.len = 0;
|
||||
ctx.box = &doc_view->box;
|
||||
ctx.xoffset = 0;
|
||||
ctx.yoffset = 0;
|
||||
|
||||
common_ctx.found = 0;
|
||||
common_ctx.textlen = textlen;
|
||||
common_ctx.y1 = -1;
|
||||
common_ctx.y2 = doc_view->document->height;
|
||||
common_ctx.pattern = txt;
|
||||
common_ctx.s1 = s1;
|
||||
common_ctx.s2 = s2;
|
||||
|
||||
search_for_pattern(&common_ctx, &ctx, get_searched_regex_match_all);
|
||||
|
||||
mem_free(txt);
|
||||
*pt = ctx.points;
|
||||
*pl = ctx.len;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TRE */
|
||||
|
||||
static void
|
||||
@ -854,12 +943,50 @@ static enum find_error find_next_do(struct session *ses,
|
||||
|
||||
static void print_find_error(struct session *ses, enum find_error find_error);
|
||||
|
||||
static enum find_error
|
||||
get_searched_all(struct session *ses, struct document_view *doc_view, struct point **pt, int *pl, int utf8)
|
||||
{
|
||||
struct search *s1, *s2;
|
||||
int l;
|
||||
|
||||
assert(ses && doc_view && doc_view->vs && pt && pl);
|
||||
if_assert_failed return FIND_ERROR_MEMORY;
|
||||
|
||||
if (!ses->search_word) {
|
||||
if (!ses->last_search_word) {
|
||||
return FIND_ERROR_NO_PREVIOUS_SEARCH;
|
||||
}
|
||||
ses->search_word = stracpy(ses->last_search_word);
|
||||
if (!ses->search_word) return FIND_ERROR_MEMORY;
|
||||
}
|
||||
|
||||
get_search_data(doc_view->document);
|
||||
l = strlen_u(*doc_view->search_word, utf8);
|
||||
|
||||
if (get_range(doc_view->document, 0,
|
||||
doc_view->document->height, l, &s1, &s2)) {
|
||||
*pt = NULL;
|
||||
*pl = 0;
|
||||
|
||||
return FIND_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TRE
|
||||
if (get_opt_int("document.browse.search.regex", NULL))
|
||||
get_searched_regex_all(doc_view, pt, pl, l, s1, s2, utf8);
|
||||
else
|
||||
#endif
|
||||
get_searched_plain_all(doc_view, pt, pl, l, s1, s2, utf8);
|
||||
|
||||
return move_search_do(ses, doc_view, 0);
|
||||
}
|
||||
|
||||
static enum find_error
|
||||
search_for_do(struct session *ses, unsigned char *str, int direction,
|
||||
int report_errors)
|
||||
{
|
||||
struct document_view *doc_view;
|
||||
enum find_error error;
|
||||
int utf8 = 0;
|
||||
|
||||
assert(ses && str);
|
||||
if_assert_failed return FIND_ERROR_NOT_FOUND;
|
||||
@ -869,8 +996,15 @@ search_for_do(struct session *ses, unsigned char *str, int direction,
|
||||
assert(doc_view);
|
||||
if_assert_failed return FIND_ERROR_NOT_FOUND;
|
||||
|
||||
#ifdef CONFIG_UTF8
|
||||
utf8 = doc_view->document->options.utf8;
|
||||
#endif
|
||||
|
||||
mem_free_set(&ses->search_word, NULL);
|
||||
mem_free_set(&ses->last_search_word, NULL);
|
||||
mem_free_set(&doc_view->document->search_points, NULL);
|
||||
doc_view->document->number_of_search_points = 0;
|
||||
doc_view->vs->current_search_number = -1;
|
||||
|
||||
if (!*str) return FIND_ERROR_NOT_FOUND;
|
||||
|
||||
@ -879,15 +1013,10 @@ search_for_do(struct session *ses, unsigned char *str, int direction,
|
||||
* initialized. find_next() will set ses->search_word for us. */
|
||||
ses->last_search_word = stracpy(str);
|
||||
if (!ses->last_search_word) return FIND_ERROR_NOT_FOUND;
|
||||
|
||||
ses->search_direction = direction;
|
||||
|
||||
error = find_next_do(ses, doc_view, 1);
|
||||
|
||||
if (report_errors)
|
||||
print_find_error(ses, error);
|
||||
|
||||
return error;
|
||||
return get_searched_all(ses, doc_view, &doc_view->document->search_points,
|
||||
&doc_view->document->number_of_search_points, utf8);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1139,6 +1268,86 @@ print_find_error(struct session *ses, enum find_error find_error)
|
||||
info_box(ses->tab->term, 0, N_("Search"), ALIGN_CENTER, message);
|
||||
}
|
||||
|
||||
static enum find_error move_search_number(struct session *ses, struct document_view *doc_view, int number);
|
||||
|
||||
static int
|
||||
is_y_on_screen(struct document_view *doc_view, int y)
|
||||
{
|
||||
return y >= doc_view->vs->y && y < doc_view->vs->y + doc_view->box.height;
|
||||
}
|
||||
|
||||
static void
|
||||
find_first_search_in_view(struct session *ses, struct document_view *doc_view)
|
||||
{
|
||||
int i;
|
||||
int current_search_number = doc_view->vs->current_search_number;
|
||||
|
||||
if (!doc_view->document->number_of_search_points)
|
||||
return;
|
||||
|
||||
if (current_search_number >= 0 && current_search_number < doc_view->document->number_of_search_points) {
|
||||
struct point *point = doc_view->document->search_points + current_search_number;
|
||||
|
||||
if (is_y_on_screen(doc_view, point[0].y))
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < doc_view->document->number_of_search_points; ++i) {
|
||||
int y = doc_view->document->search_points[i].y;
|
||||
|
||||
if (y >= doc_view->vs->y)
|
||||
break;
|
||||
}
|
||||
doc_view->vs->current_search_number = i;
|
||||
}
|
||||
|
||||
static enum frame_event_status
|
||||
move_search_do(struct session *ses, struct document_view *doc_view, int direction)
|
||||
{
|
||||
int number;
|
||||
|
||||
find_first_search_in_view(ses, doc_view);
|
||||
number = doc_view->vs->current_search_number + direction;
|
||||
print_find_error(ses, move_search_number(ses, doc_view, number));
|
||||
|
||||
return FRAME_EVENT_REFRESH;
|
||||
}
|
||||
enum frame_event_status
|
||||
move_search_next(struct session *ses, struct document_view *doc_view)
|
||||
{
|
||||
return move_search_do(ses, doc_view, 1);
|
||||
}
|
||||
|
||||
enum frame_event_status
|
||||
move_search_prev(struct session *ses, struct document_view *doc_view)
|
||||
{
|
||||
return move_search_do(ses, doc_view, -1);
|
||||
}
|
||||
|
||||
static enum find_error
|
||||
move_search_number(struct session *ses, struct document_view *doc_view, int number)
|
||||
{
|
||||
struct point *pt;
|
||||
int x, y;
|
||||
|
||||
if (number < 0)
|
||||
return FIND_ERROR_HIT_TOP;
|
||||
if (number >= doc_view->document->number_of_search_points)
|
||||
return FIND_ERROR_HIT_BOTTOM;
|
||||
|
||||
doc_view->vs->current_search_number = number;
|
||||
pt = doc_view->document->search_points;
|
||||
x = pt[number].x;
|
||||
y = pt[number].y;
|
||||
|
||||
if (x < doc_view->vs->x || x >= doc_view->vs->x + doc_view->box.width)
|
||||
doc_view->vs->x = x;
|
||||
doc_view->vs->y = y;
|
||||
set_link(doc_view);
|
||||
|
||||
return FIND_ERROR_NONE;
|
||||
}
|
||||
|
||||
enum frame_event_status
|
||||
find_next(struct session *ses, struct document_view *doc_view, int direction)
|
||||
{
|
||||
|
@ -15,6 +15,9 @@ extern struct module search_history_module;
|
||||
void draw_searched(struct terminal *term, struct document_view *doc_view);
|
||||
|
||||
enum frame_event_status find_next(struct session *ses, struct document_view *doc_view, int direction);
|
||||
enum frame_event_status move_search_next(struct session *ses, struct document_view *doc_view);
|
||||
enum frame_event_status move_search_prev(struct session *ses, struct document_view *doc_view);
|
||||
|
||||
|
||||
enum frame_event_status search_dlg(struct session *ses, struct document_view *doc_view, int direction);
|
||||
enum frame_event_status search_typeahead(struct session *ses, struct document_view *doc_view, action_id_T action_id);
|
||||
|
@ -34,6 +34,7 @@ init_vs(struct view_state *vs, struct uri *uri, int plain)
|
||||
memset(vs, 0, sizeof(*vs));
|
||||
vs->current_link = -1;
|
||||
vs->old_current_link = -1;
|
||||
vs->current_search_number = -1;
|
||||
vs->plain = plain;
|
||||
vs->uri = uri ? get_uri_reference(uri) : NULL;
|
||||
vs->did_fragment = !uri->fragmentlen;
|
||||
|
@ -36,6 +36,7 @@ struct view_state {
|
||||
* or -1 of none. */
|
||||
int current_link;
|
||||
int old_current_link;
|
||||
int current_search_number;
|
||||
|
||||
int plain;
|
||||
unsigned int wrap:1;
|
||||
|
Loading…
Reference in New Issue
Block a user