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