{"thread":{"id":"5657","subject":"[PATCH 1/2] diff.c: second war on whitespace.","startedAt":"2006-09-23T07:47:39Z","lastAt":"2006-09-23T09:37:37Z","messageCount":3,"participants":["Junio C Hamano","Jakub Narebski"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"27450","messageId":"7vbqp7vxb8.fsf@assigned-by-dhcp.cox.net","threadId":"5657","inReplyTo":null,"subject":"[PATCH 1/2] diff.c: second war on whitespace.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-23T07:47:39Z","receivedAt":"2006-09-23T07:47:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This adds DIFF_WHITESPACE color class (default = reverse red) to\ncolored diff output to let you catch common whitespace errors.\n\n - trailing whitespaces at the end of line\n - a space followed by a tab in the indent\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n diff.c |  172 +++++++++++++++++++++++++++++++++++++++++++++++++---------------\n diff.h |    1 \n 2 files changed, 132 insertions(+), 41 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 443e248..2464238 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -20,12 +20,13 @@ static int diff_use_color_default;\n \n static char diff_colors[][COLOR_MAXLEN] = {\n \t\"\\033[m\",\t/* reset */\n-\t\"\",\t\t/* normal */\n-\t\"\\033[1m\",\t/* bold */\n-\t\"\\033[36m\",\t/* cyan */\n-\t\"\\033[31m\",\t/* red */\n-\t\"\\033[32m\",\t/* green */\n-\t\"\\033[33m\"\t/* yellow */\n+\t\"\",\t\t/* PLAIN (normal) */\n+\t\"\\033[1m\",\t/* METAINFO (bold) */\n+\t\"\\033[36m\",\t/* FRAGINFO (cyan) */\n+\t\"\\033[31m\",\t/* OLD (red) */\n+\t\"\\033[32m\",\t/* NEW (green) */\n+\t\"\\033[33m\",\t/* COMMIT (yellow) */\n+\t\"\\033[41m\",\t/* WHITESPACE (red background) */\n };\n \n static int parse_diff_color_slot(const char *var, int ofs)\n@@ -42,6 +43,8 @@ static int parse_diff_color_slot(const c\n \t\treturn DIFF_FILE_NEW;\n \tif (!strcasecmp(var+ofs, \"commit\"))\n \t\treturn DIFF_COMMIT;\n+\tif (!strcasecmp(var+ofs, \"whitespace\"))\n+\t\treturn DIFF_WHITESPACE;\n \tdie(\"bad config variable '%s'\", var);\n }\n \n@@ -383,9 +386,89 @@ const char *diff_get_color(int diff_use_\n \treturn \"\";\n }\n \n+static void emit_line(const char *set, const char *reset, const char *line, int len)\n+{\n+\tif (len > 0 && line[len-1] == '\\n')\n+\t\tlen--;\n+\tfputs(set, stdout);\n+\tfwrite(line, len, 1, stdout);\n+\tputs(reset);\n+}\n+\n+static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)\n+{\n+\tint col0 = ecbdata->nparents;\n+\tint last_tab_in_indent = -1;\n+\tint last_space_in_indent = -1;\n+\tint i;\n+\tint tail = len;\n+\tint need_highlight_leading_space = 0;\n+\tconst char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);\n+\tconst char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);\n+\n+\tif (!*ws) {\n+\t\temit_line(set, reset, line, len);\n+\t\treturn;\n+\t}\n+\n+\t/* The line is a newly added line.  Does it have funny leading\n+\t * whitespaces?  In indent, SP should never precede a TAB.\n+\t */\n+\tfor (i = col0; i < len; i++) {\n+\t\tif (line[i] == '\\t') {\n+\t\t\tlast_tab_in_indent = i;\n+\t\t\tif (0 <= last_space_in_indent)\n+\t\t\t\tneed_highlight_leading_space = 1;\n+\t\t}\n+\t\telse if (line[i] == ' ')\n+\t\t\tlast_space_in_indent = i;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\tfputs(set, stdout);\n+\tfwrite(line, col0, 1, stdout);\n+\tfputs(reset, stdout);\n+\tif (((i == len) || line[i] == '\\n') && i != col0) {\n+\t\t/* The whole line was indent */\n+\t\temit_line(ws, reset, line + col0, len - col0);\n+\t\treturn;\n+\t}\n+\ti = col0;\n+\tif (need_highlight_leading_space) {\n+\t\twhile (i < last_tab_in_indent) {\n+\t\t\tif (line[i] == ' ') {\n+\t\t\t\tfputs(ws, stdout);\n+\t\t\t\tputchar(' ');\n+\t\t\t\tfputs(reset, stdout);\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\tputchar(line[i]);\n+\t\t\ti++;\n+\t\t}\n+\t}\n+\ttail = len - 1;\n+\tif (line[tail] == '\\n' && i < tail)\n+\t\ttail--;\n+\twhile (i < tail) {\n+\t\tif (!isspace(line[tail]))\n+\t\t\tbreak;\n+\t\ttail--;\n+\t}\n+\tif ((i < tail && line[tail + 1] != '\\n')) {\n+\t\t/* This has whitespace between tail+1..len */\n+\t\tfputs(set, stdout);\n+\t\tfwrite(line + i, tail - i + 1, 1, stdout);\n+\t\tfputs(reset, stdout);\n+\t\temit_line(ws, reset, line + tail + 1, len - tail - 1);\n+\t}\n+\telse\n+\t\temit_line(set, reset, line + i, len - i);\n+}\n+\n static void fn_out_consume(void *priv, char *line, unsigned long len)\n {\n \tint i;\n+\tint color;\n \tstruct emit_callback *ecbdata = priv;\n \tconst char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);\n \tconst char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);\n@@ -403,45 +486,52 @@ static void fn_out_consume(void *priv, c\n \t\t;\n \tif (2 <= i && i < len && line[i] == ' ') {\n \t\tecbdata->nparents = i - 1;\n-\t\tset = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);\n+\t\temit_line(diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),\n+\t\t\t  reset, line, len);\n+\t\treturn;\n \t}\n-\telse if (len < ecbdata->nparents)\n+\n+\tif (len < ecbdata->nparents) {\n \t\tset = reset;\n-\telse {\n-\t\tint nparents = ecbdata->nparents;\n-\t\tint color = DIFF_PLAIN;\n-\t\tif (ecbdata->diff_words && nparents != 1)\n-\t\t\t/* fall back to normal diff */\n-\t\t\tfree_diff_words_data(ecbdata);\n-\t\tif (ecbdata->diff_words) {\n-\t\t\tif (line[0] == '-') {\n-\t\t\t\tdiff_words_append(line, len,\n-\t\t\t\t\t\t&ecbdata->diff_words->minus);\n-\t\t\t\treturn;\n-\t\t\t} else if (line[0] == '+') {\n-\t\t\t\tdiff_words_append(line, len,\n-\t\t\t\t\t\t&ecbdata->diff_words->plus);\n-\t\t\t\treturn;\n-\t\t\t}\n-\t\t\tif (ecbdata->diff_words->minus.text.size ||\n-\t\t\t\t\tecbdata->diff_words->plus.text.size)\n-\t\t\t\tdiff_words_show(ecbdata->diff_words);\n-\t\t\tline++;\n-\t\t\tlen--;\n-\t\t} else\n-\t\t\tfor (i = 0; i < nparents && len; i++) {\n-\t\t\t\tif (line[i] == '-')\n-\t\t\t\t\tcolor = DIFF_FILE_OLD;\n-\t\t\t\telse if (line[i] == '+')\n-\t\t\t\t\tcolor = DIFF_FILE_NEW;\n-\t\t\t}\n-\t\tset = diff_get_color(ecbdata->color_diff, color);\n+\t\temit_line(reset, reset, line, len);\n+\t\treturn;\n \t}\n-\tif (len > 0 && line[len-1] == '\\n')\n+\n+\tcolor = DIFF_PLAIN;\n+\tif (ecbdata->diff_words && ecbdata->nparents != 1)\n+\t\t/* fall back to normal diff */\n+\t\tfree_diff_words_data(ecbdata);\n+\tif (ecbdata->diff_words) {\n+\t\tif (line[0] == '-') {\n+\t\t\tdiff_words_append(line, len,\n+\t\t\t\t\t  &ecbdata->diff_words->minus);\n+\t\t\treturn;\n+\t\t} else if (line[0] == '+') {\n+\t\t\tdiff_words_append(line, len,\n+\t\t\t\t\t  &ecbdata->diff_words->plus);\n+\t\t\treturn;\n+\t\t}\n+\t\tif (ecbdata->diff_words->minus.text.size ||\n+\t\t    ecbdata->diff_words->plus.text.size)\n+\t\t\tdiff_words_show(ecbdata->diff_words);\n+\t\tline++;\n \t\tlen--;\n-\tfputs (set, stdout);\n-\tfwrite (line, len, 1, stdout);\n-\tputs (reset);\n+\t\temit_line(set, reset, line, len);\n+\t\treturn;\n+\t}\n+\tfor (i = 0; i < ecbdata->nparents && len; i++) {\n+\t\tif (line[i] == '-')\n+\t\t\tcolor = DIFF_FILE_OLD;\n+\t\telse if (line[i] == '+')\n+\t\t\tcolor = DIFF_FILE_NEW;\n+\t}\n+\n+\tif (color != DIFF_FILE_NEW) {\n+\t\temit_line(diff_get_color(ecbdata->color_diff, color),\n+\t\t\t  reset, line, len);\n+\t\treturn;\n+\t}\n+\temit_add_line(reset, ecbdata, line, len);\n }\n \n static char *pprint_rename(const char *a, const char *b)\ndiff --git a/diff.h b/diff.h\nindex b60a02e..3435fe7 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -86,6 +86,7 @@ enum color_diff {\n \tDIFF_FILE_OLD = 4,\n \tDIFF_FILE_NEW = 5,\n \tDIFF_COMMIT = 6,\n+\tDIFF_WHITESPACE = 7,\n };\n const char *diff_get_color(int diff_use_color, enum color_diff ix);\n \n-- \n1.4.2.1.gf2bba\n"},{"id":"27458","messageId":"ef2u05$f29$1@sea.gmane.org","threadId":"5657","inReplyTo":"7vbqp7vxb8.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/2] diff.c: second war on whitespace.","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-09-23T09:15:53Z","receivedAt":"2006-09-23T09:15:53Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n> gmane.comp.version-control.git\n> This adds DIFF_WHITESPACE color class (default = reverse red) to\n> colored diff output to let you catch common whitespace errors.\n> \n>  - trailing whitespaces at the end of line\n>  - a space followed by a tab in the indent\n\nIn gitweb/gitweb.perl, around %feature hash definition, we have:\n\n        <TAB> # <SP> <TAB> 'sub' ...\n\nand I think that is exception to the \"no space followed by tab\" rule.\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"27459","messageId":"7vzmcqudni.fsf@assigned-by-dhcp.cox.net","threadId":"5657","inReplyTo":"ef2u05$f29$1@sea.gmane.org","subject":"Re: [PATCH 1/2] diff.c: second war on whitespace.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-23T09:37:37Z","receivedAt":"2006-09-23T09:37:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>\n>> gmane.comp.version-control.git\n>> This adds DIFF_WHITESPACE color class (default = reverse red) to\n>> colored diff output to let you catch common whitespace errors.\n>> \n>>  - trailing whitespaces at the end of line\n>>  - a space followed by a tab in the indent\n>\n> In gitweb/gitweb.perl, around %feature hash definition, we have:\n>\n>         <TAB> # <SP> <TAB> 'sub' ...\n>\n> and I think that is exception to the \"no space followed by tab\" rule.\n\nRead the description again.  No space IN INDENT that is followed\nby tab.\n"}]}