Skip to content

Commit 0cfb6ab

Browse files
committed
diff: highlight and error out on incomplete lines
Teach "git diff" to highlight "\ No newline at end of file" message as a whitespace error when incomplete-line whitespace error class is in effect. Thanks to the previous refactoring of complete rewrite code path, we can do this at a single place. Unlike whitespace errors in the payload where we need to annotate in line, possibly using colors, the line that has whitespace problems, we have a dedicated line already that can serve as the error message, so paint it as a whitespace error message. Also teach "git diff --check" to notice incomplete lines as whitespace errors and report when incomplete-line whitespace error class is in effect. Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 806aa30 commit 0cfb6ab

File tree

2 files changed

+86
-6
lines changed

2 files changed

+86
-6
lines changed

diff.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,7 +1370,11 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
13701370
emit_line(o, "", "", line, len);
13711371
break;
13721372
case DIFF_SYMBOL_CONTEXT_INCOMPLETE:
1373-
set = diff_get_color_opt(o, DIFF_CONTEXT);
1373+
if ((flags & WS_INCOMPLETE_LINE) &&
1374+
(flags & o->ws_error_highlight))
1375+
set = diff_get_color_opt(o, DIFF_WHITESPACE);
1376+
else
1377+
set = diff_get_color_opt(o, DIFF_CONTEXT);
13741378
reset = diff_get_color_opt(o, DIFF_RESET);
13751379
emit_line(o, set, reset, line, len);
13761380
break;
@@ -1666,8 +1670,14 @@ static void emit_context_line(struct emit_callback *ecbdata,
16661670
static void emit_incomplete_line(struct emit_callback *ecbdata,
16671671
const char *line, int len)
16681672
{
1673+
int last_line_kind = ecbdata->last_line_kind;
1674+
unsigned flags = (last_line_kind == '+'
1675+
? WSEH_NEW
1676+
: last_line_kind == '-'
1677+
? WSEH_OLD
1678+
: WSEH_CONTEXT) | ecbdata->ws_rule;
16691679
emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_CONTEXT_INCOMPLETE,
1670-
line, len, 0);
1680+
line, len, flags);
16711681
}
16721682

