whitespace: add tab-in-indent error class
authorChris Webb <chris@arachsys.com>
Fri, 2 Apr 2010 23:37:08 +0000 (00:37 +0100)
committerJunio C Hamano <gitster@pobox.com>
Sat, 3 Apr 2010 04:08:04 +0000 (21:08 -0700)
Some projects and languages use coding style where no tab character is used to
indent the lines.

This only adds support and documentation for "apply --whitespace=warn" and
"diff --check"; later patches add "apply --whitespace=fix" and tests.

Signed-off-by: Chris Webb <chris@arachsys.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt
cache.h
ws.c

index 06b2f827b414651bde25165b4f42dc4160892d7a..9bb8f3d8985eaefac983fa3a468650b1792c2dd4 100644 (file)
@@ -481,6 +481,8 @@ core.whitespace::
   error (enabled by default).
 * `indent-with-non-tab` treats a line that is indented with 8 or more
   space characters as an error (not enabled by default).
+* `tab-in-indent` treats a tab character in the initial indent part of
+  the line 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
diff --git a/cache.h b/cache.h
index 6dcb100a6cfc1b1d311602507bc3dcb483c1558d..030af327f72d6c117b46175e44a74a155f765a97 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1040,6 +1040,7 @@ void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char *
 #define WS_INDENT_WITH_NON_TAB 04
 #define WS_CR_AT_EOL           010
 #define WS_BLANK_AT_EOF        020
+#define WS_TAB_IN_INDENT       040
 #define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
 #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
 extern unsigned whitespace_rule_cfg;
diff --git a/ws.c b/ws.c
index f4afcddd4f3d41a920ee269c1750e5c5c6c0dfc7..0302ef5480da2e39e35b7257f50b69caa5f69e32 100644 (file)
--- a/ws.c
+++ b/ws.c
@@ -19,6 +19,7 @@ static struct whitespace_rule {
        { "cr-at-eol", WS_CR_AT_EOL, 1 },
        { "blank-at-eol", WS_BLANK_AT_EOL, 0 },
        { "blank-at-eof", WS_BLANK_AT_EOF, 0 },
+       { "tab-in-indent", WS_TAB_IN_INDENT, 0, 1 },
 };
 
 unsigned parse_whitespace_rule(const char *string)
@@ -57,6 +58,9 @@ unsigned parse_whitespace_rule(const char *string)
                }
                string = ep;
        }
+
+       if (rule & WS_TAB_IN_INDENT && rule & WS_INDENT_WITH_NON_TAB)
+               die("cannot enforce both tab-in-indent and indent-with-non-tab");
        return rule;
 }
 
@@ -127,6 +131,11 @@ char *whitespace_error_string(unsigned ws)
                        strbuf_addstr(&err, ", ");
                strbuf_addstr(&err, "indent with spaces");
        }
+       if (ws & WS_TAB_IN_INDENT) {
+               if (err.len)
+                       strbuf_addstr(&err, ", ");
+               strbuf_addstr(&err, "tab in indent");
+       }
        return strbuf_detach(&err, NULL);
 }
 
@@ -165,7 +174,7 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,
                }
        }
 
-       /* Check for space before tab in initial indent. */
+       /* Check indentation */
        for (i = 0; i < len; i++) {
                if (line[i] == ' ')
                        continue;
@@ -177,11 +186,19 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,
                                fputs(ws, stream);
                                fwrite(line + written, i - written, 1, stream);
                                fputs(reset, stream);
+                               fwrite(line + i, 1, 1, stream);
                        }
-               } else if (stream)
-                       fwrite(line + written, i - written, 1, stream);
-               if (stream)
-                       fwrite(line + i, 1, 1, stream);
+               } else if (ws_rule & WS_TAB_IN_INDENT) {
+                       result |= WS_TAB_IN_INDENT;
+                       if (stream) {
+                               fwrite(line + written, i - written, 1, stream);
+                               fputs(ws, stream);
+                               fwrite(line + i, 1, 1, stream);
+                               fputs(reset, stream);
+                       }
+               } else if (stream) {
+                       fwrite(line + written, i - written + 1, 1, stream);
+               }
                written = i + 1;
        }