summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 2e8488b)
raw | patch | inline | side by side (parent: 2e8488b)
author | Jonas Fonseca <fonseca@diku.dk> | |
Tue, 2 May 2006 20:36:50 +0000 (22:36 +0200) | ||
committer | Jonas Fonseca <fonseca@antimatter.localdomain> | |
Tue, 2 May 2006 20:36:50 +0000 (22:36 +0200) |
tig.c | patch | blob | history |
index 4c2d56dd790b5be62ba3228d60f4660241d649a4..7ba1a718e031021fa4cef1fd4854a8f3089c023a 100644 (file)
--- a/tig.c
+++ b/tig.c
static void die(const char *err, ...);
static void report(const char *msg, ...);
-static void update_title(void);
#define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */
#define SIZEOF_CMD 1024 /* Size of command buffer. */
#define DATE_FORMAT "%Y-%m-%d %H:%M"
#define DATE_COLS (STRING_SIZE("2006-04-29 14:21 "))
-/* The interval between line numbers. */
+/* The default interval between line numbers. */
#define NUMBER_INTERVAL 1
+#define SCALE_SPLIT_VIEW(height) ((height) * 2 / 3)
+
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define STRING_SIZE(x) (sizeof(x) - 1)
/* Some ascii-shorthands that fit into the ncurses namespace. */
-#define KEY_TAB 9
+#define KEY_TAB '\t'
+#define KEY_RETURN '\r'
#define KEY_ESC 27
-/* User requests. */
+/* User action requests. */
enum request {
+ /* Offset all requests to avoid conflicts with ncurses getch values. */
+ REQ_OFFSET = KEY_MAX + 1,
+
/* XXX: Keep the view request first and in sync with views[]. */
REQ_VIEW_MAIN,
REQ_VIEW_DIFF,
REQ_QUIT,
REQ_SHOW_VERSION,
+ REQ_SHOW_COMMIT,
REQ_STOP_LOADING,
REQ_SCREEN_REDRAW,
REQ_SCREEN_UPDATE,
};
struct commit {
- char id[41];
- char title[75];
- char author[75];
- struct tm time;
+ char id[41]; /* SHA1 ID. */
+ char title[75]; /* The first line of the commit message. */
+ char author[75]; /* The author of the commit. */
+ struct tm time; /* Date from the author ident. */
};
**/
if (!strcmp(opt, "log") ||
!strcmp(opt, "diff")) {
- opt_request = opt[0] = 'l'
+ opt_request = opt[0] == 'l'
? REQ_VIEW_LOG : REQ_VIEW_DIFF;
return i;
{ KEY_PPAGE, REQ_MOVE_PAGE_UP },
/* Scrolling */
- { KEY_IC, REQ_SCROLL_LINE_UP }, /* scroll field backward a line */
- { KEY_DC, REQ_SCROLL_LINE_DOWN }, /* scroll field forward a line */
- { 's', REQ_SCROLL_PAGE_DOWN }, /* scroll field forward a page */
- { 'w', REQ_SCROLL_PAGE_UP }, /* scroll field backward a page */
+ { KEY_IC, REQ_SCROLL_LINE_UP },
+ { KEY_DC, REQ_SCROLL_LINE_DOWN },
+ { 'w', REQ_SCROLL_PAGE_UP },
+ { 's', REQ_SCROLL_PAGE_DOWN },
+
+ { KEY_RETURN, REQ_SHOW_COMMIT },
/* View switching */
{ 'm', REQ_VIEW_MAIN },
/*
* Line-oriented content detection.
- */
-
-/* Line type String to match Foreground Background Attr
- * --------- --------------- ---------- ---------- ---- */
+ *
+ * Line type String to match Foreground Background Attributes
+ * --------- --------------- ---------- ---------- ---------- */
#define LINE_INFO \
- /* Diff markup */ \
- LINE(DIFF, "diff --git ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- LINE(INDEX, "index ", COLOR_BLUE, COLOR_DEFAULT, 0), \
- LINE(DIFF_CHUNK, "@@", COLOR_MAGENTA, COLOR_DEFAULT, 0), \
- LINE(DIFF_ADD, "+", COLOR_GREEN, COLOR_DEFAULT, 0), \
- LINE(DIFF_DEL, "-", COLOR_RED, COLOR_DEFAULT, 0), \
- LINE(DIFF_OLDMODE, "old mode ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- LINE(DIFF_NEWMODE, "new mode ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- LINE(DIFF_COPY, "copy ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- LINE(DIFF_RENAME, "rename ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- LINE(DIFF_SIM, "similarity ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- LINE(DIFF_DISSIM, "dissimilarity ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- /* Pretty print commit header */ \
- LINE(AUTHOR, "Author: ", COLOR_CYAN, COLOR_DEFAULT, 0), \
- LINE(MERGE, "Merge: ", COLOR_BLUE, COLOR_DEFAULT, 0), \
- LINE(DATE, "Date: ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- /* Raw commit header */ \
- LINE(COMMIT, "commit ", COLOR_GREEN, COLOR_DEFAULT, 0), \
- LINE(PARENT, "parent ", COLOR_BLUE, COLOR_DEFAULT, 0), \
- LINE(TREE, "tree ", COLOR_BLUE, COLOR_DEFAULT, 0), \
- LINE(AUTHOR_IDENT, "author ", COLOR_CYAN, COLOR_DEFAULT, 0), \
- LINE(COMMITTER, "committer ", COLOR_MAGENTA, COLOR_DEFAULT, 0), \
- /* Misc */ \
- LINE(DIFF_TREE, "diff-tree ", COLOR_BLUE, COLOR_DEFAULT, 0), \
- LINE(SIGNOFF, " Signed-off-by", COLOR_YELLOW, COLOR_DEFAULT, 0), \
- /* UI colors */ \
- LINE(DEFAULT, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \
- LINE(CURSOR, "", COLOR_WHITE, COLOR_GREEN, A_BOLD), \
- LINE(STATUS, "", COLOR_GREEN, COLOR_DEFAULT, 0), \
- LINE(TITLE, "", COLOR_WHITE, COLOR_BLUE, A_BOLD), \
- LINE(MAIN_DATE, "", COLOR_BLUE, COLOR_DEFAULT, 0), \
- LINE(MAIN_AUTHOR, "", COLOR_GREEN, COLOR_DEFAULT, 0), \
- LINE(MAIN_COMMIT, "", COLOR_DEFAULT, COLOR_DEFAULT, 0), \
- LINE(MAIN_DELIM, "", COLOR_MAGENTA, COLOR_DEFAULT, 0),
+/* Diff markup */ \
+LINE(DIFF, "diff --git ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+LINE(INDEX, "index ", COLOR_BLUE, COLOR_DEFAULT, 0), \
+LINE(DIFF_CHUNK, "@@", COLOR_MAGENTA, COLOR_DEFAULT, 0), \
+LINE(DIFF_ADD, "+", COLOR_GREEN, COLOR_DEFAULT, 0), \
+LINE(DIFF_DEL, "-", COLOR_RED, COLOR_DEFAULT, 0), \
+LINE(DIFF_OLDMODE, "old mode ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+LINE(DIFF_NEWMODE, "new mode ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+LINE(DIFF_COPY, "copy ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+LINE(DIFF_RENAME, "rename ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+LINE(DIFF_SIM, "similarity ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+LINE(DIFF_DISSIM, "dissimilarity ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+/* Pretty print commit header */ \
+LINE(AUTHOR, "Author: ", COLOR_CYAN, COLOR_DEFAULT, 0), \
+LINE(MERGE, "Merge: ", COLOR_BLUE, COLOR_DEFAULT, 0), \
+LINE(DATE, "Date: ", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+/* Raw commit header */ \
+LINE(COMMIT, "commit ", COLOR_GREEN, COLOR_DEFAULT, 0), \
+LINE(PARENT, "parent ", COLOR_BLUE, COLOR_DEFAULT, 0), \
+LINE(TREE, "tree ", COLOR_BLUE, COLOR_DEFAULT, 0), \
+LINE(AUTHOR_IDENT, "author ", COLOR_CYAN, COLOR_DEFAULT, 0), \
+LINE(COMMITTER, "committer ", COLOR_MAGENTA, COLOR_DEFAULT, 0), \
+/* Misc */ \
+LINE(DIFF_TREE, "diff-tree ", COLOR_BLUE, COLOR_DEFAULT, 0), \
+LINE(SIGNOFF, " Signed-off-by", COLOR_YELLOW, COLOR_DEFAULT, 0), \
+/* UI colors */ \
+LINE(DEFAULT, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \
+LINE(CURSOR, "", COLOR_WHITE, COLOR_GREEN, A_BOLD), \
+LINE(STATUS, "", COLOR_GREEN, COLOR_DEFAULT, 0), \
+LINE(TITLE, "", COLOR_WHITE, COLOR_BLUE, 0), \
+LINE(MAIN_DATE, "", COLOR_BLUE, COLOR_DEFAULT, 0), \
+LINE(MAIN_AUTHOR, "", COLOR_GREEN, COLOR_DEFAULT, 0), \
+LINE(MAIN_COMMIT, "", COLOR_DEFAULT, COLOR_DEFAULT, 0), \
+LINE(MAIN_DELIM, "", COLOR_MAGENTA, COLOR_DEFAULT, 0),
enum line_type {
#define LINE(type, line, fg, bg, attr) \
};
struct line_info {
- enum line_type type; /* Returned when looking up line type. */
char *line; /* The start of line to match. */
int linelen; /* Size of string to match. */
int fg, bg, attr; /* Color and text attributes for the lines. */
static struct line_info line_info[] = {
#define LINE(type, line, fg, bg, attr) \
- { LINE_##type, (line), STRING_SIZE(line), (fg), (bg), (attr) }
+ { (line), STRING_SIZE(line), (fg), (bg), (attr) }
LINE_INFO
#undef LINE
};
get_line_type(char *line)
{
int linelen = strlen(line);
- int i;
+ enum line_type type;
- for (i = 0; i < ARRAY_SIZE(line_info); i++)
+ for (type = 0; type < ARRAY_SIZE(line_info); type++)
/* Case insensitive search matches Signed-off-by lines better. */
- if (linelen >= line_info[i].linelen &&
- !strncasecmp(line_info[i].line, line, line_info[i].linelen))
- return line_info[i].type;
+ if (linelen >= line_info[type].linelen &&
+ !strncasecmp(line_info[type].line, line, line_info[type].linelen))
+ return type;
return LINE_DEFAULT;
}
{
int default_bg = COLOR_BLACK;
int default_fg = COLOR_WHITE;
- int i;
+ enum line_type type;
start_color();
default_fg = -1;
}
- for (i = 0; i < ARRAY_SIZE(line_info); i++) {
- struct line_info *info = &line_info[i];
+ for (type = 0; type < ARRAY_SIZE(line_info); type++) {
+ struct line_info *info = &line_info[type];
int bg = info->bg == COLOR_DEFAULT ? default_bg : info->bg;
int fg = info->fg == COLOR_DEFAULT ? default_fg : info->fg;
- init_pair(info->type, fg, bg);
+ init_pair(type, fg, bg);
}
}
char cmdbuf[SIZEOF_CMD];
WINDOW *win;
+ WINDOW *title;
int height, width;
/* Navigation */
static int main_draw(struct view *view, unsigned int lineno);
static int main_read(struct view *view, char *line);
+static void update_title(struct view *view);
+
#define DIFF_CMD \
"git log --stat -n1 %s ; echo; " \
"git diff --find-copies-harder -B -C %s^ %s"
/* The status window is used for polling keystrokes. */
static WINDOW *status_win;
-static WINDOW *title_win;
/* The number of loading views. Controls when nodelay should be in effect when
* polling user input. */
{ "help", HELP_CMD, ref_head, pager_read, pager_draw, sizeof(char) },
};
+#define VIEW(req) (&views[(req) - REQ_OFFSET - 1])
+
/* The display array of active views and the index of the current view. */
static struct view *display[ARRAY_SIZE(views)];
static unsigned int current_view;
redraw_view_from(view, 0);
}
-static void
+static struct view *
resize_view(struct view *view)
{
int lines, cols;
view->win = newwin(lines - 2, 0, 0, 0);
if (!view->win) {
report("Failed to create %s view", view->name);
- return;
+ return NULL;
}
scrollok(view->win, TRUE);
+
+ view->title = newwin(1, 0, lines - 2, 0);
+ if (!view->title) {
+ delwin(view->win);
+ view->win = NULL;
+ report("Failed to create title window");
+ return NULL;
+ }
+ wbkgdset(view->title, get_line_attr(LINE_TITLE));
+
}
getmaxyx(view->win, view->height, view->width);
+
+ return view;
}
}
/* CPU hogilicious! */
- update_title();
+ update_title(view);
if (redraw_from >= 0) {
/* If this is an incremental update, redraw the previous line
- * since for commits some members could have changed. */
+ * since for commits some members could have changed when
+ * loading the main view. */
if (redraw_from > 0)
redraw_from--;
} else if (feof(view->pipe)) {
time_t secs = time(NULL) - view->start_time;
- if (view == &views[REQ_VIEW_HELP]){
- report(HELP);
+ if (view == VIEW(REQ_VIEW_HELP)) {
+ report("%s", HELP);
goto end;
}
static struct view *
switch_view(struct view *prev, int request)
{
- struct view *view = &views[request];
+ struct view *view = VIEW(request);
struct view *displayed;
int i;
- if (prev && prev->pipe)
- end_update(prev);
+ if (!view->win && !resize_view(view))
+ return prev;
if (view == prev) {
- foreach_view (displayed, i) ;
+ foreach_view (displayed, i)
+ /* count */ ;
- if (i == 1)
+ if (i == 1) {
report("Already in %s view", view->name);
- else
- report("FIXME: Maximize");
+ return view;
+ }
+ report("FIXME: Maximize");
return view;
} else {
foreach_view (displayed, i) {
if (view == displayed) {
current_view = i;
- report("new current view");
+ /* Blur out the title of the previous view. */
+ update_title(prev);
+ report("Switching to %s view", view->name);
return view;
}
}
- }
- if (!view->win)
- resize_view(view);
+ /* Split to diff view */
+ if (i == 1 &&
+ SCALE_SPLIT_VIEW(prev->height) > 3 &&
+ prev == VIEW(REQ_VIEW_MAIN) &&
+ view == VIEW(REQ_VIEW_DIFF)) {
+ view->height = SCALE_SPLIT_VIEW(prev->height) - 1;
+ prev->height -= view->height + 1;
+
+ wresize(prev->win, prev->height, prev->width);
+ mvwin(prev->title, prev->height, 0);
+
+ wresize(view->win, view->height, view->width);
+ mvwin(view->win, prev->height + 1, 0);
+ mvwin(view->title, prev->height + 1 + view->height, 0);
+ wrefresh(view->win);
+ current_view++;
+ update_title(prev);
+ }
+ }
- /* Reload */
+ /* Continue loading split views in the background. */
+ if (prev && prev->pipe && current_view < 1)
+ end_update(prev);
if (begin_update(view)) {
/* Clear the old view and let the incremental updating refill
int request = get_request(key);
int i;
+ assert(view);
+
switch (request) {
case REQ_MOVE_UP:
case REQ_MOVE_DOWN:
case REQ_MOVE_PAGE_DOWN:
case REQ_MOVE_FIRST_LINE:
case REQ_MOVE_LAST_LINE:
- if (view)
- move_view(view, request);
+ move_view(view, request);
break;
case REQ_SCROLL_LINE_DOWN:
case REQ_SCROLL_LINE_UP:
case REQ_SCROLL_PAGE_DOWN:
case REQ_SCROLL_PAGE_UP:
- if (view)
- scroll_view(view, request);
+ scroll_view(view, request);
break;
case REQ_VIEW_MAIN:
case REQ_TOGGLE_LINE_NUMBERS:
opt_line_number = !opt_line_number;
- if (view)
- redraw_view(view);
+ redraw_view(view);
break;
case REQ_STOP_LOADING:
default:
/* An unknown key will show most commonly used commands. */
- report(HELP);
+ report("%s", HELP);
return TRUE;
}
if (opt_line_number) {
unsigned int real_lineno = view->offset + lineno + 1;
- int col = 1;
+ int col = 0;
if (real_lineno == 1 || (real_lineno % opt_num_interval) == 0)
mvwprintw(view->win, lineno, 0, "%4d: ", real_lineno);
{
if (status_win)
delwin(status_win);
- if (title_win)
- delwin(title_win);
endwin();
/* FIXME: Shutdown gracefully. */
}
static void
-update_title(void)
+update_title(struct view *view)
{
- struct view *view = display[current_view];
+ werase(view->title);
+ wmove(view->title, 0, 0);
- assert(view);
-
- werase(title_win);
- wmove(title_win, 0, 0);
+ if (view == &views[current_view])
+ wattrset(view->title, A_BOLD);
+ else
+ wattrset(view->title, A_NORMAL);
/* [main] ref: 334b506... - line 6 of 4383 (0%) */
- wprintw(title_win, "[%s] ref: %s", view->name, ref_commit);
+ wprintw(view->title, "[%s] ref: %s", view->name, ref_commit);
if (view->lines) {
- wprintw(title_win, " - line %d of %d (%d%%)",
+ wprintw(view->title, " - line %d of %d (%d%%)",
view->lineno + 1,
view->lines,
(view->lineno + 1) * 100 / view->lines);
}
- wrefresh(title_win);
+ wrefresh(view->title);
}
/* Update status and title window. */
/* Update the title window first, so the cursor ends up in the status
* window. */
- update_title();
+ update_title(display[current_view]);
werase(status_win);
wmove(status_win, 0, 0);
if (!status_win)
die("Failed to create status window");
- title_win = newwin(1, 0, y - 2, 0);
- if (!title_win)
- die("Failed to create title window");
-
/* Enable keyboard mapping */
keypad(status_win, TRUE);
wbkgdset(status_win, get_line_attr(LINE_STATUS));
- wbkgdset(title_win, get_line_attr(LINE_TITLE));
while (view_driver(display[current_view], request)) {
struct view *view;
mvwin(status_win, lines - 1, 0);
wresize(status_win, 1, cols - 1);
-
- mvwin(title_win, lines - 2, 0);
- wresize(title_win, 1, cols - 1);
}
}