Merge pull request #530 from jjlin/master
[tig.git] / src / prompt.c
blobc9435ceaf443a0ace5c8cb7125e6d0bcd6158596
1 /* Copyright (c) 2006-2015 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/repo.h"
16 #include "tig/view.h"
17 #include "tig/draw.h"
18 #include "tig/display.h"
19 #include "tig/options.h"
20 #include "tig/prompt.h"
21 #include "tig/pager.h"
22 #include "tig/types.h"
24 #ifdef HAVE_READLINE
25 #include <readline/readline.h>
26 #include <readline/history.h>
27 #endif /* HAVE_READLINE */
29 static char *
30 prompt_input(const char *prompt, struct input *input)
32 enum input_status status = INPUT_OK;
33 unsigned char chars_length[SIZEOF_STR];
34 struct key key;
35 size_t promptlen = strlen(prompt);
36 int pos = 0, chars = 0;
37 int last_buf_length = promptlen ? -1 : promptlen;
39 input->buf[0] = 0;
41 while (status == INPUT_OK || status == INPUT_SKIP) {
42 int buf_length = strlen(input->buf) + promptlen;
43 int offset = pos || buf_length != last_buf_length ? pos + promptlen : -1;
45 last_buf_length = buf_length;
46 if (offset >= 0)
47 update_status("%s%.*s", prompt, pos, input->buf);
49 if (get_input(offset, &key) == OK) {
50 int len = strlen(key.data.bytes);
52 if (pos + len >= sizeof(input->buf)) {
53 report("Input string too long");
54 return NULL;
57 string_ncopy_do(input->buf + pos, sizeof(input->buf) - pos, key.data.bytes, len);
58 pos += len;
59 chars_length[chars++] = len;
60 status = input->handler(input, &key);
61 if (status != INPUT_OK) {
62 pos -= len;
63 chars--;
64 } else {
65 int changed_pos = strlen(input->buf);
67 if (changed_pos != pos) {
68 pos = changed_pos;
69 chars_length[chars - 1] = changed_pos - (pos - len);
72 } else {
73 status = input->handler(input, &key);
74 if (status == INPUT_DELETE) {
75 int len = chars_length[--chars];
77 pos -= len;
78 status = INPUT_OK;
79 } else {
80 int changed_pos = strlen(input->buf);
82 if (changed_pos != pos) {
83 pos = changed_pos;
84 chars_length[chars++] = changed_pos - pos;
88 input->buf[pos] = 0;
91 report_clear();
93 if (status == INPUT_CANCEL)
94 return NULL;
96 input->buf[pos++] = 0;
98 return input->buf;
101 enum input_status
102 prompt_default_handler(struct input *input, struct key *key)
104 switch (key_to_value(key)) {
105 case KEY_RETURN:
106 case KEY_ENTER:
107 case '\n':
108 return *input->buf || input->allow_empty ? INPUT_STOP : INPUT_CANCEL;
110 case KEY_BACKSPACE:
111 return *input->buf ? INPUT_DELETE : INPUT_CANCEL;
113 case KEY_ESC:
114 return INPUT_CANCEL;
116 default:
117 return INPUT_SKIP;
121 static enum input_status
122 prompt_yesno_handler(struct input *input, struct key *key)
124 unsigned long c = key_to_unicode(key);
126 if (c == 'y' || c == 'Y')
127 return INPUT_STOP;
128 if (c == 'n' || c == 'N')
129 return INPUT_CANCEL;
130 return prompt_default_handler(input, key);
133 bool
134 prompt_yesno(const char *prompt)
136 char prompt2[SIZEOF_STR];
137 struct input input = { prompt_yesno_handler, false, NULL };
139 if (!string_format(prompt2, "%s [Yy/Nn]", prompt))
140 return false;
142 return !!prompt_input(prompt2, &input);
145 struct incremental_input {
146 struct input input;
147 input_handler handler;
148 bool edit_mode;
151 static enum input_status
152 read_prompt_handler(struct input *input, struct key *key)
154 struct incremental_input *incremental = (struct incremental_input *) input;
156 if (incremental->edit_mode && !key->modifiers.multibytes)
157 return prompt_default_handler(input, key);
159 if (!unicode_width(key_to_unicode(key), 8))
160 return INPUT_SKIP;
162 if (!incremental->handler)
163 return INPUT_OK;
165 return incremental->handler(input, key);
168 char *
169 read_prompt_incremental(const char *prompt, bool edit_mode, bool allow_empty, input_handler handler, void *data)
171 static struct incremental_input incremental = { { read_prompt_handler } };
173 incremental.input.allow_empty = allow_empty;
174 incremental.input.data = data;
175 incremental.handler = handler;
176 incremental.edit_mode = edit_mode;
178 return prompt_input(prompt, (struct input *) &incremental);
181 #ifdef HAVE_READLINE
182 static void
183 readline_display(void)
185 update_status("%s%s", rl_display_prompt, rl_line_buffer);
186 wmove(status_win, 0, strlen(rl_display_prompt) + rl_point);
187 wrefresh(status_win);
190 static char *
191 readline_variable_generator(const char *text, int state)
193 static const char *vars[] = {
194 #define FORMAT_VAR(type, name, ifempty, initval) "%(" #name ")",
195 ARGV_ENV_INFO(FORMAT_VAR)
196 #undef FORMAT_VAR
197 NULL
200 static int index, len;
201 const char *name;
202 char *variable = NULL; /* No match */
204 /* If it is a new word to complete, initialize */
205 if (!state) {
206 index = 0;
207 len = strlen(text);
210 /* Return the next name which partially matches */
211 while ((name = vars[index])) {
212 index++;
214 /* Complete or format a variable */
215 if (strncmp(name, text, len) == 0) {
216 if (strlen(name) > len)
217 variable = strdup(name);
218 else
219 variable = argv_format_arg(&argv_env, text);
220 break;
224 return variable;
227 static char *
228 readline_action_generator(const char *text, int state)
230 static const char *actions[] = {
231 "!",
232 "source",
233 "color",
234 "bind",
235 "set",
236 "toggle",
237 "goto",
238 "save-display",
239 "save-options",
240 "exec",
241 #define REQ_GROUP(help)
242 #define REQ_(req, help) #req
243 REQ_INFO,
244 #undef REQ_GROUP
245 #undef REQ_
246 NULL
249 static int index, len;
250 const char *name;
251 char *match = NULL; /* No match */
253 /* If it is a new word to complete, initialize */
254 if (!state) {
255 index = 0;
256 len = strlen(text);
259 /* Return the next name which partially matches */
260 while ((name = actions[index])) {
261 name = enum_name(name);
262 index++;
264 if (strncmp(name, text, len) == 0) {
265 /* Ignore exact completion */
266 if (strlen(name) > len)
267 match = strdup(name);
268 break;
272 return match;
275 static char *
276 readline_set_generator(const char *text, int state)
278 static const char *words[] = {
279 #define DEFINE_OPTION_NAME(name, type, flags) #name " = ",
280 OPTION_INFO(DEFINE_OPTION_NAME)
281 #undef DEFINE_OPTION_NAME
282 NULL
285 static int index, len;
286 const char *name;
287 char *match = NULL; /* No match */
289 /* If it is a new word to complete, initialize */
290 if (!state) {
291 index = 0;
292 len = strlen(text);
295 /* Return the next name which partially matches */
296 while ((name = words[index])) {
297 name = enum_name(name);
298 index++;
300 if (strncmp(name, text, len) == 0) {
301 /* Ignore exact completion */
302 if (strlen(name) > len)
303 match = strdup(name);
304 break;
308 return match;
311 static char *
312 readline_toggle_generator(const char *text, int state)
314 static const char **words;
315 static int index, len;
316 const char *name;
317 char *match = NULL; /* No match */
319 if (!words) {
320 /* TODO: Only complete column options that are defined
321 * for the view. */
323 #define DEFINE_OPTION_WORD(name, type, flags) argv_append(&words, #name);
324 #define DEFINE_COLUMN_OPTIONS_WORD(name, type, flags) #name,
325 #define DEFINE_COLUMN_OPTIONS_WORDS(name, id, options) \
326 if (VIEW_COLUMN_##id != VIEW_COLUMN_SECTION) { \
327 const char *vars[] = { \
328 options(DEFINE_COLUMN_OPTIONS_WORD) \
329 }; \
330 char buf[SIZEOF_STR]; \
331 int i; \
332 for (i = 0; i < ARRAY_SIZE(vars); i++) { \
333 if (enum_name_prefixed(buf, sizeof(buf), #name, vars[i])) \
334 argv_append(&words, buf); \
338 OPTION_INFO(DEFINE_OPTION_WORD)
339 COLUMN_OPTIONS(DEFINE_COLUMN_OPTIONS_WORDS);
342 /* If it is a new word to complete, initialize */
343 if (!state) {
344 index = 0;
345 len = strlen(text);
348 /* Return the next name which partially matches */
349 while ((name = words[index])) {
350 name = enum_name(name);
351 index++;
353 if (strncmp(name, text, len) == 0) {
354 /* Ignore exact completion */
355 if (strlen(name) > len)
356 match = strdup(name);
357 break;
361 return match;
364 static int
365 readline_getc(FILE *stream)
367 return get_input_char();
370 static char **
371 readline_completion(const char *text, int start, int end)
373 /* Do not append a space after a completion */
374 rl_completion_suppress_append = 1;
377 * If the word is at the start of the line,
378 * then it is a tig action to complete.
380 if (start == 0)
381 return rl_completion_matches(text, readline_action_generator);
384 * If the line begins with "toggle", then we complete toggle options.
386 if (start >= 7 && strncmp(rl_line_buffer, "toggle ", 7) == 0)
387 return rl_completion_matches(text, readline_toggle_generator);
390 * If the line begins with "set", then we complete set options.
391 * (unless it is already completed)
393 if (start >= 4 && strncmp(rl_line_buffer, "set ", 4) == 0 &&
394 !strchr(rl_line_buffer, '='))
395 return rl_completion_matches(text, readline_set_generator);
398 * Otherwise it might be a variable name...
400 if (strncmp(text, "%(", 2) == 0)
401 return rl_completion_matches(text, readline_variable_generator);
404 * ... or finally fall back to filename completion.
406 return NULL;
409 static void
410 readline_display_matches(char **matches, int num_matches, int max_length)
412 unsigned int i;
414 wmove(status_win, 0, 0);
415 waddstr(status_win, "matches: ");
417 /* matches[0] is the incomplete word */
418 for (i = 1; i < num_matches + 1; ++i) {
419 waddstr(status_win, matches[i]);
420 waddch(status_win, ' ');
423 wgetch(status_win);
424 wrefresh(status_win);
427 static void
428 readline_init(void)
430 /* Allow conditional parsing of the ~/.inputrc file. */
431 rl_readline_name = "tig";
433 /* Word break caracters (we removed '(' to match variables) */
434 rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{";
436 /* Custom display function */
437 rl_redisplay_function = readline_display;
438 rl_getc_function = readline_getc;
440 /* Completion support */
441 rl_attempted_completion_function = readline_completion;
443 rl_completion_display_matches_hook = readline_display_matches;
446 char *
447 read_prompt(const char *prompt)
449 static char *line = NULL;
451 if (line) {
452 free(line);
453 line = NULL;
456 line = readline(prompt);
458 if (line && !*line) {
459 free(line);
460 line = NULL;
463 if (line)
464 add_history(line);
466 return line;
469 void
470 prompt_init(void)
472 readline_init();
474 #else
475 char *
476 read_prompt(const char *prompt)
478 return read_prompt_incremental(prompt, true, false, NULL, NULL);
481 void
482 prompt_init(void)
485 #endif /* HAVE_READLINE */
487 bool
488 prompt_menu(const char *prompt, const struct menu_item *items, int *selected)
490 enum input_status status = INPUT_OK;
491 struct key key;
492 int size = 0;
494 while (items[size].text)
495 size++;
497 assert(size > 0);
499 while (status == INPUT_OK) {
500 const struct menu_item *item = &items[*selected];
501 char hotkey[] = { '[', (char) item->hotkey, ']', ' ', 0 };
502 int i;
504 update_status("%s (%d of %d) %s%s", prompt, *selected + 1, size,
505 item->hotkey ? hotkey : "", item->text);
507 switch (get_input(COLS - 1, &key)) {
508 case KEY_RETURN:
509 case KEY_ENTER:
510 case '\n':
511 status = INPUT_STOP;
512 break;
514 case KEY_LEFT:
515 case KEY_UP:
516 *selected = *selected - 1;
517 if (*selected < 0)
518 *selected = size - 1;
519 break;
521 case KEY_RIGHT:
522 case KEY_DOWN:
523 *selected = (*selected + 1) % size;
524 break;
526 case KEY_ESC:
527 status = INPUT_CANCEL;
528 break;
530 default:
531 for (i = 0; items[i].text; i++)
532 if (items[i].hotkey == key.data.bytes[0]) {
533 *selected = i;
534 status = INPUT_STOP;
535 break;
540 report_clear();
542 return status != INPUT_CANCEL;
545 static struct option_info option_toggles[] = {
546 #define DEFINE_OPTION_TOGGLES(name, type, flags) { #name, STRING_SIZE(#name), #type, &opt_ ## name, flags },
547 OPTION_INFO(DEFINE_OPTION_TOGGLES)
550 static bool
551 find_arg(const char *argv[], const char *arg)
553 int i;
555 for (i = 0; argv && argv[i]; i++)
556 if (!strcmp(argv[i], arg))
557 return true;
558 return false;
561 static enum status_code
562 prompt_toggle_option(struct view *view, const char *argv[], const char *prefix,
563 struct option_info *toggle, enum view_flag *flags)
565 char name[SIZEOF_STR];
567 if (!enum_name_prefixed(name, sizeof(name), prefix, toggle->name))
568 return error("Failed to toggle option %s", toggle->name);
570 *flags = toggle->flags;
572 if (!strcmp(toggle->type, "bool")) {
573 bool *opt = toggle->value;
575 *opt = !*opt;
576 if (opt == &opt_mouse)
577 enable_mouse(*opt);
578 return success("set %s = %s", name, *opt ? "yes" : "no");
580 } else if (!strncmp(toggle->type, "enum", 4)) {
581 const char *type = toggle->type + STRING_SIZE("enum ");
582 enum author *opt = toggle->value;
583 const struct enum_map *map = find_enum_map(type);
585 *opt = (*opt + 1) % map->size;
586 return success("set %s = %s", name, enum_name(map->entries[*opt].name));
588 } else if (!strcmp(toggle->type, "int")) {
589 const char *arg = argv[2] ? argv[2] : "1";
590 int diff = atoi(arg);
591 int *opt = toggle->value;
593 if (!diff)
594 diff = *arg == '-' ? -1 : 1;
596 if (opt == &opt_diff_context && *opt < 0)
597 *opt = -*opt;
598 if (opt == &opt_diff_context && diff < 0) {
599 if (!*opt)
600 return error("Diff context cannot be less than zero");
601 if (*opt < -diff)
602 diff = -*opt;
605 if (strstr(name, "commit-title-overflow")) {
606 *opt = *opt ? -*opt : 50;
607 if (*opt < 0)
608 return success("set %s = no", name);
609 diff = 0;
612 *opt += diff;
613 return success("set %s = %d", name, *opt);
615 } else if (!strcmp(toggle->type, "double")) {
616 const char *arg = argv[2] ? argv[2] : "1.0";
617 double *opt = toggle->value;
618 int sign = 1;
619 double diff;
621 if (*arg == '-') {
622 sign = -1;
623 arg++;
626 if (parse_step(&diff, arg) != SUCCESS)
627 diff = strtod(arg, NULL);
629 *opt += sign * diff;
630 return success("set %s = %.2f", name, *opt);
632 } else if (!strcmp(toggle->type, "const char **")) {
633 const char ***opt = toggle->value;
634 bool found = true;
635 int i;
637 if (argv_size(argv) <= 2) {
638 argv_free(*opt);
639 (*opt)[0] = NULL;
640 return SUCCESS;
643 for (i = 2; argv[i]; i++) {
644 if (!find_arg(*opt, argv[i])) {
645 found = false;
646 break;
650 if (found) {
651 int next, pos;
653 for (next = 0, pos = 0; (*opt)[pos]; pos++) {
654 const char *arg = (*opt)[pos];
656 if (find_arg(argv + 2, arg)) {
657 free((void *) arg);
658 continue;
660 (*opt)[next++] = arg;
663 (*opt)[next] = NULL;
665 } else if (!argv_copy(opt, argv + 2)) {
666 return ERROR_OUT_OF_MEMORY;
668 return SUCCESS;
670 } else {
671 return error("Unsupported `:toggle %s` (%s)", name, toggle->type);
675 static enum status_code
676 prompt_toggle(struct view *view, const char *argv[], enum view_flag *flags)
678 const char *option = argv[1];
679 size_t optionlen = option ? strlen(option) : 0;
680 struct option_info template;
681 struct option_info *toggle;
682 struct view_column *column;
683 const char *column_name;
685 if (!option)
686 return error("%s", "No option name given to :toggle");
688 if (enum_equals_static("sort-field", option, optionlen) ||
689 enum_equals_static("sort-order", option, optionlen)) {
690 if (!view_has_flags(view, VIEW_SORTABLE)) {
691 return error("Sorting is not yet supported for the %s view", view->name);
692 } else {
693 bool sort_field = enum_equals_static("sort-field", option, optionlen);
694 struct sort_state *sort = &view->sort;
696 sort_view(view, sort_field);
697 return success("set %s = %s", option,
698 sort_field ? view_column_name(get_sort_field(view))
699 : sort->reverse ? "descending" : "ascending");
703 toggle = find_option_info(option_toggles, ARRAY_SIZE(option_toggles), "", option);
704 if (toggle)
705 return prompt_toggle_option(view, argv, "", toggle, flags);
707 for (column = view->columns; column; column = column->next) {
708 toggle = find_column_option_info(column->type, &column->opt, option, &template, &column_name);
709 if (toggle)
710 return prompt_toggle_option(view, argv, column_name, toggle, flags);
713 return error("`:toggle %s` not supported", option);
716 static void
717 prompt_update_display(enum view_flag flags)
719 struct view *view;
720 int i;
722 if (flags & VIEW_RESET_DISPLAY) {
723 resize_display();
724 redraw_display(true);
727 foreach_displayed_view(view, i) {
728 if (view_has_flags(view, flags) && view_can_refresh(view))
729 reload_view(view);
730 else
731 redraw_view(view);
735 enum request
736 run_prompt_command(struct view *view, const char *argv[])
738 enum request request;
739 const char *cmd = argv[0];
740 size_t cmdlen = cmd ? strlen(cmd) : 0;
742 if (!cmd)
743 return REQ_NONE;
745 if (string_isnumber(cmd)) {
746 int lineno = view->pos.lineno + 1;
748 if (parse_int(&lineno, cmd, 0, view->lines + 1) == SUCCESS) {
749 if (!lineno)
750 lineno = 1;
751 select_view_line(view, lineno - 1);
752 report_clear();
753 } else {
754 report("Unable to parse '%s' as a line number", cmd);
756 } else if (iscommit(cmd)) {
757 goto_id(view, cmd, true, true);
758 return REQ_NONE;
760 } else if (cmdlen > 1 && (cmd[0] == '/' || cmd[0] == '?')) {
761 char search[SIZEOF_STR];
763 if (!argv_to_string(argv, search, sizeof(search), " ")) {
764 report("Failed to copy search string");
765 return REQ_NONE;
768 if (!strcmp(search + 1, view->env->search))
769 return cmd[0] == '/' ? REQ_FIND_NEXT : REQ_FIND_PREV;
771 string_ncopy(view->env->search, search + 1, strlen(search + 1));
772 return cmd[0] == '/' ? REQ_FIND_NEXT : REQ_FIND_PREV;
774 } else if (cmdlen > 1 && cmd[0] == '!') {
775 struct view *next = &pager_view;
776 bool copied;
778 /* Trim the leading '!'. */
779 argv[0] = cmd + 1;
780 copied = argv_format(view->env, &next->argv, argv, false, true);
781 argv[0] = cmd;
783 if (!copied) {
784 report("Argument formatting failed");
785 } else {
786 /* When running random commands, initially show the
787 * command in the title. However, it maybe later be
788 * overwritten if a commit line is selected. */
789 argv_to_string(next->argv, next->ref, sizeof(next->ref), " ");
791 next->dir = NULL;
792 open_pager_view(view, OPEN_PREPARED | OPEN_WITH_STDERR);
795 } else if (!strcmp(cmd, "goto")) {
796 if (!argv[1] || !strlen(argv[1]))
797 report("goto requires an argument");
798 else
799 goto_id(view, argv[1], true, true);
800 return REQ_NONE;
802 } else if (!strcmp(cmd, "save-display")) {
803 const char *path = argv[1] ? argv[1] : "tig-display.txt";
805 if (!save_display(path))
806 report("Failed to save screen to %s", path);
807 else
808 report("Saved screen to %s", path);
810 } else if (!strcmp(cmd, "save-options")) {
811 const char *path = argv[1] ? argv[1] : "tig-options.txt";
812 enum status_code code = save_options(path);
814 if (code != SUCCESS)
815 report("Failed to save options: %s", get_status_message(code));
816 else
817 report("Saved options to %s", path);
819 } else if (!strcmp(cmd, "exec")) {
820 // argv may be allocated and mutations below will cause
821 // free() to error out so backup and restore. :(
822 const char *cmd = argv[1];
823 struct run_request req = { view->keymap, {0}, argv + 1 };
824 enum status_code code = parse_run_request_flags(&req.flags, argv + 1);
826 if (code != SUCCESS) {
827 argv[1] = cmd;
828 report("Failed to execute command: %s", get_status_message(code));
829 } else {
830 request = exec_run_request(view, &req);
831 argv[1] = cmd;
832 return request;
835 } else if (!strcmp(cmd, "toggle")) {
836 enum view_flag flags = VIEW_NO_FLAGS;
837 enum status_code code = prompt_toggle(view, argv, &flags);
838 const char *action = get_status_message(code);
840 if (code != SUCCESS) {
841 report("%s", action);
842 return REQ_NONE;
845 prompt_update_display(flags);
847 if (*action)
848 report("%s", action);
850 } else if (!strcmp(cmd, "script")) {
851 enum status_code code = open_script(argv[1]);
853 if (code != SUCCESS)
854 report("%s", get_status_message(code));
855 return REQ_NONE;
857 } else {
858 struct key key = {{0}};
859 enum status_code code;
860 enum view_flag flags = VIEW_NO_FLAGS;
862 /* Try :<key> */
863 key.modifiers.multibytes = 1;
864 string_ncopy(key.data.bytes, cmd, cmdlen);
865 request = get_keybinding(view->keymap, &key, 1, NULL);
866 if (request != REQ_UNKNOWN)
867 return request;
869 /* Try :<command> */
870 request = get_request(cmd);
871 if (request != REQ_UNKNOWN)
872 return request;
874 code = set_option(argv[0], argv_size(argv + 1), &argv[1]);
875 if (code != SUCCESS) {
876 report("%s", get_status_message(code));
877 return REQ_NONE;
880 if (!strcmp(cmd, "set")) {
881 struct option_info *toggle;
883 toggle = find_option_info(option_toggles, ARRAY_SIZE(option_toggles),
884 "", argv[1]);
886 if (toggle)
887 flags = toggle->flags;
890 if (flags) {
891 prompt_update_display(flags);
893 } else {
894 request = view_can_refresh(view) ? REQ_REFRESH : REQ_SCREEN_REDRAW;
895 if (!strcmp(cmd, "color"))
896 init_colors();
897 resize_display();
898 redraw_display(true);
902 return REQ_NONE;
905 enum request
906 exec_run_request(struct view *view, struct run_request *req)
908 const char **argv = NULL;
909 bool confirmed = false;
910 enum request request = REQ_NONE;
911 char cmd[SIZEOF_STR];
912 const char *req_argv[SIZEOF_ARG];
913 int req_argc = 0;
915 if (!argv_to_string(req->argv, cmd, sizeof(cmd), " ")
916 || !argv_from_string_no_quotes(req_argv, &req_argc, cmd)
917 || !argv_format(view->env, &argv, req_argv, false, true)) {
918 report("Failed to format arguments");
919 return REQ_NONE;
922 if (req->flags.internal) {
923 request = run_prompt_command(view, argv);
925 } else {
926 confirmed = !req->flags.confirm;
928 if (req->flags.confirm) {
929 char cmd[SIZEOF_STR], prompt[SIZEOF_STR];
930 const char *and_exit = req->flags.exit ? " and exit" : "";
932 if (argv_to_string_quoted(argv, cmd, sizeof(cmd), " ") &&
933 string_format(prompt, "Run `%s`%s?", cmd, and_exit) &&
934 prompt_yesno(prompt)) {
935 confirmed = true;
939 if (confirmed)
940 open_external_viewer(argv, repo.cdup, req->flags.silent,
941 !req->flags.exit, false, "");
944 if (argv)
945 argv_free(argv);
946 free(argv);
948 if (request == REQ_NONE) {
949 if (req->flags.confirm && !confirmed)
950 request = REQ_NONE;
952 else if (req->flags.exit)
953 request = REQ_QUIT;
955 else if (!req->flags.internal && watch_dirty(&view->watch))
956 request = REQ_REFRESH;
960 return request;
963 enum request
964 open_prompt(struct view *view)
966 char *cmd = read_prompt(":");
967 const char *argv[SIZEOF_ARG] = { NULL };
968 int argc = 0;
970 if (cmd && !argv_from_string(argv, &argc, cmd)) {
971 report("Too many arguments");
972 return REQ_NONE;
975 return run_prompt_command(view, argv);
978 /* vim: set ts=8 sw=8 noexpandtab: */