mirror of
https://github.com/rkd77/elinks.git
synced 2024-11-03 08:07:17 -05: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->search);
|
||||||
mem_free_if(document->slines1);
|
mem_free_if(document->slines1);
|
||||||
mem_free_if(document->slines2);
|
mem_free_if(document->slines2);
|
||||||
|
mem_free_if(document->search_points);
|
||||||
|
|
||||||
del_from_list(document);
|
del_from_list(document);
|
||||||
mem_free(document);
|
mem_free(document);
|
||||||
|
@ -237,6 +237,7 @@ struct document {
|
|||||||
struct search *search;
|
struct search *search;
|
||||||
struct search **slines1;
|
struct search **slines1;
|
||||||
struct search **slines2;
|
struct search **slines2;
|
||||||
|
struct point *search_points;
|
||||||
|
|
||||||
#ifdef CONFIG_UTF8
|
#ifdef CONFIG_UTF8
|
||||||
unsigned char buf[7];
|
unsigned char buf[7];
|
||||||
@ -256,6 +257,7 @@ struct document {
|
|||||||
int width, height; /**< size of document */
|
int width, height; /**< size of document */
|
||||||
int nlinks;
|
int nlinks;
|
||||||
int nsearch;
|
int nsearch;
|
||||||
|
int number_of_search_points;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
color_T background;
|
color_T background;
|
||||||
|
@ -188,11 +188,11 @@ do_action(struct session *ses, enum main_action action_id, int verbose)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_MAIN_FIND_NEXT:
|
case ACT_MAIN_FIND_NEXT:
|
||||||
status = find_next(ses, doc_view, 1);
|
status = move_search_next(ses, doc_view);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_MAIN_FIND_NEXT_BACK:
|
case ACT_MAIN_FIND_NEXT_BACK:
|
||||||
status = find_next(ses, doc_view, -1);
|
status = move_search_prev(ses, doc_view);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_MAIN_FORGET_CREDENTIALS:
|
case ACT_MAIN_FORGET_CREDENTIALS:
|
||||||
|
@ -65,7 +65,7 @@ static INIT_INPUT_HISTORY(search_history);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static UCHAR *memacpy_u(unsigned char *text, int textlen, int utf8);
|
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
|
static inline void
|
||||||
add_srch_chr(struct document *document, UCHAR c, int x, int y, int nn)
|
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) {
|
foreachback (node, document->nodes) {
|
||||||
int x, y;
|
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++) {
|
for (y = node->box.y; y < height; y++) {
|
||||||
int width = int_min(node->box.x + node->box.width,
|
int width = document->data[y].length;
|
||||||
document->data[y].length);
|
|
||||||
|
|
||||||
for (x = node->box.x;
|
for (x = 0;
|
||||||
x < width && document->data[y].chars[x].data <= ' ';
|
x < width && document->data[y].chars[x].data <= ' ';
|
||||||
x++);
|
x++);
|
||||||
|
|
||||||
@ -693,6 +692,52 @@ srch_failed:
|
|||||||
*pl = len;
|
*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
|
#ifdef CONFIG_TRE
|
||||||
struct get_searched_regex_context {
|
struct get_searched_regex_context {
|
||||||
int xoffset;
|
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
|
static void
|
||||||
get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
||||||
int textlen, struct search *s1, struct search *s2, int utf8)
|
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;
|
*pt = ctx.points;
|
||||||
*pl = ctx.len;
|
*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 */
|
#endif /* CONFIG_TRE */
|
||||||
|
|
||||||
static void
|
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 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
|
static enum find_error
|
||||||
search_for_do(struct session *ses, unsigned char *str, int direction,
|
search_for_do(struct session *ses, unsigned char *str, int direction,
|
||||||
int report_errors)
|
int report_errors)
|
||||||
{
|
{
|
||||||
struct document_view *doc_view;
|
struct document_view *doc_view;
|
||||||
enum find_error error;
|
int utf8 = 0;
|
||||||
|
|
||||||
assert(ses && str);
|
assert(ses && str);
|
||||||
if_assert_failed return FIND_ERROR_NOT_FOUND;
|
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);
|
assert(doc_view);
|
||||||
if_assert_failed return FIND_ERROR_NOT_FOUND;
|
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->search_word, NULL);
|
||||||
mem_free_set(&ses->last_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;
|
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. */
|
* initialized. find_next() will set ses->search_word for us. */
|
||||||
ses->last_search_word = stracpy(str);
|
ses->last_search_word = stracpy(str);
|
||||||
if (!ses->last_search_word) return FIND_ERROR_NOT_FOUND;
|
if (!ses->last_search_word) return FIND_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
ses->search_direction = direction;
|
ses->search_direction = direction;
|
||||||
|
|
||||||
error = find_next_do(ses, doc_view, 1);
|
return get_searched_all(ses, doc_view, &doc_view->document->search_points,
|
||||||
|
&doc_view->document->number_of_search_points, utf8);
|
||||||
if (report_errors)
|
|
||||||
print_find_error(ses, error);
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
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
|
enum frame_event_status
|
||||||
find_next(struct session *ses, struct document_view *doc_view, int direction)
|
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);
|
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 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_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);
|
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));
|
memset(vs, 0, sizeof(*vs));
|
||||||
vs->current_link = -1;
|
vs->current_link = -1;
|
||||||
vs->old_current_link = -1;
|
vs->old_current_link = -1;
|
||||||
|
vs->current_search_number = -1;
|
||||||
vs->plain = plain;
|
vs->plain = plain;
|
||||||
vs->uri = uri ? get_uri_reference(uri) : NULL;
|
vs->uri = uri ? get_uri_reference(uri) : NULL;
|
||||||
vs->did_fragment = !uri->fragmentlen;
|
vs->did_fragment = !uri->fragmentlen;
|
||||||
|
@ -36,6 +36,7 @@ struct view_state {
|
|||||||
* or -1 of none. */
|
* or -1 of none. */
|
||||||
int current_link;
|
int current_link;
|
||||||
int old_current_link;
|
int old_current_link;
|
||||||
|
int current_search_number;
|
||||||
|
|
||||||
int plain;
|
int plain;
|
||||||
unsigned int wrap:1;
|
unsigned int wrap:1;
|
||||||
|
Loading…
Reference in New Issue
Block a user