📄 search.c
字号:
regex_flags |= REG_EXTENDED; if (!get_opt_bool("document.browse.search.case")) regex_flags |= REG_ICASE; /* TODO: show error message */ reg_err = regcomp(®ex, *doc_view->search_word, regex_flags); if (reg_err) {#if 0 /* Where and how should we display the error dialog ? */ unsigned char regerror_string[MAX_STR_LEN]; regerror(reg_err, ®ex, regerror_string, sizeof(regerror_string));#endif regfree(®ex); goto ret; } doclen = s2 - s1 + l; if (!doclen) { regfree(®ex); goto ret; } doc = get_search_region_from_search_nodes(s1, doclen); if (!doc) { regfree(®ex); goto ret; } box = &doc_view->box; xoffset = box->x - doc_view->vs->x; yoffset = box->y - doc_view->vs->y; y1 = doc_view->vs->y - 1; y2 = doc_view->vs->y + box->height; doctmp = doc;find_next: while (pos < doclen) { int y = search_start[pos].y; if (y >= y1 && y <= y2) break; pos++; } doctmp = &doc[pos]; s1 = &search_start[pos]; while (pos < doclen) { int y = search_start[pos].y; if (y < y1 || y > y2) break; pos++; } save_c = doc[pos]; doc[pos] = 0; while (*doctmp && !regexec(®ex, doctmp, 1, ®match, regexec_flags)) { regexec_flags = REG_NOTBOL; l = regmatch.rm_eo - regmatch.rm_so; if (!l) { doc[pos] = save_c; goto free_stuff; } s1 += regmatch.rm_so; doctmp += regmatch.rm_so; for (i = 0; i < l; i++) { int j; int y = s1[i].y + yoffset; if (!row_is_in_box(box, y)) continue; for (j = 0; j < s1[i].n; j++) { int sx = s1[i].x + j; int x = sx + xoffset; if (!col_is_in_box(box, x)) continue; if (!realloc_points(&points, len)) continue; points[len].x = sx; points[len++].y = s1[i].y; } } doctmp += int_max(l, 1); s1 += int_max(l, 1); } doc[pos] = save_c; if (pos < doclen) goto find_next;free_stuff: regfree(®ex); mem_free(doc);ret: *pt = points; *pl = len;}#endif /* HAVE_REGEX_H */static voidget_searched(struct document_view *doc_view, struct point **pt, int *pl){ struct search *s1, *s2; int l; assert(doc_view && doc_view->vs && pt && pl); if_assert_failed return; if (!has_search_word(doc_view)) return; get_search_data(doc_view->document); l = strlen(*doc_view->search_word); if (get_range(doc_view->document, doc_view->vs->y, doc_view->box.height, l, &s1, &s2)) { *pt = NULL; *pl = 0; return; }#ifdef HAVE_REGEX_H if (get_opt_int("document.browse.search.regex")) get_searched_regex(doc_view, pt, pl, l, s1, s2); else#endif get_searched_plain(doc_view, pt, pl, l, s1, s2);}/* Highlighting of searched strings. */voiddraw_searched(struct terminal *term, struct document_view *doc_view){ struct point *pt = NULL; int len = 0; assert(term && doc_view); if_assert_failed return; if (!has_search_word(doc_view)) return; get_searched(doc_view, &pt, &len); if (len) { int i; struct color_pair *color = get_bfu_color(term, "searched"); int xoffset = doc_view->box.x - doc_view->vs->x; int yoffset = doc_view->box.y - doc_view->vs->y; for (i = 0; i < len; i++) { int x = pt[i].x + xoffset; int y = pt[i].y + yoffset; /* TODO: We should take in account original colors and * combine them with defined color. */#if 0 /* This piece of code shows the old way of handling * colors and screen char attributes. */ unsigned co = get_char(term, x, y); co = ((co >> 3) & 0x0700) | ((co << 3) & 0x3800);#endif draw_char_color(term, x, y, color); } } mem_free_if(pt);}enum find_error { FIND_ERROR_NONE, FIND_ERROR_NO_PREVIOUS_SEARCH, FIND_ERROR_HIT_TOP, FIND_ERROR_HIT_BOTTOM, FIND_ERROR_NOT_FOUND, FIND_ERROR_MEMORY, FIND_ERROR_REGEX,};static enum find_error find_next_do(struct session *ses, struct document_view *doc_view, int direction);static void print_find_error(struct session *ses, enum find_error find_error);static enum find_errorsearch_for_do(struct session *ses, unsigned char *str, int direction, int report_errors){ struct document_view *doc_view; enum find_error error; assert(ses && str); if_assert_failed return FIND_ERROR_NOT_FOUND; doc_view = current_frame(ses); assert(doc_view); if_assert_failed return FIND_ERROR_NOT_FOUND; mem_free_set(&ses->search_word, NULL); mem_free_set(&ses->last_search_word, NULL); if (!*str) return FIND_ERROR_NOT_FOUND; /* We only set the last search word because we don.t want find_next() * to try to find next link in search before the search data has been * 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;}static voidsearch_for_back(struct session *ses, unsigned char *str){ assert(ses && str); if_assert_failed return; search_for_do(ses, str, -1, 1);}static voidsearch_for(struct session *ses, unsigned char *str){ assert(ses && str); if_assert_failed return; search_for_do(ses, str, 1, 1);}static inline intpoint_intersect(struct point *p1, int l1, struct point *p2, int l2){#define HASH_SIZE 4096#define HASH(p) ((((p).y << 6) + (p).x) & (HASH_SIZE - 1)) int i; static char hash[HASH_SIZE]; static int first_time = 1; assert(p2); if_assert_failed return 0; if (first_time) memset(hash, 0, HASH_SIZE), first_time = 0; for (i = 0; i < l1; i++) hash[HASH(p1[i])] = 1; for (i = 0; i < l2; i++) { int j; if (!hash[HASH(p2[i])]) continue; for (j = 0; j < l1; j++) { if (p1[j].x != p2[i].x) continue; if (p1[j].y != p2[i].y) continue; for (i = 0; i < l1; i++) hash[HASH(p1[i])] = 0; return 1; } } for (i = 0; i < l1; i++) hash[HASH(p1[i])] = 0; return 0;#undef HASH#undef HASH_SIZE}static intfind_next_link_in_search(struct document_view *doc_view, int direction){ assert(doc_view && doc_view->vs); if_assert_failed return 0; if (direction == -2 || direction == 2) { direction /= 2; if (direction < 0) find_link_page_up(doc_view); else find_link_page_down(doc_view); if (doc_view->vs->current_link == -1) return 1; goto nt; } while (doc_view->vs->current_link != -1 && next_link_in_view(doc_view, doc_view->vs->current_link + direction, direction, link_in_view, NULL)) { struct point *pt = NULL; struct link *link; int len;nt: link = &doc_view->document->links[doc_view->vs->current_link]; get_searched(doc_view, &pt, &len); if (point_intersect(pt, len, link->points, link->npoints)) { mem_free(pt); return 0; } mem_free_if(pt); } if (direction < 0) find_link_page_up(doc_view); else find_link_page_down(doc_view); return 1;}static enum find_errorfind_next_do(struct session *ses, struct document_view *doc_view, int direction){ int p, min, max, c = 0; int step, hit_bottom = 0, hit_top = 0; int height; assert(ses && ses->tab && ses->tab->term && doc_view && doc_view->vs && direction); if_assert_failed return FIND_ERROR_NONE; direction *= ses->search_direction; p = doc_view->vs->y; height = doc_view->box.height; step = direction * height; if (ses->search_word) { if (!find_next_link_in_search(doc_view, direction)) return FIND_ERROR_NONE; p += step; } 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_NONE; } get_search_data(doc_view->document); do { int in_range = is_in_range(doc_view->document, p, height, ses->search_word, &min, &max); if (in_range == -1) return FIND_ERROR_MEMORY; if (in_range == -2) return FIND_ERROR_REGEX; if (in_range) { doc_view->vs->y = p; if (max >= min) doc_view->vs->x = int_min(int_max(doc_view->vs->x, max - doc_view->box.width), min); set_link(doc_view); find_next_link_in_search(doc_view, direction * 2); if (hit_top) return FIND_ERROR_HIT_TOP; if (hit_bottom) return FIND_ERROR_HIT_BOTTOM; return FIND_ERROR_NONE; } p += step; if (p > doc_view->document->height) { hit_bottom = 1; p = 0; } if (p < 0) { hit_top = 1; p = 0; while (p < doc_view->document->height) p += height; p -= height; } c += height; } while (c < doc_view->document->height + height); return FIND_ERROR_NOT_FOUND;}static voidprint_find_error_not_found(struct session *ses, unsigned char *title, unsigned char *message, unsigned char *search_string){ switch (get_opt_int("document.browse.search.show_not_found")) { case 2: info_box(ses->tab->term, MSGBOX_FREE_TEXT, title, ALIGN_CENTER, msg_text(ses->tab->term, message, search_string)); break; case 1: beep_terminal(ses->tab->term); default: break; }}static voidprint_find_error(struct session *ses, enum find_error find_error){ int hit_top = 0; unsigned char *message = NULL; switch (find_error) { case FIND_ERROR_HIT_TOP: hit_top = 1; case FIND_ERROR_HIT_BOTTOM: if (!get_opt_bool("document.browse.search" ".show_hit_top_bottom")) break; message = hit_top ? N_("Search hit top, continuing at bottom.") : N_("Search hit bottom, continuing at top."); break; case FIND_ERROR_NO_PREVIOUS_SEARCH: message = N_("No previous search"); break; case FIND_ERROR_NOT_FOUND: print_find_error_not_found(ses, N_("Search"), N_("Search string" " '%s' not found"), ses->search_word); break; case FIND_ERROR_REGEX: print_find_error_not_found(ses, N_("Search"), N_("Could not compile" " regular expression" " '%s'"), ses->search_word); break; case FIND_ERROR_MEMORY: /* Why bother trying to create a msg_box? * We probably don't have the memory... */ case FIND_ERROR_NONE: break; } if (!message) return; info_box(ses->tab->term, 0, N_("Search"), ALIGN_CENTER, message);}enum frame_event_statusfind_next(struct session *ses, struct document_view *doc_view, int direction){ print_find_error(ses, find_next_do(ses, doc_view, direction)); /* FIXME: Make this more fine-grained */ return FRAME_EVENT_REFRESH;}/* Link typeahead */enum typeahead_code { TYPEAHEAD_MATCHED, TYPEAHEAD_ERROR, TYPEAHEAD_ERROR_NO_FURTHER, TYPEAHEAD_CANCEL,};static voidtypeahead_error(struct session *ses, unsigned char *typeahead, int no_further){ unsigned char *message; if (no_further) message = N_("No further matches for '%s'."); else message = N_("Could not find a link with the text '%s'."); print_find_error_not_found(ses, N_("Typeahead"), message, typeahead);}static inline unsigned char *get_link_typeahead_text(struct link *link){ unsigned char *name = get_link_name(link); if (name) return name; if (link->where) return link->where; if (link->where_img) return link->where_img; return "";}static intmatch_link_text(struct link *link, unsigned char *text, int textlen, int case_sensitive){ unsigned char *match = get_link_typeahead_text(link); unsigned char *matchpos; if (link_is_form(link) || textlen > strlen(match)) return -1; matchpos = case_sensitive ? strstr(match, text) : strcasestr(match, text); if (matchpos) { return matchpos - match; } return -1;}/* Searches the @document for a link with the given @text. takes the * current_link in the view, the link to start searching from @i and the * direction to search (1 is forward, -1 is back). */static inline intsearch_link_text(struct document *document, int current_link, int i, unsigned char *text, int direction, int *offset){ int upper_link, lower_link;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -