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