Branch view: fix loading to handle when two branches have same commit
[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->author ? &branch->time : NULL))
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         struct branch *reference;
4682         size_t i;
4683
4684         if (!line)
4685                 return TRUE;
4686
4687         switch (get_line_type(line)) {
4688         case LINE_COMMIT:
4689                 string_copy_rev(id, line + STRING_SIZE("commit "));
4690                 return TRUE;
4691
4692         case LINE_AUTHOR:
4693                 for (i = 0, reference = NULL; i < view->lines; i++) {
4694                         struct branch *branch = view->line[i].data;
4695
4696                         if (strcmp(branch->ref->id, id))
4697                                 continue;
4698
4699                         view->line[i].dirty = TRUE;
4700                         if (reference) {
4701                                 branch->author = reference->author;
4702                                 branch->time = reference->time;
4703                                 continue;
4704                         }
4705
4706                         parse_author_line(line + STRING_SIZE("author "),
4707                                           &branch->author, &branch->time);
4708                         reference = branch;
4709                 }
4710                 return TRUE;
4711
4712         default:
4713                 return TRUE;
4714         }
4715
4716 }
4717
4718 static bool
4719 branch_open_visitor(void *data, struct ref *ref)
4720 {
4721         struct view *view = data;
4722         struct branch *branch;
4723
4724         if (ref->tag || ref->ltag || ref->remote)
4725                 return TRUE;
4726
4727         branch = calloc(1, sizeof(*branch));
4728         if (!branch)
4729                 return FALSE;
4730
4731         branch->ref = ref;
4732         return !!add_line_data(view, branch, LINE_DEFAULT);
4733 }
4734
4735 static bool
4736 branch_open(struct view *view)
4737 {
4738         const char *branch_log[] = {
4739                 "git", "log", "--no-color", "--pretty=raw",
4740                         "--simplify-by-decoration", "--all", NULL
4741         };
4742
4743         if (!run_io_rd(&view->io, branch_log, FORMAT_NONE)) {
4744                 report("Failed to load branch data");
4745                 return TRUE;
4746         }
4747
4748         setup_update(view, view->id);
4749         foreach_ref(branch_open_visitor, view);
4750
4751         return TRUE;
4752 }
4753
4754 static bool
4755 branch_grep(struct view *view, struct line *line)
4756 {
4757         struct branch *branch = line->data;
4758         const char *text[] = {
4759                 branch->ref->name,
4760                 branch->author,
4761                 NULL
4762         };
4763
4764         return grep_text(view, text);
4765 }
4766
4767 static void
4768 branch_select(struct view *view, struct line *line)
4769 {
4770         struct branch *branch = line->data;
4771
4772         string_copy_rev(view->ref, branch->ref->id);
4773         string_copy_rev(ref_commit, branch->ref->id);
4774         string_copy_rev(ref_head, branch->ref->id);
4775 }
4776
4777 static struct view_ops branch_ops = {
4778         "branch",
4779         NULL,
4780         branch_open,
4781         branch_read,
4782         branch_draw,
4783         branch_request,
4784         branch_grep,
4785         branch_select,
4786 };
4787
4788 /*
4789  * Status backend
4790  */
4791
4792 struct status {
4793         char status;
4794         struct {
4795                 mode_t mode;
4796                 char rev[SIZEOF_REV];
4797                 char name[SIZEOF_STR];
4798         } old;
4799         struct {
4800                 mode_t mode;
4801                 char rev[SIZEOF_REV];
4802                 char name[SIZEOF_STR];
4803         } new;
4804 };
4805
4806 static char status_onbranch[SIZEOF_STR];
4807 static struct status stage_status;
4808 static enum line_type stage_line_type;
4809 static size_t stage_chunks;
4810 static int *stage_chunk;
4811
4812 DEFINE_ALLOCATOR(realloc_ints, int, 32)
4813
4814 /* This should work even for the "On branch" line. */
4815 static inline bool
4816 status_has_none(struct view *view, struct line *line)
4817 {
4818         return line < view->line + view->lines && !line[1].data;
4819 }
4820
4821 /* Get fields from the diff line:
4822  * :100644 100644 06a5d6ae9eca55be2e0e585a152e6b1336f2b20e 0000000000000000000000000000000000000000 M
4823  */
4824 static inline bool
4825 status_get_diff(struct status *file, const char *buf, size_t bufsize)
4826 {
4827         const char *old_mode = buf +  1;
4828         const char *new_mode = buf +  8;
4829         const char *old_rev  = buf + 15;
4830         const char *new_rev  = buf + 56;
4831         const char *status   = buf + 97;
4832
4833         if (bufsize < 98 ||
4834             old_mode[-1] != ':' ||
4835             new_mode[-1] != ' ' ||
4836             old_rev[-1]  != ' ' ||
4837             new_rev[-1]  != ' ' ||
4838             status[-1]   != ' ')
4839                 return FALSE;
4840
4841         file->status = *status;
4842
4843         string_copy_rev(file->old.rev, old_rev);
4844         string_copy_rev(file->new.rev, new_rev);
4845
4846         file->old.mode = strtoul(old_mode, NULL, 8);
4847         file->new.mode = strtoul(new_mode, NULL, 8);
4848
4849         file->old.name[0] = file->new.name[0] = 0;
4850
4851         return TRUE;
4852 }
4853
4854 static bool
4855 status_run(struct view *view, const char *argv[], char status, enum line_type type)
4856 {
4857         struct status *unmerged = NULL;
4858         char *buf;
4859         struct io io = {};
4860
4861         if (!run_io(&io, argv, NULL, IO_RD))
4862                 return FALSE;
4863
4864         add_line_data(view, NULL, type);
4865
4866         while ((buf = io_get(&io, 0, TRUE))) {
4867                 struct status *file = unmerged;
4868
4869                 if (!file) {
4870                         file = calloc(1, sizeof(*file));
4871                         if (!file || !add_line_data(view, file, type))
4872                                 goto error_out;
4873                 }
4874
4875                 /* Parse diff info part. */
4876                 if (status) {
4877                         file->status = status;
4878                         if (status == 'A')
4879                                 string_copy(file->old.rev, NULL_ID);
4880
4881                 } else if (!file->status || file == unmerged) {
4882                         if (!status_get_diff(file, buf, strlen(buf)))
4883                                 goto error_out;
4884
4885                         buf = io_get(&io, 0, TRUE);
4886                         if (!buf)
4887                                 break;
4888
4889                         /* Collapse all modified entries that follow an
4890                          * associated unmerged entry. */
4891                         if (unmerged == file) {
4892                                 unmerged->status = 'U';
4893                                 unmerged = NULL;
4894                         } else if (file->status == 'U') {
4895                                 unmerged = file;
4896                         }
4897                 }
4898
4899                 /* Grab the old name for rename/copy. */
4900                 if (!*file->old.name &&
4901                     (file->status == 'R' || file->status == 'C')) {
4902                         string_ncopy(file->old.name, buf, strlen(buf));
4903
4904                         buf = io_get(&io, 0, TRUE);
4905                         if (!buf)
4906                                 break;
4907                 }
4908
4909                 /* git-ls-files just delivers a NUL separated list of
4910                  * file names similar to the second half of the
4911                  * git-diff-* output. */
4912                 string_ncopy(file->new.name, buf, strlen(buf));
4913                 if (!*file->old.name)
4914                         string_copy(file->old.name, file->new.name);
4915                 file = NULL;
4916         }
4917
4918         if (io_error(&io)) {
4919 error_out:
4920                 done_io(&io);
4921                 return FALSE;
4922         }
4923
4924         if (!view->line[view->lines - 1].data)
4925                 add_line_data(view, NULL, LINE_STAT_NONE);
4926
4927         done_io(&io);
4928         return TRUE;
4929 }
4930
4931 /* Don't show unmerged entries in the staged section. */
4932 static const char *status_diff_index_argv[] = {
4933         "git", "diff-index", "-z", "--diff-filter=ACDMRTXB",
4934                              "--cached", "-M", "HEAD", NULL
4935 };
4936
4937 static const char *status_diff_files_argv[] = {
4938         "git", "diff-files", "-z", NULL
4939 };
4940
4941 static const char *status_list_other_argv[] = {
4942         "git", "ls-files", "-z", "--others", "--exclude-standard", NULL
4943 };
4944
4945 static const char *status_list_no_head_argv[] = {
4946         "git", "ls-files", "-z", "--cached", "--exclude-standard", NULL
4947 };
4948
4949 static const char *update_index_argv[] = {
4950         "git", "update-index", "-q", "--unmerged", "--refresh", NULL
4951 };
4952
4953 /* Restore the previous line number to stay in the context or select a
4954  * line with something that can be updated. */
4955 static void
4956 status_restore(struct view *view)
4957 {
4958         if (view->p_lineno >= view->lines)
4959                 view->p_lineno = view->lines - 1;
4960         while (view->p_lineno < view->lines && !view->line[view->p_lineno].data)
4961                 view->p_lineno++;
4962         while (view->p_lineno > 0 && !view->line[view->p_lineno].data)
4963                 view->p_lineno--;
4964
4965         /* If the above fails, always skip the "On branch" line. */
4966         if (view->p_lineno < view->lines)
4967                 view->lineno = view->p_lineno;
4968         else
4969                 view->lineno = 1;
4970
4971         if (view->lineno < view->offset)
4972                 view->offset = view->lineno;
4973         else if (view->offset + view->height <= view->lineno)
4974                 view->offset = view->lineno - view->height + 1;
4975
4976         view->p_restore = FALSE;
4977 }
4978
4979 static void
4980 status_update_onbranch(void)
4981 {
4982         static const char *paths[][2] = {
4983                 { "rebase-apply/rebasing",      "Rebasing" },
4984                 { "rebase-apply/applying",      "Applying mailbox" },
4985                 { "rebase-apply/",              "Rebasing mailbox" },
4986                 { "rebase-merge/interactive",   "Interactive rebase" },
4987                 { "rebase-merge/",              "Rebase merge" },
4988                 { "MERGE_HEAD",                 "Merging" },
4989                 { "BISECT_LOG",                 "Bisecting" },
4990                 { "HEAD",                       "On branch" },
4991         };
4992         char buf[SIZEOF_STR];
4993         struct stat stat;
4994         int i;
4995
4996         if (is_initial_commit()) {
4997                 string_copy(status_onbranch, "Initial commit");
4998                 return;
4999         }
5000
5001         for (i = 0; i < ARRAY_SIZE(paths); i++) {
5002                 char *head = opt_head;
5003
5004                 if (!string_format(buf, "%s/%s", opt_git_dir, paths[i][0]) ||
5005                     lstat(buf, &stat) < 0)
5006                         continue;
5007
5008                 if (!*opt_head) {
5009                         struct io io = {};
5010
5011                         if (string_format(buf, "%s/rebase-merge/head-name", opt_git_dir) &&
5012                             io_open(&io, buf) &&
5013                             io_read_buf(&io, buf, sizeof(buf))) {
5014                                 head = buf;
5015                                 if (!prefixcmp(head, "refs/heads/"))
5016                                         head += STRING_SIZE("refs/heads/");
5017                         }
5018                 }
5019
5020                 if (!string_format(status_onbranch, "%s %s", paths[i][1], head))
5021                         string_copy(status_onbranch, opt_head);
5022                 return;
5023         }
5024
5025         string_copy(status_onbranch, "Not currently on any branch");
5026 }
5027
5028 /* First parse staged info using git-diff-index(1), then parse unstaged
5029  * info using git-diff-files(1), and finally untracked files using
5030  * git-ls-files(1). */
5031 static bool
5032 status_open(struct view *view)
5033 {
5034         reset_view(view);
5035
5036         add_line_data(view, NULL, LINE_STAT_HEAD);
5037         status_update_onbranch();
5038
5039         run_io_bg(update_index_argv);
5040
5041         if (is_initial_commit()) {
5042                 if (!status_run(view, status_list_no_head_argv, 'A', LINE_STAT_STAGED))
5043                         return FALSE;
5044         } else if (!status_run(view, status_diff_index_argv, 0, LINE_STAT_STAGED)) {
5045                 return FALSE;
5046         }
5047
5048         if (!status_run(view, status_diff_files_argv, 0, LINE_STAT_UNSTAGED) ||
5049             !status_run(view, status_list_other_argv, '?', LINE_STAT_UNTRACKED))
5050                 return FALSE;
5051
5052         /* Restore the exact position or use the specialized restore
5053          * mode? */
5054         if (!view->p_restore)
5055                 status_restore(view);
5056         return TRUE;
5057 }
5058
5059 static bool
5060 status_draw(struct view *view, struct line *line, unsigned int lineno)
5061 {
5062         struct status *status = line->data;
5063         enum line_type type;
5064         const char *text;
5065
5066         if (!status) {
5067                 switch (line->type) {
5068                 case LINE_STAT_STAGED:
5069                         type = LINE_STAT_SECTION;
5070                         text = "Changes to be committed:";
5071                         break;
5072
5073                 case LINE_STAT_UNSTAGED:
5074                         type = LINE_STAT_SECTION;
5075                         text = "Changed but not updated:";
5076                         break;
5077
5078                 case LINE_STAT_UNTRACKED:
5079                         type = LINE_STAT_SECTION;
5080                         text = "Untracked files:";
5081                         break;
5082
5083                 case LINE_STAT_NONE:
5084                         type = LINE_DEFAULT;
5085                         text = "  (no files)";
5086                         break;
5087
5088                 case LINE_STAT_HEAD:
5089                         type = LINE_STAT_HEAD;
5090                         text = status_onbranch;
5091                         break;
5092
5093                 default:
5094                         return FALSE;
5095                 }
5096         } else {
5097                 static char buf[] = { '?', ' ', ' ', ' ', 0 };
5098
5099                 buf[0] = status->status;
5100                 if (draw_text(view, line->type, buf, TRUE))
5101                         return TRUE;
5102                 type = LINE_DEFAULT;
5103                 text = status->new.name;
5104         }
5105
5106         draw_text(view, type, text, TRUE);
5107         return TRUE;
5108 }
5109
5110 static enum request
5111 status_load_error(struct view *view, struct view *stage, const char *path)
5112 {
5113         if (displayed_views() == 2 || display[current_view] != view)
5114                 maximize_view(view);
5115         report("Failed to load '%s': %s", path, io_strerror(&stage->io));
5116         return REQ_NONE;
5117 }
5118
5119 static enum request
5120 status_enter(struct view *view, struct line *line)
5121 {
5122         struct status *status = line->data;
5123         const char *oldpath = status ? status->old.name : NULL;
5124         /* Diffs for unmerged entries are empty when passing the new
5125          * path, so leave it empty. */
5126         const char *newpath = status && status->status != 'U' ? status->new.name : NULL;
5127         const char *info;
5128         enum open_flags split;
5129         struct view *stage = VIEW(REQ_VIEW_STAGE);
5130
5131         if (line->type == LINE_STAT_NONE ||
5132             (!status && line[1].type == LINE_STAT_NONE)) {
5133                 report("No file to diff");
5134                 return REQ_NONE;
5135         }
5136
5137         switch (line->type) {
5138         case LINE_STAT_STAGED:
5139                 if (is_initial_commit()) {
5140                         const char *no_head_diff_argv[] = {
5141                                 "git", "diff", "--no-color", "--patch-with-stat",
5142                                         "--", "/dev/null", newpath, NULL
5143                         };
5144
5145                         if (!prepare_update(stage, no_head_diff_argv, opt_cdup, FORMAT_DASH))
5146                                 return status_load_error(view, stage, newpath);
5147                 } else {
5148                         const char *index_show_argv[] = {
5149                                 "git", "diff-index", "--root", "--patch-with-stat",
5150                                         "-C", "-M", "--cached", "HEAD", "--",
5151                                         oldpath, newpath, NULL
5152                         };
5153
5154                         if (!prepare_update(stage, index_show_argv, opt_cdup, FORMAT_DASH))
5155                                 return status_load_error(view, stage, newpath);
5156                 }
5157
5158                 if (status)
5159                         info = "Staged changes to %s";
5160                 else
5161                         info = "Staged changes";
5162                 break;
5163
5164         case LINE_STAT_UNSTAGED:
5165         {
5166                 const char *files_show_argv[] = {
5167                         "git", "diff-files", "--root", "--patch-with-stat",
5168                                 "-C", "-M", "--", oldpath, newpath, NULL
5169                 };
5170
5171                 if (!prepare_update(stage, files_show_argv, opt_cdup, FORMAT_DASH))
5172                         return status_load_error(view, stage, newpath);
5173                 if (status)
5174                         info = "Unstaged changes to %s";
5175                 else
5176                         info = "Unstaged changes";
5177                 break;
5178         }
5179         case LINE_STAT_UNTRACKED:
5180                 if (!newpath) {
5181                         report("No file to show");
5182                         return REQ_NONE;
5183                 }
5184
5185                 if (!suffixcmp(status->new.name, -1, "/")) {
5186                         report("Cannot display a directory");
5187                         return REQ_NONE;
5188                 }
5189
5190                 if (!prepare_update_file(stage, newpath))
5191                         return status_load_error(view, stage, newpath);
5192                 info = "Untracked file %s";
5193                 break;
5194
5195         case LINE_STAT_HEAD:
5196                 return REQ_NONE;
5197
5198         default:
5199                 die("line type %d not handled in switch", line->type);
5200         }
5201
5202         split = view_is_displayed(view) ? OPEN_SPLIT : 0;
5203         open_view(view, REQ_VIEW_STAGE, OPEN_PREPARED | split);
5204         if (view_is_displayed(VIEW(REQ_VIEW_STAGE))) {
5205                 if (status) {
5206                         stage_status = *status;
5207                 } else {
5208                         memset(&stage_status, 0, sizeof(stage_status));
5209                 }
5210
5211                 stage_line_type = line->type;
5212                 stage_chunks = 0;
5213                 string_format(VIEW(REQ_VIEW_STAGE)->ref, info, stage_status.new.name);
5214         }
5215
5216         return REQ_NONE;
5217 }
5218
5219 static bool
5220 status_exists(struct status *status, enum line_type type)
5221 {
5222         struct view *view = VIEW(REQ_VIEW_STATUS);
5223         unsigned long lineno;
5224
5225         for (lineno = 0; lineno < view->lines; lineno++) {
5226                 struct line *line = &view->line[lineno];
5227                 struct status *pos = line->data;
5228
5229                 if (line->type != type)
5230                         continue;
5231                 if (!pos && (!status || !status->status) && line[1].data) {
5232                         select_view_line(view, lineno);
5233                         return TRUE;
5234                 }
5235                 if (pos && !strcmp(status->new.name, pos->new.name)) {
5236                         select_view_line(view, lineno);
5237                         return TRUE;
5238                 }
5239         }
5240
5241         return FALSE;
5242 }
5243
5244
5245 static bool
5246 status_update_prepare(struct io *io, enum line_type type)
5247 {
5248         const char *staged_argv[] = {
5249                 "git", "update-index", "-z", "--index-info", NULL
5250         };
5251         const char *others_argv[] = {
5252                 "git", "update-index", "-z", "--add", "--remove", "--stdin", NULL
5253         };
5254
5255         switch (type) {
5256         case LINE_STAT_STAGED:
5257                 return run_io(io, staged_argv, opt_cdup, IO_WR);
5258
5259         case LINE_STAT_UNSTAGED:
5260                 return run_io(io, others_argv, opt_cdup, IO_WR);
5261
5262         case LINE_STAT_UNTRACKED:
5263                 return run_io(io, others_argv, NULL, IO_WR);
5264
5265         default:
5266                 die("line type %d not handled in switch", type);
5267                 return FALSE;
5268         }
5269 }
5270
5271 static bool
5272 status_update_write(struct io *io, struct status *status, enum line_type type)
5273 {
5274         char buf[SIZEOF_STR];
5275         size_t bufsize = 0;
5276
5277         switch (type) {
5278         case LINE_STAT_STAGED:
5279                 if (!string_format_from(buf, &bufsize, "%06o %s\t%s%c",
5280                                         status->old.mode,
5281                                         status->old.rev,
5282                                         status->old.name, 0))
5283                         return FALSE;
5284                 break;
5285
5286         case LINE_STAT_UNSTAGED:
5287         case LINE_STAT_UNTRACKED:
5288                 if (!string_format_from(buf, &bufsize, "%s%c", status->new.name, 0))
5289                         return FALSE;
5290                 break;
5291
5292         default:
5293                 die("line type %d not handled in switch", type);
5294         }
5295
5296         return io_write(io, buf, bufsize);
5297 }
5298
5299 static bool
5300 status_update_file(struct status *status, enum line_type type)
5301 {
5302         struct io io = {};
5303         bool result;
5304
5305         if (!status_update_prepare(&io, type))
5306                 return FALSE;
5307
5308         result = status_update_write(&io, status, type);
5309         return done_io(&io) && result;
5310 }
5311
5312 static bool
5313 status_update_files(struct view *view, struct line *line)
5314 {
5315         char buf[sizeof(view->ref)];
5316         struct io io = {};
5317         bool result = TRUE;
5318         struct line *pos = view->line + view->lines;
5319         int files = 0;
5320         int file, done;
5321         int cursor_y, cursor_x;
5322
5323         if (!status_update_prepare(&io, line->type))
5324                 return FALSE;
5325
5326         for (pos = line; pos < view->line + view->lines && pos->data; pos++)
5327                 files++;
5328
5329         string_copy(buf, view->ref);
5330         getsyx(cursor_y, cursor_x);
5331         for (file = 0, done = 5; result && file < files; line++, file++) {
5332                 int almost_done = file * 100 / files;
5333
5334                 if (almost_done > done) {
5335                         done = almost_done;
5336                         string_format(view->ref, "updating file %u of %u (%d%% done)",
5337                                       file, files, done);
5338                         update_view_title(view);
5339                         setsyx(cursor_y, cursor_x);
5340                         doupdate();
5341                 }
5342                 result = status_update_write(&io, line->data, line->type);
5343         }
5344         string_copy(view->ref, buf);
5345
5346         return done_io(&io) && result;
5347 }
5348
5349 static bool
5350 status_update(struct view *view)
5351 {
5352         struct line *line = &view->line[view->lineno];
5353
5354         assert(view->lines);
5355
5356         if (!line->data) {
5357                 /* This should work even for the "On branch" line. */
5358                 if (line < view->line + view->lines && !line[1].data) {
5359                         report("Nothing to update");
5360                         return FALSE;
5361                 }
5362
5363                 if (!status_update_files(view, line + 1)) {
5364                         report("Failed to update file status");
5365                         return FALSE;
5366                 }
5367
5368         } else if (!status_update_file(line->data, line->type)) {
5369                 report("Failed to update file status");
5370                 return FALSE;
5371         }
5372
5373         return TRUE;
5374 }
5375
5376 static bool
5377 status_revert(struct status *status, enum line_type type, bool has_none)
5378 {
5379         if (!status || type != LINE_STAT_UNSTAGED) {
5380                 if (type == LINE_STAT_STAGED) {
5381                         report("Cannot revert changes to staged files");
5382                 } else if (type == LINE_STAT_UNTRACKED) {
5383                         report("Cannot revert changes to untracked files");
5384                 } else if (has_none) {
5385                         report("Nothing to revert");
5386                 } else {
5387                         report("Cannot revert changes to multiple files");
5388                 }
5389                 return FALSE;
5390
5391         } else {
5392                 char mode[10] = "100644";
5393                 const char *reset_argv[] = {
5394                         "git", "update-index", "--cacheinfo", mode,
5395                                 status->old.rev, status->old.name, NULL
5396                 };
5397                 const char *checkout_argv[] = {
5398                         "git", "checkout", "--", status->old.name, NULL
5399                 };
5400
5401                 if (!prompt_yesno("Are you sure you want to overwrite any changes?"))
5402                         return FALSE;
5403                 string_format(mode, "%o", status->old.mode);
5404                 return (status->status != 'U' || run_io_fg(reset_argv, opt_cdup)) &&
5405                         run_io_fg(checkout_argv, opt_cdup);
5406         }
5407 }
5408
5409 static enum request
5410 status_request(struct view *view, enum request request, struct line *line)
5411 {
5412         struct status *status = line->data;
5413
5414         switch (request) {
5415         case REQ_STATUS_UPDATE:
5416                 if (!status_update(view))
5417                         return REQ_NONE;
5418                 break;
5419
5420         case REQ_STATUS_REVERT:
5421                 if (!status_revert(status, line->type, status_has_none(view, line)))
5422                         return REQ_NONE;
5423                 break;
5424
5425         case REQ_STATUS_MERGE:
5426                 if (!status || status->status != 'U') {
5427                         report("Merging only possible for files with unmerged status ('U').");
5428                         return REQ_NONE;
5429                 }
5430                 open_mergetool(status->new.name);
5431                 break;
5432
5433         case REQ_EDIT:
5434                 if (!status)
5435                         return request;
5436                 if (status->status == 'D') {
5437                         report("File has been deleted.");
5438                         return REQ_NONE;
5439                 }
5440
5441                 open_editor(status->status != '?', status->new.name);
5442                 break;
5443
5444         case REQ_VIEW_BLAME:
5445                 if (status) {
5446                         string_copy(opt_file, status->new.name);
5447                         opt_ref[0] = 0;
5448                 }
5449                 return request;
5450
5451         case REQ_ENTER:
5452                 /* After returning the status view has been split to
5453                  * show the stage view. No further reloading is
5454                  * necessary. */
5455                 return status_enter(view, line);
5456
5457         case REQ_REFRESH:
5458                 /* Simply reload the view. */
5459                 break;
5460
5461         default:
5462                 return request;
5463         }
5464
5465         open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD);
5466
5467         return REQ_NONE;
5468 }
5469
5470 static void
5471 status_select(struct view *view, struct line *line)
5472 {
5473         struct status *status = line->data;
5474         char file[SIZEOF_STR] = "all files";
5475         const char *text;
5476         const char *key;
5477
5478         if (status && !string_format(file, "'%s'", status->new.name))
5479                 return;
5480
5481         if (!status && line[1].type == LINE_STAT_NONE)
5482                 line++;
5483
5484         switch (line->type) {
5485         case LINE_STAT_STAGED:
5486                 text = "Press %s to unstage %s for commit";
5487                 break;
5488
5489         case LINE_STAT_UNSTAGED:
5490                 text = "Press %s to stage %s for commit";
5491                 break;
5492
5493         case LINE_STAT_UNTRACKED:
5494                 text = "Press %s to stage %s for addition";
5495                 break;
5496
5497         case LINE_STAT_HEAD:
5498         case LINE_STAT_NONE:
5499                 text = "Nothing to update";
5500                 break;
5501
5502         default:
5503                 die("line type %d not handled in switch", line->type);
5504         }
5505
5506         if (status && status->status == 'U') {
5507                 text = "Press %s to resolve conflict in %s";
5508                 key = get_key(REQ_STATUS_MERGE);
5509
5510         } else {
5511                 key = get_key(REQ_STATUS_UPDATE);
5512         }
5513
5514         string_format(view->ref, text, key, file);
5515 }
5516
5517 static bool
5518 status_grep(struct view *view, struct line *line)
5519 {
5520         struct status *status = line->data;
5521
5522         if (status) {
5523                 const char buf[2] = { status->status, 0 };
5524                 const char *text[] = { status->new.name, buf, NULL };
5525
5526                 return grep_text(view, text);
5527         }
5528
5529         return FALSE;
5530 }
5531
5532 static struct view_ops status_ops = {
5533         "file",
5534         NULL,
5535         status_open,
5536         NULL,
5537         status_draw,
5538         status_request,
5539         status_grep,
5540         status_select,
5541 };
5542
5543
5544 static bool
5545 stage_diff_write(struct io *io, struct line *line, struct line *end)
5546 {
5547         while (line < end) {
5548                 if (!io_write(io, line->data, strlen(line->data)) ||
5549                     !io_write(io, "\n", 1))
5550                         return FALSE;
5551                 line++;
5552                 if (line->type == LINE_DIFF_CHUNK ||
5553                     line->type == LINE_DIFF_HEADER)
5554                         break;
5555         }
5556
5557         return TRUE;
5558 }
5559
5560 static struct line *
5561 stage_diff_find(struct view *view, struct line *line, enum line_type type)
5562 {
5563         for (; view->line < line; line--)
5564                 if (line->type == type)
5565                         return line;
5566
5567         return NULL;
5568 }
5569
5570 static bool
5571 stage_apply_chunk(struct view *view, struct line *chunk, bool revert)
5572 {
5573         const char *apply_argv[SIZEOF_ARG] = {
5574                 "git", "apply", "--whitespace=nowarn", NULL
5575         };
5576         struct line *diff_hdr;
5577         struct io io = {};
5578         int argc = 3;
5579
5580         diff_hdr = stage_diff_find(view, chunk, LINE_DIFF_HEADER);
5581         if (!diff_hdr)
5582                 return FALSE;
5583
5584         if (!revert)
5585                 apply_argv[argc++] = "--cached";
5586         if (revert || stage_line_type == LINE_STAT_STAGED)
5587                 apply_argv[argc++] = "-R";
5588         apply_argv[argc++] = "-";
5589         apply_argv[argc++] = NULL;
5590         if (!run_io(&io, apply_argv, opt_cdup, IO_WR))
5591                 return FALSE;
5592
5593         if (!stage_diff_write(&io, diff_hdr, chunk) ||
5594             !stage_diff_write(&io, chunk, view->line + view->lines))
5595                 chunk = NULL;
5596
5597         done_io(&io);
5598         run_io_bg(update_index_argv);
5599
5600         return chunk ? TRUE : FALSE;
5601 }
5602
5603 static bool
5604 stage_update(struct view *view, struct line *line)
5605 {
5606         struct line *chunk = NULL;
5607
5608         if (!is_initial_commit() && stage_line_type != LINE_STAT_UNTRACKED)
5609                 chunk = stage_diff_find(view, line, LINE_DIFF_CHUNK);
5610
5611         if (chunk) {
5612                 if (!stage_apply_chunk(view, chunk, FALSE)) {
5613                         report("Failed to apply chunk");
5614                         return FALSE;
5615                 }
5616
5617         } else if (!stage_status.status) {
5618                 view = VIEW(REQ_VIEW_STATUS);
5619
5620                 for (line = view->line; line < view->line + view->lines; line++)
5621                         if (line->type == stage_line_type)
5622                                 break;
5623
5624                 if (!status_update_files(view, line + 1)) {
5625                         report("Failed to update files");
5626                         return FALSE;
5627                 }
5628
5629         } else if (!status_update_file(&stage_status, stage_line_type)) {
5630                 report("Failed to update file");
5631                 return FALSE;
5632         }
5633
5634         return TRUE;
5635 }
5636
5637 static bool
5638 stage_revert(struct view *view, struct line *line)
5639 {
5640         struct line *chunk = NULL;
5641
5642         if (!is_initial_commit() && stage_line_type == LINE_STAT_UNSTAGED)
5643                 chunk = stage_diff_find(view, line, LINE_DIFF_CHUNK);
5644
5645         if (chunk) {
5646                 if (!prompt_yesno("Are you sure you want to revert changes?"))
5647                         return FALSE;
5648
5649                 if (!stage_apply_chunk(view, chunk, TRUE)) {
5650                         report("Failed to revert chunk");
5651                         return FALSE;
5652                 }
5653                 return TRUE;
5654
5655         } else {
5656                 return status_revert(stage_status.status ? &stage_status : NULL,
5657                                      stage_line_type, FALSE);
5658         }
5659 }
5660
5661
5662 static void
5663 stage_next(struct view *view, struct line *line)
5664 {
5665         int i;
5666
5667         if (!stage_chunks) {
5668                 for (line = view->line; line < view->line + view->lines; line++) {
5669                         if (line->type != LINE_DIFF_CHUNK)
5670                                 continue;
5671
5672                         if (!realloc_ints(&stage_chunk, stage_chunks, 1)) {
5673                                 report("Allocation failure");
5674                                 return;
5675                         }
5676
5677                         stage_chunk[stage_chunks++] = line - view->line;
5678                 }
5679         }
5680
5681         for (i = 0; i < stage_chunks; i++) {
5682                 if (stage_chunk[i] > view->lineno) {
5683                         do_scroll_view(view, stage_chunk[i] - view->lineno);
5684                         report("Chunk %d of %d", i + 1, stage_chunks);
5685                         return;
5686                 }
5687         }
5688
5689         report("No next chunk found");
5690 }
5691
5692 static enum request
5693 stage_request(struct view *view, enum request request, struct line *line)
5694 {
5695         switch (request) {
5696         case REQ_STATUS_UPDATE:
5697                 if (!stage_update(view, line))
5698                         return REQ_NONE;
5699                 break;
5700
5701         case REQ_STATUS_REVERT:
5702                 if (!stage_revert(view, line))
5703                         return REQ_NONE;
5704                 break;
5705
5706         case REQ_STAGE_NEXT:
5707                 if (stage_line_type == LINE_STAT_UNTRACKED) {
5708                         report("File is untracked; press %s to add",
5709                                get_key(REQ_STATUS_UPDATE));
5710                         return REQ_NONE;
5711                 }
5712                 stage_next(view, line);
5713                 return REQ_NONE;
5714
5715         case REQ_EDIT:
5716                 if (!stage_status.new.name[0])
5717                         return request;
5718                 if (stage_status.status == 'D') {
5719                         report("File has been deleted.");
5720                         return REQ_NONE;
5721                 }
5722
5723                 open_editor(stage_status.status != '?', stage_status.new.name);
5724                 break;
5725
5726         case REQ_REFRESH:
5727                 /* Reload everything ... */
5728                 break;
5729
5730         case REQ_VIEW_BLAME:
5731                 if (stage_status.new.name[0]) {
5732                         string_copy(opt_file, stage_status.new.name);
5733                         opt_ref[0] = 0;
5734                 }
5735                 return request;
5736
5737         case REQ_ENTER:
5738                 return pager_request(view, request, line);
5739
5740         default:
5741                 return request;
5742         }
5743
5744         VIEW(REQ_VIEW_STATUS)->p_restore = TRUE;
5745         open_view(view, REQ_VIEW_STATUS, OPEN_REFRESH);
5746
5747         /* Check whether the staged entry still exists, and close the
5748          * stage view if it doesn't. */
5749         if (!status_exists(&stage_status, stage_line_type)) {
5750                 status_restore(VIEW(REQ_VIEW_STATUS));
5751                 return REQ_VIEW_CLOSE;
5752         }
5753
5754         if (stage_line_type == LINE_STAT_UNTRACKED) {
5755                 if (!suffixcmp(stage_status.new.name, -1, "/")) {
5756                         report("Cannot display a directory");
5757                         return REQ_NONE;
5758                 }
5759
5760                 if (!prepare_update_file(view, stage_status.new.name)) {
5761                         report("Failed to open file: %s", strerror(errno));
5762                         return REQ_NONE;
5763                 }
5764         }
5765         open_view(view, REQ_VIEW_STAGE, OPEN_REFRESH);
5766
5767         return REQ_NONE;
5768 }
5769
5770 static struct view_ops stage_ops = {
5771         "line",
5772         NULL,
5773         NULL,
5774         pager_read,
5775         pager_draw,
5776         stage_request,
5777         pager_grep,
5778         pager_select,
5779 };
5780
5781
5782 /*
5783  * Revision graph
5784  */
5785
5786 struct commit {
5787         char id[SIZEOF_REV];            /* SHA1 ID. */
5788         char title[128];                /* First line of the commit message. */
5789         const char *author;             /* Author of the commit. */
5790         time_t time;                    /* Date from the author ident. */
5791         struct ref **refs;              /* Repository references. */
5792         chtype graph[SIZEOF_REVGRAPH];  /* Ancestry chain graphics. */
5793         size_t graph_size;              /* The width of the graph array. */
5794         bool has_parents;               /* Rewritten --parents seen. */
5795 };
5796
5797 /* Size of rev graph with no  "padding" columns */
5798 #define SIZEOF_REVITEMS (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2))
5799
5800 struct rev_graph {
5801         struct rev_graph *prev, *next, *parents;
5802         char rev[SIZEOF_REVITEMS][SIZEOF_REV];
5803         size_t size;
5804         struct commit *commit;
5805         size_t pos;
5806         unsigned int boundary:1;
5807 };
5808
5809 /* Parents of the commit being visualized. */
5810 static struct rev_graph graph_parents[4];
5811
5812 /* The current stack of revisions on the graph. */
5813 static struct rev_graph graph_stacks[4] = {
5814         { &graph_stacks[3], &graph_stacks[1], &graph_parents[0] },
5815         { &graph_stacks[0], &graph_stacks[2], &graph_parents[1] },
5816         { &graph_stacks[1], &graph_stacks[3], &graph_parents[2] },
5817         { &graph_stacks[2], &graph_stacks[0], &graph_parents[3] },
5818 };
5819
5820 static inline bool
5821 graph_parent_is_merge(struct rev_graph *graph)
5822 {
5823         return graph->parents->size > 1;
5824 }
5825
5826 static inline void
5827 append_to_rev_graph(struct rev_graph *graph, chtype symbol)
5828 {
5829         struct commit *commit = graph->commit;
5830
5831         if (commit->graph_size < ARRAY_SIZE(commit->graph) - 1)
5832                 commit->graph[commit->graph_size++] = symbol;
5833 }
5834
5835 static void
5836 clear_rev_graph(struct rev_graph *graph)
5837 {
5838         graph->boundary = 0;
5839         graph->size = graph->pos = 0;
5840         graph->commit = NULL;
5841         memset(graph->parents, 0, sizeof(*graph->parents));
5842 }
5843
5844 static void
5845 done_rev_graph(struct rev_graph *graph)
5846 {
5847         if (graph_parent_is_merge(graph) &&
5848             graph->pos < graph->size - 1 &&
5849             graph->next->size == graph->size + graph->parents->size - 1) {
5850                 size_t i = graph->pos + graph->parents->size - 1;
5851
5852                 graph->commit->graph_size = i * 2;
5853                 while (i < graph->next->size - 1) {
5854                         append_to_rev_graph(graph, ' ');
5855                         append_to_rev_graph(graph, '\\');
5856                         i++;
5857                 }
5858         }
5859
5860         clear_rev_graph(graph);
5861 }
5862
5863 static void
5864 push_rev_graph(struct rev_graph *graph, const char *parent)
5865 {
5866         int i;
5867
5868         /* "Collapse" duplicate parents lines.
5869          *
5870          * FIXME: This needs to also update update the drawn graph but
5871          * for now it just serves as a method for pruning graph lines. */
5872         for (i = 0; i < graph->size; i++)
5873                 if (!strncmp(graph->rev[i], parent, SIZEOF_REV))
5874                         return;
5875
5876         if (graph->size < SIZEOF_REVITEMS) {
5877                 string_copy_rev(graph->rev[graph->size++], parent);
5878         }
5879 }
5880
5881 static chtype
5882 get_rev_graph_symbol(struct rev_graph *graph)
5883 {
5884         chtype symbol;
5885
5886         if (graph->boundary)
5887                 symbol = REVGRAPH_BOUND;
5888         else if (graph->parents->size == 0)
5889                 symbol = REVGRAPH_INIT;
5890         else if (graph_parent_is_merge(graph))
5891                 symbol = REVGRAPH_MERGE;
5892         else if (graph->pos >= graph->size)
5893                 symbol = REVGRAPH_BRANCH;
5894         else
5895                 symbol = REVGRAPH_COMMIT;
5896
5897         return symbol;
5898 }
5899
5900 static void
5901 draw_rev_graph(struct rev_graph *graph)
5902 {
5903         struct rev_filler {
5904                 chtype separator, line;
5905         };
5906         enum { DEFAULT, RSHARP, RDIAG, LDIAG };
5907         static struct rev_filler fillers[] = {
5908                 { ' ',  '|' },
5909                 { '`',  '.' },
5910                 { '\'', ' ' },
5911                 { '/',  ' ' },
5912         };
5913         chtype symbol = get_rev_graph_symbol(graph);
5914         struct rev_filler *filler;
5915         size_t i;
5916
5917         if (opt_line_graphics)
5918                 fillers[DEFAULT].line = line_graphics[LINE_GRAPHIC_VLINE];
5919
5920         filler = &fillers[DEFAULT];
5921
5922         for (i = 0; i < graph->pos; i++) {
5923                 append_to_rev_graph(graph, filler->line);
5924                 if (graph_parent_is_merge(graph->prev) &&
5925                     graph->prev->pos == i)
5926                         filler = &fillers[RSHARP];
5927
5928                 append_to_rev_graph(graph, filler->separator);
5929         }
5930
5931         /* Place the symbol for this revision. */
5932         append_to_rev_graph(graph, symbol);
5933
5934         if (graph->prev->size > graph->size)
5935                 filler = &fillers[RDIAG];
5936         else
5937                 filler = &fillers[DEFAULT];
5938
5939         i++;
5940
5941         for (; i < graph->size; i++) {
5942                 append_to_rev_graph(graph, filler->separator);
5943                 append_to_rev_graph(graph, filler->line);
5944                 if (graph_parent_is_merge(graph->prev) &&
5945                     i < graph->prev->pos + graph->parents->size)
5946                         filler = &fillers[RSHARP];
5947                 if (graph->prev->size > graph->size)
5948                         filler = &fillers[LDIAG];
5949         }
5950
5951         if (graph->prev->size > graph->size) {
5952                 append_to_rev_graph(graph, filler->separator);
5953                 if (filler->line != ' ')
5954                         append_to_rev_graph(graph, filler->line);
5955         }
5956 }
5957
5958 /* Prepare the next rev graph */
5959 static void
5960 prepare_rev_graph(struct rev_graph *graph)
5961 {
5962         size_t i;
5963
5964         /* First, traverse all lines of revisions up to the active one. */
5965         for (graph->pos = 0; graph->pos < graph->size; graph->pos++) {
5966                 if (!strcmp(graph->rev[graph->pos], graph->commit->id))
5967                         break;
5968
5969                 push_rev_graph(graph->next, graph->rev[graph->pos]);
5970         }
5971
5972         /* Interleave the new revision parent(s). */
5973         for (i = 0; !graph->boundary && i < graph->parents->size; i++)
5974                 push_rev_graph(graph->next, graph->parents->rev[i]);
5975
5976         /* Lastly, put any remaining revisions. */
5977         for (i = graph->pos + 1; i < graph->size; i++)
5978                 push_rev_graph(graph->next, graph->rev[i]);
5979 }
5980
5981 static void
5982 update_rev_graph(struct view *view, struct rev_graph *graph)
5983 {
5984         /* If this is the finalizing update ... */
5985         if (graph->commit)
5986                 prepare_rev_graph(graph);
5987
5988         /* Graph visualization needs a one rev look-ahead,
5989          * so the first update doesn't visualize anything. */
5990         if (!graph->prev->commit)
5991                 return;
5992
5993         if (view->lines > 2)
5994                 view->line[view->lines - 3].dirty = 1;
5995         if (view->lines > 1)
5996                 view->line[view->lines - 2].dirty = 1;
5997         draw_rev_graph(graph->prev);
5998         done_rev_graph(graph->prev->prev);
5999 }
6000
6001
6002 /*
6003  * Main view backend
6004  */
6005
6006 static const char *main_argv[SIZEOF_ARG] = {
6007         "git", "log", "--no-color", "--pretty=raw", "--parents",
6008                       "--topo-order", "%(head)", NULL
6009 };
6010
6011 static bool
6012 main_draw(struct view *view, struct line *line, unsigned int lineno)
6013 {
6014         struct commit *commit = line->data;
6015
6016         if (!commit->author)
6017                 return FALSE;
6018
6019         if (opt_date && draw_date(view, &commit->time))
6020                 return TRUE;
6021
6022         if (opt_author && draw_author(view, commit->author))
6023                 return TRUE;
6024
6025         if (opt_rev_graph && commit->graph_size &&
6026             draw_graphic(view, LINE_MAIN_REVGRAPH, commit->graph, commit->graph_size))
6027                 return TRUE;
6028
6029         if (opt_show_refs && commit->refs) {
6030                 size_t i = 0;
6031
6032                 do {
6033                         struct ref *ref = commit->refs[i];
6034                         enum line_type type;
6035
6036                         if (ref->head)
6037                                 type = LINE_MAIN_HEAD;
6038                         else if (ref->ltag)
6039                                 type = LINE_MAIN_LOCAL_TAG;
6040                         else if (ref->tag)
6041                                 type = LINE_MAIN_TAG;
6042                         else if (ref->tracked)
6043                                 type = LINE_MAIN_TRACKED;
6044                         else if (ref->remote)
6045                                 type = LINE_MAIN_REMOTE;
6046                         else
6047                                 type = LINE_MAIN_REF;
6048
6049                         if (draw_text(view, type, "[", TRUE) ||
6050                             draw_text(view, type, ref->name, TRUE) ||
6051                             draw_text(view, type, "]", TRUE))
6052                                 return TRUE;
6053
6054                         if (draw_text(view, LINE_DEFAULT, " ", TRUE))
6055                                 return TRUE;
6056                 } while (commit->refs[i++]->next);
6057         }
6058
6059         draw_text(view, LINE_DEFAULT, commit->title, TRUE);
6060         return TRUE;
6061 }
6062
6063 /* Reads git log --pretty=raw output and parses it into the commit struct. */
6064 static bool
6065 main_read(struct view *view, char *line)
6066 {
6067         static struct rev_graph *graph = graph_stacks;
6068         enum line_type type;
6069         struct commit *commit;
6070
6071         if (!line) {
6072                 int i;
6073
6074                 if (!view->lines && !view->parent)
6075                         die("No revisions match the given arguments.");
6076                 if (view->lines > 0) {
6077                         commit = view->line[view->lines - 1].data;
6078                         view->line[view->lines - 1].dirty = 1;
6079                         if (!commit->author) {
6080                                 view->lines--;
6081                                 free(commit);
6082                                 graph->commit = NULL;
6083                         }
6084                 }
6085                 update_rev_graph(view, graph);
6086
6087                 for (i = 0; i < ARRAY_SIZE(graph_stacks); i++)
6088                         clear_rev_graph(&graph_stacks[i]);
6089                 return TRUE;
6090         }
6091
6092         type = get_line_type(line);
6093         if (type == LINE_COMMIT) {
6094                 commit = calloc(1, sizeof(struct commit));
6095                 if (!commit)
6096                         return FALSE;
6097
6098                 line += STRING_SIZE("commit ");
6099                 if (*line == '-') {
6100                         graph->boundary = 1;
6101                         line++;
6102                 }
6103
6104                 string_copy_rev(commit->id, line);
6105                 commit->refs = get_refs(commit->id);
6106                 graph->commit = commit;
6107                 add_line_data(view, commit, LINE_MAIN_COMMIT);
6108
6109                 while ((line = strchr(line, ' '))) {
6110                         line++;
6111                         push_rev_graph(graph->parents, line);
6112                         commit->has_parents = TRUE;
6113                 }
6114                 return TRUE;
6115         }
6116
6117         if (!view->lines)
6118                 return TRUE;
6119         commit = view->line[view->lines - 1].data;
6120
6121         switch (type) {
6122         case LINE_PARENT:
6123                 if (commit->has_parents)
6124                         break;
6125                 push_rev_graph(graph->parents, line + STRING_SIZE("parent "));
6126                 break;
6127
6128         case LINE_AUTHOR:
6129                 parse_author_line(line + STRING_SIZE("author "),
6130                                   &commit->author, &commit->time);
6131                 update_rev_graph(view, graph);
6132                 graph = graph->next;
6133                 break;
6134
6135         default:
6136                 /* Fill in the commit title if it has not already been set. */
6137                 if (commit->title[0])
6138                         break;
6139
6140                 /* Require titles to start with a non-space character at the
6141                  * offset used by git log. */
6142                 if (strncmp(line, "    ", 4))
6143                         break;
6144                 line += 4;
6145                 /* Well, if the title starts with a whitespace character,
6146                  * try to be forgiving.  Otherwise we end up with no title. */
6147                 while (isspace(*line))
6148                         line++;
6149                 if (*line == '\0')
6150                         break;
6151                 /* FIXME: More graceful handling of titles; append "..." to
6152                  * shortened titles, etc. */
6153
6154                 string_expand(commit->title, sizeof(commit->title), line, 1);
6155                 view->line[view->lines - 1].dirty = 1;
6156         }
6157
6158         return TRUE;
6159 }
6160
6161 static enum request
6162 main_request(struct view *view, enum request request, struct line *line)
6163 {
6164         enum open_flags flags = display[0] == view ? OPEN_SPLIT : OPEN_DEFAULT;
6165
6166         switch (request) {
6167         case REQ_ENTER:
6168                 open_view(view, REQ_VIEW_DIFF, flags);
6169                 break;
6170         case REQ_REFRESH:
6171                 load_refs();
6172                 open_view(view, REQ_VIEW_MAIN, OPEN_REFRESH);
6173                 break;
6174         default:
6175                 return request;
6176         }
6177
6178         return REQ_NONE;
6179 }
6180
6181 static bool
6182 grep_refs(struct ref **refs, regex_t *regex)
6183 {
6184         regmatch_t pmatch;
6185         size_t i = 0;
6186
6187         if (!opt_show_refs || !refs)
6188                 return FALSE;
6189         do {
6190                 if (regexec(regex, refs[i]->name, 1, &pmatch, 0) != REG_NOMATCH)
6191                         return TRUE;
6192         } while (refs[i++]->next);
6193
6194         return FALSE;
6195 }
6196
6197 static bool
6198 main_grep(struct view *view, struct line *line)
6199 {
6200         struct commit *commit = line->data;
6201         const char *text[] = {
6202                 commit->title,
6203                 opt_author ? commit->author : "",
6204                 opt_date ? mkdate(&commit->time) : "",
6205                 NULL
6206         };
6207
6208         return grep_text(view, text) || grep_refs(commit->refs, view->regex);
6209 }
6210
6211 static void
6212 main_select(struct view *view, struct line *line)
6213 {
6214         struct commit *commit = line->data;
6215
6216         string_copy_rev(view->ref, commit->id);
6217         string_copy_rev(ref_commit, view->ref);
6218 }
6219
6220 static struct view_ops main_ops = {
6221         "commit",
6222         main_argv,
6223         NULL,
6224         main_read,
6225         main_draw,
6226         main_request,
6227         main_grep,
6228         main_select,
6229 };
6230
6231
6232 /*
6233  * Unicode / UTF-8 handling
6234  *
6235  * NOTE: Much of the following code for dealing with Unicode is derived from
6236  * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
6237  * src/intl/charset.c from the UTF-8 branch commit elinks-0.11.0-g31f2c28.
6238  */
6239
6240 static inline int
6241 unicode_width(unsigned long c)
6242 {
6243         if (c >= 0x1100 &&
6244            (c <= 0x115f                         /* Hangul Jamo */
6245             || c == 0x2329
6246             || c == 0x232a
6247             || (c >= 0x2e80  && c <= 0xa4cf && c != 0x303f)
6248                                                 /* CJK ... Yi */
6249             || (c >= 0xac00  && c <= 0xd7a3)    /* Hangul Syllables */
6250             || (c >= 0xf900  && c <= 0xfaff)    /* CJK Compatibility Ideographs */
6251             || (c >= 0xfe30  && c <= 0xfe6f)    /* CJK Compatibility Forms */
6252             || (c >= 0xff00  && c <= 0xff60)    /* Fullwidth Forms */
6253             || (c >= 0xffe0  && c <= 0xffe6)
6254             || (c >= 0x20000 && c <= 0x2fffd)
6255             || (c >= 0x30000 && c <= 0x3fffd)))
6256                 return 2;
6257
6258         if (c == '\t')
6259                 return opt_tab_size;
6260
6261         return 1;
6262 }
6263
6264 /* Number of bytes used for encoding a UTF-8 character indexed by first byte.
6265  * Illegal bytes are set one. */
6266 static const unsigned char utf8_bytes[256] = {
6267         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,
6268         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,
6269         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,
6270         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,
6271         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,
6272         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,
6273         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,
6274         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,
6275 };
6276
6277 /* Decode UTF-8 multi-byte representation into a Unicode character. */
6278 static inline unsigned long
6279 utf8_to_unicode(const char *string, size_t length)
6280 {
6281         unsigned long unicode;
6282
6283         switch (length) {
6284         case 1:
6285                 unicode  =   string[0];
6286                 break;
6287         case 2:
6288                 unicode  =  (string[0] & 0x1f) << 6;
6289                 unicode +=  (string[1] & 0x3f);
6290                 break;
6291         case 3:
6292                 unicode  =  (string[0] & 0x0f) << 12;
6293                 unicode += ((string[1] & 0x3f) << 6);
6294                 unicode +=  (string[2] & 0x3f);
6295                 break;
6296         case 4:
6297                 unicode  =  (string[0] & 0x0f) << 18;
6298                 unicode += ((string[1] & 0x3f) << 12);
6299                 unicode += ((string[2] & 0x3f) << 6);
6300                 unicode +=  (string[3] & 0x3f);
6301                 break;
6302         case 5:
6303                 unicode  =  (string[0] & 0x0f) << 24;
6304                 unicode += ((string[1] & 0x3f) << 18);
6305                 unicode += ((string[2] & 0x3f) << 12);
6306                 unicode += ((string[3] & 0x3f) << 6);
6307                 unicode +=  (string[4] & 0x3f);
6308                 break;
6309         case 6:
6310                 unicode  =  (string[0] & 0x01) << 30;
6311                 unicode += ((string[1] & 0x3f) << 24);
6312                 unicode += ((string[2] & 0x3f) << 18);
6313                 unicode += ((string[3] & 0x3f) << 12);
6314                 unicode += ((string[4] & 0x3f) << 6);
6315                 unicode +=  (string[5] & 0x3f);
6316                 break;
6317         default:
6318                 die("Invalid Unicode length");
6319         }
6320
6321         /* Invalid characters could return the special 0xfffd value but NUL
6322          * should be just as good. */
6323         return unicode > 0xffff ? 0 : unicode;
6324 }
6325
6326 /* Calculates how much of string can be shown within the given maximum width
6327  * and sets trimmed parameter to non-zero value if all of string could not be
6328  * shown. If the reserve flag is TRUE, it will reserve at least one
6329  * trailing character, which can be useful when drawing a delimiter.
6330  *
6331  * Returns the number of bytes to output from string to satisfy max_width. */
6332 static size_t
6333 utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve)
6334 {
6335         const char *string = *start;
6336         const char *end = strchr(string, '\0');
6337         unsigned char last_bytes = 0;
6338         size_t last_ucwidth = 0;
6339
6340         *width = 0;
6341         *trimmed = 0;
6342
6343         while (string < end) {
6344                 int c = *(unsigned char *) string;
6345                 unsigned char bytes = utf8_bytes[c];
6346                 size_t ucwidth;
6347                 unsigned long unicode;
6348
6349                 if (string + bytes > end)
6350                         break;
6351
6352                 /* Change representation to figure out whether
6353                  * it is a single- or double-width character. */
6354
6355                 unicode = utf8_to_unicode(string, bytes);
6356                 /* FIXME: Graceful handling of invalid Unicode character. */
6357                 if (!unicode)
6358                         break;
6359
6360                 ucwidth = unicode_width(unicode);
6361                 if (skip > 0) {
6362                         skip -= ucwidth <= skip ? ucwidth : skip;
6363                         *start += bytes;
6364                 }
6365                 *width  += ucwidth;
6366                 if (*width > max_width) {
6367                         *trimmed = 1;
6368                         *width -= ucwidth;
6369                         if (reserve && *width == max_width) {
6370                                 string -= last_bytes;
6371                                 *width -= last_ucwidth;
6372                         }
6373                         break;
6374                 }
6375
6376                 string  += bytes;
6377                 last_bytes = ucwidth ? bytes : 0;
6378                 last_ucwidth = ucwidth;
6379         }
6380
6381         return string - *start;
6382 }
6383
6384
6385 /*
6386  * Status management
6387  */
6388
6389 /* Whether or not the curses interface has been initialized. */
6390 static bool cursed = FALSE;
6391
6392 /* Terminal hacks and workarounds. */
6393 static bool use_scroll_redrawwin;
6394 static bool use_scroll_status_wclear;
6395
6396 /* The status window is used for polling keystrokes. */
6397 static WINDOW *status_win;
6398
6399 /* Reading from the prompt? */
6400 static bool input_mode = FALSE;
6401
6402 static bool status_empty = FALSE;
6403
6404 /* Update status and title window. */
6405 static void
6406 report(const char *msg, ...)
6407 {
6408         struct view *view = display[current_view];
6409
6410         if (input_mode)
6411                 return;
6412
6413         if (!view) {
6414                 char buf[SIZEOF_STR];
6415                 va_list args;
6416
6417                 va_start(args, msg);
6418                 if (vsnprintf(buf, sizeof(buf), msg, args) >= sizeof(buf)) {
6419                         buf[sizeof(buf) - 1] = 0;
6420                         buf[sizeof(buf) - 2] = '.';
6421                         buf[sizeof(buf) - 3] = '.';
6422                         buf[sizeof(buf) - 4] = '.';
6423                 }
6424                 va_end(args);
6425                 die("%s", buf);
6426         }
6427
6428         if (!status_empty || *msg) {
6429                 va_list args;
6430
6431                 va_start(args, msg);
6432
6433                 wmove(status_win, 0, 0);
6434                 if (view->has_scrolled && use_scroll_status_wclear)
6435                         wclear(status_win);
6436                 if (*msg) {
6437                         vwprintw(status_win, msg, args);
6438                         status_empty = FALSE;
6439                 } else {
6440                         status_empty = TRUE;
6441                 }
6442                 wclrtoeol(status_win);
6443                 wnoutrefresh(status_win);
6444
6445                 va_end(args);
6446         }
6447
6448         update_view_title(view);
6449 }
6450
6451 /* Controls when nodelay should be in effect when polling user input. */
6452 static void
6453 set_nonblocking_input(bool loading)
6454 {
6455         static unsigned int loading_views;
6456
6457         if ((loading == FALSE && loading_views-- == 1) ||
6458             (loading == TRUE  && loading_views++ == 0))
6459                 nodelay(status_win, loading);
6460 }
6461
6462 static void
6463 init_display(void)
6464 {
6465         const char *term;
6466         int x, y;
6467
6468         /* Initialize the curses library */
6469         if (isatty(STDIN_FILENO)) {
6470                 cursed = !!initscr();
6471                 opt_tty = stdin;
6472         } else {
6473                 /* Leave stdin and stdout alone when acting as a pager. */
6474                 opt_tty = fopen("/dev/tty", "r+");
6475                 if (!opt_tty)
6476                         die("Failed to open /dev/tty");
6477                 cursed = !!newterm(NULL, opt_tty, opt_tty);
6478         }
6479
6480         if (!cursed)
6481                 die("Failed to initialize curses");
6482
6483         nonl();         /* Disable conversion and detect newlines from input. */
6484         cbreak();       /* Take input chars one at a time, no wait for \n */
6485         noecho();       /* Don't echo input */
6486         leaveok(stdscr, FALSE);
6487
6488         if (has_colors())
6489                 init_colors();
6490
6491         getmaxyx(stdscr, y, x);
6492         status_win = newwin(1, 0, y - 1, 0);
6493         if (!status_win)
6494                 die("Failed to create status window");
6495
6496         /* Enable keyboard mapping */
6497         keypad(status_win, TRUE);
6498         wbkgdset(status_win, get_line_attr(LINE_STATUS));
6499
6500         TABSIZE = opt_tab_size;
6501         if (opt_line_graphics) {
6502                 line_graphics[LINE_GRAPHIC_VLINE] = ACS_VLINE;
6503         }
6504
6505         term = getenv("XTERM_VERSION") ? NULL : getenv("COLORTERM");
6506         if (term && !strcmp(term, "gnome-terminal")) {
6507                 /* In the gnome-terminal-emulator, the message from
6508                  * scrolling up one line when impossible followed by
6509                  * scrolling down one line causes corruption of the
6510                  * status line. This is fixed by calling wclear. */
6511                 use_scroll_status_wclear = TRUE;
6512                 use_scroll_redrawwin = FALSE;
6513
6514         } else if (term && !strcmp(term, "xrvt-xpm")) {
6515                 /* No problems with full optimizations in xrvt-(unicode)
6516                  * and aterm. */
6517                 use_scroll_status_wclear = use_scroll_redrawwin = FALSE;
6518
6519         } else {
6520                 /* When scrolling in (u)xterm the last line in the
6521                  * scrolling direction will update slowly. */
6522                 use_scroll_redrawwin = TRUE;
6523                 use_scroll_status_wclear = FALSE;
6524         }
6525 }
6526
6527 static int
6528 get_input(int prompt_position)
6529 {
6530         struct view *view;
6531         int i, key, cursor_y, cursor_x;
6532
6533         if (prompt_position)
6534                 input_mode = TRUE;
6535
6536         while (TRUE) {
6537                 foreach_view (view, i) {
6538                         update_view(view);
6539                         if (view_is_displayed(view) && view->has_scrolled &&
6540                             use_scroll_redrawwin)
6541                                 redrawwin(view->win);
6542                         view->has_scrolled = FALSE;
6543                 }
6544
6545                 /* Update the cursor position. */
6546                 if (prompt_position) {
6547                         getbegyx(status_win, cursor_y, cursor_x);
6548                         cursor_x = prompt_position;
6549                 } else {
6550                         view = display[current_view];
6551                         getbegyx(view->win, cursor_y, cursor_x);
6552                         cursor_x = view->width - 1;
6553                         cursor_y += view->lineno - view->offset;
6554                 }
6555                 setsyx(cursor_y, cursor_x);
6556
6557                 /* Refresh, accept single keystroke of input */
6558                 doupdate();
6559                 key = wgetch(status_win);
6560
6561                 /* wgetch() with nodelay() enabled returns ERR when
6562                  * there's no input. */
6563                 if (key == ERR) {
6564
6565                 } else if (key == KEY_RESIZE) {
6566                         int height, width;
6567
6568                         getmaxyx(stdscr, height, width);
6569
6570                         wresize(status_win, 1, width);
6571                         mvwin(status_win, height - 1, 0);
6572                         wnoutrefresh(status_win);
6573                         resize_display();
6574                         redraw_display(TRUE);
6575
6576                 } else {
6577                         input_mode = FALSE;
6578                         return key;
6579                 }
6580         }
6581 }
6582
6583 static char *
6584 prompt_input(const char *prompt, input_handler handler, void *data)
6585 {
6586         enum input_status status = INPUT_OK;
6587         static char buf[SIZEOF_STR];
6588         size_t pos = 0;
6589
6590         buf[pos] = 0;
6591
6592         while (status == INPUT_OK || status == INPUT_SKIP) {
6593                 int key;
6594
6595                 mvwprintw(status_win, 0, 0, "%s%.*s", prompt, pos, buf);
6596                 wclrtoeol(status_win);
6597
6598                 key = get_input(pos + 1);
6599                 switch (key) {
6600                 case KEY_RETURN:
6601                 case KEY_ENTER:
6602                 case '\n':
6603                         status = pos ? INPUT_STOP : INPUT_CANCEL;
6604                         break;
6605
6606                 case KEY_BACKSPACE:
6607                         if (pos > 0)
6608                                 buf[--pos] = 0;
6609                         else
6610                                 status = INPUT_CANCEL;
6611                         break;
6612
6613                 case KEY_ESC:
6614                         status = INPUT_CANCEL;
6615                         break;
6616
6617                 default:
6618                         if (pos >= sizeof(buf)) {
6619                                 report("Input string too long");
6620                                 return NULL;
6621                         }
6622
6623                         status = handler(data, buf, key);
6624                         if (status == INPUT_OK)
6625                                 buf[pos++] = (char) key;
6626                 }
6627         }
6628
6629         /* Clear the status window */
6630         status_empty = FALSE;
6631         report("");
6632
6633         if (status == INPUT_CANCEL)
6634                 return NULL;
6635
6636         buf[pos++] = 0;
6637
6638         return buf;
6639 }
6640
6641 static enum input_status
6642 prompt_yesno_handler(void *data, char *buf, int c)
6643 {
6644         if (c == 'y' || c == 'Y')
6645                 return INPUT_STOP;
6646         if (c == 'n' || c == 'N')
6647                 return INPUT_CANCEL;
6648         return INPUT_SKIP;
6649 }
6650
6651 static bool
6652 prompt_yesno(const char *prompt)
6653 {
6654         char prompt2[SIZEOF_STR];
6655
6656         if (!string_format(prompt2, "%s [Yy/Nn]", prompt))
6657                 return FALSE;
6658
6659         return !!prompt_input(prompt2, prompt_yesno_handler, NULL);
6660 }
6661
6662 static enum input_status
6663 read_prompt_handler(void *data, char *buf, int c)
6664 {
6665         return isprint(c) ? INPUT_OK : INPUT_SKIP;
6666 }
6667
6668 static char *
6669 read_prompt(const char *prompt)
6670 {
6671         return prompt_input(prompt, read_prompt_handler, NULL);
6672 }
6673
6674 /*
6675  * Repository properties
6676  */
6677
6678 static struct ref *refs = NULL;
6679 static size_t refs_size = 0;
6680
6681 /* Id <-> ref store */
6682 static struct ref ***id_refs = NULL;
6683 static size_t id_refs_size = 0;
6684
6685 DEFINE_ALLOCATOR(realloc_refs, struct ref, 256)
6686 DEFINE_ALLOCATOR(realloc_refs_list, struct ref *, 8)
6687 DEFINE_ALLOCATOR(realloc_refs_lists, struct ref **, 8)
6688
6689 static int
6690 compare_refs(const void *ref1_, const void *ref2_)
6691 {
6692         const struct ref *ref1 = *(const struct ref **)ref1_;
6693         const struct ref *ref2 = *(const struct ref **)ref2_;
6694
6695         if (ref1->tag != ref2->tag)
6696                 return ref2->tag - ref1->tag;
6697         if (ref1->ltag != ref2->ltag)
6698                 return ref2->ltag - ref2->ltag;
6699         if (ref1->head != ref2->head)
6700                 return ref2->head - ref1->head;
6701         if (ref1->tracked != ref2->tracked)
6702                 return ref2->tracked - ref1->tracked;
6703         if (ref1->remote != ref2->remote)
6704                 return ref2->remote - ref1->remote;
6705         return strcmp(ref1->name, ref2->name);
6706 }
6707
6708 static void
6709 foreach_ref(bool (*visitor)(void *data, struct ref *ref), void *data)
6710 {
6711         size_t i;
6712
6713         for (i = 0; i < refs_size; i++)
6714                 if (!visitor(data, &refs[i]))
6715                         break;
6716 }
6717
6718 static struct ref **
6719 get_refs(const char *id)
6720 {
6721         struct ref **ref_list = NULL;
6722         size_t ref_list_size = 0;
6723         size_t i;
6724
6725         for (i = 0; i < id_refs_size; i++)
6726                 if (!strcmp(id, id_refs[i][0]->id))
6727                         return id_refs[i];
6728
6729         if (!realloc_refs_lists(&id_refs, id_refs_size, 1))
6730                 return NULL;
6731
6732         for (i = 0; i < refs_size; i++) {
6733                 if (strcmp(id, refs[i].id))
6734                         continue;
6735
6736                 if (!realloc_refs_list(&ref_list, ref_list_size, 1))
6737                         break;
6738
6739                 ref_list[ref_list_size] = &refs[i];
6740                 /* XXX: The properties of the commit chains ensures that we can
6741                  * safely modify the shared ref. The repo references will
6742                  * always be similar for the same id. */
6743                 ref_list[ref_list_size]->next = 1;
6744                 ref_list_size++;
6745         }
6746
6747         if (ref_list) {
6748                 qsort(ref_list, ref_list_size, sizeof(*ref_list), compare_refs);
6749                 ref_list[ref_list_size - 1]->next = 0;
6750                 id_refs[id_refs_size++] = ref_list;
6751         }
6752
6753         return ref_list;
6754 }
6755
6756 static int
6757 read_ref(char *id, size_t idlen, char *name, size_t namelen)
6758 {
6759         struct ref *ref;
6760         bool tag = FALSE;
6761         bool ltag = FALSE;
6762         bool remote = FALSE;
6763         bool tracked = FALSE;
6764         bool check_replace = FALSE;
6765         bool head = FALSE;
6766
6767         if (!prefixcmp(name, "refs/tags/")) {
6768                 if (!suffixcmp(name, namelen, "^{}")) {
6769                         namelen -= 3;
6770                         name[namelen] = 0;
6771                         if (refs_size > 0 && refs[refs_size - 1].ltag == TRUE)
6772                                 check_replace = TRUE;
6773                 } else {
6774                         ltag = TRUE;
6775                 }
6776
6777                 tag = TRUE;
6778                 namelen -= STRING_SIZE("refs/tags/");
6779                 name    += STRING_SIZE("refs/tags/");
6780
6781         } else if (!prefixcmp(name, "refs/remotes/")) {
6782                 remote = TRUE;
6783                 namelen -= STRING_SIZE("refs/remotes/");
6784                 name    += STRING_SIZE("refs/remotes/");
6785                 tracked  = !strcmp(opt_remote, name);
6786
6787         } else if (!prefixcmp(name, "refs/heads/")) {
6788                 namelen -= STRING_SIZE("refs/heads/");
6789                 name    += STRING_SIZE("refs/heads/");
6790                 head     = !strncmp(opt_head, name, namelen);
6791
6792         } else if (!strcmp(name, "HEAD")) {
6793                 string_ncopy(opt_head_rev, id, idlen);
6794                 return OK;
6795         }
6796
6797         if (check_replace && !strcmp(name, refs[refs_size - 1].name)) {
6798                 /* it's an annotated tag, replace the previous SHA1 with the
6799                  * resolved commit id; relies on the fact git-ls-remote lists
6800                  * the commit id of an annotated tag right before the commit id
6801                  * it points to. */
6802                 refs[refs_size - 1].ltag = ltag;
6803                 string_copy_rev(refs[refs_size - 1].id, id);
6804
6805                 return OK;
6806         }
6807
6808         if (!realloc_refs(&refs, refs_size, 1))
6809                 return ERR;
6810
6811         ref = &refs[refs_size++];
6812         ref->name = malloc(namelen + 1);
6813         if (!ref->name)
6814                 return ERR;
6815
6816         strncpy(ref->name, name, namelen);
6817         ref->name[namelen] = 0;
6818         ref->head = head;
6819         ref->tag = tag;
6820         ref->ltag = ltag;
6821         ref->remote = remote;
6822         ref->tracked = tracked;
6823         string_copy_rev(ref->id, id);
6824
6825         return OK;
6826 }
6827
6828 static int
6829 load_refs(void)
6830 {
6831         const char *head_argv[] = {
6832                 "git", "symbolic-ref", "HEAD", NULL
6833         };
6834         static const char *ls_remote_argv[SIZEOF_ARG] = {
6835                 "git", "ls-remote", opt_git_dir, NULL
6836         };
6837         static bool init = FALSE;
6838
6839         if (!init) {
6840                 argv_from_env(ls_remote_argv, "TIG_LS_REMOTE");
6841                 init = TRUE;
6842         }
6843
6844         if (!*opt_git_dir)
6845                 return OK;
6846
6847         if (run_io_buf(head_argv, opt_head, sizeof(opt_head)) &&
6848             !prefixcmp(opt_head, "refs/heads/")) {
6849                 char *offset = opt_head + STRING_SIZE("refs/heads/");
6850
6851                 memmove(opt_head, offset, strlen(offset) + 1);
6852         }
6853
6854         while (refs_size > 0)
6855                 free(refs[--refs_size].name);
6856         while (id_refs_size > 0)
6857                 free(id_refs[--id_refs_size]);
6858
6859         return run_io_load(ls_remote_argv, "\t", read_ref);
6860 }
6861
6862 static void
6863 set_remote_branch(const char *name, const char *value, size_t valuelen)
6864 {
6865         if (!strcmp(name, ".remote")) {
6866                 string_ncopy(opt_remote, value, valuelen);
6867
6868         } else if (*opt_remote && !strcmp(name, ".merge")) {
6869                 size_t from = strlen(opt_remote);
6870
6871                 if (!prefixcmp(value, "refs/heads/"))
6872                         value += STRING_SIZE("refs/heads/");
6873
6874                 if (!string_format_from(opt_remote, &from, "/%s", value))
6875                         opt_remote[0] = 0;
6876         }
6877 }
6878
6879 static void
6880 set_repo_config_option(char *name, char *value, int (*cmd)(int, const char **))
6881 {
6882         const char *argv[SIZEOF_ARG] = { name, "=" };
6883         int argc = 1 + (cmd == option_set_command);
6884         int error = ERR;
6885
6886         if (!argv_from_string(argv, &argc, value))
6887                 config_msg = "Too many option arguments";
6888         else
6889                 error = cmd(argc, argv);
6890
6891         if (error == ERR)
6892                 warn("Option 'tig.%s': %s", name, config_msg);
6893 }
6894
6895 static bool
6896 set_environment_variable(const char *name, const char *value)
6897 {
6898         size_t len = strlen(name) + 1 + strlen(value) + 1;
6899         char *env = malloc(len);
6900
6901         if (env &&
6902             string_nformat(env, len, NULL, "%s=%s", name, value) &&
6903             putenv(env) == 0)
6904                 return TRUE;
6905         free(env);
6906         return FALSE;
6907 }
6908
6909 static void
6910 set_work_tree(const char *value)
6911 {
6912         char cwd[SIZEOF_STR];
6913
6914         if (!getcwd(cwd, sizeof(cwd)))
6915                 die("Failed to get cwd path: %s", strerror(errno));
6916         if (chdir(opt_git_dir) < 0)
6917                 die("Failed to chdir(%s): %s", strerror(errno));
6918         if (!getcwd(opt_git_dir, sizeof(opt_git_dir)))
6919                 die("Failed to get git path: %s", strerror(errno));
6920         if (chdir(cwd) < 0)
6921                 die("Failed to chdir(%s): %s", cwd, strerror(errno));
6922         if (chdir(value) < 0)
6923                 die("Failed to chdir(%s): %s", value, strerror(errno));
6924         if (!getcwd(cwd, sizeof(cwd)))
6925                 die("Failed to get cwd path: %s", strerror(errno));
6926         if (!set_environment_variable("GIT_WORK_TREE", cwd))
6927                 die("Failed to set GIT_WORK_TREE to '%s'", cwd);
6928         if (!set_environment_variable("GIT_DIR", opt_git_dir))
6929                 die("Failed to set GIT_DIR to '%s'", opt_git_dir);
6930         opt_is_inside_work_tree = TRUE;
6931 }
6932
6933 static int
6934 read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen)
6935 {
6936         if (!strcmp(name, "i18n.commitencoding"))
6937                 string_ncopy(opt_encoding, value, valuelen);
6938
6939         else if (!strcmp(name, "core.editor"))
6940                 string_ncopy(opt_editor, value, valuelen);
6941
6942         else if (!strcmp(name, "core.worktree"))
6943                 set_work_tree(value);
6944
6945         else if (!prefixcmp(name, "tig.color."))
6946                 set_repo_config_option(name + 10, value, option_color_command);
6947
6948         else if (!prefixcmp(name, "tig.bind."))
6949                 set_repo_config_option(name + 9, value, option_bind_command);
6950
6951         else if (!prefixcmp(name, "tig."))
6952                 set_repo_config_option(name + 4, value, option_set_command);
6953
6954         else if (*opt_head && !prefixcmp(name, "branch.") &&
6955                  !strncmp(name + 7, opt_head, strlen(opt_head)))
6956                 set_remote_branch(name + 7 + strlen(opt_head), value, valuelen);
6957
6958         return OK;
6959 }
6960
6961 static int
6962 load_git_config(void)
6963 {
6964         const char *config_list_argv[] = { "git", GIT_CONFIG, "--list", NULL };
6965
6966         return run_io_load(config_list_argv, "=", read_repo_config_option);
6967 }
6968
6969 static int
6970 read_repo_info(char *name, size_t namelen, char *value, size_t valuelen)
6971 {
6972         if (!opt_git_dir[0]) {
6973                 string_ncopy(opt_git_dir, name, namelen);
6974
6975         } else if (opt_is_inside_work_tree == -1) {
6976                 /* This can be 3 different values depending on the
6977                  * version of git being used. If git-rev-parse does not
6978                  * understand --is-inside-work-tree it will simply echo
6979                  * the option else either "true" or "false" is printed.
6980                  * Default to true for the unknown case. */
6981                 opt_is_inside_work_tree = strcmp(name, "false") ? TRUE : FALSE;
6982
6983         } else if (*name == '.') {
6984                 string_ncopy(opt_cdup, name, namelen);
6985
6986         } else {
6987                 string_ncopy(opt_prefix, name, namelen);
6988         }
6989
6990         return OK;
6991 }
6992
6993 static int
6994 load_repo_info(void)
6995 {
6996         const char *rev_parse_argv[] = {
6997                 "git", "rev-parse", "--git-dir", "--is-inside-work-tree",
6998                         "--show-cdup", "--show-prefix", NULL
6999         };
7000
7001         return run_io_load(rev_parse_argv, "=", read_repo_info);
7002 }
7003
7004
7005 /*
7006  * Main
7007  */
7008
7009 static const char usage[] =
7010 "tig " TIG_VERSION " (" __DATE__ ")\n"
7011 "\n"
7012 "Usage: tig        [options] [revs] [--] [paths]\n"
7013 "   or: tig show   [options] [revs] [--] [paths]\n"
7014 "   or: tig blame  [rev] path\n"
7015 "   or: tig status\n"
7016 "   or: tig <      [git command output]\n"
7017 "\n"
7018 "Options:\n"
7019 "  -v, --version   Show version and exit\n"
7020 "  -h, --help      Show help message and exit";
7021
7022 static void __NORETURN
7023 quit(int sig)
7024 {
7025         /* XXX: Restore tty modes and let the OS cleanup the rest! */
7026         if (cursed)
7027                 endwin();
7028         exit(0);
7029 }
7030
7031 static void __NORETURN
7032 die(const char *err, ...)
7033 {
7034         va_list args;
7035
7036         endwin();
7037
7038         va_start(args, err);
7039         fputs("tig: ", stderr);
7040         vfprintf(stderr, err, args);
7041         fputs("\n", stderr);
7042         va_end(args);
7043
7044         exit(1);
7045 }
7046
7047 static void
7048 warn(const char *msg, ...)
7049 {
7050         va_list args;
7051
7052         va_start(args, msg);
7053         fputs("tig warning: ", stderr);
7054         vfprintf(stderr, msg, args);
7055         fputs("\n", stderr);
7056         va_end(args);
7057 }
7058
7059 static enum request
7060 parse_options(int argc, const char *argv[])
7061 {
7062         enum request request = REQ_VIEW_MAIN;
7063         const char *subcommand;
7064         bool seen_dashdash = FALSE;
7065         /* XXX: This is vulnerable to the user overriding options
7066          * required for the main view parser. */
7067         const char *custom_argv[SIZEOF_ARG] = {
7068                 "git", "log", "--no-color", "--pretty=raw", "--parents",
7069                         "--topo-order", NULL
7070         };
7071         int i, j = 6;
7072
7073         if (!isatty(STDIN_FILENO)) {
7074                 io_open(&VIEW(REQ_VIEW_PAGER)->io, "");
7075                 return REQ_VIEW_PAGER;
7076         }
7077
7078         if (argc <= 1)
7079                 return REQ_NONE;
7080
7081         subcommand = argv[1];
7082         if (!strcmp(subcommand, "status")) {
7083                 if (argc > 2)
7084                         warn("ignoring arguments after `%s'", subcommand);
7085                 return REQ_VIEW_STATUS;
7086
7087         } else if (!strcmp(subcommand, "blame")) {
7088                 if (argc <= 2 || argc > 4)
7089                         die("invalid number of options to blame\n\n%s", usage);
7090
7091                 i = 2;
7092                 if (argc == 4) {
7093                         string_ncopy(opt_ref, argv[i], strlen(argv[i]));
7094                         i++;
7095                 }
7096
7097                 string_ncopy(opt_file, argv[i], strlen(argv[i]));
7098                 return REQ_VIEW_BLAME;
7099
7100         } else if (!strcmp(subcommand, "show")) {
7101                 request = REQ_VIEW_DIFF;
7102
7103         } else {
7104                 subcommand = NULL;
7105         }
7106
7107         if (subcommand) {
7108                 custom_argv[1] = subcommand;
7109                 j = 2;
7110         }
7111
7112         for (i = 1 + !!subcommand; i < argc; i++) {
7113                 const char *opt = argv[i];
7114
7115                 if (seen_dashdash || !strcmp(opt, "--")) {
7116                         seen_dashdash = TRUE;
7117
7118                 } else if (!strcmp(opt, "-v") || !strcmp(opt, "--version")) {
7119                         printf("tig version %s\n", TIG_VERSION);
7120                         quit(0);
7121
7122                 } else if (!strcmp(opt, "-h") || !strcmp(opt, "--help")) {
7123                         printf("%s\n", usage);
7124                         quit(0);
7125                 }
7126
7127                 custom_argv[j++] = opt;
7128                 if (j >= ARRAY_SIZE(custom_argv))
7129                         die("command too long");
7130         }
7131
7132         if (!prepare_update(VIEW(request), custom_argv, NULL, FORMAT_NONE))                                                                        
7133                 die("Failed to format arguments"); 
7134
7135         return request;
7136 }
7137
7138 int
7139 main(int argc, const char *argv[])
7140 {
7141         enum request request = parse_options(argc, argv);
7142         struct view *view;
7143         size_t i;
7144
7145         signal(SIGINT, quit);
7146         signal(SIGPIPE, SIG_IGN);
7147
7148         if (setlocale(LC_ALL, "")) {
7149                 char *codeset = nl_langinfo(CODESET);
7150
7151                 string_ncopy(opt_codeset, codeset, strlen(codeset));
7152         }
7153
7154         if (load_repo_info() == ERR)
7155                 die("Failed to load repo info.");
7156
7157         if (load_options() == ERR)
7158                 die("Failed to load user config.");
7159
7160         if (load_git_config() == ERR)
7161                 die("Failed to load repo config.");
7162
7163         /* Require a git repository unless when running in pager mode. */
7164         if (!opt_git_dir[0] && request != REQ_VIEW_PAGER)
7165                 die("Not a git repository");
7166
7167         if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
7168                 opt_utf8 = FALSE;
7169
7170         if (*opt_codeset && strcmp(opt_codeset, opt_encoding)) {
7171                 opt_iconv = iconv_open(opt_codeset, opt_encoding);
7172                 if (opt_iconv == ICONV_NONE)
7173                         die("Failed to initialize character set conversion");
7174         }
7175
7176         if (load_refs() == ERR)
7177                 die("Failed to load refs.");
7178
7179         foreach_view (view, i)
7180                 argv_from_env(view->ops->argv, view->cmd_env);
7181
7182         init_display();
7183
7184         if (request != REQ_NONE)
7185                 open_view(NULL, request, OPEN_PREPARED);
7186         request = request == REQ_NONE ? REQ_VIEW_MAIN : REQ_NONE;
7187
7188         while (view_driver(display[current_view], request)) {
7189                 int key = get_input(0);
7190
7191                 view = display[current_view];
7192                 request = get_keybinding(view->keymap, key);
7193
7194                 /* Some low-level request handling. This keeps access to
7195                  * status_win restricted. */
7196                 switch (request) {
7197                 case REQ_PROMPT:
7198                 {
7199                         char *cmd = read_prompt(":");
7200
7201                         if (cmd && isdigit(*cmd)) {
7202                                 int lineno = view->lineno + 1;
7203
7204                                 if (parse_int(&lineno, cmd, 1, view->lines + 1) == OK) {
7205                                         select_view_line(view, lineno - 1);
7206                                         report("");
7207                                 } else {
7208                                         report("Unable to parse '%s' as a line number", cmd);
7209                                 }
7210
7211                         } else if (cmd) {
7212                                 struct view *next = VIEW(REQ_VIEW_PAGER);
7213                                 const char *argv[SIZEOF_ARG] = { "git" };
7214                                 int argc = 1;
7215
7216                                 /* When running random commands, initially show the
7217                                  * command in the title. However, it maybe later be
7218                                  * overwritten if a commit line is selected. */
7219                                 string_ncopy(next->ref, cmd, strlen(cmd));
7220
7221                                 if (!argv_from_string(argv, &argc, cmd)) {
7222                                         report("Too many arguments");
7223                                 } else if (!prepare_update(next, argv, NULL, FORMAT_DASH)) {
7224                                         report("Failed to format command");
7225                                 } else {
7226                                         open_view(view, REQ_VIEW_PAGER, OPEN_PREPARED);
7227                                 }
7228                         }
7229
7230                         request = REQ_NONE;
7231                         break;
7232                 }
7233                 case REQ_SEARCH:
7234                 case REQ_SEARCH_BACK:
7235                 {
7236                         const char *prompt = request == REQ_SEARCH ? "/" : "?";
7237                         char *search = read_prompt(prompt);
7238
7239                         if (search)
7240                                 string_ncopy(opt_search, search, strlen(search));
7241                         else if (*opt_search)
7242                                 request = request == REQ_SEARCH ?
7243                                         REQ_FIND_NEXT :
7244                                         REQ_FIND_PREV;
7245                         else
7246                                 request = REQ_NONE;
7247                         break;
7248                 }
7249                 default:
7250                         break;
7251                 }
7252         }
7253
7254         quit(0);
7255
7256         return 0;
7257 }