2 * Copyright (c) 2021, 2024 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
36 #include "minibuffer.h"
38 #include "telescope.h"
43 #define GUARD_RECURSIVE_MINIBUFFER() \
45 if (in_minibuffer) { \
46 message("enable-recursive-minibuffers " \
47 "is not yet available."); \
52 #define GUARD_READ_ONLY() \
54 if (!in_minibuffer) { \
55 message("text is read-only"); \
60 /* return 1 if moved, 0 otherwise */
62 forward_line(struct buffer *buffer, int n)
67 int did, target, col = 0; /* XXX breaks with tabs! */
69 if (buffer->current_line == NULL)
71 vl = buffer->current_line;
73 text = vl->parent->line + vl->from;
74 left = MIN(vl->len, buffer->point_offset);
75 target = utf8_snwidth(text, left, 0); /* XXX breaks with tabs! */
80 vl = TAILQ_NEXT(vl, vlines);
83 if (vl->parent->flags & L_HIDDEN)
85 buffer->current_line = vl;
88 vl = TAILQ_PREV(vl, vhead, vlines);
91 if (vl->parent->flags & L_HIDDEN)
93 if (buffer->current_line == buffer->top_line) {
95 buffer->top_line = vl;
97 buffer->current_line = vl;
104 /* keep the cursor in the same column */
106 vl = buffer->current_line;
107 text = vl->parent->line + vl->from;
109 buffer->point_offset = 0;
110 while (left > 0 && col < target) {
111 off = grapheme_next_character_break_utf8(text, left);
112 col += utf8_snwidth(text, off, col);
115 buffer->point_offset += off;
123 cmd_previous_line(struct buffer *buffer)
125 forward_line(buffer, -1);
129 cmd_next_line(struct buffer *buffer)
131 forward_line(buffer, +1);
135 cmd_backward_char(struct buffer *buffer)
139 size_t left, off, point = 0;
141 if ((vl = buffer->current_line) == NULL)
144 text = vl->parent->line + vl->from;
148 off = grapheme_next_character_break_utf8(text, left);
149 if (point + off >= buffer->point_offset)
156 buffer->point_offset = point;
160 cmd_forward_char(struct buffer *buffer)
166 if ((vl = buffer->current_line) == NULL)
169 text = vl->parent->line + vl->from;
172 text += buffer->point_offset;
173 left -= buffer->point_offset;
175 off = grapheme_next_character_break_utf8(text, left);
176 buffer->point_offset += off;
180 cmd_backward_paragraph(struct buffer *buffer)
183 if (!forward_line(buffer, -1)) {
184 message("No previous paragraph");
187 } while (buffer->current_line->len != 0 ||
188 buffer->current_line->parent->type != LINE_TEXT);
192 cmd_forward_paragraph(struct buffer *buffer)
195 if (!forward_line(buffer, +1)) {
196 message("No next paragraph");
199 } while (buffer->current_line->len != 0 ||
200 buffer->current_line->parent->type != LINE_TEXT);
204 cmd_move_beginning_of_line(struct buffer *buffer)
206 buffer->point_offset = 0;
210 cmd_move_end_of_line(struct buffer *buffer)
214 vl = buffer->current_line;
217 buffer->point_offset = vl->len;
221 cmd_redraw(struct buffer *buffer)
223 ui_schedule_redraw();
227 cmd_scroll_line_up(struct buffer *buffer)
232 if (buffer->top_line == NULL)
235 if ((vl = TAILQ_PREV(buffer->top_line, vhead, vlines))
239 buffer->top_line = vl;
241 if (vl->parent->flags & L_HIDDEN)
249 forward_line(buffer, -1);
253 cmd_scroll_line_down(struct buffer *buffer)
255 if (!forward_line(buffer, +1))
259 if (buffer->top_line == NULL)
262 buffer->top_line = TAILQ_NEXT(buffer->top_line, vlines);
263 if (buffer->top_line->parent->flags & L_HIDDEN)
272 cmd_scroll_up(struct buffer *buffer)
277 if (buffer->top_line == NULL)
280 for (i = 0; i < body_lines; ++i) {
281 vl = TAILQ_PREV(buffer->top_line, vhead, vlines);
285 buffer->top_line = vl;
286 forward_line(buffer, -1);
291 cmd_scroll_down(struct buffer *buffer)
295 if (buffer->top_line == NULL)
298 for (i = 0; i < body_lines; ++i) {
299 if (!forward_line(buffer, +1))
302 buffer->top_line = TAILQ_NEXT(buffer->top_line,
309 cmd_beginning_of_buffer(struct buffer *buffer)
311 buffer->current_line = TAILQ_FIRST(&buffer->vhead);
312 buffer->point_offset = 0;
313 buffer->top_line = buffer->current_line;
314 buffer->line_off = 0;
318 cmd_end_of_buffer(struct buffer *buffer)
320 buffer->current_line = TAILQ_LAST(&buffer->vhead, vhead);
322 if (buffer->current_line == NULL)
325 /* deal with invisible lines */
326 if (buffer->current_line->parent->flags & L_HIDDEN)
327 forward_line(buffer, -1);
329 cmd_move_end_of_line(buffer);
333 kill_telescope_cb(int r, void *data)
342 cmd_kill_telescope(struct buffer *buffer)
344 yornp("really quit?", kill_telescope_cb, NULL);
348 cmd_push_button(struct buffer *buffer)
353 vl = buffer->current_line;
358 switch (vl->parent->type) {
360 load_url_in_tab(current_tab, vl->parent->alt, NULL,
364 l = TAILQ_NEXT(vl->parent, lines);
365 for (; l != NULL; l = TAILQ_NEXT(l, lines)) {
366 if (l->type == LINE_PRE_END)
368 l->flags ^= L_HIDDEN;
369 if (l->flags & L_HIDDEN)
381 cmd_push_button_new_tab(struct buffer *buffer)
385 vl = buffer->current_line;
386 if (vl == NULL || vl->parent->type != LINE_LINK)
389 new_tab(vl->parent->alt, hist_cur(current_tab->hist), current_tab);
393 cmd_previous_button(struct buffer *buffer)
395 struct excursion place;
397 save_excursion(&place, buffer);
400 if (!forward_line(buffer, -1)) {
401 restore_excursion(&place, buffer);
402 message("No previous link");
405 } while (buffer->current_line->parent->type != LINE_LINK);
409 cmd_next_button(struct buffer *buffer)
411 struct excursion place;
413 save_excursion(&place, buffer);
416 if (!forward_line(buffer, +1)){
417 restore_excursion(&place, buffer);
418 message("No next link");
421 } while (buffer->current_line->parent->type != LINE_LINK);
425 is_heading(const struct line *l)
427 return l->type == LINE_TITLE_1 ||
428 l->type == LINE_TITLE_2 ||
429 l->type == LINE_TITLE_3;
433 cmd_previous_heading(struct buffer *buffer)
435 struct excursion place;
437 save_excursion(&place, buffer);
440 if (!forward_line(buffer, -1)) {
441 restore_excursion(&place, buffer);
442 message("No previous heading");
445 } while (!is_heading(buffer->current_line->parent));
449 cmd_next_heading(struct buffer *buffer)
451 struct excursion place;
453 save_excursion(&place, buffer);
456 if (!forward_line(buffer, +1)) {
457 restore_excursion(&place, buffer);
458 message("No next heading");
461 } while (!is_heading(buffer->current_line->parent));
465 cmd_previous_page(struct buffer *buffer)
467 if (!load_previous_page(current_tab))
468 message("No previous page");
472 cmd_next_page(struct buffer *buffer)
474 if (!load_next_page(current_tab))
475 message("No next page");
479 cmd_clear_minibuf(struct buffer *buffer)
485 cmd_execute_extended_command(struct buffer *buffer)
487 struct minibuffer m = {
488 .self_insert = sensible_self_insert,
489 .done = eecmd_select,
490 .history = eecmd_history,
491 .complfn = compl_eecmd,
495 GUARD_RECURSIVE_MINIBUFFER();
497 enter_minibuffer(&m, "%s%s%s", thiskey.meta ? "M-" : "",
498 ui_keyname(thiskey.key), thiskey.meta ? " " : "");
502 cmd_tab_close(struct buffer *buffer)
508 if ((t = TAILQ_NEXT(tab, tabs)) != NULL ||
509 (t = TAILQ_PREV(tab, tabshead, tabs)) != NULL) {
513 message("Can't close the only tab.");
518 cmd_tab_close_other(struct buffer *buffer)
522 TAILQ_FOREACH_SAFE(t, &tabshead, tabs, i) {
523 if (t == current_tab)
531 cmd_tab_undo_close(struct buffer *buffer)
535 if ((t = unkill_tab()) == NULL) {
536 message("No recently-closed tabs");
544 cmd_tab_new(struct buffer *buffer)
548 if ((url = new_tab_url) == NULL)
551 new_tab(url, NULL, NULL);
555 cmd_tab_next(struct buffer *buffer)
559 if ((t = TAILQ_NEXT(current_tab, tabs)) == NULL)
560 t = TAILQ_FIRST(&tabshead);
565 cmd_tab_previous(struct buffer *buffer)
569 if ((t = TAILQ_PREV(current_tab, tabshead, tabs)) == NULL)
570 t = TAILQ_LAST(&tabshead, tabshead);
575 cmd_tab_move(struct buffer *buffer)
579 t = TAILQ_NEXT(current_tab, tabs);
580 TAILQ_REMOVE(&tabshead, current_tab, tabs);
583 TAILQ_INSERT_HEAD(&tabshead, current_tab, tabs);
585 TAILQ_INSERT_AFTER(&tabshead, t, current_tab, tabs);
589 cmd_tab_move_to(struct buffer *buffer)
593 t = TAILQ_PREV(current_tab, tabshead, tabs);
594 TAILQ_REMOVE(&tabshead, current_tab, tabs);
597 TAILQ_INSERT_TAIL(&tabshead, current_tab, tabs);
599 TAILQ_INSERT_BEFORE(t, current_tab, tabs);
603 cmd_tab_select(struct buffer *buffer)
605 struct minibuffer m = {
606 .self_insert = sensible_self_insert,
612 GUARD_RECURSIVE_MINIBUFFER();
614 enter_minibuffer(&m, "Select tab: ");
618 cmd_load_url(struct buffer *buffer)
620 struct minibuffer m = {
621 .self_insert = sensible_self_insert,
623 .history = lu_history,
627 GUARD_RECURSIVE_MINIBUFFER();
629 enter_minibuffer(&m, "Load URL: ");
633 cmd_load_current_url(struct buffer *buffer)
635 struct minibuffer m = {
636 .self_insert = sensible_self_insert,
638 .history = lu_history,
640 .input = hist_cur(current_tab->hist),
643 GUARD_RECURSIVE_MINIBUFFER();
645 enter_minibuffer(&m, "Load URL: ");
649 cmd_reload_page(struct buffer *buffer)
651 load_url_in_tab(current_tab, hist_cur(current_tab->hist), NULL,
652 LU_MODE_NOHIST|LU_MODE_NOCACHE);
656 cmd_bookmark_page(struct buffer *buffer)
658 struct minibuffer m = {
659 .self_insert = sensible_self_insert,
661 .input = hist_cur(current_tab->hist),
664 GUARD_RECURSIVE_MINIBUFFER();
666 enter_minibuffer(&m, "Bookmark URL: ");
670 cmd_list_bookmarks(struct buffer *buffer)
672 load_url_in_tab(current_tab, "about:bookmarks", NULL, LU_MODE_NONE);
676 cmd_toggle_help(struct buffer *buffer)
678 ui_toggle_side_window(SIDE_WINDOW_LEFT);
682 cmd_link_select(struct buffer *buffer)
685 struct minibuffer m = {
686 .self_insert = sensible_self_insert,
693 GUARD_RECURSIVE_MINIBUFFER();
695 l = TAILQ_FIRST(&buffer->head);
696 while (l != NULL && l->type != LINE_LINK)
697 l = TAILQ_NEXT(l, lines);
700 message("No links found");
705 enter_minibuffer(&m, "Select link: ");
709 cmd_swiper(struct buffer *buffer)
711 struct minibuffer m = {
712 .self_insert = sensible_self_insert,
713 .done = swiper_select,
714 .complfn = compl_swiper,
715 .compldata = TAILQ_FIRST(&buffer->head),
719 GUARD_RECURSIVE_MINIBUFFER();
721 enter_minibuffer(&m, "Select line: ");
725 cmd_toc(struct buffer *buffer)
728 struct minibuffer m = {
729 .self_insert = sensible_self_insert,
731 .complfn = compl_toc,
736 GUARD_RECURSIVE_MINIBUFFER();
738 l = TAILQ_FIRST(&buffer->head);
740 l->type != LINE_TITLE_1 &&
741 l->type != LINE_TITLE_2 &&
742 l->type != LINE_TITLE_3)
743 l = TAILQ_NEXT(l, lines);
746 message("No headings found");
751 enter_minibuffer(&m, "Select heading: ");
755 cmd_inc_fill_column(struct buffer *buffer)
757 if (fill_column == INT_MAX)
761 message("fill-column: %d", fill_column);
763 ui_schedule_redraw();
767 cmd_dec_fill_column(struct buffer *buffer)
769 if (fill_column == INT_MAX || fill_column < 8)
773 message("fill-column: %d", fill_column);
775 ui_schedule_redraw();
779 cmd_olivetti_mode(struct buffer *buffer)
781 olivetti_mode = !olivetti_mode;
783 message("olivetti-mode enabled");
785 message("olivetti-mode disabled");
787 ui_schedule_redraw();
791 cmd_mini_delete_char(struct buffer *buffer)
795 size_t old_point, gap, rest;
799 vl = buffer->current_line;
800 old_point = buffer->point_offset;
801 cmd_forward_char(buffer);
802 gap = buffer->point_offset - old_point;
806 minibuffer_taint_hist();
808 text = vl->parent->line + vl->from + old_point;
809 rest = vl->len - buffer->point_offset;
810 memmove(text, text + gap, rest + 1);
811 buffer->point_offset = old_point;
814 recompute_completions(0);
818 cmd_mini_delete_backward_char(struct buffer *buffer)
822 size_t old_point, gap, rest;
826 vl = buffer->current_line;
827 old_point = buffer->point_offset;
828 cmd_backward_char(buffer);
829 gap = old_point - buffer->point_offset;
833 minibuffer_taint_hist();
835 text = vl->parent->line + vl->from + buffer->point_offset;
836 rest = vl->len - old_point;
837 memmove(text, text + gap, rest + 1);
840 recompute_completions(0);
844 cmd_mini_kill_line(struct buffer *buffer)
850 minibuffer_taint_hist();
852 line = buffer->current_line->parent->line + buffer->current_line->from;
853 c = line + buffer->point_offset;
856 recompute_completions(0);
860 cmd_mini_kill_whole_line(struct buffer *buffer)
864 minibuffer_taint_hist();
865 *buffer->current_line->parent->line = '\0';
866 buffer->point_offset = 0;
867 buffer->current_line->len = 0;
869 recompute_completions(0);
873 cmd_mini_abort(struct buffer *buffer)
882 cmd_mini_complete_and_exit(struct buffer *buffer)
889 if (ministate.compl.must_select && ministate.hist == NULL) {
890 vl = ministate.compl.buffer.current_line;
891 if (vl == NULL || vl->parent->flags & L_HIDDEN ||
892 vl->parent->type == LINE_COMPL) {
898 minibuffer_confirm();
902 cmd_mini_previous_history_element(struct buffer *buffer)
906 if (ministate.hist == NULL) {
907 message("No history");
911 if (hist_prev(ministate.hist) == NULL) {
912 message("No prev history item");
916 ministate.editing = 0;
918 /* XXX the minibuffer line is never modified so this is fine */
919 text = (char *)hist_cur(ministate.hist);
920 buffer->current_line->parent->line = text;
921 recompute_completions(0);
925 cmd_mini_next_history_element(struct buffer *buffer)
929 if (ministate.hist == NULL) {
930 message("No history");
934 if (hist_next(ministate.hist) == NULL) {
935 message("No next history item");
939 ministate.editing = 0;
941 /* XXX the minibuffer line is never modified so this is fine */
942 text = (char *)hist_cur(ministate.hist);
943 buffer->current_line->parent->line = text;
944 recompute_completions(0);
948 cmd_previous_completion(struct buffer *buffer)
950 if (in_minibuffer != MB_COMPREAD)
953 buffer = &ministate.compl.buffer;
954 if (buffer->current_line == NULL)
957 buffer->current_line->parent->type = LINE_COMPL;
958 if (!forward_line(buffer, -1))
959 buffer->current_line->parent->type = LINE_COMPL;
961 buffer->current_line->parent->type = LINE_COMPL_CURRENT;
965 cmd_next_completion(struct buffer *buffer)
967 if (in_minibuffer != MB_COMPREAD)
970 buffer = &ministate.compl.buffer;
971 if (buffer->current_line == NULL)
974 if (buffer->current_line->parent->type == LINE_COMPL_CURRENT) {
975 buffer->current_line->parent->type = LINE_COMPL;
976 forward_line(buffer, +1);
979 if (buffer->current_line != NULL)
980 buffer->current_line->parent->type = LINE_COMPL_CURRENT;
984 cmd_insert_current_candidate(struct buffer *buffer)
986 if (in_minibuffer != MB_COMPREAD)
989 minibuffer_insert_current_candidate();
993 cmd_suspend_telescope(struct buffer *buffer)
997 kill(getpid(), SIGSTOP);
1002 cmd_toggle_pre_wrap(struct buffer *buffer)
1004 dont_wrap_pre = !dont_wrap_pre;
1007 message("Don't wrap preformatted blocks");
1009 message("Wrap preformatted blocks");
1011 ui_schedule_redraw();
1015 cmd_toggle_styling(struct buffer *buffer)
1017 dont_apply_styling = !dont_apply_styling;
1019 config_apply_style();
1021 /* Force a reload here, rather than calling ui_schedule_redraw() so
1022 * that any lines which are set as L_HIDDEN are redrawn appropriately.
1024 load_url_in_tab(current_tab, hist_cur(current_tab->hist), NULL,
1029 cmd_mini_goto_beginning(struct buffer *buffer)
1036 buffer = &ministate.compl.buffer;
1038 if ((vl = buffer->current_line) != NULL)
1039 vl->parent->type = LINE_COMPL;
1041 vl = TAILQ_FIRST(&buffer->vhead);
1042 while (vl != NULL && vl->parent->flags & L_HIDDEN)
1043 vl = TAILQ_NEXT(vl, vlines);
1048 vl->parent->type = LINE_COMPL_CURRENT;
1049 buffer->top_line = vl;
1050 buffer->current_line = vl;
1054 cmd_mini_goto_end(struct buffer *buffer)
1061 buffer = &ministate.compl.buffer;
1063 if ((vl = buffer->current_line) != NULL)
1064 vl->parent->type = LINE_COMPL;
1066 vl = TAILQ_LAST(&buffer->vhead, vhead);
1067 while (vl != NULL && vl->parent->flags & L_HIDDEN)
1068 vl = TAILQ_PREV(vl, vhead, vlines);
1073 vl->parent->type = LINE_COMPL_CURRENT;
1074 buffer->current_line = vl;
1078 cmd_other_window(struct buffer *buffer)
1084 cmd_mini_scroll_up(struct buffer *buffer)
1089 buffer = &ministate.compl.buffer;
1090 if (buffer->current_line == NULL)
1093 buffer->current_line->parent->type = LINE_COMPL;
1094 cmd_scroll_up(buffer);
1095 buffer->current_line->parent->type = LINE_COMPL_CURRENT;
1099 cmd_mini_scroll_down(struct buffer *buffer)
1104 buffer = &ministate.compl.buffer;
1105 if (buffer->current_line == NULL)
1108 buffer->current_line->parent->type = LINE_COMPL;
1109 cmd_scroll_down(buffer);
1110 buffer->current_line->parent->type = LINE_COMPL_CURRENT;
1114 cmd_toggle_downloads(struct buffer *buffer)
1116 ui_toggle_side_window(SIDE_WINDOW_BOTTOM);
1120 cmd_cache_info(struct buffer *buffer)
1123 char fmt[FMT_SCALED_STRSIZE];
1125 mcache_info(&npages, &tot);
1127 if (fmt_scaled(tot, fmt) == 0)
1128 message("pages: %zu, total: %s", npages, fmt);
1130 message("pages: %zu, total: %zu", npages, tot);
1134 cmd_reply_last_input(struct buffer *buffer)
1136 GUARD_RECURSIVE_MINIBUFFER();
1138 if (current_tab->last_input_url == NULL) {
1139 message("there was no previous input request in this tab");
1143 if (!strncmp(current_tab->last_input_url, "gopher", 6)) {
1144 load_url_in_tab(current_tab, current_tab->last_input_url,
1145 NULL, LU_MODE_NOCACHE);
1149 message("%s", current_tab->last_input_url);
1150 ui_require_input(current_tab, 0, ir_select_reply);
1154 cmd_write_buffer(struct buffer *buffer)
1156 const char *f, *url;
1157 char path[PATH_MAX];
1159 GUARD_RECURSIVE_MINIBUFFER();
1162 message("Can't write buffer in safe-mode.");
1166 url = hist_cur(current_tab->hist);
1168 if ((f = strrchr(url, '/')) != NULL)
1170 if (f == NULL || *f == '\0') {
1171 /* guess a decent file name based on the protocol used */
1172 if (!strncmp(url, "gemini://", 9))
1178 strlcpy(path, download_path, sizeof(path));
1179 strlcat(path, f, sizeof(path));
1181 ui_read("Write file", write_buffer, current_tab, path);
1185 cmd_home(struct buffer *buffer)
1187 char path[GEMINI_URL_LEN];
1190 strlcpy(path, current_tab->iri.iri_path, sizeof(path));
1192 if ((tilde = strstr(path, "/~")) != NULL &&
1193 tilde[2] != '\0' && tilde[2] != '/') {
1194 if ((t = strchr(tilde + 2, '/')) != NULL)
1196 load_url_in_tab(current_tab, path, NULL, LU_MODE_NOCACHE);
1202 cmd_root(struct buffer *buffer)
1204 load_url_in_tab(current_tab, "/", NULL, LU_MODE_NOCACHE);
1208 cmd_up(struct buffer *buffer)
1210 load_url_in_tab(current_tab, "..", NULL, LU_MODE_NOCACHE);
1214 cmd_use_certificate(struct buffer *buffer)
1216 struct minibuffer m = {
1217 .self_insert = sensible_self_insert,
1219 .complfn = compl_uc,
1223 GUARD_RECURSIVE_MINIBUFFER();
1225 enter_minibuffer(&m, "Select certificate: ");
1229 cmd_client_certificate_info(struct buffer *buffer)
1231 if (current_tab->client_cert)
1232 message("Using certificate %s", current_tab->client_cert);
1234 message("Not using any client certificate.");
1238 unload_certificate_cb(int r, void *data)
1240 struct tab *tab = data;
1242 message("Won't use %s for this site.", tab->client_cert);
1243 cert_delete_for(tab->client_cert, &tab->iri, r);
1247 cmd_unload_certificate(struct buffer *buffer)
1249 struct tab *tab = current_tab;
1251 GUARD_RECURSIVE_MINIBUFFER();
1253 if (tab->client_cert == NULL) {
1254 message("No client certificate in use!");
1258 if (tab->client_cert_temp) {
1259 message("Won't use %s for this site.", tab->client_cert);
1260 cert_delete_for(tab->client_cert, &tab->iri, 0);
1264 yornp("Unload only for the current session?", unload_certificate_cb,
1269 cmd_search(struct buffer *buffer)
1271 struct minibuffer m = {
1272 .self_insert = sensible_self_insert,
1273 .done = search_select,
1276 GUARD_RECURSIVE_MINIBUFFER();
1278 if (!strncmp(default_search_engine, "gopher://", 9)) {
1279 load_url_in_tab(current_tab, default_search_engine, NULL,
1284 enter_minibuffer(&m, "Search: ");
1288 cmd_mini_edit_external(struct buffer *buffer)
1296 if (ministate.compl.must_select || ministate.donefn == NULL) {
1297 message("Can't use an external editor to complete");
1301 if ((fp = exec_editor(ministate.buf, strlen(ministate.buf))) == NULL)
1304 while (len < sizeof(buf) - 1) {
1305 r = fread(buf + len, 1, sizeof(buf) - 1 - len, fp);
1311 while (len > 0 && buf[len-1] == '\n')
1315 * XXX: do not use minibuffer_confirm() since the text could
1316 * have multiple lines and we are not prepared to render them
1317 * in the history navigation.
1319 ministate.donefn(buf);