⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 search.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 3 页
字号:
	int case_sensitive = get_opt_bool("document.browse.search.case");	int wraparound = get_opt_bool("document.browse.search.wraparound");	int textlen = strlen(text);	assert(textlen && direction && offset);	/* The link interval in which we are currently searching */	/* Set up the range of links that should be search in first attempt */	if (direction > 0) {		upper_link = document->nlinks;		lower_link = i - 1;	} else {		upper_link = i + 1;		lower_link = -1;	}	for (; i > lower_link && i < upper_link; i += direction) {		struct link *link = &document->links[i];		int match_offset = match_link_text(link, text, textlen,						   case_sensitive);		if (match_offset >= 0) {			*offset = match_offset;			return i;		}		if (!wraparound) continue;		/* Check if we are at the end of the first range.		 * Only wrap around one time. Initialize @i with		 * {+= direction} in mind. */		if (direction > 0) {			 if (i == upper_link - 1) {				upper_link = current_link + 1;				lower_link = -1;				i = lower_link;				wraparound = 0;			 }		} else {			if (i == lower_link + 1) {				upper_link = document->nlinks;				lower_link = current_link - 1;				i = upper_link;				wraparound = 0;			}		}	}	return -1;}/* The typeahead input line takes up one of the viewed lines so we * might have to scroll if the link is under the input line. */static inline voidfixup_typeahead_match(struct session *ses, struct document_view *doc_view){	int current_link = doc_view->vs->current_link;	struct link *link = &doc_view->document->links[current_link];	doc_view->box.height -= 1;	set_pos_x(doc_view, link);	set_pos_y(doc_view, link);	doc_view->box.height += 1;}static inline unsigned charget_document_char(struct document *document, int x, int y){	return (document->height > y && document->data[y].length > x)		? document->data[y].chars[x].data : 0;}static voiddraw_typeahead_match(struct terminal *term, struct document_view *doc_view,		     int chars, int offset){	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;	struct link *link = get_current_link(doc_view);	unsigned char *text = get_link_typeahead_text(link);	int end = offset + chars;	int i, j;	for (i = 0, j = 0; text[j] && i < end; i++, j++) {		int x = link->points[i].x;		int y = link->points[i].y;		unsigned char data = get_document_char(doc_view->document, x, y);		/* Text wrapping might remove space chars from the link		 * position array so try to align the matched typeahead text		 * with what is actually on the screen by shifting the link		 * position variables if the canvas data do not match. */		if (data != text[j]) {			i--;			end--;			offset--;		} else if (i >= offset) {			/* TODO: We should take in account original colors and			 * combine them with defined color. */			draw_char_color(term, xoffset + x, yoffset + y, color);		}	}}static enum typeahead_codedo_typeahead(struct session *ses, struct document_view *doc_view,	     unsigned char *text, int action, int *offset){	int current = int_max(doc_view->vs->current_link, 0);	int direction, match, i = current;	struct document *document = doc_view->document;	switch (action) {		case ACT_EDIT_PREVIOUS_ITEM:		case ACT_EDIT_UP:			direction = -1;			i--;			if (i >= 0) break;			if (!get_opt_bool("document.browse.search.wraparound")) {search_hit_boundary:				if (match_link_text(&document->links[current],						    text, strlen(text),						    get_opt_bool("document"								 ".browse"								 ".search"								 ".case"))				     >= 0) {					return TYPEAHEAD_ERROR_NO_FURTHER;				}				return TYPEAHEAD_ERROR;			}			i = doc_view->document->nlinks - 1;			break;		case ACT_EDIT_NEXT_ITEM:		case ACT_EDIT_DOWN:			direction = 1;			i++;			if (i < doc_view->document->nlinks) break;			if (!get_opt_bool("document.browse.search.wraparound"))				goto search_hit_boundary;			i = 0;			break; 		case ACT_EDIT_ENTER:			goto_current_link(ses, doc_view, 0);			return TYPEAHEAD_CANCEL;		default:			direction = 1;	}	match = search_link_text(document, current, i, text, direction, offset);	if (match == current && i != current)		return TYPEAHEAD_ERROR_NO_FURTHER;	if (match < 0) {		if (i != current)			return TYPEAHEAD_ERROR_NO_FURTHER;		return TYPEAHEAD_ERROR;	}	assert(match >= 0 && match < doc_view->document->nlinks);	doc_view->vs->current_link = match;	return TYPEAHEAD_MATCHED;}/* Typeahead */static enum input_line_codetext_typeahead_handler(struct input_line *line, int action){	struct session *ses = line->ses;	unsigned char *buffer = line->buffer;	struct document_view *doc_view = current_frame(ses);	int direction = ((unsigned char *) line->data)[0] == '/' ? 1 : -1;	int report_errors = action == -1;	enum find_error error;	assertm(doc_view, "document not formatted");	if_assert_failed return INPUT_LINE_CANCEL;	switch (action) {		case ACT_EDIT_REDRAW:			return INPUT_LINE_PROCEED;		case ACT_EDIT_ENTER:			if (!*buffer) {				/* This ensures that search-typeahead-text				 * followed immediately with enter				 * clears the last search. */				search_for_do(ses, buffer, direction, 0);			}			goto_current_link(ses, doc_view, 0);			return INPUT_LINE_CANCEL;		case ACT_EDIT_PREVIOUS_ITEM:			find_next(ses, doc_view, -1);			break;		case ACT_EDIT_NEXT_ITEM:			find_next(ses, doc_view, 1);			break;		case ACT_EDIT_SEARCH_TOGGLE_REGEX: {			struct option *opt =				get_opt_rec(config_options,					    "document.browse.search.regex");			opt->value.number = (opt->value.number + 1)					    % (opt->max + 1);			opt->flags |= OPT_TOUCHED;		}		/* Fall thru */		default:			error = search_for_do(ses, buffer, direction, 0);			if (error == FIND_ERROR_REGEX)				break;			if (report_errors)				print_find_error(ses, error);			/* We need to check |*buffer| here because			 * the input-line code will call this handler			 * even after it handles a back-space press. */			if (error != FIND_ERROR_HIT_TOP			    && error != FIND_ERROR_HIT_BOTTOM			    && error != FIND_ERROR_NONE && *buffer)				return INPUT_LINE_REWIND;	}	draw_formatted(ses, 0);	return INPUT_LINE_PROCEED;}static enum input_line_codelink_typeahead_handler(struct input_line *line, int action){	struct session *ses = line->ses;	unsigned char *buffer = line->buffer;	struct document_view *doc_view = current_frame(ses);	int offset = 0;	assertm(doc_view, "document not formatted");	if_assert_failed return INPUT_LINE_CANCEL;	/* If there is nothing to match with don't start searching */	if (!*buffer) {		/* If something already were typed we need to redraw		 * in order to remove the coloring of the link text. */		if (line->data) draw_formatted(ses, 0);		return INPUT_LINE_PROCEED;	}	if (action == ACT_EDIT_REDRAW) {		int current = doc_view->vs->current_link;		int offset, bufferlen;		if (current < 0) return INPUT_LINE_PROCEED;		bufferlen = strlen(buffer);		offset = match_link_text(&doc_view->document->links[current],					 buffer, bufferlen,					 get_opt_bool("document.browse"						      ".search.case"));		if (offset >= 0) {			draw_typeahead_match(ses->tab->term, doc_view,					     bufferlen, offset);		}		return INPUT_LINE_PROCEED;	}	/* Hack time .. should we change mode? */	if (!line->data) {		enum main_action action = ACT_MAIN_NONE;		switch (*buffer) {			case '#':				action = ACT_MAIN_SEARCH_TYPEAHEAD_LINK;				break;			case '?':				action = ACT_MAIN_SEARCH_TYPEAHEAD_TEXT_BACK;				break;			case '/':				action = ACT_MAIN_SEARCH_TYPEAHEAD_TEXT;				break;			default:				break;		}		/* Should we reboot the input line .. (inefficient but easy) */		if (action != ACT_MAIN_NONE) {			search_typeahead(ses, doc_view, action);			return INPUT_LINE_CANCEL;		}		line->data = "#";	}	switch (do_typeahead(ses, doc_view, buffer, action, &offset)) {		case TYPEAHEAD_MATCHED:			fixup_typeahead_match(ses, doc_view);			draw_formatted(ses, 0);			draw_typeahead_match(ses->tab->term, doc_view, strlen(buffer), offset);			return INPUT_LINE_PROCEED;		case TYPEAHEAD_ERROR_NO_FURTHER:			typeahead_error(ses, buffer, 1);			draw_typeahead_match(ses->tab->term, doc_view, strlen(buffer), offset);			return INPUT_LINE_PROCEED;		case TYPEAHEAD_ERROR:			typeahead_error(ses, buffer, 0);			return INPUT_LINE_REWIND;		case TYPEAHEAD_CANCEL:		default:			return INPUT_LINE_CANCEL;	}}enum frame_event_statussearch_typeahead(struct session *ses, struct document_view *doc_view,		 int action){	unsigned char *prompt = "#";	unsigned char *data = NULL;	input_line_handler handler = text_typeahead_handler;	struct input_history *history = &search_history;	switch (action) {		case ACT_MAIN_SEARCH_TYPEAHEAD_TEXT:			prompt = data = "/";			break;		case ACT_MAIN_SEARCH_TYPEAHEAD_TEXT_BACK:			prompt = data = "?";			break;		case ACT_MAIN_SEARCH_TYPEAHEAD_LINK:			data = "#";			/* Falling forward .. good punk rock */		case ACT_MAIN_SEARCH_TYPEAHEAD:		default:			if (doc_view->document->nlinks) {				handler = link_typeahead_handler;				break;			}			info_box(ses->tab->term, MSGBOX_FREE_TEXT,				 N_("Typeahead"), ALIGN_CENTER,				 msg_text(ses->tab->term,					  N_("No links in current document")));						return FRAME_EVENT_OK;	}	input_field_line(ses, prompt, data, history, handler);	return FRAME_EVENT_OK;}/* The dialog functions are clones of input_field() ones. Gross code * duplication. *//* TODO: This is just hacked input_field(), containing a lot of generic crap * etc. The useless cruft should be blasted out. And it's quite ugly anyway, * a nice cleanup target ;-). --pasky */enum search_option {	SEARCH_OPT_REGEX,	SEARCH_OPT_CASE,	SEARCH_OPTIONS,};static struct option_resolver resolvers[] = {	{ SEARCH_OPT_REGEX,	"document.browse.search.regex" },	{ SEARCH_OPT_CASE,	"document.browse.search.case" },};struct search_dlg_hop {	void *data;	union option_value values[SEARCH_OPTIONS];};static t_handler_event_statussearch_dlg_cancel(struct dialog_data *dlg_data, struct widget_data *widget_data){	void (*fn)(void *) = widget_data->widget->data;	struct search_dlg_hop *hop = dlg_data->dlg->udata2;	void *data = hop->data;	if (fn) fn(data);	return cancel_dialog(dlg_data, widget_data);}static t_handler_event_statussearch_dlg_ok(struct dialog_data *dlg_data, struct widget_data *widget_data){	void (*fn)(void *, unsigned char *) = widget_data->widget->data;	struct search_dlg_hop *hop = dlg_data->dlg->udata2;	void *data = hop->data;	unsigned char *text = dlg_data->widgets_data->cdata;	update_dialog_data(dlg_data);	commit_option_values(resolvers, config_options,			     hop->values, SEARCH_OPTIONS);	if (check_dialog(dlg_data)) return EVENT_NOT_PROCESSED;	add_to_input_history(dlg_data->dlg->widgets->info.field.history, text, 1);	if (fn) fn(data, text);	return cancel_dialog(dlg_data, widget_data);}/* XXX: @data is ignored. */static voidsearch_dlg_do(struct terminal *term, struct memory_list *ml,	      unsigned char *title, void *data,	      struct input_history *history,	      void (*fn)(void *, unsigned char *)){	struct dialog *dlg;	unsigned char *field;	struct search_dlg_hop *hop;	unsigned char *text = _("Search for text", term);	hop = mem_calloc(1, sizeof(*hop));	if (!hop) return;	checkout_option_values(resolvers, config_options,			       hop->values, SEARCH_OPTIONS);	hop->data = data;#define SEARCH_WIDGETS_COUNT 8	dlg = calloc_dialog(SEARCH_WIDGETS_COUNT, MAX_STR_LEN);	if (!dlg) {		mem_free(hop);		return;	}	dlg->title = _(title, term);	dlg->layouter = generic_dialog_layouter;	dlg->layout.fit_datalen = 1;	dlg->layout.float_groups = 1;	dlg->udata = text;	dlg->udata2 = hop;	add_to_ml(&ml, hop, NULL);	/* @field is automatically cleared by calloc() */	field = get_dialog_offset(dlg, SEARCH_WIDGETS_COUNT);	add_dlg_field(dlg, text, 0, 0, NULL, MAX_STR_LEN, field, history);	add_dlg_radio(dlg, _("Normal search", term), 1, 0, hop->values[SEARCH_OPT_REGEX].number);	add_dlg_radio(dlg, _("Regexp search", term), 1, 1, hop->values[SEARCH_OPT_REGEX].number);	add_dlg_radio(dlg, _("Extended regexp search", term), 1, 2, hop->values[SEARCH_OPT_REGEX].number);	add_dlg_radio(dlg, _("Case sensitive", term), 2, 1, hop->values[SEARCH_OPT_CASE].number);	add_dlg_radio(dlg, _("Case insensitive", term), 2, 0, hop->values[SEARCH_OPT_CASE].number);	add_dlg_button(dlg, _("~OK", term), B_ENTER, search_dlg_ok, fn);	add_dlg_button(dlg, _("~Cancel", term), B_ESC, search_dlg_cancel, NULL);	add_dlg_end(dlg, SEARCH_WIDGETS_COUNT);	add_to_ml(&ml, dlg, NULL);	do_dialog(term, dlg, ml);}enum frame_event_statussearch_dlg(struct session *ses, struct document_view *doc_view, int direction){	unsigned char *title;	void *search_function;	assert(direction);	if_assert_failed return FRAME_EVENT_OK;	if (direction > 0) {		title = N_("Search");		search_function = search_for;	} else {		title = N_("Search backward");		search_function = search_for_back;	}	search_dlg_do(ses->tab->term, NULL,		      title, ses,		      &search_history,		      search_function);	return FRAME_EVENT_OK;}static enum evhook_statussearch_history_write_hook(va_list ap, void *data){	save_input_history(&search_history, SEARCH_HISTORY_FILENAME);	return EVENT_HOOK_STATUS_NEXT;}struct event_hook_info search_history_hooks[] = {	{ "periodic-saving", search_history_write_hook, NULL },	NULL_EVENT_HOOK_INFO,};voidinit_search_history(void){	load_input_history(&search_history, SEARCH_HISTORY_FILENAME);	register_event_hooks(search_history_hooks);}voiddone_search_history(void){	unregister_event_hooks(search_history_hooks);	save_input_history(&search_history, SEARCH_HISTORY_FILENAME);	free_list(search_history.entries);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -