Merge branch 'jc/maint-blank-at-eof' into maint
* jc/maint-blank-at-eof: diff -B: colour whitespace errors diff.c: emit_add_line() takes only the rest of the line diff.c: split emit_line() from the first char and the rest of the line diff.c: shuffling code around 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
6dbdba00ea
@ -416,13 +416,17 @@ core.whitespace::
|
|||||||
consider them as errors. You can prefix `-` to disable
|
consider them as errors. You can prefix `-` to disable
|
||||||
any of them (e.g. `-trailing-space`):
|
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).
|
as an error (enabled by default).
|
||||||
* `space-before-tab` treats a space character that appears immediately
|
* `space-before-tab` treats a space character that appears immediately
|
||||||
before a tab character in the initial indent part of the line as an
|
before a tab character in the initial indent part of the line as an
|
||||||
error (enabled by default).
|
error (enabled by default).
|
||||||
* `indent-with-non-tab` treats a line that is indented with 8 or more
|
* `indent-with-non-tab` treats a line that is indented with 8 or more
|
||||||
space characters as an error (not enabled by default).
|
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
|
* `cr-at-eol` treats a carriage-return at the end of line as
|
||||||
part of the line terminator, i.e. with it, `trailing-space`
|
part of the line terminator, i.e. with it, `trailing-space`
|
||||||
does not trigger if the character before such a carriage-return
|
does not trigger if the character before such a carriage-return
|
||||||
|
@ -153,6 +153,7 @@ struct fragment {
|
|||||||
const char *patch;
|
const char *patch;
|
||||||
int size;
|
int size;
|
||||||
int rejected;
|
int rejected;
|
||||||
|
int linenr;
|
||||||
struct fragment *next;
|
struct fragment *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1227,23 +1228,29 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
|||||||
return -1;
|
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;
|
char *err;
|
||||||
unsigned result = ws_check(line + 1, len - 1, ws_rule);
|
|
||||||
if (!result)
|
if (!result)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
whitespace_error++;
|
whitespace_error++;
|
||||||
if (squelch_whitespace_errors &&
|
if (squelch_whitespace_errors &&
|
||||||
squelch_whitespace_errors < whitespace_error)
|
squelch_whitespace_errors < whitespace_error)
|
||||||
;
|
return;
|
||||||
else {
|
|
||||||
err = whitespace_error_string(result);
|
err = whitespace_error_string(result);
|
||||||
fprintf(stderr, "%s:%d: %s.\n%.*s\n",
|
fprintf(stderr, "%s:%d: %s.\n%.*s\n",
|
||||||
patch_input_file, linenr, err, len - 2, line + 1);
|
patch_input_file, linenr, err, len, line);
|
||||||
free(err);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1359,6 +1366,7 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
|
|||||||
int len;
|
int len;
|
||||||
|
|
||||||
fragment = xcalloc(1, sizeof(*fragment));
|
fragment = xcalloc(1, sizeof(*fragment));
|
||||||
|
fragment->linenr = linenr;
|
||||||
len = parse_fragment(line, size, patch, fragment);
|
len = parse_fragment(line, size, patch, fragment);
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
die("corrupt patch at line %d", linenr);
|
die("corrupt patch at line %d", linenr);
|
||||||
@ -2142,6 +2150,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
|||||||
int len = linelen(patch, size);
|
int len = linelen(patch, size);
|
||||||
int plen, added;
|
int plen, added;
|
||||||
int added_blank_line = 0;
|
int added_blank_line = 0;
|
||||||
|
int is_blank_context = 0;
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
break;
|
break;
|
||||||
@ -2174,8 +2183,12 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
|||||||
*new++ = '\n';
|
*new++ = '\n';
|
||||||
add_line_info(&preimage, "\n", 1, LINE_COMMON);
|
add_line_info(&preimage, "\n", 1, LINE_COMMON);
|
||||||
add_line_info(&postimage, "\n", 1, LINE_COMMON);
|
add_line_info(&postimage, "\n", 1, LINE_COMMON);
|
||||||
|
is_blank_context = 1;
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
|
if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
|
||||||
|
ws_blank_line(patch + 1, plen, ws_rule))
|
||||||
|
is_blank_context = 1;
|
||||||
case '-':
|
case '-':
|
||||||
memcpy(old, patch + 1, plen);
|
memcpy(old, patch + 1, plen);
|
||||||
add_line_info(&preimage, old, plen,
|
add_line_info(&preimage, old, plen,
|
||||||
@ -2202,7 +2215,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
|||||||
(first == '+' ? 0 : LINE_COMMON));
|
(first == '+' ? 0 : LINE_COMMON));
|
||||||
new += added;
|
new += added;
|
||||||
if (first == '+' &&
|
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;
|
added_blank_line = 1;
|
||||||
break;
|
break;
|
||||||
case '@': case '\\':
|
case '@': case '\\':
|
||||||
@ -2215,6 +2229,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
|||||||
}
|
}
|
||||||
if (added_blank_line)
|
if (added_blank_line)
|
||||||
new_blank_lines_at_end++;
|
new_blank_lines_at_end++;
|
||||||
|
else if (is_blank_context)
|
||||||
|
;
|
||||||
else
|
else
|
||||||
new_blank_lines_at_end = 0;
|
new_blank_lines_at_end = 0;
|
||||||
patch += len;
|
patch += len;
|
||||||
@ -2296,17 +2312,24 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (applied_pos >= 0) {
|
if (applied_pos >= 0) {
|
||||||
if (ws_error_action == correct_ws_error &&
|
if (new_blank_lines_at_end &&
|
||||||
new_blank_lines_at_end &&
|
preimage.nr + applied_pos == img->nr &&
|
||||||
postimage.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
|
* We would want to prevent write_out_results()
|
||||||
* at the end, and if the patch applies at the
|
* from taking place in apply_patch() that follows
|
||||||
* end of the image, remove those added blank
|
* the callchain led us here, which is:
|
||||||
* lines.
|
* apply_patch->check_patch_list->check_patch->
|
||||||
|
* apply_data->apply_fragments->apply_one_fragment
|
||||||
*/
|
*/
|
||||||
while (new_blank_lines_at_end--)
|
if (ws_error_action == die_on_ws_error)
|
||||||
remove_last_line(&postimage);
|
apply = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
4
cache.h
4
cache.h
@ -986,10 +986,12 @@ void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, i
|
|||||||
* whitespace rules.
|
* whitespace rules.
|
||||||
* used by both diff and apply
|
* 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_SPACE_BEFORE_TAB 02
|
||||||
#define WS_INDENT_WITH_NON_TAB 04
|
#define WS_INDENT_WITH_NON_TAB 04
|
||||||
#define WS_CR_AT_EOL 010
|
#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)
|
#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
|
||||||
extern unsigned whitespace_rule_cfg;
|
extern unsigned whitespace_rule_cfg;
|
||||||
extern unsigned whitespace_rule(const char *);
|
extern unsigned whitespace_rule(const char *);
|
||||||
|
407
diff.c
407
diff.c
@ -174,6 +174,175 @@ static struct diff_tempfile {
|
|||||||
char tmp_path[PATH_MAX];
|
char tmp_path[PATH_MAX];
|
||||||
} diff_temp[2];
|
} diff_temp[2];
|
||||||
|
|
||||||
|
typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
|
||||||
|
|
||||||
|
struct emit_callback {
|
||||||
|
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;
|
||||||
|
int *found_changesp;
|
||||||
|
FILE *file;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int count_lines(const char *data, int size)
|
||||||
|
{
|
||||||
|
int count, ch, completely_empty = 1, nl_just_seen = 0;
|
||||||
|
count = 0;
|
||||||
|
while (0 < size--) {
|
||||||
|
ch = *data++;
|
||||||
|
if (ch == '\n') {
|
||||||
|
count++;
|
||||||
|
nl_just_seen = 1;
|
||||||
|
completely_empty = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nl_just_seen = 0;
|
||||||
|
completely_empty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (completely_empty)
|
||||||
|
return 0;
|
||||||
|
if (!nl_just_seen)
|
||||||
|
count++; /* no trailing newline */
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
|
||||||
|
{
|
||||||
|
if (!DIFF_FILE_VALID(one)) {
|
||||||
|
mf->ptr = (char *)""; /* does not matter */
|
||||||
|
mf->size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (diff_populate_filespec(one, 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mf->ptr = one->data;
|
||||||
|
mf->size = one->size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 emit_line_0(FILE *file, const char *set, const char *reset,
|
||||||
|
int first, const char *line, int len)
|
||||||
|
{
|
||||||
|
int has_trailing_newline, has_trailing_carriage_return;
|
||||||
|
int nofirst;
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
has_trailing_newline = (first == '\n');
|
||||||
|
has_trailing_carriage_return = (!has_trailing_newline &&
|
||||||
|
(first == '\r'));
|
||||||
|
nofirst = has_trailing_newline || has_trailing_carriage_return;
|
||||||
|
} else {
|
||||||
|
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--;
|
||||||
|
nofirst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs(set, file);
|
||||||
|
|
||||||
|
if (!nofirst)
|
||||||
|
fputc(first, file);
|
||||||
|
fwrite(line, len, 1, file);
|
||||||
|
fputs(reset, file);
|
||||||
|
if (has_trailing_carriage_return)
|
||||||
|
fputc('\r', file);
|
||||||
|
if (has_trailing_newline)
|
||||||
|
fputc('\n', file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_line(FILE *file, const char *set, const char *reset,
|
||||||
|
const char *line, int len)
|
||||||
|
{
|
||||||
|
emit_line_0(file, set, reset, line[0], line+1, len-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, len, 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);
|
||||||
|
const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
|
||||||
|
|
||||||
|
if (!*ws)
|
||||||
|
emit_line_0(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_0(ecbdata->file, ws, reset, '+', line, len);
|
||||||
|
else {
|
||||||
|
/* Emit just the prefix, then the rest. */
|
||||||
|
emit_line_0(ecbdata->file, set, reset, '+', "", 0);
|
||||||
|
ws_check_emit(line, len, ecbdata->ws_rule,
|
||||||
|
ecbdata->file, set, reset, ws);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct diff_tempfile *claim_diff_tempfile(void) {
|
static struct diff_tempfile *claim_diff_tempfile(void) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
|
for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
|
||||||
@ -201,29 +370,6 @@ static void remove_tempfile_on_signal(int signo)
|
|||||||
raise(signo);
|
raise(signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_lines(const char *data, int size)
|
|
||||||
{
|
|
||||||
int count, ch, completely_empty = 1, nl_just_seen = 0;
|
|
||||||
count = 0;
|
|
||||||
while (0 < size--) {
|
|
||||||
ch = *data++;
|
|
||||||
if (ch == '\n') {
|
|
||||||
count++;
|
|
||||||
nl_just_seen = 1;
|
|
||||||
completely_empty = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nl_just_seen = 0;
|
|
||||||
completely_empty = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (completely_empty)
|
|
||||||
return 0;
|
|
||||||
if (!nl_just_seen)
|
|
||||||
count++; /* no trailing newline */
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_line_count(FILE *file, int count)
|
static void print_line_count(FILE *file, int count)
|
||||||
{
|
{
|
||||||
switch (count) {
|
switch (count) {
|
||||||
@ -239,26 +385,36 @@ static void print_line_count(FILE *file, int count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_file_with_prefix(FILE *file,
|
static void emit_rewrite_lines(struct emit_callback *ecb,
|
||||||
int prefix, const char *data, int size,
|
int prefix, const char *data, int size)
|
||||||
const char *set, const char *reset)
|
|
||||||
{
|
{
|
||||||
int ch, nl_just_seen = 1;
|
const char *endp = NULL;
|
||||||
while (0 < size--) {
|
static const char *nneof = " No newline at end of file\n";
|
||||||
ch = *data++;
|
const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD);
|
||||||
if (nl_just_seen) {
|
const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET);
|
||||||
fputs(set, file);
|
|
||||||
putc(prefix, file);
|
while (0 < size) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
endp = memchr(data, '\n', size);
|
||||||
|
len = endp ? (endp - data + 1) : size;
|
||||||
|
if (prefix != '+') {
|
||||||
|
ecb->lno_in_preimage++;
|
||||||
|
emit_line_0(ecb->file, old, reset, '-',
|
||||||
|
data, len);
|
||||||
|
} else {
|
||||||
|
ecb->lno_in_postimage++;
|
||||||
|
emit_add_line(reset, ecb, data, len);
|
||||||
}
|
}
|
||||||
if (ch == '\n') {
|
size -= len;
|
||||||
nl_just_seen = 1;
|
data += len;
|
||||||
fputs(reset, file);
|
}
|
||||||
} else
|
if (!endp) {
|
||||||
nl_just_seen = 0;
|
const char *plain = diff_get_color(ecb->color_diff,
|
||||||
putc(ch, file);
|
DIFF_PLAIN);
|
||||||
|
emit_line_0(ecb->file, plain, reset, '\\',
|
||||||
|
nneof, strlen(nneof));
|
||||||
}
|
}
|
||||||
if (!nl_just_seen)
|
|
||||||
fprintf(file, "%s\n\\ No newline at end of file\n", reset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_rewrite_diff(const char *name_a,
|
static void emit_rewrite_diff(const char *name_a,
|
||||||
@ -274,13 +430,12 @@ static void emit_rewrite_diff(const char *name_a,
|
|||||||
const char *name_a_tab, *name_b_tab;
|
const char *name_a_tab, *name_b_tab;
|
||||||
const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
|
const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
|
||||||
const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
|
const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
|
||||||
const char *old = diff_get_color(color_diff, DIFF_FILE_OLD);
|
|
||||||
const char *new = diff_get_color(color_diff, DIFF_FILE_NEW);
|
|
||||||
const char *reset = diff_get_color(color_diff, DIFF_RESET);
|
const char *reset = diff_get_color(color_diff, DIFF_RESET);
|
||||||
static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT;
|
static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT;
|
||||||
const char *a_prefix, *b_prefix;
|
const char *a_prefix, *b_prefix;
|
||||||
const char *data_one, *data_two;
|
const char *data_one, *data_two;
|
||||||
size_t size_one, size_two;
|
size_t size_one, size_two;
|
||||||
|
struct emit_callback ecbdata;
|
||||||
|
|
||||||
if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
|
if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
|
||||||
a_prefix = o->b_prefix;
|
a_prefix = o->b_prefix;
|
||||||
@ -321,6 +476,22 @@ static void emit_rewrite_diff(const char *name_a,
|
|||||||
size_two = two->size;
|
size_two = two->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&ecbdata, 0, sizeof(ecbdata));
|
||||||
|
ecbdata.color_diff = color_diff;
|
||||||
|
ecbdata.found_changesp = &o->found_changes;
|
||||||
|
ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
|
||||||
|
ecbdata.file = o->file;
|
||||||
|
if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
|
||||||
|
mmfile_t mf1, mf2;
|
||||||
|
mf1.ptr = (char *)data_one;
|
||||||
|
mf2.ptr = (char *)data_two;
|
||||||
|
mf1.size = size_one;
|
||||||
|
mf2.size = size_two;
|
||||||
|
check_blank_at_eof(&mf1, &mf2, &ecbdata);
|
||||||
|
}
|
||||||
|
ecbdata.lno_in_preimage = 1;
|
||||||
|
ecbdata.lno_in_postimage = 1;
|
||||||
|
|
||||||
lc_a = count_lines(data_one, size_one);
|
lc_a = count_lines(data_one, size_one);
|
||||||
lc_b = count_lines(data_two, size_two);
|
lc_b = count_lines(data_two, size_two);
|
||||||
fprintf(o->file,
|
fprintf(o->file,
|
||||||
@ -332,24 +503,9 @@ static void emit_rewrite_diff(const char *name_a,
|
|||||||
print_line_count(o->file, lc_b);
|
print_line_count(o->file, lc_b);
|
||||||
fprintf(o->file, " @@%s\n", reset);
|
fprintf(o->file, " @@%s\n", reset);
|
||||||
if (lc_a)
|
if (lc_a)
|
||||||
copy_file_with_prefix(o->file, '-', data_one, size_one, old, reset);
|
emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
|
||||||
if (lc_b)
|
if (lc_b)
|
||||||
copy_file_with_prefix(o->file, '+', data_two, size_two, new, reset);
|
emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
|
||||||
}
|
|
||||||
|
|
||||||
static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
|
|
||||||
{
|
|
||||||
if (!DIFF_FILE_VALID(one)) {
|
|
||||||
mf->ptr = (char *)""; /* does not matter */
|
|
||||||
mf->size = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (diff_populate_filespec(one, 0))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
mf->ptr = one->data;
|
|
||||||
mf->size = one->size;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct diff_words_buffer {
|
struct diff_words_buffer {
|
||||||
@ -529,18 +685,6 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
|||||||
diff_words->minus.text.size = diff_words->plus.text.size = 0;
|
diff_words->minus.text.size = diff_words->plus.text.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
|
|
||||||
|
|
||||||
struct emit_callback {
|
|
||||||
int nparents, color_diff;
|
|
||||||
unsigned ws_rule;
|
|
||||||
sane_truncate_fn truncate;
|
|
||||||
const char **label_path;
|
|
||||||
struct diff_words_data *diff_words;
|
|
||||||
int *found_changesp;
|
|
||||||
FILE *file;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void free_diff_words_data(struct emit_callback *ecbdata)
|
static void free_diff_words_data(struct emit_callback *ecbdata)
|
||||||
{
|
{
|
||||||
if (ecbdata->diff_words) {
|
if (ecbdata->diff_words) {
|
||||||
@ -566,42 +710,6 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
|
|
||||||
|
|
||||||
if (!*ws)
|
|
||||||
emit_line(ecbdata->file, set, 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,
|
|
||||||
ecbdata->file, set, reset, ws);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len)
|
static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
const char *cp;
|
const char *cp;
|
||||||
@ -620,10 +728,23 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u
|
|||||||
return allot - l;
|
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)
|
static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int color;
|
|
||||||
struct emit_callback *ecbdata = priv;
|
struct emit_callback *ecbdata = priv;
|
||||||
const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
|
const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
|
||||||
const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
|
const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
|
||||||
@ -650,14 +771,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
len = 1;
|
len = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is not really necessary for now because
|
if (line[0] == '@') {
|
||||||
* 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;
|
|
||||||
len = sane_truncate_line(ecbdata, line, len);
|
len = sane_truncate_line(ecbdata, line, len);
|
||||||
|
find_lno(line, ecbdata);
|
||||||
emit_line(ecbdata->file,
|
emit_line(ecbdata->file,
|
||||||
diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
|
diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
|
||||||
reset, line, len);
|
reset, line, len);
|
||||||
@ -666,15 +782,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < ecbdata->nparents) {
|
if (len < 1) {
|
||||||
emit_line(ecbdata->file, reset, reset, line, len);
|
emit_line(ecbdata->file, reset, reset, line, len);
|
||||||
return;
|
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 (ecbdata->diff_words) {
|
||||||
if (line[0] == '-') {
|
if (line[0] == '-') {
|
||||||
diff_words_append(line, len,
|
diff_words_append(line, len,
|
||||||
@ -693,20 +805,19 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
emit_line(ecbdata->file, plain, reset, line, len);
|
emit_line(ecbdata->file, plain, reset, line, len);
|
||||||
return;
|
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) {
|
if (line[0] != '+') {
|
||||||
emit_line(ecbdata->file,
|
const char *color =
|
||||||
diff_get_color(ecbdata->color_diff, color),
|
diff_get_color(ecbdata->color_diff,
|
||||||
reset, line, len);
|
line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN);
|
||||||
return;
|
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 + 1, len - 1);
|
||||||
}
|
}
|
||||||
emit_add_line(reset, ecbdata, line, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *pprint_rename(const char *a, const char *b)
|
static char *pprint_rename(const char *a, const char *b)
|
||||||
@ -1211,7 +1322,6 @@ struct checkdiff_t {
|
|||||||
struct diff_options *o;
|
struct diff_options *o;
|
||||||
unsigned ws_rule;
|
unsigned ws_rule;
|
||||||
unsigned status;
|
unsigned status;
|
||||||
int trailing_blanks_start;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int is_conflict_marker(const char *line, unsigned long len)
|
static int is_conflict_marker(const char *line, unsigned long len)
|
||||||
@ -1255,10 +1365,6 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
|||||||
if (line[0] == '+') {
|
if (line[0] == '+') {
|
||||||
unsigned bad;
|
unsigned bad;
|
||||||
data->lineno++;
|
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)) {
|
if (is_conflict_marker(line + 1, len - 1)) {
|
||||||
data->status |= 1;
|
data->status |= 1;
|
||||||
fprintf(data->o->file,
|
fprintf(data->o->file,
|
||||||
@ -1278,14 +1384,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
|||||||
data->o->file, set, reset, ws);
|
data->o->file, set, reset, ws);
|
||||||
} else if (line[0] == ' ') {
|
} else if (line[0] == ' ') {
|
||||||
data->lineno++;
|
data->lineno++;
|
||||||
data->trailing_blanks_start = 0;
|
|
||||||
} else if (line[0] == '@') {
|
} else if (line[0] == '@') {
|
||||||
char *plus = strchr(line, '+');
|
char *plus = strchr(line, '+');
|
||||||
if (plus)
|
if (plus)
|
||||||
data->lineno = strtol(plus, NULL, 10) - 1;
|
data->lineno = strtol(plus, NULL, 10) - 1;
|
||||||
else
|
else
|
||||||
die("invalid diff");
|
die("invalid diff");
|
||||||
data->trailing_blanks_start = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1562,6 +1666,8 @@ static void builtin_diff(const char *name_a,
|
|||||||
ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
|
ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
|
||||||
ecbdata.found_changesp = &o->found_changes;
|
ecbdata.found_changesp = &o->found_changes;
|
||||||
ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
|
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;
|
ecbdata.file = o->file;
|
||||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||||
xecfg.ctxlen = o->context;
|
xecfg.ctxlen = o->context;
|
||||||
@ -1704,11 +1810,22 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
|||||||
xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
|
xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
|
||||||
&xpp, &xecfg, &ecb);
|
&xpp, &xecfg, &ecb);
|
||||||
|
|
||||||
if ((data.ws_rule & WS_TRAILING_SPACE) &&
|
if (data.ws_rule & WS_BLANK_AT_EOF) {
|
||||||
data.trailing_blanks_start) {
|
struct emit_callback ecbdata;
|
||||||
fprintf(o->file, "%s:%d: ends with blank lines.\n",
|
int blank_at_eof;
|
||||||
data.filename, data.trailing_blanks_start);
|
|
||||||
data.status = 1; /* report errors */
|
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:
|
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 "foo();" >x &&
|
||||||
echo "" >>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' '
|
test_expect_success 'checkdiff allows new blank lines' '
|
||||||
|
@ -165,7 +165,7 @@ test_expect_success 'trailing empty lines (1)' '
|
|||||||
|
|
||||||
rm -f .gitattributes &&
|
rm -f .gitattributes &&
|
||||||
test_must_fail git diff --check >output &&
|
test_must_fail git diff --check >output &&
|
||||||
grep "ends with blank lines." output &&
|
grep "new blank line at" output &&
|
||||||
grep "trailing whitespace" 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
|
test_done
|
||||||
|
@ -170,4 +170,95 @@ test_expect_success 'trailing whitespace & no newline at the end of file' '
|
|||||||
grep "^$" target
|
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
|
test_done
|
||||||
|
19
ws.c
19
ws.c
@ -16,6 +16,8 @@ static struct whitespace_rule {
|
|||||||
{ "space-before-tab", WS_SPACE_BEFORE_TAB, 0 },
|
{ "space-before-tab", WS_SPACE_BEFORE_TAB, 0 },
|
||||||
{ "indent-with-non-tab", WS_INDENT_WITH_NON_TAB, 0 },
|
{ "indent-with-non-tab", WS_INDENT_WITH_NON_TAB, 0 },
|
||||||
{ "cr-at-eol", WS_CR_AT_EOL, 1 },
|
{ "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)
|
unsigned parse_whitespace_rule(const char *string)
|
||||||
@ -102,8 +104,17 @@ unsigned whitespace_rule(const char *pathname)
|
|||||||
char *whitespace_error_string(unsigned ws)
|
char *whitespace_error_string(unsigned ws)
|
||||||
{
|
{
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
if (ws & WS_TRAILING_SPACE)
|
if ((ws & WS_TRAILING_SPACE) == WS_TRAILING_SPACE)
|
||||||
strbuf_addstr(&err, "trailing whitespace");
|
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 (ws & WS_SPACE_BEFORE_TAB) {
|
||||||
if (err.len)
|
if (err.len)
|
||||||
strbuf_addstr(&err, ", ");
|
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. */
|
/* Check for trailing whitespace. */
|
||||||
if (ws_rule & WS_TRAILING_SPACE) {
|
if (ws_rule & WS_BLANK_AT_EOL) {
|
||||||
for (i = len - 1; i >= 0; i--) {
|
for (i = len - 1; i >= 0; i--) {
|
||||||
if (isspace(line[i])) {
|
if (isspace(line[i])) {
|
||||||
trailing_whitespace = i;
|
trailing_whitespace = i;
|
||||||
result |= WS_TRAILING_SPACE;
|
result |= WS_BLANK_AT_EOL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@ -261,7 +272,7 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro
|
|||||||
/*
|
/*
|
||||||
* Strip trailing whitespace
|
* Strip trailing whitespace
|
||||||
*/
|
*/
|
||||||
if (ws_rule & WS_TRAILING_SPACE) {
|
if (ws_rule & WS_BLANK_AT_EOL) {
|
||||||
if (0 < len && src[len - 1] == '\n') {
|
if (0 < len && src[len - 1] == '\n') {
|
||||||
add_nl_to_tail = 1;
|
add_nl_to_tail = 1;
|
||||||
len--;
|
len--;
|
||||||
|
Loading…
Reference in New Issue
Block a user