commit - 6570a66d534155e8cfc35bc2023b9f655a6f30eb
commit + 6d17833f854902ee602bfbaf73cc67df9b25e1e8
blob - f1c654737061914c1e6789930e5d84be5117070c
blob + 4e252ffbac5584645f2d0ce7bd4ba2688825f65d
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_TAG_EXISTS 109
#define GOT_ERR_GIT_REPO_FORMAT 110
#define GOT_ERR_REBASE_REQUIRED 111
+#define GOT_ERR_REGEX 112
static const struct got_error {
int code;
{ GOT_ERR_TAG_EXISTS,"specified tag already exists" },
{ GOT_ERR_GIT_REPO_FORMAT,"unknown git repository format version" },
{ GOT_ERR_REBASE_REQUIRED,"specified branch must be rebased first" },
+ { GOT_ERR_REGEX, "regular expression error" },
};
/*
blob - 4af5ca7c1f56bf6f604dc53635ac15ce4a13edb1
blob + 59ba7c9f63a0734b9e9e30f34ef9a5d707f40b4a
--- tog/tog.1
+++ tog/tog.1
automatically, provided the abbreviation is unique.
.El
.El
+.Sh ENVIRONMENT
+.Bl -tag -width TOG_COLORS
+.It Ev TOG_COLORS
+.Nm
+shows colorized output if this variable is set to a non-empty value.
+The default color scheme can be modified by setting the environment
+variables documented below.
+The colors available in color schemes are
+.Dq black ,
+.Dq red ,
+.Dq green ,
+.Dq yellow ,
+.Dq blue ,
+.Dq megenta ,
+and
+.Dq cyan .
+.It Ev TOG_COLOR_DIFF_MINUS
+The color used to mark up removed lines in diffs.
+If not set, the default value
+.Dq magenta
+is used.
+.It Ev TOG_COLOR_DIFF_PLUS
+The color used to mark up added lines in diffs.
+If not set, the default value
+.Dq cyan
+is used.
+.It Ev TOG_COLOR_DIFF_CHUNK_HEADER
+The color used to mark up chunk header lines in diffs.
+If not set, the default value
+.Dq yellow
+is used.
+.It Ev TOG_COLOR_DIFF_META
+The color used to mark up meta data in diffs.
+If not set, the default value
+.Dq green
+is used.
+.El
.Sh EXIT STATUS
.Ex -std tog
.Sh SEE ALSO
blob - 0ff3b6287ab653b866bd0d00bd1eb725becd81e6
blob + cc9b6c1d8c40fe9084dbd96074e8889eec6a6e97
--- tog/tog.c
+++ tog/tog.c
struct commit_queue {
int ncommits;
struct commit_queue_head head;
+};
+
+struct tog_line_color {
+ SIMPLEQ_ENTRY(tog_line_color) entry;
+ regex_t regex;
+ short colorpair;
};
+SIMPLEQ_HEAD(tog_line_colors, tog_line_color);
struct tog_diff_view_state {
struct got_object_id *id1, *id2;
int diff_context;
struct got_repository *repo;
struct got_reflist_head *refs;
+ struct tog_line_colors line_colors;
/* passed from log view; may be NULL */
struct tog_view *log_view;
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
curs_set(0);
+ if (getenv("TOG_COLORS") != NULL) {
+ start_color();
+ use_default_colors();
+ }
signal(SIGWINCH, tog_sigwinch);
signal(SIGPIPE, tog_sigpipe);
}
return line;
}
+static int
+match_line(const char *line, regex_t *regex)
+{
+ regmatch_t regmatch;
+
+ return regexec(regex, line, 1, ®match, 0) == 0;
+}
+
+struct tog_line_color *
+match_line_color(struct tog_line_colors *colors, const char *line)
+{
+ struct tog_line_color *tc = NULL;
+
+ SIMPLEQ_FOREACH(tc, colors, entry) {
+ if (match_line(line, &tc->regex))
+ return tc;
+ }
+
+ return NULL;
+}
+
static const struct got_error *
draw_file(struct tog_view *view, FILE *f, int *first_displayed_line,
- int *last_displayed_line, int *eof, int max_lines,
- char *header)
+ int *last_displayed_line, int *eof, int max_lines, char *header,
+ struct tog_line_colors *colors)
{
const struct got_error *err;
int nlines = 0, nprinted = 0;
char *line;
+ struct tog_line_color *lc;
size_t len;
wchar_t *wline;
int width;
free(line);
return err;
}
+
+ lc = match_line_color(colors, line);
+ if (lc)
+ wattr_on(view->window,
+ COLOR_PAIR(lc->colorpair), NULL);
waddwstr(view->window, wline);
+ if (lc)
+ wattr_off(view->window,
+ COLOR_PAIR(lc->colorpair), NULL);
if (width <= view->ncols - 1)
waddch(view->window, '\n');
if (++nprinted == 1)
mvwaddstr(view->window, 0, 0, "diffing...");
update_panels();
doupdate();
+}
+
+static const struct got_error *
+add_line_color(struct tog_line_colors *colors, const char *pattern,
+ int idx, short color)
+{
+ const struct got_error *err = NULL;
+ struct tog_line_color *lc;
+ int regerr = 0;
+
+ init_pair(idx, color, -1);
+
+ lc = calloc(1, sizeof(*lc));
+ if (lc == NULL)
+ return got_error_from_errno("calloc");
+ regerr = regcomp(&lc->regex, pattern,
+ REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ if (regerr) {
+ static char regerr_msg[512];
+ static char err_msg[512];
+ regerror(regerr, &lc->regex, regerr_msg,
+ sizeof(regerr_msg));
+ snprintf(err_msg, sizeof(err_msg), "regcomp: %s",
+ regerr_msg);
+ err = got_error_msg(GOT_ERR_REGEX, err_msg);
+ free(lc);
+ return err;
+ }
+ lc->colorpair = idx;
+ SIMPLEQ_INSERT_HEAD(colors, lc, entry);
+ return NULL;
+}
+
+void
+free_line_colors(struct tog_line_colors *colors)
+{
+ struct tog_line_color *lc;
+
+ while (!SIMPLEQ_EMPTY(colors)) {
+ lc = SIMPLEQ_FIRST(colors);
+ SIMPLEQ_REMOVE_HEAD(colors, entry);
+ regfree(&lc->regex);
+ free(lc);
+ }
+}
+
+static int
+default_color_value(const char *envvar)
+{
+ if (strcmp(envvar, "TOG_COLOR_DIFF_MINUS") == 0)
+ return COLOR_MAGENTA;
+ if (strcmp(envvar, "TOG_COLOR_DIFF_PLUS") == 0)
+ return COLOR_CYAN;
+ if (strcmp(envvar, "TOG_COLOR_DIFF_CHUNK_HEADER") == 0)
+ return COLOR_YELLOW;
+ if (strcmp(envvar, "TOG_COLOR_DIFF_META") == 0)
+ return COLOR_GREEN;
+
+ return -1;
+}
+
+static int
+get_color_value(const char *envvar)
+{
+ const char *val = getenv(envvar);
+
+ if (val == NULL)
+ return default_color_value(envvar);
+
+ if (strcasecmp(val, "black") == 0)
+ return COLOR_BLACK;
+ if (strcasecmp(val, "red") == 0)
+ return COLOR_RED;
+ if (strcasecmp(val, "green") == 0)
+ return COLOR_GREEN;
+ if (strcasecmp(val, "yellow") == 0)
+ return COLOR_YELLOW;
+ if (strcasecmp(val, "blue") == 0)
+ return COLOR_BLUE;
+ if (strcasecmp(val, "magenta") == 0)
+ return COLOR_MAGENTA;
+ if (strcasecmp(val, "cyan") == 0)
+ return COLOR_CYAN;
+ if (strcasecmp(val, "white") == 0)
+ return COLOR_WHITE;
+
+ return default_color_value(envvar);
}
static const struct got_error *
view->state.diff.log_view = log_view;
view->state.diff.repo = repo;
view->state.diff.refs = refs;
+ SIMPLEQ_INIT(&view->state.diff.line_colors);
+
+ if (has_colors() && getenv("TOG_COLORS") != NULL) {
+ err = add_line_color(&view->state.diff.line_colors,
+ "^-", 1, get_color_value("TOG_COLOR_DIFF_MINUS"));
+ if (err)
+ return err;
+ err = add_line_color(&view->state.diff.line_colors,
+ "^\\+", 2, get_color_value("TOG_COLOR_DIFF_PLUS"));
+ if (err) {
+ free_line_colors(&view->state.diff.line_colors);
+ return err;
+ }
+ err = add_line_color(&view->state.diff.line_colors,
+ "^@@", 3,
+ get_color_value("TOG_COLOR_DIFF_CHUNK_HEADER"));
+ if (err) {
+ free_line_colors(&view->state.diff.line_colors);
+ return err;
+ }
+
+ err = add_line_color(&view->state.diff.line_colors,
+ "^(commit|(blob|file) [-+] )", 4,
+ get_color_value("TOG_COLOR_DIFF_META"));
+ if (err) {
+ free_line_colors(&view->state.diff.line_colors);
+ return err;
+ }
+ }
if (log_view && view_is_splitscreen(view))
show_log_view(log_view); /* draw vborder */
view->state.diff.id2 = NULL;
if (view->state.diff.f && fclose(view->state.diff.f) == EOF)
err = got_error_from_errno("fclose");
+ free_line_colors(&view->state.diff.line_colors);
return err;
}
return draw_file(view, s->f, &s->first_displayed_line,
&s->last_displayed_line, &s->eof, view->nlines,
- header);
+ header, &s->line_colors);
}
static const struct got_error *
return NULL;
}
-static int
-match_line(const char *line, regex_t *regex)
-{
- regmatch_t regmatch;
-
- return regexec(regex, line, 1, ®match, 0) == 0;
-}
-
-
static const struct got_error *
search_next_blame_view(struct tog_view *view)
{