* doc/diffutils.texi (diff Options): Add documentation for --color. Copied from coreutils ls --color. * src/context.c (pr_unidiff_hunk): Add calls to set_color_context. * src/diff.h (enum colors): New enum to register the current color to use. (enum colors_style): New enum to record when to use colors. (colors_style): New variable to memorize the argument value. (set_color_context): Add function definition. * src/diff.c (specify_colors_style): New function. (BINARY_OPTION): Add COLOR_OPTION. (longopts): Add --color. (main): Handle --color argument. (option_help_msgid): Add usage string for --color. * src/normal.c (print_normal_hunk): Add calls to set_color_context * src/side.c (print_1sdiff_line): Add calls to set_color_context. * src/util.c (colors_enabled): New boolean variable. (check_color_output): New function. (begin_output): Call check_color_output every time the output file is changed. (set_color_context): New function. If colors are enabled, print the right command for the terminal to change the color. ---
I got so used to having colors in git diff that I become unable to quickly spot differences in the plain diff output. This patch fills the gap between the two versions. doc/diffutils.texi | 22 ++++++++++++++++++++++ src/context.c | 4 ++++ src/diff.c | 27 ++++++++++++++++++++++++++- src/diff.h | 30 ++++++++++++++++++++++++++++++ src/normal.c | 16 ++++++++++++---- src/side.c | 15 +++++++++++++++ src/util.c | 36 ++++++++++++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 5 deletions(-) diff --git a/doc/diffutils.texi b/doc/diffutils.texi index 3e25807..bc7169a 100644 --- a/doc/diffutils.texi +++ b/doc/diffutils.texi @@ -3745,6 +3745,28 @@ Read and write data in binary mode. @xref{Binary}. Use the context output format, showing three lines of context. @xref{Context Format}. +@item --color [=@var{when}] +@cindex color, distinguishing file types with +Specify whether to use color for distinguishing file types. @var{when} +may be omitted, or one of: +@itemize @bullet +@item none +@vindex none @r{color option} +- Do not use color at all. This is the default. +@item auto +@vindex auto @r{color option} +@cindex terminal, using color iff +- Only use color if standard output is a terminal. +@item always +@vindex always @r{color option} +- Always use color. +@end itemize +Specifying @option{--color} and no @var{when} is equivalent to +@option{--color=always}. +Piping a colorized listing through a pager like @command{more} or +@command{less} usually produces unreadable results. However, using +@code{more -f} does seem to work. + @item -C @var{lines} @itemx --context@r{[}=@var{lines}@r{]} Use the context output format, showing @var{lines} (an integer) lines of diff --git a/src/context.c b/src/context.c index e0f21c4..88ddfde 100644 --- a/src/context.c +++ b/src/context.c @@ -366,10 +366,12 @@ pr_unidiff_hunk (struct change *hunk) while (k--) { char const * const *line = &files[0].linbuf[i++]; + set_color_context (DELETE); putc ('-', out); if (initial_tab && ! (suppress_blank_empty && **line == '\n')) putc ('\t', out); print_1_line (NULL, line); + set_color_context (RESET); } /* Then output the inserted part. */ @@ -378,10 +380,12 @@ pr_unidiff_hunk (struct change *hunk) while (k--) { char const * const *line = &files[1].linbuf[j++]; + set_color_context (ADD); putc ('+', out); if (initial_tab && ! (suppress_blank_empty && **line == '\n')) putc ('\t', out); print_1_line (NULL, line); + set_color_context (RESET); } /* We're done with this hunk, so on to the next! */ diff --git a/src/diff.c b/src/diff.c index ff28377..7d14877 100644 --- a/src/diff.c +++ b/src/diff.c @@ -70,6 +70,7 @@ static void add_regexp (struct regexp_list *, char const *); static void summarize_regexp_list (struct regexp_list *); static void specify_style (enum output_style); static void specify_value (char const **, char const *, char const *); +static void specify_colors_style (char const *); static void try_help (char const *, char const *) __attribute__((noreturn)); static void check_stdout (void); static void usage (void); @@ -136,7 +137,9 @@ enum UNCHANGED_GROUP_FORMAT_OPTION, OLD_GROUP_FORMAT_OPTION, NEW_GROUP_FORMAT_OPTION, - CHANGED_GROUP_FORMAT_OPTION + CHANGED_GROUP_FORMAT_OPTION, + + COLOR_OPTION, }; static char const group_format_option[][sizeof "--unchanged-group-format"] = @@ -159,6 +162,7 @@ static struct option const longopts[] = {"binary", 0, 0, BINARY_OPTION}, {"brief", 0, 0, 'q'}, {"changed-group-format", 1, 0, CHANGED_GROUP_FORMAT_OPTION}, + {"color", 2, 0, COLOR_OPTION}, {"context", 2, 0, 'C'}, {"ed", 0, 0, 'e'}, {"exclude", 1, 0, 'x'}, @@ -627,6 +631,10 @@ main (int argc, char **argv) specify_value (&group_format[c], optarg, group_format_option[c]); break; + case COLOR_OPTION: + specify_colors_style (optarg); + break; + default: try_help (NULL, NULL); } @@ -940,6 +948,8 @@ static char const * const option_help_msgid[] = { N_("-d, --minimal try hard to find a smaller set of changes"), N_(" --horizon-lines=NUM keep NUM lines of the common prefix and suffix"), N_(" --speed-large-files assume large files and many scattered small changes"), + N_(" --color[=WHEN] colorize the output; WHEN can be 'never', 'auto',"), + N_(" or 'always' (the default); more info below"), "", N_(" --help display this help and exit"), N_("-v, --version output version information and exit"), @@ -1008,6 +1018,21 @@ specify_style (enum output_style style) output_style = style; } } + +/* Set the color mode. */ +static void +specify_colors_style (char const *value) +{ + if (value == NULL || STREQ (value, "always")) + colors_style = ALWAYS; + else if (STREQ (value, "never")) + colors_style = NEVER; + else if (STREQ (value, "auto")) + colors_style = AUTO; + else + try_help ("invalid color '%s'", value); +} + /* Set the last-modified time of *ST to be the current time. */ diff --git a/src/diff.h b/src/diff.h index 465e4bc..cad961b 100644 --- a/src/diff.h +++ b/src/diff.h @@ -38,6 +38,32 @@ enum changes /* Both deletes and inserts: a hunk containing both old and new lines. */ CHANGED }; + +/* What kind of changes a hunk contains. */ +enum colors +{ + /* Reset to the default color. */ + RESET, + + /* Delete lines. Show output in red. */ + DELETE, + + /* Added lines. Show them in green. */ + ADD, +}; + +/* What kind of changes a hunk contains. */ +enum colors_style +{ + /* Never output colors. */ + NEVER, + + /* Output colors if the output is a terminal. */ + AUTO, + + /* Always output colors. */ + ALWAYS, +}; /* Variables for command line options */ @@ -83,6 +109,9 @@ enum output_style XTERN enum output_style output_style; +/* True if colors are printed. */ +XTERN enum colors_style colors_style; + /* Nonzero if output cannot be generated for identical files. */ XTERN bool no_diff_means_no_output; @@ -390,3 +419,4 @@ extern void print_script (struct change *, struct change * (*) (struct change *) extern void setup_output (char const *, char const *, bool); extern void translate_range (struct file_data const *, lin, lin, long int *, long int *); +extern void set_color_context (enum colors); diff --git a/src/normal.c b/src/normal.c index 721fd1a..c5211cb 100644 --- a/src/normal.c +++ b/src/normal.c @@ -56,14 +56,22 @@ print_normal_hunk (struct change *hunk) /* Print the lines that the first file has. */ if (changes & OLD) - for (i = first0; i <= last0; i++) - print_1_line ("<", &files[0].linbuf[i]); + { + set_color_context (DELETE); + for (i = first0; i <= last0; i++) + print_1_line ("<", &files[0].linbuf[i]); + set_color_context (RESET); + } if (changes == CHANGED) fputs ("---\n", outfile); /* Print the lines that the second file has. */ if (changes & NEW) - for (i = first1; i <= last1; i++) - print_1_line (">", &files[1].linbuf[i]); + { + set_color_context (ADD); + for (i = first1; i <= last1; i++) + print_1_line (">", &files[1].linbuf[i]); + set_color_context (RESET); + } } diff --git a/src/side.c b/src/side.c index 155512c..e52454e 100644 --- a/src/side.c +++ b/src/side.c @@ -206,6 +206,18 @@ print_1sdiff_line (char const *const *left, char sep, size_t c2o = sdiff_column2_offset; size_t col = 0; bool put_newline = false; + bool color_to_reset = false; + + if (sep == '<') + { + set_color_context (DELETE); + color_to_reset = true; + } + else if (sep == '>') + { + set_color_context (ADD); + color_to_reset = true; + } if (left) { @@ -233,6 +245,9 @@ print_1sdiff_line (char const *const *left, char sep, if (put_newline) putc ('\n', out); + + if (color_to_reset) + set_color_context (RESET); } /* Print lines common to both files in side-by-side format. */ diff --git a/src/util.c b/src/util.c index 2d6d3fc..3687b5e 100644 --- a/src/util.c +++ b/src/util.c @@ -153,6 +153,17 @@ print_message_queue (void) static char const *current_name0; static char const *current_name1; static bool currently_recursive; +static bool colors_enabled; + +static void +check_color_output (void) +{ + if (! outfile) + return; + + colors_enabled = (colors_style == ALWAYS) + || (colors_style == AUTO && isatty (fileno (outfile))); +} void setup_output (char const *name0, char const *name1, bool recursive) @@ -313,6 +324,7 @@ begin_output (void) outfile = fdopen (pipes[1], "w"); if (!outfile) pfatal_with_name ("fdopen"); + check_color_output (); } #else char *command = system_quote_argv (SCI_SYSTEM, (char **) argv); @@ -320,6 +332,7 @@ begin_output (void) outfile = popen (command, "w"); if (!outfile) pfatal_with_name (command); + check_color_output (); free (command); #endif } @@ -330,6 +343,7 @@ begin_output (void) /* If -l was not specified, output the diff straight to 'stdout'. */ outfile = stdout; + check_color_output (); /* If handling multiple files (because scanning a directory), print which files the following output is about. */ @@ -717,6 +731,28 @@ output_1_line (char const *base, char const *limit, char const *flag_format, } } +void +set_color_context (enum colors con) +{ + if (! colors_enabled) + return; + + switch (con) + { + case DELETE: + fprintf (outfile, "\x1B[31m"); + break; + + case ADD: + fprintf (outfile, "\x1B[32m"); + break; + + case RESET: + fprintf(outfile, "\x1b[0m"); + break; + } +} + char const change_letter[] = { 0, 'd', 'a', 'c' }; /* Translate an internal line number (an index into diff's table of lines) -- 2.1.0