Skip to content

Commit 3928097

Browse files
committed
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>
1 parent bbb896d commit 3928097

File tree

3 files changed

+34
-3
lines changed

3 files changed

+34
-3
lines changed

combine-diff.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,18 @@ static int hunk_comment_line(const char *bol)
500500
return (isalpha(ch) || ch == '_' || ch == '$');
501501
}
502502

503+
static void show_line_to_eol(const char *line, int len, const char *reset)
504+
{
505+
int saw_cr_at_eol = 0;
506+
if (len < 0)
507+
len = strlen(line);
508+
saw_cr_at_eol = (len && line[len-1] == '\r');
509+
510+
printf("%.*s%s%s\n", len - saw_cr_at_eol, line,
511+
reset,
512+
saw_cr_at_eol ? "\r" : "");
513+
}
514+
503515
static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
504516
int use_color)
505517
{
@@ -593,7 +605,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
593605
else
594606
putchar(' ');
595607
}
596-
printf("%s%s\n", ll->line, c_reset);
608+
show_line_to_eol(ll->line, -1, c_reset);
597609
ll = ll->next;
598610
}
599611
if (cnt < lno)
@@ -617,7 +629,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
617629
putchar(' ');
618630
p_mask <<= 1;
619631
}
620-
printf("%.*s%s\n", sl->len, sl->bol, c_reset);
632+
show_line_to_eol(sl->bol, sl->len, c_reset);
621633
}
622634
}
623635
}

diff.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,13 +511,20 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
511511

512512
static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
513513
{
514-
int has_trailing_newline = (len > 0 && line[len-1] == '\n');
514+
int has_trailing_newline, has_trailing_carriage_return;
515+
516+
has_trailing_newline = (len > 0 && line[len-1] == '\n');
515517
if (has_trailing_newline)
516518
len--;
519+
has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
520+
if (has_trailing_carriage_return)
521+
len--;
517522

518523
fputs(set, file);
519524
fwrite(line, len, 1, file);
520525
fputs(reset, file);
526+
if (has_trailing_carriage_return)
527+
fputc('\r', file);
521528
if (has_trailing_newline)
522529
fputc('\n', file);
523530
}

t/t4019-diff-wserror.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,16 @@ test_expect_success 'trailing empty lines (2)' '
178178
179179
'
180180

181+
test_expect_success 'do not color trailing cr in context' '
182+
git config --unset core.whitespace
183+
rm -f .gitattributes &&
184+
echo AAAQ | tr Q "\015" >G &&
185+
git add G &&
186+
echo BBBQ | tr Q "\015" >>G
187+
git diff --color G | tr "\015" Q >output &&
188+
grep "BBB.*${blue_grep}Q" output &&
189+
grep "AAA.*\[mQ" output
190+
191+
'
192+
181193
test_done

0 commit comments

Comments
 (0)