7 * tig - text-mode interface for git
13 * tig [options] log [git log options]
14 * tig [options] diff [git diff options]
15 * tig [options] < [git log or git diff output]
19 * Browse changes in a git repository.
27 #define VERSION "tig-0.1"
43 static void die(const char *err
, ...);
44 static void report(const char *msg
, ...);
46 /* Some ascii-shorthands that fit into the ncurses namespace. */
52 /* REQ_* values from form.h is used as a basis for user actions. */
54 /* Offset new values relative to MAX_COMMAND from form.h. */
55 REQ_OFFSET
= MAX_COMMAND
,
57 /* XXX: Keep the view request first and in sync with views[]. */
72 /* The request are used for adressing the view array. */
73 #define VIEW_OFFSET(r) ((r) - REQ_OFFSET - 1)
75 /* Size of symbolic or SHA1 ID. */
76 #define SIZEOF_REF 256
78 /* This color name can be used to refer to the default term colors. */
79 #define COLOR_DEFAULT (-1)
81 /* The format and size of the date column in the main view. */
82 #define DATE_FORMAT "%Y-%m-%d %H:%M"
83 #define DATE_COLS (STRING_SIZE("2006-04-29 14:21") + 1)
85 /* The interval between line numbers. */
86 #define NUMBER_INTERVAL 5
88 #define ABS(x) ((x) >= 0 ? (x) : -(x))
89 #define MIN(x, y) ((x) < (y) ? (x) : (y))
91 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
92 #define STRING_SIZE(x) (sizeof(x) - 1)
103 string_ncopy(char *dst
, char *src
, int dstlen
)
105 strncpy(dst
, src
, dstlen
- 1);
109 /* Shorthand for safely copying into a fixed buffer. */
110 #define string_copy(dst, src) \
111 string_ncopy(dst, src, sizeof(dst))
119 static int opt_line_number
;
120 static int opt_request
= REQ_MAIN
;
122 char head_id
[SIZEOF_REF
] = "HEAD";
123 char commit_id
[SIZEOF_REF
] = "HEAD";
125 /* Returns the index of log or diff command or -1 to exit. */
127 parse_options(int argc
, char *argv
[])
131 for (i
= 1; i
< argc
; i
++) {
138 if (!strcmp(opt
, "log")) {
139 opt_request
= REQ_LOG
;
146 } else if (!strcmp(opt
, "diff")) {
147 opt_request
= REQ_DIFF
;
152 * Start up in log view.
154 } else if (!strcmp(opt
, "-l")) {
155 opt_request
= REQ_LOG
;
159 * Start up in diff view.
161 } else if (!strcmp(opt
, "-d")) {
162 opt_request
= REQ_DIFF
;
165 * -n, --line-number::
166 * Prefix line numbers in log and diff view.
168 } else if (!strcmp(opt
, "-n") ||
169 !strcmp(opt
, "--line-number")) {
174 * Show version and exit.
176 } else if (!strcmp(opt
, "-v") ||
177 !strcmp(opt
, "--version")) {
178 printf("tig version %s\n", VERSION
);
183 * Commit reference, symbolic or raw SHA1 ID.
185 } else if (opt
[0] && opt
[0] != '-') {
186 string_copy(head_id
, opt
);
187 string_copy(commit_id
, opt
);
190 die("unknown command '%s'", opt
);
199 * Line-oriented content detection.
244 #define LINE(type, line, fg, bg, attr) \
245 { LINE_##type, (line), STRING_SIZE(line), (fg), (bg), (attr) }
247 static struct line_info line_info
[] = {
249 LINE(DIFF
, "diff --git ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
250 LINE(INDEX
, "index ", COLOR_BLUE
, COLOR_DEFAULT
, 0),
251 LINE(DIFF_CHUNK
, "@@", COLOR_MAGENTA
, COLOR_DEFAULT
, 0),
252 LINE(DIFF_ADD
, "+", COLOR_GREEN
, COLOR_DEFAULT
, 0),
253 LINE(DIFF_DEL
, "-", COLOR_RED
, COLOR_DEFAULT
, 0),
254 LINE(DIFF_OLDMODE
, "old mode ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
255 LINE(DIFF_NEWMODE
, "new mode ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
256 LINE(DIFF_COPY
, "copy ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
257 LINE(DIFF_RENAME
, "rename ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
258 LINE(DIFF_SIM
, "similarity ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
259 LINE(DIFF_DISSIM
, "dissimilarity ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
261 /* Pretty print commit header */
262 LINE(AUTHOR
, "Author: ", COLOR_CYAN
, COLOR_DEFAULT
, 0),
263 LINE(MERGE
, "Merge: ", COLOR_BLUE
, COLOR_DEFAULT
, 0),
264 LINE(DATE
, "Date: ", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
266 /* Raw commit header */
267 LINE(COMMIT
, "commit ", COLOR_GREEN
, COLOR_DEFAULT
, 0),
268 LINE(PARENT
, "parent ", COLOR_BLUE
, COLOR_DEFAULT
, 0),
269 LINE(TREE
, "tree ", COLOR_BLUE
, COLOR_DEFAULT
, 0),
270 LINE(AUTHOR_IDENT
, "author ", COLOR_CYAN
, COLOR_DEFAULT
, 0),
271 LINE(COMMITTER
, "committer ", COLOR_MAGENTA
, COLOR_DEFAULT
, 0),
274 LINE(DIFF_TREE
, "diff-tree ", COLOR_BLUE
, COLOR_DEFAULT
, 0),
275 LINE(SIGNOFF
, " Signed-off-by", COLOR_YELLOW
, COLOR_DEFAULT
, 0),
278 LINE(DEFAULT
, "", COLOR_DEFAULT
, COLOR_DEFAULT
, A_NORMAL
),
279 LINE(CURSOR
, "", COLOR_WHITE
, COLOR_GREEN
, A_BOLD
),
280 LINE(STATUS
, "", COLOR_GREEN
, COLOR_DEFAULT
, 0),
281 LINE(TITLE
, "", COLOR_YELLOW
, COLOR_BLUE
, A_BOLD
),
282 LINE(MAIN_DATE
, "", COLOR_BLUE
, COLOR_DEFAULT
, 0),
283 LINE(MAIN_AUTHOR
, "", COLOR_GREEN
, COLOR_DEFAULT
, 0),
284 LINE(MAIN_COMMIT
, "", COLOR_DEFAULT
, COLOR_DEFAULT
, 0),
285 LINE(MAIN_DELIM
, "", COLOR_MAGENTA
, COLOR_DEFAULT
, 0),
288 static struct line_info
*
289 get_line_info(char *line
)
291 int linelen
= strlen(line
);
294 for (i
= 0; i
< ARRAY_SIZE(line_info
); i
++) {
295 if (linelen
< line_info
[i
].linelen
296 || strncasecmp(line_info
[i
].line
, line
, line_info
[i
].linelen
))
299 return &line_info
[i
];
305 static enum line_type
306 get_line_type(char *line
)
308 struct line_info
*info
= get_line_info(line
);
310 return info ? info
->type
: LINE_DEFAULT
;
314 get_line_attr(enum line_type type
)
318 for (i
= 0; i
< ARRAY_SIZE(line_info
); i
++)
319 if (line_info
[i
].type
== type
)
320 return COLOR_PAIR(line_info
[i
].type
) | line_info
[i
].attr
;
328 int default_bg
= COLOR_BLACK
;
329 int default_fg
= COLOR_WHITE
;
334 if (use_default_colors() != ERR
) {
339 for (i
= 0; i
< ARRAY_SIZE(line_info
); i
++) {
340 struct line_info
*info
= &line_info
[i
];
341 int bg
= info
->bg
== COLOR_DEFAULT ? default_bg
: info
->bg
;
342 int fg
= info
->fg
== COLOR_DEFAULT ? default_fg
: info
->fg
;
344 init_pair(info
->type
, fg
, bg
);
362 * stop all background loading
373 #define HELP "(d)iff, (l)og, (m)ain, (q)uit, (v)ersion, (h)elp"
380 struct keymap keymap
[] = {
381 /* Cursor navigation */
382 { KEY_UP
, REQ_PREV_LINE
},
383 { 'k', REQ_PREV_LINE
},
384 { KEY_DOWN
, REQ_NEXT_LINE
},
385 { 'j', REQ_NEXT_LINE
},
386 { KEY_HOME
, REQ_FIRST_LINE
},
387 { KEY_END
, REQ_LAST_LINE
},
388 { KEY_NPAGE
, REQ_NEXT_PAGE
},
389 { KEY_PPAGE
, REQ_PREV_PAGE
},
392 { KEY_IC
, REQ_SCR_BLINE
}, /* scroll field backward a line */
393 { KEY_DC
, REQ_SCR_FLINE
}, /* scroll field forward a line */
394 { 's', REQ_SCR_FPAGE
}, /* scroll field forward a page */
395 { 'w', REQ_SCR_BPAGE
}, /* scroll field backward a page */
402 /* Line number toggling */
403 { 'n', REQ_LINE_NUMBER
},
404 /* No input from wgetch() with nodelay() enabled. */
408 { KEY_ESC
, REQ_QUIT
},
411 { 'v', REQ_VERSION
},
416 get_request(int request
)
420 for (i
= 0; i
< ARRAY_SIZE(keymap
); i
++)
421 if (keymap
[i
].alias
== request
)
422 return keymap
[i
].request
;
439 int (*read
)(struct view
*, char *);
440 int (*draw
)(struct view
*, unsigned int);
441 size_t objsize
; /* Size of objects in the line index */
447 unsigned long offset
; /* Offset of the window top */
448 unsigned long lineno
; /* Current line number */
451 unsigned long lines
; /* Total number of lines */
452 void **line
; /* Line index */
458 static int pager_draw(struct view
*view
, unsigned int lineno
);
459 static int pager_read(struct view
*view
, char *line
);
461 static int main_draw(struct view
*view
, unsigned int lineno
);
462 static int main_read(struct view
*view
, char *line
);
465 "git log --stat -n1 %s ; echo; " \
466 "git diff --find-copies-harder -B -C %s^ %s"
469 "git log --stat -n100 %s"
472 "git log --stat --pretty=raw %s"
474 /* The status window is used for polling keystrokes. */
475 static WINDOW
*status_win
;
476 static WINDOW
*title_win
;
478 /* The number of loading views. Controls when nodelay should be in effect when
479 * polling user input. */
480 static unsigned int nloading
;
482 static struct view views
[] = {
483 { "diff", DIFF_CMD
, commit_id
, pager_read
, pager_draw
, sizeof(char) },
484 { "log", LOG_CMD
, head_id
, pager_read
, pager_draw
, sizeof(char) },
485 { "main", MAIN_CMD
, head_id
, main_read
, main_draw
, sizeof(struct commit
) },
488 /* The display array of active views and the index of the current view. */
489 static struct view
*display
[ARRAY_SIZE(views
)];
490 static unsigned int current_view
;
492 #define foreach_view(view, i) \
493 for (i = 0; i < sizeof(display) && (view = display[i]); i++)
497 redraw_view_from(struct view
*view
, int lineno
)
499 assert(0 <= lineno
&& lineno
< view
->height
);
501 for (; lineno
< view
->height
; lineno
++) {
502 if (!view
->draw(view
, lineno
))
506 redrawwin(view
->win
);
511 redraw_view(struct view
*view
)
514 redraw_view_from(view
, 0);
518 resize_view(struct view
*view
)
522 getmaxyx(stdscr
, lines
, cols
);
525 mvwin(view
->win
, 0, 0);
526 wresize(view
->win
, lines
- 2, cols
);
529 view
->win
= newwin(lines
- 2, 0, 0, 0);
531 report("failed to create %s view", view
->name
);
534 scrollok(view
->win
, TRUE
);
537 getmaxyx(view
->win
, view
->height
, view
->width
);
540 /* FIXME: Fix percentage. */
542 report_position(struct view
*view
, int all
)
544 report(all ?
"line %d of %d (%d%%)"
548 view
->lines ?
(view
->lineno
+ 1) * 100 / view
->lines
: 0);
553 move_view(struct view
*view
, int lines
)
555 /* The rendering expects the new offset. */
556 view
->offset
+= lines
;
558 assert(0 <= view
->offset
&& view
->offset
< view
->lines
);
561 /* Redraw the whole screen if scrolling is pointless. */
562 if (view
->height
< ABS(lines
)) {
566 int line
= lines
> 0 ? view
->height
- lines
: 0;
567 int end
= line
+ ABS(lines
);
569 wscrl(view
->win
, lines
);
571 for (; line
< end
; line
++) {
572 if (!view
->draw(view
, line
))
577 /* Move current line into the view. */
578 if (view
->lineno
< view
->offset
) {
579 view
->lineno
= view
->offset
;
582 } else if (view
->lineno
>= view
->offset
+ view
->height
) {
583 view
->lineno
= view
->offset
+ view
->height
- 1;
584 view
->draw(view
, view
->lineno
- view
->offset
);
587 assert(view
->offset
<= view
->lineno
&& view
->lineno
< view
->lines
);
589 redrawwin(view
->win
);
592 report_position(view
, lines
);
596 scroll_view(struct view
*view
, int request
)
602 lines
= view
->height
;
604 if (view
->offset
+ lines
> view
->lines
)
605 lines
= view
->lines
- view
->offset
;
607 if (lines
== 0 || view
->offset
+ view
->height
>= view
->lines
) {
608 report("already at last line");
614 lines
= view
->height
;
616 if (lines
> view
->offset
)
617 lines
= view
->offset
;
620 report("already at first line");
628 move_view(view
, lines
);
632 navigate_view(struct view
*view
, int request
)
638 steps
= -view
->lineno
;
642 steps
= view
->lines
- view
->lineno
- 1;
646 steps
= view
->height
> view
->lineno
647 ?
-view
->lineno
: -view
->height
;
651 steps
= view
->lineno
+ view
->height
>= view
->lines
652 ? view
->lines
- view
->lineno
- 1 : view
->height
;
664 if (steps
<= 0 && view
->lineno
== 0) {
665 report("already at first line");
668 } else if (steps
>= 0 && view
->lineno
+ 1 == view
->lines
) {
669 report("already at last line");
673 /* Move the current line */
674 view
->lineno
+= steps
;
675 assert(0 <= view
->lineno
&& view
->lineno
< view
->lines
);
677 /* Repaint the old "current" line if we be scrolling */
678 if (ABS(steps
) < view
->height
)
679 view
->draw(view
, view
->lineno
- steps
- view
->offset
);
681 /* Check whether the view needs to be scrolled */
682 if (view
->lineno
< view
->offset
||
683 view
->lineno
>= view
->offset
+ view
->height
) {
684 if (steps
< 0 && -steps
> view
->offset
) {
685 steps
= -view
->offset
;
687 } else if (steps
> 0) {
688 if (view
->lineno
== view
->lines
- 1 &&
689 view
->lines
> view
->height
) {
690 steps
= view
->lines
- view
->offset
- 1;
691 if (steps
>= view
->height
)
692 steps
-= view
->height
- 1;
696 move_view(view
, steps
);
700 /* Draw the current line */
701 view
->draw(view
, view
->lineno
- view
->offset
);
703 redrawwin(view
->win
);
706 report_position(view
, view
->height
);
712 begin_update(struct view
*view
)
719 if (snprintf(buf
, sizeof(buf
), view
->cmd
, id
, id
, id
) < sizeof(buf
))
720 view
->pipe
= popen(buf
, "r");
726 nodelay(status_win
, TRUE
);
729 display
[current_view
] = view
;
739 end_update(struct view
*view
)
741 wattrset(view
->win
, A_NORMAL
);
746 nodelay(status_win
, FALSE
);
750 update_view(struct view
*view
)
755 /* The number of lines to read. If too low it will cause too much
756 * redrawing (and possible flickering), if too high responsiveness
758 int lines
= view
->height
;
759 int redraw_from
= -1;
764 /* Only redraw if lines are visible. */
765 if (view
->offset
+ view
->height
>= view
->lines
)
766 redraw_from
= view
->lines
- view
->offset
;
768 tmp
= realloc(view
->line
, sizeof(*view
->line
) * (view
->lines
+ lines
));
774 while ((line
= fgets(buffer
, sizeof(buffer
), view
->pipe
))) {
777 linelen
= strlen(line
);
779 line
[linelen
- 1] = 0;
781 if (!view
->read(view
, line
))
788 if (redraw_from
>= 0) {
789 /* If this is an incremental update, redraw the previous line
790 * since for commits some members could have changed. */
794 /* Incrementally draw avoids flickering. */
795 redraw_view_from(view
, redraw_from
);
798 if (ferror(view
->pipe
)) {
799 report("failed to read %s: %s", view
->cmd
, strerror(errno
));
802 } else if (feof(view
->pipe
)) {
803 report_position(view
, 0);
810 report("allocation failure");
819 switch_view(struct view
*prev
, int request
)
821 struct view
*view
= &views
[VIEW_OFFSET(request
)];
822 struct view
*displayed
;
826 foreach_view (displayed
, i
) ;
829 report("already in %s view", view
->name
);
831 report("FIXME: Maximize");
836 foreach_view (displayed
, i
) {
837 if (view
== displayed
) {
839 report("new current view");
851 for (i
= 0; i
< view
->lines
; i
++)
859 if (prev
&& prev
->pipe
)
862 if (begin_update(view
)) {
866 /* Clear the old view and let the incremental updating
867 * refill the screen. */
869 report("loading...");
877 /* Process a keystroke */
879 view_driver(struct view
*view
, int key
)
881 int request
= get_request(key
);
892 navigate_view(view
, request
);
900 scroll_view(view
, request
);
906 view
= switch_view(view
, request
);
909 case REQ_LINE_NUMBER
:
910 opt_line_number
= !opt_line_number
;
919 foreach_view (view
, i
) {
922 scroll_view(view
, 0);
928 report("version %s", VERSION
);
952 pager_draw(struct view
*view
, unsigned int lineno
)
959 if (view
->offset
+ lineno
>= view
->lines
)
962 line
= view
->line
[view
->offset
+ lineno
];
963 type
= get_line_type(line
);
965 if (view
->offset
+ lineno
== view
->lineno
) {
966 if (type
== LINE_COMMIT
)
967 string_copy(commit_id
, line
+ 7);
971 attr
= get_line_attr(type
);
972 wattrset(view
->win
, attr
);
974 linelen
= strlen(line
);
975 linelen
= MIN(linelen
, view
->width
);
977 if (opt_line_number
) {
978 unsigned int real_lineno
= view
->offset
+ lineno
+ 1;
981 if (real_lineno
== 1 || (real_lineno
% NUMBER_INTERVAL
) == 0)
982 mvwprintw(view
->win
, lineno
, 0, "%4d: ", real_lineno
);
984 mvwaddstr(view
->win
, lineno
, 0, " : ");
988 waddnstr(view
->win
, " ", 8 - (col
% 8));
989 col
+= 8 - (col
% 8);
993 char *tab
= strchr(line
, '\t');
996 waddnstr(view
->win
, line
, tab
- line
);
998 waddstr(view
->win
, line
);
1003 waddstr(view
->win
, line
);
1006 /* No empty lines makes cursor drawing and clearing implicit. */
1008 line
= " ", linelen
= 1;
1009 mvwaddnstr(view
->win
, lineno
, 0, line
, linelen
);
1016 pager_read(struct view
*view
, char *line
)
1018 view
->line
[view
->lines
] = strdup(line
);
1019 if (!view
->line
[view
->lines
])
1027 main_draw(struct view
*view
, unsigned int lineno
)
1030 struct commit
*commit
;
1031 enum line_type type
;
1035 if (view
->offset
+ lineno
>= view
->lines
)
1038 commit
= view
->line
[view
->offset
+ lineno
];
1039 if (!*commit
->author
)
1042 if (view
->offset
+ lineno
== view
->lineno
) {
1043 string_copy(commit_id
, commit
->id
);
1046 type
= LINE_MAIN_COMMIT
;
1049 wmove(view
->win
, lineno
, cols
);
1050 wattrset(view
->win
, get_line_attr(LINE_MAIN_DATE
));
1052 timelen
= strftime(buf
, sizeof(buf
), DATE_FORMAT
, &commit
->time
);
1053 waddnstr(view
->win
, buf
, timelen
);
1054 waddstr(view
->win
, " ");
1057 wmove(view
->win
, lineno
, cols
);
1058 wattrset(view
->win
, get_line_attr(LINE_MAIN_AUTHOR
));
1060 if (strlen(commit
->author
) > 19) {
1061 waddnstr(view
->win
, commit
->author
, 18);
1062 wattrset(view
->win
, get_line_attr(LINE_MAIN_DELIM
));
1063 waddch(view
->win
, '~');
1065 waddstr(view
->win
, commit
->author
);
1069 wattrset(view
->win
, A_NORMAL
);
1070 mvwaddch(view
->win
, lineno
, cols
, ACS_LTEE
);
1071 wattrset(view
->win
, get_line_attr(type
));
1072 mvwaddstr(view
->win
, lineno
, cols
+ 2, commit
->title
);
1073 wattrset(view
->win
, A_NORMAL
);
1078 /* Reads git log --pretty=raw output and parses it into the commit struct. */
1080 main_read(struct view
*view
, char *line
)
1082 enum line_type type
= get_line_type(line
);
1083 struct commit
*commit
;
1087 commit
= calloc(1, sizeof(struct commit
));
1091 line
+= STRING_SIZE("commit ");
1093 view
->line
[view
->lines
++] = commit
;
1094 string_copy(commit
->id
, line
);
1097 case LINE_AUTHOR_IDENT
:
1099 char *ident
= line
+ STRING_SIZE("author ");
1100 char *end
= strchr(ident
, '<');
1103 for (; end
> ident
&& isspace(end
[-1]); end
--) ;
1107 commit
= view
->line
[view
->lines
- 1];
1108 string_copy(commit
->author
, ident
);
1110 /* Parse epoch and timezone */
1112 char *secs
= strchr(end
+ 1, '>');
1116 if (!secs
|| secs
[1] != ' ')
1120 time
= (time_t) atol(secs
);
1121 zone
= strchr(secs
, ' ');
1122 if (zone
&& strlen(zone
) == STRING_SIZE(" +0700")) {
1126 tz
= ('0' - zone
[1]) * 60 * 60 * 10;
1127 tz
+= ('0' - zone
[2]) * 60 * 60;
1128 tz
+= ('0' - zone
[3]) * 60;
1129 tz
+= ('0' - zone
[4]) * 60;
1136 gmtime_r(&time
, &commit
->time
);
1141 /* Fill in the commit title */
1142 commit
= view
->line
[view
->lines
- 1];
1143 if (commit
->title
[0] ||
1144 strncmp(line
, " ", 4) ||
1148 string_copy(commit
->title
, line
+ 4);
1168 /* FIXME: Shutdown gracefully. */
1173 static void die(const char *err
, ...)
1179 va_start(args
, err
);
1180 fputs("tig: ", stderr
);
1181 vfprintf(stderr
, err
, args
);
1182 fputs("\n", stderr
);
1189 report(const char *msg
, ...)
1194 wmove(title_win
, 0, 0);
1195 wprintw(title_win
, "commit %s", commit_id
);
1196 wrefresh(title_win
);
1198 va_start(args
, msg
);
1201 wmove(status_win
, 0, 0);
1204 if (display
[current_view
])
1205 wprintw(status_win
, "%s %4s: ", commit_id
, display
[current_view
]->name
);
1207 vwprintw(status_win
, msg
, args
);
1208 wrefresh(status_win
);
1214 main(int argc
, char *argv
[])
1220 signal(SIGINT
, quit
);
1222 git_cmd
= parse_options(argc
, argv
);
1225 if (git_cmd
< argc
) {
1229 request
= opt_request
;
1231 initscr(); /* initialize the curses library */
1232 nonl(); /* tell curses not to do NL->CR/NL on output */
1233 cbreak(); /* take input chars one at a time, no wait for \n */
1234 noecho(); /* don't echo input */
1235 leaveok(stdscr
, TRUE
);
1241 getmaxyx(stdscr
, y
, x
);
1242 status_win
= newwin(1, 0, y
- 1, 0);
1244 die("Failed to create status window");
1246 title_win
= newwin(1, 0, y
- 2, 0);
1248 die("Failed to create title window");
1250 /* Enable keyboard mapping */
1251 keypad(status_win
, TRUE
);
1252 wbkgdset(status_win
, get_line_attr(LINE_STATUS
));
1253 wbkgdset(title_win
, get_line_attr(LINE_TITLE
));
1255 while (view_driver(display
[current_view
], request
)) {
1259 foreach_view (view
, i
) {
1265 /* Refresh, accept single keystroke of input */
1266 request
= wgetch(status_win
);
1267 if (request
== KEY_RESIZE
) {
1270 getmaxyx(stdscr
, lines
, cols
);
1272 mvwin(status_win
, lines
- 1, 0);
1273 wresize(status_win
, 1, cols
- 1);
1275 mvwin(title_win
, lines
- 2, 0);
1276 wresize(title_win
, 1, cols
- 1);
1288 * Known bugs and problems:
1290 * Redrawing of the main view while loading::
1291 * If only part of a commit has been parsed not all fields will be visible
1292 * or even redrawn when the whole commit have loaded. This can be
1293 * triggered when continuously moving to the last line. Use 'r' to redraw
1298 * Features that should be explored.
1300 * - Dynamic scaling of line number indentation.
1302 * - Proper command line handling; ability to take the command that should be
1307 * - Internal command line (exmode-inspired) which allows to specify what git
1308 * log or git diff command to run. Example:
1312 * - Proper resizing support. I am yet to figure out whether catching SIGWINCH
1313 * is preferred over using ncurses' built-in support for resizing.
1319 * Copyright (c) Jonas Fonseca, 2006
1321 * This program is free software; you can redistribute it and/or modify
1322 * it under the terms of the GNU General Public License as published by
1323 * the Free Software Foundation; either version 2 of the License, or
1324 * (at your option) any later version.
1329 * link:http://www.kernel.org/pub/software/scm/git/docs/[git(7)],
1330 * link:http://www.kernel.org/pub/software/scm/cogito/docs/[cogito(7)]
1331 * gitk(1): git repository browser written using tcl/tk,
1332 * gitview(1): git repository browser written using python/gtk.