Merge branch 'jc/whitespace'
* jc/whitespace: git-apply: second war on whitespace. diff.c: second war on whitespace.
This commit is contained in:
commit
f2ce6a4c3c
122
builtin-apply.c
122
builtin-apply.c
@ -854,6 +854,49 @@ 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)
|
||||||
|
{
|
||||||
|
const char *err = "Adds trailing whitespace";
|
||||||
|
int seen_space = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We know len is at least two, since we have a '+' and we
|
||||||
|
* checked that the last character was a '\n' before calling
|
||||||
|
* this function. That is, an addition of an empty line would
|
||||||
|
* check the '+' here. Sneaky...
|
||||||
|
*/
|
||||||
|
if (isspace(line[len-2]))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure that there is no space followed by a tab in
|
||||||
|
* indentation.
|
||||||
|
*/
|
||||||
|
err = "Space in indent is followed by a tab";
|
||||||
|
for (i = 1; i < len; i++) {
|
||||||
|
if (line[i] == '\t') {
|
||||||
|
if (seen_space)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else if (line[i] == ' ')
|
||||||
|
seen_space = 1;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
whitespace_error++;
|
||||||
|
if (squelch_whitespace_errors &&
|
||||||
|
squelch_whitespace_errors < whitespace_error)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s.\n%s:%d:%.*s\n",
|
||||||
|
err, patch_input_file, linenr, len-2, line+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a unified diff. Note that this really needs to parse each
|
* Parse a unified diff. Note that this really needs to parse each
|
||||||
* fragment separately, since the only way to know the difference
|
* fragment separately, since the only way to know the difference
|
||||||
@ -904,25 +947,8 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
|
|||||||
trailing = 0;
|
trailing = 0;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
/*
|
if (new_whitespace != nowarn_whitespace)
|
||||||
* We know len is at least two, since we have a '+' and
|
check_whitespace(line, len);
|
||||||
* we checked that the last character was a '\n' above.
|
|
||||||
* That is, an addition of an empty line would check
|
|
||||||
* the '+' here. Sneaky...
|
|
||||||
*/
|
|
||||||
if ((new_whitespace != nowarn_whitespace) &&
|
|
||||||
isspace(line[len-2])) {
|
|
||||||
whitespace_error++;
|
|
||||||
if (squelch_whitespace_errors &&
|
|
||||||
squelch_whitespace_errors <
|
|
||||||
whitespace_error)
|
|
||||||
;
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Adds trailing whitespace.\n%s:%d:%.*s\n",
|
|
||||||
patch_input_file,
|
|
||||||
linenr, len-2, line+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
added++;
|
added++;
|
||||||
newlines--;
|
newlines--;
|
||||||
trailing = 0;
|
trailing = 0;
|
||||||
@ -1494,22 +1520,68 @@ static int apply_line(char *output, const char *patch, int plen)
|
|||||||
{
|
{
|
||||||
/* plen is number of bytes to be copied from patch,
|
/* plen is number of bytes to be copied from patch,
|
||||||
* starting at patch+1 (patch[0] is '+'). Typically
|
* starting at patch+1 (patch[0] is '+'). Typically
|
||||||
* patch[plen] is '\n'.
|
* patch[plen] is '\n', unless this is the incomplete
|
||||||
|
* last line.
|
||||||
*/
|
*/
|
||||||
|
int i;
|
||||||
int add_nl_to_tail = 0;
|
int add_nl_to_tail = 0;
|
||||||
if ((new_whitespace == strip_whitespace) &&
|
int fixed = 0;
|
||||||
1 < plen && isspace(patch[plen-1])) {
|
int last_tab_in_indent = -1;
|
||||||
|
int last_space_in_indent = -1;
|
||||||
|
int need_fix_leading_space = 0;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if ((new_whitespace != strip_whitespace) || !whitespace_error) {
|
||||||
|
memcpy(output, patch + 1, plen);
|
||||||
|
return plen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 < plen && isspace(patch[plen-1])) {
|
||||||
if (patch[plen] == '\n')
|
if (patch[plen] == '\n')
|
||||||
add_nl_to_tail = 1;
|
add_nl_to_tail = 1;
|
||||||
plen--;
|
plen--;
|
||||||
while (0 < plen && isspace(patch[plen]))
|
while (0 < plen && isspace(patch[plen]))
|
||||||
plen--;
|
plen--;
|
||||||
applied_after_stripping++;
|
fixed = 1;
|
||||||
}
|
}
|
||||||
memcpy(output, patch + 1, plen);
|
|
||||||
|
for (i = 1; i < plen; i++) {
|
||||||
|
char ch = patch[i];
|
||||||
|
if (ch == '\t') {
|
||||||
|
last_tab_in_indent = i;
|
||||||
|
if (0 <= last_space_in_indent)
|
||||||
|
need_fix_leading_space = 1;
|
||||||
|
}
|
||||||
|
else if (ch == ' ')
|
||||||
|
last_space_in_indent = i;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = output;
|
||||||
|
if (need_fix_leading_space) {
|
||||||
|
/* between patch[1..last_tab_in_indent] strip the
|
||||||
|
* funny spaces, updating them to tab as needed.
|
||||||
|
*/
|
||||||
|
for (i = 1; i < last_tab_in_indent; i++, plen--) {
|
||||||
|
char ch = patch[i];
|
||||||
|
if (ch != ' ')
|
||||||
|
*output++ = ch;
|
||||||
|
else if ((i % 8) == 0)
|
||||||
|
*output++ = '\t';
|
||||||
|
}
|
||||||
|
fixed = 1;
|
||||||
|
i = last_tab_in_indent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i = 1;
|
||||||
|
|
||||||
|
memcpy(output, patch + i, plen);
|
||||||
if (add_nl_to_tail)
|
if (add_nl_to_tail)
|
||||||
output[plen++] = '\n';
|
output[plen++] = '\n';
|
||||||
return plen;
|
if (fixed)
|
||||||
|
applied_after_stripping++;
|
||||||
|
return output + plen - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
|
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
|
||||||
|
172
diff.c
172
diff.c
@ -20,12 +20,13 @@ static int diff_use_color_default;
|
|||||||
|
|
||||||
static char diff_colors[][COLOR_MAXLEN] = {
|
static char diff_colors[][COLOR_MAXLEN] = {
|
||||||
"\033[m", /* reset */
|
"\033[m", /* reset */
|
||||||
"", /* normal */
|
"", /* PLAIN (normal) */
|
||||||
"\033[1m", /* bold */
|
"\033[1m", /* METAINFO (bold) */
|
||||||
"\033[36m", /* cyan */
|
"\033[36m", /* FRAGINFO (cyan) */
|
||||||
"\033[31m", /* red */
|
"\033[31m", /* OLD (red) */
|
||||||
"\033[32m", /* green */
|
"\033[32m", /* NEW (green) */
|
||||||
"\033[33m" /* yellow */
|
"\033[33m", /* COMMIT (yellow) */
|
||||||
|
"\033[41m", /* WHITESPACE (red background) */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int parse_diff_color_slot(const char *var, int ofs)
|
static int parse_diff_color_slot(const char *var, int ofs)
|
||||||
@ -42,6 +43,8 @@ static int parse_diff_color_slot(const char *var, int ofs)
|
|||||||
return DIFF_FILE_NEW;
|
return DIFF_FILE_NEW;
|
||||||
if (!strcasecmp(var+ofs, "commit"))
|
if (!strcasecmp(var+ofs, "commit"))
|
||||||
return DIFF_COMMIT;
|
return DIFF_COMMIT;
|
||||||
|
if (!strcasecmp(var+ofs, "whitespace"))
|
||||||
|
return DIFF_WHITESPACE;
|
||||||
die("bad config variable '%s'", var);
|
die("bad config variable '%s'", var);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,9 +386,89 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void emit_line(const char *set, const char *reset, const char *line, int len)
|
||||||
|
{
|
||||||
|
if (len > 0 && line[len-1] == '\n')
|
||||||
|
len--;
|
||||||
|
fputs(set, stdout);
|
||||||
|
fwrite(line, len, 1, stdout);
|
||||||
|
puts(reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
|
||||||
|
{
|
||||||
|
int col0 = ecbdata->nparents;
|
||||||
|
int last_tab_in_indent = -1;
|
||||||
|
int last_space_in_indent = -1;
|
||||||
|
int i;
|
||||||
|
int tail = len;
|
||||||
|
int need_highlight_leading_space = 0;
|
||||||
|
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(set, reset, line, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The line is a newly added line. Does it have funny leading
|
||||||
|
* whitespaces? In indent, SP should never precede a TAB.
|
||||||
|
*/
|
||||||
|
for (i = col0; i < len; i++) {
|
||||||
|
if (line[i] == '\t') {
|
||||||
|
last_tab_in_indent = i;
|
||||||
|
if (0 <= last_space_in_indent)
|
||||||
|
need_highlight_leading_space = 1;
|
||||||
|
}
|
||||||
|
else if (line[i] == ' ')
|
||||||
|
last_space_in_indent = i;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fputs(set, stdout);
|
||||||
|
fwrite(line, col0, 1, stdout);
|
||||||
|
fputs(reset, stdout);
|
||||||
|
if (((i == len) || line[i] == '\n') && i != col0) {
|
||||||
|
/* The whole line was indent */
|
||||||
|
emit_line(ws, reset, line + col0, len - col0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i = col0;
|
||||||
|
if (need_highlight_leading_space) {
|
||||||
|
while (i < last_tab_in_indent) {
|
||||||
|
if (line[i] == ' ') {
|
||||||
|
fputs(ws, stdout);
|
||||||
|
putchar(' ');
|
||||||
|
fputs(reset, stdout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
putchar(line[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tail = len - 1;
|
||||||
|
if (line[tail] == '\n' && i < tail)
|
||||||
|
tail--;
|
||||||
|
while (i < tail) {
|
||||||
|
if (!isspace(line[tail]))
|
||||||
|
break;
|
||||||
|
tail--;
|
||||||
|
}
|
||||||
|
if ((i < tail && line[tail + 1] != '\n')) {
|
||||||
|
/* This has whitespace between tail+1..len */
|
||||||
|
fputs(set, stdout);
|
||||||
|
fwrite(line + i, tail - i + 1, 1, stdout);
|
||||||
|
fputs(reset, stdout);
|
||||||
|
emit_line(ws, reset, line + tail + 1, len - tail - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
emit_line(set, reset, line + i, len - i);
|
||||||
|
}
|
||||||
|
|
||||||
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 i;
|
||||||
|
int color;
|
||||||
struct emit_callback *ecbdata = priv;
|
struct emit_callback *ecbdata = priv;
|
||||||
const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
|
const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
|
||||||
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
|
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
|
||||||
@ -403,45 +486,52 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
;
|
;
|
||||||
if (2 <= i && i < len && line[i] == ' ') {
|
if (2 <= i && i < len && line[i] == ' ') {
|
||||||
ecbdata->nparents = i - 1;
|
ecbdata->nparents = i - 1;
|
||||||
set = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);
|
emit_line(diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
|
||||||
|
reset, line, len);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (len < ecbdata->nparents)
|
|
||||||
|
if (len < ecbdata->nparents) {
|
||||||
set = reset;
|
set = reset;
|
||||||
else {
|
emit_line(reset, reset, line, len);
|
||||||
int nparents = ecbdata->nparents;
|
return;
|
||||||
int color = DIFF_PLAIN;
|
|
||||||
if (ecbdata->diff_words && nparents != 1)
|
|
||||||
/* fall back to normal diff */
|
|
||||||
free_diff_words_data(ecbdata);
|
|
||||||
if (ecbdata->diff_words) {
|
|
||||||
if (line[0] == '-') {
|
|
||||||
diff_words_append(line, len,
|
|
||||||
&ecbdata->diff_words->minus);
|
|
||||||
return;
|
|
||||||
} else if (line[0] == '+') {
|
|
||||||
diff_words_append(line, len,
|
|
||||||
&ecbdata->diff_words->plus);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ecbdata->diff_words->minus.text.size ||
|
|
||||||
ecbdata->diff_words->plus.text.size)
|
|
||||||
diff_words_show(ecbdata->diff_words);
|
|
||||||
line++;
|
|
||||||
len--;
|
|
||||||
} else
|
|
||||||
for (i = 0; i < nparents && len; i++) {
|
|
||||||
if (line[i] == '-')
|
|
||||||
color = DIFF_FILE_OLD;
|
|
||||||
else if (line[i] == '+')
|
|
||||||
color = DIFF_FILE_NEW;
|
|
||||||
}
|
|
||||||
set = diff_get_color(ecbdata->color_diff, color);
|
|
||||||
}
|
}
|
||||||
if (len > 0 && line[len-1] == '\n')
|
|
||||||
|
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,
|
||||||
|
&ecbdata->diff_words->minus);
|
||||||
|
return;
|
||||||
|
} else if (line[0] == '+') {
|
||||||
|
diff_words_append(line, len,
|
||||||
|
&ecbdata->diff_words->plus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ecbdata->diff_words->minus.text.size ||
|
||||||
|
ecbdata->diff_words->plus.text.size)
|
||||||
|
diff_words_show(ecbdata->diff_words);
|
||||||
|
line++;
|
||||||
len--;
|
len--;
|
||||||
fputs (set, stdout);
|
emit_line(set, reset, line, len);
|
||||||
fwrite (line, len, 1, stdout);
|
return;
|
||||||
puts (reset);
|
}
|
||||||
|
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(diff_get_color(ecbdata->color_diff, color),
|
||||||
|
reset, line, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
1
diff.h
1
diff.h
@ -86,6 +86,7 @@ enum color_diff {
|
|||||||
DIFF_FILE_OLD = 4,
|
DIFF_FILE_OLD = 4,
|
||||||
DIFF_FILE_NEW = 5,
|
DIFF_FILE_NEW = 5,
|
||||||
DIFF_COMMIT = 6,
|
DIFF_COMMIT = 6,
|
||||||
|
DIFF_WHITESPACE = 7,
|
||||||
};
|
};
|
||||||
const char *diff_get_color(int diff_use_color, enum color_diff ix);
|
const char *diff_get_color(int diff_use_color, enum color_diff ix);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user