From 392ea394e6ae7fe34aed7b0b98ab4d47b3652df2 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Fri, 28 May 2021 15:21:45 -0400 Subject: [PATCH] diff(1): Add --color support --- usr.bin/diff/diff.1 | 17 +++++++++++++++++ usr.bin/diff/diff.c | 39 ++++++++++++++++++++++++++++++++++++++- usr.bin/diff/diff.h | 3 ++- usr.bin/diff/diffreg.c | 16 ++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/usr.bin/diff/diff.1 b/usr.bin/diff/diff.1 index e0a790f6efb..50fd43902d5 100644 --- a/usr.bin/diff/diff.1 +++ b/usr.bin/diff/diff.1 @@ -44,6 +44,7 @@ .Fl n | q | u | y .Oc .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -71,6 +72,7 @@ .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern .Op Fl L Ar label | Fl -label Ar label .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -96,6 +98,7 @@ .Op Fl aBbdiltw .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -122,6 +125,7 @@ .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern .Op Fl L Ar label | Fl -label Ar label .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -150,6 +154,7 @@ .Fl n | q | u .Oc .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -context .Op Fl -ed @@ -184,6 +189,7 @@ .Ar dir1 dir2 .Nm diff .Op Fl aBbditwW +.Op Fl -color Ns = Ns Ar when .Op Fl -expand-tabs .Op Fl -ignore-all-blanks .Op Fl -ignore-blank-lines @@ -332,6 +338,17 @@ Causes chunks that include only blank lines to be ignored. .It Fl b -ignore-space-change Causes trailing blanks (spaces and tabs) to be ignored, and other strings of blanks to compare equal. +.It Fl Fl color= Ns Oo Ar when Oc +Mark up the matching text with the expression stored in the +.Ev DIFFCOLOR +environment variable. +The possible values of +.Ar when +are +.Dq Cm never , +.Dq Cm always +and +.Dq Cm auto . .It Fl d -minimal Try very hard to produce a diff as small as possible. This may consume a lot of processing power and memory when processing diff --git a/usr.bin/diff/diff.c b/usr.bin/diff/diff.c index 1bad6226f49..5204f85ed1c 100644 --- a/usr.bin/diff/diff.c +++ b/usr.bin/diff/diff.c @@ -38,11 +38,12 @@ __FBSDID("$FreeBSD$"); #include "diff.h" #include "xmalloc.h" -int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag; +int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag, colorflag = 0; int diff_format, diff_context, status, ignore_file_case, suppress_common; int tabsize = 8, width = 130; char *start, *ifdefname, *diffargs, *label[2], *ignore_pats; char *group_format = NULL; +const char *add_code, *del_code; struct stat stb1, stb2; struct excludes *excludes_list; regex_t ignore_re; @@ -57,6 +58,7 @@ enum { OPT_HORIZON_LINES, OPT_CHANGED_GROUP_FORMAT, OPT_SUPPRESS_COMMON, + OPT_COLOR, }; static struct option longopts[] = { @@ -97,6 +99,7 @@ static struct option longopts[] = { { "tabsize", required_argument, NULL, OPT_TSIZE }, { "changed-group-format", required_argument, NULL, OPT_CHANGED_GROUP_FORMAT}, { "suppress-common-lines", no_argument, NULL, OPT_SUPPRESS_COMMON }, + { "color", optional_argument, NULL, OPT_COLOR }, { NULL, 0, 0, '\0'} }; @@ -106,6 +109,7 @@ void push_excludes(char *); void push_ignore_pats(char *); void read_excludes_file(char *file); void set_argstr(char **, char **); +static const char *init_code(int, const char *); int main(int argc, char **argv) @@ -301,6 +305,21 @@ main(int argc, char **argv) case OPT_SUPPRESS_COMMON: suppress_common = 1; break; + case OPT_COLOR: + if (optarg == NULL || strncmp(optarg, "auto", 4) == 0) + colorflag = isatty(STDOUT_FILENO) ? 1 : 0; + else if (strncmp(optarg, "always", 6) == 0) + colorflag = 1; + else if (strncmp(optarg, "never", 5) == 0) + colorflag = 0; + else + errx(2, "unsupported --color value '%s' (must be always, auto, or never)", + optarg); + if (colorflag) { + add_code = init_code(1, "32"); + del_code = init_code(2, "31"); + } + break; default: usage(); break; @@ -550,3 +569,21 @@ conflicting_format(void) fprintf(stderr, "error: conflicting output format options.\n"); usage(); } + +static const char * +init_code(int i, const char *rv) +{ + char *buf, *p, *env; + int j; + + env = getenv("DIFFCOLORS"); + if (env != NULL && *env != '\0') { + p = strdup(env); + for (j = 0; j < i; j++) + buf = strsep(&p, ":"); + free(p); + if (buf != NULL) + return buf; + } + return rv; +} diff --git a/usr.bin/diff/diff.h b/usr.bin/diff/diff.h index b5536bd7bf7..0c325d004b8 100644 --- a/usr.bin/diff/diff.h +++ b/usr.bin/diff/diff.h @@ -90,12 +90,13 @@ struct excludes { struct excludes *next; }; -extern int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag; +extern int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag, colorflag; extern int diff_format, diff_context, status, ignore_file_case; extern int suppress_common; extern int tabsize, width; extern char *start, *ifdefname, *diffargs, *label[2], *ignore_pats; extern char *group_format; +extern const char *add_code, *del_code; extern struct stat stb1, stb2; extern struct excludes *excludes_list; extern regex_t ignore_re; diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c index 1b28281024c..6b01af67a82 100644 --- a/usr.bin/diff/diffreg.c +++ b/usr.bin/diff/diffreg.c @@ -1183,13 +1183,23 @@ change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d, } } if (diff_format == D_SIDEBYSIDE) { + if (colorflag && (a>b)) + printf("\033[%sm", add_code); + else if (colorflag && (c>d)) + printf("\033[%sm", del_code); if (a > b) { print_space(0, hw + padding , *pflags); } else { nc = fetch(ixold, a, b, f1, '\0', 1, *pflags); print_space(nc, hw - nc + padding, *pflags); } + if (colorflag && (a>b)) + printf("\033[%sm", add_code); + else if (colorflag && (c>d)) + printf("\033[%sm", del_code); printf("%c", (a>b)? '>' : ((c>d)? '<' : '|')); + if (colorflag && (c>d)) + printf("\33[m"); print_space(hw + padding + 1 , padding, *pflags); fetch(ixnew, c, d, f2, '\0', 0, *pflags); printf("\n"); @@ -1263,6 +1273,10 @@ fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) nc = hw; if ((diff_format != D_IFDEF && diff_format != D_GFORMAT) && ch != '\0') { + if (colorflag && (ch == '>' || ch == '+')) + printf("\033[%sm", add_code); + else if (colorflag && (ch == '<' || ch == '-')) + printf("\033[%sm", del_code); printf("%c", ch); if (Tflag && (diff_format == D_NORMAL || diff_format == D_CONTEXT || @@ -1335,6 +1349,8 @@ fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) } } } + if (colorflag) + printf("\33[m"); return col; } -- 2.31.1