Unify whitespace checking
This commit unifies three separate places where whitespace checking was performed: - the whitespace checking previously done in builtin-apply.c is extracted into a function in ws.c - the equivalent logic in "git diff" is removed - the emit_line_with_ws() function is also removed because that also rechecks the whitespace, and its functionality is rolled into ws.c The new function is called check_and_emit_line() and it does two things: checks a line for whitespace errors and optionally emits it. The checking is based on lines of content rather than patch lines (in other words, the caller must strip the leading "+" or "-"); this was suggested by Junio on the mailing list to allow for a future extension to "git show" to display whitespace errors in blobs. At the same time we teach it to report all classes of whitespace errors found for a given line rather than reporting only the first found error. Signed-off-by: Wincent Colaiuta <win@wincent.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
da31b358fb
commit
c1795bb08a
105
ws.c
105
ws.c
@ -94,3 +94,108 @@ unsigned whitespace_rule(const char *pathname)
|
||||
return whitespace_rule_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
/* The returned string should be freed by the caller. */
|
||||
char *whitespace_error_string(unsigned ws)
|
||||
{
|
||||
struct strbuf err;
|
||||
strbuf_init(&err, 0);
|
||||
if (ws & WS_TRAILING_SPACE)
|
||||
strbuf_addstr(&err, "Adds trailing whitespace");
|
||||
if (ws & WS_SPACE_BEFORE_TAB) {
|
||||
if (err.len)
|
||||
strbuf_addstr(&err, ", ");
|
||||
strbuf_addstr(&err, "Space in indent is followed by a tab");
|
||||
}
|
||||
if (ws & WS_INDENT_WITH_NON_TAB) {
|
||||
if (err.len)
|
||||
strbuf_addstr(&err, ", ");
|
||||
strbuf_addstr(&err, "Indent more than 8 places with spaces");
|
||||
}
|
||||
return strbuf_detach(&err, NULL);
|
||||
}
|
||||
|
||||
/* If stream is non-NULL, emits the line after checking. */
|
||||
unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule,
|
||||
FILE *stream, const char *set,
|
||||
const char *reset, const char *ws)
|
||||
{
|
||||
unsigned result = 0;
|
||||
int leading_space = -1;
|
||||
int trailing_whitespace = -1;
|
||||
int trailing_newline = 0;
|
||||
int i;
|
||||
|
||||
/* Logic is simpler if we temporarily ignore the trailing newline. */
|
||||
if (len > 0 && line[len - 1] == '\n') {
|
||||
trailing_newline = 1;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Check for trailing whitespace. */
|
||||
if (ws_rule & WS_TRAILING_SPACE) {
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
if (isspace(line[i])) {
|
||||
trailing_whitespace = i;
|
||||
result |= WS_TRAILING_SPACE;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for space before tab in initial indent. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (line[i] == '\t') {
|
||||
if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
|
||||
(leading_space != -1))
|
||||
result |= WS_SPACE_BEFORE_TAB;
|
||||
break;
|
||||
}
|
||||
else if (line[i] == ' ')
|
||||
leading_space = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for indent using non-tab. */
|
||||
if ((ws_rule & WS_INDENT_WITH_NON_TAB) && leading_space >= 8)
|
||||
result |= WS_INDENT_WITH_NON_TAB;
|
||||
|
||||
if (stream) {
|
||||
/* Highlight errors in leading whitespace. */
|
||||
if ((result & WS_SPACE_BEFORE_TAB) ||
|
||||
(result & WS_INDENT_WITH_NON_TAB)) {
|
||||
fputs(ws, stream);
|
||||
fwrite(line, leading_space + 1, 1, stream);
|
||||
fputs(reset, stream);
|
||||
leading_space++;
|
||||
}
|
||||
else
|
||||
leading_space = 0;
|
||||
|
||||
/* Now the rest of the line starts at leading_space.
|
||||
* The non-highlighted part ends at trailing_whitespace. */
|
||||
if (trailing_whitespace == -1)
|
||||
trailing_whitespace = len;
|
||||
|
||||
/* Emit non-highlighted (middle) segment. */
|
||||
if (trailing_whitespace - leading_space > 0) {
|
||||
fputs(set, stream);
|
||||
fwrite(line + leading_space,
|
||||
trailing_whitespace - leading_space, 1, stream);
|
||||
fputs(reset, stream);
|
||||
}
|
||||
|
||||
/* Highlight errors in trailing whitespace. */
|
||||
if (trailing_whitespace != len) {
|
||||
fputs(ws, stream);
|
||||
fwrite(line + trailing_whitespace,
|
||||
len - trailing_whitespace, 1, stream);
|
||||
fputs(reset, stream);
|
||||
}
|
||||
if (trailing_newline)
|
||||
fputc('\n', stream);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user