[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add suppo
From: |
Giuseppe Scrivano |
Subject: |
[bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color |
Date: |
Wed, 11 Mar 2015 20:58:15 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.4 (gnu/linux) |
Paul Eggert <address@hidden> writes:
> There's no limit on line length though, right? Other than available
> memory. So this could be a problem. ('ls' doesn't have a similar
> problem, if I understand it correctly, as OSes typically have
> reasonably short limits on file name length.)
>
>>> >Also, 'diff --color' needn't mess with signal handling unless isatty
>>> >(fileno (outfile)).
>> Should this also be done if --color=always is used?
>
> Yes. diff needs to mess with signal handling only if both (1) diff is
> outputting colors and (2) the output is a terminal. This is
> independent of why diff is doing (1).
ok, thanks for the explanation. I've addressed your comments in the
version below.
Now I make sure that we don't write more than "max_chunk" bytes in
output_1_line and unblock/block the signals.
Regards,
Giuseppe
>From 41b868be5adb8c3de2c57c235693d1f2ec426b12 Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <address@hidden>
Date: Sun, 8 Mar 2015 22:45:11 +0100
Subject: [PATCH] diff: add support for --color
* bootstrap.conf (gnulib_modules): Add "sigprocmask".
* 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: : Define COLOR_OPTION.
(specify_colors_style): New function.
(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.
(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.
---
bootstrap.conf | 1 +
doc/diffutils.texi | 20 +++++++++
src/context.c | 4 ++
src/diff.c | 30 +++++++++++++-
src/diff.h | 34 +++++++++++++++
src/normal.c | 20 +++++++--
src/side.c | 15 +++++++
src/util.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++---
8 files changed, 234 insertions(+), 10 deletions(-)
diff --git a/bootstrap.conf b/bootstrap.conf
index 9b2de22..63be732 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -61,6 +61,7 @@ readme-release
regex
sh-quote
signal
+sigprocmask
stat
stat-macros
stat-time
diff --git a/doc/diffutils.texi b/doc/diffutils.texi
index 3e25807..92a7243 100644
--- a/doc/diffutils.texi
+++ b/doc/diffutils.texi
@@ -3745,6 +3745,26 @@ Read and write data in binary mode. @xref{Binary}.
Use the context output format, showing three lines of context.
@xref{Context Format}.
address@hidden --color address@hidden
address@hidden color, distinguishing file types with
+Specify whether to use color for distinguishing file types. @var{when}
+may be omitted, or one of:
address@hidden @bullet
address@hidden none
address@hidden none @r{color option}
+- Do not use color at all. This is the default when no --color option
+is present.
address@hidden auto
address@hidden auto @r{color option}
address@hidden terminal, using color iff
+- Only use color if standard output is a terminal.
address@hidden always
address@hidden always @r{color option}
+- Always use color.
address@hidden itemize
+Specifying @option{--color} and no @var{when} is equivalent to
address@hidden
+
@item -C @var{lines}
@itemx address@hidden@address@hidden
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..07fcb57 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);
}
@@ -645,6 +653,9 @@ main (int argc, char **argv)
specify_style (OUTPUT_NORMAL);
}
+ if (colors_style != NEVER && paginate)
+ error (EXIT_TROUBLE, 0, _("Cannot specify both --color and --paginate."));
+
if (output_style != OUTPUT_CONTEXT || hard_locale (LC_TIME))
{
#if (defined STAT_TIMESPEC || defined STAT_TIMESPEC_NS \
@@ -940,6 +951,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',
'always',"),
+ N_(" or 'auto' (the default)"),
"",
N_(" --help display this help and exit"),
N_("-v, --version output version information and exit"),
@@ -1008,6 +1021,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, "auto"))
+ colors_style = AUTO;
+ else if (STREQ (value, "always"))
+ colors_style = ALWAYS;
+ else if (STREQ (value, "never"))
+ colors_style = NEVER;
+ 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..0291fdd 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -38,6 +38,36 @@ 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,
+
+ /* Does not modify the context. Use it to periodically process pending
+ signals. */
+ SAME,
+};
+
+/* 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 +113,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 +423,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..0d53033 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -56,14 +56,26 @@ 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]);
+ {
+ for (i = first0; i <= last0; i++)
+ {
+ set_color_context (DELETE);
+ 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]);
+ {
+ for (i = first1; i <= last1; i++)
+ {
+ set_color_context (ADD);
+ 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..dcb3a59 100644
--- a/src/util.c
+++ b/src/util.c
@@ -24,6 +24,7 @@
#include <system-quote.h>
#include <xalloc.h>
#include "xvasprintf.h"
+#include <signal.h>
char const pr_program[] = PR_PROGRAM;
@@ -153,6 +154,20 @@ print_message_queue (void)
static char const *current_name0;
static char const *current_name1;
static bool currently_recursive;
+static bool colors_enabled;
+static bool output_is_tty;
+
+static void
+check_color_output (void)
+{
+ if (! outfile)
+ return;
+
+ output_is_tty = isatty (fileno (outfile));
+
+ colors_enabled = (colors_style == ALWAYS)
+ || (colors_style == AUTO && output_is_tty);
+}
void
setup_output (char const *name0, char const *name1, bool recursive)
@@ -313,6 +328,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 +336,7 @@ begin_output (void)
outfile = popen (command, "w");
if (!outfile)
pfatal_with_name (command);
+ check_color_output ();
free (command);
#endif
}
@@ -330,6 +347,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. */
@@ -672,8 +690,20 @@ void
output_1_line (char const *base, char const *limit, char const *flag_format,
char const *line_flag)
{
+ /* Try to avoid to block for too long and write more than MAX_CHUNK bytes
before
+ checking for pending signals. */
+ const size_t max_chunk = 4096;
if (!expand_tabs)
- fwrite (base, sizeof (char), limit - base, outfile);
+ {
+ size_t left = limit - base;
+ while (left)
+ {
+ size_t len = MIN (left, max_chunk);
+ fwrite (base, sizeof (char), len, outfile);
+ set_color_context (SAME);
+ left -= len;
+ }
+ }
else
{
register FILE *out = outfile;
@@ -681,6 +711,7 @@ output_1_line (char const *base, char const *limit, char
const *flag_format,
register char const *t = base;
register size_t column = 0;
size_t tab_size = tabsize;
+ size_t written = 0;
while (t < limit)
switch ((c = *t++))
@@ -690,7 +721,9 @@ output_1_line (char const *base, char const *limit, char
const *flag_format,
size_t spaces = tab_size - column % tab_size;
column += spaces;
do
- putc (' ', out);
+ {
+ written += putc (' ', out);
+ }
while (--spaces);
}
break;
@@ -698,7 +731,7 @@ output_1_line (char const *base, char const *limit, char
const *flag_format,
case '\r':
putc (c, out);
if (flag_format && t < limit && *t != '\n')
- fprintf (out, flag_format, line_flag);
+ written += fprintf (out, flag_format, line_flag);
column = 0;
break;
@@ -706,17 +739,94 @@ output_1_line (char const *base, char const *limit, char
const *flag_format,
if (column == 0)
continue;
column--;
- putc (c, out);
+ written += putc (c, out);
break;
default:
column += isprint (c) != 0;
- putc (c, out);
+ written += putc (c, out);
+ if (written >= max_chunk)
+ {
+ set_color_context (SAME);
+ written = 0;
+ }
break;
}
}
}
+static sigset_t old_sigproc_set;
+void
+set_color_context (enum colors con)
+{
+ int j;
+ static sigset_t set;
+ static bool set_initialized;
+ static enum colors last_color_context = RESET;
+ static int const sig[] =
+ {
+ SIGTSTP,
+ SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM,
+#ifdef SIGPOLL
+ SIGPOLL,
+#endif
+#ifdef SIGPROF
+ SIGPROF,
+#endif
+#ifdef SIGVTALRM
+ SIGVTALRM,
+#endif
+#ifdef SIGXCPU
+ SIGXCPU,
+#endif
+#ifdef SIGXFSZ
+ SIGXFSZ,
+#endif
+ };
+
+ if (!colors_enabled || (con == SAME && !output_is_tty))
+ return;
+
+ if (output_is_tty && !set_initialized)
+ {
+ sigemptyset (&set);
+ for (j = 0; j < sizeof (sig) / sizeof (*sig); j++)
+ sigaddset (&set, sig[j]);
+ set_initialized = true;
+ }
+
+repeat:
+ switch (con)
+ {
+ case DELETE:
+ if (output_is_tty)
+ sigprocmask (SIG_BLOCK, &set, &old_sigproc_set);
+ fprintf (outfile, "\x1B[31m");
+ break;
+
+ case ADD:
+ if (output_is_tty)
+ sigprocmask (SIG_BLOCK, &set, &old_sigproc_set);
+ fprintf (outfile, "\x1B[32m");
+ break;
+
+ case SAME:
+ case RESET:
+ fprintf (outfile, "\x1b[0m");
+ fflush (outfile);
+ if (output_is_tty)
+ sigprocmask (SIG_SETMASK, &old_sigproc_set, NULL);
+ if (con == SAME)
+ {
+ con = last_color_context;
+ goto repeat;
+ }
+ break;
+ }
+
+ last_color_context = con;
+}
+
char const change_letter[] = { 0, 'd', 'a', 'c' };
/* Translate an internal line number (an index into diff's table of lines)
--
2.1.0
- [bug-diffutils] bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/08
- [bug-diffutils] bug#20062: bug#20062: [PATCH] diff: add support for --color, Eric Blake, 2015/03/09
- [bug-diffutils] bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/09
- [bug-diffutils] bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/10
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/10
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/10
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/10
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/10
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/10
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color,
Giuseppe Scrivano <=
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/11
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/12
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/12
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/12
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/12
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/12
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/12
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Paul Eggert, 2015/03/12
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/13
- [bug-diffutils] bug#20062: bug#20062: bug#20062: [PATCH] diff: add support for --color, Giuseppe Scrivano, 2015/03/13