aboutsummaryrefslogtreecommitdiff
path: root/ws.c
diff options
context:
space:
mode:
authorWincent Colaiuta <win@wincent.com>2007-12-13 14:32:29 +0100
committerJunio C Hamano <gitster@pobox.com>2007-12-13 23:43:58 -0800
commitc1795bb08aae9fb7e4dc1a01e292b85e59b1c640 (patch)
treeac058e760489ae65eb89daa910cd721492c7e64a /ws.c
parentda31b358fb39b32622c14343ffe157a765f3948b (diff)
downloadgit-c1795bb08aae9fb7e4dc1a01e292b85e59b1c640.tar.gz
git-c1795bb08aae9fb7e4dc1a01e292b85e59b1c640.tar.xz
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>
Diffstat (limited to 'ws.c')
-rw-r--r--ws.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/ws.c b/ws.c
index 52c10caf3..d7d1522f8 100644
--- a/ws.c
+++ b/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;
+}