X-Git-Url: https://git.distorted.org.uk/~mdw/tig/blobdiff_plain/f4de14c5762fe2beef8633a254c470a37376b4c2..3704f96bd94e20eb7e516afdd9e324ea1dcc7f4d:/tig.c diff --git a/tig.c b/tig.c index ee9d706..a5d6a5e 100644 --- a/tig.c +++ b/tig.c @@ -143,11 +143,12 @@ static size_t utf8_length(const char *string, size_t max_width, int *trimmed, bo struct ref { char *name; /* Ref name; tag or head names are shortened. */ char id[SIZEOF_REV]; /* Commit SHA1 ID */ + unsigned int head:1; /* Is it the current HEAD? */ unsigned int tag:1; /* Is it a tag? */ unsigned int ltag:1; /* If so, is the tag local? */ unsigned int remote:1; /* Is it a remote ref? */ + unsigned int tracked:1; /* Is it the remote for the current HEAD? */ unsigned int next:1; /* For ref lists: are there more refs? */ - unsigned int head:1; /* Is it the current HEAD? */ }; static struct ref **get_refs(char *id); @@ -447,6 +448,7 @@ static char opt_path[SIZEOF_STR] = ""; static char opt_file[SIZEOF_STR] = ""; static char opt_ref[SIZEOF_REF] = ""; static char opt_head[SIZEOF_REF] = ""; +static char opt_remote[SIZEOF_REF] = ""; static bool opt_no_head = TRUE; static FILE *opt_pipe = NULL; static char opt_encoding[20] = "UTF-8"; @@ -584,16 +586,18 @@ LINE(DEFAULT, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \ LINE(CURSOR, "", COLOR_WHITE, COLOR_GREEN, A_BOLD), \ LINE(STATUS, "", COLOR_GREEN, COLOR_DEFAULT, 0), \ LINE(DELIMITER, "", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ +LINE(LINE_NUMBER, "", COLOR_CYAN, COLOR_DEFAULT, 0), \ LINE(TITLE_BLUR, "", COLOR_WHITE, COLOR_BLUE, 0), \ LINE(TITLE_FOCUS, "", 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_TAG, "", COLOR_MAGENTA, COLOR_DEFAULT, A_BOLD), \ -LINE(MAIN_LOCAL_TAG,"", COLOR_MAGENTA, COLOR_DEFAULT, A_BOLD), \ -LINE(MAIN_REMOTE, "", COLOR_YELLOW, COLOR_DEFAULT, A_BOLD), \ -LINE(MAIN_REF, "", COLOR_CYAN, COLOR_DEFAULT, A_BOLD), \ -LINE(MAIN_HEAD, "", COLOR_RED, COLOR_DEFAULT, A_BOLD), \ +LINE(MAIN_LOCAL_TAG,"", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ +LINE(MAIN_REMOTE, "", COLOR_YELLOW, COLOR_DEFAULT, 0), \ +LINE(MAIN_TRACKED, "", COLOR_YELLOW, COLOR_DEFAULT, A_BOLD), \ +LINE(MAIN_REF, "", COLOR_CYAN, COLOR_DEFAULT, 0), \ +LINE(MAIN_HEAD, "", COLOR_CYAN, COLOR_DEFAULT, A_BOLD), \ LINE(MAIN_REVGRAPH,"", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ LINE(TREE_DIR, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \ LINE(TREE_FILE, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \ @@ -606,8 +610,7 @@ LINE(STAT_UNTRACKED,"", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ LINE(BLAME_DATE, "", COLOR_BLUE, COLOR_DEFAULT, 0), \ LINE(BLAME_AUTHOR, "", COLOR_GREEN, COLOR_DEFAULT, 0), \ LINE(BLAME_COMMIT, "", COLOR_DEFAULT, COLOR_DEFAULT, 0), \ -LINE(BLAME_ID, "", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ -LINE(BLAME_LINENO, "", COLOR_CYAN, COLOR_DEFAULT, 0) +LINE(BLAME_ID, "", COLOR_MAGENTA, COLOR_DEFAULT, 0) enum line_type { #define LINE(type, line, fg, bg, attr) \ @@ -1504,6 +1507,8 @@ draw_lineno(struct view *view, unsigned int lineno, int max, bool selected) if (max < max_number) max_number = max; + if (!selected) + wattrset(view->win, get_line_attr(LINE_LINE_NUMBER)); col = draw_text(view, number, max_number, showtrimmed, selected); if (col < max) { if (!selected) @@ -2302,6 +2307,7 @@ enum open_flags { OPEN_SPLIT = 1, /* Split current view. */ OPEN_BACKGROUNDED = 2, /* Backgrounded. */ OPEN_RELOAD = 4, /* Reload view even if it is the current. */ + OPEN_NOMAXIMIZE = 8, /* Do not maximize the current view. */ }; static void @@ -2310,6 +2316,7 @@ open_view(struct view *prev, enum request request, enum open_flags flags) bool backgrounded = !!(flags & OPEN_BACKGROUNDED); bool split = !!(flags & OPEN_SPLIT); bool reload = !!(flags & OPEN_RELOAD); + bool nomaximize = !!(flags & OPEN_NOMAXIMIZE); struct view *view = VIEW(request); int nviews = displayed_views(); struct view *base_view = display[0]; @@ -2328,7 +2335,7 @@ open_view(struct view *prev, enum request request, enum open_flags flags) display[1] = view; if (!backgrounded) current_view = 1; - } else { + } else if (!nomaximize) { /* Maximize the current view. */ memset(display, 0, sizeof(display)); current_view = 0; @@ -2374,7 +2381,7 @@ open_view(struct view *prev, enum request request, enum open_flags flags) if (view->pipe && view->lines == 0) { /* Clear the old view and let the incremental updating refill * the screen. */ - wclear(view->win); + werase(view->win); report(""); } else { redraw_view(view); @@ -2501,7 +2508,12 @@ view_driver(struct view *view, enum request request) if (request > REQ_NONE) { open_run_request(request); - return TRUE; + /* FIXME: When all views can refresh always do this. */ + if (view == VIEW(REQ_VIEW_STATUS) || + view == VIEW(REQ_VIEW_STAGE)) + request = REQ_REFRESH; + else + return TRUE; } if (view && view->lines) { @@ -2634,27 +2646,27 @@ view_driver(struct view *view, enum request request) case REQ_TOGGLE_LINENO: opt_line_number = !opt_line_number; - redraw_display(); + redraw_view(view); break; case REQ_TOGGLE_DATE: opt_date = !opt_date; - redraw_display(); + redraw_view(view); break; case REQ_TOGGLE_AUTHOR: opt_author = !opt_author; - redraw_display(); + redraw_view(view); break; case REQ_TOGGLE_REV_GRAPH: opt_rev_graph = !opt_rev_graph; - redraw_display(); + redraw_view(view); break; case REQ_TOGGLE_REFS: opt_show_refs = !opt_show_refs; - redraw_display(); + redraw_view(view); break; case REQ_PROMPT: @@ -3476,6 +3488,8 @@ blame_read_file(struct view *view, char *line) if (view->lines > 0) pipe = popen(view->cmd, "r"); + else if (!view->parent) + die("No blame exist for %s", view->vid); view->cmd[0] = 0; if (!pipe) { report("Failed to load blame data"); @@ -3632,8 +3646,6 @@ blame_draw(struct view *view, struct line *line, unsigned int lineno, bool selec } { - if (!selected) - wattrset(view->win, get_line_attr(LINE_BLAME_LINENO)); col += draw_lineno(view, lineno, view->width - col, selected); if (col >= view->width) return TRUE; @@ -4002,6 +4014,8 @@ static bool status_draw(struct view *view, struct line *line, unsigned int lineno, bool selected) { struct status *status = line->data; + char *text; + int col = 0; wmove(view->win, lineno, 0); @@ -4022,8 +4036,6 @@ status_draw(struct view *view, struct line *line, unsigned int lineno, bool sele } if (!status) { - char *text; - switch (line->type) { case LINE_STAT_STAGED: text = "Changes to be committed:"; @@ -4048,19 +4060,16 @@ status_draw(struct view *view, struct line *line, unsigned int lineno, bool sele default: return FALSE; } + } else { + char buf[] = { status->status, ' ', ' ', ' ', 0 }; - draw_text(view, text, view->width, TRUE, selected); - return TRUE; + col += draw_text(view, buf, view->width, TRUE, selected); + if (!selected) + wattrset(view->win, A_NORMAL); + text = status->new.name; } - waddch(view->win, status->status); - if (!selected) - wattrset(view->win, A_NORMAL); - wmove(view->win, lineno, 4); - if (view->width < 5) - return TRUE; - - draw_text(view, status->new.name, view->width - 5, TRUE, selected); + draw_text(view, text, view->width - col, TRUE, selected); return TRUE; } @@ -4159,6 +4168,23 @@ status_enter(struct view *view, struct line *line) return REQ_NONE; } +static bool +status_exists(struct status *status, enum line_type type) +{ + struct view *view = VIEW(REQ_VIEW_STATUS); + struct line *line; + + for (line = view->line; line < view->line + view->lines; line++) { + struct status *pos = line->data; + + if (line->type == type && pos && + !strcmp(status->new.name, pos->new.name)) + return TRUE; + } + + return FALSE; +} + static FILE * status_update_prepare(enum line_type type) @@ -4449,36 +4475,39 @@ stage_diff_line(FILE *pipe, struct line *line) return written == bufsize; } -static struct line * -stage_diff_hdr(struct view *view, struct line *line) +static bool +stage_diff_write(FILE *pipe, struct line *line, struct line *end) { - int diff_hdr_dir = line->type == LINE_DIFF_CHUNK ? -1 : 1; - struct line *diff_hdr; - - if (line->type == LINE_DIFF_CHUNK) - diff_hdr = line - 1; - else - diff_hdr = view->line + 1; + while (line < end) { + if (!stage_diff_line(pipe, line++)) + return FALSE; + if (line->type == LINE_DIFF_CHUNK || + line->type == LINE_DIFF_HEADER) + break; + } - while (diff_hdr > view->line && diff_hdr < view->line + view->lines) { - if (diff_hdr->type == LINE_DIFF_HEADER) - return diff_hdr; + return TRUE; +} - diff_hdr += diff_hdr_dir; - } +static struct line * +stage_diff_find(struct view *view, struct line *line, enum line_type type) +{ + for (; view->line < line; line--) + if (line->type == type) + return line; return NULL; } static bool -stage_update_chunk(struct view *view, struct line *line) +stage_update_chunk(struct view *view, struct line *chunk) { char cmd[SIZEOF_STR]; size_t cmdsize = 0; - struct line *diff_hdr, *diff_chunk, *diff_end; + struct line *diff_hdr; FILE *pipe; - diff_hdr = stage_diff_hdr(view, line); + diff_hdr = stage_diff_find(view, chunk, LINE_DIFF_HEADER); if (!diff_hdr) return FALSE; @@ -4496,69 +4525,35 @@ stage_update_chunk(struct view *view, struct line *line) if (!pipe) return FALSE; - diff_end = view->line + view->lines; - if (line->type != LINE_DIFF_CHUNK) { - diff_chunk = diff_hdr; - - } else { - for (diff_chunk = line + 1; diff_chunk < diff_end; diff_chunk++) - if (diff_chunk->type == LINE_DIFF_CHUNK || - diff_chunk->type == LINE_DIFF_HEADER) - diff_end = diff_chunk; - - diff_chunk = line; - - while (diff_hdr->type != LINE_DIFF_CHUNK) { - switch (diff_hdr->type) { - case LINE_DIFF_HEADER: - case LINE_DIFF_INDEX: - case LINE_DIFF_ADD: - case LINE_DIFF_DEL: - break; - - default: - diff_hdr++; - continue; - } - - if (!stage_diff_line(pipe, diff_hdr++)) { - pclose(pipe); - return FALSE; - } - } - } - - while (diff_chunk < diff_end && stage_diff_line(pipe, diff_chunk)) - diff_chunk++; + if (!stage_diff_write(pipe, diff_hdr, chunk) || + !stage_diff_write(pipe, chunk, view->line + view->lines)) + chunk = NULL; pclose(pipe); - if (diff_chunk != diff_end) - return FALSE; - - return TRUE; + return chunk ? TRUE : FALSE; } -static void +static bool stage_update(struct view *view, struct line *line) { - if (!opt_no_head && stage_line_type != LINE_STAT_UNTRACKED && - (line->type == LINE_DIFF_CHUNK || !stage_status.status)) { - if (!stage_update_chunk(view, line)) { + struct line *chunk = NULL; + + if (!opt_no_head && stage_line_type != LINE_STAT_UNTRACKED) + chunk = stage_diff_find(view, line, LINE_DIFF_CHUNK); + + if (chunk) { + if (!stage_update_chunk(view, chunk)) { report("Failed to apply chunk"); - return; + return FALSE; } } else if (!status_update_file(&stage_status, stage_line_type)) { report("Failed to update file"); - return; + return FALSE; } - open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD); - - view = VIEW(REQ_VIEW_STATUS); - if (view_is_displayed(view)) - status_enter(view, &view->line[view->lineno]); + return TRUE; } static enum request @@ -4576,6 +4571,10 @@ stage_request(struct view *view, enum request request, struct line *line) open_editor(stage_status.status != '?', stage_status.new.name); break; + case REQ_REFRESH: + /* Reload everything ... */ + break; + case REQ_VIEW_BLAME: if (stage_status.new.name[0]) { string_copy(opt_file, stage_status.new.name); @@ -4584,13 +4583,25 @@ stage_request(struct view *view, enum request request, struct line *line) return request; case REQ_ENTER: - pager_request(view, request, line); - break; + return pager_request(view, request, line); default: return request; } + open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD | OPEN_NOMAXIMIZE); + + /* Check whether the staged entry still exists, and close the + * stage view if it doesn't. */ + if (!status_exists(&stage_status, stage_line_type)) + return REQ_VIEW_CLOSE; + + if (stage_line_type == LINE_STAT_UNTRACKED) + opt_pipe = fopen(stage_status.new.name, "r"); + else + string_copy(opt_cmd, view->cmd); + open_view(view, REQ_VIEW_STAGE, OPEN_RELOAD | OPEN_NOMAXIMIZE); + return REQ_NONE; } @@ -4903,6 +4914,8 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select wattrset(view->win, get_line_attr(LINE_MAIN_LOCAL_TAG)); else if (commit->refs[i]->tag) wattrset(view->win, get_line_attr(LINE_MAIN_TAG)); + else if (commit->refs[i]->tracked) + wattrset(view->win, get_line_attr(LINE_MAIN_TRACKED)); else if (commit->refs[i]->remote) wattrset(view->win, get_line_attr(LINE_MAIN_REMOTE)); else @@ -4936,6 +4949,8 @@ main_read(struct view *view, char *line) struct commit *commit; if (!line) { + if (!view->lines && !view->parent) + die("No revisions match the given arguments."); update_rev_graph(graph); return TRUE; } @@ -5510,6 +5525,7 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen) bool tag = FALSE; bool ltag = FALSE; bool remote = FALSE; + bool tracked = FALSE; bool check_replace = FALSE; bool head = FALSE; @@ -5531,6 +5547,7 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen) remote = TRUE; namelen -= STRING_SIZE("refs/remotes/"); name += STRING_SIZE("refs/remotes/"); + tracked = !strcmp(opt_remote, name); } else if (!strncmp(name, "refs/heads/", STRING_SIZE("refs/heads/"))) { namelen -= STRING_SIZE("refs/heads/"); @@ -5563,10 +5580,11 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen) strncpy(ref->name, name, namelen); ref->name[namelen] = 0; + ref->head = head; ref->tag = tag; ref->ltag = ltag; ref->remote = remote; - ref->head = head; + ref->tracked = tracked; string_copy_rev(ref->id, id); return OK; @@ -5590,11 +5608,33 @@ read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen if (!strcmp(name, "core.editor")) string_ncopy(opt_editor, value, valuelen); + /* branch..remote */ + if (*opt_head && + !strncmp(name, "branch.", 7) && + !strncmp(name + 7, opt_head, strlen(opt_head)) && + !strcmp(name + 7 + strlen(opt_head), ".remote")) + string_ncopy(opt_remote, value, valuelen); + + if (*opt_head && *opt_remote && + !strncmp(name, "branch.", 7) && + !strncmp(name + 7, opt_head, strlen(opt_head)) && + !strcmp(name + 7 + strlen(opt_head), ".merge")) { + size_t from = strlen(opt_remote); + + if (!strncmp(value, "refs/heads/", STRING_SIZE("refs/heads/"))) { + value += STRING_SIZE("refs/heads/"); + valuelen -= STRING_SIZE("refs/heads/"); + } + + if (!string_format_from(opt_remote, &from, "/%s", value)) + opt_remote[0] = 0; + } + return OK; } static int -load_repo_config(void) +load_git_config(void) { return read_properties(popen(GIT_CONFIG " --list", "r"), "=", read_repo_config_option); @@ -5631,8 +5671,8 @@ static int load_repo_info(void) { int result; - FILE *pipe = popen("git rev-parse --git-dir --is-inside-work-tree " - " --show-cdup --symbolic-full-name HEAD 2>/dev/null", "r"); + FILE *pipe = popen("(git rev-parse --git-dir --is-inside-work-tree " + " --show-cdup; git symbolic-ref HEAD) 2>/dev/null", "r"); /* XXX: The line outputted by "--show-cdup" can be empty so * initialize it to something invalid to make it possible to @@ -5749,9 +5789,7 @@ main(int argc, char *argv[]) if (load_options() == ERR) die("Failed to load user config."); - /* Load the repo config file so options can be overwritten from - * the command line. */ - if (load_repo_config() == ERR) + if (load_git_config() == ERR) die("Failed to load repo config."); if (!parse_options(argc, argv)) @@ -5770,7 +5808,7 @@ main(int argc, char *argv[]) die("Failed to initialize character set conversion"); } - if (load_refs() == ERR) + if (*opt_git_dir && load_refs() == ERR) die("Failed to load refs."); for (i = 0; i < ARRAY_SIZE(views) && (view = &views[i]); i++)