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