X-Git-Url: https://git.distorted.org.uk/~mdw/tig/blobdiff_plain/b86250daae850bc6f456df3f520a706501347b75..b6607e7e796f5b58d64211c022d3e1af6159bdaa:/tig.c?ds=inline diff --git a/tig.c b/tig.c index c96faae..c44409e 100644 --- a/tig.c +++ b/tig.c @@ -72,6 +72,7 @@ static size_t utf8_length(const char *string, size_t max_width, int *coloffset, #define REVGRAPH_MERGE 'M' #define REVGRAPH_BRANCH '+' #define REVGRAPH_COMMIT '*' +#define REVGRAPH_BOUND '^' #define REVGRAPH_LINE '|' #define SIZEOF_REVGRAPH 19 /* Size of revision ancestry graphics. */ @@ -105,13 +106,13 @@ static size_t utf8_length(const char *string, size_t max_width, int *coloffset, "git ls-remote $(git rev-parse --git-dir) 2>/dev/null" #define TIG_DIFF_CMD \ - "git show --root --patch-with-stat --find-copies-harder -B -C %s 2>/dev/null" + "git show --no-color --root --patch-with-stat --find-copies-harder -C %s 2>/dev/null" #define TIG_LOG_CMD \ - "git log --cc --stat -n100 %s 2>/dev/null" + "git log --no-color --cc --stat -n100 %s 2>/dev/null" #define TIG_MAIN_CMD \ - "git log --topo-order --pretty=raw %s 2>/dev/null" + "git log --no-color --topo-order --boundary --pretty=raw %s 2>/dev/null" #define TIG_TREE_CMD \ "git ls-tree %s %s" @@ -352,6 +353,7 @@ sq_quote(char buf[SIZEOF_STR], size_t bufsize, const char *src) REQ_(TOGGLE_REV_GRAPH, "Toggle revision graph visualization"), \ REQ_(STATUS_UPDATE, "Update file status"), \ REQ_(STATUS_MERGE, "Merge file using external tool"), \ + REQ_(TREE_PARENT, "Switch to parent directory in tree view"), \ REQ_(EDIT, "Open in editor"), \ REQ_(NONE, "Do nothing") @@ -505,6 +507,26 @@ parse_options(int argc, char *argv[]) if (opt[0] && opt[0] != '-') break; + if (!strcmp(opt, "--")) { + i++; + break; + } + + if (check_option(opt, 'v', "version", OPT_NONE)) { + printf("tig version %s\n", TIG_VERSION); + return FALSE; + } + + if (check_option(opt, 'h', "help", OPT_NONE)) { + printf(usage); + return FALSE; + } + + if (!strcmp(opt, "-S")) { + opt_request = REQ_VIEW_STATUS; + continue; + } + if (!strcmp(opt, "-l")) { opt_request = REQ_VIEW_LOG; continue; @@ -515,11 +537,6 @@ parse_options(int argc, char *argv[]) continue; } - if (!strcmp(opt, "-S")) { - opt_request = REQ_VIEW_STATUS; - continue; - } - if (check_option(opt, 'n', "line-number", OPT_INT, &opt_num_interval)) { opt_line_number = TRUE; continue; @@ -530,21 +547,6 @@ parse_options(int argc, char *argv[]) continue; } - if (check_option(opt, 'v', "version", OPT_NONE)) { - printf("tig version %s\n", TIG_VERSION); - return FALSE; - } - - if (check_option(opt, 'h', "help", OPT_NONE)) { - printf(usage); - return FALSE; - } - - if (!strcmp(opt, "--")) { - i++; - break; - } - die("unknown option '%s'\n\n%s", opt, usage); } @@ -558,7 +560,7 @@ parse_options(int argc, char *argv[]) if (opt_request == REQ_VIEW_MAIN) /* XXX: This is vulnerable to the user overriding * options required for the main view parser. */ - string_copy(opt_cmd, "git log --pretty=raw"); + string_copy(opt_cmd, "git log --no-color --pretty=raw --boundary"); else string_copy(opt_cmd, "git"); buf_size = strlen(opt_cmd); @@ -626,6 +628,7 @@ LINE(MAIN_DELIM, "", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ LINE(MAIN_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_REVGRAPH,"", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ LINE(TREE_DIR, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \ LINE(TREE_FILE, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \ LINE(STAT_SECTION, "", COLOR_CYAN, COLOR_DEFAULT, 0), \ @@ -694,15 +697,15 @@ get_line_info(char *name, int namelen) static void init_colors(void) { - int default_bg = COLOR_BLACK; - int default_fg = COLOR_WHITE; + int default_bg = line_info[LINE_DEFAULT].bg; + int default_fg = line_info[LINE_DEFAULT].fg; enum line_type type; start_color(); - if (use_default_colors() != ERR) { - default_bg = -1; - default_fg = -1; + if (assume_default_colors(default_fg, default_bg) == ERR) { + default_bg = COLOR_BLACK; + default_fg = COLOR_WHITE; } for (type = 0; type < ARRAY_SIZE(line_info); type++) { @@ -787,6 +790,7 @@ static struct keybinding default_keybindings[] = { { ':', REQ_PROMPT }, { 'u', REQ_STATUS_UPDATE }, { 'M', REQ_STATUS_MERGE }, + { ',', REQ_TREE_PARENT }, { 'e', REQ_EDIT }, /* Using the ncurses SIGWINCH handler. */ @@ -937,7 +941,6 @@ static char * get_key(enum request request) { static char buf[BUFSIZ]; - static char key_char[] = "'X'"; size_t pos = 0; char *sep = ""; int i; @@ -946,27 +949,12 @@ get_key(enum request request) for (i = 0; i < ARRAY_SIZE(default_keybindings); i++) { struct keybinding *keybinding = &default_keybindings[i]; - char *seq = NULL; - int key; if (keybinding->request != request) continue; - for (key = 0; key < ARRAY_SIZE(key_table); key++) - if (key_table[key].value == keybinding->alias) - seq = key_table[key].name; - - if (seq == NULL && - keybinding->alias < 127 && - isprint(keybinding->alias)) { - key_char[1] = (char) keybinding->alias; - seq = key_char; - } - - if (!seq) - seq = "'?'"; - - if (!string_format_from(buf, &pos, "%s%s", sep, seq)) + if (!string_format_from(buf, &pos, "%s%s", sep, + get_key_name(keybinding->alias))) return "Too many keybindings!"; sep = ", "; } @@ -1184,7 +1172,7 @@ option_bind_command(int argc, char *argv[]) } request = get_request(argv[2]); - if (request = REQ_NONE) { + if (request == REQ_NONE) { const char *obsolete[] = { "cherry-pick" }; size_t namelen = strlen(argv[2]); int i; @@ -1283,29 +1271,47 @@ read_option(char *opt, size_t optlen, char *value, size_t valuelen) return OK; } -static int -load_options(void) +static void +load_option_file(const char *path) { - char *home = getenv("HOME"); - char buf[SIZEOF_STR]; FILE *file; + /* It's ok that the file doesn't exist. */ + file = fopen(path, "r"); + if (!file) + return; + config_lineno = 0; config_errors = FALSE; - add_builtin_run_requests(); + if (read_properties(file, " \t", read_option) == ERR || + config_errors == TRUE) + fprintf(stderr, "Errors while loading %s.\n", path); +} - if (!home || !string_format(buf, "%s/.tigrc", home)) - return ERR; +static int +load_options(void) +{ + char *home = getenv("HOME"); + char *tigrc_user = getenv("TIGRC_USER"); + char *tigrc_system = getenv("TIGRC_SYSTEM"); + char buf[SIZEOF_STR]; - /* It's ok that the file doesn't exist. */ - file = fopen(buf, "r"); - if (!file) - return OK; + add_builtin_run_requests(); - if (read_properties(file, " \t", read_option) == ERR || - config_errors == TRUE) - fprintf(stderr, "Errors while loading %s.\n", buf); + if (!tigrc_system) { + if (!string_format(buf, "%s/tigrc", SYSCONFDIR)) + return ERR; + tigrc_system = buf; + } + load_option_file(tigrc_system); + + if (!tigrc_user) { + if (!home || !string_format(buf, "%s/.tigrc", home)) + return ERR; + tigrc_user = buf; + } + load_option_file(tigrc_user); return OK; } @@ -3035,6 +3041,16 @@ tree_request(struct view *view, enum request request, struct line *line) { enum open_flags flags; + if (request == REQ_TREE_PARENT) { + if (*opt_path) { + /* fake 'cd ..' */ + request = REQ_ENTER; + line = &view->line[1]; + } else { + /* quit view if at top of tree */ + return REQ_VIEW_CLOSE; + } + } if (request != REQ_ENTER) return request; @@ -3276,8 +3292,11 @@ error_out: #define STATUS_LIST_OTHER_CMD \ "git ls-files -z --others --exclude-per-directory=.gitignore" -#define STATUS_DIFF_SHOW_CMD \ - "git diff --root --patch-with-stat --find-copies-harder -B -C %s -- %s 2>/dev/null" +#define STATUS_DIFF_INDEX_SHOW_CMD \ + "git diff-index --root --patch-with-stat --find-copies-harder -C --cached HEAD -- %s 2>/dev/null" + +#define STATUS_DIFF_FILES_SHOW_CMD \ + "git diff-files --root --patch-with-stat --find-copies-harder -C -- %s 2>/dev/null" /* First parse staged info using git-diff-index(1), then parse unstaged * info using git-diff-files(1), and finally untracked files using @@ -3408,8 +3427,8 @@ status_enter(struct view *view, struct line *line) switch (line->type) { case LINE_STAT_STAGED: - if (!string_format_from(opt_cmd, &cmdsize, STATUS_DIFF_SHOW_CMD, - "--cached", path)) + if (!string_format_from(opt_cmd, &cmdsize, + STATUS_DIFF_INDEX_SHOW_CMD, path)) return REQ_QUIT; if (status) info = "Staged changes to %s"; @@ -3418,8 +3437,8 @@ status_enter(struct view *view, struct line *line) break; case LINE_STAT_UNSTAGED: - if (!string_format_from(opt_cmd, &cmdsize, STATUS_DIFF_SHOW_CMD, - "", path)) + if (!string_format_from(opt_cmd, &cmdsize, + STATUS_DIFF_FILES_SHOW_CMD, path)) return REQ_QUIT; if (status) info = "Unstaged changes to %s"; @@ -3549,6 +3568,10 @@ status_request(struct view *view, enum request request, struct line *line) break; case REQ_STATUS_MERGE: + if (!status || status->status != 'U') { + report("Merging only possible for files with unmerged status ('U')."); + return REQ_NONE; + } open_mergetool(status->name); break; @@ -3856,6 +3879,7 @@ struct rev_graph { size_t size; struct commit *commit; size_t pos; + unsigned int boundary:1; }; /* Parents of the commit being visualized. */ @@ -3928,7 +3952,9 @@ get_rev_graph_symbol(struct rev_graph *graph) { chtype symbol; - if (graph->parents->size == 0) + if (graph->boundary) + symbol = REVGRAPH_BOUND; + else if (graph->parents->size == 0) symbol = REVGRAPH_INIT; else if (graph_parent_is_merge(graph)) symbol = REVGRAPH_MERGE; @@ -4010,7 +4036,7 @@ prepare_rev_graph(struct rev_graph *graph) } /* Interleave the new revision parent(s). */ - for (i = 0; i < graph->parents->size; i++) + for (i = 0; !graph->boundary && i < graph->parents->size; i++) push_rev_graph(graph->next, graph->parents->rev[i]); /* Lastly, put any remaining revisions. */ @@ -4094,12 +4120,12 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select } col += AUTHOR_COLS; - if (type != LINE_CURSOR) - wattrset(view->win, A_NORMAL); if (opt_rev_graph && commit->graph_size) { size_t i; + if (type != LINE_CURSOR) + wattrset(view->win, get_line_attr(LINE_MAIN_REVGRAPH)); wmove(view->win, lineno, col); /* Using waddch() instead of waddnstr() ensures that * they'll be rendered correctly for the cursor line. */ @@ -4109,6 +4135,8 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select waddch(view->win, ' '); col += commit->graph_size + 1; } + if (type != LINE_CURSOR) + wattrset(view->win, A_NORMAL); wmove(view->win, lineno, col); @@ -4168,7 +4196,13 @@ main_read(struct view *view, char *line) if (!commit) return FALSE; - string_copy_rev(commit->id, line + STRING_SIZE("commit ")); + line += STRING_SIZE("commit "); + if (*line == '-') { + graph->boundary = 1; + line++; + } + + string_copy_rev(commit->id, line); commit->refs = get_refs(commit->id); graph->commit = commit; add_line_data(view, commit, LINE_MAIN_COMMIT);