Move format_argv to argv module
[tig.git] / src / tig.c
blobb4e4c34ff0eaafd19241d218f775ceb0ec73052a
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 #define WARN_MISSING_CURSES_CONFIGURATION
16 #include "tig.h"
17 #include "types.h"
18 #include "util.h"
19 #include "parse.h"
20 #include "io.h"
21 #include "argv.h"
22 #include "refs.h"
23 #include "graph.h"
24 #include "git.h"
25 #include "request.h"
26 #include "line.h"
27 #include "keys.h"
28 #include "view.h"
29 #include "repo.h"
30 #include "options.h"
31 #include "draw.h"
32 #include "display.h"
34 static bool
35 forward_request_to_child(struct view *child, enum request request)
37 return displayed_views() == 2 && view_is_displayed(child) &&
38 !strcmp(child->vid, child->ops->id);
41 static enum request
42 view_request(struct view *view, enum request request)
44 if (!view || !view->lines)
45 return request;
47 if (request == REQ_ENTER && !opt_focus_child &&
48 view_has_flags(view, VIEW_SEND_CHILD_ENTER)) {
49 struct view *child = display[1];
51 if (forward_request_to_child(child, request)) {
52 view_request(child, request);
53 return REQ_NONE;
57 if (request == REQ_REFRESH && view->unrefreshable) {
58 report("This view can not be refreshed");
59 return REQ_NONE;
62 return view->ops->request(view, request, &view->line[view->pos.lineno]);
66 * Option management
69 #define VIEW_FLAG_RESET_DISPLAY ((enum view_flag) -1)
71 #define TOGGLE_MENU_INFO(_) \
72 _(LINENO, '.', "line numbers", &opt_show_line_numbers, NULL, VIEW_NO_FLAGS), \
73 _(DATE, 'D', "dates", &opt_show_date, date_map, VIEW_NO_FLAGS), \
74 _(AUTHOR, 'A', "author", &opt_show_author, author_map, VIEW_NO_FLAGS), \
75 _(GRAPHIC, '~', "graphics", &opt_line_graphics, graphic_map, VIEW_NO_FLAGS), \
76 _(REV_GRAPH, 'g', "revision graph", &opt_show_rev_graph, NULL, VIEW_LOG_LIKE), \
77 _(FILENAME, '#', "file names", &opt_show_filename, filename_map, VIEW_NO_FLAGS), \
78 _(FILE_SIZE, '*', "file sizes", &opt_show_file_size, file_size_map, VIEW_NO_FLAGS), \
79 _(IGNORE_SPACE, 'W', "space changes", &opt_ignore_space, ignore_space_map, VIEW_DIFF_LIKE), \
80 _(COMMIT_ORDER, 'l', "commit order", &opt_commit_order, commit_order_map, VIEW_LOG_LIKE), \
81 _(REFS, 'F', "reference display", &opt_show_refs, NULL, VIEW_NO_FLAGS), \
82 _(CHANGES, 'C', "local change display", &opt_show_changes, NULL, VIEW_NO_FLAGS), \
83 _(ID, 'X', "commit ID display", &opt_show_id, NULL, VIEW_NO_FLAGS), \
84 _(FILES, '%', "file filtering", &opt_file_filter, NULL, VIEW_DIFF_LIKE | VIEW_LOG_LIKE), \
85 _(TITLE_OVERFLOW, '$', "commit title overflow display", &opt_title_overflow, NULL, VIEW_NO_FLAGS), \
86 _(UNTRACKED_DIRS, 'd', "untracked directory info", &opt_status_untracked_dirs, NULL, VIEW_STATUS_LIKE), \
87 _(VERTICAL_SPLIT, '|', "view split", &opt_vertical_split, vertical_split_map, VIEW_FLAG_RESET_DISPLAY), \
89 static enum view_flag
90 toggle_option(struct view *view, enum request request, char msg[SIZEOF_STR])
92 const struct {
93 enum request request;
94 const struct enum_map *map;
95 enum view_flag reload_flags;
96 } data[] = {
97 #define DEFINE_TOGGLE_DATA(id, key, help, value, map, vflags) { REQ_TOGGLE_ ## id, map, vflags }
98 TOGGLE_MENU_INFO(DEFINE_TOGGLE_DATA)
100 const struct menu_item menu[] = {
101 #define DEFINE_TOGGLE_MENU(id, key, help, value, map, vflags) { key, help, value }
102 TOGGLE_MENU_INFO(DEFINE_TOGGLE_MENU)
103 { 0 }
105 int i = 0;
107 if (request == REQ_OPTIONS) {
108 if (!prompt_menu("Toggle option", menu, &i))
109 return VIEW_NO_FLAGS;
110 } else {
111 while (i < ARRAY_SIZE(data) && data[i].request != request)
112 i++;
113 if (i >= ARRAY_SIZE(data))
114 die("Invalid request (%d)", request);
117 if (data[i].map != NULL) {
118 unsigned int *opt = menu[i].data;
120 *opt = (*opt + 1) % data[i].map->size;
121 if (data[i].map == ignore_space_map) {
122 update_ignore_space_arg();
123 string_format_size(msg, SIZEOF_STR,
124 "Ignoring %s %s", enum_name(data[i].map->entries[*opt]), menu[i].text);
126 } else if (data[i].map == commit_order_map) {
127 update_commit_order_arg();
128 string_format_size(msg, SIZEOF_STR,
129 "Using %s %s", enum_name(data[i].map->entries[*opt]), menu[i].text);
131 } else {
132 string_format_size(msg, SIZEOF_STR,
133 "Displaying %s %s", enum_name(data[i].map->entries[*opt]), menu[i].text);
136 } else if (menu[i].data == &opt_title_overflow) {
137 int *option = menu[i].data;
139 *option = *option ? -*option : 50;
140 string_format_size(msg, SIZEOF_STR,
141 "%sabling %s", *option > 0 ? "En" : "Dis", menu[i].text);
143 } else {
144 bool *option = menu[i].data;
146 *option = !*option;
147 string_format_size(msg, SIZEOF_STR,
148 "%sabling %s", *option ? "En" : "Dis", menu[i].text);
151 return data[i].reload_flags;
156 * View opening
159 static enum request run_prompt_command(struct view *view, char *cmd);
161 static enum request
162 open_run_request(struct view *view, enum request request)
164 struct run_request *req = get_run_request(request);
165 const char **argv = NULL;
166 bool confirmed = FALSE;
168 request = REQ_NONE;
170 if (!req) {
171 report("Unknown run request");
172 return request;
175 if (format_argv(view->env, &argv, req->argv, FALSE, TRUE)) {
176 if (req->internal) {
177 char cmd[SIZEOF_STR];
179 if (argv_to_string(argv, cmd, sizeof(cmd), " ")) {
180 request = run_prompt_command(view, cmd);
183 else {
184 confirmed = !req->confirm;
186 if (req->confirm) {
187 char cmd[SIZEOF_STR], prompt[SIZEOF_STR];
188 const char *and_exit = req->exit ? " and exit" : "";
190 if (argv_to_string(argv, cmd, sizeof(cmd), " ") &&
191 string_format(prompt, "Run `%s`%s?", cmd, and_exit) &&
192 prompt_yesno(prompt)) {
193 confirmed = TRUE;
197 if (confirmed && argv_remove_quotes(argv)) {
198 if (req->silent)
199 io_run_bg(argv);
200 else
201 open_external_viewer(argv, NULL, !req->exit, "");
206 if (argv)
207 argv_free(argv);
208 free(argv);
210 if (request == REQ_NONE) {
211 if (req->confirm && !confirmed)
212 request = REQ_NONE;
214 else if (req->exit)
215 request = REQ_QUIT;
217 else if (view_has_flags(view, VIEW_REFRESH) && !view->unrefreshable)
218 request = REQ_REFRESH;
220 return request;
224 * User request switch noodle
227 static int
228 view_driver(struct view *view, enum request request)
230 int i;
232 if (request == REQ_NONE)
233 return TRUE;
235 if (request >= REQ_RUN_REQUESTS) {
236 request = open_run_request(view, request);
238 // exit quickly rather than going through view_request and back
239 if (request == REQ_QUIT)
240 return FALSE;
243 request = view_request(view, request);
244 if (request == REQ_NONE)
245 return TRUE;
247 switch (request) {
248 case REQ_MOVE_UP:
249 case REQ_MOVE_DOWN:
250 case REQ_MOVE_PAGE_UP:
251 case REQ_MOVE_PAGE_DOWN:
252 case REQ_MOVE_FIRST_LINE:
253 case REQ_MOVE_LAST_LINE:
254 move_view(view, request);
255 break;
257 case REQ_SCROLL_FIRST_COL:
258 case REQ_SCROLL_LEFT:
259 case REQ_SCROLL_RIGHT:
260 case REQ_SCROLL_LINE_DOWN:
261 case REQ_SCROLL_LINE_UP:
262 case REQ_SCROLL_PAGE_DOWN:
263 case REQ_SCROLL_PAGE_UP:
264 case REQ_SCROLL_WHEEL_DOWN:
265 case REQ_SCROLL_WHEEL_UP:
266 scroll_view(view, request);
267 break;
269 case REQ_VIEW_MAIN:
270 case REQ_VIEW_DIFF:
271 case REQ_VIEW_LOG:
272 case REQ_VIEW_TREE:
273 case REQ_VIEW_HELP:
274 case REQ_VIEW_BRANCH:
275 case REQ_VIEW_BLAME:
276 case REQ_VIEW_BLOB:
277 case REQ_VIEW_STATUS:
278 case REQ_VIEW_STAGE:
279 case REQ_VIEW_PAGER:
280 case REQ_VIEW_STASH:
281 open_view(view, request, OPEN_DEFAULT);
282 break;
284 case REQ_NEXT:
285 case REQ_PREVIOUS:
286 if (view->parent) {
287 int line;
289 view = view->parent;
290 line = view->pos.lineno;
291 view_request(view, request);
292 move_view(view, request);
293 if (view_is_displayed(view))
294 update_view_title(view);
295 if (line != view->pos.lineno)
296 view_request(view, REQ_ENTER);
297 } else {
298 move_view(view, request);
300 break;
302 case REQ_VIEW_NEXT:
304 int nviews = displayed_views();
305 int next_view = (current_view + 1) % nviews;
307 if (next_view == current_view) {
308 report("Only one view is displayed");
309 break;
312 current_view = next_view;
313 /* Blur out the title of the previous view. */
314 update_view_title(view);
315 report_clear();
316 break;
318 case REQ_REFRESH:
319 report("Refreshing is not supported by the %s view", view->name);
320 break;
322 case REQ_PARENT:
323 report("Moving to parent is not supported by the the %s view", view->name);
324 break;
326 case REQ_BACK:
327 report("Going back is not supported for by %s view", view->name);
328 break;
330 case REQ_MAXIMIZE:
331 if (displayed_views() == 2)
332 maximize_view(view, TRUE);
333 break;
335 case REQ_OPTIONS:
336 case REQ_TOGGLE_LINENO:
337 case REQ_TOGGLE_DATE:
338 case REQ_TOGGLE_AUTHOR:
339 case REQ_TOGGLE_FILENAME:
340 case REQ_TOGGLE_GRAPHIC:
341 case REQ_TOGGLE_REV_GRAPH:
342 case REQ_TOGGLE_REFS:
343 case REQ_TOGGLE_CHANGES:
344 case REQ_TOGGLE_IGNORE_SPACE:
345 case REQ_TOGGLE_ID:
346 case REQ_TOGGLE_FILES:
347 case REQ_TOGGLE_TITLE_OVERFLOW:
348 case REQ_TOGGLE_FILE_SIZE:
349 case REQ_TOGGLE_UNTRACKED_DIRS:
350 case REQ_TOGGLE_VERTICAL_SPLIT:
352 char action[SIZEOF_STR] = "";
353 enum view_flag flags = toggle_option(view, request, action);
355 if (flags == VIEW_FLAG_RESET_DISPLAY) {
356 resize_display();
357 redraw_display(TRUE);
358 } else {
359 foreach_displayed_view(view, i) {
360 if (view_has_flags(view, flags) && !view->unrefreshable)
361 reload_view(view);
362 else
363 redraw_view(view);
367 if (*action)
368 report("%s", action);
370 break;
372 case REQ_TOGGLE_SORT_FIELD:
373 case REQ_TOGGLE_SORT_ORDER:
374 report("Sorting is not yet supported for the %s view", view->name);
375 break;
377 case REQ_DIFF_CONTEXT_UP:
378 case REQ_DIFF_CONTEXT_DOWN:
379 report("Changing the diff context is not yet supported for the %s view", view->name);
380 break;
382 case REQ_SEARCH:
383 case REQ_SEARCH_BACK:
384 search_view(view, request);
385 break;
387 case REQ_FIND_NEXT:
388 case REQ_FIND_PREV:
389 find_next(view, request);
390 break;
392 case REQ_STOP_LOADING:
393 foreach_view(view, i) {
394 if (view->pipe)
395 report("Stopped loading the %s view", view->name),
396 end_update(view, TRUE);
398 break;
400 case REQ_SHOW_VERSION:
401 report("tig-%s (built %s)", TIG_VERSION, __DATE__);
402 return TRUE;
404 case REQ_SCREEN_REDRAW:
405 redraw_display(TRUE);
406 break;
408 case REQ_EDIT:
409 report("Nothing to edit");
410 break;
412 case REQ_ENTER:
413 report("Nothing to enter");
414 break;
416 case REQ_VIEW_CLOSE:
417 /* XXX: Mark closed views by letting view->prev point to the
418 * view itself. Parents to closed view should never be
419 * followed. */
420 if (view->prev && view->prev != view) {
421 maximize_view(view->prev, TRUE);
422 view->prev = view;
423 break;
425 /* Fall-through */
426 case REQ_QUIT:
427 return FALSE;
429 default:
430 report("Unknown key, press %s for help",
431 get_view_key(view, REQ_VIEW_HELP));
432 return TRUE;
435 return TRUE;
439 * Main
442 static const char usage_string[] =
443 "tig " TIG_VERSION " (" __DATE__ ")\n"
444 "\n"
445 "Usage: tig [options] [revs] [--] [paths]\n"
446 " or: tig log [options] [revs] [--] [paths]\n"
447 " or: tig show [options] [revs] [--] [paths]\n"
448 " or: tig blame [options] [rev] [--] path\n"
449 " or: tig stash\n"
450 " or: tig status\n"
451 " or: tig < [git command output]\n"
452 "\n"
453 "Options:\n"
454 " +<number> Select line <number> in the first view\n"
455 " -v, --version Show version and exit\n"
456 " -h, --help Show help message and exit";
458 void
459 usage(const char *message)
461 die("%s\n\n%s", message, usage_string);
464 static int
465 read_filter_args(char *name, size_t namelen, char *value, size_t valuelen, void *data)
467 const char ***filter_args = data;
469 return argv_append(filter_args, name) ? OK : ERR;
472 static void
473 filter_rev_parse(const char ***args, const char *arg1, const char *arg2, const char *argv[])
475 const char *rev_parse_argv[SIZEOF_ARG] = { "git", "rev-parse", arg1, arg2 };
476 const char **all_argv = NULL;
478 if (!argv_append_array(&all_argv, rev_parse_argv) ||
479 !argv_append_array(&all_argv, argv) ||
480 io_run_load(all_argv, "\n", read_filter_args, args) == ERR)
481 die("Failed to split arguments");
482 argv_free(all_argv);
483 free(all_argv);
486 static bool
487 is_rev_flag(const char *flag)
489 static const char *rev_flags[] = { GIT_REV_FLAGS };
490 int i;
492 for (i = 0; i < ARRAY_SIZE(rev_flags); i++)
493 if (!strcmp(flag, rev_flags[i]))
494 return TRUE;
496 return FALSE;
499 static void
500 filter_options(const char *argv[])
502 const char **flags = NULL;
503 int next, flags_pos;
505 update_options_from_argv(argv);
507 filter_rev_parse(&opt_file_argv, "--no-revs", "--no-flags", argv);
508 filter_rev_parse(&flags, "--flags", "--no-revs", argv);
510 if (flags) {
511 for (next = flags_pos = 0; flags && flags[next]; next++) {
512 const char *flag = flags[next];
514 if (is_rev_flag(flag))
515 argv_append(&opt_rev_argv, flag);
516 else
517 flags[flags_pos++] = flag;
520 flags[flags_pos] = NULL;
522 opt_cmdline_argv = flags;
525 filter_rev_parse(&opt_rev_argv, "--symbolic", "--revs-only", argv);
528 static enum request
529 parse_options(int argc, const char *argv[], bool pager_mode)
531 enum request request;
532 const char *subcommand;
533 bool seen_dashdash = FALSE;
534 const char **filter_argv = NULL;
535 int i;
537 request = pager_mode ? REQ_VIEW_PAGER : REQ_VIEW_MAIN;
539 if (argc <= 1)
540 return request;
542 subcommand = argv[1];
543 if (!strcmp(subcommand, "status")) {
544 request = REQ_VIEW_STATUS;
546 } else if (!strcmp(subcommand, "blame")) {
547 request = REQ_VIEW_BLAME;
549 } else if (!strcmp(subcommand, "show")) {
550 request = REQ_VIEW_DIFF;
552 } else if (!strcmp(subcommand, "log")) {
553 request = REQ_VIEW_LOG;
555 } else if (!strcmp(subcommand, "stash")) {
556 request = REQ_VIEW_STASH;
558 } else {
559 subcommand = NULL;
562 for (i = 1 + !!subcommand; i < argc; i++) {
563 const char *opt = argv[i];
565 // stop parsing our options after -- and let rev-parse handle the rest
566 if (!seen_dashdash) {
567 if (!strcmp(opt, "--")) {
568 seen_dashdash = TRUE;
569 continue;
571 } else if (!strcmp(opt, "-v") || !strcmp(opt, "--version")) {
572 printf("tig version %s\n", TIG_VERSION);
573 exit(EXIT_SUCCESS);
575 } else if (!strcmp(opt, "-h") || !strcmp(opt, "--help")) {
576 printf("%s\n", usage_string);
577 exit(EXIT_SUCCESS);
579 } else if (strlen(opt) >= 2 && *opt == '+' && string_isnumber(opt + 1)) {
580 int lineno = atoi(opt + 1);
582 view_env.lineno = lineno > 0 ? lineno - 1 : 0;
583 continue;
588 if (!argv_append(&filter_argv, opt))
589 die("command too long");
592 if (filter_argv)
593 filter_options(filter_argv);
595 return request;
598 static enum request
599 open_pager_mode(enum request request)
601 enum open_flags flags = OPEN_DEFAULT;
603 if (request == REQ_VIEW_PAGER) {
604 /* Detect if the user requested the main view. */
605 if (argv_contains(opt_rev_argv, "--stdin")) {
606 request = REQ_VIEW_MAIN;
607 flags |= OPEN_FORWARD_STDIN;
608 } else if (argv_contains(opt_cmdline_argv, "--pretty=raw")) {
609 request = REQ_VIEW_MAIN;
610 flags |= OPEN_STDIN;
611 } else {
612 flags |= OPEN_STDIN;
615 } else if (request == REQ_VIEW_DIFF) {
616 if (argv_contains(opt_rev_argv, "--stdin"))
617 flags |= OPEN_FORWARD_STDIN;
620 /* Open the requested view even if the pager mode is enabled so
621 * the warning message below is displayed correctly. */
622 open_view(NULL, request, flags);
624 if (!open_in_pager_mode(flags)) {
625 close(STDIN_FILENO);
626 report("Ignoring stdin.");
629 return REQ_NONE;
632 static enum request
633 run_prompt_command(struct view *view, char *cmd)
635 enum request request;
637 if (cmd && string_isnumber(cmd)) {
638 int lineno = view->pos.lineno + 1;
640 if (parse_int(&lineno, cmd, 1, view->lines + 1) == SUCCESS) {
641 select_view_line(view, lineno - 1);
642 report_clear();
643 } else {
644 report("Unable to parse '%s' as a line number", cmd);
646 } else if (cmd && iscommit(cmd)) {
647 string_ncopy(view->env->search, cmd, strlen(cmd));
649 request = view_request(view, REQ_JUMP_COMMIT);
650 if (request == REQ_JUMP_COMMIT) {
651 report("Jumping to commits is not supported by the '%s' view", view->name);
654 } else if (cmd && strlen(cmd) == 1) {
655 request = get_keybinding(&view->ops->keymap, cmd[0]);
656 return request;
658 } else if (cmd && cmd[0] == '!') {
659 struct view *next = VIEW(REQ_VIEW_PAGER);
660 const char *argv[SIZEOF_ARG];
661 int argc = 0;
663 cmd++;
664 /* When running random commands, initially show the
665 * command in the title. However, it maybe later be
666 * overwritten if a commit line is selected. */
667 string_ncopy(next->ref, cmd, strlen(cmd));
669 if (!argv_from_string(argv, &argc, cmd)) {
670 report("Too many arguments");
671 } else if (!format_argv(view->env, &next->argv, argv, FALSE, TRUE)) {
672 report("Argument formatting failed");
673 } else {
674 next->dir = NULL;
675 open_view(view, REQ_VIEW_PAGER, OPEN_PREPARED);
678 } else if (cmd) {
679 request = get_request(cmd);
680 if (request != REQ_UNKNOWN)
681 return request;
683 char *args = strchr(cmd, ' ');
684 if (args) {
685 *args++ = 0;
686 if (set_option(cmd, args) == SUCCESS) {
687 request = !view->unrefreshable ? REQ_REFRESH : REQ_SCREEN_REDRAW;
688 if (!strcmp(cmd, "color"))
689 init_colors();
692 return request;
694 return REQ_NONE;
697 #ifdef NCURSES_MOUSE_VERSION
698 static struct view *
699 find_clicked_view(MEVENT *event)
701 struct view *view;
702 int i;
704 foreach_displayed_view (view, i) {
705 int beg_y = 0, beg_x = 0;
707 getbegyx(view->win, beg_y, beg_x);
709 if (beg_y <= event->y && event->y < beg_y + view->height
710 && beg_x <= event->x && event->x < beg_x + view->width) {
711 if (i != current_view) {
712 current_view = i;
714 return view;
718 return NULL;
721 static enum request
722 handle_mouse_event(void)
724 MEVENT event;
725 struct view *view;
727 if (getmouse(&event) != OK)
728 return REQ_NONE;
730 view = find_clicked_view(&event);
731 if (!view)
732 return REQ_NONE;
734 if (event.bstate & BUTTON2_PRESSED)
735 return REQ_SCROLL_WHEEL_DOWN;
737 if (event.bstate & BUTTON4_PRESSED)
738 return REQ_SCROLL_WHEEL_UP;
740 if (event.bstate & BUTTON1_PRESSED) {
741 if (event.y == view->pos.lineno - view->pos.offset) {
742 /* Click is on the same line, perform an "ENTER" */
743 return REQ_ENTER;
745 } else {
746 int y = getbegy(view->win);
747 unsigned long lineno = (event.y - y) + view->pos.offset;
749 select_view_line(view, lineno);
750 update_view_title(view);
751 report_clear();
755 return REQ_NONE;
757 #endif
760 main(int argc, const char *argv[])
762 const char *codeset = ENCODING_UTF8;
763 bool pager_mode = !isatty(STDIN_FILENO);
764 enum request request = parse_options(argc, argv, pager_mode);
765 struct view *view;
766 int i;
768 signal(SIGPIPE, SIG_IGN);
770 if (setlocale(LC_ALL, "")) {
771 codeset = nl_langinfo(CODESET);
774 foreach_view(view, i) {
775 add_keymap(&view->ops->keymap);
778 if (load_repo_info() == ERR)
779 die("Failed to load repo info.");
781 if (load_options() == ERR)
782 die("Failed to load user config.");
784 if (load_git_config() == ERR)
785 die("Failed to load repo config.");
787 /* Require a git repository unless when running in pager mode. */
788 if (!repo.git_dir[0] && request != REQ_VIEW_PAGER)
789 die("Not a git repository");
791 if (codeset && strcmp(codeset, ENCODING_UTF8)) {
792 char translit[SIZEOF_STR];
794 if (string_format(translit, "%s%s", codeset, ICONV_TRANSLIT))
795 opt_iconv_out = iconv_open(translit, ENCODING_UTF8);
796 else
797 opt_iconv_out = iconv_open(codeset, ENCODING_UTF8);
798 if (opt_iconv_out == ICONV_NONE)
799 die("Failed to initialize character set conversion");
802 if (load_refs(FALSE) == ERR)
803 die("Failed to load refs.");
805 init_display();
807 if (pager_mode)
808 request = open_pager_mode(request);
810 while (view_driver(display[current_view], request)) {
811 int key = get_input(0);
813 #ifdef NCURSES_MOUSE_VERSION
814 if (key == KEY_MOUSE) {
815 request = handle_mouse_event();
816 continue;
818 #endif
820 if (key == KEY_ESC)
821 key = get_input(0) + 0x80;
823 view = display[current_view];
824 request = get_keybinding(&view->ops->keymap, key);
826 /* Some low-level request handling. This keeps access to
827 * status_win restricted. */
828 switch (request) {
829 case REQ_NONE:
830 report("Unknown key, press %s for help",
831 get_view_key(view, REQ_VIEW_HELP));
832 break;
833 case REQ_PROMPT:
835 char *cmd = read_prompt(":");
836 request = run_prompt_command(view, cmd);
837 break;
839 case REQ_SEARCH:
840 case REQ_SEARCH_BACK:
842 const char *prompt = request == REQ_SEARCH ? "/" : "?";
843 char *search = read_prompt(prompt);
845 if (search)
846 string_ncopy(view_env.search, search, strlen(search));
847 else if (*view_env.search)
848 request = request == REQ_SEARCH ?
849 REQ_FIND_NEXT :
850 REQ_FIND_PREV;
851 else
852 request = REQ_NONE;
853 break;
855 default:
856 break;
860 exit(EXIT_SUCCESS);
862 return 0;
865 /* vim: set ts=8 sw=8 noexpandtab: */