Merge branch 'jc/maint-1.6.0-blank-at-eof' (early part) into jc/maint-blank-at-eof
* 'jc/maint-1.6.0-blank-at-eof' (early part): diff --whitespace: fix blank lines at end core.whitespace: split trailing-space into blank-at-{eol,eof} diff --color: color blank-at-eof diff --whitespace=warn/error: fix blank-at-eof check diff --whitespace=warn/error: obey blank-at-eof diff.c: the builtin_diff() deals with only two-file comparison apply --whitespace: warn blank but not necessarily empty lines at EOF apply --whitespace=warn/error: diagnose blank at EOF apply.c: split check_whitespace() into two apply --whitespace=fix: detect new blank lines at eof correctly apply --whitespace=fix: fix handling of blank lines at the eof
This commit is contained in:
commit
afd9db4173
@ -401,13 +401,17 @@ core.whitespace::
|
||||
consider them as errors. You can prefix `-` to disable
|
||||
any of them (e.g. `-trailing-space`):
|
||||
+
|
||||
* `trailing-space` treats trailing whitespaces at the end of the line
|
||||
* `blank-at-eol` treats trailing whitespaces at the end of the line
|
||||
as an error (enabled by default).
|
||||
* `space-before-tab` treats a space character that appears immediately
|
||||
before a tab character in the initial indent part of the line as an
|
||||
error (enabled by default).
|
||||
* `indent-with-non-tab` treats a line that is indented with 8 or more
|
||||
space characters as an error (not enabled by default).
|
||||
* `blank-at-eof` treats blank lines added at the end of file as an error
|
||||
(enabled by default).
|
||||
* `trailing-space` is a short-hand to cover both `blank-at-eol` and
|
||||
`blank-at-eof`.
|
||||
* `cr-at-eol` treats a carriage-return at the end of line as
|
||||
part of the line terminator, i.e. with it, `trailing-space`
|
||||
does not trigger if the character before such a carriage-return
|
||||
|
@ -131,6 +131,7 @@ struct fragment {
|
||||
const char *patch;
|
||||
int size;
|
||||
int rejected;
|
||||
int linenr;
|
||||
struct fragment *next;
|
||||
};
|
||||
|
||||
@ -1149,23 +1150,29 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void check_whitespace(const char *line, int len, unsigned ws_rule)
|
||||
static void record_ws_error(unsigned result, const char *line, int len, int linenr)
|
||||
{
|
||||
char *err;
|
||||
unsigned result = ws_check(line + 1, len - 1, ws_rule);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
whitespace_error++;
|
||||
if (squelch_whitespace_errors &&
|
||||
squelch_whitespace_errors < whitespace_error)
|
||||
;
|
||||
else {
|
||||
err = whitespace_error_string(result);
|
||||
fprintf(stderr, "%s:%d: %s.\n%.*s\n",
|
||||
patch_input_file, linenr, err, len - 2, line + 1);
|
||||
free(err);
|
||||
}
|
||||
return;
|
||||
|
||||
err = whitespace_error_string(result);
|
||||
fprintf(stderr, "%s:%d: %s.\n%.*s\n",
|
||||
patch_input_file, linenr, err, len, line);
|
||||
free(err);
|
||||
}
|
||||
|
||||
static void check_whitespace(const char *line, int len, unsigned ws_rule)
|
||||
{
|
||||
unsigned result = ws_check(line + 1, len - 1, ws_rule);
|
||||
|
||||
record_ws_error(result, line + 1, len - 2, linenr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1281,6 +1288,7 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
|
||||
int len;
|
||||
|
||||
fragment = xcalloc(1, sizeof(*fragment));
|
||||
fragment->linenr = linenr;
|
||||
len = parse_fragment(line, size, patch, fragment);
|
||||
if (len <= 0)
|
||||
die("corrupt patch at line %d", linenr);
|
||||
@ -2005,6 +2013,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
||||
int len = linelen(patch, size);
|
||||
int plen, added;
|
||||
int added_blank_line = 0;
|
||||
int is_blank_context = 0;
|
||||
|
||||
if (!len)
|
||||
break;
|
||||
@ -2037,8 +2046,12 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
||||
*new++ = '\n';
|
||||
add_line_info(&preimage, "\n", 1, LINE_COMMON);
|
||||
add_line_info(&postimage, "\n", 1, LINE_COMMON);
|
||||
is_blank_context = 1;
|
||||
break;
|
||||
case ' ':
|
||||
if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
|
||||
ws_blank_line(patch + 1, plen, ws_rule))
|
||||
is_blank_context = 1;
|
||||
case '-':
|
||||
memcpy(old, patch + 1, plen);
|
||||
add_line_info(&preimage, old, plen,
|
||||
@ -2065,7 +2078,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
||||
(first == '+' ? 0 : LINE_COMMON));
|
||||
new += added;
|
||||
if (first == '+' &&
|
||||
added == 1 && new[-1] == '\n')
|
||||
(ws_rule & WS_BLANK_AT_EOF) &&
|
||||
ws_blank_line(patch + 1, plen, ws_rule))
|
||||
added_blank_line = 1;
|
||||
break;
|
||||
case '@': case '\\':
|
||||
@ -2078,6 +2092,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
||||
}
|
||||
if (added_blank_line)
|
||||
new_blank_lines_at_end++;
|
||||
else if (is_blank_context)
|
||||
;
|
||||
else
|
||||
new_blank_lines_at_end = 0;
|
||||
patch += len;
|
||||
@ -2159,17 +2175,24 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
||||
}
|
||||
|
||||
if (applied_pos >= 0) {
|
||||
if (ws_error_action == correct_ws_error &&
|
||||
new_blank_lines_at_end &&
|
||||
postimage.nr + applied_pos == img->nr) {
|
||||
if (new_blank_lines_at_end &&
|
||||
preimage.nr + applied_pos == img->nr &&
|
||||
(ws_rule & WS_BLANK_AT_EOF) &&
|
||||
ws_error_action != nowarn_ws_error) {
|
||||
record_ws_error(WS_BLANK_AT_EOF, "+", 1, frag->linenr);
|
||||
if (ws_error_action == correct_ws_error) {
|
||||
while (new_blank_lines_at_end--)
|
||||
remove_last_line(&postimage);
|
||||
}
|
||||
/*
|
||||
* If the patch application adds blank lines
|
||||
* at the end, and if the patch applies at the
|
||||
* end of the image, remove those added blank
|
||||
* lines.
|
||||
* We would want to prevent write_out_results()
|
||||
* from taking place in apply_patch() that follows
|
||||
* the callchain led us here, which is:
|
||||
* apply_patch->check_patch_list->check_patch->
|
||||
* apply_data->apply_fragments->apply_one_fragment
|
||||
*/
|
||||
while (new_blank_lines_at_end--)
|
||||
remove_last_line(&postimage);
|
||||
if (ws_error_action == die_on_ws_error)
|
||||
apply = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
4
cache.h
4
cache.h
@ -967,10 +967,12 @@ void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, i
|
||||
* whitespace rules.
|
||||
* used by both diff and apply
|
||||
*/
|
||||
#define WS_TRAILING_SPACE 01
|
||||
#define WS_BLANK_AT_EOL 01
|
||||
#define WS_SPACE_BEFORE_TAB 02
|
||||
#define WS_INDENT_WITH_NON_TAB 04
|
||||
#define WS_CR_AT_EOL 010
|
||||
#define WS_BLANK_AT_EOF 020
|
||||
#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
|
||||
#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
|
||||
extern unsigned whitespace_rule_cfg;
|
||||
extern unsigned whitespace_rule(const char *);
|
||||
|
155
diff.c
155
diff.c
@ -532,8 +532,12 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
||||
typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
|
||||
|
||||
struct emit_callback {
|
||||
int nparents, color_diff;
|
||||
int color_diff;
|
||||
unsigned ws_rule;
|
||||
int blank_at_eof_in_preimage;
|
||||
int blank_at_eof_in_postimage;
|
||||
int lno_in_preimage;
|
||||
int lno_in_postimage;
|
||||
sane_truncate_fn truncate;
|
||||
const char **label_path;
|
||||
struct diff_words_data *diff_words;
|
||||
@ -586,6 +590,17 @@ static void emit_line(FILE *file, const char *set, const char *reset, const char
|
||||
fputc('\n', file);
|
||||
}
|
||||
|
||||
static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len)
|
||||
{
|
||||
if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) &&
|
||||
ecbdata->blank_at_eof_in_preimage &&
|
||||
ecbdata->blank_at_eof_in_postimage &&
|
||||
ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage &&
|
||||
ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage))
|
||||
return 0;
|
||||
return ws_blank_line(line + 1, len - 1, ecbdata->ws_rule);
|
||||
}
|
||||
|
||||
static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
|
||||
{
|
||||
const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
|
||||
@ -593,11 +608,13 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons
|
||||
|
||||
if (!*ws)
|
||||
emit_line(ecbdata->file, set, reset, line, len);
|
||||
else if (new_blank_line_at_eof(ecbdata, line, len))
|
||||
/* Blank line at EOF - paint '+' as well */
|
||||
emit_line(ecbdata->file, ws, reset, line, len);
|
||||
else {
|
||||
/* Emit just the prefix, then the rest. */
|
||||
emit_line(ecbdata->file, set, reset, line, ecbdata->nparents);
|
||||
ws_check_emit(line + ecbdata->nparents,
|
||||
len - ecbdata->nparents, ecbdata->ws_rule,
|
||||
emit_line(ecbdata->file, set, reset, line, 1);
|
||||
ws_check_emit(line + 1, len - 1, ecbdata->ws_rule,
|
||||
ecbdata->file, set, reset, ws);
|
||||
}
|
||||
}
|
||||
@ -620,10 +637,23 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u
|
||||
return allot - l;
|
||||
}
|
||||
|
||||
static void find_lno(const char *line, struct emit_callback *ecbdata)
|
||||
{
|
||||
const char *p;
|
||||
ecbdata->lno_in_preimage = 0;
|
||||
ecbdata->lno_in_postimage = 0;
|
||||
p = strchr(line, '-');
|
||||
if (!p)
|
||||
return; /* cannot happen */
|
||||
ecbdata->lno_in_preimage = strtol(p + 1, NULL, 10);
|
||||
p = strchr(p, '+');
|
||||
if (!p)
|
||||
return; /* cannot happen */
|
||||
ecbdata->lno_in_postimage = strtol(p + 1, NULL, 10);
|
||||
}
|
||||
|
||||
static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
{
|
||||
int i;
|
||||
int color;
|
||||
struct emit_callback *ecbdata = priv;
|
||||
const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
|
||||
const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
|
||||
@ -650,14 +680,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
len = 1;
|
||||
}
|
||||
|
||||
/* This is not really necessary for now because
|
||||
* this codepath only deals with two-way diffs.
|
||||
*/
|
||||
for (i = 0; i < len && line[i] == '@'; i++)
|
||||
;
|
||||
if (2 <= i && i < len && line[i] == ' ') {
|
||||
ecbdata->nparents = i - 1;
|
||||
if (line[0] == '@') {
|
||||
len = sane_truncate_line(ecbdata, line, len);
|
||||
find_lno(line, ecbdata);
|
||||
emit_line(ecbdata->file,
|
||||
diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
|
||||
reset, line, len);
|
||||
@ -666,15 +691,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < ecbdata->nparents) {
|
||||
if (len < 1) {
|
||||
emit_line(ecbdata->file, reset, reset, line, len);
|
||||
return;
|
||||
}
|
||||
|
||||
color = DIFF_PLAIN;
|
||||
if (ecbdata->diff_words && ecbdata->nparents != 1)
|
||||
/* fall back to normal diff */
|
||||
free_diff_words_data(ecbdata);
|
||||
if (ecbdata->diff_words) {
|
||||
if (line[0] == '-') {
|
||||
diff_words_append(line, len,
|
||||
@ -693,20 +714,19 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
emit_line(ecbdata->file, plain, reset, line, len);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < ecbdata->nparents && len; i++) {
|
||||
if (line[i] == '-')
|
||||
color = DIFF_FILE_OLD;
|
||||
else if (line[i] == '+')
|
||||
color = DIFF_FILE_NEW;
|
||||
}
|
||||
|
||||
if (color != DIFF_FILE_NEW) {
|
||||
emit_line(ecbdata->file,
|
||||
diff_get_color(ecbdata->color_diff, color),
|
||||
reset, line, len);
|
||||
return;
|
||||
if (line[0] != '+') {
|
||||
const char *color =
|
||||
diff_get_color(ecbdata->color_diff,
|
||||
line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN);
|
||||
ecbdata->lno_in_preimage++;
|
||||
if (line[0] == ' ')
|
||||
ecbdata->lno_in_postimage++;
|
||||
emit_line(ecbdata->file, color, reset, line, len);
|
||||
} else {
|
||||
ecbdata->lno_in_postimage++;
|
||||
emit_add_line(reset, ecbdata, line, len);
|
||||
}
|
||||
emit_add_line(reset, ecbdata, line, len);
|
||||
}
|
||||
|
||||
static char *pprint_rename(const char *a, const char *b)
|
||||
@ -1211,7 +1231,6 @@ struct checkdiff_t {
|
||||
struct diff_options *o;
|
||||
unsigned ws_rule;
|
||||
unsigned status;
|
||||
int trailing_blanks_start;
|
||||
};
|
||||
|
||||
static int is_conflict_marker(const char *line, unsigned long len)
|
||||
@ -1255,10 +1274,6 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
if (line[0] == '+') {
|
||||
unsigned bad;
|
||||
data->lineno++;
|
||||
if (!ws_blank_line(line + 1, len - 1, data->ws_rule))
|
||||
data->trailing_blanks_start = 0;
|
||||
else if (!data->trailing_blanks_start)
|
||||
data->trailing_blanks_start = data->lineno;
|
||||
if (is_conflict_marker(line + 1, len - 1)) {
|
||||
data->status |= 1;
|
||||
fprintf(data->o->file,
|
||||
@ -1278,14 +1293,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
data->o->file, set, reset, ws);
|
||||
} else if (line[0] == ' ') {
|
||||
data->lineno++;
|
||||
data->trailing_blanks_start = 0;
|
||||
} else if (line[0] == '@') {
|
||||
char *plus = strchr(line, '+');
|
||||
if (plus)
|
||||
data->lineno = strtol(plus, NULL, 10) - 1;
|
||||
else
|
||||
die("invalid diff");
|
||||
data->trailing_blanks_start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1437,6 +1450,51 @@ static const char *get_textconv(struct diff_filespec *one)
|
||||
return one->driver->textconv;
|
||||
}
|
||||
|
||||
static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
|
||||
{
|
||||
char *ptr = mf->ptr;
|
||||
long size = mf->size;
|
||||
int cnt = 0;
|
||||
|
||||
if (!size)
|
||||
return cnt;
|
||||
ptr += size - 1; /* pointing at the very end */
|
||||
if (*ptr != '\n')
|
||||
; /* incomplete line */
|
||||
else
|
||||
ptr--; /* skip the last LF */
|
||||
while (mf->ptr < ptr) {
|
||||
char *prev_eol;
|
||||
for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--)
|
||||
if (*prev_eol == '\n')
|
||||
break;
|
||||
if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule))
|
||||
break;
|
||||
cnt++;
|
||||
ptr = prev_eol - 1;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
|
||||
struct emit_callback *ecbdata)
|
||||
{
|
||||
int l1, l2, at;
|
||||
unsigned ws_rule = ecbdata->ws_rule;
|
||||
l1 = count_trailing_blank(mf1, ws_rule);
|
||||
l2 = count_trailing_blank(mf2, ws_rule);
|
||||
if (l2 <= l1) {
|
||||
ecbdata->blank_at_eof_in_preimage = 0;
|
||||
ecbdata->blank_at_eof_in_postimage = 0;
|
||||
return;
|
||||
}
|
||||
at = count_lines(mf1->ptr, mf1->size);
|
||||
ecbdata->blank_at_eof_in_preimage = (at - l1) + 1;
|
||||
|
||||
at = count_lines(mf2->ptr, mf2->size);
|
||||
ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
|
||||
}
|
||||
|
||||
static void builtin_diff(const char *name_a,
|
||||
const char *name_b,
|
||||
struct diff_filespec *one,
|
||||
@ -1562,6 +1620,8 @@ static void builtin_diff(const char *name_a,
|
||||
ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
|
||||
ecbdata.found_changesp = &o->found_changes;
|
||||
ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
|
||||
if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
|
||||
check_blank_at_eof(&mf1, &mf2, &ecbdata);
|
||||
ecbdata.file = o->file;
|
||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||
xecfg.ctxlen = o->context;
|
||||
@ -1704,11 +1764,22 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
||||
xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
|
||||
&xpp, &xecfg, &ecb);
|
||||
|
||||
if ((data.ws_rule & WS_TRAILING_SPACE) &&
|
||||
data.trailing_blanks_start) {
|
||||
fprintf(o->file, "%s:%d: ends with blank lines.\n",
|
||||
data.filename, data.trailing_blanks_start);
|
||||
data.status = 1; /* report errors */
|
||||
if (data.ws_rule & WS_BLANK_AT_EOF) {
|
||||
struct emit_callback ecbdata;
|
||||
int blank_at_eof;
|
||||
|
||||
ecbdata.ws_rule = data.ws_rule;
|
||||
check_blank_at_eof(&mf1, &mf2, &ecbdata);
|
||||
blank_at_eof = ecbdata.blank_at_eof_in_preimage;
|
||||
|
||||
if (blank_at_eof) {
|
||||
static char *err;
|
||||
if (!err)
|
||||
err = whitespace_error_string(WS_BLANK_AT_EOF);
|
||||
fprintf(o->file, "%s:%d: %s.\n",
|
||||
data.filename, blank_at_eof, err);
|
||||
data.status = 1; /* report errors */
|
||||
}
|
||||
}
|
||||
}
|
||||
free_and_return:
|
||||
|
@ -362,10 +362,17 @@ test_expect_success 'line numbers in --check output are correct' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'checkdiff detects trailing blank lines' '
|
||||
test_expect_success 'checkdiff detects new trailing blank lines (1)' '
|
||||
echo "foo();" >x &&
|
||||
echo "" >>x &&
|
||||
git diff --check | grep "ends with blank"
|
||||
git diff --check | grep "new blank line"
|
||||
'
|
||||
|
||||
test_expect_success 'checkdiff detects new trailing blank lines (2)' '
|
||||
{ echo a; echo b; echo; echo; } >x &&
|
||||
git add x &&
|
||||
{ echo a; echo; echo; echo; echo; } >x &&
|
||||
git diff --check | grep "new blank line"
|
||||
'
|
||||
|
||||
test_expect_success 'checkdiff allows new blank lines' '
|
||||
|
@ -165,7 +165,7 @@ test_expect_success 'trailing empty lines (1)' '
|
||||
|
||||
rm -f .gitattributes &&
|
||||
test_must_fail git diff --check >output &&
|
||||
grep "ends with blank lines." output &&
|
||||
grep "new blank line at" output &&
|
||||
grep "trailing whitespace" output
|
||||
|
||||
'
|
||||
@ -190,4 +190,13 @@ test_expect_success 'do not color trailing cr in context' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'color new trailing blank lines' '
|
||||
{ echo a; echo b; echo; echo; } >x &&
|
||||
git add x &&
|
||||
{ echo a; echo; echo; echo; echo c; echo; echo; echo; echo; } >x &&
|
||||
git diff --color x >output &&
|
||||
cnt=$(grep "${blue_grep}" output | wc -l) &&
|
||||
test $cnt = 2
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -170,4 +170,95 @@ test_expect_success 'trailing whitespace & no newline at the end of file' '
|
||||
grep "^$" target
|
||||
'
|
||||
|
||||
test_expect_success 'blank at EOF with --whitespace=fix (1)' '
|
||||
: these can fail depending on what we did before
|
||||
git config --unset core.whitespace
|
||||
rm -f .gitattributes
|
||||
|
||||
{ echo a; echo b; echo c; } >one &&
|
||||
git add one &&
|
||||
{ echo a; echo b; echo c; } >expect &&
|
||||
{ cat expect; echo; } >one &&
|
||||
git diff -- one >patch &&
|
||||
|
||||
git checkout one &&
|
||||
git apply --whitespace=fix patch &&
|
||||
test_cmp expect one
|
||||
'
|
||||
|
||||
test_expect_success 'blank at EOF with --whitespace=fix (2)' '
|
||||
{ echo a; echo b; echo c; } >one &&
|
||||
git add one &&
|
||||
{ echo a; echo c; } >expect &&
|
||||
{ cat expect; echo; echo; } >one &&
|
||||
git diff -- one >patch &&
|
||||
|
||||
git checkout one &&
|
||||
git apply --whitespace=fix patch &&
|
||||
test_cmp expect one
|
||||
'
|
||||
|
||||
test_expect_success 'blank at EOF with --whitespace=fix (3)' '
|
||||
{ echo a; echo b; echo; } >one &&
|
||||
git add one &&
|
||||
{ echo a; echo c; echo; } >expect &&
|
||||
{ cat expect; echo; echo; } >one &&
|
||||
git diff -- one >patch &&
|
||||
|
||||
git checkout one &&
|
||||
git apply --whitespace=fix patch &&
|
||||
test_cmp expect one
|
||||
'
|
||||
|
||||
test_expect_success 'blank at end of hunk, not at EOF with --whitespace=fix' '
|
||||
{ echo a; echo b; echo; echo; echo; echo; echo; echo d; } >one &&
|
||||
git add one &&
|
||||
{ echo a; echo c; echo; echo; echo; echo; echo; echo; echo d; } >expect &&
|
||||
cp expect one &&
|
||||
git diff -- one >patch &&
|
||||
|
||||
git checkout one &&
|
||||
git apply --whitespace=fix patch &&
|
||||
test_cmp expect one
|
||||
'
|
||||
|
||||
test_expect_success 'blank at EOF with --whitespace=warn' '
|
||||
{ echo a; echo b; echo c; } >one &&
|
||||
git add one &&
|
||||
echo >>one &&
|
||||
cat one >expect &&
|
||||
git diff -- one >patch &&
|
||||
|
||||
git checkout one &&
|
||||
git apply --whitespace=warn patch 2>error &&
|
||||
test_cmp expect one &&
|
||||
grep "new blank line at EOF" error
|
||||
'
|
||||
|
||||
test_expect_success 'blank at EOF with --whitespace=error' '
|
||||
{ echo a; echo b; echo c; } >one &&
|
||||
git add one &&
|
||||
cat one >expect &&
|
||||
echo >>one &&
|
||||
git diff -- one >patch &&
|
||||
|
||||
git checkout one &&
|
||||
test_must_fail git apply --whitespace=error patch 2>error &&
|
||||
test_cmp expect one &&
|
||||
grep "new blank line at EOF" error
|
||||
'
|
||||
|
||||
test_expect_success 'blank but not empty at EOF' '
|
||||
{ echo a; echo b; echo c; } >one &&
|
||||
git add one &&
|
||||
echo " " >>one &&
|
||||
cat one >expect &&
|
||||
git diff -- one >patch &&
|
||||
|
||||
git checkout one &&
|
||||
git apply --whitespace=warn patch 2>error &&
|
||||
test_cmp expect one &&
|
||||
grep "new blank line at EOF" error
|
||||
'
|
||||
|
||||
test_done
|
||||
|
19
ws.c
19
ws.c
@ -16,6 +16,8 @@ static struct whitespace_rule {
|
||||
{ "space-before-tab", WS_SPACE_BEFORE_TAB, 0 },
|
||||
{ "indent-with-non-tab", WS_INDENT_WITH_NON_TAB, 0 },
|
||||
{ "cr-at-eol", WS_CR_AT_EOL, 1 },
|
||||
{ "blank-at-eol", WS_BLANK_AT_EOL, 0 },
|
||||
{ "blank-at-eof", WS_BLANK_AT_EOF, 0 },
|
||||
};
|
||||
|
||||
unsigned parse_whitespace_rule(const char *string)
|
||||
@ -102,8 +104,17 @@ unsigned whitespace_rule(const char *pathname)
|
||||
char *whitespace_error_string(unsigned ws)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
if (ws & WS_TRAILING_SPACE)
|
||||
if ((ws & WS_TRAILING_SPACE) == WS_TRAILING_SPACE)
|
||||
strbuf_addstr(&err, "trailing whitespace");
|
||||
else {
|
||||
if (ws & WS_BLANK_AT_EOL)
|
||||
strbuf_addstr(&err, "trailing whitespace");
|
||||
if (ws & WS_BLANK_AT_EOF) {
|
||||
if (err.len)
|
||||
strbuf_addstr(&err, ", ");
|
||||
strbuf_addstr(&err, "new blank line at EOF");
|
||||
}
|
||||
}
|
||||
if (ws & WS_SPACE_BEFORE_TAB) {
|
||||
if (err.len)
|
||||
strbuf_addstr(&err, ", ");
|
||||
@ -141,11 +152,11 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,
|
||||
}
|
||||
|
||||
/* Check for trailing whitespace. */
|
||||
if (ws_rule & WS_TRAILING_SPACE) {
|
||||
if (ws_rule & WS_BLANK_AT_EOL) {
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
if (isspace(line[i])) {
|
||||
trailing_whitespace = i;
|
||||
result |= WS_TRAILING_SPACE;
|
||||
result |= WS_BLANK_AT_EOL;
|
||||
}
|
||||
else
|
||||
break;
|
||||
@ -261,7 +272,7 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro
|
||||
/*
|
||||
* Strip trailing whitespace
|
||||
*/
|
||||
if (ws_rule & WS_TRAILING_SPACE) {
|
||||
if (ws_rule & WS_BLANK_AT_EOL) {
|
||||
if (0 < len && src[len - 1] == '\n') {
|
||||
add_nl_to_tail = 1;
|
||||
len--;
|
||||
|
Loading…
Reference in New Issue
Block a user