Initialize status_empty flag to FALSE
[tig] / tig.c
1 /* Copyright (c) 2006-2009 Jonas Fonseca <fonseca@diku.dk>
2  *
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.
7  *
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.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #ifndef TIG_VERSION
19 #define TIG_VERSION "unknown-version"
20 #endif
21
22 #ifndef DEBUG
23 #define NDEBUG
24 #endif
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <signal.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <sys/stat.h>
37 #include <sys/select.h>
38 #include <unistd.h>
39 #include <time.h>
40 #include <fcntl.h>
41
42 #include <regex.h>
43
44 #include <locale.h>
45 #include <langinfo.h>
46 #include <iconv.h>
47
48 /* ncurses(3): Must be defined to have extended wide-character functions. */
49 #define _XOPEN_SOURCE_EXTENDED
50
51 #ifdef HAVE_NCURSESW_NCURSES_H
52 #include <ncursesw/ncurses.h>
53 #else
54 #ifdef HAVE_NCURSES_NCURSES_H
55 #include <ncurses/ncurses.h>
56 #else
57 #include <ncurses.h>
58 #endif
59 #endif
60
61 #if __GNUC__ >= 3
62 #define __NORETURN __attribute__((__noreturn__))
63 #else
64 #define __NORETURN
65 #endif
66
67 static void __NORETURN die(const char *err, ...);
68 static void warn(const char *msg, ...);
69 static void report(const char *msg, ...);
70 static void set_nonblocking_input(bool loading);
71 static size_t utf8_length(const char *string, int *width, size_t max_width, int *trimmed, bool reserve);
72 static int load_refs(void);
73
74 #define ABS(x)          ((x) >= 0  ? (x) : -(x))
75 #define MIN(x, y)       ((x) < (y) ? (x) :  (y))
76
77 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof(x[0]))
78 #define STRING_SIZE(x)  (sizeof(x) - 1)
79
80 #define SIZEOF_STR      1024    /* Default string size. */
81 #define SIZEOF_REF      256     /* Size of symbolic or SHA1 ID. */
82 #define SIZEOF_REV      41      /* Holds a SHA-1 and an ending NUL. */
83 #define SIZEOF_ARG      32      /* Default argument array size. */
84
85 /* Revision graph */
86
87 #define REVGRAPH_INIT   'I'
88 #define REVGRAPH_MERGE  'M'
89 #define REVGRAPH_BRANCH '+'
90 #define REVGRAPH_COMMIT '*'
91 #define REVGRAPH_BOUND  '^'
92
93 #define SIZEOF_REVGRAPH 19      /* Size of revision ancestry graphics. */
94
95 /* This color name can be used to refer to the default term colors. */
96 #define COLOR_DEFAULT   (-1)
97
98 #define ICONV_NONE      ((iconv_t) -1)
99 #ifndef ICONV_CONST
100 #define ICONV_CONST     /* nothing */
101 #endif
102
103 /* The format and size of the date column in the main view. */
104 #define DATE_FORMAT     "%Y-%m-%d %H:%M"
105 #define DATE_COLS       STRING_SIZE("2006-04-29 14:21 ")
106
107 #define AUTHOR_COLS     20
108 #define ID_COLS         8
109
110 /* The default interval between line numbers. */
111 #define NUMBER_INTERVAL 5
112
113 #define TAB_SIZE        8
114
115 #define SCALE_SPLIT_VIEW(height)        ((height) * 2 / 3)
116
117 #define NULL_ID         "0000000000000000000000000000000000000000"
118
119 #ifndef GIT_CONFIG
120 #define GIT_CONFIG "config"
121 #endif
122
123 /* Some ascii-shorthands fitted into the ncurses namespace. */
124 #define KEY_TAB         '\t'
125 #define KEY_RETURN      '\r'
126 #define KEY_ESC         27
127
128
129 struct ref {
130         char *name;             /* Ref name; tag or head names are shortened. */
131         char id[SIZEOF_REV];    /* Commit SHA1 ID */
132         unsigned int head:1;    /* Is it the current HEAD? */
133         unsigned int tag:1;     /* Is it a tag? */
134         unsigned int ltag:1;    /* If so, is the tag local? */
135         unsigned int remote:1;  /* Is it a remote ref? */
136         unsigned int tracked:1; /* Is it the remote for the current HEAD? */
137         unsigned int next:1;    /* For ref lists: are there more refs? */
138 };
139
140 static struct ref **get_refs(const char *id);
141
142 enum format_flags {
143         FORMAT_ALL,             /* Perform replacement in all arguments. */
144         FORMAT_DASH,            /* Perform replacement up until "--". */
145         FORMAT_NONE             /* No replacement should be performed. */
146 };
147
148 static bool format_argv(const char *dst[], const char *src[], enum format_flags flags);
149
150 struct int_map {
151         const char *name;
152         int namelen;
153         int value;
154 };
155
156 static int
157 set_from_int_map(struct int_map *map, size_t map_size,
158                  int *value, const char *name, int namelen)
159 {
160
161         int i;
162
163         for (i = 0; i < map_size; i++)
164                 if (namelen == map[i].namelen &&
165                     !strncasecmp(name, map[i].name, namelen)) {
166                         *value = map[i].value;
167                         return OK;
168                 }
169
170         return ERR;
171 }
172
173 enum input_status {
174         INPUT_OK,
175         INPUT_SKIP,
176         INPUT_STOP,
177         INPUT_CANCEL
178 };
179
180 typedef enum input_status (*input_handler)(void *data, char *buf, int c);
181
182 static char *prompt_input(const char *prompt, input_handler handler, void *data);
183 static bool prompt_yesno(const char *prompt);
184
185 /*
186  * String helpers
187  */
188
189 static inline void
190 string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
191 {
192         if (srclen > dstlen - 1)
193                 srclen = dstlen - 1;
194
195         strncpy(dst, src, srclen);
196         dst[srclen] = 0;
197 }
198
199 /* Shorthands for safely copying into a fixed buffer. */
200
201 #define string_copy(dst, src) \
202         string_ncopy_do(dst, sizeof(dst), src, sizeof(src))
203
204 #define string_ncopy(dst, src, srclen) \
205         string_ncopy_do(dst, sizeof(dst), src, srclen)
206
207 #define string_copy_rev(dst, src) \
208         string_ncopy_do(dst, SIZEOF_REV, src, SIZEOF_REV - 1)
209
210 #define string_add(dst, from, src) \
211         string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
212
213 static char *
214 chomp_string(char *name)
215 {
216         int namelen;
217
218         while (isspace(*name))
219                 name++;
220
221         namelen = strlen(name) - 1;
222         while (namelen > 0 && isspace(name[namelen]))
223                 name[namelen--] = 0;
224
225         return name;
226 }
227
228 static bool
229 string_nformat(char *buf, size_t bufsize, size_t *bufpos, const char *fmt, ...)
230 {
231         va_list args;
232         size_t pos = bufpos ? *bufpos : 0;
233
234         va_start(args, fmt);
235         pos += vsnprintf(buf + pos, bufsize - pos, fmt, args);
236         va_end(args);
237
238         if (bufpos)
239                 *bufpos = pos;
240
241         return pos >= bufsize ? FALSE : TRUE;
242 }
243
244 #define string_format(buf, fmt, args...) \
245         string_nformat(buf, sizeof(buf), NULL, fmt, args)
246
247 #define string_format_from(buf, from, fmt, args...) \
248         string_nformat(buf, sizeof(buf), from, fmt, args)
249
250 static int
251 string_enum_compare(const char *str1, const char *str2, int len)
252 {
253         size_t i;
254
255 #define string_enum_sep(x) ((x) == '-' || (x) == '_' || (x) == '.')
256
257         /* Diff-Header == DIFF_HEADER */
258         for (i = 0; i < len; i++) {
259                 if (toupper(str1[i]) == toupper(str2[i]))
260                         continue;
261
262                 if (string_enum_sep(str1[i]) &&
263                     string_enum_sep(str2[i]))
264                         continue;
265
266                 return str1[i] - str2[i];
267         }
268
269         return 0;
270 }
271
272 #define prefixcmp(str1, str2) \
273         strncmp(str1, str2, STRING_SIZE(str2))
274
275 static inline int
276 suffixcmp(const char *str, int slen, const char *suffix)
277 {
278         size_t len = slen >= 0 ? slen : strlen(str);
279         size_t suffixlen = strlen(suffix);
280
281         return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
282 }
283
284
285 static bool
286 argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
287 {
288         int valuelen;
289
290         while (*cmd && *argc < SIZEOF_ARG && (valuelen = strcspn(cmd, " \t"))) {
291                 bool advance = cmd[valuelen] != 0;
292
293                 cmd[valuelen] = 0;
294                 argv[(*argc)++] = chomp_string(cmd);
295                 cmd += valuelen + advance;
296         }
297
298         if (*argc < SIZEOF_ARG)
299                 argv[*argc] = NULL;
300         return *argc < SIZEOF_ARG;
301 }
302
303 static void
304 argv_from_env(const char **argv, const char *name)
305 {
306         char *env = argv ? getenv(name) : NULL;
307         int argc = 0;
308
309         if (env && *env)
310                 env = strdup(env);
311         if (env && !argv_from_string(argv, &argc, env))
312                 die("Too many arguments in the `%s` environment variable", name);
313 }
314
315
316 /*
317  * Executing external commands.
318  */
319
320 enum io_type {
321         IO_FD,                  /* File descriptor based IO. */
322         IO_BG,                  /* Execute command in the background. */
323         IO_FG,                  /* Execute command with same std{in,out,err}. */
324         IO_RD,                  /* Read only fork+exec IO. */
325         IO_WR,                  /* Write only fork+exec IO. */
326         IO_AP,                  /* Append fork+exec output to file. */
327 };
328
329 struct io {
330         enum io_type type;      /* The requested type of pipe. */
331         const char *dir;        /* Directory from which to execute. */
332         pid_t pid;              /* Pipe for reading or writing. */
333         int pipe;               /* Pipe end for reading or writing. */
334         int error;              /* Error status. */
335         const char *argv[SIZEOF_ARG];   /* Shell command arguments. */
336         char *buf;              /* Read buffer. */
337         size_t bufalloc;        /* Allocated buffer size. */
338         size_t bufsize;         /* Buffer content size. */
339         char *bufpos;           /* Current buffer position. */
340         unsigned int eof:1;     /* Has end of file been reached. */
341 };
342
343 static void
344 reset_io(struct io *io)
345 {
346         io->pipe = -1;
347         io->pid = 0;
348         io->buf = io->bufpos = NULL;
349         io->bufalloc = io->bufsize = 0;
350         io->error = 0;
351         io->eof = 0;
352 }
353
354 static void
355 init_io(struct io *io, const char *dir, enum io_type type)
356 {
357         reset_io(io);
358         io->type = type;
359         io->dir = dir;
360 }
361
362 static bool
363 init_io_rd(struct io *io, const char *argv[], const char *dir,
364                 enum format_flags flags)
365 {
366         init_io(io, dir, IO_RD);
367         return format_argv(io->argv, argv, flags);
368 }
369
370 static bool
371 io_open(struct io *io, const char *name)
372 {
373         init_io(io, NULL, IO_FD);
374         io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
375         return io->pipe != -1;
376 }
377
378 static bool
379 kill_io(struct io *io)
380 {
381         return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
382 }
383
384 static bool
385 done_io(struct io *io)
386 {
387         pid_t pid = io->pid;
388
389         if (io->pipe != -1)
390                 close(io->pipe);
391         free(io->buf);
392         reset_io(io);
393
394         while (pid > 0) {
395                 int status;
396                 pid_t waiting = waitpid(pid, &status, 0);
397
398                 if (waiting < 0) {
399                         if (errno == EINTR)
400                                 continue;
401                         report("waitpid failed (%s)", strerror(errno));
402                         return FALSE;
403                 }
404
405                 return waiting == pid &&
406                        !WIFSIGNALED(status) &&
407                        WIFEXITED(status) &&
408                        !WEXITSTATUS(status);
409         }
410
411         return TRUE;
412 }
413
414 static bool
415 start_io(struct io *io)
416 {
417         int pipefds[2] = { -1, -1 };
418
419         if (io->type == IO_FD)
420                 return TRUE;
421
422         if ((io->type == IO_RD || io->type == IO_WR) &&
423             pipe(pipefds) < 0)
424                 return FALSE;
425         else if (io->type == IO_AP)
426                 pipefds[1] = io->pipe;
427
428         if ((io->pid = fork())) {
429                 if (pipefds[!(io->type == IO_WR)] != -1)
430                         close(pipefds[!(io->type == IO_WR)]);
431                 if (io->pid != -1) {
432                         io->pipe = pipefds[!!(io->type == IO_WR)];
433                         return TRUE;
434                 }
435
436         } else {
437                 if (io->type != IO_FG) {
438                         int devnull = open("/dev/null", O_RDWR);
439                         int readfd  = io->type == IO_WR ? pipefds[0] : devnull;
440                         int writefd = (io->type == IO_RD || io->type == IO_AP)
441                                                         ? pipefds[1] : devnull;
442
443                         dup2(readfd,  STDIN_FILENO);
444                         dup2(writefd, STDOUT_FILENO);
445                         dup2(devnull, STDERR_FILENO);
446
447                         close(devnull);
448                         if (pipefds[0] != -1)
449                                 close(pipefds[0]);
450                         if (pipefds[1] != -1)
451                                 close(pipefds[1]);
452                 }
453
454                 if (io->dir && *io->dir && chdir(io->dir) == -1)
455                         die("Failed to change directory: %s", strerror(errno));
456
457                 execvp(io->argv[0], (char *const*) io->argv);
458                 die("Failed to execute program: %s", strerror(errno));
459         }
460
461         if (pipefds[!!(io->type == IO_WR)] != -1)
462                 close(pipefds[!!(io->type == IO_WR)]);
463         return FALSE;
464 }
465
466 static bool
467 run_io(struct io *io, const char **argv, const char *dir, enum io_type type)
468 {
469         init_io(io, dir, type);
470         if (!format_argv(io->argv, argv, FORMAT_NONE))
471                 return FALSE;
472         return start_io(io);
473 }
474
475 static int
476 run_io_do(struct io *io)
477 {
478         return start_io(io) && done_io(io);
479 }
480
481 static int
482 run_io_bg(const char **argv)
483 {
484         struct io io = {};
485
486         init_io(&io, NULL, IO_BG);
487         if (!format_argv(io.argv, argv, FORMAT_NONE))
488                 return FALSE;
489         return run_io_do(&io);
490 }
491
492 static bool
493 run_io_fg(const char **argv, const char *dir)
494 {
495         struct io io = {};
496
497         init_io(&io, dir, IO_FG);
498         if (!format_argv(io.argv, argv, FORMAT_NONE))
499                 return FALSE;
500         return run_io_do(&io);
501 }
502
503 static bool
504 run_io_append(const char **argv, enum format_flags flags, int fd)
505 {
506         struct io io = {};
507
508         init_io(&io, NULL, IO_AP);
509         io.pipe = fd;
510         if (format_argv(io.argv, argv, flags))
511                 return run_io_do(&io);
512         close(fd);
513         return FALSE;
514 }
515
516 static bool
517 run_io_rd(struct io *io, const char **argv, enum format_flags flags)
518 {
519         return init_io_rd(io, argv, NULL, flags) && start_io(io);
520 }
521
522 static bool
523 io_eof(struct io *io)
524 {
525         return io->eof;
526 }
527
528 static int
529 io_error(struct io *io)
530 {
531         return io->error;
532 }
533
534 static bool
535 io_strerror(struct io *io)
536 {
537         return strerror(io->error);
538 }
539
540 static bool
541 io_can_read(struct io *io)
542 {
543         struct timeval tv = { 0, 500 };
544         fd_set fds;
545
546         FD_ZERO(&fds);
547         FD_SET(io->pipe, &fds);
548
549         return select(io->pipe + 1, &fds, NULL, NULL, &tv) > 0;
550 }
551
552 static ssize_t
553 io_read(struct io *io, void *buf, size_t bufsize)
554 {
555         do {
556                 ssize_t readsize = read(io->pipe, buf, bufsize);
557
558                 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
559                         continue;
560                 else if (readsize == -1)
561                         io->error = errno;
562                 else if (readsize == 0)
563                         io->eof = 1;
564                 return readsize;
565         } while (1);
566 }
567
568 static char *
569 io_get(struct io *io, int c, bool can_read)
570 {
571         char *eol;
572         ssize_t readsize;
573
574         if (!io->buf) {
575                 io->buf = io->bufpos = malloc(BUFSIZ);
576                 if (!io->buf)
577                         return NULL;
578                 io->bufalloc = BUFSIZ;
579                 io->bufsize = 0;
580         }
581
582         while (TRUE) {
583                 if (io->bufsize > 0) {
584                         eol = memchr(io->bufpos, c, io->bufsize);
585                         if (eol) {
586                                 char *line = io->bufpos;
587
588                                 *eol = 0;
589                                 io->bufpos = eol + 1;
590                                 io->bufsize -= io->bufpos - line;
591                                 return line;
592                         }
593                 }
594
595                 if (io_eof(io)) {
596                         if (io->bufsize) {
597                                 io->bufpos[io->bufsize] = 0;
598                                 io->bufsize = 0;
599                                 return io->bufpos;
600                         }
601                         return NULL;
602                 }
603
604                 if (!can_read)
605                         return NULL;
606
607                 if (io->bufsize > 0 && io->bufpos > io->buf)
608                         memmove(io->buf, io->bufpos, io->bufsize);
609
610                 io->bufpos = io->buf;
611                 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
612                 if (io_error(io))
613                         return NULL;
614                 io->bufsize += readsize;
615         }
616 }
617
618 static bool
619 io_write(struct io *io, const void *buf, size_t bufsize)
620 {
621         size_t written = 0;
622
623         while (!io_error(io) && written < bufsize) {
624                 ssize_t size;
625
626                 size = write(io->pipe, buf + written, bufsize - written);
627                 if (size < 0 && (errno == EAGAIN || errno == EINTR))
628                         continue;
629                 else if (size == -1)
630                         io->error = errno;
631                 else
632                         written += size;
633         }
634
635         return written == bufsize;
636 }
637
638 static bool
639 run_io_buf(const char **argv, char buf[], size_t bufsize)
640 {
641         struct io io = {};
642         bool error;
643
644         if (!run_io_rd(&io, argv, FORMAT_NONE))
645                 return FALSE;
646
647         io.buf = io.bufpos = buf;
648         io.bufalloc = bufsize;
649         error = !io_get(&io, '\n', TRUE) && io_error(&io);
650         io.buf = NULL;
651
652         return done_io(&io) || error;
653 }
654
655 static int read_properties(struct io *io, const char *separators, int (*read)(char *, size_t, char *, size_t));
656
657 /*
658  * User requests
659  */
660
661 #define REQ_INFO \
662         /* XXX: Keep the view request first and in sync with views[]. */ \
663         REQ_GROUP("View switching") \
664         REQ_(VIEW_MAIN,         "Show main view"), \
665         REQ_(VIEW_DIFF,         "Show diff view"), \
666         REQ_(VIEW_LOG,          "Show log view"), \
667         REQ_(VIEW_TREE,         "Show tree view"), \
668         REQ_(VIEW_BLOB,         "Show blob view"), \
669         REQ_(VIEW_BLAME,        "Show blame view"), \
670         REQ_(VIEW_HELP,         "Show help page"), \
671         REQ_(VIEW_PAGER,        "Show pager view"), \
672         REQ_(VIEW_STATUS,       "Show status view"), \
673         REQ_(VIEW_STAGE,        "Show stage view"), \
674         \
675         REQ_GROUP("View manipulation") \
676         REQ_(ENTER,             "Enter current line and scroll"), \
677         REQ_(NEXT,              "Move to next"), \
678         REQ_(PREVIOUS,          "Move to previous"), \
679         REQ_(PARENT,            "Move to parent"), \
680         REQ_(VIEW_NEXT,         "Move focus to next view"), \
681         REQ_(REFRESH,           "Reload and refresh"), \
682         REQ_(MAXIMIZE,          "Maximize the current view"), \
683         REQ_(VIEW_CLOSE,        "Close the current view"), \
684         REQ_(QUIT,              "Close all views and quit"), \
685         \
686         REQ_GROUP("View specific requests") \
687         REQ_(STATUS_UPDATE,     "Update file status"), \
688         REQ_(STATUS_REVERT,     "Revert file changes"), \
689         REQ_(STATUS_MERGE,      "Merge file using external tool"), \
690         REQ_(STAGE_NEXT,        "Find next chunk to stage"), \
691         \
692         REQ_GROUP("Cursor navigation") \
693         REQ_(MOVE_UP,           "Move cursor one line up"), \
694         REQ_(MOVE_DOWN,         "Move cursor one line down"), \
695         REQ_(MOVE_PAGE_DOWN,    "Move cursor one page down"), \
696         REQ_(MOVE_PAGE_UP,      "Move cursor one page up"), \
697         REQ_(MOVE_FIRST_LINE,   "Move cursor to first line"), \
698         REQ_(MOVE_LAST_LINE,    "Move cursor to last line"), \
699         \
700         REQ_GROUP("Scrolling") \
701         REQ_(SCROLL_LINE_UP,    "Scroll one line up"), \
702         REQ_(SCROLL_LINE_DOWN,  "Scroll one line down"), \
703         REQ_(SCROLL_PAGE_UP,    "Scroll one page up"), \
704         REQ_(SCROLL_PAGE_DOWN,  "Scroll one page down"), \
705         \
706         REQ_GROUP("Searching") \
707         REQ_(SEARCH,            "Search the view"), \
708         REQ_(SEARCH_BACK,       "Search backwards in the view"), \
709         REQ_(FIND_NEXT,         "Find next search match"), \
710         REQ_(FIND_PREV,         "Find previous search match"), \
711         \
712         REQ_GROUP("Option manipulation") \
713         REQ_(TOGGLE_LINENO,     "Toggle line numbers"), \
714         REQ_(TOGGLE_DATE,       "Toggle date display"), \
715         REQ_(TOGGLE_AUTHOR,     "Toggle author display"), \
716         REQ_(TOGGLE_REV_GRAPH,  "Toggle revision graph visualization"), \
717         REQ_(TOGGLE_REFS,       "Toggle reference display (tags/branches)"), \
718         \
719         REQ_GROUP("Misc") \
720         REQ_(PROMPT,            "Bring up the prompt"), \
721         REQ_(SCREEN_REDRAW,     "Redraw the screen"), \
722         REQ_(SHOW_VERSION,      "Show version information"), \
723         REQ_(STOP_LOADING,      "Stop all loading views"), \
724         REQ_(EDIT,              "Open in editor"), \
725         REQ_(NONE,              "Do nothing")
726
727
728 /* User action requests. */
729 enum request {
730 #define REQ_GROUP(help)
731 #define REQ_(req, help) REQ_##req
732
733         /* Offset all requests to avoid conflicts with ncurses getch values. */
734         REQ_OFFSET = KEY_MAX + 1,
735         REQ_INFO
736
737 #undef  REQ_GROUP
738 #undef  REQ_
739 };
740
741 struct request_info {
742         enum request request;
743         const char *name;
744         int namelen;
745         const char *help;
746 };
747
748 static struct request_info req_info[] = {
749 #define REQ_GROUP(help) { 0, NULL, 0, (help) },
750 #define REQ_(req, help) { REQ_##req, (#req), STRING_SIZE(#req), (help) }
751         REQ_INFO
752 #undef  REQ_GROUP
753 #undef  REQ_
754 };
755
756 static enum request
757 get_request(const char *name)
758 {
759         int namelen = strlen(name);
760         int i;
761
762         for (i = 0; i < ARRAY_SIZE(req_info); i++)
763                 if (req_info[i].namelen == namelen &&
764                     !string_enum_compare(req_info[i].name, name, namelen))
765                         return req_info[i].request;
766
767         return REQ_NONE;
768 }
769
770
771 /*
772  * Options
773  */
774
775 static const char usage[] =
776 "tig " TIG_VERSION " (" __DATE__ ")\n"
777 "\n"
778 "Usage: tig        [options] [revs] [--] [paths]\n"
779 "   or: tig show   [options] [revs] [--] [paths]\n"
780 "   or: tig blame  [rev] path\n"
781 "   or: tig status\n"
782 "   or: tig <      [git command output]\n"
783 "\n"
784 "Options:\n"
785 "  -v, --version   Show version and exit\n"
786 "  -h, --help      Show help message and exit";
787
788 /* Option and state variables. */
789 static bool opt_date                    = TRUE;
790 static bool opt_author                  = TRUE;
791 static bool opt_line_number             = FALSE;
792 static bool opt_line_graphics           = TRUE;
793 static bool opt_rev_graph               = FALSE;
794 static bool opt_show_refs               = TRUE;
795 static int opt_num_interval             = NUMBER_INTERVAL;
796 static int opt_tab_size                 = TAB_SIZE;
797 static int opt_author_cols              = AUTHOR_COLS-1;
798 static char opt_path[SIZEOF_STR]        = "";
799 static char opt_file[SIZEOF_STR]        = "";
800 static char opt_ref[SIZEOF_REF]         = "";
801 static char opt_head[SIZEOF_REF]        = "";
802 static char opt_head_rev[SIZEOF_REV]    = "";
803 static char opt_remote[SIZEOF_REF]      = "";
804 static char opt_encoding[20]            = "UTF-8";
805 static bool opt_utf8                    = TRUE;
806 static char opt_codeset[20]             = "UTF-8";
807 static iconv_t opt_iconv                = ICONV_NONE;
808 static char opt_search[SIZEOF_STR]      = "";
809 static char opt_cdup[SIZEOF_STR]        = "";
810 static char opt_prefix[SIZEOF_STR]      = "";
811 static char opt_git_dir[SIZEOF_STR]     = "";
812 static signed char opt_is_inside_work_tree      = -1; /* set to TRUE or FALSE */
813 static char opt_editor[SIZEOF_STR]      = "";
814 static FILE *opt_tty                    = NULL;
815
816 #define is_initial_commit()     (!*opt_head_rev)
817 #define is_head_commit(rev)     (!strcmp((rev), "HEAD") || !strcmp(opt_head_rev, (rev)))
818
819 static enum request
820 parse_options(int argc, const char *argv[], const char ***run_argv)
821 {
822         enum request request = REQ_VIEW_MAIN;
823         const char *subcommand;
824         bool seen_dashdash = FALSE;
825         /* XXX: This is vulnerable to the user overriding options
826          * required for the main view parser. */
827         static const char *custom_argv[SIZEOF_ARG] = {
828                 "git", "log", "--no-color", "--pretty=raw", "--parents",
829                         "--topo-order", NULL
830         };
831         int i, j = 6;
832
833         if (!isatty(STDIN_FILENO))
834                 return REQ_VIEW_PAGER;
835
836         if (argc <= 1)
837                 return REQ_VIEW_MAIN;
838
839         subcommand = argv[1];
840         if (!strcmp(subcommand, "status") || !strcmp(subcommand, "-S")) {
841                 if (!strcmp(subcommand, "-S"))
842                         warn("`-S' has been deprecated; use `tig status' instead");
843                 if (argc > 2)
844                         warn("ignoring arguments after `%s'", subcommand);
845                 return REQ_VIEW_STATUS;
846
847         } else if (!strcmp(subcommand, "blame")) {
848                 if (argc <= 2 || argc > 4)
849                         die("invalid number of options to blame\n\n%s", usage);
850
851                 i = 2;
852                 if (argc == 4) {
853                         string_ncopy(opt_ref, argv[i], strlen(argv[i]));
854                         i++;
855                 }
856
857                 string_ncopy(opt_file, argv[i], strlen(argv[i]));
858                 return REQ_VIEW_BLAME;
859
860         } else if (!strcmp(subcommand, "show")) {
861                 request = REQ_VIEW_DIFF;
862
863         } else if (!strcmp(subcommand, "log") || !strcmp(subcommand, "diff")) {
864                 request = subcommand[0] == 'l' ? REQ_VIEW_LOG : REQ_VIEW_DIFF;
865                 warn("`tig %s' has been deprecated", subcommand);
866
867         } else {
868                 subcommand = NULL;
869         }
870
871         if (subcommand) {
872                 custom_argv[1] = subcommand;
873                 j = 2;
874         }
875
876         for (i = 1 + !!subcommand; i < argc; i++) {
877                 const char *opt = argv[i];
878
879                 if (seen_dashdash || !strcmp(opt, "--")) {
880                         seen_dashdash = TRUE;
881
882                 } else if (!strcmp(opt, "-v") || !strcmp(opt, "--version")) {
883                         printf("tig version %s\n", TIG_VERSION);
884                         return REQ_NONE;
885
886                 } else if (!strcmp(opt, "-h") || !strcmp(opt, "--help")) {
887                         printf("%s\n", usage);
888                         return REQ_NONE;
889                 }
890
891                 custom_argv[j++] = opt;
892                 if (j >= ARRAY_SIZE(custom_argv))
893                         die("command too long");
894         }
895
896         custom_argv[j] = NULL;
897         *run_argv = custom_argv;
898
899         return request;
900 }
901
902
903 /*
904  * Line-oriented content detection.
905  */
906
907 #define LINE_INFO \
908 LINE(DIFF_HEADER,  "diff --git ",       COLOR_YELLOW,   COLOR_DEFAULT,  0), \
909 LINE(DIFF_CHUNK,   "@@",                COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
910 LINE(DIFF_ADD,     "+",                 COLOR_GREEN,    COLOR_DEFAULT,  0), \
911 LINE(DIFF_DEL,     "-",                 COLOR_RED,      COLOR_DEFAULT,  0), \
912 LINE(DIFF_INDEX,        "index ",         COLOR_BLUE,   COLOR_DEFAULT,  0), \
913 LINE(DIFF_OLDMODE,      "old file mode ", COLOR_YELLOW, COLOR_DEFAULT,  0), \
914 LINE(DIFF_NEWMODE,      "new file mode ", COLOR_YELLOW, COLOR_DEFAULT,  0), \
915 LINE(DIFF_COPY_FROM,    "copy from",      COLOR_YELLOW, COLOR_DEFAULT,  0), \
916 LINE(DIFF_COPY_TO,      "copy to",        COLOR_YELLOW, COLOR_DEFAULT,  0), \
917 LINE(DIFF_RENAME_FROM,  "rename from",    COLOR_YELLOW, COLOR_DEFAULT,  0), \
918 LINE(DIFF_RENAME_TO,    "rename to",      COLOR_YELLOW, COLOR_DEFAULT,  0), \
919 LINE(DIFF_SIMILARITY,   "similarity ",    COLOR_YELLOW, COLOR_DEFAULT,  0), \
920 LINE(DIFF_DISSIMILARITY,"dissimilarity ", COLOR_YELLOW, COLOR_DEFAULT,  0), \
921 LINE(DIFF_TREE,         "diff-tree ",     COLOR_BLUE,   COLOR_DEFAULT,  0), \
922 LINE(PP_AUTHOR,    "Author: ",          COLOR_CYAN,     COLOR_DEFAULT,  0), \
923 LINE(PP_COMMIT,    "Commit: ",          COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
924 LINE(PP_MERGE,     "Merge: ",           COLOR_BLUE,     COLOR_DEFAULT,  0), \
925 LINE(PP_DATE,      "Date:   ",          COLOR_YELLOW,   COLOR_DEFAULT,  0), \
926 LINE(PP_ADATE,     "AuthorDate: ",      COLOR_YELLOW,   COLOR_DEFAULT,  0), \
927 LINE(PP_CDATE,     "CommitDate: ",      COLOR_YELLOW,   COLOR_DEFAULT,  0), \
928 LINE(PP_REFS,      "Refs: ",            COLOR_RED,      COLOR_DEFAULT,  0), \
929 LINE(COMMIT,       "commit ",           COLOR_GREEN,    COLOR_DEFAULT,  0), \
930 LINE(PARENT,       "parent ",           COLOR_BLUE,     COLOR_DEFAULT,  0), \
931 LINE(TREE,         "tree ",             COLOR_BLUE,     COLOR_DEFAULT,  0), \
932 LINE(AUTHOR,       "author ",           COLOR_CYAN,     COLOR_DEFAULT,  0), \
933 LINE(COMMITTER,    "committer ",        COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
934 LINE(SIGNOFF,      "    Signed-off-by", COLOR_YELLOW,   COLOR_DEFAULT,  0), \
935 LINE(ACKED,        "    Acked-by",      COLOR_YELLOW,   COLOR_DEFAULT,  0), \
936 LINE(DEFAULT,      "",                  COLOR_DEFAULT,  COLOR_DEFAULT,  A_NORMAL), \
937 LINE(CURSOR,       "",                  COLOR_WHITE,    COLOR_GREEN,    A_BOLD), \
938 LINE(STATUS,       "",                  COLOR_GREEN,    COLOR_DEFAULT,  0), \
939 LINE(DELIMITER,    "",                  COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
940 LINE(DATE,         "",                  COLOR_BLUE,     COLOR_DEFAULT,  0), \
941 LINE(LINE_NUMBER,  "",                  COLOR_CYAN,     COLOR_DEFAULT,  0), \
942 LINE(TITLE_BLUR,   "",                  COLOR_WHITE,    COLOR_BLUE,     0), \
943 LINE(TITLE_FOCUS,  "",                  COLOR_WHITE,    COLOR_BLUE,     A_BOLD), \
944 LINE(MAIN_AUTHOR,  "",                  COLOR_GREEN,    COLOR_DEFAULT,  0), \
945 LINE(MAIN_COMMIT,  "",                  COLOR_DEFAULT,  COLOR_DEFAULT,  0), \
946 LINE(MAIN_TAG,     "",                  COLOR_MAGENTA,  COLOR_DEFAULT,  A_BOLD), \
947 LINE(MAIN_LOCAL_TAG,"",                 COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
948 LINE(MAIN_REMOTE,  "",                  COLOR_YELLOW,   COLOR_DEFAULT,  0), \
949 LINE(MAIN_TRACKED, "",                  COLOR_YELLOW,   COLOR_DEFAULT,  A_BOLD), \
950 LINE(MAIN_REF,     "",                  COLOR_CYAN,     COLOR_DEFAULT,  0), \
951 LINE(MAIN_HEAD,    "",                  COLOR_CYAN,     COLOR_DEFAULT,  A_BOLD), \
952 LINE(MAIN_REVGRAPH,"",                  COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
953 LINE(TREE_PARENT,  "",                  COLOR_DEFAULT,  COLOR_DEFAULT,  A_BOLD), \
954 LINE(TREE_MODE,    "",                  COLOR_CYAN,     COLOR_DEFAULT,  0), \
955 LINE(TREE_DIR,     "",                  COLOR_YELLOW,   COLOR_DEFAULT,  A_NORMAL), \
956 LINE(TREE_FILE,    "",                  COLOR_DEFAULT,  COLOR_DEFAULT,  A_NORMAL), \
957 LINE(STAT_HEAD,    "",                  COLOR_YELLOW,   COLOR_DEFAULT,  0), \
958 LINE(STAT_SECTION, "",                  COLOR_CYAN,     COLOR_DEFAULT,  0), \
959 LINE(STAT_NONE,    "",                  COLOR_DEFAULT,  COLOR_DEFAULT,  0), \
960 LINE(STAT_STAGED,  "",                  COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
961 LINE(STAT_UNSTAGED,"",                  COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
962 LINE(STAT_UNTRACKED,"",                 COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
963 LINE(BLAME_ID,     "",                  COLOR_MAGENTA,  COLOR_DEFAULT,  0)
964
965 enum line_type {
966 #define LINE(type, line, fg, bg, attr) \
967         LINE_##type
968         LINE_INFO,
969         LINE_NONE
970 #undef  LINE
971 };
972
973 struct line_info {
974         const char *name;       /* Option name. */
975         int namelen;            /* Size of option name. */
976         const char *line;       /* The start of line to match. */
977         int linelen;            /* Size of string to match. */
978         int fg, bg, attr;       /* Color and text attributes for the lines. */
979 };
980
981 static struct line_info line_info[] = {
982 #define LINE(type, line, fg, bg, attr) \
983         { #type, STRING_SIZE(#type), (line), STRING_SIZE(line), (fg), (bg), (attr) }
984         LINE_INFO
985 #undef  LINE
986 };
987
988 static enum line_type
989 get_line_type(const char *line)
990 {
991         int linelen = strlen(line);
992         enum line_type type;
993
994         for (type = 0; type < ARRAY_SIZE(line_info); type++)
995                 /* Case insensitive search matches Signed-off-by lines better. */
996                 if (linelen >= line_info[type].linelen &&
997                     !strncasecmp(line_info[type].line, line, line_info[type].linelen))
998                         return type;
999
1000         return LINE_DEFAULT;
1001 }
1002
1003 static inline int
1004 get_line_attr(enum line_type type)
1005 {
1006         assert(type < ARRAY_SIZE(line_info));
1007         return COLOR_PAIR(type) | line_info[type].attr;
1008 }
1009
1010 static struct line_info *
1011 get_line_info(const char *name)
1012 {
1013         size_t namelen = strlen(name);
1014         enum line_type type;
1015
1016         for (type = 0; type < ARRAY_SIZE(line_info); type++)
1017                 if (namelen == line_info[type].namelen &&
1018                     !string_enum_compare(line_info[type].name, name, namelen))
1019                         return &line_info[type];
1020
1021         return NULL;
1022 }
1023
1024 static void
1025 init_colors(void)
1026 {
1027         int default_bg = line_info[LINE_DEFAULT].bg;
1028         int default_fg = line_info[LINE_DEFAULT].fg;
1029         enum line_type type;
1030
1031         start_color();
1032
1033         if (assume_default_colors(default_fg, default_bg) == ERR) {
1034                 default_bg = COLOR_BLACK;
1035                 default_fg = COLOR_WHITE;
1036         }
1037
1038         for (type = 0; type < ARRAY_SIZE(line_info); type++) {
1039                 struct line_info *info = &line_info[type];
1040                 int bg = info->bg == COLOR_DEFAULT ? default_bg : info->bg;
1041                 int fg = info->fg == COLOR_DEFAULT ? default_fg : info->fg;
1042
1043                 init_pair(type, fg, bg);
1044         }
1045 }
1046
1047 struct line {
1048         enum line_type type;
1049
1050         /* State flags */
1051         unsigned int selected:1;
1052         unsigned int dirty:1;
1053         unsigned int cleareol:1;
1054
1055         void *data;             /* User data */
1056 };
1057
1058
1059 /*
1060  * Keys
1061  */
1062
1063 struct keybinding {
1064         int alias;
1065         enum request request;
1066 };
1067
1068 static struct keybinding default_keybindings[] = {
1069         /* View switching */
1070         { 'm',          REQ_VIEW_MAIN },
1071         { 'd',          REQ_VIEW_DIFF },
1072         { 'l',          REQ_VIEW_LOG },
1073         { 't',          REQ_VIEW_TREE },
1074         { 'f',          REQ_VIEW_BLOB },
1075         { 'B',          REQ_VIEW_BLAME },
1076         { 'p',          REQ_VIEW_PAGER },
1077         { 'h',          REQ_VIEW_HELP },
1078         { 'S',          REQ_VIEW_STATUS },
1079         { 'c',          REQ_VIEW_STAGE },
1080
1081         /* View manipulation */
1082         { 'q',          REQ_VIEW_CLOSE },
1083         { KEY_TAB,      REQ_VIEW_NEXT },
1084         { KEY_RETURN,   REQ_ENTER },
1085         { KEY_UP,       REQ_PREVIOUS },
1086         { KEY_DOWN,     REQ_NEXT },
1087         { 'R',          REQ_REFRESH },
1088         { KEY_F(5),     REQ_REFRESH },
1089         { 'O',          REQ_MAXIMIZE },
1090
1091         /* Cursor navigation */
1092         { 'k',          REQ_MOVE_UP },
1093         { 'j',          REQ_MOVE_DOWN },
1094         { KEY_HOME,     REQ_MOVE_FIRST_LINE },
1095         { KEY_END,      REQ_MOVE_LAST_LINE },
1096         { KEY_NPAGE,    REQ_MOVE_PAGE_DOWN },
1097         { ' ',          REQ_MOVE_PAGE_DOWN },
1098         { KEY_PPAGE,    REQ_MOVE_PAGE_UP },
1099         { 'b',          REQ_MOVE_PAGE_UP },
1100         { '-',          REQ_MOVE_PAGE_UP },
1101
1102         /* Scrolling */
1103         { KEY_IC,       REQ_SCROLL_LINE_UP },
1104         { KEY_DC,       REQ_SCROLL_LINE_DOWN },
1105         { 'w',          REQ_SCROLL_PAGE_UP },
1106         { 's',          REQ_SCROLL_PAGE_DOWN },
1107
1108         /* Searching */
1109         { '/',          REQ_SEARCH },
1110         { '?',          REQ_SEARCH_BACK },
1111         { 'n',          REQ_FIND_NEXT },
1112         { 'N',          REQ_FIND_PREV },
1113
1114         /* Misc */
1115         { 'Q',          REQ_QUIT },
1116         { 'z',          REQ_STOP_LOADING },
1117         { 'v',          REQ_SHOW_VERSION },
1118         { 'r',          REQ_SCREEN_REDRAW },
1119         { '.',          REQ_TOGGLE_LINENO },
1120         { 'D',          REQ_TOGGLE_DATE },
1121         { 'A',          REQ_TOGGLE_AUTHOR },
1122         { 'g',          REQ_TOGGLE_REV_GRAPH },
1123         { 'F',          REQ_TOGGLE_REFS },
1124         { ':',          REQ_PROMPT },
1125         { 'u',          REQ_STATUS_UPDATE },
1126         { '!',          REQ_STATUS_REVERT },
1127         { 'M',          REQ_STATUS_MERGE },
1128         { '@',          REQ_STAGE_NEXT },
1129         { ',',          REQ_PARENT },
1130         { 'e',          REQ_EDIT },
1131 };
1132
1133 #define KEYMAP_INFO \
1134         KEYMAP_(GENERIC), \
1135         KEYMAP_(MAIN), \
1136         KEYMAP_(DIFF), \
1137         KEYMAP_(LOG), \
1138         KEYMAP_(TREE), \
1139         KEYMAP_(BLOB), \
1140         KEYMAP_(BLAME), \
1141         KEYMAP_(PAGER), \
1142         KEYMAP_(HELP), \
1143         KEYMAP_(STATUS), \
1144         KEYMAP_(STAGE)
1145
1146 enum keymap {
1147 #define KEYMAP_(name) KEYMAP_##name
1148         KEYMAP_INFO
1149 #undef  KEYMAP_
1150 };
1151
1152 static struct int_map keymap_table[] = {
1153 #define KEYMAP_(name) { #name, STRING_SIZE(#name), KEYMAP_##name }
1154         KEYMAP_INFO
1155 #undef  KEYMAP_
1156 };
1157
1158 #define set_keymap(map, name) \
1159         set_from_int_map(keymap_table, ARRAY_SIZE(keymap_table), map, name, strlen(name))
1160
1161 struct keybinding_table {
1162         struct keybinding *data;
1163         size_t size;
1164 };
1165
1166 static struct keybinding_table keybindings[ARRAY_SIZE(keymap_table)];
1167
1168 static void
1169 add_keybinding(enum keymap keymap, enum request request, int key)
1170 {
1171         struct keybinding_table *table = &keybindings[keymap];
1172
1173         table->data = realloc(table->data, (table->size + 1) * sizeof(*table->data));
1174         if (!table->data)
1175                 die("Failed to allocate keybinding");
1176         table->data[table->size].alias = key;
1177         table->data[table->size++].request = request;
1178 }
1179
1180 /* Looks for a key binding first in the given map, then in the generic map, and
1181  * lastly in the default keybindings. */
1182 static enum request
1183 get_keybinding(enum keymap keymap, int key)
1184 {
1185         size_t i;
1186
1187         for (i = 0; i < keybindings[keymap].size; i++)
1188                 if (keybindings[keymap].data[i].alias == key)
1189                         return keybindings[keymap].data[i].request;
1190
1191         for (i = 0; i < keybindings[KEYMAP_GENERIC].size; i++)
1192                 if (keybindings[KEYMAP_GENERIC].data[i].alias == key)
1193                         return keybindings[KEYMAP_GENERIC].data[i].request;
1194
1195         for (i = 0; i < ARRAY_SIZE(default_keybindings); i++)
1196                 if (default_keybindings[i].alias == key)
1197                         return default_keybindings[i].request;
1198
1199         return (enum request) key;
1200 }
1201
1202
1203 struct key {
1204         const char *name;
1205         int value;
1206 };
1207
1208 static struct key key_table[] = {
1209         { "Enter",      KEY_RETURN },
1210         { "Space",      ' ' },
1211         { "Backspace",  KEY_BACKSPACE },
1212         { "Tab",        KEY_TAB },
1213         { "Escape",     KEY_ESC },
1214         { "Left",       KEY_LEFT },
1215         { "Right",      KEY_RIGHT },
1216         { "Up",         KEY_UP },
1217         { "Down",       KEY_DOWN },
1218         { "Insert",     KEY_IC },
1219         { "Delete",     KEY_DC },
1220         { "Hash",       '#' },
1221         { "Home",       KEY_HOME },
1222         { "End",        KEY_END },
1223         { "PageUp",     KEY_PPAGE },
1224         { "PageDown",   KEY_NPAGE },
1225         { "F1",         KEY_F(1) },
1226         { "F2",         KEY_F(2) },
1227         { "F3",         KEY_F(3) },
1228         { "F4",         KEY_F(4) },
1229         { "F5",         KEY_F(5) },
1230         { "F6",         KEY_F(6) },
1231         { "F7",         KEY_F(7) },
1232         { "F8",         KEY_F(8) },
1233         { "F9",         KEY_F(9) },
1234         { "F10",        KEY_F(10) },
1235         { "F11",        KEY_F(11) },
1236         { "F12",        KEY_F(12) },
1237 };
1238
1239 static int
1240 get_key_value(const char *name)
1241 {
1242         int i;
1243
1244         for (i = 0; i < ARRAY_SIZE(key_table); i++)
1245                 if (!strcasecmp(key_table[i].name, name))
1246                         return key_table[i].value;
1247
1248         if (strlen(name) == 1 && isprint(*name))
1249                 return (int) *name;
1250
1251         return ERR;
1252 }
1253
1254 static const char *
1255 get_key_name(int key_value)
1256 {
1257         static char key_char[] = "'X'";
1258         const char *seq = NULL;
1259         int key;
1260
1261         for (key = 0; key < ARRAY_SIZE(key_table); key++)
1262                 if (key_table[key].value == key_value)
1263                         seq = key_table[key].name;
1264
1265         if (seq == NULL &&
1266             key_value < 127 &&
1267             isprint(key_value)) {
1268                 key_char[1] = (char) key_value;
1269                 seq = key_char;
1270         }
1271
1272         return seq ? seq : "(no key)";
1273 }
1274
1275 static const char *
1276 get_key(enum request request)
1277 {
1278         static char buf[BUFSIZ];
1279         size_t pos = 0;
1280         char *sep = "";
1281         int i;
1282
1283         buf[pos] = 0;
1284
1285         for (i = 0; i < ARRAY_SIZE(default_keybindings); i++) {
1286                 struct keybinding *keybinding = &default_keybindings[i];
1287
1288                 if (keybinding->request != request)
1289                         continue;
1290
1291                 if (!string_format_from(buf, &pos, "%s%s", sep,
1292                                         get_key_name(keybinding->alias)))
1293                         return "Too many keybindings!";
1294                 sep = ", ";
1295         }
1296
1297         return buf;
1298 }
1299
1300 struct run_request {
1301         enum keymap keymap;
1302         int key;
1303         const char *argv[SIZEOF_ARG];
1304 };
1305
1306 static struct run_request *run_request;
1307 static size_t run_requests;
1308
1309 static enum request
1310 add_run_request(enum keymap keymap, int key, int argc, const char **argv)
1311 {
1312         struct run_request *req;
1313
1314         if (argc >= ARRAY_SIZE(req->argv) - 1)
1315                 return REQ_NONE;
1316
1317         req = realloc(run_request, (run_requests + 1) * sizeof(*run_request));
1318         if (!req)
1319                 return REQ_NONE;
1320
1321         run_request = req;
1322         req = &run_request[run_requests];
1323         req->keymap = keymap;
1324         req->key = key;
1325         req->argv[0] = NULL;
1326
1327         if (!format_argv(req->argv, argv, FORMAT_NONE))
1328                 return REQ_NONE;
1329
1330         return REQ_NONE + ++run_requests;
1331 }
1332
1333 static struct run_request *
1334 get_run_request(enum request request)
1335 {
1336         if (request <= REQ_NONE)
1337                 return NULL;
1338         return &run_request[request - REQ_NONE - 1];
1339 }
1340
1341 static void
1342 add_builtin_run_requests(void)
1343 {
1344         const char *cherry_pick[] = { "git", "cherry-pick", "%(commit)", NULL };
1345         const char *gc[] = { "git", "gc", NULL };
1346         struct {
1347                 enum keymap keymap;
1348                 int key;
1349                 int argc;
1350                 const char **argv;
1351         } reqs[] = {
1352                 { KEYMAP_MAIN,    'C', ARRAY_SIZE(cherry_pick) - 1, cherry_pick },
1353                 { KEYMAP_GENERIC, 'G', ARRAY_SIZE(gc) - 1, gc },
1354         };
1355         int i;
1356
1357         for (i = 0; i < ARRAY_SIZE(reqs); i++) {
1358                 enum request req;
1359
1360                 req = add_run_request(reqs[i].keymap, reqs[i].key, reqs[i].argc, reqs[i].argv);
1361                 if (req != REQ_NONE)
1362                         add_keybinding(reqs[i].keymap, req, reqs[i].key);
1363         }
1364 }
1365
1366 /*
1367  * User config file handling.
1368  */
1369
1370 static struct int_map color_map[] = {
1371 #define COLOR_MAP(name) { #name, STRING_SIZE(#name), COLOR_##name }
1372         COLOR_MAP(DEFAULT),
1373         COLOR_MAP(BLACK),
1374         COLOR_MAP(BLUE),
1375         COLOR_MAP(CYAN),
1376         COLOR_MAP(GREEN),
1377         COLOR_MAP(MAGENTA),
1378         COLOR_MAP(RED),
1379         COLOR_MAP(WHITE),
1380         COLOR_MAP(YELLOW),
1381 };
1382
1383 #define set_color(color, name) \
1384         set_from_int_map(color_map, ARRAY_SIZE(color_map), color, name, strlen(name))
1385
1386 static struct int_map attr_map[] = {
1387 #define ATTR_MAP(name) { #name, STRING_SIZE(#name), A_##name }
1388         ATTR_MAP(NORMAL),
1389         ATTR_MAP(BLINK),
1390         ATTR_MAP(BOLD),
1391         ATTR_MAP(DIM),
1392         ATTR_MAP(REVERSE),
1393         ATTR_MAP(STANDOUT),
1394         ATTR_MAP(UNDERLINE),
1395 };
1396
1397 #define set_attribute(attr, name) \
1398         set_from_int_map(attr_map, ARRAY_SIZE(attr_map), attr, name, strlen(name))
1399
1400 static int   config_lineno;
1401 static bool  config_errors;
1402 static const char *config_msg;
1403
1404 /* Wants: object fgcolor bgcolor [attr] */
1405 static int
1406 option_color_command(int argc, const char *argv[])
1407 {
1408         struct line_info *info;
1409
1410         if (argc != 3 && argc != 4) {
1411                 config_msg = "Wrong number of arguments given to color command";
1412                 return ERR;
1413         }
1414
1415         info = get_line_info(argv[0]);
1416         if (!info) {
1417                 if (!string_enum_compare(argv[0], "main-delim", strlen("main-delim"))) {
1418                         info = get_line_info("delimiter");
1419
1420                 } else if (!string_enum_compare(argv[0], "main-date", strlen("main-date"))) {
1421                         info = get_line_info("date");
1422
1423                 } else {
1424                         config_msg = "Unknown color name";
1425                         return ERR;
1426                 }
1427         }
1428
1429         if (set_color(&info->fg, argv[1]) == ERR ||
1430             set_color(&info->bg, argv[2]) == ERR) {
1431                 config_msg = "Unknown color";
1432                 return ERR;
1433         }
1434
1435         if (argc == 4 && set_attribute(&info->attr, argv[3]) == ERR) {
1436                 config_msg = "Unknown attribute";
1437                 return ERR;
1438         }
1439
1440         return OK;
1441 }
1442
1443 static bool parse_bool(const char *s)
1444 {
1445         return (!strcmp(s, "1") || !strcmp(s, "true") ||
1446                 !strcmp(s, "yes")) ? TRUE : FALSE;
1447 }
1448
1449 static int
1450 parse_int(const char *s, int default_value, int min, int max)
1451 {
1452         int value = atoi(s);
1453
1454         return (value < min || value > max) ? default_value : value;
1455 }
1456
1457 /* Wants: name = value */
1458 static int
1459 option_set_command(int argc, const char *argv[])
1460 {
1461         if (argc != 3) {
1462                 config_msg = "Wrong number of arguments given to set command";
1463                 return ERR;
1464         }
1465
1466         if (strcmp(argv[1], "=")) {
1467                 config_msg = "No value assigned";
1468                 return ERR;
1469         }
1470
1471         if (!strcmp(argv[0], "show-author")) {
1472                 opt_author = parse_bool(argv[2]);
1473                 return OK;
1474         }
1475
1476         if (!strcmp(argv[0], "show-date")) {
1477                 opt_date = parse_bool(argv[2]);
1478                 return OK;
1479         }
1480
1481         if (!strcmp(argv[0], "show-rev-graph")) {
1482                 opt_rev_graph = parse_bool(argv[2]);
1483                 return OK;
1484         }
1485
1486         if (!strcmp(argv[0], "show-refs")) {
1487                 opt_show_refs = parse_bool(argv[2]);
1488                 return OK;
1489         }
1490
1491         if (!strcmp(argv[0], "show-line-numbers")) {
1492                 opt_line_number = parse_bool(argv[2]);
1493                 return OK;
1494         }
1495
1496         if (!strcmp(argv[0], "line-graphics")) {
1497                 opt_line_graphics = parse_bool(argv[2]);
1498                 return OK;
1499         }
1500
1501         if (!strcmp(argv[0], "line-number-interval")) {
1502                 opt_num_interval = parse_int(argv[2], opt_num_interval, 1, 1024);
1503                 return OK;
1504         }
1505
1506         if (!strcmp(argv[0], "author-width")) {
1507                 opt_author_cols = parse_int(argv[2], opt_author_cols, 0, 1024);
1508                 return OK;
1509         }
1510
1511         if (!strcmp(argv[0], "tab-size")) {
1512                 opt_tab_size = parse_int(argv[2], opt_tab_size, 1, 1024);
1513                 return OK;
1514         }
1515
1516         if (!strcmp(argv[0], "commit-encoding")) {
1517                 const char *arg = argv[2];
1518                 int arglen = strlen(arg);
1519
1520                 switch (arg[0]) {
1521                 case '"':
1522                 case '\'':
1523                         if (arglen == 1 || arg[arglen - 1] != arg[0]) {
1524                                 config_msg = "Unmatched quotation";
1525                                 return ERR;
1526                         }
1527                         arg += 1; arglen -= 2;
1528                 default:
1529                         string_ncopy(opt_encoding, arg, strlen(arg));
1530                         return OK;
1531                 }
1532         }
1533
1534         config_msg = "Unknown variable name";
1535         return ERR;
1536 }
1537
1538 /* Wants: mode request key */
1539 static int
1540 option_bind_command(int argc, const char *argv[])
1541 {
1542         enum request request;
1543         int keymap;
1544         int key;
1545
1546         if (argc < 3) {
1547                 config_msg = "Wrong number of arguments given to bind command";
1548                 return ERR;
1549         }
1550
1551         if (set_keymap(&keymap, argv[0]) == ERR) {
1552                 config_msg = "Unknown key map";
1553                 return ERR;
1554         }
1555
1556         key = get_key_value(argv[1]);
1557         if (key == ERR) {
1558                 config_msg = "Unknown key";
1559                 return ERR;
1560         }
1561
1562         request = get_request(argv[2]);
1563         if (request == REQ_NONE) {
1564                 struct {
1565                         const char *name;
1566                         enum request request;
1567                 } obsolete[] = {
1568                         { "cherry-pick",        REQ_NONE },
1569                         { "screen-resize",      REQ_NONE },
1570                         { "tree-parent",        REQ_PARENT },
1571                 };
1572                 size_t namelen = strlen(argv[2]);
1573                 int i;
1574
1575                 for (i = 0; i < ARRAY_SIZE(obsolete); i++) {
1576                         if (namelen != strlen(obsolete[i].name) ||
1577                             string_enum_compare(obsolete[i].name, argv[2], namelen))
1578                                 continue;
1579                         if (obsolete[i].request != REQ_NONE)
1580                                 add_keybinding(keymap, obsolete[i].request, key);
1581                         config_msg = "Obsolete request name";
1582                         return ERR;
1583                 }
1584         }
1585         if (request == REQ_NONE && *argv[2]++ == '!')
1586                 request = add_run_request(keymap, key, argc - 2, argv + 2);
1587         if (request == REQ_NONE) {
1588                 config_msg = "Unknown request name";
1589                 return ERR;
1590         }
1591
1592         add_keybinding(keymap, request, key);
1593
1594         return OK;
1595 }
1596
1597 static int
1598 set_option(const char *opt, char *value)
1599 {
1600         const char *argv[SIZEOF_ARG];
1601         int argc = 0;
1602
1603         if (!argv_from_string(argv, &argc, value)) {
1604                 config_msg = "Too many option arguments";
1605                 return ERR;
1606         }
1607
1608         if (!strcmp(opt, "color"))
1609                 return option_color_command(argc, argv);
1610
1611         if (!strcmp(opt, "set"))
1612                 return option_set_command(argc, argv);
1613
1614         if (!strcmp(opt, "bind"))
1615                 return option_bind_command(argc, argv);
1616
1617         config_msg = "Unknown option command";
1618         return ERR;
1619 }
1620
1621 static int
1622 read_option(char *opt, size_t optlen, char *value, size_t valuelen)
1623 {
1624         int status = OK;
1625
1626         config_lineno++;
1627         config_msg = "Internal error";
1628
1629         /* Check for comment markers, since read_properties() will
1630          * only ensure opt and value are split at first " \t". */
1631         optlen = strcspn(opt, "#");
1632         if (optlen == 0)
1633                 return OK;
1634
1635         if (opt[optlen] != 0) {
1636                 config_msg = "No option value";
1637                 status = ERR;
1638
1639         }  else {
1640                 /* Look for comment endings in the value. */
1641                 size_t len = strcspn(value, "#");
1642
1643                 if (len < valuelen) {
1644                         valuelen = len;
1645                         value[valuelen] = 0;
1646                 }
1647
1648                 status = set_option(opt, value);
1649         }
1650
1651         if (status == ERR) {
1652                 fprintf(stderr, "Error on line %d, near '%.*s': %s\n",
1653                         config_lineno, (int) optlen, opt, config_msg);
1654                 config_errors = TRUE;
1655         }
1656
1657         /* Always keep going if errors are encountered. */
1658         return OK;
1659 }
1660
1661 static void
1662 load_option_file(const char *path)
1663 {
1664         struct io io = {};
1665
1666         /* It's ok that the file doesn't exist. */
1667         if (!io_open(&io, path))
1668                 return;
1669
1670         config_lineno = 0;
1671         config_errors = FALSE;
1672
1673         if (read_properties(&io, " \t", read_option) == ERR ||
1674             config_errors == TRUE)
1675                 fprintf(stderr, "Errors while loading %s.\n", path);
1676 }
1677
1678 static int
1679 load_options(void)
1680 {
1681         const char *home = getenv("HOME");
1682         const char *tigrc_user = getenv("TIGRC_USER");
1683         const char *tigrc_system = getenv("TIGRC_SYSTEM");
1684         char buf[SIZEOF_STR];
1685
1686         add_builtin_run_requests();
1687
1688         if (!tigrc_system) {
1689                 if (!string_format(buf, "%s/tigrc", SYSCONFDIR))
1690                         return ERR;
1691                 tigrc_system = buf;
1692         }
1693         load_option_file(tigrc_system);
1694
1695         if (!tigrc_user) {
1696                 if (!home || !string_format(buf, "%s/.tigrc", home))
1697                         return ERR;
1698                 tigrc_user = buf;
1699         }
1700         load_option_file(tigrc_user);
1701
1702         return OK;
1703 }
1704
1705
1706 /*
1707  * The viewer
1708  */
1709
1710 struct view;
1711 struct view_ops;
1712
1713 /* The display array of active views and the index of the current view. */
1714 static struct view *display[2];
1715 static unsigned int current_view;
1716
1717 /* Reading from the prompt? */
1718 static bool input_mode = FALSE;
1719
1720 #define foreach_displayed_view(view, i) \
1721         for (i = 0; i < ARRAY_SIZE(display) && (view = display[i]); i++)
1722
1723 #define displayed_views()       (display[1] != NULL ? 2 : 1)
1724
1725 /* Current head and commit ID */
1726 static char ref_blob[SIZEOF_REF]        = "";
1727 static char ref_commit[SIZEOF_REF]      = "HEAD";
1728 static char ref_head[SIZEOF_REF]        = "HEAD";
1729
1730 struct view {
1731         const char *name;       /* View name */
1732         const char *cmd_env;    /* Command line set via environment */
1733         const char *id;         /* Points to either of ref_{head,commit,blob} */
1734
1735         struct view_ops *ops;   /* View operations */
1736
1737         enum keymap keymap;     /* What keymap does this view have */
1738         bool git_dir;           /* Whether the view requires a git directory. */
1739
1740         char ref[SIZEOF_REF];   /* Hovered commit reference */
1741         char vid[SIZEOF_REF];   /* View ID. Set to id member when updating. */
1742
1743         int height, width;      /* The width and height of the main window */
1744         WINDOW *win;            /* The main window */
1745         WINDOW *title;          /* The title window living below the main window */
1746
1747         /* Navigation */
1748         unsigned long offset;   /* Offset of the window top */
1749         unsigned long lineno;   /* Current line number */
1750         unsigned long p_offset; /* Previous offset of the window top */
1751         unsigned long p_lineno; /* Previous current line number */
1752         bool p_restore;         /* Should the previous position be restored. */
1753
1754         /* Searching */
1755         char grep[SIZEOF_STR];  /* Search string */
1756         regex_t *regex;         /* Pre-compiled regex */
1757
1758         /* If non-NULL, points to the view that opened this view. If this view
1759          * is closed tig will switch back to the parent view. */
1760         struct view *parent;
1761
1762         /* Buffering */
1763         size_t lines;           /* Total number of lines */
1764         struct line *line;      /* Line index */
1765         size_t line_alloc;      /* Total number of allocated lines */
1766         unsigned int digits;    /* Number of digits in the lines member. */
1767
1768         /* Drawing */
1769         struct line *curline;   /* Line currently being drawn. */
1770         enum line_type curtype; /* Attribute currently used for drawing. */
1771         unsigned long col;      /* Column when drawing. */
1772
1773         /* Loading */
1774         struct io io;
1775         struct io *pipe;
1776         time_t start_time;
1777         time_t update_secs;
1778 };
1779
1780 struct view_ops {
1781         /* What type of content being displayed. Used in the title bar. */
1782         const char *type;
1783         /* Default command arguments. */
1784         const char **argv;
1785         /* Open and reads in all view content. */
1786         bool (*open)(struct view *view);
1787         /* Read one line; updates view->line. */
1788         bool (*read)(struct view *view, char *data);
1789         /* Draw one line; @lineno must be < view->height. */
1790         bool (*draw)(struct view *view, struct line *line, unsigned int lineno);
1791         /* Depending on view handle a special requests. */
1792         enum request (*request)(struct view *view, enum request request, struct line *line);
1793         /* Search for regex in a line. */
1794         bool (*grep)(struct view *view, struct line *line);
1795         /* Select line */
1796         void (*select)(struct view *view, struct line *line);
1797 };
1798
1799 static struct view_ops blame_ops;
1800 static struct view_ops blob_ops;
1801 static struct view_ops diff_ops;
1802 static struct view_ops help_ops;
1803 static struct view_ops log_ops;
1804 static struct view_ops main_ops;
1805 static struct view_ops pager_ops;
1806 static struct view_ops stage_ops;
1807 static struct view_ops status_ops;
1808 static struct view_ops tree_ops;
1809
1810 #define VIEW_STR(name, env, ref, ops, map, git) \
1811         { name, #env, ref, ops, map, git }
1812
1813 #define VIEW_(id, name, ops, git, ref) \
1814         VIEW_STR(name, TIG_##id##_CMD, ref, ops, KEYMAP_##id, git)
1815
1816
1817 static struct view views[] = {
1818         VIEW_(MAIN,   "main",   &main_ops,   TRUE,  ref_head),
1819         VIEW_(DIFF,   "diff",   &diff_ops,   TRUE,  ref_commit),
1820         VIEW_(LOG,    "log",    &log_ops,    TRUE,  ref_head),
1821         VIEW_(TREE,   "tree",   &tree_ops,   TRUE,  ref_commit),
1822         VIEW_(BLOB,   "blob",   &blob_ops,   TRUE,  ref_blob),
1823         VIEW_(BLAME,  "blame",  &blame_ops,  TRUE,  ref_commit),
1824         VIEW_(HELP,   "help",   &help_ops,   FALSE, ""),
1825         VIEW_(PAGER,  "pager",  &pager_ops,  FALSE, "stdin"),
1826         VIEW_(STATUS, "status", &status_ops, TRUE,  ""),
1827         VIEW_(STAGE,  "stage",  &stage_ops,  TRUE,  ""),
1828 };
1829
1830 #define VIEW(req)       (&views[(req) - REQ_OFFSET - 1])
1831 #define VIEW_REQ(view)  ((view) - views + REQ_OFFSET + 1)
1832
1833 #define foreach_view(view, i) \
1834         for (i = 0; i < ARRAY_SIZE(views) && (view = &views[i]); i++)
1835
1836 #define view_is_displayed(view) \
1837         (view == display[0] || view == display[1])
1838
1839
1840 enum line_graphic {
1841         LINE_GRAPHIC_VLINE
1842 };
1843
1844 static int line_graphics[] = {
1845         /* LINE_GRAPHIC_VLINE: */ '|'
1846 };
1847
1848 static inline void
1849 set_view_attr(struct view *view, enum line_type type)
1850 {
1851         if (!view->curline->selected && view->curtype != type) {
1852                 wattrset(view->win, get_line_attr(type));
1853                 wchgat(view->win, -1, 0, type, NULL);
1854                 view->curtype = type;
1855         }
1856 }
1857
1858 static int
1859 draw_chars(struct view *view, enum line_type type, const char *string,
1860            int max_len, bool use_tilde)
1861 {
1862         int len = 0;
1863         int col = 0;
1864         int trimmed = FALSE;
1865
1866         if (max_len <= 0)
1867                 return 0;
1868
1869         if (opt_utf8) {
1870                 len = utf8_length(string, &col, max_len, &trimmed, use_tilde);
1871         } else {
1872                 col = len = strlen(string);
1873                 if (len > max_len) {
1874                         if (use_tilde) {
1875                                 max_len -= 1;
1876                         }
1877                         col = len = max_len;
1878                         trimmed = TRUE;
1879                 }
1880         }
1881
1882         set_view_attr(view, type);
1883         waddnstr(view->win, string, len);
1884         if (trimmed && use_tilde) {
1885                 set_view_attr(view, LINE_DELIMITER);
1886                 waddch(view->win, '~');
1887                 col++;
1888         }
1889
1890         return col;
1891 }
1892
1893 static int
1894 draw_space(struct view *view, enum line_type type, int max, int spaces)
1895 {
1896         static char space[] = "                    ";
1897         int col = 0;
1898
1899         spaces = MIN(max, spaces);
1900
1901         while (spaces > 0) {
1902                 int len = MIN(spaces, sizeof(space) - 1);
1903
1904                 col += draw_chars(view, type, space, spaces, FALSE);
1905                 spaces -= len;
1906         }
1907
1908         return col;
1909 }
1910
1911 static bool
1912 draw_lineno(struct view *view, unsigned int lineno)
1913 {
1914         char number[10];
1915         int digits3 = view->digits < 3 ? 3 : view->digits;
1916         int max_number = MIN(digits3, STRING_SIZE(number));
1917         int max = view->width - view->col;
1918         int col;
1919
1920         if (max < max_number)
1921                 max_number = max;
1922
1923         lineno += view->offset + 1;
1924         if (lineno == 1 || (lineno % opt_num_interval) == 0) {
1925                 static char fmt[] = "%1ld";
1926
1927                 if (view->digits <= 9)
1928                         fmt[1] = '0' + digits3;
1929
1930                 if (!string_format(number, fmt, lineno))
1931                         number[0] = 0;
1932                 col = draw_chars(view, LINE_LINE_NUMBER, number, max_number, TRUE);
1933         } else {
1934                 col = draw_space(view, LINE_LINE_NUMBER, max_number, max_number);
1935         }
1936
1937         if (col < max) {
1938                 set_view_attr(view, LINE_DEFAULT);
1939                 waddch(view->win, line_graphics[LINE_GRAPHIC_VLINE]);
1940                 col++;
1941         }
1942
1943         if (col < max)
1944                 col += draw_space(view, LINE_DEFAULT, max - col, 1);
1945         view->col += col;
1946
1947         return view->width - view->col <= 0;
1948 }
1949
1950 static bool
1951 draw_text(struct view *view, enum line_type type, const char *string, bool trim)
1952 {
1953         view->col += draw_chars(view, type, string, view->width - view->col, trim);
1954         return view->width - view->col <= 0;
1955 }
1956
1957 static bool
1958 draw_graphic(struct view *view, enum line_type type, chtype graphic[], size_t size)
1959 {
1960         int max = view->width - view->col;
1961         int i;
1962
1963         if (max < size)
1964                 size = max;
1965
1966         set_view_attr(view, type);
1967         /* Using waddch() instead of waddnstr() ensures that
1968          * they'll be rendered correctly for the cursor line. */
1969         for (i = 0; i < size; i++)
1970                 waddch(view->win, graphic[i]);
1971
1972         view->col += size;
1973         if (size < max) {
1974                 waddch(view->win, ' ');
1975                 view->col++;
1976         }
1977
1978         return view->width - view->col <= 0;
1979 }
1980
1981 static bool
1982 draw_field(struct view *view, enum line_type type, const char *text, int len, bool trim)
1983 {
1984         int max = MIN(view->width - view->col, len);
1985         int col;
1986
1987         if (text)
1988                 col = draw_chars(view, type, text, max - 1, trim);
1989         else
1990                 col = draw_space(view, type, max - 1, max - 1);
1991
1992         view->col += col + draw_space(view, LINE_DEFAULT, max - col, max - col);
1993         return view->width - view->col <= 0;
1994 }
1995
1996 static bool
1997 draw_date(struct view *view, struct tm *time)
1998 {
1999         char buf[DATE_COLS];
2000         char *date;
2001         int timelen = 0;
2002
2003         if (time)
2004                 timelen = strftime(buf, sizeof(buf), DATE_FORMAT, time);
2005         date = timelen ? buf : NULL;
2006
2007         return draw_field(view, LINE_DATE, date, DATE_COLS, FALSE);
2008 }
2009
2010 static bool
2011 draw_view_line(struct view *view, unsigned int lineno)
2012 {
2013         struct line *line;
2014         bool selected = (view->offset + lineno == view->lineno);
2015         bool draw_ok;
2016
2017         assert(view_is_displayed(view));
2018
2019         if (view->offset + lineno >= view->lines)
2020                 return FALSE;
2021
2022         line = &view->line[view->offset + lineno];
2023
2024         wmove(view->win, lineno, 0);
2025         if (line->cleareol)
2026                 wclrtoeol(view->win);
2027         view->col = 0;
2028         view->curline = line;
2029         view->curtype = LINE_NONE;
2030         line->selected = FALSE;
2031         line->dirty = line->cleareol = 0;
2032
2033         if (selected) {
2034                 set_view_attr(view, LINE_CURSOR);
2035                 line->selected = TRUE;
2036                 view->ops->select(view, line);
2037         }
2038
2039         scrollok(view->win, FALSE);
2040         draw_ok = view->ops->draw(view, line, lineno);
2041         scrollok(view->win, TRUE);
2042
2043         return draw_ok;
2044 }
2045
2046 static void
2047 redraw_view_dirty(struct view *view)
2048 {
2049         bool dirty = FALSE;
2050         int lineno;
2051
2052         for (lineno = 0; lineno < view->height; lineno++) {
2053                 if (view->offset + lineno >= view->lines)
2054                         break;
2055                 if (!view->line[view->offset + lineno].dirty)
2056                         continue;
2057                 dirty = TRUE;
2058                 if (!draw_view_line(view, lineno))
2059                         break;
2060         }
2061
2062         if (!dirty)
2063                 return;
2064         if (input_mode)
2065                 wnoutrefresh(view->win);
2066         else
2067                 wrefresh(view->win);
2068 }
2069
2070 static void
2071 redraw_view_from(struct view *view, int lineno)
2072 {
2073         assert(0 <= lineno && lineno < view->height);
2074
2075         for (; lineno < view->height; lineno++) {
2076                 if (!draw_view_line(view, lineno))
2077                         break;
2078         }
2079
2080         if (input_mode)
2081                 wnoutrefresh(view->win);
2082         else
2083                 wrefresh(view->win);
2084 }
2085
2086 static void
2087 redraw_view(struct view *view)
2088 {
2089         werase(view->win);
2090         redraw_view_from(view, 0);
2091 }
2092
2093
2094 static void
2095 update_view_title(struct view *view)
2096 {
2097         char buf[SIZEOF_STR];
2098         char state[SIZEOF_STR];
2099         size_t bufpos = 0, statelen = 0;
2100
2101         assert(view_is_displayed(view));
2102
2103         if (view != VIEW(REQ_VIEW_STATUS) && view->lines) {
2104                 unsigned int view_lines = view->offset + view->height;
2105                 unsigned int lines = view->lines
2106                                    ? MIN(view_lines, view->lines) * 100 / view->lines
2107                                    : 0;
2108
2109                 string_format_from(state, &statelen, " - %s %d of %d (%d%%)",
2110                                    view->ops->type,
2111                                    view->lineno + 1,
2112                                    view->lines,
2113                                    lines);
2114
2115         }
2116
2117         if (view->pipe) {
2118                 time_t secs = time(NULL) - view->start_time;
2119
2120                 /* Three git seconds are a long time ... */
2121                 if (secs > 2)
2122                         string_format_from(state, &statelen, " loading %lds", secs);
2123         }
2124
2125         string_format_from(buf, &bufpos, "[%s]", view->name);
2126         if (*view->ref && bufpos < view->width) {
2127                 size_t refsize = strlen(view->ref);
2128                 size_t minsize = bufpos + 1 + /* abbrev= */ 7 + 1 + statelen;
2129
2130                 if (minsize < view->width)
2131                         refsize = view->width - minsize + 7;
2132                 string_format_from(buf, &bufpos, " %.*s", (int) refsize, view->ref);
2133         }
2134
2135         if (statelen && bufpos < view->width) {
2136                 string_format_from(buf, &bufpos, "%s", state);
2137         }
2138
2139         if (view == display[current_view])
2140                 wbkgdset(view->title, get_line_attr(LINE_TITLE_FOCUS));
2141         else
2142                 wbkgdset(view->title, get_line_attr(LINE_TITLE_BLUR));
2143
2144         mvwaddnstr(view->title, 0, 0, buf, bufpos);
2145         wclrtoeol(view->title);
2146         wmove(view->title, 0, view->width - 1);
2147
2148         if (input_mode)
2149                 wnoutrefresh(view->title);
2150         else
2151                 wrefresh(view->title);
2152 }
2153
2154 static void
2155 resize_display(void)
2156 {
2157         int offset, i;
2158         struct view *base = display[0];
2159         struct view *view = display[1] ? display[1] : display[0];
2160
2161         /* Setup window dimensions */
2162
2163         getmaxyx(stdscr, base->height, base->width);
2164
2165         /* Make room for the status window. */
2166         base->height -= 1;
2167
2168         if (view != base) {
2169                 /* Horizontal split. */
2170                 view->width   = base->width;
2171                 view->height  = SCALE_SPLIT_VIEW(base->height);
2172                 base->height -= view->height;
2173
2174                 /* Make room for the title bar. */
2175                 view->height -= 1;
2176         }
2177
2178         /* Make room for the title bar. */
2179         base->height -= 1;
2180
2181         offset = 0;
2182
2183         foreach_displayed_view (view, i) {
2184                 if (!view->win) {
2185                         view->win = newwin(view->height, 0, offset, 0);
2186                         if (!view->win)
2187                                 die("Failed to create %s view", view->name);
2188
2189                         scrollok(view->win, TRUE);
2190
2191                         view->title = newwin(1, 0, offset + view->height, 0);
2192                         if (!view->title)
2193                                 die("Failed to create title window");
2194
2195                 } else {
2196                         wresize(view->win, view->height, view->width);
2197                         mvwin(view->win,   offset, 0);
2198                         mvwin(view->title, offset + view->height, 0);
2199                 }
2200
2201                 offset += view->height + 1;
2202         }
2203 }
2204
2205 static void
2206 redraw_display(bool clear)
2207 {
2208         struct view *view;
2209         int i;
2210
2211         foreach_displayed_view (view, i) {
2212                 if (clear)
2213                         wclear(view->win);
2214                 redraw_view(view);
2215                 update_view_title(view);
2216         }
2217 }
2218
2219 static void
2220 update_display_cursor(struct view *view)
2221 {
2222         /* Move the cursor to the right-most column of the cursor line.
2223          *
2224          * XXX: This could turn out to be a bit expensive, but it ensures that
2225          * the cursor does not jump around. */
2226         if (view->lines) {
2227                 wmove(view->win, view->lineno - view->offset, view->width - 1);
2228                 wrefresh(view->win);
2229         }
2230 }
2231
2232 static void
2233 toggle_view_option(bool *option, const char *help)
2234 {
2235         *option = !*option;
2236         redraw_display(FALSE);
2237         report("%sabling %s", *option ? "En" : "Dis", help);
2238 }
2239
2240 /*
2241  * Navigation
2242  */
2243
2244 /* Scrolling backend */
2245 static void
2246 do_scroll_view(struct view *view, int lines)
2247 {
2248         bool redraw_current_line = FALSE;
2249
2250         /* The rendering expects the new offset. */
2251         view->offset += lines;
2252
2253         assert(0 <= view->offset && view->offset < view->lines);
2254         assert(lines);
2255
2256         /* Move current line into the view. */
2257         if (view->lineno < view->offset) {
2258                 view->lineno = view->offset;
2259                 redraw_current_line = TRUE;
2260         } else if (view->lineno >= view->offset + view->height) {
2261                 view->lineno = view->offset + view->height - 1;
2262                 redraw_current_line = TRUE;
2263         }
2264
2265         assert(view->offset <= view->lineno && view->lineno < view->lines);
2266
2267         /* Redraw the whole screen if scrolling is pointless. */
2268         if (view->height < ABS(lines)) {
2269                 redraw_view(view);
2270
2271         } else {
2272                 int line = lines > 0 ? view->height - lines : 0;
2273                 int end = line + ABS(lines);
2274
2275                 wscrl(view->win, lines);
2276
2277                 for (; line < end; line++) {
2278                         if (!draw_view_line(view, line))
2279                                 break;
2280                 }
2281
2282                 if (redraw_current_line)
2283                         draw_view_line(view, view->lineno - view->offset);
2284         }
2285
2286         wrefresh(view->win);
2287         report("");
2288 }
2289
2290 /* Scroll frontend */
2291 static void
2292 scroll_view(struct view *view, enum request request)
2293 {
2294         int lines = 1;
2295
2296         assert(view_is_displayed(view));
2297
2298         switch (request) {
2299         case REQ_SCROLL_PAGE_DOWN:
2300                 lines = view->height;
2301         case REQ_SCROLL_LINE_DOWN:
2302                 if (view->offset + lines > view->lines)
2303                         lines = view->lines - view->offset;
2304
2305                 if (lines == 0 || view->offset + view->height >= view->lines) {
2306                         report("Cannot scroll beyond the last line");
2307                         return;
2308                 }
2309                 break;
2310
2311         case REQ_SCROLL_PAGE_UP:
2312                 lines = view->height;
2313         case REQ_SCROLL_LINE_UP:
2314                 if (lines > view->offset)
2315                         lines = view->offset;
2316
2317                 if (lines == 0) {
2318                         report("Cannot scroll beyond the first line");
2319                         return;
2320                 }
2321
2322                 lines = -lines;
2323                 break;
2324
2325         default:
2326                 die("request %d not handled in switch", request);
2327         }
2328
2329         do_scroll_view(view, lines);
2330 }
2331
2332 /* Cursor moving */
2333 static void
2334 move_view(struct view *view, enum request request)
2335 {
2336         int scroll_steps = 0;
2337         int steps;
2338
2339         switch (request) {
2340         case REQ_MOVE_FIRST_LINE:
2341                 steps = -view->lineno;
2342                 break;
2343
2344         case REQ_MOVE_LAST_LINE:
2345                 steps = view->lines - view->lineno - 1;
2346                 break;
2347
2348         case REQ_MOVE_PAGE_UP:
2349                 steps = view->height > view->lineno
2350                       ? -view->lineno : -view->height;
2351                 break;
2352
2353         case REQ_MOVE_PAGE_DOWN:
2354                 steps = view->lineno + view->height >= view->lines
2355                       ? view->lines - view->lineno - 1 : view->height;
2356                 break;
2357
2358         case REQ_MOVE_UP:
2359                 steps = -1;
2360                 break;
2361
2362         case REQ_MOVE_DOWN:
2363                 steps = 1;
2364                 break;
2365
2366         default:
2367                 die("request %d not handled in switch", request);
2368         }
2369
2370         if (steps <= 0 && view->lineno == 0) {
2371                 report("Cannot move beyond the first line");
2372                 return;
2373
2374         } else if (steps >= 0 && view->lineno + 1 >= view->lines) {
2375                 report("Cannot move beyond the last line");
2376                 return;
2377         }
2378
2379         /* Move the current line */
2380         view->lineno += steps;
2381         assert(0 <= view->lineno && view->lineno < view->lines);
2382
2383         /* Check whether the view needs to be scrolled */
2384         if (view->lineno < view->offset ||
2385             view->lineno >= view->offset + view->height) {
2386                 scroll_steps = steps;
2387                 if (steps < 0 && -steps > view->offset) {
2388                         scroll_steps = -view->offset;
2389
2390                 } else if (steps > 0) {
2391                         if (view->lineno == view->lines - 1 &&
2392                             view->lines > view->height) {
2393                                 scroll_steps = view->lines - view->offset - 1;
2394                                 if (scroll_steps >= view->height)
2395                                         scroll_steps -= view->height - 1;
2396                         }
2397                 }
2398         }
2399
2400         if (!view_is_displayed(view)) {
2401                 view->offset += scroll_steps;
2402                 assert(0 <= view->offset && view->offset < view->lines);
2403                 view->ops->select(view, &view->line[view->lineno]);
2404                 return;
2405         }
2406
2407         /* Repaint the old "current" line if we be scrolling */
2408         if (ABS(steps) < view->height)
2409                 draw_view_line(view, view->lineno - steps - view->offset);
2410
2411         if (scroll_steps) {
2412                 do_scroll_view(view, scroll_steps);
2413                 return;
2414         }
2415
2416         /* Draw the current line */
2417         draw_view_line(view, view->lineno - view->offset);
2418
2419         wrefresh(view->win);
2420         report("");
2421 }
2422
2423
2424 /*
2425  * Searching
2426  */
2427
2428 static void search_view(struct view *view, enum request request);
2429
2430 static void
2431 select_view_line(struct view *view, unsigned long lineno)
2432 {
2433         if (lineno - view->offset >= view->height) {
2434                 view->offset = lineno;
2435                 view->lineno = lineno;
2436                 if (view_is_displayed(view))
2437                         redraw_view(view);
2438
2439         } else {
2440                 unsigned long old_lineno = view->lineno - view->offset;
2441
2442                 view->lineno = lineno;
2443                 if (view_is_displayed(view)) {
2444                         draw_view_line(view, old_lineno);
2445                         draw_view_line(view, view->lineno - view->offset);
2446                         wrefresh(view->win);
2447                 } else {
2448                         view->ops->select(view, &view->line[view->lineno]);
2449                 }
2450         }
2451 }
2452
2453 static void
2454 find_next(struct view *view, enum request request)
2455 {
2456         unsigned long lineno = view->lineno;
2457         int direction;
2458
2459         if (!*view->grep) {
2460                 if (!*opt_search)
2461                         report("No previous search");
2462                 else
2463                         search_view(view, request);
2464                 return;
2465         }
2466
2467         switch (request) {
2468         case REQ_SEARCH:
2469         case REQ_FIND_NEXT:
2470                 direction = 1;
2471                 break;
2472
2473         case REQ_SEARCH_BACK:
2474         case REQ_FIND_PREV:
2475                 direction = -1;
2476                 break;
2477
2478         default:
2479                 return;
2480         }
2481
2482         if (request == REQ_FIND_NEXT || request == REQ_FIND_PREV)
2483                 lineno += direction;
2484
2485         /* Note, lineno is unsigned long so will wrap around in which case it
2486          * will become bigger than view->lines. */
2487         for (; lineno < view->lines; lineno += direction) {
2488                 if (view->ops->grep(view, &view->line[lineno])) {
2489                         select_view_line(view, lineno);
2490                         report("Line %ld matches '%s'", lineno + 1, view->grep);
2491                         return;
2492                 }
2493         }
2494
2495         report("No match found for '%s'", view->grep);
2496 }
2497
2498 static void
2499 search_view(struct view *view, enum request request)
2500 {
2501         int regex_err;
2502
2503         if (view->regex) {
2504                 regfree(view->regex);
2505                 *view->grep = 0;
2506         } else {
2507                 view->regex = calloc(1, sizeof(*view->regex));
2508                 if (!view->regex)
2509                         return;
2510         }
2511
2512         regex_err = regcomp(view->regex, opt_search, REG_EXTENDED);
2513         if (regex_err != 0) {
2514                 char buf[SIZEOF_STR] = "unknown error";
2515
2516                 regerror(regex_err, view->regex, buf, sizeof(buf));
2517                 report("Search failed: %s", buf);
2518                 return;
2519         }
2520
2521         string_copy(view->grep, opt_search);
2522
2523         find_next(view, request);
2524 }
2525
2526 /*
2527  * Incremental updating
2528  */
2529
2530 static void
2531 reset_view(struct view *view)
2532 {
2533         int i;
2534
2535         for (i = 0; i < view->lines; i++)
2536                 free(view->line[i].data);
2537         free(view->line);
2538
2539         view->p_offset = view->offset;
2540         view->p_lineno = view->lineno;
2541
2542         view->line = NULL;
2543         view->offset = 0;
2544         view->lines  = 0;
2545         view->lineno = 0;
2546         view->line_alloc = 0;
2547         view->vid[0] = 0;
2548         view->update_secs = 0;
2549 }
2550
2551 static void
2552 free_argv(const char *argv[])
2553 {
2554         int argc;
2555
2556         for (argc = 0; argv[argc]; argc++)
2557                 free((void *) argv[argc]);
2558 }
2559
2560 static bool
2561 format_argv(const char *dst_argv[], const char *src_argv[], enum format_flags flags)
2562 {
2563         char buf[SIZEOF_STR];
2564         int argc;
2565         bool noreplace = flags == FORMAT_NONE;
2566
2567         free_argv(dst_argv);
2568
2569         for (argc = 0; src_argv[argc]; argc++) {
2570                 const char *arg = src_argv[argc];
2571                 size_t bufpos = 0;
2572
2573                 while (arg) {
2574                         char *next = strstr(arg, "%(");
2575                         int len = next - arg;
2576                         const char *value;
2577
2578                         if (!next || noreplace) {
2579                                 if (flags == FORMAT_DASH && !strcmp(arg, "--"))
2580                                         noreplace = TRUE;
2581                                 len = strlen(arg);
2582                                 value = "";
2583
2584                         } else if (!prefixcmp(next, "%(directory)")) {
2585                                 value = opt_path;
2586
2587                         } else if (!prefixcmp(next, "%(file)")) {
2588                                 value = opt_file;
2589
2590                         } else if (!prefixcmp(next, "%(ref)")) {
2591                                 value = *opt_ref ? opt_ref : "HEAD";
2592
2593                         } else if (!prefixcmp(next, "%(head)")) {
2594                                 value = ref_head;
2595
2596                         } else if (!prefixcmp(next, "%(commit)")) {
2597                                 value = ref_commit;
2598
2599                         } else if (!prefixcmp(next, "%(blob)")) {
2600                                 value = ref_blob;
2601
2602                         } else {
2603                                 report("Unknown replacement: `%s`", next);
2604                                 return FALSE;
2605                         }
2606
2607                         if (!string_format_from(buf, &bufpos, "%.*s%s", len, arg, value))
2608                                 return FALSE;
2609
2610                         arg = next && !noreplace ? strchr(next, ')') + 1 : NULL;
2611                 }
2612
2613                 dst_argv[argc] = strdup(buf);
2614                 if (!dst_argv[argc])
2615                         break;
2616         }
2617
2618         dst_argv[argc] = NULL;
2619
2620         return src_argv[argc] == NULL;
2621 }
2622
2623 static bool
2624 restore_view_position(struct view *view)
2625 {
2626         if (!view->p_restore || (view->pipe && view->lines <= view->p_lineno))
2627                 return FALSE;
2628
2629         /* Changing the view position cancels the restoring. */
2630         /* FIXME: Changing back to the first line is not detected. */
2631         if (view->offset != 0 || view->lineno != 0) {
2632                 view->p_restore = FALSE;
2633                 return FALSE;
2634         }
2635
2636         if (view->p_lineno >= view->lines) {
2637                 view->p_lineno = view->lines > 0 ? view->lines - 1 : 0;
2638                 if (view->p_offset >= view->p_lineno) {
2639                         unsigned long half = view->height / 2;
2640
2641                         if (view->p_lineno > half)
2642                                 view->p_offset = view->p_lineno - half;
2643                         else
2644                                 view->p_offset = 0;
2645                 }
2646         }
2647
2648         if (view_is_displayed(view) &&
2649             view->offset != view->p_offset &&
2650             view->lineno != view->p_lineno)
2651                 werase(view->win);
2652
2653         view->offset = view->p_offset;
2654         view->lineno = view->p_lineno;
2655         view->p_restore = FALSE;
2656
2657         return TRUE;
2658 }
2659
2660 static void
2661 end_update(struct view *view, bool force)
2662 {
2663         if (!view->pipe)
2664                 return;
2665         while (!view->ops->read(view, NULL))
2666                 if (!force)
2667                         return;
2668         set_nonblocking_input(FALSE);
2669         if (force)
2670                 kill_io(view->pipe);
2671         done_io(view->pipe);
2672         view->pipe = NULL;
2673 }
2674
2675 static void
2676 setup_update(struct view *view, const char *vid)
2677 {
2678         set_nonblocking_input(TRUE);
2679         reset_view(view);
2680         string_copy_rev(view->vid, vid);
2681         view->pipe = &view->io;
2682         view->start_time = time(NULL);
2683 }
2684
2685 static bool
2686 prepare_update(struct view *view, const char *argv[], const char *dir,
2687                enum format_flags flags)
2688 {
2689         if (view->pipe)
2690                 end_update(view, TRUE);
2691         return init_io_rd(&view->io, argv, dir, flags);
2692 }
2693
2694 static bool
2695 prepare_update_file(struct view *view, const char *name)
2696 {
2697         if (view->pipe)
2698                 end_update(view, TRUE);
2699         return io_open(&view->io, name);
2700 }
2701
2702 static bool
2703 begin_update(struct view *view, bool refresh)
2704 {
2705         if (view->pipe)
2706                 end_update(view, TRUE);
2707
2708         if (refresh) {
2709                 if (!start_io(&view->io))
2710                         return FALSE;
2711
2712         } else {
2713                 if (view == VIEW(REQ_VIEW_TREE) && strcmp(view->vid, view->id))
2714                         opt_path[0] = 0;
2715
2716                 if (!run_io_rd(&view->io, view->ops->argv, FORMAT_ALL))
2717                         return FALSE;
2718
2719                 /* Put the current ref_* value to the view title ref
2720                  * member. This is needed by the blob view. Most other
2721                  * views sets it automatically after loading because the
2722                  * first line is a commit line. */
2723                 string_copy_rev(view->ref, view->id);
2724         }
2725
2726         setup_update(view, view->id);
2727
2728         return TRUE;
2729 }
2730
2731 #define ITEM_CHUNK_SIZE 256
2732 static void *
2733 realloc_items(void *mem, size_t *size, size_t new_size, size_t item_size)
2734 {
2735         size_t num_chunks = *size / ITEM_CHUNK_SIZE;
2736         size_t num_chunks_new = (new_size + ITEM_CHUNK_SIZE - 1) / ITEM_CHUNK_SIZE;
2737
2738         if (mem == NULL || num_chunks != num_chunks_new) {
2739                 *size = num_chunks_new * ITEM_CHUNK_SIZE;
2740                 mem = realloc(mem, *size * item_size);
2741         }
2742
2743         return mem;
2744 }
2745
2746 static struct line *
2747 realloc_lines(struct view *view, size_t line_size)
2748 {
2749         size_t alloc = view->line_alloc;
2750         struct line *tmp = realloc_items(view->line, &alloc, line_size,
2751                                          sizeof(*view->line));
2752
2753         if (!tmp)
2754                 return NULL;
2755
2756         view->line = tmp;
2757         view->line_alloc = alloc;
2758         return view->line;
2759 }
2760
2761 static bool
2762 update_view(struct view *view)
2763 {
2764         char out_buffer[BUFSIZ * 2];
2765         char *line;
2766         /* Clear the view and redraw everything since the tree sorting
2767          * might have rearranged things. */
2768         bool redraw = view->lines == 0;
2769         bool can_read = TRUE;
2770
2771         if (!view->pipe)
2772                 return TRUE;
2773
2774         if (!io_can_read(view->pipe)) {
2775                 if (view->lines == 0) {
2776                         time_t secs = time(NULL) - view->start_time;
2777
2778                         if (secs > view->update_secs) {
2779                                 if (view->update_secs == 0)
2780                                         redraw_view(view);
2781                                 update_view_title(view);
2782                                 view->update_secs = secs;
2783                         }
2784                 }
2785                 return TRUE;
2786         }
2787
2788         for (; (line = io_get(view->pipe, '\n', can_read)); can_read = FALSE) {
2789                 if (opt_iconv != ICONV_NONE) {
2790                         ICONV_CONST char *inbuf = line;
2791                         size_t inlen = strlen(line) + 1;
2792
2793                         char *outbuf = out_buffer;
2794                         size_t outlen = sizeof(out_buffer);
2795
2796                         size_t ret;
2797
2798                         ret = iconv(opt_iconv, &inbuf, &inlen, &outbuf, &outlen);
2799                         if (ret != (size_t) -1)
2800                                 line = out_buffer;
2801                 }
2802
2803                 if (!view->ops->read(view, line)) {
2804                         report("Allocation failure");
2805                         end_update(view, TRUE);
2806                         return FALSE;
2807                 }
2808         }
2809
2810         {
2811                 unsigned long lines = view->lines;
2812                 int digits;
2813
2814                 for (digits = 0; lines; digits++)
2815                         lines /= 10;
2816
2817                 /* Keep the displayed view in sync with line number scaling. */
2818                 if (digits != view->digits) {
2819                         view->digits = digits;
2820                         if (opt_line_number || view == VIEW(REQ_VIEW_BLAME))
2821                                 redraw = TRUE;
2822                 }
2823         }
2824
2825         if (io_error(view->pipe)) {
2826                 report("Failed to read: %s", io_strerror(view->pipe));
2827                 end_update(view, TRUE);
2828
2829         } else if (io_eof(view->pipe)) {
2830                 report("");
2831                 end_update(view, FALSE);
2832         }
2833
2834         if (restore_view_position(view))
2835                 redraw = TRUE;
2836
2837         if (!view_is_displayed(view))
2838                 return TRUE;
2839
2840         if (redraw)
2841                 redraw_view_from(view, 0);
2842         else
2843                 redraw_view_dirty(view);
2844
2845         /* Update the title _after_ the redraw so that if the redraw picks up a
2846          * commit reference in view->ref it'll be available here. */
2847         update_view_title(view);
2848         return TRUE;
2849 }
2850
2851 static struct line *
2852 add_line_data(struct view *view, void *data, enum line_type type)
2853 {
2854         struct line *line;
2855
2856         if (!realloc_lines(view, view->lines + 1))
2857                 return NULL;
2858
2859         line = &view->line[view->lines++];
2860         memset(line, 0, sizeof(*line));
2861         line->type = type;
2862         line->data = data;
2863         line->dirty = 1;
2864
2865         return line;
2866 }
2867
2868 static struct line *
2869 add_line_text(struct view *view, const char *text, enum line_type type)
2870 {
2871         char *data = text ? strdup(text) : NULL;
2872
2873         return data ? add_line_data(view, data, type) : NULL;
2874 }
2875
2876 static struct line *
2877 add_line_format(struct view *view, enum line_type type, const char *fmt, ...)
2878 {
2879         char buf[SIZEOF_STR];
2880         va_list args;
2881
2882         va_start(args, fmt);
2883         if (vsnprintf(buf, sizeof(buf), fmt, args) >= sizeof(buf))
2884                 buf[0] = 0;
2885         va_end(args);
2886
2887         return buf[0] ? add_line_text(view, buf, type) : NULL;
2888 }
2889
2890 /*
2891  * View opening
2892  */
2893
2894 enum open_flags {
2895         OPEN_DEFAULT = 0,       /* Use default view switching. */
2896         OPEN_SPLIT = 1,         /* Split current view. */
2897         OPEN_BACKGROUNDED = 2,  /* Backgrounded. */
2898         OPEN_RELOAD = 4,        /* Reload view even if it is the current. */
2899         OPEN_NOMAXIMIZE = 8,    /* Do not maximize the current view. */
2900         OPEN_REFRESH = 16,      /* Refresh view using previous command. */
2901         OPEN_PREPARED = 32,     /* Open already prepared command. */
2902 };
2903
2904 static void
2905 open_view(struct view *prev, enum request request, enum open_flags flags)
2906 {
2907         bool backgrounded = !!(flags & OPEN_BACKGROUNDED);
2908         bool split = !!(flags & OPEN_SPLIT);
2909         bool reload = !!(flags & (OPEN_RELOAD | OPEN_REFRESH | OPEN_PREPARED));
2910         bool nomaximize = !!(flags & (OPEN_NOMAXIMIZE | OPEN_REFRESH));
2911         struct view *view = VIEW(request);
2912         int nviews = displayed_views();
2913         struct view *base_view = display[0];
2914
2915         if (view == prev && nviews == 1 && !reload) {
2916                 report("Already in %s view", view->name);
2917                 return;
2918         }
2919
2920         if (view->git_dir && !opt_git_dir[0]) {
2921                 report("The %s view is disabled in pager view", view->name);
2922                 return;
2923         }
2924
2925         if (split) {
2926                 display[1] = view;
2927                 if (!backgrounded)
2928                         current_view = 1;
2929         } else if (!nomaximize) {
2930                 /* Maximize the current view. */
2931                 memset(display, 0, sizeof(display));
2932                 current_view = 0;
2933                 display[current_view] = view;
2934         }
2935
2936         /* Resize the view when switching between split- and full-screen,
2937          * or when switching between two different full-screen views. */
2938         if (nviews != displayed_views() ||
2939             (nviews == 1 && base_view != display[0]))
2940                 resize_display();
2941
2942         if (view->ops->open) {
2943                 if (view->pipe)
2944                         end_update(view, TRUE);
2945                 if (!view->ops->open(view)) {
2946                         report("Failed to load %s view", view->name);
2947                         return;
2948                 }
2949                 restore_view_position(view);
2950
2951         } else if ((reload || strcmp(view->vid, view->id)) &&
2952                    !begin_update(view, flags & (OPEN_REFRESH | OPEN_PREPARED))) {
2953                 report("Failed to load %s view", view->name);
2954                 return;
2955         }
2956
2957         if (split && prev->lineno - prev->offset >= prev->height) {
2958                 /* Take the title line into account. */
2959                 int lines = prev->lineno - prev->offset - prev->height + 1;
2960
2961                 /* Scroll the view that was split if the current line is
2962                  * outside the new limited view. */
2963                 do_scroll_view(prev, lines);
2964         }
2965
2966         if (prev && view != prev) {
2967                 if (split && !backgrounded) {
2968                         /* "Blur" the previous view. */
2969                         update_view_title(prev);
2970                 }
2971
2972                 view->parent = prev;
2973         }
2974
2975         if (view->pipe && view->lines == 0) {
2976                 /* Clear the old view and let the incremental updating refill
2977                  * the screen. */
2978                 werase(view->win);
2979                 view->p_restore = flags & (OPEN_RELOAD | OPEN_REFRESH);
2980                 report("");
2981         } else if (view_is_displayed(view)) {
2982                 redraw_view(view);
2983                 report("");
2984         }
2985
2986         /* If the view is backgrounded the above calls to report()
2987          * won't redraw the view title. */
2988         if (backgrounded)
2989                 update_view_title(view);
2990 }
2991
2992 static void
2993 open_external_viewer(const char *argv[], const char *dir)
2994 {
2995         def_prog_mode();           /* save current tty modes */
2996         endwin();                  /* restore original tty modes */
2997         run_io_fg(argv, dir);
2998         fprintf(stderr, "Press Enter to continue");
2999         getc(opt_tty);
3000         reset_prog_mode();
3001         redraw_display(TRUE);
3002 }
3003
3004 static void
3005 open_mergetool(const char *file)
3006 {
3007         const char *mergetool_argv[] = { "git", "mergetool", file, NULL };
3008
3009         open_external_viewer(mergetool_argv, opt_cdup);
3010 }
3011
3012 static void
3013 open_editor(bool from_root, const char *file)
3014 {
3015         const char *editor_argv[] = { "vi", file, NULL };
3016         const char *editor;
3017
3018         editor = getenv("GIT_EDITOR");
3019         if (!editor && *opt_editor)
3020                 editor = opt_editor;
3021         if (!editor)
3022                 editor = getenv("VISUAL");
3023         if (!editor)
3024                 editor = getenv("EDITOR");
3025         if (!editor)
3026                 editor = "vi";
3027
3028         editor_argv[0] = editor;
3029         open_external_viewer(editor_argv, from_root ? opt_cdup : NULL);
3030 }
3031
3032 static void
3033 open_run_request(enum request request)
3034 {
3035         struct run_request *req = get_run_request(request);
3036         const char *argv[ARRAY_SIZE(req->argv)] = { NULL };
3037
3038         if (!req) {
3039                 report("Unknown run request");
3040                 return;
3041         }
3042
3043         if (format_argv(argv, req->argv, FORMAT_ALL))
3044                 open_external_viewer(argv, NULL);
3045         free_argv(argv);
3046 }
3047
3048 /*
3049  * User request switch noodle
3050  */
3051
3052 static int
3053 view_driver(struct view *view, enum request request)
3054 {
3055         int i;
3056
3057         if (request == REQ_NONE) {
3058                 doupdate();
3059                 return TRUE;
3060         }
3061
3062         if (request > REQ_NONE) {
3063                 open_run_request(request);
3064                 /* FIXME: When all views can refresh always do this. */
3065                 if (view == VIEW(REQ_VIEW_STATUS) ||
3066                     view == VIEW(REQ_VIEW_MAIN) ||
3067                     view == VIEW(REQ_VIEW_LOG) ||
3068                     view == VIEW(REQ_VIEW_STAGE))
3069                         request = REQ_REFRESH;
3070                 else
3071                         return TRUE;
3072         }
3073
3074         if (view && view->lines) {
3075                 request = view->ops->request(view, request, &view->line[view->lineno]);
3076                 if (request == REQ_NONE)
3077                         return TRUE;
3078         }
3079
3080         switch (request) {
3081         case REQ_MOVE_UP:
3082         case REQ_MOVE_DOWN:
3083         case REQ_MOVE_PAGE_UP:
3084         case REQ_MOVE_PAGE_DOWN:
3085         case REQ_MOVE_FIRST_LINE:
3086         case REQ_MOVE_LAST_LINE:
3087                 move_view(view, request);
3088                 break;
3089
3090         case REQ_SCROLL_LINE_DOWN:
3091         case REQ_SCROLL_LINE_UP:
3092         case REQ_SCROLL_PAGE_DOWN:
3093         case REQ_SCROLL_PAGE_UP:
3094                 scroll_view(view, request);
3095                 break;
3096
3097         case REQ_VIEW_BLAME:
3098                 if (!opt_file[0]) {
3099                         report("No file chosen, press %s to open tree view",
3100                                get_key(REQ_VIEW_TREE));
3101                         break;
3102                 }
3103                 open_view(view, request, OPEN_DEFAULT);
3104                 break;
3105
3106         case REQ_VIEW_BLOB:
3107                 if (!ref_blob[0]) {
3108                         report("No file chosen, press %s to open tree view",
3109                                get_key(REQ_VIEW_TREE));
3110                         break;
3111                 }
3112                 open_view(view, request, OPEN_DEFAULT);
3113                 break;
3114
3115         case REQ_VIEW_PAGER:
3116                 if (!VIEW(REQ_VIEW_PAGER)->pipe && !VIEW(REQ_VIEW_PAGER)->lines) {
3117                         report("No pager content, press %s to run command from prompt",
3118                                get_key(REQ_PROMPT));
3119                         break;
3120                 }
3121                 open_view(view, request, OPEN_DEFAULT);
3122                 break;
3123
3124         case REQ_VIEW_STAGE:
3125                 if (!VIEW(REQ_VIEW_STAGE)->lines) {
3126                         report("No stage content, press %s to open the status view and choose file",
3127                                get_key(REQ_VIEW_STATUS));
3128                         break;
3129                 }
3130                 open_view(view, request, OPEN_DEFAULT);
3131                 break;
3132
3133         case REQ_VIEW_STATUS:
3134                 if (opt_is_inside_work_tree == FALSE) {
3135                         report("The status view requires a working tree");
3136                         break;
3137                 }
3138                 open_view(view, request, OPEN_DEFAULT);
3139                 break;
3140
3141         case REQ_VIEW_MAIN:
3142         case REQ_VIEW_DIFF:
3143         case REQ_VIEW_LOG:
3144         case REQ_VIEW_TREE:
3145         case REQ_VIEW_HELP:
3146                 open_view(view, request, OPEN_DEFAULT);
3147                 break;
3148
3149         case REQ_NEXT:
3150         case REQ_PREVIOUS:
3151                 request = request == REQ_NEXT ? REQ_MOVE_DOWN : REQ_MOVE_UP;
3152
3153                 if ((view == VIEW(REQ_VIEW_DIFF) &&
3154                      view->parent == VIEW(REQ_VIEW_MAIN)) ||
3155                    (view == VIEW(REQ_VIEW_DIFF) &&
3156                      view->parent == VIEW(REQ_VIEW_BLAME)) ||
3157                    (view == VIEW(REQ_VIEW_STAGE) &&
3158                      view->parent == VIEW(REQ_VIEW_STATUS)) ||
3159                    (view == VIEW(REQ_VIEW_BLOB) &&
3160                      view->parent == VIEW(REQ_VIEW_TREE))) {
3161                         int line;
3162
3163                         view = view->parent;
3164                         line = view->lineno;
3165                         move_view(view, request);
3166                         if (view_is_displayed(view))
3167                                 update_view_title(view);
3168                         if (line != view->lineno)
3169                                 view->ops->request(view, REQ_ENTER,
3170                                                    &view->line[view->lineno]);
3171
3172                 } else {
3173                         move_view(view, request);
3174                 }
3175                 break;
3176
3177         case REQ_VIEW_NEXT:
3178         {
3179                 int nviews = displayed_views();
3180                 int next_view = (current_view + 1) % nviews;
3181
3182                 if (next_view == current_view) {
3183                         report("Only one view is displayed");
3184                         break;
3185                 }
3186
3187                 current_view = next_view;
3188                 /* Blur out the title of the previous view. */
3189                 update_view_title(view);
3190                 report("");
3191                 break;
3192         }
3193         case REQ_REFRESH:
3194                 report("Refreshing is not yet supported for the %s view", view->name);
3195                 break;
3196
3197         case REQ_MAXIMIZE:
3198                 if (displayed_views() == 2)
3199                         open_view(view, VIEW_REQ(view), OPEN_DEFAULT);
3200                 break;
3201
3202         case REQ_TOGGLE_LINENO:
3203                 toggle_view_option(&opt_line_number, "line numbers");
3204                 break;
3205
3206         case REQ_TOGGLE_DATE:
3207                 toggle_view_option(&opt_date, "date display");
3208                 break;
3209
3210         case REQ_TOGGLE_AUTHOR:
3211                 toggle_view_option(&opt_author, "author display");
3212                 break;
3213
3214         case REQ_TOGGLE_REV_GRAPH:
3215                 toggle_view_option(&opt_rev_graph, "revision graph display");
3216                 break;
3217
3218         case REQ_TOGGLE_REFS:
3219                 toggle_view_option(&opt_show_refs, "reference display");
3220                 break;
3221
3222         case REQ_SEARCH:
3223         case REQ_SEARCH_BACK:
3224                 search_view(view, request);
3225                 break;
3226
3227         case REQ_FIND_NEXT:
3228         case REQ_FIND_PREV:
3229                 find_next(view, request);
3230                 break;
3231
3232         case REQ_STOP_LOADING:
3233                 for (i = 0; i < ARRAY_SIZE(views); i++) {
3234                         view = &views[i];
3235                         if (view->pipe)
3236                                 report("Stopped loading the %s view", view->name),
3237                         end_update(view, TRUE);
3238                 }
3239                 break;
3240
3241         case REQ_SHOW_VERSION:
3242                 report("tig-%s (built %s)", TIG_VERSION, __DATE__);
3243                 return TRUE;
3244
3245         case REQ_SCREEN_REDRAW:
3246                 redraw_display(TRUE);
3247                 break;
3248
3249         case REQ_EDIT:
3250                 report("Nothing to edit");
3251                 break;
3252
3253         case REQ_ENTER:
3254                 report("Nothing to enter");
3255                 break;
3256
3257         case REQ_VIEW_CLOSE:
3258                 /* XXX: Mark closed views by letting view->parent point to the
3259                  * view itself. Parents to closed view should never be
3260                  * followed. */
3261                 if (view->parent &&
3262                     view->parent->parent != view->parent) {
3263                         memset(display, 0, sizeof(display));
3264                         current_view = 0;
3265                         display[current_view] = view->parent;
3266                         view->parent = view;
3267                         resize_display();
3268                         redraw_display(FALSE);
3269                         report("");
3270                         break;
3271                 }
3272                 /* Fall-through */
3273         case REQ_QUIT:
3274                 return FALSE;
3275
3276         default:
3277                 report("Unknown key, press 'h' for help");
3278                 return TRUE;
3279         }
3280
3281         return TRUE;
3282 }
3283
3284
3285 /*
3286  * View backend utilities
3287  */
3288
3289 /* Parse author lines where the name may be empty:
3290  *      author  <email@address.tld> 1138474660 +0100
3291  */
3292 static void
3293 parse_author_line(char *ident, char *author, size_t authorsize, struct tm *tm)
3294 {
3295         char *nameend = strchr(ident, '<');
3296         char *emailend = strchr(ident, '>');
3297
3298         if (nameend && emailend)
3299                 *nameend = *emailend = 0;
3300         ident = chomp_string(ident);
3301         if (!*ident) {
3302                 if (nameend)
3303                         ident = chomp_string(nameend + 1);
3304                 if (!*ident)
3305                         ident = "Unknown";
3306         }
3307
3308         string_ncopy_do(author, authorsize, ident, strlen(ident));
3309
3310         /* Parse epoch and timezone */
3311         if (emailend && emailend[1] == ' ') {
3312                 char *secs = emailend + 2;
3313                 char *zone = strchr(secs, ' ');
3314                 time_t time = (time_t) atol(secs);
3315
3316                 if (zone && strlen(zone) == STRING_SIZE(" +0700")) {
3317                         long tz;
3318
3319                         zone++;
3320                         tz  = ('0' - zone[1]) * 60 * 60 * 10;
3321                         tz += ('0' - zone[2]) * 60 * 60;
3322                         tz += ('0' - zone[3]) * 60;
3323                         tz += ('0' - zone[4]) * 60;
3324
3325                         if (zone[0] == '-')
3326                                 tz = -tz;
3327
3328                         time -= tz;
3329                 }
3330
3331                 gmtime_r(&time, tm);
3332         }
3333 }
3334
3335 static enum input_status
3336 select_commit_parent_handler(void *data, char *buf, int c)
3337 {
3338         size_t parents = *(size_t *) data;
3339         int parent = 0;
3340
3341         if (!isdigit(c))
3342                 return INPUT_SKIP;
3343
3344         if (*buf)
3345                 parent = atoi(buf) * 10;
3346         parent += c - '0';
3347
3348         if (parent > parents)
3349                 return INPUT_SKIP;
3350         return INPUT_OK;
3351 }
3352
3353 static bool
3354 select_commit_parent(const char *id, char rev[SIZEOF_REV])
3355 {
3356         char buf[SIZEOF_STR * 4];
3357         const char *revlist_argv[] = {
3358                 "git", "rev-list", "-1", "--parents", id, NULL
3359         };
3360         int parents;
3361
3362         if (!run_io_buf(revlist_argv, buf, sizeof(buf)) ||
3363             !*chomp_string(buf) ||
3364             (parents = (strlen(buf) / 40) - 1) < 0) {
3365                 report("Failed to get parent information");
3366                 return FALSE;
3367
3368         } else if (parents == 0) {
3369                 report("The selected commit has no parents");
3370                 return FALSE;
3371         }
3372
3373         if (parents > 1) {
3374                 char prompt[SIZEOF_STR];
3375                 char *result;
3376
3377                 if (!string_format(prompt, "Which parent? [1..%d] ", parents))
3378                         return FALSE;
3379                 result = prompt_input(prompt, select_commit_parent_handler, &parents);
3380                 if (!result)
3381                         return FALSE;
3382                 parents = atoi(result);
3383         }
3384
3385         string_copy_rev(rev, &buf[41 * parents]);
3386         return TRUE;
3387 }
3388
3389 /*
3390  * Pager backend
3391  */
3392
3393 static bool
3394 pager_draw(struct view *view, struct line *line, unsigned int lineno)
3395 {
3396         char *text = line->data;
3397
3398         if (opt_line_number && draw_lineno(view, lineno))
3399                 return TRUE;
3400
3401         draw_text(view, line->type, text, TRUE);
3402         return TRUE;
3403 }
3404
3405 static bool
3406 add_describe_ref(char *buf, size_t *bufpos, const char *commit_id, const char *sep)
3407 {
3408         const char *describe_argv[] = { "git", "describe", commit_id, NULL };
3409         char refbuf[SIZEOF_STR];
3410         char *ref = NULL;
3411
3412         if (run_io_buf(describe_argv, refbuf, sizeof(refbuf)))
3413                 ref = chomp_string(refbuf);
3414
3415         if (!ref || !*ref)
3416                 return TRUE;
3417
3418         /* This is the only fatal call, since it can "corrupt" the buffer. */
3419         if (!string_nformat(buf, SIZEOF_STR, bufpos, "%s%s", sep, ref))
3420                 return FALSE;
3421
3422         return TRUE;
3423 }
3424
3425 static void
3426 add_pager_refs(struct view *view, struct line *line)
3427 {
3428         char buf[SIZEOF_STR];
3429         char *commit_id = (char *)line->data + STRING_SIZE("commit ");
3430         struct ref **refs;
3431         size_t bufpos = 0, refpos = 0;
3432         const char *sep = "Refs: ";
3433         bool is_tag = FALSE;
3434
3435         assert(line->type == LINE_COMMIT);
3436
3437         refs = get_refs(commit_id);
3438         if (!refs) {
3439                 if (view == VIEW(REQ_VIEW_DIFF))
3440                         goto try_add_describe_ref;
3441                 return;
3442         }
3443
3444         do {
3445                 struct ref *ref = refs[refpos];
3446                 const char *fmt = ref->tag    ? "%s[%s]" :
3447                                   ref->remote ? "%s<%s>" : "%s%s";
3448
3449                 if (!string_format_from(buf, &bufpos, fmt, sep, ref->name))
3450                         return;
3451                 sep = ", ";
3452                 if (ref->tag)
3453                         is_tag = TRUE;
3454         } while (refs[refpos++]->next);
3455
3456         if (!is_tag && view == VIEW(REQ_VIEW_DIFF)) {
3457 try_add_describe_ref:
3458                 /* Add <tag>-g<commit_id> "fake" reference. */
3459                 if (!add_describe_ref(buf, &bufpos, commit_id, sep))
3460                         return;
3461         }
3462
3463         if (bufpos == 0)
3464                 return;
3465
3466         add_line_text(view, buf, LINE_PP_REFS);
3467 }
3468
3469 static bool
3470 pager_read(struct view *view, char *data)
3471 {
3472         struct line *line;
3473
3474         if (!data)
3475                 return TRUE;
3476
3477         line = add_line_text(view, data, get_line_type(data));
3478         if (!line)
3479                 return FALSE;
3480
3481         if (line->type == LINE_COMMIT &&
3482             (view == VIEW(REQ_VIEW_DIFF) ||
3483              view == VIEW(REQ_VIEW_LOG)))
3484                 add_pager_refs(view, line);
3485
3486         return TRUE;
3487 }
3488
3489 static enum request
3490 pager_request(struct view *view, enum request request, struct line *line)
3491 {
3492         int split = 0;
3493
3494         if (request != REQ_ENTER)
3495                 return request;
3496
3497         if (line->type == LINE_COMMIT &&
3498            (view == VIEW(REQ_VIEW_LOG) ||
3499             view == VIEW(REQ_VIEW_PAGER))) {
3500                 open_view(view, REQ_VIEW_DIFF, OPEN_SPLIT);
3501                 split = 1;
3502         }
3503
3504         /* Always scroll the view even if it was split. That way
3505          * you can use Enter to scroll through the log view and
3506          * split open each commit diff. */
3507         scroll_view(view, REQ_SCROLL_LINE_DOWN);
3508
3509         /* FIXME: A minor workaround. Scrolling the view will call report("")
3510          * but if we are scrolling a non-current view this won't properly
3511          * update the view title. */
3512         if (split)
3513                 update_view_title(view);
3514
3515         return REQ_NONE;
3516 }
3517
3518 static bool
3519 pager_grep(struct view *view, struct line *line)
3520 {
3521         regmatch_t pmatch;
3522         char *text = line->data;
3523
3524         if (!*text)
3525                 return FALSE;
3526
3527         if (regexec(view->regex, text, 1, &pmatch, 0) == REG_NOMATCH)
3528                 return FALSE;
3529
3530         return TRUE;
3531 }
3532
3533 static void
3534 pager_select(struct view *view, struct line *line)
3535 {
3536         if (line->type == LINE_COMMIT) {
3537                 char *text = (char *)line->data + STRING_SIZE("commit ");
3538
3539                 if (view != VIEW(REQ_VIEW_PAGER))
3540                         string_copy_rev(view->ref, text);
3541                 string_copy_rev(ref_commit, text);
3542         }
3543 }
3544
3545 static struct view_ops pager_ops = {
3546         "line",
3547         NULL,
3548         NULL,
3549         pager_read,
3550         pager_draw,
3551         pager_request,
3552         pager_grep,
3553         pager_select,
3554 };
3555
3556 static const char *log_argv[SIZEOF_ARG] = {
3557         "git", "log", "--no-color", "--cc", "--stat", "-n100", "%(head)", NULL
3558 };
3559
3560 static enum request
3561 log_request(struct view *view, enum request request, struct line *line)
3562 {
3563         switch (request) {
3564         case REQ_REFRESH:
3565                 load_refs();
3566                 open_view(view, REQ_VIEW_LOG, OPEN_REFRESH);
3567                 return REQ_NONE;
3568         default:
3569                 return pager_request(view, request, line);
3570         }
3571 }
3572
3573 static struct view_ops log_ops = {
3574         "line",
3575         log_argv,
3576         NULL,
3577         pager_read,
3578         pager_draw,
3579         log_request,
3580         pager_grep,
3581         pager_select,
3582 };
3583
3584 static const char *diff_argv[SIZEOF_ARG] = {
3585         "git", "show", "--pretty=fuller", "--no-color", "--root",
3586                 "--patch-with-stat", "--find-copies-harder", "-C", "%(commit)", NULL
3587 };
3588
3589 static struct view_ops diff_ops = {
3590         "line",
3591         diff_argv,
3592         NULL,
3593         pager_read,
3594         pager_draw,
3595         pager_request,
3596         pager_grep,
3597         pager_select,
3598 };
3599
3600 /*
3601  * Help backend
3602  */
3603
3604 static bool
3605 help_open(struct view *view)
3606 {
3607         char buf[SIZEOF_STR];
3608         size_t bufpos;
3609         int i;
3610
3611         if (view->lines > 0)
3612                 return TRUE;
3613
3614         add_line_text(view, "Quick reference for tig keybindings:", LINE_DEFAULT);
3615
3616         for (i = 0; i < ARRAY_SIZE(req_info); i++) {
3617                 const char *key;
3618
3619                 if (req_info[i].request == REQ_NONE)
3620                         continue;
3621
3622                 if (!req_info[i].request) {
3623                         add_line_text(view, "", LINE_DEFAULT);
3624                         add_line_text(view, req_info[i].help, LINE_DEFAULT);
3625                         continue;
3626                 }
3627
3628                 key = get_key(req_info[i].request);
3629                 if (!*key)
3630                         key = "(no key defined)";
3631
3632                 for (bufpos = 0; bufpos <= req_info[i].namelen; bufpos++) {
3633                         buf[bufpos] = tolower(req_info[i].name[bufpos]);
3634                         if (buf[bufpos] == '_')
3635                                 buf[bufpos] = '-';
3636                 }
3637
3638                 add_line_format(view, LINE_DEFAULT, "    %-25s %-20s %s",
3639                                 key, buf, req_info[i].help);
3640         }
3641
3642         if (run_requests) {
3643                 add_line_text(view, "", LINE_DEFAULT);
3644                 add_line_text(view, "External commands:", LINE_DEFAULT);
3645         }
3646
3647         for (i = 0; i < run_requests; i++) {
3648                 struct run_request *req = get_run_request(REQ_NONE + i + 1);
3649                 const char *key;
3650                 int argc;
3651
3652                 if (!req)
3653                         continue;
3654
3655                 key = get_key_name(req->key);
3656                 if (!*key)
3657                         key = "(no key defined)";
3658
3659                 for (bufpos = 0, argc = 0; req->argv[argc]; argc++)
3660                         if (!string_format_from(buf, &bufpos, "%s%s",
3661                                                 argc ? " " : "", req->argv[argc]))
3662                                 return REQ_NONE;
3663
3664                 add_line_format(view, LINE_DEFAULT, "    %-10s %-14s `%s`",
3665                                 keymap_table[req->keymap].name, key, buf);
3666         }
3667
3668         return TRUE;
3669 }
3670
3671 static struct view_ops help_ops = {
3672         "line",
3673         NULL,
3674         help_open,
3675         NULL,
3676         pager_draw,
3677         pager_request,
3678         pager_grep,
3679         pager_select,
3680 };
3681
3682
3683 /*
3684  * Tree backend
3685  */
3686
3687 struct tree_stack_entry {
3688         struct tree_stack_entry *prev;  /* Entry below this in the stack */
3689         unsigned long lineno;           /* Line number to restore */
3690         char *name;                     /* Position of name in opt_path */
3691 };
3692
3693 /* The top of the path stack. */
3694 static struct tree_stack_entry *tree_stack = NULL;
3695 unsigned long tree_lineno = 0;
3696
3697 static void
3698 pop_tree_stack_entry(void)
3699 {
3700         struct tree_stack_entry *entry = tree_stack;
3701
3702         tree_lineno = entry->lineno;
3703         entry->name[0] = 0;
3704         tree_stack = entry->prev;
3705         free(entry);
3706 }
3707
3708 static void
3709 push_tree_stack_entry(const char *name, unsigned long lineno)
3710 {
3711         struct tree_stack_entry *entry = calloc(1, sizeof(*entry));
3712         size_t pathlen = strlen(opt_path);
3713
3714         if (!entry)
3715                 return;
3716
3717         entry->prev = tree_stack;
3718         entry->name = opt_path + pathlen;
3719         tree_stack = entry;
3720
3721         if (!string_format_from(opt_path, &pathlen, "%s/", name)) {
3722                 pop_tree_stack_entry();
3723                 return;
3724         }
3725
3726         /* Move the current line to the first tree entry. */
3727         tree_lineno = 1;
3728         entry->lineno = lineno;
3729 }
3730
3731 /* Parse output from git-ls-tree(1):
3732  *
3733  * 100644 blob fb0e31ea6cc679b7379631188190e975f5789c26 Makefile
3734  * 100644 blob 5304ca4260aaddaee6498f9630e7d471b8591ea6 README
3735  * 100644 blob f931e1d229c3e185caad4449bf5b66ed72462657 tig.c
3736  * 100644 blob ed09fe897f3c7c9af90bcf80cae92558ea88ae38 web.conf
3737  */
3738
3739 #define SIZEOF_TREE_ATTR \
3740         STRING_SIZE("100644 blob ed09fe897f3c7c9af90bcf80cae92558ea88ae38\t")
3741
3742 #define SIZEOF_TREE_MODE \
3743         STRING_SIZE("100644 ")
3744
3745 #define TREE_ID_OFFSET \
3746         STRING_SIZE("100644 blob ")
3747
3748 struct tree_entry {
3749         char id[SIZEOF_REV];
3750         mode_t mode;
3751         struct tm time;                 /* Date from the author ident. */
3752         char author[75];                /* Author of the commit. */
3753         char name[1];
3754 };
3755
3756 static const char *
3757 tree_path(struct line *line)
3758 {
3759         return ((struct tree_entry *) line->data)->name;
3760 }
3761
3762
3763 static int
3764 tree_compare_entry(struct line *line1, struct line *line2)
3765 {
3766         if (line1->type != line2->type)
3767                 return line1->type == LINE_TREE_DIR ? -1 : 1;
3768         return strcmp(tree_path(line1), tree_path(line2));
3769 }
3770
3771 static struct line *
3772 tree_entry(struct view *view, enum line_type type, const char *path,
3773            const char *mode, const char *id)
3774 {
3775         struct tree_entry *entry = calloc(1, sizeof(*entry) + strlen(path));
3776         struct line *line = entry ? add_line_data(view, entry, type) : NULL;
3777
3778         if (!entry || !line) {
3779                 free(entry);
3780                 return NULL;
3781         }
3782
3783         strncpy(entry->name, path, strlen(path));
3784         if (mode)
3785                 entry->mode = strtoul(mode, NULL, 8);
3786         if (id)
3787                 string_copy_rev(entry->id, id);
3788
3789         return line;
3790 }
3791
3792 static bool
3793 tree_read_date(struct view *view, char *text, bool *read_date)
3794 {
3795         static char author_name[SIZEOF_STR];
3796         static struct tm author_time;
3797
3798         if (!text && *read_date) {
3799                 *read_date = FALSE;
3800                 return TRUE;
3801
3802         } else if (!text) {
3803                 char *path = *opt_path ? opt_path : ".";
3804                 /* Find next entry to process */
3805                 const char *log_file[] = {
3806                         "git", "log", "--no-color", "--pretty=raw",
3807                                 "--cc", "--raw", view->id, "--", path, NULL
3808                 };
3809                 struct io io = {};
3810
3811                 if (!run_io_rd(&io, log_file, FORMAT_NONE)) {
3812                         report("Failed to load tree data");
3813                         return TRUE;
3814                 }
3815
3816                 done_io(view->pipe);
3817                 view->io = io;
3818                 *read_date = TRUE;
3819                 return FALSE;
3820
3821         } else if (*text == 'a' && get_line_type(text) == LINE_AUTHOR) {
3822                 parse_author_line(text + STRING_SIZE("author "),
3823                                   author_name, sizeof(author_name), &author_time);
3824
3825         } else if (*text == ':') {
3826                 char *pos;
3827                 size_t annotated = 1;
3828                 size_t i;
3829
3830                 pos = strchr(text, '\t');
3831                 if (!pos)
3832                         return TRUE;
3833                 text = pos + 1;
3834                 if (*opt_prefix && !strncmp(text, opt_prefix, strlen(opt_prefix)))
3835                         text += strlen(opt_prefix);
3836                 if (*opt_path && !strncmp(text, opt_path, strlen(opt_path)))
3837                         text += strlen(opt_path);
3838                 pos = strchr(text, '/');
3839                 if (pos)
3840                         *pos = 0;
3841
3842                 for (i = 1; i < view->lines; i++) {
3843                         struct line *line = &view->line[i];
3844                         struct tree_entry *entry = line->data;
3845
3846                         annotated += !!*entry->author;
3847                         if (*entry->author || strcmp(entry->name, text))
3848                                 continue;
3849
3850                         string_copy(entry->author, author_name);
3851                         memcpy(&entry->time, &author_time, sizeof(entry->time));
3852                         line->dirty = 1;
3853                         break;
3854                 }
3855
3856                 if (annotated == view->lines)
3857                         kill_io(view->pipe);
3858         }
3859         return TRUE;
3860 }
3861
3862 static bool
3863 tree_read(struct view *view, char *text)
3864 {
3865         static bool read_date = FALSE;
3866         struct tree_entry *data;
3867         struct line *entry, *line;
3868         enum line_type type;
3869         size_t textlen = text ? strlen(text) : 0;
3870         char *path = text + SIZEOF_TREE_ATTR;
3871
3872         if (read_date || !text)
3873                 return tree_read_date(view, text, &read_date);
3874
3875         if (textlen <= SIZEOF_TREE_ATTR)
3876                 return FALSE;
3877         if (view->lines == 0 &&
3878             !tree_entry(view, LINE_TREE_PARENT, opt_path, NULL, NULL))
3879                 return FALSE;
3880
3881         /* Strip the path part ... */
3882         if (*opt_path) {
3883                 size_t pathlen = textlen - SIZEOF_TREE_ATTR;
3884                 size_t striplen = strlen(opt_path);
3885
3886                 if (pathlen > striplen)
3887                         memmove(path, path + striplen,
3888                                 pathlen - striplen + 1);
3889
3890                 /* Insert "link" to parent directory. */
3891                 if (view->lines == 1 &&
3892                     !tree_entry(view, LINE_TREE_DIR, "..", "040000", view->ref))
3893                         return FALSE;
3894         }
3895
3896         type = text[SIZEOF_TREE_MODE] == 't' ? LINE_TREE_DIR : LINE_TREE_FILE;
3897         entry = tree_entry(view, type, path, text, text + TREE_ID_OFFSET);
3898         if (!entry)
3899                 return FALSE;
3900         data = entry->data;
3901
3902         /* Skip "Directory ..." and ".." line. */
3903         for (line = &view->line[1 + !!*opt_path]; line < entry; line++) {
3904                 if (tree_compare_entry(line, entry) <= 0)
3905                         continue;
3906
3907                 memmove(line + 1, line, (entry - line) * sizeof(*entry));
3908
3909                 line->data = data;
3910                 line->type = type;
3911                 for (; line <= entry; line++)
3912                         line->dirty = line->cleareol = 1;
3913                 return TRUE;
3914         }
3915
3916         if (tree_lineno > view->lineno) {
3917                 view->lineno = tree_lineno;
3918                 tree_lineno = 0;
3919         }
3920
3921         return TRUE;
3922 }
3923
3924 static bool
3925 tree_draw(struct view *view, struct line *line, unsigned int lineno)
3926 {
3927         struct tree_entry *entry = line->data;
3928
3929         if (line->type == LINE_TREE_PARENT) {
3930                 if (draw_text(view, line->type, "Directory path /", TRUE))
3931                         return TRUE;
3932         } else {
3933                 char mode[11] = "-r--r--r--";
3934
3935                 if (S_ISDIR(entry->mode)) {
3936                         mode[3] = mode[6] = mode[9] = 'x';
3937                         mode[0] = 'd';
3938                 }
3939                 if (S_ISLNK(entry->mode))
3940                         mode[0] = 'l';
3941                 if (entry->mode & S_IWUSR)
3942                         mode[2] = 'w';
3943                 if (entry->mode & S_IXUSR)
3944                         mode[3] = 'x';
3945                 if (entry->mode & S_IXGRP)
3946                         mode[6] = 'x';
3947                 if (entry->mode & S_IXOTH)
3948                         mode[9] = 'x';
3949                 if (draw_field(view, LINE_TREE_MODE, mode, 11, TRUE))
3950                         return TRUE;
3951
3952                 if (opt_author &&
3953                     draw_field(view, LINE_MAIN_AUTHOR, entry->author, opt_author_cols, TRUE))
3954                         return TRUE;
3955
3956                 if (opt_date && draw_date(view, *entry->author ? &entry->time : NULL))
3957                         return TRUE;
3958         }
3959         if (draw_text(view, line->type, entry->name, TRUE))
3960                 return TRUE;
3961         return TRUE;
3962 }
3963
3964 static void
3965 open_blob_editor()
3966 {
3967         char file[SIZEOF_STR] = "/tmp/tigblob.XXXXXX";
3968         int fd = mkstemp(file);
3969
3970         if (fd == -1)
3971                 report("Failed to create temporary file");
3972         else if (!run_io_append(blob_ops.argv, FORMAT_ALL, fd))
3973                 report("Failed to save blob data to file");
3974         else
3975                 open_editor(FALSE, file);
3976         if (fd != -1)
3977                 unlink(file);
3978 }
3979
3980 static enum request
3981 tree_request(struct view *view, enum request request, struct line *line)
3982 {
3983         enum open_flags flags;
3984
3985         switch (request) {
3986         case REQ_VIEW_BLAME:
3987                 if (line->type != LINE_TREE_FILE) {
3988                         report("Blame only supported for files");
3989                         return REQ_NONE;
3990                 }
3991
3992                 string_copy(opt_ref, view->vid);
3993                 return request;
3994
3995         case REQ_EDIT:
3996                 if (line->type != LINE_TREE_FILE) {
3997                         report("Edit only supported for files");
3998                 } else if (!is_head_commit(view->vid)) {
3999                         open_blob_editor();
4000                 } else {
4001                         open_editor(TRUE, opt_file);
4002                 }
4003                 return REQ_NONE;
4004
4005         case REQ_PARENT:
4006                 if (!*opt_path) {
4007                         /* quit view if at top of tree */
4008                         return REQ_VIEW_CLOSE;
4009                 }
4010                 /* fake 'cd  ..' */
4011                 line = &view->line[1];
4012                 break;
4013
4014         case REQ_ENTER:
4015                 break;
4016
4017         default:
4018                 return request;
4019         }
4020
4021         /* Cleanup the stack if the tree view is at a different tree. */
4022         while (!*opt_path && tree_stack)
4023                 pop_tree_stack_entry();
4024
4025         switch (line->type) {
4026         case LINE_TREE_DIR:
4027                 /* Depending on whether it is a subdir or parent (updir?) link
4028                  * mangle the path buffer. */
4029                 if (line == &view->line[1] && *opt_path) {
4030                         pop_tree_stack_entry();
4031
4032                 } else {
4033                         const char *basename = tree_path(line);
4034
4035                         push_tree_stack_entry(basename, view->lineno);
4036                 }
4037
4038                 /* Trees and subtrees share the same ID, so they are not not
4039                  * unique like blobs. */
4040                 flags = OPEN_RELOAD;
4041                 request = REQ_VIEW_TREE;
4042                 break;
4043
4044         case LINE_TREE_FILE:
4045                 flags = display[0] == view ? OPEN_SPLIT : OPEN_DEFAULT;
4046                 request = REQ_VIEW_BLOB;
4047                 break;
4048
4049         default:
4050                 return REQ_NONE;
4051         }
4052
4053         open_view(view, request, flags);
4054         if (request == REQ_VIEW_TREE)
4055                 view->lineno = tree_lineno;
4056
4057         return REQ_NONE;
4058 }
4059
4060 static void
4061 tree_select(struct view *view, struct line *line)
4062 {
4063         struct tree_entry *entry = line->data;
4064
4065         if (line->type == LINE_TREE_FILE) {
4066                 string_copy_rev(ref_blob, entry->id);
4067                 string_format(opt_file, "%s%s", opt_path, tree_path(line));
4068
4069         } else if (line->type != LINE_TREE_DIR) {
4070                 return;
4071         }
4072
4073         string_copy_rev(view->ref, entry->id);
4074 }
4075
4076 static const char *tree_argv[SIZEOF_ARG] = {
4077         "git", "ls-tree", "%(commit)", "%(directory)", NULL
4078 };
4079
4080 static struct view_ops tree_ops = {
4081         "file",
4082         tree_argv,
4083         NULL,
4084         tree_read,
4085         tree_draw,
4086         tree_request,
4087         pager_grep,
4088         tree_select,
4089 };
4090
4091 static bool
4092 blob_read(struct view *view, char *line)
4093 {
4094         if (!line)
4095                 return TRUE;
4096         return add_line_text(view, line, LINE_DEFAULT) != NULL;
4097 }
4098
4099 static enum request
4100 blob_request(struct view *view, enum request request, struct line *line)
4101 {
4102         switch (request) {
4103         case REQ_EDIT:
4104                 open_blob_editor();
4105                 return REQ_NONE;
4106         default:
4107                 return pager_request(view, request, line);
4108         }
4109 }
4110
4111 static const char *blob_argv[SIZEOF_ARG] = {
4112         "git", "cat-file", "blob", "%(blob)", NULL
4113 };
4114
4115 static struct view_ops blob_ops = {
4116         "line",
4117         blob_argv,
4118         NULL,
4119         blob_read,
4120         pager_draw,
4121         blob_request,
4122         pager_grep,
4123         pager_select,
4124 };
4125
4126 /*
4127  * Blame backend
4128  *
4129  * Loading the blame view is a two phase job:
4130  *
4131  *  1. File content is read either using opt_file from the
4132  *     filesystem or using git-cat-file.
4133  *  2. Then blame information is incrementally added by
4134  *     reading output from git-blame.
4135  */
4136
4137 static const char *blame_head_argv[] = {
4138         "git", "blame", "--incremental", "--", "%(file)", NULL
4139 };
4140
4141 static const char *blame_ref_argv[] = {
4142         "git", "blame", "--incremental", "%(ref)", "--", "%(file)", NULL
4143 };
4144
4145 static const char *blame_cat_file_argv[] = {
4146         "git", "cat-file", "blob", "%(ref):%(file)", NULL
4147 };
4148
4149 struct blame_commit {
4150         char id[SIZEOF_REV];            /* SHA1 ID. */
4151         char title[128];                /* First line of the commit message. */
4152         char author[75];                /* Author of the commit. */
4153         struct tm time;                 /* Date from the author ident. */
4154         char filename[128];             /* Name of file. */
4155         bool has_previous;              /* Was a "previous" line detected. */
4156 };
4157
4158 struct blame {
4159         struct blame_commit *commit;
4160         char text[1];
4161 };
4162
4163 static bool
4164 blame_open(struct view *view)
4165 {
4166         if (*opt_ref || !io_open(&view->io, opt_file)) {
4167                 if (!run_io_rd(&view->io, blame_cat_file_argv, FORMAT_ALL))
4168                         return FALSE;
4169         }
4170
4171         setup_update(view, opt_file);
4172         string_format(view->ref, "%s ...", opt_file);
4173
4174         return TRUE;
4175 }
4176
4177 static struct blame_commit *
4178 get_blame_commit(struct view *view, const char *id)
4179 {
4180         size_t i;
4181
4182         for (i = 0; i < view->lines; i++) {
4183                 struct blame *blame = view->line[i].data;
4184
4185                 if (!blame->commit)
4186                         continue;
4187
4188                 if (!strncmp(blame->commit->id, id, SIZEOF_REV - 1))
4189                         return blame->commit;
4190         }
4191
4192         {
4193                 struct blame_commit *commit = calloc(1, sizeof(*commit));
4194
4195                 if (commit)
4196                         string_ncopy(commit->id, id, SIZEOF_REV);
4197                 return commit;
4198         }
4199 }
4200
4201 static bool
4202 parse_number(const char **posref, size_t *number, size_t min, size_t max)
4203 {
4204         const char *pos = *posref;
4205
4206         *posref = NULL;
4207         pos = strchr(pos + 1, ' ');
4208         if (!pos || !isdigit(pos[1]))
4209                 return FALSE;
4210         *number = atoi(pos + 1);
4211         if (*number < min || *number > max)
4212                 return FALSE;
4213
4214         *posref = pos;
4215         return TRUE;
4216 }
4217
4218 static struct blame_commit *
4219 parse_blame_commit(struct view *view, const char *text, int *blamed)
4220 {
4221         struct blame_commit *commit;
4222         struct blame *blame;
4223         const char *pos = text + SIZEOF_REV - 1;
4224         size_t lineno;
4225         size_t group;
4226
4227         if (strlen(text) <= SIZEOF_REV || *pos != ' ')
4228                 return NULL;
4229
4230         if (!parse_number(&pos, &lineno, 1, view->lines) ||
4231             !parse_number(&pos, &group, 1, view->lines - lineno + 1))
4232                 return NULL;
4233
4234         commit = get_blame_commit(view, text);
4235         if (!commit)
4236                 return NULL;
4237
4238         *blamed += group;
4239         while (group--) {
4240                 struct line *line = &view->line[lineno + group - 1];
4241
4242                 blame = line->data;
4243                 blame->commit = commit;
4244                 line->dirty = 1;
4245         }
4246
4247         return commit;
4248 }
4249
4250 static bool
4251 blame_read_file(struct view *view, const char *line, bool *read_file)
4252 {
4253         if (!line) {
4254                 const char **argv = *opt_ref ? blame_ref_argv : blame_head_argv;
4255                 struct io io = {};
4256
4257                 if (view->lines == 0 && !view->parent)
4258                         die("No blame exist for %s", view->vid);
4259
4260                 if (view->lines == 0 || !run_io_rd(&io, argv, FORMAT_ALL)) {
4261                         report("Failed to load blame data");
4262                         return TRUE;
4263                 }
4264
4265                 done_io(view->pipe);
4266                 view->io = io;
4267                 *read_file = FALSE;
4268                 return FALSE;
4269
4270         } else {
4271                 size_t linelen = strlen(line);
4272                 struct blame *blame = malloc(sizeof(*blame) + linelen);
4273
4274                 blame->commit = NULL;
4275                 strncpy(blame->text, line, linelen);
4276                 blame->text[linelen] = 0;
4277                 return add_line_data(view, blame, LINE_BLAME_ID) != NULL;
4278         }
4279 }
4280
4281 static bool
4282 match_blame_header(const char *name, char **line)
4283 {
4284         size_t namelen = strlen(name);
4285         bool matched = !strncmp(name, *line, namelen);
4286
4287         if (matched)
4288                 *line += namelen;
4289
4290         return matched;
4291 }
4292
4293 static bool
4294 blame_read(struct view *view, char *line)
4295 {
4296         static struct blame_commit *commit = NULL;
4297         static int blamed = 0;
4298         static time_t author_time;
4299         static bool read_file = TRUE;
4300
4301         if (read_file)
4302                 return blame_read_file(view, line, &read_file);
4303
4304         if (!line) {
4305                 /* Reset all! */
4306                 commit = NULL;
4307                 blamed = 0;
4308                 read_file = TRUE;
4309                 string_format(view->ref, "%s", view->vid);
4310                 if (view_is_displayed(view)) {
4311                         update_view_title(view);
4312                         redraw_view_from(view, 0);
4313                 }
4314                 return TRUE;
4315         }
4316
4317         if (!commit) {
4318                 commit = parse_blame_commit(view, line, &blamed);
4319                 string_format(view->ref, "%s %2d%%", view->vid,
4320                               view->lines ? blamed * 100 / view->lines : 0);
4321
4322         } else if (match_blame_header("author ", &line)) {
4323                 string_ncopy(commit->author, line, strlen(line));
4324
4325         } else if (match_blame_header("author-time ", &line)) {
4326                 author_time = (time_t) atol(line);
4327
4328         } else if (match_blame_header("author-tz ", &line)) {
4329                 long tz;
4330
4331                 tz  = ('0' - line[1]) * 60 * 60 * 10;
4332                 tz += ('0' - line[2]) * 60 * 60;
4333                 tz += ('0' - line[3]) * 60;
4334                 tz += ('0' - line[4]) * 60;
4335
4336                 if (line[0] == '-')
4337                         tz = -tz;
4338
4339                 author_time -= tz;
4340                 gmtime_r(&author_time, &commit->time);
4341
4342         } else if (match_blame_header("summary ", &line)) {
4343                 string_ncopy(commit->title, line, strlen(line));
4344
4345         } else if (match_blame_header("previous ", &line)) {
4346                 commit->has_previous = TRUE;
4347
4348         } else if (match_blame_header("filename ", &line)) {
4349                 string_ncopy(commit->filename, line, strlen(line));
4350                 commit = NULL;
4351         }
4352
4353         return TRUE;
4354 }
4355
4356 static bool
4357 blame_draw(struct view *view, struct line *line, unsigned int lineno)
4358 {
4359         struct blame *blame = line->data;
4360         struct tm *time = NULL;
4361         const char *id = NULL, *author = NULL;
4362
4363         if (blame->commit && *blame->commit->filename) {
4364                 id = blame->commit->id;
4365                 author = blame->commit->author;
4366                 time = &blame->commit->time;
4367         }
4368
4369         if (opt_date && draw_date(view, time))
4370                 return TRUE;
4371
4372         if (opt_author &&
4373             draw_field(view, LINE_MAIN_AUTHOR, author, opt_author_cols, TRUE))
4374                 return TRUE;
4375
4376         if (draw_field(view, LINE_BLAME_ID, id, ID_COLS, FALSE))
4377                 return TRUE;
4378
4379         if (draw_lineno(view, lineno))
4380                 return TRUE;
4381
4382         draw_text(view, LINE_DEFAULT, blame->text, TRUE);
4383         return TRUE;
4384 }
4385
4386 static bool
4387 check_blame_commit(struct blame *blame)
4388 {
4389         if (!blame->commit)
4390                 report("Commit data not loaded yet");
4391         else if (!strcmp(blame->commit->id, NULL_ID))
4392                 report("No commit exist for the selected line");
4393         else
4394                 return TRUE;
4395         return FALSE;
4396 }
4397
4398 static enum request
4399 blame_request(struct view *view, enum request request, struct line *line)
4400 {
4401         enum open_flags flags = display[0] == view ? OPEN_SPLIT : OPEN_DEFAULT;
4402         struct blame *blame = line->data;
4403
4404         switch (request) {
4405         case REQ_VIEW_BLAME:
4406                 if (check_blame_commit(blame)) {
4407                         string_copy(opt_ref, blame->commit->id);
4408                         open_view(view, REQ_VIEW_BLAME, OPEN_REFRESH);
4409                 }
4410                 break;
4411
4412         case REQ_PARENT:
4413                 if (check_blame_commit(blame) &&
4414                     select_commit_parent(blame->commit->id, opt_ref))
4415                         open_view(view, REQ_VIEW_BLAME, OPEN_REFRESH);
4416                 break;
4417
4418         case REQ_ENTER:
4419                 if (!blame->commit) {
4420                         report("No commit loaded yet");
4421                         break;
4422                 }
4423
4424                 if (view_is_displayed(VIEW(REQ_VIEW_DIFF)) &&
4425                     !strcmp(blame->commit->id, VIEW(REQ_VIEW_DIFF)->ref))
4426                         break;
4427
4428                 if (!strcmp(blame->commit->id, NULL_ID)) {
4429                         struct view *diff = VIEW(REQ_VIEW_DIFF);
4430                         const char *diff_index_argv[] = {
4431                                 "git", "diff-index", "--root", "--patch-with-stat",
4432                                         "-C", "-M", "HEAD", "--", view->vid, NULL
4433                         };
4434
4435                         if (!blame->commit->has_previous) {
4436                                 diff_index_argv[1] = "diff";
4437                                 diff_index_argv[2] = "--no-color";
4438                                 diff_index_argv[6] = "--";
4439                                 diff_index_argv[7] = "/dev/null";
4440                         }
4441
4442                         if (!prepare_update(diff, diff_index_argv, NULL, FORMAT_DASH)) {
4443                                 report("Failed to allocate diff command");
4444                                 break;
4445                         }
4446                         flags |= OPEN_PREPARED;
4447                 }
4448
4449                 open_view(view, REQ_VIEW_DIFF, flags);
4450                 if (VIEW(REQ_VIEW_DIFF)->pipe && !strcmp(blame->commit->id, NULL_ID))
4451                         string_copy_rev(VIEW(REQ_VIEW_DIFF)->ref, NULL_ID);
4452                 break;
4453
4454         default:
4455                 return request;
4456         }
4457
4458         return REQ_NONE;
4459 }
4460
4461 static bool
4462 blame_grep(struct view *view, struct line *line)
4463 {
4464         struct blame *blame = line->data;
4465         struct blame_commit *commit = blame->commit;
4466         regmatch_t pmatch;
4467
4468 #define MATCH(text, on)                                                 \
4469         (on && *text && regexec(view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
4470
4471         if (commit) {
4472                 char buf[DATE_COLS + 1];
4473
4474                 if (MATCH(commit->title, 1) ||
4475                     MATCH(commit->author, opt_author) ||
4476                     MATCH(commit->id, opt_date))
4477                         return TRUE;
4478
4479                 if (strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time) &&
4480                     MATCH(buf, 1))
4481                         return TRUE;
4482         }
4483
4484         return MATCH(blame->text, 1);
4485
4486 #undef MATCH
4487 }
4488
4489 static void
4490 blame_select(struct view *view, struct line *line)
4491 {
4492         struct blame *blame = line->data;
4493         struct blame_commit *commit = blame->commit;
4494
4495         if (!commit)
4496                 return;
4497
4498         if (!strcmp(commit->id, NULL_ID))
4499                 string_ncopy(ref_commit, "HEAD", 4);
4500         else
4501                 string_copy_rev(ref_commit, commit->id);
4502 }
4503
4504 static struct view_ops blame_ops = {
4505         "line",
4506         NULL,
4507         blame_open,
4508         blame_read,
4509         blame_draw,
4510         blame_request,
4511         blame_grep,
4512         blame_select,
4513 };
4514
4515 /*
4516  * Status backend
4517  */
4518
4519 struct status {
4520         char status;
4521         struct {
4522                 mode_t mode;
4523                 char rev[SIZEOF_REV];
4524                 char name[SIZEOF_STR];
4525         } old;
4526         struct {
4527                 mode_t mode;
4528                 char rev[SIZEOF_REV];
4529                 char name[SIZEOF_STR];
4530         } new;
4531 };
4532
4533 static char status_onbranch[SIZEOF_STR];
4534 static struct status stage_status;
4535 static enum line_type stage_line_type;
4536 static size_t stage_chunks;
4537 static int *stage_chunk;
4538
4539 /* This should work even for the "On branch" line. */
4540 static inline bool
4541 status_has_none(struct view *view, struct line *line)
4542 {
4543         return line < view->line + view->lines && !line[1].data;
4544 }
4545
4546 /* Get fields from the diff line:
4547  * :100644 100644 06a5d6ae9eca55be2e0e585a152e6b1336f2b20e 0000000000000000000000000000000000000000 M
4548  */
4549 static inline bool
4550 status_get_diff(struct status *file, const char *buf, size_t bufsize)
4551 {
4552         const char *old_mode = buf +  1;
4553         const char *new_mode = buf +  8;
4554         const char *old_rev  = buf + 15;
4555         const char *new_rev  = buf + 56;
4556         const char *status   = buf + 97;
4557
4558         if (bufsize < 98 ||
4559             old_mode[-1] != ':' ||
4560             new_mode[-1] != ' ' ||
4561             old_rev[-1]  != ' ' ||
4562             new_rev[-1]  != ' ' ||
4563             status[-1]   != ' ')
4564                 return FALSE;
4565
4566         file->status = *status;
4567
4568         string_copy_rev(file->old.rev, old_rev);
4569         string_copy_rev(file->new.rev, new_rev);
4570
4571         file->old.mode = strtoul(old_mode, NULL, 8);
4572         file->new.mode = strtoul(new_mode, NULL, 8);
4573
4574         file->old.name[0] = file->new.name[0] = 0;
4575
4576         return TRUE;
4577 }
4578
4579 static bool
4580 status_run(struct view *view, const char *argv[], char status, enum line_type type)
4581 {
4582         struct status *file = NULL;
4583         struct status *unmerged = NULL;
4584         char *buf;
4585         struct io io = {};
4586
4587         if (!run_io(&io, argv, NULL, IO_RD))
4588                 return FALSE;
4589
4590         add_line_data(view, NULL, type);
4591
4592         while ((buf = io_get(&io, 0, TRUE))) {
4593                 if (!file) {
4594                         file = calloc(1, sizeof(*file));
4595                         if (!file || !add_line_data(view, file, type))
4596                                 goto error_out;
4597                 }
4598
4599                 /* Parse diff info part. */
4600                 if (status) {
4601                         file->status = status;
4602                         if (status == 'A')
4603                                 string_copy(file->old.rev, NULL_ID);
4604
4605                 } else if (!file->status) {
4606                         if (!status_get_diff(file, buf, strlen(buf)))
4607                                 goto error_out;
4608
4609                         buf = io_get(&io, 0, TRUE);
4610                         if (!buf)
4611                                 break;
4612
4613                         /* Collapse all 'M'odified entries that follow a
4614                          * associated 'U'nmerged entry. */
4615                         if (file->status == 'U') {
4616                                 unmerged = file;
4617
4618                         } else if (unmerged) {
4619                                 int collapse = !strcmp(buf, unmerged->new.name);
4620
4621                                 unmerged = NULL;
4622                                 if (collapse) {
4623                                         free(file);
4624                                         file = NULL;
4625                                         view->lines--;
4626                                         continue;
4627                                 }
4628                         }
4629                 }
4630
4631                 /* Grab the old name for rename/copy. */
4632                 if (!*file->old.name &&
4633                     (file->status == 'R' || file->status == 'C')) {
4634                         string_ncopy(file->old.name, buf, strlen(buf));
4635
4636                         buf = io_get(&io, 0, TRUE);
4637                         if (!buf)
4638                                 break;
4639                 }
4640
4641                 /* git-ls-files just delivers a NUL separated list of
4642                  * file names similar to the second half of the
4643                  * git-diff-* output. */
4644                 string_ncopy(file->new.name, buf, strlen(buf));
4645                 if (!*file->old.name)
4646                         string_copy(file->old.name, file->new.name);
4647                 file = NULL;
4648         }
4649
4650         if (io_error(&io)) {
4651 error_out:
4652                 done_io(&io);
4653                 return FALSE;
4654         }
4655
4656         if (!view->line[view->lines - 1].data)
4657                 add_line_data(view, NULL, LINE_STAT_NONE);
4658
4659         done_io(&io);
4660         return TRUE;
4661 }
4662
4663 /* Don't show unmerged entries in the staged section. */
4664 static const char *status_diff_index_argv[] = {
4665         "git", "diff-index", "-z", "--diff-filter=ACDMRTXB",
4666                              "--cached", "-M", "HEAD", NULL
4667 };
4668
4669 static const char *status_diff_files_argv[] = {
4670         "git", "diff-files", "-z", NULL
4671 };
4672
4673 static const char *status_list_other_argv[] = {
4674         "git", "ls-files", "-z", "--others", "--exclude-standard", NULL
4675 };
4676
4677 static const char *status_list_no_head_argv[] = {
4678         "git", "ls-files", "-z", "--cached", "--exclude-standard", NULL
4679 };
4680
4681 static const char *update_index_argv[] = {
4682         "git", "update-index", "-q", "--unmerged", "--refresh", NULL
4683 };
4684
4685 /* Restore the previous line number to stay in the context or select a
4686  * line with something that can be updated. */
4687 static void
4688 status_restore(struct view *view)
4689 {
4690         if (view->p_lineno >= view->lines)
4691                 view->p_lineno = view->lines - 1;
4692         while (view->p_lineno < view->lines && !view->line[view->p_lineno].data)
4693                 view->p_lineno++;
4694         while (view->p_lineno > 0 && !view->line[view->p_lineno].data)
4695                 view->p_lineno--;
4696
4697         /* If the above fails, always skip the "On branch" line. */
4698         if (view->p_lineno < view->lines)
4699                 view->lineno = view->p_lineno;
4700         else
4701                 view->lineno = 1;
4702
4703         if (view->lineno < view->offset)
4704                 view->offset = view->lineno;
4705         else if (view->offset + view->height <= view->lineno)
4706                 view->offset = view->lineno - view->height + 1;
4707
4708         view->p_restore = FALSE;
4709 }
4710
4711 /* First parse staged info using git-diff-index(1), then parse unstaged
4712  * info using git-diff-files(1), and finally untracked files using
4713  * git-ls-files(1). */
4714 static bool
4715 status_open(struct view *view)
4716 {
4717         reset_view(view);
4718
4719         add_line_data(view, NULL, LINE_STAT_HEAD);
4720         if (is_initial_commit())
4721                 string_copy(status_onbranch, "Initial commit");
4722         else if (!*opt_head)
4723                 string_copy(status_onbranch, "Not currently on any branch");
4724         else if (!string_format(status_onbranch, "On branch %s", opt_head))
4725                 return FALSE;
4726
4727         run_io_bg(update_index_argv);
4728
4729         if (is_initial_commit()) {
4730                 if (!status_run(view, status_list_no_head_argv, 'A', LINE_STAT_STAGED))
4731                         return FALSE;
4732         } else if (!status_run(view, status_diff_index_argv, 0, LINE_STAT_STAGED)) {
4733                 return FALSE;
4734         }
4735
4736         if (!status_run(view, status_diff_files_argv, 0, LINE_STAT_UNSTAGED) ||
4737             !status_run(view, status_list_other_argv, '?', LINE_STAT_UNTRACKED))
4738                 return FALSE;
4739
4740         /* Restore the exact position or use the specialized restore
4741          * mode? */
4742         if (!view->p_restore)
4743                 status_restore(view);
4744         return TRUE;
4745 }
4746
4747 static bool
4748 status_draw(struct view *view, struct line *line, unsigned int lineno)
4749 {
4750         struct status *status = line->data;
4751         enum line_type type;
4752         const char *text;
4753
4754         if (!status) {
4755                 switch (line->type) {
4756                 case LINE_STAT_STAGED:
4757                         type = LINE_STAT_SECTION;
4758                         text = "Changes to be committed:";
4759                         break;
4760
4761                 case LINE_STAT_UNSTAGED:
4762                         type = LINE_STAT_SECTION;
4763                         text = "Changed but not updated:";
4764                         break;
4765
4766                 case LINE_STAT_UNTRACKED:
4767                         type = LINE_STAT_SECTION;
4768                         text = "Untracked files:";
4769                         break;
4770
4771                 case LINE_STAT_NONE:
4772                         type = LINE_DEFAULT;
4773                         text = "    (no files)";
4774                         break;
4775
4776                 case LINE_STAT_HEAD:
4777                         type = LINE_STAT_HEAD;
4778                         text = status_onbranch;
4779                         break;
4780
4781                 default:
4782                         return FALSE;
4783                 }
4784         } else {
4785                 static char buf[] = { '?', ' ', ' ', ' ', 0 };
4786
4787                 buf[0] = status->status;
4788                 if (draw_text(view, line->type, buf, TRUE))
4789                         return TRUE;
4790                 type = LINE_DEFAULT;
4791                 text = status->new.name;
4792         }
4793
4794         draw_text(view, type, text, TRUE);
4795         return TRUE;
4796 }
4797
4798 static enum request
4799 status_enter(struct view *view, struct line *line)
4800 {
4801         struct status *status = line->data;
4802         const char *oldpath = status ? status->old.name : NULL;
4803         /* Diffs for unmerged entries are empty when passing the new
4804          * path, so leave it empty. */
4805         const char *newpath = status && status->status != 'U' ? status->new.name : NULL;
4806         const char *info;
4807         enum open_flags split;
4808         struct view *stage = VIEW(REQ_VIEW_STAGE);
4809
4810         if (line->type == LINE_STAT_NONE ||
4811             (!status && line[1].type == LINE_STAT_NONE)) {
4812                 report("No file to diff");
4813                 return REQ_NONE;
4814         }
4815
4816         switch (line->type) {
4817         case LINE_STAT_STAGED:
4818                 if (is_initial_commit()) {
4819                         const char *no_head_diff_argv[] = {
4820                                 "git", "diff", "--no-color", "--patch-with-stat",
4821                                         "--", "/dev/null", newpath, NULL
4822                         };
4823
4824                         if (!prepare_update(stage, no_head_diff_argv, opt_cdup, FORMAT_DASH))
4825                                 return REQ_QUIT;
4826                 } else {
4827                         const char *index_show_argv[] = {
4828                                 "git", "diff-index", "--root", "--patch-with-stat",
4829                                         "-C", "-M", "--cached", "HEAD", "--",
4830                                         oldpath, newpath, NULL
4831                         };
4832
4833                         if (!prepare_update(stage, index_show_argv, opt_cdup, FORMAT_DASH))
4834                                 return REQ_QUIT;
4835                 }
4836
4837                 if (status)
4838                         info = "Staged changes to %s";
4839                 else
4840                         info = "Staged changes";
4841                 break;
4842
4843         case LINE_STAT_UNSTAGED:
4844         {
4845                 const char *files_show_argv[] = {
4846                         "git", "diff-files", "--root", "--patch-with-stat",
4847                                 "-C", "-M", "--", oldpath, newpath, NULL
4848                 };
4849
4850                 if (!prepare_update(stage, files_show_argv, opt_cdup, FORMAT_DASH))
4851                         return REQ_QUIT;
4852                 if (status)
4853                         info = "Unstaged changes to %s";
4854                 else
4855                         info = "Unstaged changes";
4856                 break;
4857         }
4858         case LINE_STAT_UNTRACKED:
4859                 if (!newpath) {
4860                         report("No file to show");
4861                         return REQ_NONE;
4862                 }
4863
4864                 if (!suffixcmp(status->new.name, -1, "/")) {
4865                         report("Cannot display a directory");
4866                         return REQ_NONE;
4867                 }
4868
4869                 if (!prepare_update_file(stage, newpath))
4870                         return REQ_QUIT;
4871                 info = "Untracked file %s";
4872                 break;
4873
4874         case LINE_STAT_HEAD:
4875                 return REQ_NONE;
4876
4877         default:
4878                 die("line type %d not handled in switch", line->type);
4879         }
4880
4881         split = view_is_displayed(view) ? OPEN_SPLIT : 0;
4882         open_view(view, REQ_VIEW_STAGE, OPEN_PREPARED | split);
4883         if (view_is_displayed(VIEW(REQ_VIEW_STAGE))) {
4884                 if (status) {
4885                         stage_status = *status;
4886                 } else {
4887                         memset(&stage_status, 0, sizeof(stage_status));
4888                 }
4889
4890                 stage_line_type = line->type;
4891                 stage_chunks = 0;
4892                 string_format(VIEW(REQ_VIEW_STAGE)->ref, info, stage_status.new.name);
4893         }
4894
4895         return REQ_NONE;
4896 }
4897
4898 static bool
4899 status_exists(struct status *status, enum line_type type)
4900 {
4901         struct view *view = VIEW(REQ_VIEW_STATUS);
4902         unsigned long lineno;
4903
4904         for (lineno = 0; lineno < view->lines; lineno++) {
4905                 struct line *line = &view->line[lineno];
4906                 struct status *pos = line->data;
4907
4908                 if (line->type != type)
4909                         continue;
4910                 if (!pos && (!status || !status->status) && line[1].data) {
4911                         select_view_line(view, lineno);
4912                         return TRUE;
4913                 }
4914                 if (pos && !strcmp(status->new.name, pos->new.name)) {
4915                         select_view_line(view, lineno);
4916                         return TRUE;
4917                 }
4918         }
4919
4920         return FALSE;
4921 }
4922
4923
4924 static bool
4925 status_update_prepare(struct io *io, enum line_type type)
4926 {
4927         const char *staged_argv[] = {
4928                 "git", "update-index", "-z", "--index-info", NULL
4929         };
4930         const char *others_argv[] = {
4931                 "git", "update-index", "-z", "--add", "--remove", "--stdin", NULL
4932         };
4933
4934         switch (type) {
4935         case LINE_STAT_STAGED:
4936                 return run_io(io, staged_argv, opt_cdup, IO_WR);
4937
4938         case LINE_STAT_UNSTAGED:
4939                 return run_io(io, others_argv, opt_cdup, IO_WR);
4940
4941         case LINE_STAT_UNTRACKED:
4942                 return run_io(io, others_argv, NULL, IO_WR);
4943
4944         default:
4945                 die("line type %d not handled in switch", type);
4946                 return FALSE;
4947         }
4948 }
4949
4950 static bool
4951 status_update_write(struct io *io, struct status *status, enum line_type type)
4952 {
4953         char buf[SIZEOF_STR];
4954         size_t bufsize = 0;
4955
4956         switch (type) {
4957         case LINE_STAT_STAGED:
4958                 if (!string_format_from(buf, &bufsize, "%06o %s\t%s%c",
4959                                         status->old.mode,
4960                                         status->old.rev,
4961                                         status->old.name, 0))
4962                         return FALSE;
4963                 break;
4964
4965         case LINE_STAT_UNSTAGED:
4966         case LINE_STAT_UNTRACKED:
4967                 if (!string_format_from(buf, &bufsize, "%s%c", status->new.name, 0))
4968                         return FALSE;
4969                 break;
4970
4971         default:
4972                 die("line type %d not handled in switch", type);
4973         }
4974
4975         return io_write(io, buf, bufsize);
4976 }
4977
4978 static bool
4979 status_update_file(struct status *status, enum line_type type)
4980 {
4981         struct io io = {};
4982         bool result;
4983
4984         if (!status_update_prepare(&io, type))
4985                 return FALSE;
4986
4987         result = status_update_write(&io, status, type);
4988         done_io(&io);
4989         return result;
4990 }
4991
4992 static bool
4993 status_update_files(struct view *view, struct line *line)
4994 {
4995         struct io io = {};
4996         bool result = TRUE;
4997         struct line *pos = view->line + view->lines;
4998         int files = 0;
4999         int file, done;
5000
5001         if (!status_update_prepare(&io, line->type))
5002                 return FALSE;
5003
5004         for (pos = line; pos < view->line + view->lines && pos->data; pos++)
5005                 files++;
5006
5007         for (file = 0, done = 0; result && file < files; line++, file++) {
5008                 int almost_done = file * 100 / files;
5009
5010                 if (almost_done > done) {
5011                         done = almost_done;
5012                         string_format(view->ref, "updating file %u of %u (%d%% done)",
5013                                       file, files, done);
5014                         update_view_title(view);
5015                 }
5016                 result = status_update_write(&io, line->data, line->type);
5017         }
5018
5019         done_io(&io);
5020         return result;
5021 }
5022
5023 static bool
5024 status_update(struct view *view)
5025 {
5026         struct line *line = &view->line[view->lineno];
5027
5028         assert(view->lines);
5029
5030         if (!line->data) {
5031                 /* This should work even for the "On branch" line. */
5032                 if (line < view->line + view->lines && !line[1].data) {
5033                         report("Nothing to update");
5034                         return FALSE;
5035                 }
5036
5037                 if (!status_update_files(view, line + 1)) {
5038                         report("Failed to update file status");
5039                         return FALSE;
5040                 }
5041
5042         } else if (!status_update_file(line->data, line->type)) {
5043                 report("Failed to update file status");
5044                 return FALSE;
5045         }
5046
5047         return TRUE;
5048 }
5049
5050 static bool
5051 status_revert(struct status *status, enum line_type type, bool has_none)
5052 {
5053         if (!status || type != LINE_STAT_UNSTAGED) {
5054                 if (type == LINE_STAT_STAGED) {
5055                         report("Cannot revert changes to staged files");
5056                 } else if (type == LINE_STAT_UNTRACKED) {
5057                         report("Cannot revert changes to untracked files");
5058                 } else if (has_none) {
5059                         report("Nothing to revert");
5060                 } else {
5061                         report("Cannot revert changes to multiple files");
5062                 }
5063                 return FALSE;
5064
5065         } else {
5066                 const char *checkout_argv[] = {
5067                         "git", "checkout", "--", status->old.name, NULL
5068                 };
5069
5070                 if (!prompt_yesno("Are you sure you want to overwrite any changes?"))
5071                         return FALSE;
5072                 return run_io_fg(checkout_argv, opt_cdup);
5073         }
5074 }
5075
5076 static enum request
5077 status_request(struct view *view, enum request request, struct line *line)
5078 {
5079         struct status *status = line->data;
5080
5081         switch (request) {
5082         case REQ_STATUS_UPDATE:
5083                 if (!status_update(view))
5084                         return REQ_NONE;
5085                 break;
5086
5087         case REQ_STATUS_REVERT:
5088                 if (!status_revert(status, line->type, status_has_none(view, line)))
5089                         return REQ_NONE;
5090                 break;
5091
5092         case REQ_STATUS_MERGE:
5093                 if (!status || status->status != 'U') {
5094                         report("Merging only possible for files with unmerged status ('U').");
5095                         return REQ_NONE;
5096                 }
5097                 open_mergetool(status->new.name);
5098                 break;
5099
5100         case REQ_EDIT:
5101                 if (!status)
5102                         return request;
5103                 if (status->status == 'D') {
5104                         report("File has been deleted.");
5105                         return REQ_NONE;
5106                 }
5107
5108                 open_editor(status->status != '?', status->new.name);
5109                 break;
5110
5111         case REQ_VIEW_BLAME:
5112                 if (status) {
5113                         string_copy(opt_file, status->new.name);
5114                         opt_ref[0] = 0;
5115                 }
5116                 return request;
5117
5118         case REQ_ENTER:
5119                 /* After returning the status view has been split to
5120                  * show the stage view. No further reloading is
5121                  * necessary. */
5122                 status_enter(view, line);
5123                 return REQ_NONE;
5124
5125         case REQ_REFRESH:
5126                 /* Simply reload the view. */
5127                 break;
5128
5129         default:
5130                 return request;
5131         }
5132
5133         open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD);
5134
5135         return REQ_NONE;
5136 }
5137
5138 static void
5139 status_select(struct view *view, struct line *line)
5140 {
5141         struct status *status = line->data;
5142         char file[SIZEOF_STR] = "all files";
5143         const char *text;
5144         const char *key;
5145
5146         if (status && !string_format(file, "'%s'", status->new.name))
5147                 return;
5148
5149         if (!status && line[1].type == LINE_STAT_NONE)
5150                 line++;
5151
5152         switch (line->type) {
5153         case LINE_STAT_STAGED:
5154                 text = "Press %s to unstage %s for commit";
5155                 break;
5156
5157         case LINE_STAT_UNSTAGED:
5158                 text = "Press %s to stage %s for commit";
5159                 break;
5160
5161         case LINE_STAT_UNTRACKED:
5162                 text = "Press %s to stage %s for addition";
5163                 break;
5164
5165         case LINE_STAT_HEAD:
5166         case LINE_STAT_NONE:
5167                 text = "Nothing to update";
5168                 break;
5169
5170         default:
5171                 die("line type %d not handled in switch", line->type);
5172         }
5173
5174         if (status && status->status == 'U') {
5175                 text = "Press %s to resolve conflict in %s";
5176                 key = get_key(REQ_STATUS_MERGE);
5177
5178         } else {
5179                 key = get_key(REQ_STATUS_UPDATE);
5180         }
5181
5182         string_format(view->ref, text, key, file);
5183 }
5184
5185 static bool
5186 status_grep(struct view *view, struct line *line)
5187 {
5188         struct status *status = line->data;
5189         enum { S_STATUS, S_NAME, S_END } state;
5190         char buf[2] = "?";
5191         regmatch_t pmatch;
5192
5193         if (!status)
5194                 return FALSE;
5195
5196         for (state = S_STATUS; state < S_END; state++) {
5197                 const char *text;
5198
5199                 switch (state) {
5200                 case S_NAME:    text = status->new.name;        break;
5201                 case S_STATUS:
5202                         buf[0] = status->status;
5203                         text = buf;
5204                         break;
5205
5206                 default:
5207                         return FALSE;
5208                 }
5209
5210                 if (regexec(view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
5211                         return TRUE;
5212         }
5213
5214         return FALSE;
5215 }
5216
5217 static struct view_ops status_ops = {
5218         "file",
5219         NULL,
5220         status_open,
5221         NULL,
5222         status_draw,
5223         status_request,
5224         status_grep,
5225         status_select,
5226 };
5227
5228
5229 static bool
5230 stage_diff_write(struct io *io, struct line *line, struct line *end)
5231 {
5232         while (line < end) {
5233                 if (!io_write(io, line->data, strlen(line->data)) ||
5234                     !io_write(io, "\n", 1))
5235                         return FALSE;
5236                 line++;
5237                 if (line->type == LINE_DIFF_CHUNK ||
5238                     line->type == LINE_DIFF_HEADER)
5239                         break;
5240         }
5241
5242         return TRUE;
5243 }
5244
5245 static struct line *
5246 stage_diff_find(struct view *view, struct line *line, enum line_type type)
5247 {
5248         for (; view->line < line; line--)
5249                 if (line->type == type)
5250                         return line;
5251
5252         return NULL;
5253 }
5254
5255 static bool
5256 stage_apply_chunk(struct view *view, struct line *chunk, bool revert)
5257 {
5258         const char *apply_argv[SIZEOF_ARG] = {
5259                 "git", "apply", "--whitespace=nowarn", NULL
5260         };
5261         struct line *diff_hdr;
5262         struct io io = {};
5263         int argc = 3;
5264
5265         diff_hdr = stage_diff_find(view, chunk, LINE_DIFF_HEADER);
5266         if (!diff_hdr)
5267                 return FALSE;
5268
5269         if (!revert)
5270                 apply_argv[argc++] = "--cached";
5271         if (revert || stage_line_type == LINE_STAT_STAGED)
5272                 apply_argv[argc++] = "-R";
5273         apply_argv[argc++] = "-";
5274         apply_argv[argc++] = NULL;
5275         if (!run_io(&io, apply_argv, opt_cdup, IO_WR))
5276                 return FALSE;
5277
5278         if (!stage_diff_write(&io, diff_hdr, chunk) ||
5279             !stage_diff_write(&io, chunk, view->line + view->lines))
5280                 chunk = NULL;
5281
5282         done_io(&io);
5283         run_io_bg(update_index_argv);
5284
5285         return chunk ? TRUE : FALSE;
5286 }
5287
5288 static bool
5289 stage_update(struct view *view, struct line *line)
5290 {
5291         struct line *chunk = NULL;
5292
5293         if (!is_initial_commit() && stage_line_type != LINE_STAT_UNTRACKED)
5294                 chunk = stage_diff_find(view, line, LINE_DIFF_CHUNK);
5295
5296         if (chunk) {
5297                 if (!stage_apply_chunk(view, chunk, FALSE)) {
5298                         report("Failed to apply chunk");
5299                         return FALSE;
5300                 }
5301
5302         } else if (!stage_status.status) {
5303                 view = VIEW(REQ_VIEW_STATUS);
5304
5305                 for (line = view->line; line < view->line + view->lines; line++)
5306                         if (line->type == stage_line_type)
5307                                 break;
5308
5309                 if (!status_update_files(view, line + 1)) {
5310                         report("Failed to update files");
5311                         return FALSE;
5312                 }
5313
5314         } else if (!status_update_file(&stage_status, stage_line_type)) {
5315                 report("Failed to update file");
5316                 return FALSE;
5317         }
5318
5319         return TRUE;
5320 }
5321
5322 static bool
5323 stage_revert(struct view *view, struct line *line)
5324 {
5325         struct line *chunk = NULL;
5326
5327         if (!is_initial_commit() && stage_line_type == LINE_STAT_UNSTAGED)
5328                 chunk = stage_diff_find(view, line, LINE_DIFF_CHUNK);
5329
5330         if (chunk) {
5331                 if (!prompt_yesno("Are you sure you want to revert changes?"))
5332                         return FALSE;
5333
5334                 if (!stage_apply_chunk(view, chunk, TRUE)) {
5335                         report("Failed to revert chunk");
5336                         return FALSE;
5337                 }
5338                 return TRUE;
5339
5340         } else {
5341                 return status_revert(stage_status.status ? &stage_status : NULL,
5342                                      stage_line_type, FALSE);
5343         }
5344 }
5345
5346
5347 static void
5348 stage_next(struct view *view, struct line *line)
5349 {
5350         int i;
5351
5352         if (!stage_chunks) {
5353                 static size_t alloc = 0;
5354                 int *tmp;
5355
5356                 for (line = view->line; line < view->line + view->lines; line++) {
5357                         if (line->type != LINE_DIFF_CHUNK)
5358                                 continue;
5359
5360                         tmp = realloc_items(stage_chunk, &alloc,
5361                                             stage_chunks, sizeof(*tmp));
5362                         if (!tmp) {
5363                                 report("Allocation failure");
5364                                 return;
5365                         }
5366
5367                         stage_chunk = tmp;
5368                         stage_chunk[stage_chunks++] = line - view->line;
5369                 }
5370         }
5371
5372         for (i = 0; i < stage_chunks; i++) {
5373                 if (stage_chunk[i] > view->lineno) {
5374                         do_scroll_view(view, stage_chunk[i] - view->lineno);
5375                         report("Chunk %d of %d", i + 1, stage_chunks);
5376                         return;
5377                 }
5378         }
5379
5380         report("No next chunk found");
5381 }
5382
5383 static enum request
5384 stage_request(struct view *view, enum request request, struct line *line)
5385 {
5386         switch (request) {
5387         case REQ_STATUS_UPDATE:
5388                 if (!stage_update(view, line))
5389                         return REQ_NONE;
5390                 break;
5391
5392         case REQ_STATUS_REVERT:
5393                 if (!stage_revert(view, line))
5394                         return REQ_NONE;
5395                 break;
5396
5397         case REQ_STAGE_NEXT:
5398                 if (stage_line_type == LINE_STAT_UNTRACKED) {
5399                         report("File is untracked; press %s to add",
5400                                get_key(REQ_STATUS_UPDATE));
5401                         return REQ_NONE;
5402                 }
5403                 stage_next(view, line);
5404                 return REQ_NONE;
5405
5406         case REQ_EDIT:
5407                 if (!stage_status.new.name[0])
5408                         return request;
5409                 if (stage_status.status == 'D') {
5410                         report("File has been deleted.");
5411                         return REQ_NONE;
5412                 }
5413
5414                 open_editor(stage_status.status != '?', stage_status.new.name);
5415                 break;
5416
5417         case REQ_REFRESH:
5418                 /* Reload everything ... */
5419                 break;
5420
5421         case REQ_VIEW_BLAME:
5422                 if (stage_status.new.name[0]) {
5423                         string_copy(opt_file, stage_status.new.name);
5424                         opt_ref[0] = 0;
5425                 }
5426                 return request;
5427
5428         case REQ_ENTER:
5429                 return pager_request(view, request, line);
5430
5431         default:
5432                 return request;
5433         }
5434
5435         VIEW(REQ_VIEW_STATUS)->p_restore = TRUE;
5436         open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD | OPEN_NOMAXIMIZE);
5437
5438         /* Check whether the staged entry still exists, and close the
5439          * stage view if it doesn't. */
5440         if (!status_exists(&stage_status, stage_line_type)) {
5441                 status_restore(VIEW(REQ_VIEW_STATUS));
5442                 return REQ_VIEW_CLOSE;
5443         }
5444
5445         if (stage_line_type == LINE_STAT_UNTRACKED) {
5446                 if (!suffixcmp(stage_status.new.name, -1, "/")) {
5447                         report("Cannot display a directory");
5448                         return REQ_NONE;
5449                 }
5450
5451                 if (!prepare_update_file(view, stage_status.new.name)) {
5452                         report("Failed to open file: %s", strerror(errno));
5453                         return REQ_NONE;
5454                 }
5455         }
5456         open_view(view, REQ_VIEW_STAGE, OPEN_REFRESH);
5457
5458         return REQ_NONE;
5459 }
5460
5461 static struct view_ops stage_ops = {
5462         "line",
5463         NULL,
5464         NULL,
5465         pager_read,
5466         pager_draw,
5467         stage_request,
5468         pager_grep,
5469         pager_select,
5470 };
5471
5472
5473 /*
5474  * Revision graph
5475  */
5476
5477 struct commit {
5478         char id[SIZEOF_REV];            /* SHA1 ID. */
5479         char title[128];                /* First line of the commit message. */
5480         char author[75];                /* Author of the commit. */
5481         struct tm time;                 /* Date from the author ident. */
5482         struct ref **refs;              /* Repository references. */
5483         chtype graph[SIZEOF_REVGRAPH];  /* Ancestry chain graphics. */
5484         size_t graph_size;              /* The width of the graph array. */
5485         bool has_parents;               /* Rewritten --parents seen. */
5486 };
5487
5488 /* Size of rev graph with no  "padding" columns */
5489 #define SIZEOF_REVITEMS (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2))
5490
5491 struct rev_graph {
5492         struct rev_graph *prev, *next, *parents;
5493         char rev[SIZEOF_REVITEMS][SIZEOF_REV];
5494         size_t size;
5495         struct commit *commit;
5496         size_t pos;
5497         unsigned int boundary:1;
5498 };
5499
5500 /* Parents of the commit being visualized. */
5501 static struct rev_graph graph_parents[4];
5502
5503 /* The current stack of revisions on the graph. */
5504 static struct rev_graph graph_stacks[4] = {
5505         { &graph_stacks[3], &graph_stacks[1], &graph_parents[0] },
5506         { &graph_stacks[0], &graph_stacks[2], &graph_parents[1] },
5507         { &graph_stacks[1], &graph_stacks[3], &graph_parents[2] },
5508         { &graph_stacks[2], &graph_stacks[0], &graph_parents[3] },
5509 };
5510
5511 static inline bool
5512 graph_parent_is_merge(struct rev_graph *graph)
5513 {
5514         return graph->parents->size > 1;
5515 }
5516
5517 static inline void
5518 append_to_rev_graph(struct rev_graph *graph, chtype symbol)
5519 {
5520         struct commit *commit = graph->commit;
5521
5522         if (commit->graph_size < ARRAY_SIZE(commit->graph) - 1)
5523                 commit->graph[commit->graph_size++] = symbol;
5524 }
5525
5526 static void
5527 clear_rev_graph(struct rev_graph *graph)
5528 {
5529         graph->boundary = 0;
5530         graph->size = graph->pos = 0;
5531         graph->commit = NULL;
5532         memset(graph->parents, 0, sizeof(*graph->parents));
5533 }
5534
5535 static void
5536 done_rev_graph(struct rev_graph *graph)
5537 {
5538         if (graph_parent_is_merge(graph) &&
5539             graph->pos < graph->size - 1 &&
5540             graph->next->size == graph->size + graph->parents->size - 1) {
5541                 size_t i = graph->pos + graph->parents->size - 1;
5542
5543                 graph->commit->graph_size = i * 2;
5544                 while (i < graph->next->size - 1) {
5545                         append_to_rev_graph(graph, ' ');
5546                         append_to_rev_graph(graph, '\\');
5547                         i++;
5548                 }
5549         }
5550
5551         clear_rev_graph(graph);
5552 }
5553
5554 static void
5555 push_rev_graph(struct rev_graph *graph, const char *parent)
5556 {
5557         int i;
5558
5559         /* "Collapse" duplicate parents lines.
5560          *
5561          * FIXME: This needs to also update update the drawn graph but
5562          * for now it just serves as a method for pruning graph lines. */
5563         for (i = 0; i < graph->size; i++)
5564                 if (!strncmp(graph->rev[i], parent, SIZEOF_REV))
5565                         return;
5566
5567         if (graph->size < SIZEOF_REVITEMS) {
5568                 string_copy_rev(graph->rev[graph->size++], parent);
5569         }
5570 }
5571
5572 static chtype
5573 get_rev_graph_symbol(struct rev_graph *graph)
5574 {
5575         chtype symbol;
5576
5577         if (graph->boundary)
5578                 symbol = REVGRAPH_BOUND;
5579         else if (graph->parents->size == 0)
5580                 symbol = REVGRAPH_INIT;
5581         else if (graph_parent_is_merge(graph))
5582                 symbol = REVGRAPH_MERGE;
5583         else if (graph->pos >= graph->size)
5584                 symbol = REVGRAPH_BRANCH;
5585         else
5586                 symbol = REVGRAPH_COMMIT;
5587
5588         return symbol;
5589 }
5590
5591 static void
5592 draw_rev_graph(struct rev_graph *graph)
5593 {
5594         struct rev_filler {
5595                 chtype separator, line;
5596         };
5597         enum { DEFAULT, RSHARP, RDIAG, LDIAG };
5598         static struct rev_filler fillers[] = {
5599                 { ' ',  '|' },
5600                 { '`',  '.' },
5601                 { '\'', ' ' },
5602                 { '/',  ' ' },
5603         };
5604         chtype symbol = get_rev_graph_symbol(graph);
5605         struct rev_filler *filler;
5606         size_t i;
5607
5608         if (opt_line_graphics)
5609                 fillers[DEFAULT].line = line_graphics[LINE_GRAPHIC_VLINE];
5610
5611         filler = &fillers[DEFAULT];
5612
5613         for (i = 0; i < graph->pos; i++) {
5614                 append_to_rev_graph(graph, filler->line);
5615                 if (graph_parent_is_merge(graph->prev) &&
5616                     graph->prev->pos == i)
5617                         filler = &fillers[RSHARP];
5618
5619                 append_to_rev_graph(graph, filler->separator);
5620         }
5621
5622         /* Place the symbol for this revision. */
5623         append_to_rev_graph(graph, symbol);
5624
5625         if (graph->prev->size > graph->size)
5626                 filler = &fillers[RDIAG];
5627         else
5628                 filler = &fillers[DEFAULT];
5629
5630         i++;
5631
5632         for (; i < graph->size; i++) {
5633                 append_to_rev_graph(graph, filler->separator);
5634                 append_to_rev_graph(graph, filler->line);
5635                 if (graph_parent_is_merge(graph->prev) &&
5636                     i < graph->prev->pos + graph->parents->size)
5637                         filler = &fillers[RSHARP];
5638                 if (graph->prev->size > graph->size)
5639                         filler = &fillers[LDIAG];
5640         }
5641
5642         if (graph->prev->size > graph->size) {
5643                 append_to_rev_graph(graph, filler->separator);
5644                 if (filler->line != ' ')
5645                         append_to_rev_graph(graph, filler->line);
5646         }
5647 }
5648
5649 /* Prepare the next rev graph */
5650 static void
5651 prepare_rev_graph(struct rev_graph *graph)
5652 {
5653         size_t i;
5654
5655         /* First, traverse all lines of revisions up to the active one. */
5656         for (graph->pos = 0; graph->pos < graph->size; graph->pos++) {
5657                 if (!strcmp(graph->rev[graph->pos], graph->commit->id))
5658                         break;
5659
5660                 push_rev_graph(graph->next, graph->rev[graph->pos]);
5661         }
5662
5663         /* Interleave the new revision parent(s). */
5664         for (i = 0; !graph->boundary && i < graph->parents->size; i++)
5665                 push_rev_graph(graph->next, graph->parents->rev[i]);
5666
5667         /* Lastly, put any remaining revisions. */
5668         for (i = graph->pos + 1; i < graph->size; i++)
5669                 push_rev_graph(graph->next, graph->rev[i]);
5670 }
5671
5672 static void
5673 update_rev_graph(struct view *view, struct rev_graph *graph)
5674 {
5675         /* If this is the finalizing update ... */
5676         if (graph->commit)
5677                 prepare_rev_graph(graph);
5678
5679         /* Graph visualization needs a one rev look-ahead,
5680          * so the first update doesn't visualize anything. */
5681         if (!graph->prev->commit)
5682                 return;
5683
5684         if (view->lines > 2)
5685                 view->line[view->lines - 3].dirty = 1;
5686         if (view->lines > 1)
5687                 view->line[view->lines - 2].dirty = 1;
5688         draw_rev_graph(graph->prev);
5689         done_rev_graph(graph->prev->prev);
5690 }
5691
5692
5693 /*
5694  * Main view backend
5695  */
5696
5697 static const char *main_argv[SIZEOF_ARG] = {
5698         "git", "log", "--no-color", "--pretty=raw", "--parents",
5699                       "--topo-order", "%(head)", NULL
5700 };
5701
5702 static bool
5703 main_draw(struct view *view, struct line *line, unsigned int lineno)
5704 {
5705         struct commit *commit = line->data;
5706
5707         if (!*commit->author)
5708                 return FALSE;
5709
5710         if (opt_date && draw_date(view, &commit->time))
5711                 return TRUE;
5712
5713         if (opt_author &&
5714             draw_field(view, LINE_MAIN_AUTHOR, commit->author, opt_author_cols, TRUE))
5715                 return TRUE;
5716
5717         if (opt_rev_graph && commit->graph_size &&
5718             draw_graphic(view, LINE_MAIN_REVGRAPH, commit->graph, commit->graph_size))
5719                 return TRUE;
5720
5721         if (opt_show_refs && commit->refs) {
5722                 size_t i = 0;
5723
5724                 do {
5725                         enum line_type type;
5726
5727                         if (commit->refs[i]->head)
5728                                 type = LINE_MAIN_HEAD;
5729                         else if (commit->refs[i]->ltag)
5730                                 type = LINE_MAIN_LOCAL_TAG;
5731                         else if (commit->refs[i]->tag)
5732                                 type = LINE_MAIN_TAG;
5733                         else if (commit->refs[i]->tracked)
5734                                 type = LINE_MAIN_TRACKED;
5735                         else if (commit->refs[i]->remote)
5736                                 type = LINE_MAIN_REMOTE;
5737                         else
5738                                 type = LINE_MAIN_REF;
5739
5740                         if (draw_text(view, type, "[", TRUE) ||
5741                             draw_text(view, type, commit->refs[i]->name, TRUE) ||
5742                             draw_text(view, type, "]", TRUE))
5743                                 return TRUE;
5744
5745                         if (draw_text(view, LINE_DEFAULT, " ", TRUE))
5746                                 return TRUE;
5747                 } while (commit->refs[i++]->next);
5748         }
5749
5750         draw_text(view, LINE_DEFAULT, commit->title, TRUE);
5751         return TRUE;
5752 }
5753
5754 /* Reads git log --pretty=raw output and parses it into the commit struct. */
5755 static bool
5756 main_read(struct view *view, char *line)
5757 {
5758         static struct rev_graph *graph = graph_stacks;
5759         enum line_type type;
5760         struct commit *commit;
5761
5762         if (!line) {
5763                 int i;
5764
5765                 if (!view->lines && !view->parent)
5766                         die("No revisions match the given arguments.");
5767                 if (view->lines > 0) {
5768                         commit = view->line[view->lines - 1].data;
5769                         view->line[view->lines - 1].dirty = 1;
5770                         if (!*commit->author) {
5771                                 view->lines--;
5772                                 free(commit);
5773                                 graph->commit = NULL;
5774                         }
5775                 }
5776                 update_rev_graph(view, graph);
5777
5778                 for (i = 0; i < ARRAY_SIZE(graph_stacks); i++)
5779                         clear_rev_graph(&graph_stacks[i]);
5780                 return TRUE;
5781         }
5782
5783         type = get_line_type(line);
5784         if (type == LINE_COMMIT) {
5785                 commit = calloc(1, sizeof(struct commit));
5786                 if (!commit)
5787                         return FALSE;
5788
5789                 line += STRING_SIZE("commit ");
5790                 if (*line == '-') {
5791                         graph->boundary = 1;
5792                         line++;
5793                 }
5794
5795                 string_copy_rev(commit->id, line);
5796                 commit->refs = get_refs(commit->id);
5797                 graph->commit = commit;
5798                 add_line_data(view, commit, LINE_MAIN_COMMIT);
5799
5800                 while ((line = strchr(line, ' '))) {
5801                         line++;
5802                         push_rev_graph(graph->parents, line);
5803                         commit->has_parents = TRUE;
5804                 }
5805                 return TRUE;
5806         }
5807
5808         if (!view->lines)
5809                 return TRUE;
5810         commit = view->line[view->lines - 1].data;
5811
5812         switch (type) {
5813         case LINE_PARENT:
5814                 if (commit->has_parents)
5815                         break;
5816                 push_rev_graph(graph->parents, line + STRING_SIZE("parent "));
5817                 break;
5818
5819         case LINE_AUTHOR:
5820                 parse_author_line(line + STRING_SIZE("author "),
5821                                   commit->author, sizeof(commit->author),
5822                                   &commit->time);
5823                 update_rev_graph(view, graph);
5824                 graph = graph->next;
5825                 break;
5826
5827         default:
5828                 /* Fill in the commit title if it has not already been set. */
5829                 if (commit->title[0])
5830                         break;
5831
5832                 /* Require titles to start with a non-space character at the
5833                  * offset used by git log. */
5834                 if (strncmp(line, "    ", 4))
5835                         break;
5836                 line += 4;
5837                 /* Well, if the title starts with a whitespace character,
5838                  * try to be forgiving.  Otherwise we end up with no title. */
5839                 while (isspace(*line))
5840                         line++;
5841                 if (*line == '\0')
5842                         break;
5843                 /* FIXME: More graceful handling of titles; append "..." to
5844                  * shortened titles, etc. */
5845
5846                 string_ncopy(commit->title, line, strlen(line));
5847                 view->line[view->lines - 1].dirty = 1;
5848         }
5849
5850         return TRUE;
5851 }
5852
5853 static enum request
5854 main_request(struct view *view, enum request request, struct line *line)
5855 {
5856         enum open_flags flags = display[0] == view ? OPEN_SPLIT : OPEN_DEFAULT;
5857
5858         switch (request) {
5859         case REQ_ENTER:
5860                 open_view(view, REQ_VIEW_DIFF, flags);
5861                 break;
5862         case REQ_REFRESH:
5863                 load_refs();
5864                 open_view(view, REQ_VIEW_MAIN, OPEN_REFRESH);
5865                 break;
5866         default:
5867                 return request;
5868         }
5869
5870         return REQ_NONE;
5871 }
5872
5873 static bool
5874 grep_refs(struct ref **refs, regex_t *regex)
5875 {
5876         regmatch_t pmatch;
5877         size_t i = 0;
5878
5879         if (!refs)
5880                 return FALSE;
5881         do {
5882                 if (regexec(regex, refs[i]->name, 1, &pmatch, 0) != REG_NOMATCH)
5883                         return TRUE;
5884         } while (refs[i++]->next);
5885
5886         return FALSE;
5887 }
5888
5889 static bool
5890 main_grep(struct view *view, struct line *line)
5891 {
5892         struct commit *commit = line->data;
5893         enum { S_TITLE, S_AUTHOR, S_DATE, S_REFS, S_END } state;
5894         char buf[DATE_COLS + 1];
5895         regmatch_t pmatch;
5896
5897         for (state = S_TITLE; state < S_END; state++) {
5898                 char *text;
5899
5900                 switch (state) {
5901                 case S_TITLE:   text = commit->title;   break;
5902                 case S_AUTHOR:
5903                         if (!opt_author)
5904                                 continue;
5905                         text = commit->author;
5906                         break;
5907                 case S_DATE:
5908                         if (!opt_date)
5909                                 continue;
5910                         if (!strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time))
5911                                 continue;
5912                         text = buf;
5913                         break;
5914                 case S_REFS:
5915                         if (!opt_show_refs)
5916                                 continue;
5917                         if (grep_refs(commit->refs, view->regex) == TRUE)
5918                                 return TRUE;
5919                         continue;
5920                 default:
5921                         return FALSE;
5922                 }
5923
5924                 if (regexec(view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
5925                         return TRUE;
5926         }
5927
5928         return FALSE;
5929 }
5930
5931 static void
5932 main_select(struct view *view, struct line *line)
5933 {
5934         struct commit *commit = line->data;
5935
5936         string_copy_rev(view->ref, commit->id);
5937         string_copy_rev(ref_commit, view->ref);
5938 }
5939
5940 static struct view_ops main_ops = {
5941         "commit",
5942         main_argv,
5943         NULL,
5944         main_read,
5945         main_draw,
5946         main_request,
5947         main_grep,
5948         main_select,
5949 };
5950
5951
5952 /*
5953  * Unicode / UTF-8 handling
5954  *
5955  * NOTE: Much of the following code for dealing with unicode is derived from
5956  * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
5957  * src/intl/charset.c from the utf8 branch commit elinks-0.11.0-g31f2c28.
5958  */
5959
5960 /* I've (over)annotated a lot of code snippets because I am not entirely
5961  * confident that the approach taken by this small UTF-8 interface is correct.
5962  * --jonas */
5963
5964 static inline int
5965 unicode_width(unsigned long c)
5966 {
5967         if (c >= 0x1100 &&
5968            (c <= 0x115f                         /* Hangul Jamo */
5969             || c == 0x2329
5970             || c == 0x232a
5971             || (c >= 0x2e80  && c <= 0xa4cf && c != 0x303f)
5972                                                 /* CJK ... Yi */
5973             || (c >= 0xac00  && c <= 0xd7a3)    /* Hangul Syllables */
5974             || (c >= 0xf900  && c <= 0xfaff)    /* CJK Compatibility Ideographs */
5975             || (c >= 0xfe30  && c <= 0xfe6f)    /* CJK Compatibility Forms */
5976             || (c >= 0xff00  && c <= 0xff60)    /* Fullwidth Forms */
5977             || (c >= 0xffe0  && c <= 0xffe6)
5978             || (c >= 0x20000 && c <= 0x2fffd)
5979             || (c >= 0x30000 && c <= 0x3fffd)))
5980                 return 2;
5981
5982         if (c == '\t')
5983                 return opt_tab_size;
5984
5985         return 1;
5986 }
5987
5988 /* Number of bytes used for encoding a UTF-8 character indexed by first byte.
5989  * Illegal bytes are set one. */
5990 static const unsigned char utf8_bytes[256] = {
5991         1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
5992         1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
5993         1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
5994         1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
5995         1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
5996         1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
5997         2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
5998         3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
5999 };
6000
6001 /* Decode UTF-8 multi-byte representation into a unicode character. */
6002 static inline unsigned long
6003 utf8_to_unicode(const char *string, size_t length)
6004 {
6005         unsigned long unicode;
6006
6007         switch (length) {
6008         case 1:
6009                 unicode  =   string[0];
6010                 break;
6011         case 2:
6012                 unicode  =  (string[0] & 0x1f) << 6;
6013                 unicode +=  (string[1] & 0x3f);
6014                 break;
6015         case 3:
6016                 unicode  =  (string[0] & 0x0f) << 12;
6017                 unicode += ((string[1] & 0x3f) << 6);
6018                 unicode +=  (string[2] & 0x3f);
6019                 break;
6020         case 4:
6021                 unicode  =  (string[0] & 0x0f) << 18;
6022                 unicode += ((string[1] & 0x3f) << 12);
6023                 unicode += ((string[2] & 0x3f) << 6);
6024                 unicode +=  (string[3] & 0x3f);
6025                 break;
6026         case 5:
6027                 unicode  =  (string[0] & 0x0f) << 24;
6028                 unicode += ((string[1] & 0x3f) << 18);
6029                 unicode += ((string[2] & 0x3f) << 12);
6030                 unicode += ((string[3] & 0x3f) << 6);
6031                 unicode +=  (string[4] & 0x3f);
6032                 break;
6033         case 6:
6034                 unicode  =  (string[0] & 0x01) << 30;
6035                 unicode += ((string[1] & 0x3f) << 24);
6036                 unicode += ((string[2] & 0x3f) << 18);
6037                 unicode += ((string[3] & 0x3f) << 12);
6038                 unicode += ((string[4] & 0x3f) << 6);
6039                 unicode +=  (string[5] & 0x3f);
6040                 break;
6041         default:
6042                 die("Invalid unicode length");
6043         }
6044
6045         /* Invalid characters could return the special 0xfffd value but NUL
6046          * should be just as good. */
6047         return unicode > 0xffff ? 0 : unicode;
6048 }
6049
6050 /* Calculates how much of string can be shown within the given maximum width
6051  * and sets trimmed parameter to non-zero value if all of string could not be
6052  * shown. If the reserve flag is TRUE, it will reserve at least one
6053  * trailing character, which can be useful when drawing a delimiter.
6054  *
6055  * Returns the number of bytes to output from string to satisfy max_width. */
6056 static size_t
6057 utf8_length(const char *string, int *width, size_t max_width, int *trimmed, bool reserve)
6058 {
6059         const char *start = string;
6060         const char *end = strchr(string, '\0');
6061         unsigned char last_bytes = 0;
6062         size_t last_ucwidth = 0;
6063
6064         *width = 0;
6065         *trimmed = 0;
6066
6067         while (string < end) {
6068                 int c = *(unsigned char *) string;
6069                 unsigned char bytes = utf8_bytes[c];
6070                 size_t ucwidth;
6071                 unsigned long unicode;
6072
6073                 if (string + bytes > end)
6074                         break;
6075
6076                 /* Change representation to figure out whether
6077                  * it is a single- or double-width character. */
6078
6079                 unicode = utf8_to_unicode(string, bytes);
6080                 /* FIXME: Graceful handling of invalid unicode character. */
6081                 if (!unicode)
6082                         break;
6083
6084                 ucwidth = unicode_width(unicode);
6085                 *width  += ucwidth;
6086                 if (*width > max_width) {
6087                         *trimmed = 1;
6088                         *width -= ucwidth;
6089                         if (reserve && *width == max_width) {
6090                                 string -= last_bytes;
6091                                 *width -= last_ucwidth;
6092                         }
6093                         break;
6094                 }
6095
6096                 string  += bytes;
6097                 last_bytes = bytes;
6098                 last_ucwidth = ucwidth;
6099         }
6100
6101         return string - start;
6102 }
6103
6104
6105 /*
6106  * Status management
6107  */
6108
6109 /* Whether or not the curses interface has been initialized. */
6110 static bool cursed = FALSE;
6111
6112 /* The status window is used for polling keystrokes. */
6113 static WINDOW *status_win;
6114
6115 static bool status_empty = FALSE;
6116
6117 /* Update status and title window. */
6118 static void
6119 report(const char *msg, ...)
6120 {
6121         struct view *view = display[current_view];
6122
6123         if (input_mode)
6124                 return;
6125
6126         if (!view) {
6127                 char buf[SIZEOF_STR];
6128                 va_list args;
6129
6130                 va_start(args, msg);
6131                 if (vsnprintf(buf, sizeof(buf), msg, args) >= sizeof(buf)) {
6132                         buf[sizeof(buf) - 1] = 0;
6133                         buf[sizeof(buf) - 2] = '.';
6134                         buf[sizeof(buf) - 3] = '.';
6135                         buf[sizeof(buf) - 4] = '.';
6136                 }
6137                 va_end(args);
6138                 die("%s", buf);
6139         }
6140
6141         if (!status_empty || *msg) {
6142                 va_list args;
6143
6144                 va_start(args, msg);
6145
6146                 wmove(status_win, 0, 0);
6147                 if (*msg) {
6148                         vwprintw(status_win, msg, args);
6149                         status_empty = FALSE;
6150                 } else {
6151                         status_empty = TRUE;
6152                 }
6153                 wclrtoeol(status_win);
6154                 wrefresh(status_win);
6155
6156                 va_end(args);
6157         }
6158
6159         update_view_title(view);
6160         update_display_cursor(view);
6161 }
6162
6163 /* Controls when nodelay should be in effect when polling user input. */
6164 static void
6165 set_nonblocking_input(bool loading)
6166 {
6167         static unsigned int loading_views;
6168
6169         if ((loading == FALSE && loading_views-- == 1) ||
6170             (loading == TRUE  && loading_views++ == 0))
6171                 nodelay(status_win, loading);
6172 }
6173
6174 static void
6175 init_display(void)
6176 {
6177         int x, y;
6178
6179         /* Initialize the curses library */
6180         if (isatty(STDIN_FILENO)) {
6181                 cursed = !!initscr();
6182                 opt_tty = stdin;
6183         } else {
6184                 /* Leave stdin and stdout alone when acting as a pager. */
6185                 opt_tty = fopen("/dev/tty", "r+");
6186                 if (!opt_tty)
6187                         die("Failed to open /dev/tty");
6188                 cursed = !!newterm(NULL, opt_tty, opt_tty);
6189         }
6190
6191         if (!cursed)
6192                 die("Failed to initialize curses");
6193
6194         nonl();         /* Tell curses not to do NL->CR/NL on output */
6195         cbreak();       /* Take input chars one at a time, no wait for \n */
6196         noecho();       /* Don't echo input */
6197         leaveok(stdscr, TRUE);
6198
6199         if (has_colors())
6200                 init_colors();
6201
6202         getmaxyx(stdscr, y, x);
6203         status_win = newwin(1, 0, y - 1, 0);
6204         if (!status_win)
6205                 die("Failed to create status window");
6206
6207         /* Enable keyboard mapping */
6208         keypad(status_win, TRUE);
6209         wbkgdset(status_win, get_line_attr(LINE_STATUS));
6210
6211         TABSIZE = opt_tab_size;
6212         if (opt_line_graphics) {
6213                 line_graphics[LINE_GRAPHIC_VLINE] = ACS_VLINE;
6214         }
6215 }
6216
6217 static int
6218 get_input(bool prompting)
6219 {
6220         struct view *view;
6221         int i, key;
6222
6223         if (prompting)
6224                 input_mode = TRUE;
6225
6226         while (true) {
6227                 foreach_view (view, i)
6228                         update_view(view);
6229
6230                 /* Refresh, accept single keystroke of input */
6231                 key = wgetch(status_win);
6232
6233                 /* wgetch() with nodelay() enabled returns ERR when
6234                  * there's no input. */
6235                 if (key == ERR) {
6236                         doupdate();
6237
6238                 } else if (key == KEY_RESIZE) {
6239                         int height, width;
6240
6241                         getmaxyx(stdscr, height, width);
6242
6243                         /* Resize the status view and let the view driver take
6244                          * care of resizing the displayed views. */
6245                         resize_display();
6246                         redraw_display(TRUE);
6247                         wresize(status_win, 1, width);
6248                         mvwin(status_win, height - 1, 0);
6249                         wrefresh(status_win);
6250
6251                 } else {
6252                         input_mode = FALSE;
6253                         return key;
6254                 }
6255         }
6256 }
6257
6258 static char *
6259 prompt_input(const char *prompt, input_handler handler, void *data)
6260 {
6261         enum input_status status = INPUT_OK;
6262         static char buf[SIZEOF_STR];
6263         size_t pos = 0;
6264
6265         buf[pos] = 0;
6266
6267         while (status == INPUT_OK || status == INPUT_SKIP) {
6268                 int key;
6269
6270                 mvwprintw(status_win, 0, 0, "%s%.*s", prompt, pos, buf);
6271                 wclrtoeol(status_win);
6272
6273                 key = get_input(TRUE);
6274                 switch (key) {
6275                 case KEY_RETURN:
6276                 case KEY_ENTER:
6277                 case '\n':
6278                         status = pos ? INPUT_STOP : INPUT_CANCEL;
6279                         break;
6280
6281                 case KEY_BACKSPACE:
6282                         if (pos > 0)
6283                                 buf[--pos] = 0;
6284                         else
6285                                 status = INPUT_CANCEL;
6286                         break;
6287
6288                 case KEY_ESC:
6289                         status = INPUT_CANCEL;
6290                         break;
6291
6292                 default:
6293                         if (pos >= sizeof(buf)) {
6294                                 report("Input string too long");
6295                                 return NULL;
6296                         }
6297
6298                         status = handler(data, buf, key);
6299                         if (status == INPUT_OK)
6300                                 buf[pos++] = (char) key;
6301                 }
6302         }
6303
6304         /* Clear the status window */
6305         status_empty = FALSE;
6306         report("");
6307
6308         if (status == INPUT_CANCEL)
6309                 return NULL;
6310
6311         buf[pos++] = 0;
6312
6313         return buf;
6314 }
6315
6316 static enum input_status
6317 prompt_yesno_handler(void *data, char *buf, int c)
6318 {
6319         if (c == 'y' || c == 'Y')
6320                 return INPUT_STOP;
6321         if (c == 'n' || c == 'N')
6322                 return INPUT_CANCEL;
6323         return INPUT_SKIP;
6324 }
6325
6326 static bool
6327 prompt_yesno(const char *prompt)
6328 {
6329         char prompt2[SIZEOF_STR];
6330
6331         if (!string_format(prompt2, "%s [Yy/Nn]", prompt))
6332                 return FALSE;
6333
6334         return !!prompt_input(prompt2, prompt_yesno_handler, NULL);
6335 }
6336
6337 static enum input_status
6338 read_prompt_handler(void *data, char *buf, int c)
6339 {
6340         return isprint(c) ? INPUT_OK : INPUT_SKIP;
6341 }
6342
6343 static char *
6344 read_prompt(const char *prompt)
6345 {
6346         return prompt_input(prompt, read_prompt_handler, NULL);
6347 }
6348
6349 /*
6350  * Repository properties
6351  */
6352
6353 static int
6354 git_properties(const char **argv, const char *separators,
6355                int (*read_property)(char *, size_t, char *, size_t))
6356 {
6357         struct io io = {};
6358
6359         if (init_io_rd(&io, argv, NULL, FORMAT_NONE))
6360                 return read_properties(&io, separators, read_property);
6361         return ERR;
6362 }
6363
6364 static struct ref *refs = NULL;
6365 static size_t refs_alloc = 0;
6366 static size_t refs_size = 0;
6367
6368 /* Id <-> ref store */
6369 static struct ref ***id_refs = NULL;
6370 static size_t id_refs_alloc = 0;
6371 static size_t id_refs_size = 0;
6372
6373 static int
6374 compare_refs(const void *ref1_, const void *ref2_)
6375 {
6376         const struct ref *ref1 = *(const struct ref **)ref1_;
6377         const struct ref *ref2 = *(const struct ref **)ref2_;
6378
6379         if (ref1->tag != ref2->tag)
6380                 return ref2->tag - ref1->tag;
6381         if (ref1->ltag != ref2->ltag)
6382                 return ref2->ltag - ref2->ltag;
6383         if (ref1->head != ref2->head)
6384                 return ref2->head - ref1->head;
6385         if (ref1->tracked != ref2->tracked)
6386                 return ref2->tracked - ref1->tracked;
6387         if (ref1->remote != ref2->remote)
6388                 return ref2->remote - ref1->remote;
6389         return strcmp(ref1->name, ref2->name);
6390 }
6391
6392 static struct ref **
6393 get_refs(const char *id)
6394 {
6395         struct ref ***tmp_id_refs;
6396         struct ref **ref_list = NULL;
6397         size_t ref_list_alloc = 0;
6398         size_t ref_list_size = 0;
6399         size_t i;
6400
6401         for (i = 0; i < id_refs_size; i++)
6402                 if (!strcmp(id, id_refs[i][0]->id))
6403                         return id_refs[i];
6404
6405         tmp_id_refs = realloc_items(id_refs, &id_refs_alloc, id_refs_size + 1,
6406                                     sizeof(*id_refs));
6407         if (!tmp_id_refs)
6408                 return NULL;
6409
6410         id_refs = tmp_id_refs;
6411
6412         for (i = 0; i < refs_size; i++) {
6413                 struct ref **tmp;
6414
6415                 if (strcmp(id, refs[i].id))
6416                         continue;
6417
6418                 tmp = realloc_items(ref_list, &ref_list_alloc,
6419                                     ref_list_size + 1, sizeof(*ref_list));
6420                 if (!tmp) {
6421                         if (ref_list)
6422                                 free(ref_list);
6423                         return NULL;
6424                 }
6425
6426                 ref_list = tmp;
6427                 ref_list[ref_list_size] = &refs[i];
6428                 /* XXX: The properties of the commit chains ensures that we can
6429                  * safely modify the shared ref. The repo references will
6430                  * always be similar for the same id. */
6431                 ref_list[ref_list_size]->next = 1;
6432
6433                 ref_list_size++;
6434         }
6435
6436         if (ref_list) {
6437                 qsort(ref_list, ref_list_size, sizeof(*ref_list), compare_refs);
6438                 ref_list[ref_list_size - 1]->next = 0;
6439                 id_refs[id_refs_size++] = ref_list;
6440         }
6441
6442         return ref_list;
6443 }
6444
6445 static int
6446 read_ref(char *id, size_t idlen, char *name, size_t namelen)
6447 {
6448         struct ref *ref;
6449         bool tag = FALSE;
6450         bool ltag = FALSE;
6451         bool remote = FALSE;
6452         bool tracked = FALSE;
6453         bool check_replace = FALSE;
6454         bool head = FALSE;
6455
6456         if (!prefixcmp(name, "refs/tags/")) {
6457                 if (!suffixcmp(name, namelen, "^{}")) {
6458                         namelen -= 3;
6459                         name[namelen] = 0;
6460                         if (refs_size > 0 && refs[refs_size - 1].ltag == TRUE)
6461                                 check_replace = TRUE;
6462                 } else {
6463                         ltag = TRUE;
6464                 }
6465
6466                 tag = TRUE;
6467                 namelen -= STRING_SIZE("refs/tags/");
6468                 name    += STRING_SIZE("refs/tags/");
6469
6470         } else if (!prefixcmp(name, "refs/remotes/")) {
6471                 remote = TRUE;
6472                 namelen -= STRING_SIZE("refs/remotes/");
6473                 name    += STRING_SIZE("refs/remotes/");
6474                 tracked  = !strcmp(opt_remote, name);
6475
6476         } else if (!prefixcmp(name, "refs/heads/")) {
6477                 namelen -= STRING_SIZE("refs/heads/");
6478                 name    += STRING_SIZE("refs/heads/");
6479                 head     = !strncmp(opt_head, name, namelen);
6480
6481         } else if (!strcmp(name, "HEAD")) {
6482                 string_ncopy(opt_head_rev, id, idlen);
6483                 return OK;
6484         }
6485
6486         if (check_replace && !strcmp(name, refs[refs_size - 1].name)) {
6487                 /* it's an annotated tag, replace the previous sha1 with the
6488                  * resolved commit id; relies on the fact git-ls-remote lists
6489                  * the commit id of an annotated tag right before the commit id
6490                  * it points to. */
6491                 refs[refs_size - 1].ltag = ltag;
6492                 string_copy_rev(refs[refs_size - 1].id, id);
6493
6494                 return OK;
6495         }
6496         refs = realloc_items(refs, &refs_alloc, refs_size + 1, sizeof(*refs));
6497         if (!refs)
6498                 return ERR;
6499
6500         ref = &refs[refs_size++];
6501         ref->name = malloc(namelen + 1);
6502         if (!ref->name)
6503                 return ERR;
6504
6505         strncpy(ref->name, name, namelen);
6506         ref->name[namelen] = 0;
6507         ref->head = head;
6508         ref->tag = tag;
6509         ref->ltag = ltag;
6510         ref->remote = remote;
6511         ref->tracked = tracked;
6512         string_copy_rev(ref->id, id);
6513
6514         return OK;
6515 }
6516
6517 static int
6518 load_refs(void)
6519 {
6520         static const char *ls_remote_argv[SIZEOF_ARG] = {
6521                 "git", "ls-remote", ".", NULL
6522         };
6523         static bool init = FALSE;
6524
6525         if (!init) {
6526                 argv_from_env(ls_remote_argv, "TIG_LS_REMOTE");
6527                 init = TRUE;
6528         }
6529
6530         if (!*opt_git_dir)
6531                 return OK;
6532
6533         while (refs_size > 0)
6534                 free(refs[--refs_size].name);
6535         while (id_refs_size > 0)
6536                 free(id_refs[--id_refs_size]);
6537
6538         return git_properties(ls_remote_argv, "\t", read_ref);
6539 }
6540
6541 static int
6542 read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen)
6543 {
6544         if (!strcmp(name, "i18n.commitencoding"))
6545                 string_ncopy(opt_encoding, value, valuelen);
6546
6547         if (!strcmp(name, "core.editor"))
6548                 string_ncopy(opt_editor, value, valuelen);
6549
6550         /* branch.<head>.remote */
6551         if (*opt_head &&
6552             !strncmp(name, "branch.", 7) &&
6553             !strncmp(name + 7, opt_head, strlen(opt_head)) &&
6554             !strcmp(name + 7 + strlen(opt_head), ".remote"))
6555                 string_ncopy(opt_remote, value, valuelen);
6556
6557         if (*opt_head && *opt_remote &&
6558             !strncmp(name, "branch.", 7) &&
6559             !strncmp(name + 7, opt_head, strlen(opt_head)) &&
6560             !strcmp(name + 7 + strlen(opt_head), ".merge")) {
6561                 size_t from = strlen(opt_remote);
6562
6563                 if (!prefixcmp(value, "refs/heads/")) {
6564                         value += STRING_SIZE("refs/heads/");
6565                         valuelen -= STRING_SIZE("refs/heads/");
6566                 }
6567
6568                 if (!string_format_from(opt_remote, &from, "/%s", value))
6569                         opt_remote[0] = 0;
6570         }
6571
6572         return OK;
6573 }
6574
6575 static int
6576 load_git_config(void)
6577 {
6578         const char *config_list_argv[] = { "git", GIT_CONFIG, "--list", NULL };
6579
6580         return git_properties(config_list_argv, "=", read_repo_config_option);
6581 }
6582
6583 static int
6584 read_repo_info(char *name, size_t namelen, char *value, size_t valuelen)
6585 {
6586         if (!opt_git_dir[0]) {
6587                 string_ncopy(opt_git_dir, name, namelen);
6588
6589         } else if (opt_is_inside_work_tree == -1) {
6590                 /* This can be 3 different values depending on the
6591                  * version of git being used. If git-rev-parse does not
6592                  * understand --is-inside-work-tree it will simply echo
6593                  * the option else either "true" or "false" is printed.
6594                  * Default to true for the unknown case. */
6595                 opt_is_inside_work_tree = strcmp(name, "false") ? TRUE : FALSE;
6596
6597         } else if (*name == '.') {
6598                 string_ncopy(opt_cdup, name, namelen);
6599
6600         } else {
6601                 string_ncopy(opt_prefix, name, namelen);
6602         }
6603
6604         return OK;
6605 }
6606
6607 static int
6608 load_repo_info(void)
6609 {
6610         const char *head_argv[] = {
6611                 "git", "symbolic-ref", "HEAD", NULL
6612         };
6613         const char *rev_parse_argv[] = {
6614                 "git", "rev-parse", "--git-dir", "--is-inside-work-tree",
6615                         "--show-cdup", "--show-prefix", NULL
6616         };
6617
6618         if (run_io_buf(head_argv, opt_head, sizeof(opt_head))) {
6619                 chomp_string(opt_head);
6620                 if (!prefixcmp(opt_head, "refs/heads/")) {
6621                         char *offset = opt_head + STRING_SIZE("refs/heads/");
6622
6623                         memmove(opt_head, offset, strlen(offset) + 1);
6624                 }
6625         }
6626
6627         return git_properties(rev_parse_argv, "=", read_repo_info);
6628 }
6629
6630 static int
6631 read_properties(struct io *io, const char *separators,
6632                 int (*read_property)(char *, size_t, char *, size_t))
6633 {
6634         char *name;
6635         int state = OK;
6636
6637         if (!start_io(io))
6638                 return ERR;
6639
6640         while (state == OK && (name = io_get(io, '\n', TRUE))) {
6641                 char *value;
6642                 size_t namelen;
6643                 size_t valuelen;
6644
6645                 name = chomp_string(name);
6646                 namelen = strcspn(name, separators);
6647
6648                 if (name[namelen]) {
6649                         name[namelen] = 0;
6650                         value = chomp_string(name + namelen + 1);
6651                         valuelen = strlen(value);
6652
6653                 } else {
6654                         value = "";
6655                         valuelen = 0;
6656                 }
6657
6658                 state = read_property(name, namelen, value, valuelen);
6659         }
6660
6661         if (state != ERR && io_error(io))
6662                 state = ERR;
6663         done_io(io);
6664
6665         return state;
6666 }
6667
6668
6669 /*
6670  * Main
6671  */
6672
6673 static void __NORETURN
6674 quit(int sig)
6675 {
6676         /* XXX: Restore tty modes and let the OS cleanup the rest! */
6677         if (cursed)
6678                 endwin();
6679         exit(0);
6680 }
6681
6682 static void __NORETURN
6683 die(const char *err, ...)
6684 {
6685         va_list args;
6686
6687         endwin();
6688
6689         va_start(args, err);
6690         fputs("tig: ", stderr);
6691         vfprintf(stderr, err, args);
6692         fputs("\n", stderr);
6693         va_end(args);
6694
6695         exit(1);
6696 }
6697
6698 static void
6699 warn(const char *msg, ...)
6700 {
6701         va_list args;
6702
6703         va_start(args, msg);
6704         fputs("tig warning: ", stderr);
6705         vfprintf(stderr, msg, args);
6706         fputs("\n", stderr);
6707         va_end(args);
6708 }
6709
6710 int
6711 main(int argc, const char *argv[])
6712 {
6713         const char **run_argv = NULL;
6714         struct view *view;
6715         enum request request;
6716         size_t i;
6717
6718         signal(SIGINT, quit);
6719
6720         if (setlocale(LC_ALL, "")) {
6721                 char *codeset = nl_langinfo(CODESET);
6722
6723                 string_ncopy(opt_codeset, codeset, strlen(codeset));
6724         }
6725
6726         if (load_repo_info() == ERR)
6727                 die("Failed to load repo info.");
6728
6729         if (load_options() == ERR)
6730                 die("Failed to load user config.");
6731
6732         if (load_git_config() == ERR)
6733                 die("Failed to load repo config.");
6734
6735         request = parse_options(argc, argv, &run_argv);
6736         if (request == REQ_NONE)
6737                 return 0;
6738
6739         /* Require a git repository unless when running in pager mode. */
6740         if (!opt_git_dir[0] && request != REQ_VIEW_PAGER)
6741                 die("Not a git repository");
6742
6743         if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
6744                 opt_utf8 = FALSE;
6745
6746         if (*opt_codeset && strcmp(opt_codeset, opt_encoding)) {
6747                 opt_iconv = iconv_open(opt_codeset, opt_encoding);
6748                 if (opt_iconv == ICONV_NONE)
6749                         die("Failed to initialize character set conversion");
6750         }
6751
6752         if (load_refs() == ERR)
6753                 die("Failed to load refs.");
6754
6755         foreach_view (view, i)
6756                 argv_from_env(view->ops->argv, view->cmd_env);
6757
6758         init_display();
6759
6760         if (request == REQ_VIEW_PAGER || run_argv) {
6761                 if (request == REQ_VIEW_PAGER)
6762                         io_open(&VIEW(request)->io, "");
6763                 else if (!prepare_update(VIEW(request), run_argv, NULL, FORMAT_NONE))
6764                         die("Failed to format arguments");
6765                 open_view(NULL, request, OPEN_PREPARED);
6766                 request = REQ_NONE;
6767         }
6768
6769         while (view_driver(display[current_view], request)) {
6770                 int key = get_input(FALSE);
6771
6772                 view = display[current_view];
6773                 request = get_keybinding(view->keymap, key);
6774
6775                 /* Some low-level request handling. This keeps access to
6776                  * status_win restricted. */
6777                 switch (request) {
6778                 case REQ_PROMPT:
6779                 {
6780                         char *cmd = read_prompt(":");
6781
6782                         if (cmd) {
6783                                 struct view *next = VIEW(REQ_VIEW_PAGER);
6784                                 const char *argv[SIZEOF_ARG] = { "git" };
6785                                 int argc = 1;
6786
6787                                 /* When running random commands, initially show the
6788                                  * command in the title. However, it maybe later be
6789                                  * overwritten if a commit line is selected. */
6790                                 string_ncopy(next->ref, cmd, strlen(cmd));
6791
6792                                 if (!argv_from_string(argv, &argc, cmd)) {
6793                                         report("Too many arguments");
6794                                 } else if (!prepare_update(next, argv, NULL, FORMAT_DASH)) {
6795                                         report("Failed to format command");
6796                                 } else {
6797                                         open_view(view, REQ_VIEW_PAGER, OPEN_PREPARED);
6798                                 }
6799                         }
6800
6801                         request = REQ_NONE;
6802                         break;
6803                 }
6804                 case REQ_SEARCH:
6805                 case REQ_SEARCH_BACK:
6806                 {
6807                         const char *prompt = request == REQ_SEARCH ? "/" : "?";
6808                         char *search = read_prompt(prompt);
6809
6810                         if (search)
6811                                 string_ncopy(opt_search, search, strlen(search));
6812                         else
6813                                 request = REQ_NONE;
6814                         break;
6815                 }
6816                 default:
6817                         break;
6818                 }
6819         }
6820
6821         quit(0);
6822
6823         return 0;
6824 }