Add :save-options prompt command
[tig.git] / src / prompt.c
blob652e51c140a4740b829bc6992c2b91d46636dbef
1 /* Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include "tig/tig.h"
15 #include "tig/view.h"
16 #include "tig/draw.h"
17 #include "tig/display.h"
18 #include "tig/options.h"
19 #include "tig/prompt.h"
20 #include "tig/pager.h"
21 #include "tig/types.h"
23 #ifdef HAVE_READLINE
24 #include <readline/readline.h>
25 #include <readline/history.h>
26 #endif /* HAVE_READLINE */
28 static char *
29 prompt_input(const char *prompt, struct input *input)
31 enum input_status status = INPUT_OK;
32 unsigned char chars_length[SIZEOF_STR];
33 struct key key;
34 size_t promptlen = strlen(prompt);
35 int pos = 0, chars = 0;
37 input->buf[pos] = 0;
39 while (status == INPUT_OK || status == INPUT_SKIP) {
41 update_status("%s%.*s", prompt, pos, input->buf);
43 if (get_input(pos + promptlen, &key, FALSE) == OK) {
44 int len = strlen(key.data.bytes);
46 if (pos + len >= sizeof(input->buf)) {
47 report("Input string too long");
48 return NULL;
51 string_ncopy_do(input->buf + pos, sizeof(input->buf) - pos, key.data.bytes, len);
52 pos += len;
53 chars_length[chars++] = len;
54 status = input->handler(input, &key);
55 if (status != INPUT_OK) {
56 pos -= len;
57 chars--;
58 } else {
59 int changed_pos = strlen(input->buf);
61 if (changed_pos != pos) {
62 pos = changed_pos;
63 chars_length[chars - 1] = changed_pos - (pos - len);
66 } else {
67 status = input->handler(input, &key);
68 if (status == INPUT_DELETE) {
69 int len = chars_length[--chars];
71 pos -= len;
72 status = INPUT_OK;
73 } else {
74 int changed_pos = strlen(input->buf);
76 if (changed_pos != pos) {
77 pos = changed_pos;
78 chars_length[chars++] = changed_pos - pos;
82 input->buf[pos] = 0;
85 report_clear();
87 if (status == INPUT_CANCEL)
88 return NULL;
90 input->buf[pos++] = 0;
92 return input->buf;
95 static enum input_status
96 prompt_default_handler(struct input *input, struct key *key)
98 if (key->modifiers.multibytes)
99 return INPUT_SKIP;
101 switch (key->data.value) {
102 case KEY_RETURN:
103 case KEY_ENTER:
104 case '\n':
105 return *input->buf ? INPUT_STOP : INPUT_CANCEL;
107 case KEY_BACKSPACE:
108 return *input->buf ? INPUT_DELETE : INPUT_CANCEL;
110 case KEY_ESC:
111 return INPUT_CANCEL;
113 default:
114 return INPUT_SKIP;
118 static enum input_status
119 prompt_yesno_handler(struct input *input, struct key *key)
121 unsigned long c = key_to_unicode(key);
123 if (c == 'y' || c == 'Y')
124 return INPUT_STOP;
125 if (c == 'n' || c == 'N')
126 return INPUT_CANCEL;
127 return prompt_default_handler(input, key);
130 bool
131 prompt_yesno(const char *prompt)
133 char prompt2[SIZEOF_STR];
134 struct input input = { prompt_yesno_handler, NULL };
136 if (!string_format(prompt2, "%s [Yy/Nn]", prompt))
137 return FALSE;
139 return !!prompt_input(prompt2, &input);
142 struct incremental_input {
143 struct input input;
144 input_handler handler;
145 bool edit_mode;
148 static enum input_status
149 read_prompt_handler(struct input *input, struct key *key)
151 struct incremental_input *incremental = (struct incremental_input *) input;
153 if (incremental->edit_mode && !key->modifiers.multibytes)
154 return prompt_default_handler(input, key);
156 if (!unicode_width(key_to_unicode(key), 8))
157 return INPUT_SKIP;
159 if (!incremental->handler)
160 return INPUT_OK;
162 return incremental->handler(input, key);
165 char *
166 read_prompt_incremental(const char *prompt, bool edit_mode, input_handler handler, void *data)
168 static struct incremental_input incremental = { { read_prompt_handler } };
170 incremental.input.data = data;
171 incremental.handler = handler;
172 incremental.edit_mode = edit_mode;
174 return prompt_input(prompt, (struct input *) &incremental);
177 #ifdef HAVE_READLINE
178 static void
179 readline_display(void)
181 update_status("%s%s", rl_display_prompt, rl_line_buffer);
182 wrefresh(status_win);
185 static char *
186 readline_variable_generator(const char *text, int state)
188 static const char *vars[] = {
189 #define FORMAT_VAR(type, name, ifempty, initval) "%(" #name ")",
190 ARGV_ENV_INFO(FORMAT_VAR)
191 #undef FORMAT_VAR
192 NULL
195 static int index, len;
196 const char *name;
197 char *variable = NULL; /* No match */
199 /* If it is a new word to complete, initialize */
200 if (!state) {
201 index = 0;
202 len = strlen(text);
205 /* Return the next name which partially matches */
206 while ((name = vars[index])) {
207 index++;
209 /* Complete or format a variable */
210 if (strncmp(name, text, len) == 0) {
211 if (strlen(name) > len)
212 variable = strdup(name);
213 else
214 variable = argv_format_arg(&argv_env, text);
215 break;
219 return variable;
222 static char *
223 readline_action_generator(const char *text, int state)
225 static const char *actions[] = {
226 "!",
227 "source",
228 "color",
229 "bind",
230 "set",
231 "toggle",
232 "save-display",
233 "save-options",
234 "exec",
235 #define REQ_GROUP(help)
236 #define REQ_(req, help) #req
237 REQ_INFO,
238 #undef REQ_GROUP
239 #undef REQ_
240 NULL
243 static int index, len;
244 const char *name;
245 char *match = NULL; /* No match */
247 /* If it is a new word to complete, initialize */
248 if (!state) {
249 index = 0;
250 len = strlen(text);
253 /* Return the next name which partially matches */
254 while ((name = actions[index])) {
255 name = enum_name(name);
256 index++;
258 if (strncmp(name, text, len) == 0) {
259 /* Ignore exact completion */
260 if (strlen(name) > len)
261 match = strdup(name);
262 break;
266 return match;
269 static char *
270 readline_set_generator(const char *text, int state)
272 static const char *words[] = {
273 #define DEFINE_OPTION_NAME(name, type, flags) #name " = ",
274 OPTION_INFO(DEFINE_OPTION_NAME)
275 #undef DEFINE_OPTION_NAME
276 NULL
279 static int index, len;
280 const char *name;
281 char *match = NULL; /* No match */
283 /* If it is a new word to complete, initialize */
284 if (!state) {
285 index = 0;
286 len = strlen(text);
289 /* Return the next name which partially matches */
290 while ((name = words[index])) {
291 name = enum_name(name);
292 index++;
294 if (strncmp(name, text, len) == 0) {
295 /* Ignore exact completion */
296 if (strlen(name) > len)
297 match = strdup(name);
298 break;
302 return match;
305 static char *
306 readline_toggle_generator(const char *text, int state)
308 static const char **words;
309 static int index, len;
310 const char *name;
311 char *match = NULL; /* No match */
313 if (!words) {
314 /* TODO: Only complete column options that are defined
315 * for the view. */
317 #define DEFINE_OPTION_WORD(name, type, flags) argv_append(&words, #name);
318 #define DEFINE_COLUMN_OPTIONS_WORD(name, type, flags) #name,
319 #define DEFINE_COLUMN_OPTIONS_WORDS(name, id, options) \
320 if (VIEW_COLUMN_##id != VIEW_COLUMN_SECTION) { \
321 const char *vars[] = { \
322 options(DEFINE_COLUMN_OPTIONS_WORD) \
323 }; \
324 char buf[SIZEOF_STR]; \
325 int i; \
326 for (i = 0; i < ARRAY_SIZE(vars); i++) { \
327 if (enum_name_prefixed(buf, sizeof(buf), #name, vars[i])) \
328 argv_append(&words, buf); \
332 OPTION_INFO(DEFINE_OPTION_WORD)
333 COLUMN_OPTIONS(DEFINE_COLUMN_OPTIONS_WORDS);
336 /* If it is a new word to complete, initialize */
337 if (!state) {
338 index = 0;
339 len = strlen(text);
342 /* Return the next name which partially matches */
343 while ((name = words[index])) {
344 name = enum_name(name);
345 index++;
347 if (strncmp(name, text, len) == 0) {
348 /* Ignore exact completion */
349 if (strlen(name) > len)
350 match = strdup(name);
351 break;
355 return match;
358 static int
359 readline_getc(FILE *stream)
361 return get_input_char();
364 static char **
365 readline_completion(const char *text, int start, int end)
367 /* Do not append a space after a completion */
368 rl_completion_suppress_append = 1;
371 * If the word is at the start of the line,
372 * then it is a tig action to complete.
374 if (start == 0)
375 return rl_completion_matches(text, readline_action_generator);
378 * If the line begins with "toggle", then we complete toggle options.
380 if (start >= 7 && strncmp(rl_line_buffer, "toggle ", 7) == 0)
381 return rl_completion_matches(text, readline_toggle_generator);
384 * If the line begins with "set", then we complete set options.
385 * (unless it is already completed)
387 if (start >= 4 && strncmp(rl_line_buffer, "set ", 4) == 0 &&
388 !strchr(rl_line_buffer, '='))
389 return rl_completion_matches(text, readline_set_generator);
392 * Otherwise it might be a variable name...
394 if (strncmp(text, "%(", 2) == 0)
395 return rl_completion_matches(text, readline_variable_generator);
398 * ... or finally fall back to filename completion.
400 return NULL;
403 static void
404 readline_display_matches(char **matches, int num_matches, int max_length)
406 unsigned int i;
408 wmove(status_win, 0, 0);
409 waddstr(status_win, "matches: ");
411 /* matches[0] is the incomplete word */
412 for (i = 1; i < num_matches + 1; ++i) {
413 waddstr(status_win, matches[i]);
414 waddch(status_win, ' ');
417 wgetch(status_win);
418 wrefresh(status_win);
421 static void
422 readline_init(void)
424 /* Allow conditional parsing of the ~/.inputrc file. */
425 rl_readline_name = "tig";
427 /* Word break caracters (we removed '(' to match variables) */
428 rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{";
430 /* Custom display function */
431 rl_redisplay_function = readline_display;
432 rl_getc_function = readline_getc;
434 /* Completion support */
435 rl_attempted_completion_function = readline_completion;
437 rl_completion_display_matches_hook = readline_display_matches;
440 char *
441 read_prompt(const char *prompt)
443 static char *line = NULL;
445 if (line) {
446 free(line);
447 line = NULL;
450 line = readline(prompt);
452 if (line && !*line) {
453 free(line);
454 line = NULL;
457 if (line)
458 add_history(line);
460 return line;
463 void
464 prompt_init(void)
466 readline_init();
468 #else
469 char *
470 read_prompt(const char *prompt)
472 return read_prompt_incremental(prompt, TRUE, NULL, NULL);
475 void
476 prompt_init(void)
479 #endif /* HAVE_READLINE */
481 bool
482 prompt_menu(const char *prompt, const struct menu_item *items, int *selected)
484 enum input_status status = INPUT_OK;
485 struct key key;
486 int size = 0;
488 while (items[size].text)
489 size++;
491 assert(size > 0);
493 while (status == INPUT_OK) {
494 const struct menu_item *item = &items[*selected];
495 char hotkey[] = { '[', (char) item->hotkey, ']', ' ', 0 };
496 int i;
498 update_status("%s (%d of %d) %s%s", prompt, *selected + 1, size,
499 item->hotkey ? hotkey : "", item->text);
501 switch (get_input(COLS - 1, &key, FALSE)) {
502 case KEY_RETURN:
503 case KEY_ENTER:
504 case '\n':
505 status = INPUT_STOP;
506 break;
508 case KEY_LEFT:
509 case KEY_UP:
510 *selected = *selected - 1;
511 if (*selected < 0)
512 *selected = size - 1;
513 break;
515 case KEY_RIGHT:
516 case KEY_DOWN:
517 *selected = (*selected + 1) % size;
518 break;
520 case KEY_ESC:
521 status = INPUT_CANCEL;
522 break;
524 default:
525 for (i = 0; items[i].text; i++)
526 if (items[i].hotkey == key.data.bytes[0]) {
527 *selected = i;
528 status = INPUT_STOP;
529 break;
534 report_clear();
536 return status != INPUT_CANCEL;
539 static struct option_info option_toggles[] = {
540 #define DEFINE_OPTION_TOGGLES(name, type, flags) { #name, STRING_SIZE(#name), #type, &opt_ ## name, flags },
541 OPTION_INFO(DEFINE_OPTION_TOGGLES)
544 static bool
545 find_arg(const char *argv[], const char *arg)
547 int i;
549 for (i = 0; argv && argv[i]; i++)
550 if (!strcmp(argv[i], arg))
551 return TRUE;
552 return FALSE;
555 static enum status_code
556 prompt_toggle_option(struct view *view, const char *argv[], const char *prefix,
557 struct option_info *toggle, enum view_flag *flags)
559 char name[SIZEOF_STR];
561 if (!enum_name_prefixed(name, sizeof(name), prefix, toggle->name))
562 return error("Failed to toggle option %s", toggle->name);
564 *flags = toggle->flags;
566 if (!strcmp(toggle->type, "bool")) {
567 bool *opt = toggle->value;
569 *opt = !*opt;
570 if (opt == &opt_mouse)
571 enable_mouse(*opt);
572 return success("set %s = %s", name, *opt ? "yes" : "no");
574 } else if (!strncmp(toggle->type, "enum", 4)) {
575 const char *type = toggle->type + STRING_SIZE("enum ");
576 enum author *opt = toggle->value;
577 const struct enum_map *map = find_enum_map(type);
579 *opt = (*opt + 1) % map->size;
580 return success("set %s = %s", name, enum_name(map->entries[*opt].name));
582 } else if (!strcmp(toggle->type, "int")) {
583 const char *arg = argv[2] ? argv[2] : "1";
584 int diff = atoi(arg);
585 int *opt = toggle->value;
587 if (!diff)
588 diff = *arg == '-' ? -1 : 1;
590 if (opt == &opt_diff_context && *opt < 0)
591 *opt = -*opt;
592 if (opt == &opt_diff_context && diff < 0) {
593 if (!*opt)
594 return error("Diff context cannot be less than zero");
595 if (*opt < -diff)
596 diff = -*opt;
599 if (strstr(name, "commit-title-overflow")) {
600 *opt = *opt ? -*opt : 50;
601 if (*opt < 0)
602 return success("set %s = no", name);
603 diff = 0;
606 *opt += diff;
607 return success("set %s = %d", name, *opt);
609 } else if (!strcmp(toggle->type, "double")) {
610 const char *arg = argv[2] ? argv[2] : "1.0";
611 double *opt = toggle->value;
612 int sign = 1;
613 double diff;
615 if (*arg == '-') {
616 sign = -1;
617 arg++;
620 if (parse_step(&diff, arg) != SUCCESS)
621 diff = strtod(arg, NULL);
623 *opt += sign * diff;
624 return success("set %s = %.2f", name, *opt);
626 } else if (!strcmp(toggle->type, "const char **")) {
627 const char ***opt = toggle->value;
628 bool found = TRUE;
629 int i;
631 if (argv_size(argv) <= 2) {
632 argv_free(*opt);
633 (*opt)[0] = NULL;
634 return SUCCESS;
637 for (i = 2; argv[i]; i++) {
638 if (!find_arg(*opt, argv[i])) {
639 found = FALSE;
640 break;
644 if (found) {
645 int next, pos;
647 for (next = 0, pos = 0; (*opt)[pos]; pos++) {
648 const char *arg = (*opt)[pos];
650 if (find_arg(argv + 2, arg)) {
651 free((void *) arg);
652 continue;
654 (*opt)[next++] = arg;
657 (*opt)[next] = NULL;
659 } else if (!argv_copy(opt, argv + 2)) {
660 return ERROR_OUT_OF_MEMORY;
662 return SUCCESS;
664 } else {
665 return error("Unsupported `:toggle %s` (%s)", name, toggle->type);
669 static enum status_code
670 prompt_toggle(struct view *view, const char *argv[], enum view_flag *flags)
672 const char *option = argv[1];
673 size_t optionlen = option ? strlen(option) : 0;
674 struct option_info template;
675 struct option_info *toggle;
676 struct view_column *column;
677 const char *column_name;
679 if (!option)
680 return error("%s", "No option name given to :toggle");
682 if (enum_equals_static("sort-field", option, optionlen) ||
683 enum_equals_static("sort-order", option, optionlen)) {
684 if (!view_has_flags(view, VIEW_SORTABLE)) {
685 return error("Sorting is not yet supported for the %s view", view->name);
686 } else {
687 bool sort_field = enum_equals_static("sort-field", option, optionlen);
688 struct sort_state *sort = &view->sort;
690 sort_view(view, sort_field);
691 return success("set %s = %s", option,
692 sort_field ? view_column_name(get_sort_field(view))
693 : sort->reverse ? "descending" : "ascending");
697 toggle = find_option_info(option_toggles, ARRAY_SIZE(option_toggles), "", option);
698 if (toggle)
699 return prompt_toggle_option(view, argv, "", toggle, flags);
701 for (column = view->columns; column; column = column->next) {
702 toggle = find_column_option_info(column->type, &column->opt, option, &template, &column_name);
703 if (toggle)
704 return prompt_toggle_option(view, argv, column_name, toggle, flags);
707 return error("`:toggle %s` not supported", option);
710 static void
711 prompt_update_display(enum view_flag flags)
713 struct view *view;
714 int i;
716 if (flags & VIEW_RESET_DISPLAY) {
717 resize_display();
718 redraw_display(TRUE);
721 foreach_displayed_view(view, i) {
722 if (view_has_flags(view, flags) && view_can_refresh(view))
723 reload_view(view);
724 else
725 redraw_view(view);
729 enum request
730 run_prompt_command(struct view *view, const char *argv[])
732 enum request request;
733 const char *cmd = argv[0];
734 size_t cmdlen = cmd ? strlen(cmd) : 0;
736 if (!cmd)
737 return REQ_NONE;
739 if (string_isnumber(cmd)) {
740 int lineno = view->pos.lineno + 1;
742 if (parse_int(&lineno, cmd, 0, view->lines + 1) == SUCCESS) {
743 if (!lineno)
744 lineno = 1;
745 select_view_line(view, lineno - 1);
746 report_clear();
747 } else {
748 report("Unable to parse '%s' as a line number", cmd);
750 } else if (iscommit(cmd)) {
751 int lineno;
753 if (!(view->ops->column_bits & view_column_bit(ID))) {
754 report("Jumping to commits is not supported by the %s view", view->name);
755 return REQ_NONE;
758 for (lineno = 0; lineno < view->lines; lineno++) {
759 struct view_column_data column_data = {};
760 struct line *line = &view->line[lineno];
762 if (view->ops->get_column_data(view, line, &column_data) &&
763 column_data.id &&
764 !strncasecmp(column_data.id, cmd, cmdlen)) {
765 string_ncopy(view->env->search, cmd, cmdlen);
766 select_view_line(view, lineno);
767 report_clear();
768 return REQ_NONE;
772 report("Unable to find commit '%s'", view->env->search);
773 return REQ_NONE;
775 } else if (cmdlen > 1 && (cmd[0] == '/' || cmd[0] == '?')) {
776 char search[SIZEOF_STR];
778 if (!argv_to_string(argv, search, sizeof(search), " ")) {
779 report("Failed to copy search string");
780 return REQ_NONE;
783 if (!strcmp(search + 1, view->env->search))
784 return cmd[0] == '/' ? REQ_FIND_NEXT : REQ_FIND_PREV;
786 string_ncopy(view->env->search, search + 1, strlen(search + 1));
787 return cmd[0] == '/' ? REQ_SEARCH : REQ_SEARCH_BACK;
789 } else if (cmdlen > 1 && cmd[0] == '!') {
790 struct view *next = &pager_view;
791 bool copied;
793 /* Trim the leading '!'. */
794 argv[0] = cmd + 1;
795 copied = argv_format(view->env, &next->argv, argv, FALSE, TRUE);
796 argv[0] = cmd;
798 if (!copied) {
799 report("Argument formatting failed");
800 } else {
801 /* When running random commands, initially show the
802 * command in the title. However, it maybe later be
803 * overwritten if a commit line is selected. */
804 argv_to_string(next->argv, next->ref, sizeof(next->ref), " ");
806 next->dir = NULL;
807 open_pager_view(view, OPEN_PREPARED | OPEN_WITH_STDERR);
810 } else if (!strcmp(cmd, "save-display")) {
811 const char *path = argv[1] ? argv[1] : "tig-display.txt";
813 if (!save_display(path))
814 report("Failed to save screen to %s", path);
815 else
816 report("Saved screen to %s", path);
818 } else if (!strcmp(cmd, "save-options")) {
819 const char *path = argv[1] ? argv[1] : "tig-options.txt";
820 enum status_code code = save_options(path);
822 if (code != SUCCESS)
823 report("Failed to save options: %s", get_status_message(code));
824 else
825 report("Saved options to %s", path);
827 } else if (!strcmp(cmd, "exec")) {
828 struct run_request req = { view->keymap, {}, argv + 1 };
829 enum status_code code = parse_run_request_flags(&req.flags, argv + 1);
831 if (code != SUCCESS) {
832 report("Failed to execute command: %s", get_status_message(code));
833 } else {
834 return exec_run_request(view, &req);
837 } else if (!strcmp(cmd, "toggle")) {
838 enum view_flag flags = VIEW_NO_FLAGS;
839 enum status_code code = prompt_toggle(view, argv, &flags);
840 const char *action = get_status_message(code);
842 if (code != SUCCESS) {
843 report("%s", action);
844 return REQ_NONE;
847 prompt_update_display(flags);
849 if (*action)
850 report("%s", action);
852 } else if (!strcmp(cmd, "script")) {
853 enum status_code code = open_script(argv[1]);
855 if (code != SUCCESS)
856 report("%s", get_status_message(code));
857 return REQ_NONE;
859 } else {
860 struct key key = {};
861 enum status_code code;
862 enum view_flag flags = VIEW_NO_FLAGS;
864 /* Try :<key> */
865 key.modifiers.multibytes = 1;
866 string_ncopy(key.data.bytes, cmd, cmdlen);
867 request = get_keybinding(view->keymap, &key, 1);
868 if (request != REQ_NONE)
869 return request;
871 /* Try :<command> */
872 request = get_request(cmd);
873 if (request != REQ_UNKNOWN)
874 return request;
876 code = set_option(argv[0], argv_size(argv + 1), &argv[1]);
877 if (code != SUCCESS) {
878 report("%s", get_status_message(code));
879 return REQ_NONE;
882 if (!strcmp(cmd, "set")) {
883 struct option_info *toggle;
885 toggle = find_option_info(option_toggles, ARRAY_SIZE(option_toggles),
886 "", argv[1]);
888 if (toggle)
889 flags = toggle->flags;
892 if (flags) {
893 prompt_update_display(flags);
895 } else {
896 request = view_can_refresh(view) ? REQ_REFRESH : REQ_SCREEN_REDRAW;
897 if (!strcmp(cmd, "color"))
898 init_colors();
899 resize_display();
900 redraw_display(TRUE);
904 return REQ_NONE;
907 enum request
908 exec_run_request(struct view *view, struct run_request *req)
910 const char **argv = NULL;
911 bool confirmed = FALSE;
912 enum request request = REQ_NONE;
914 if (!argv_format(view->env, &argv, req->argv, FALSE, TRUE)) {
915 report("Failed to format arguments");
916 return REQ_NONE;
919 if (req->flags.internal) {
920 request = run_prompt_command(view, argv);
922 } else {
923 confirmed = !req->flags.confirm;
925 if (req->flags.confirm) {
926 char cmd[SIZEOF_STR], prompt[SIZEOF_STR];
927 const char *and_exit = req->flags.exit ? " and exit" : "";
929 if (argv_to_string(argv, cmd, sizeof(cmd), " ") &&
930 string_format(prompt, "Run `%s`%s?", cmd, and_exit) &&
931 prompt_yesno(prompt)) {
932 confirmed = TRUE;
936 if (confirmed && argv_remove_quotes(argv))
937 open_external_viewer(argv, NULL, req->flags.silent,
938 !req->flags.exit, FALSE, "");
941 if (argv)
942 argv_free(argv);
943 free(argv);
945 if (request == REQ_NONE) {
946 if (req->flags.confirm && !confirmed)
947 request = REQ_NONE;
949 else if (req->flags.exit)
950 request = REQ_QUIT;
952 else if (!req->flags.internal && watch_dirty(&view->watch))
953 request = REQ_REFRESH;
957 return request;
960 enum request
961 open_prompt(struct view *view)
963 char *cmd = read_prompt(":");
964 const char *argv[SIZEOF_ARG] = { NULL };
965 int argc = 0;
967 if (cmd && !argv_from_string(argv, &argc, cmd)) {
968 report("Too many arguments");
969 return REQ_NONE;
972 return run_prompt_command(view, argv);
975 /* vim: set ts=8 sw=8 noexpandtab: */