mirror of
https://github.com/git/git.git
synced 2026-01-10 01:56:42 +00:00
Merge branch 'jc/whitespace-incomplete-line'
Both "git apply" and "git diff" learn a new whitespace error class, "incomplete-line". * jc/whitespace-incomplete-line: attr: enable incomplete-line whitespace error for this project diff: highlight and error out on incomplete lines apply: check and fix incomplete lines whitespace: allocate a few more bits and define WS_INCOMPLETE_LINE apply: revamp the parsing of incomplete lines diff: update the way rewrite diff handles incomplete lines diff: call emit_callback ecbdata everywhere diff: refactor output of incomplete line diff: keep track of the type of the last line seen diff: correct suppress_blank_empty hack diff: emit_line_ws_markup() if/else style fix whitespace: correct bit assignment comments
This commit is contained in:
147
diff.c
147
diff.c
@@ -601,6 +601,7 @@ struct emit_callback {
|
||||
int blank_at_eof_in_postimage;
|
||||
int lno_in_preimage;
|
||||
int lno_in_postimage;
|
||||
int last_line_kind;
|
||||
const char **label_path;
|
||||
struct diff_words_data *diff_words;
|
||||
struct diff_options *opt;
|
||||
@@ -796,21 +797,23 @@ enum diff_symbol {
|
||||
DIFF_SYMBOL_CONTEXT_INCOMPLETE,
|
||||
DIFF_SYMBOL_PLUS,
|
||||
DIFF_SYMBOL_MINUS,
|
||||
DIFF_SYMBOL_NO_LF_EOF,
|
||||
DIFF_SYMBOL_CONTEXT_FRAGINFO,
|
||||
DIFF_SYMBOL_CONTEXT_MARKER,
|
||||
DIFF_SYMBOL_SEPARATOR
|
||||
};
|
||||
|
||||
/*
|
||||
* Flags for content lines:
|
||||
* 0..12 are whitespace rules
|
||||
* 13-15 are WSEH_NEW | WSEH_OLD | WSEH_CONTEXT
|
||||
* 16 is marking if the line is blank at EOF
|
||||
* 0..15 are whitespace rules (see ws.h)
|
||||
* 16..18 are WSEH_NEW | WSEH_CONTEXT | WSEH_OLD
|
||||
* 19 is marking if the line is blank at EOF
|
||||
* 20..22 are used for color-moved.
|
||||
*/
|
||||
#define DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF (1<<16)
|
||||
#define DIFF_SYMBOL_MOVED_LINE (1<<17)
|
||||
#define DIFF_SYMBOL_MOVED_LINE_ALT (1<<18)
|
||||
#define DIFF_SYMBOL_MOVED_LINE_UNINTERESTING (1<<19)
|
||||
#define DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF (1<<19)
|
||||
#define DIFF_SYMBOL_MOVED_LINE (1<<20)
|
||||
#define DIFF_SYMBOL_MOVED_LINE_ALT (1<<21)
|
||||
#define DIFF_SYMBOL_MOVED_LINE_UNINTERESTING (1<<22)
|
||||
|
||||
#define DIFF_SYMBOL_CONTENT_WS_MASK (WSEH_NEW | WSEH_OLD | WSEH_CONTEXT | WS_RULE_MASK)
|
||||
|
||||
/*
|
||||
@@ -1318,20 +1321,25 @@ static void emit_line_ws_markup(struct diff_options *o,
|
||||
const char *ws = NULL;
|
||||
int sign = o->output_indicators[sign_index];
|
||||
|
||||
if (diff_suppress_blank_empty &&
|
||||
sign_index == OUTPUT_INDICATOR_CONTEXT &&
|
||||
len == 1 && line[0] == '\n')
|
||||
sign = 0;
|
||||
|
||||
if (o->ws_error_highlight & ws_rule) {
|
||||
ws = diff_get_color_opt(o, DIFF_WHITESPACE);
|
||||
if (!*ws)
|
||||
ws = NULL;
|
||||
}
|
||||
|
||||
if (!ws && !set_sign)
|
||||
if (!ws && !set_sign) {
|
||||
emit_line_0(o, set, NULL, 0, reset, sign, line, len);
|
||||
else if (!ws) {
|
||||
} else if (!ws) {
|
||||
emit_line_0(o, set_sign, set, !!set_sign, reset, sign, line, len);
|
||||
} else if (blank_at_eof)
|
||||
} else if (blank_at_eof) {
|
||||
/* Blank line at EOF - paint '+' as well */
|
||||
emit_line_0(o, ws, NULL, 0, reset, sign, line, len);
|
||||
else {
|
||||
} else {
|
||||
/* Emit just the prefix, then the rest. */
|
||||
emit_line_0(o, set_sign ? set_sign : set, NULL, !!set_sign, reset,
|
||||
sign, "", 0);
|
||||
@@ -1343,7 +1351,6 @@ static void emit_line_ws_markup(struct diff_options *o,
|
||||
static void emit_diff_symbol_from_struct(struct diff_options *o,
|
||||
struct emitted_diff_symbol *eds)
|
||||
{
|
||||
static const char *nneof = " No newline at end of file\n";
|
||||
const char *context, *reset, *set, *set_sign, *meta, *fraginfo;
|
||||
|
||||
enum diff_symbol s = eds->s;
|
||||
@@ -1355,13 +1362,6 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
|
||||
return;
|
||||
|
||||
switch (s) {
|
||||
case DIFF_SYMBOL_NO_LF_EOF:
|
||||
context = diff_get_color_opt(o, DIFF_CONTEXT);
|
||||
reset = diff_get_color_opt(o, DIFF_RESET);
|
||||
putc('\n', o->file);
|
||||
emit_line_0(o, context, NULL, 0, reset, '\\',
|
||||
nneof, strlen(nneof));
|
||||
break;
|
||||
case DIFF_SYMBOL_SUBMODULE_HEADER:
|
||||
case DIFF_SYMBOL_SUBMODULE_ERROR:
|
||||
case DIFF_SYMBOL_SUBMODULE_PIPETHROUGH:
|
||||
@@ -1373,6 +1373,14 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
|
||||
emit_line(o, "", "", line, len);
|
||||
break;
|
||||
case DIFF_SYMBOL_CONTEXT_INCOMPLETE:
|
||||
if ((flags & WS_INCOMPLETE_LINE) &&
|
||||
(flags & o->ws_error_highlight))
|
||||
set = diff_get_color_opt(o, DIFF_WHITESPACE);
|
||||
else
|
||||
set = diff_get_color_opt(o, DIFF_CONTEXT);
|
||||
reset = diff_get_color_opt(o, DIFF_RESET);
|
||||
emit_line(o, set, reset, line, len);
|
||||
break;
|
||||
case DIFF_SYMBOL_CONTEXT_MARKER:
|
||||
context = diff_get_color_opt(o, DIFF_CONTEXT);
|
||||
reset = diff_get_color_opt(o, DIFF_RESET);
|
||||
@@ -1498,15 +1506,9 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
|
||||
case DIFF_SYMBOL_WORDS:
|
||||
context = diff_get_color_opt(o, DIFF_CONTEXT);
|
||||
reset = diff_get_color_opt(o, DIFF_RESET);
|
||||
/*
|
||||
* Skip the prefix character, if any. With
|
||||
* diff_suppress_blank_empty, there may be
|
||||
* none.
|
||||
*/
|
||||
if (line[0] != '\n') {
|
||||
line++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Skip the prefix character */
|
||||
line++; len--;
|
||||
emit_line(o, context, reset, line, len);
|
||||
break;
|
||||
case DIFF_SYMBOL_FILEPAIR_PLUS:
|
||||
@@ -1668,6 +1670,19 @@ static void emit_context_line(struct emit_callback *ecbdata,
|
||||
emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_CONTEXT, line, len, flags);
|
||||
}
|
||||
|
||||
static void emit_incomplete_line_marker(struct emit_callback *ecbdata,
|
||||
const char *line, int len)
|
||||
{
|
||||
int last_line_kind = ecbdata->last_line_kind;
|
||||
unsigned flags = (last_line_kind == '+'
|
||||
? WSEH_NEW
|
||||
: last_line_kind == '-'
|
||||
? WSEH_OLD
|
||||
: WSEH_CONTEXT) | ecbdata->ws_rule;
|
||||
emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_CONTEXT_INCOMPLETE,
|
||||
line, len, flags);
|
||||
}
|
||||
|
||||
static void emit_hunk_header(struct emit_callback *ecbdata,
|
||||
const char *line, int len)
|
||||
{
|
||||
@@ -1769,28 +1784,44 @@ static void add_line_count(struct strbuf *out, int count)
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_rewrite_lines(struct emit_callback *ecb,
|
||||
static void emit_rewrite_lines(struct emit_callback *ecbdata,
|
||||
int prefix, const char *data, int size)
|
||||
{
|
||||
const char *endp = NULL;
|
||||
|
||||
while (0 < size) {
|
||||
int len;
|
||||
int len, plen;
|
||||
char *pdata = NULL;
|
||||
|
||||
endp = memchr(data, '\n', size);
|
||||
len = endp ? (endp - data + 1) : size;
|
||||
if (prefix != '+') {
|
||||
ecb->lno_in_preimage++;
|
||||
emit_del_line(ecb, data, len);
|
||||
|
||||
if (endp) {
|
||||
len = endp - data + 1;
|
||||
plen = len;
|
||||
} else {
|
||||
ecb->lno_in_postimage++;
|
||||
emit_add_line(ecb, data, len);
|
||||
len = size;
|
||||
plen = len + 1;
|
||||
pdata = xmalloc(plen + 2);
|
||||
memcpy(pdata, data, len);
|
||||
pdata[len] = '\n';
|
||||
pdata[len + 1] = '\0';
|
||||
}
|
||||
if (prefix != '+') {
|
||||
ecbdata->lno_in_preimage++;
|
||||
emit_del_line(ecbdata, pdata ? pdata : data, plen);
|
||||
} else {
|
||||
ecbdata->lno_in_postimage++;
|
||||
emit_add_line(ecbdata, pdata ? pdata : data, plen);
|
||||
}
|
||||
free(pdata);
|
||||
size -= len;
|
||||
data += len;
|
||||
}
|
||||
if (!endp)
|
||||
emit_diff_symbol(ecb->opt, DIFF_SYMBOL_NO_LF_EOF, NULL, 0, 0);
|
||||
if (!endp) {
|
||||
static const char nneof[] = "\\ No newline at end of file\n";
|
||||
ecbdata->last_line_kind = prefix;
|
||||
emit_incomplete_line_marker(ecbdata, nneof, sizeof(nneof) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_rewrite_diff(const char *name_a,
|
||||
@@ -2375,12 +2406,6 @@ static int fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
|
||||
}
|
||||
|
||||
if (diff_suppress_blank_empty
|
||||
&& len == 2 && line[0] == ' ' && line[1] == '\n') {
|
||||
line[0] = '\n';
|
||||
len = 1;
|
||||
}
|
||||
|
||||
if (line[0] == '@') {
|
||||
if (ecbdata->diff_words)
|
||||
diff_words_flush(ecbdata);
|
||||
@@ -2431,13 +2456,24 @@ static int fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
ecbdata->lno_in_preimage++;
|
||||
emit_context_line(ecbdata, line + 1, len - 1);
|
||||
break;
|
||||
default:
|
||||
case '\\':
|
||||
/* incomplete line at the end */
|
||||
switch (ecbdata->last_line_kind) {
|
||||
case '+':
|
||||
case '-':
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
BUG("fn_out_consume: '\\No newline' after unknown line (%c)",
|
||||
ecbdata->last_line_kind);
|
||||
}
|
||||
ecbdata->lno_in_preimage++;
|
||||
emit_diff_symbol(o, DIFF_SYMBOL_CONTEXT_INCOMPLETE,
|
||||
line, len, 0);
|
||||
emit_incomplete_line_marker(ecbdata, line, len);
|
||||
break;
|
||||
default:
|
||||
BUG("fn_out_consume: unknown line '%s'", line);
|
||||
}
|
||||
ecbdata->last_line_kind = line[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3231,6 +3267,7 @@ struct checkdiff_t {
|
||||
struct diff_options *o;
|
||||
unsigned ws_rule;
|
||||
unsigned status;
|
||||
int last_line_kind;
|
||||
};
|
||||
|
||||
static int is_conflict_marker(const char *line, int marker_size, unsigned long len)
|
||||
@@ -3269,6 +3306,7 @@ static void checkdiff_consume_hunk(void *priv,
|
||||
static int checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
{
|
||||
struct checkdiff_t *data = priv;
|
||||
int last_line_kind;
|
||||
int marker_size = data->conflict_marker_size;
|
||||
const char *ws = diff_get_color(data->o->use_color, DIFF_WHITESPACE);
|
||||
const char *reset = diff_get_color(data->o->use_color, DIFF_RESET);
|
||||
@@ -3279,6 +3317,8 @@ static int checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
assert(data->o);
|
||||
line_prefix = diff_line_prefix(data->o);
|
||||
|
||||
last_line_kind = data->last_line_kind;
|
||||
data->last_line_kind = line[0];
|
||||
if (line[0] == '+') {
|
||||
unsigned bad;
|
||||
data->lineno++;
|
||||
@@ -3301,6 +3341,17 @@ static int checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
data->o->file, set, reset, ws);
|
||||
} else if (line[0] == ' ') {
|
||||
data->lineno++;
|
||||
} else if (line[0] == '\\') {
|
||||
/* no newline at the end of the line */
|
||||
if ((data->ws_rule & WS_INCOMPLETE_LINE) &&
|
||||
(last_line_kind == '+')) {
|
||||
unsigned bad = WS_INCOMPLETE_LINE;
|
||||
data->status |= bad;
|
||||
err = whitespace_error_string(bad);
|
||||
fprintf(data->o->file, "%s%s:%d: %s.\n",
|
||||
line_prefix, data->filename, data->lineno, err);
|
||||
free(err);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user