Skip to content

Commit

Permalink
Allow use of regular expressions for coloring
Browse files Browse the repository at this point in the history
When defining colors, strings of the form "/.../" will be interpreted as
regular expressions.

E.g. color "/([^:]+):([0-9]+):(|([0-9]+):)[ \t]+(note|warning|error): (.*)(\[-W([a-zA-Z0-8_-]+)\]|)/"	yellow	default	bold

Closes #1249

Suggested-by: Sebastian Gniazdowski <[email protected]>
  • Loading branch information
koutcher committed Jan 1, 2023
1 parent abe103d commit d803c7b
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 10 deletions.
5 changes: 4 additions & 1 deletion doc/tigrc.5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,8 @@ color diff-chunk magenta default
color "Reported-by:" green default
# View-specific color
color tree.date black cyan bold
# Custom color
color "/(note|warning|error):/" yellow default bold
--------------------------------------------------------------------------
Or in the Git configuration files:
Expand All @@ -998,7 +1000,8 @@ Area names::
Can be either a built-in area name or a custom quoted string. The
latter allows custom color rules to be added for lines matching a
quoted string.
quoted string. Strings of the form "/.../" are interpreted as
regular expressions.
Valid built-in area names are described below. Note, all names are
case-insensitive, and you may use '-', and '_' interchangeably,
e.g. "Diff-Header" and "DIFF_HEADER" are the same.
Expand Down
1 change: 1 addition & 0 deletions include/tig/line.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ struct line_rule {
int namelen; /* Size of option name. */
const char *line; /* The start of line to match. */
int linelen; /* Size of string to match. */
regex_t *regex; /* Pre-compiled regexp. */
struct line_info info; /* List of line info matching this rule. */
};

Expand Down
22 changes: 15 additions & 7 deletions src/line.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ get_line_type(const char *line)
for (type = 0; type < line_rules; type++) {
struct line_rule *rule = &line_rule[type];

if (rule->regex && !regexec(rule->regex, line, 0, NULL, 0))
return type;

/* Case insensitive search matches Signed-off-by lines better. */
if (rule->linelen && linelen >= rule->linelen &&
!strncasecmp(rule->line, line, rule->linelen))
Expand Down Expand Up @@ -89,7 +92,7 @@ get_line_info(const char *prefix, enum line_type type)
}

static struct line_info *
init_line_info(const char *prefix, const char *name, size_t namelen, const char *line, size_t linelen)
init_line_info(const char *prefix, const char *name, size_t namelen, const char *line, size_t linelen, regex_t *regex)
{
struct line_rule *rule;

Expand All @@ -101,6 +104,7 @@ init_line_info(const char *prefix, const char *name, size_t namelen, const char
rule->namelen = namelen;
rule->line = line;
rule->linelen = linelen;
rule->regex = regex;

rule->info.prefix = prefix;
rule->info.fg = COLOR_DEFAULT;
Expand All @@ -110,7 +114,7 @@ init_line_info(const char *prefix, const char *name, size_t namelen, const char
}

#define INIT_BUILTIN_LINE_INFO(type, line) \
init_line_info(NULL, #type, STRING_SIZE(#type), (line), STRING_SIZE(line))
init_line_info(NULL, #type, STRING_SIZE(#type), (line), STRING_SIZE(line), NULL)

static struct line_rule *
find_line_rule(struct line_rule *query)
Expand Down Expand Up @@ -145,11 +149,15 @@ add_line_rule(const char *prefix, struct line_rule *query)
if (query->name)
return NULL;

/* Quoted line. */
query->line = strndup(query->line, query->linelen);
if (!query->line)
return NULL;
return init_line_info(prefix, "", 0, query->line, query->linelen);
return init_line_info(prefix, "", 0, query->line, query->linelen, query->regex);
}

/* When a rule already exists and we are just adding view-specific
* colors, query->line and query->regex can be freed. */
free((void *) query->line);
if (query->regex) {
regfree(query->regex);
free(query->regex);
}

for (info = &rule->info; info; last = info, info = info->next)
Expand Down
41 changes: 39 additions & 2 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,46 @@ parse_color_name(const char *color, struct line_rule *rule, const char **prefix_

memset(rule, 0, sizeof(*rule));
if (is_quoted(*color)) {
rule->line = color + 1;
rule->linelen = strlen(color) - 2;
/* Interpret strings of the form "/.../" as regular expressions. */
if (strlen(color) >= 4 && color[1] == '/' && color[strlen(color) - 2] == '/') {
int regex_err;

/* rule->line and rule->regex are allocated here rather
* than in add_line_rule() to allow proper error reporting.
* Though only rule->regex will be used for matching regular
* expressions, rule->line and rule->linelen are still filled
* to look up exiting rules when defining view-specific
* colors. */
rule->linelen = strlen(color) - 4;
rule->line = strndup(color + 2, rule->linelen);
if (!rule->line)
return ERROR_OUT_OF_MEMORY;

rule->regex = calloc(1, sizeof(*rule->regex));
if (!rule->regex) {
free((void *) rule->line);
return ERROR_OUT_OF_MEMORY;
}

regex_err = regcomp(rule->regex, rule->line, REG_EXTENDED);

if (regex_err != 0) {
char buf[SIZEOF_STR];
regerror(regex_err, rule->regex, buf, sizeof(buf));
free((void *) rule->line);
free(rule->regex);
return error("Invalid color mapping: %s", buf);
}
} else {
rule->linelen = strlen(color) - 2;
rule->line = strndup(color + 1, rule->linelen);
if (!rule->line)
return ERROR_OUT_OF_MEMORY;
}
} else {
/* Built-in area names are preloaded on first call to
* find_line_rule(), so rule->name is only used to look
* up an existing rule and does not need to persist. */
rule->name = color;
rule->namelen = strlen(color);
}
Expand Down

0 comments on commit d803c7b

Please sign in to comment.