16731683
static void emit_hunk_header(struct emit_callback *ecbdata,
@@ -3257,6 +3267,7 @@ struct checkdiff_t {
32573267
struct diff_options *o;
32583268
unsigned ws_rule;
32593269
unsigned status;
3270+
int last_line_kind;
32603271
};
32613272

32623273
static int is_conflict_marker(const char *line, int marker_size, unsigned long len)
@@ -3295,6 +3306,7 @@ static void checkdiff_consume_hunk(void *priv,
32953306
static int checkdiff_consume(void *priv, char *line, unsigned long len)
32963307
{
32973308
struct checkdiff_t *data = priv;
3309+
int last_line_kind;
32983310
int marker_size = data->conflict_marker_size;
32993311
const char *ws = diff_get_color(data->o->use_color, DIFF_WHITESPACE);
33003312
const char *reset = diff_get_color(data->o->use_color, DIFF_RESET);
@@ -3305,6 +3317,8 @@ static int checkdiff_consume(void *priv, char *line, unsigned long len)
33053317
assert(data->o);
33063318
line_prefix = diff_line_prefix(data->o);
33073319

3320+
last_line_kind = data->last_line_kind;
3321+
data->last_line_kind = line[0];
33083322
if (line[0] == '+') {
33093323
unsigned bad;
33103324
data->lineno++;
@@ -3327,6 +3341,17 @@ static int checkdiff_consume(void *priv, char *line, unsigned long len)
33273341
data->o->file, set, reset, ws);
33283342
} else if (line[0] == ' ') {
33293343
data->lineno++;
3344+
} else if (line[0] == '\\') {
3345+
/* no newline at the end of the line */
3346+
if ((data->ws_rule & WS_INCOMPLETE_LINE) &&
3347+
(last_line_kind == '+')) {
3348+
unsigned bad = WS_INCOMPLETE_LINE;
3349+
data->status |= bad;
3350+
err = whitespace_error_string(bad);
3351+
fprintf(data->o->file, "%s%s:%d: %s.\n",
3352+
line_prefix, data->filename, data->lineno, err);
3353+
free(err);
3354+
}
33303355
}
33313356
return 0;
33323357
}

t/t4015-diff-whitespace.sh

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,49 @@ do
4343
'
4444
done
4545

46+
test_expect_success "incomplete line in both pre- and post-image context" '
47+
(echo foo && echo baz | tr -d "\012") >x &&
48+
git add x &&
49+
(echo bar && echo baz | tr -d "\012") >x &&
50+
git diff x &&
51+
git -c core.whitespace=incomplete diff --check x &&
52+
git diff -R x &&
53+
git -c core.whitespace=incomplete diff -R --check x
54+
'
55+
56+
test_expect_success "incomplete lines on both pre- and post-image" '
57+
# The interpretation taken here is "since you are toucing
58+
# the line anyway, you would better fix the incomplete line
59+
# while you are at it." but this is debatable.
60+
echo foo | tr -d "\012" >x &&
61+
git add x &&
62+
echo bar | tr -d "\012" >x &&
63+
git diff x &&
64+
test_must_fail git -c core.whitespace=incomplete diff --check x &&
65+
git diff -R x &&
66+
test_must_fail git -c core.whitespace=incomplete diff -R --check x
67+
'
68+
69+
test_expect_success "fix incomplete line in pre-image" '
70+
echo foo | tr -d "\012" >x &&
71+
git add x &&
72+
echo bar >x &&
73+
git diff x &&
74+
git -c core.whitespace=incomplete diff --check x &&
75+
git diff -R x &&
76+
test_must_fail git -c core.whitespace=incomplete diff -R --check x
77+
'
78+
79+
test_expect_success "new incomplete line in post-image" '
80+
echo foo >x &&
81+
git add x &&
82+
echo bar | tr -d "\012" >x &&
83+
git diff x &&
84+
test_must_fail git -c core.whitespace=incomplete diff --check x &&
85+
git diff -R x &&
86+
git -c core.whitespace=incomplete diff -R --check x
87+
'
88+
4689
test_expect_success "Ray Lehtiniemi's example" '
4790
cat <<-\EOF >x &&
4891
do {
@@ -1040,7 +1083,8 @@ test_expect_success 'ws-error-highlight test setup' '
10401083
{
10411084
echo "0. blank-at-eol " &&
10421085
echo "1. still-blank-at-eol " &&
1043-
echo "2. and a new line "
1086+
echo "2. and a new line " &&
1087+
printf "3. and more"
10441088
} >x &&
10451089
new_hash_x=$(git hash-object x) &&
10461090
after=$(git rev-parse --short "$new_hash_x") &&
@@ -1050,40 +1094,47 @@ test_expect_success 'ws-error-highlight test setup' '
10501094
<BOLD>index $before..$after 100644<RESET>
10511095
<BOLD>--- a/x<RESET>
10521096
<BOLD>+++ b/x<RESET>
1053-
<CYAN>@@ -1,2 +1,3 @@<RESET>
1097+
<CYAN>@@ -1,2 +1,4 @@<RESET>
10541098
0. blank-at-eol <RESET>
10551099
<RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
10561100
<GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
10571101
<GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1102+
<GREEN>+<RESET><GREEN>3. and more<RESET>
1103+
<BLUE>\ No newline at end of file<RESET>
10581104
EOF
10591105
10601106
cat >expect.all <<-EOF &&
10611107
<BOLD>diff --git a/x b/x<RESET>
10621108
<BOLD>index $before..$after 100644<RESET>
10631109
<BOLD>--- a/x<RESET>
10641110
<BOLD>+++ b/x<RESET>
1065-
<CYAN>@@ -1,2 +1,3 @@<RESET>
1111+
<CYAN>@@ -1,2 +1,4 @@<RESET>
10661112
<RESET>0. blank-at-eol<RESET><BLUE> <RESET>
10671113
<RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
10681114
<GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
10691115
<GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1116+
<GREEN>+<RESET><GREEN>3. and more<RESET>
1117+
<BLUE>\ No newline at end of file<RESET>
10701118
EOF
10711119
10721120
cat >expect.none <<-EOF
10731121
<BOLD>diff --git a/x b/x<RESET>
10741122
<BOLD>index $before..$after 100644<RESET>
10751123
<BOLD>--- a/x<RESET>
10761124
<BOLD>+++ b/x<RESET>
1077-
<CYAN>@@ -1,2 +1,3 @@<RESET>
1125+
<CYAN>@@ -1,2 +1,4 @@<RESET>
10781126
0. blank-at-eol <RESET>
10791127
<RED>-1. blank-at-eol <RESET>
10801128
<GREEN>+1. still-blank-at-eol <RESET>
10811129
<GREEN>+2. and a new line <RESET>
1130+
<GREEN>+3. and more<RESET>
1131+
\ No newline at end of file<RESET>
10821132
EOF
10831133
10841134
'
10851135

10861136
test_expect_success 'test --ws-error-highlight option' '
1137+
git config core.whitespace blank-at-eol,incomplete-line &&
10871138
10881139
git diff --color --ws-error-highlight=default,old >current.raw &&
10891140
test_decode_color <current.raw >current &&
@@ -1100,6 +1151,7 @@ test_expect_success 'test --ws-error-highlight option' '
11001151
'
11011152

11021153
test_expect_success 'test diff.wsErrorHighlight config' '
1154+
git config core.whitespace blank-at-eol,incomplete-line &&
11031155
11041156
git -c diff.wsErrorHighlight=default,old diff --color >current.raw &&
11051157
test_decode_color <current.raw >current &&
@@ -1116,6 +1168,7 @@ test_expect_success 'test diff.wsErrorHighlight config' '
11161168
'
11171169

11181170
test_expect_success 'option overrides diff.wsErrorHighlight' '
1171+
git config core.whitespace blank-at-eol,incomplete-line &&
11191172
11201173
git -c diff.wsErrorHighlight=none \
11211174
diff --color --ws-error-highlight=default,old >current.raw &&
@@ -1135,6 +1188,8 @@ test_expect_success 'option overrides diff.wsErrorHighlight' '
11351188
'
11361189

11371190
test_expect_success 'detect moved code, complete file' '
1191+
git config core.whitespace blank-at-eol &&
1192+
11381193
git reset --hard &&
11391194
cat <<-\EOF >test.c &&
11401195
#include<stdio.h>

0 commit comments

Comments
 (0)