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