diff --git a/NEWS.adoc b/NEWS.adoc index 59a79dea7..6c141b50a 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -72,6 +72,7 @@ Improvements: - More informative configuration error messages. - Add completion and history support to the prompt via readline. (GH #185) - Options can be toggled individually for each view. (GH #89) + - Add support for `--graph` and highlight diff stats in the log view. Bug fixes: diff --git a/include/tig/diff.h b/include/tig/diff.h index f389e436c..fd0819a14 100644 --- a/include/tig/diff.h +++ b/include/tig/diff.h @@ -26,7 +26,7 @@ struct diff_state { enum request diff_common_edit(struct view *view, enum request request, struct line *line); bool diff_common_read(struct view *view, const char *data, struct diff_state *state); enum request diff_common_enter(struct view *view, enum request request, struct line *line); -bool diff_common_add_diff_stat(struct view *view, const char *data); +struct line *diff_common_add_diff_stat(struct view *view, const char *text, size_t offset); unsigned int diff_get_lineno(struct view *view, struct line *line); const char *diff_get_pathname(struct view *view, struct line *line); diff --git a/include/tig/pager.h b/include/tig/pager.h index 7b33eab78..3c592b7cc 100644 --- a/include/tig/pager.h +++ b/include/tig/pager.h @@ -19,7 +19,7 @@ bool pager_column_init(struct view *view); bool pager_get_column_data(struct view *view, const struct line *line, struct view_column_data *column_data); bool pager_read(struct view *view, char *data); -bool pager_common_read(struct view *view, const char *data, enum line_type type); +bool pager_common_read(struct view *view, const char *data, enum line_type type, struct line **line); enum request pager_request(struct view *view, enum request request, struct line *line); void pager_select(struct view *view, struct line *line); diff --git a/include/tig/string.h b/include/tig/string.h index 7d5abeeff..6a1ac4b4d 100644 --- a/include/tig/string.h +++ b/include/tig/string.h @@ -26,6 +26,7 @@ bool string_isnumber(const char *str); bool iscommit(const char *str); +#define get_graph_indent(str) strspn(str, "*|\\/ ") static inline int ascii_toupper(int c) diff --git a/include/tig/view.h b/include/tig/view.h index 670256af0..97a58de83 100644 --- a/include/tig/view.h +++ b/include/tig/view.h @@ -35,6 +35,7 @@ struct line { unsigned int wrapped:1; unsigned int commit_title:1; unsigned int no_commit_refs:1; + unsigned int graph_indent:1; void *data; /* User data */ }; diff --git a/src/argv.c b/src/argv.c index a0fd1b5d7..162cb05a7 100644 --- a/src/argv.c +++ b/src/argv.c @@ -403,6 +403,7 @@ argv_parse_rev_flag(const char *arg, struct rev_flags *rev_flags) "--first-parent", "--fixed-strings", "--full-history", + "--graph", "--glob=", "--left-only", "--max-parents=", diff --git a/src/diff.c b/src/diff.c index e6a49b88e..3eae93bf7 100644 --- a/src/diff.c +++ b/src/diff.c @@ -37,9 +37,10 @@ diff_open(struct view *view, enum open_flags flags) return begin_update(view, NULL, diff_argv, flags); } -bool -diff_common_add_diff_stat(struct view *view, const char *data) +struct line * +diff_common_add_diff_stat(struct view *view, const char *text, size_t offset) { + const char *data = text + offset; size_t len = strlen(data); char *pipe = strchr(data, '|'); bool has_histogram = data[len - 1] == '-' || data[len - 1] == '+'; @@ -48,8 +49,8 @@ diff_common_add_diff_stat(struct view *view, const char *data) bool has_no_change = pipe && strstr(pipe, " 0"); if (pipe && (has_histogram || has_bin_diff || has_rename || has_no_change)) - return add_line_text(view, data, LINE_DIFF_STAT) != NULL; - return FALSE; + return add_line_text(view, text, LINE_DIFF_STAT); + return NULL; } bool @@ -64,7 +65,7 @@ diff_common_read(struct view *view, const char *data, struct diff_state *state) state->reading_diff_stat = TRUE; if (state->reading_diff_stat) { - if (diff_common_add_diff_stat(view, data)) + if (diff_common_add_diff_stat(view, data, 0)) return TRUE; state->reading_diff_stat = FALSE; @@ -97,7 +98,7 @@ diff_common_read(struct view *view, const char *data, struct diff_state *state) if (!state->combined_diff && (type == LINE_DIFF_ADD2 || type == LINE_DIFF_DEL2)) type = LINE_DEFAULT; - return pager_common_read(view, data, type); + return pager_common_read(view, data, type, NULL); } static bool diff --git a/src/draw.c b/src/draw.c index ab7e90658..7cc9888e4 100644 --- a/src/draw.c +++ b/src/draw.c @@ -397,7 +397,7 @@ draw_graph(struct view *view, const struct graph_canvas *canvas) static bool draw_diff_stat_part(struct view *view, enum line_type *type, const char **text, char c, enum line_type next_type) { - const char *sep = strchr(*text, c); + const char *sep = c == '|' ? strrchr(*text, c) : strchr(*text, c); if (sep != NULL) { draw_text_expanded(view, *type, *text, sep - *text, FALSE); @@ -507,6 +507,14 @@ view_column_draw(struct view *view, struct line *line, unsigned int lineno) if (line->wrapped && draw_text(view, LINE_DELIMITER, "+")) return TRUE; + + if (line->graph_indent) { + size_t indent = get_graph_indent(text); + + if (draw_text_expanded(view, LINE_DEFAULT, text, indent, FALSE)) + return TRUE; + text += indent; + } if (type == LINE_DIFF_STAT) draw_diff_stat(view, &type, &text); if (line->commit_title) { diff --git a/src/log.c b/src/log.c index d8de36ab1..f94bffe63 100644 --- a/src/log.c +++ b/src/log.c @@ -23,12 +23,22 @@ struct log_state { * commit, for example when the user scrolls up or uses the page * up/down in the log view. */ int last_lineno; + size_t graph_indent; enum line_type last_type; bool commit_title_read; bool after_commit_header; bool reading_diff_stat; }; +static inline void +log_copy_rev(struct view *view, struct line *line) +{ + const char *text = line->data; + size_t offset = get_graph_indent(text); + + string_copy_rev_from_commit_line(view->ref, text + offset); +} + static void log_select(struct view *view, struct line *line) { @@ -37,15 +47,14 @@ log_select(struct view *view, struct line *line) if (!last_lineno || abs(last_lineno - line->lineno) > 1 || (state->last_type == LINE_COMMIT && last_lineno > line->lineno)) { - const struct line *commit_line = find_prev_line_by_type(view, line, LINE_COMMIT); + struct line *commit_line = find_prev_line_by_type(view, line, LINE_COMMIT); if (commit_line) - string_copy_rev_from_commit_line(view->ref, commit_line->data); + log_copy_rev(view, commit_line); } - if (line->type == LINE_COMMIT && !view_has_flags(view, VIEW_NO_REF)) { - string_copy_rev_from_commit_line(view->ref, (char *)line->data); - } + if (line->type == LINE_COMMIT && !view_has_flags(view, VIEW_NO_REF)) + log_copy_rev(view, line); string_copy_rev(view->env->commit, view->ref); state->last_lineno = line->lineno; state->last_type = line->type; @@ -87,15 +96,21 @@ log_request(struct view *view, enum request request, struct line *line) static bool log_read(struct view *view, char *data) { + struct line *line = NULL; enum line_type type; struct log_state *state = view->private; size_t len; + char *commit; if (!data) return TRUE; - type = get_line_type(data); - len = strlen(data); + commit = strstr(data, "commit "); + if (commit && get_graph_indent(data) == commit - data) + state->graph_indent = commit - data; + + type = get_line_type(data + state->graph_indent); + len = strlen(data + state->graph_indent); if (type == LINE_COMMIT) state->commit_title_read = TRUE; @@ -106,12 +121,20 @@ log_read(struct view *view, char *data) state->after_commit_header = FALSE; state->reading_diff_stat = TRUE; } else if (state->reading_diff_stat) { - if (diff_common_add_diff_stat(view, data)) + line = diff_common_add_diff_stat(view, data, state->graph_indent); + if (line) { + if (state->graph_indent) + line->graph_indent = 1; return TRUE; + } state->reading_diff_stat = FALSE; } - return pager_common_read(view, data, type); + if (!pager_common_read(view, data, type, &line)) + return FALSE; + if (line && state->graph_indent) + line->graph_indent = 1; + return TRUE; } static struct view_ops log_ops = { diff --git a/src/main.c b/src/main.c index 9cd14778e..394ed3482 100644 --- a/src/main.c +++ b/src/main.c @@ -151,6 +151,18 @@ main_check_argv(struct view *view, const char *argv[]) const char *arg = argv[i]; struct rev_flags rev_flags = {}; + if (!strcmp(arg, "--graph")) { + struct view_column *column = get_view_column(view, VIEW_COLUMN_COMMIT_TITLE); + + if (column) { + column->opt.commit_title.graph = TRUE; + if (opt_commit_order != COMMIT_ORDER_REVERSE) + state->with_graph = TRUE; + } + argv[i] = ""; + continue; + } + if (!argv_parse_rev_flag(arg, &rev_flags)) continue; diff --git a/src/options.c b/src/options.c index a37438d5c..20fdff78a 100644 --- a/src/options.c +++ b/src/options.c @@ -130,11 +130,6 @@ update_options_from_argv(const char *argv[]) continue; } - if (!strcmp(flag, "--graph")) { - opt_show_rev_graph = TRUE; - continue; - } - argv[flags_pos++] = flag; } diff --git a/src/pager.c b/src/pager.c index 16e2482bf..4a15837b2 100644 --- a/src/pager.c +++ b/src/pager.c @@ -140,7 +140,7 @@ pager_wrap_line(struct view *view, const char *data, enum line_type type) } bool -pager_common_read(struct view *view, const char *data, enum line_type type) +pager_common_read(struct view *view, const char *data, enum line_type type, struct line **line_ptr) { struct line *line; @@ -156,6 +156,9 @@ pager_common_read(struct view *view, const char *data, enum line_type type) if (!line) return FALSE; + if (line_ptr) + *line_ptr = line; + if (line->type == LINE_COMMIT && view_has_flags(view, VIEW_ADD_PAGER_REFS)) add_pager_refs(view, data + STRING_SIZE("commit ")); @@ -168,7 +171,7 @@ pager_read(struct view *view, char *data) if (!data) return TRUE; - return pager_common_read(view, data, get_line_type(data)); + return pager_common_read(view, data, get_line_type(data), NULL); } enum request diff --git a/src/stage.c b/src/stage.c index 9f1913fa5..12dad06d3 100644 --- a/src/stage.c +++ b/src/stage.c @@ -481,7 +481,7 @@ stage_read(struct view *view, char *data) struct stage_state *state = view->private; if (stage_line_type == LINE_STAT_UNTRACKED) - return pager_common_read(view, data, LINE_DEFAULT); + return pager_common_read(view, data, LINE_DEFAULT, NULL); if (data && diff_common_read(view, data, &state->diff)) return TRUE;