Browse Source

diff: Help "less" hide ^M from the output

When the tracked contents have CRLF line endings, colored diff output
shows "^M" at the end of output lines, which is distracting, even though
the pager we use by default ("less") knows to hide them.

The problem is that "less" hides a carriage-return only at the end of the
line, immediately before a line feed.  The colored diff output does not
take this into account, and emits four element sequence for each line:

   - force this color;
   - the line up to but not including the terminating line feed;
   - reset color
   - line feed.

By including the carriage return at the end of the line in the second
item, we are breaking the smart our pager has in order not to show "^M".
This can be fixed by changing the sequence to:

   - force this color;
   - the line up to but not including the terminating end-of-line;
   - reset color
   - end-of-line.

where end-of-line is either a single linefeed or a CRLF pair.  When the
output is not colored, "force this color" and "reset color" sequences are
both empty, so we won't have this problem with or without this patch.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Junio C Hamano 17 years ago
parent
commit
3928097020
  1. 16
      combine-diff.c
  2. 9
      diff.c
  3. 12
      t/t4019-diff-wserror.sh

16
combine-diff.c

@ -500,6 +500,18 @@ static int hunk_comment_line(const char *bol) @@ -500,6 +500,18 @@ static int hunk_comment_line(const char *bol)
return (isalpha(ch) || ch == '_' || ch == '$');
}

static void show_line_to_eol(const char *line, int len, const char *reset)
{
int saw_cr_at_eol = 0;
if (len < 0)
len = strlen(line);
saw_cr_at_eol = (len && line[len-1] == '\r');

printf("%.*s%s%s\n", len - saw_cr_at_eol, line,
reset,
saw_cr_at_eol ? "\r" : "");
}

static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
int use_color)
{
@ -593,7 +605,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, @@ -593,7 +605,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
else
putchar(' ');
}
printf("%s%s\n", ll->line, c_reset);
show_line_to_eol(ll->line, -1, c_reset);
ll = ll->next;
}
if (cnt < lno)
@ -617,7 +629,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, @@ -617,7 +629,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
putchar(' ');
p_mask <<= 1;
}
printf("%.*s%s\n", sl->len, sl->bol, c_reset);
show_line_to_eol(sl->bol, sl->len, c_reset);
}
}
}

9
diff.c

@ -511,13 +511,20 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) @@ -511,13 +511,20 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)

static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
{
int has_trailing_newline = (len > 0 && line[len-1] == '\n');
int has_trailing_newline, has_trailing_carriage_return;

has_trailing_newline = (len > 0 && line[len-1] == '\n');
if (has_trailing_newline)
len--;
has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
if (has_trailing_carriage_return)
len--;

fputs(set, file);
fwrite(line, len, 1, file);
fputs(reset, file);
if (has_trailing_carriage_return)
fputc('\r', file);
if (has_trailing_newline)
fputc('\n', file);
}

12
t/t4019-diff-wserror.sh

@ -178,4 +178,16 @@ test_expect_success 'trailing empty lines (2)' ' @@ -178,4 +178,16 @@ test_expect_success 'trailing empty lines (2)' '

'

test_expect_success 'do not color trailing cr in context' '
git config --unset core.whitespace
rm -f .gitattributes &&
echo AAAQ | tr Q "\015" >G &&
git add G &&
echo BBBQ | tr Q "\015" >>G
git diff --color G | tr "\015" Q >output &&
grep "BBB.*${blue_grep}Q" output &&
grep "AAA.*\[mQ" output

'

test_done

Loading…
Cancel
Save