aboutsummaryrefslogtreecommitdiffstats
path: root/diff-1-Add-color-support.patch
blob: 31b1fdedb20ff1c769a92a455202215c26e538ac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
From 392ea394e6ae7fe34aed7b0b98ab4d47b3652df2 Mon Sep 17 00:00:00 2001
From: Cameron Katri <me@cameronkatri.com>
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