{"thread":{"id":"5505","subject":"[PATCH 3/3] git-commit.sh: convert run_status to a C builtin","startedAt":"2006-09-07T06:36:21Z","lastAt":"2006-09-08T21:19:18Z","messageCount":10,"participants":["Jeff King","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"26486","messageId":"20060907063621.GC17083@coredump.intra.peff.net","threadId":"5505","inReplyTo":"64c62cc942e872b29d7225999e74a07be586674a.1157610743.git.peff@peff.net","subject":"[PATCH 3/3] git-commit.sh: convert run_status to a C builtin","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-09-07T06:36:21Z","receivedAt":"2006-09-07T06:36:21Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This creates a new git-runstatus which should do roughly the same thing\nas the run_status function from git-commit.sh. Except for color support,\nthe main focus has been to keep the output identical, so that it can be\nverified as correct and then used as a C platform for other improvements to\nthe status printing code.\n---\n .gitignore          |    1 \n Makefile            |    3 -\n builtin-runstatus.c |   34 ++++++\n builtin.h           |    1 \n dir.c               |    7 +\n dir.h               |    1 \n git-commit.sh       |  106 +------------------\n git.c               |    1 \n status.c            |  283 +++++++++++++++++++++++++++++++++++++++++++++++++++\n status.h            |   31 ++++++\n 10 files changed, 368 insertions(+), 100 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex 78cb671..f014ad3 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -94,6 +94,7 @@ git-rev-list\n git-rev-parse\n git-revert\n git-rm\n+git-runstatus\n git-send-email\n git-send-pack\n git-sh-setup\ndiff --git a/Makefile b/Makefile\nindex 78748cb..d0ba3b5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -252,7 +252,7 @@ LIB_OBJS = \\\n \tfetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \\\n \twrite_or_die.o trace.o \\\n \talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \\\n-\tcolor.o\n+\tcolor.o status.o\n \n BUILTIN_OBJS = \\\n \tbuiltin-add.o \\\n@@ -286,6 +286,7 @@ BUILTIN_OBJS = \\\n \tbuiltin-rev-list.o \\\n \tbuiltin-rev-parse.o \\\n \tbuiltin-rm.o \\\n+\tbuiltin-runstatus.o \\\n \tbuiltin-show-branch.o \\\n \tbuiltin-stripspace.o \\\n \tbuiltin-symbolic-ref.o \\\ndiff --git a/builtin-runstatus.c b/builtin-runstatus.c\nnew file mode 100644\nindex 0000000..f3e44de\n--- /dev/null\n+++ b/builtin-runstatus.c\n@@ -0,0 +1,34 @@\n+#include \"status.h\"\n+#include \"cache.h\"\n+\n+extern int status_use_color;\n+\n+static const char runstatus_usage[] =\n+\"git-runstatus [--color|--nocolor] [--amend] [--verbose]\";\n+\n+int cmd_runstatus(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct status s;\n+\tint i;\n+\n+\tgit_config(git_status_config);\n+\tstatus_prepare(&s);\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tif (!strcmp(argv[i], \"--color\"))\n+\t\t\tstatus_use_color = 1;\n+\t\telse if (!strcmp(argv[i], \"--nocolor\"))\n+\t\t\tstatus_use_color = 0;\n+    else if (!strcmp(argv[i], \"--amend\")) {\n+      s.amend = 1;\n+      s.reference = \"HEAD^1\";\n+    }\n+    else if (!strcmp(argv[i], \"--verbose\"))\n+      s.verbose = 1;\n+\t\telse\n+\t\t\tusage(runstatus_usage);\n+\t}\n+\n+\tstatus_print(&s);\n+  return s.commitable ? 0 : 1;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 25431d7..53a896c 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -47,6 +47,7 @@ extern int cmd_repo_config(int argc, con\n extern int cmd_rev_list(int argc, const char **argv, const char *prefix);\n extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);\n extern int cmd_rm(int argc, const char **argv, const char *prefix);\n+extern int cmd_runstatus(int argc, const char **argv, const char *prefix);\n extern int cmd_show_branch(int argc, const char **argv, const char *prefix);\n extern int cmd_show(int argc, const char **argv, const char *prefix);\n extern int cmd_stripspace(int argc, const char **argv, const char *prefix);\ndiff --git a/dir.c b/dir.c\nindex 5a40d8f..e2f472b 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -397,3 +397,10 @@ int read_directory(struct dir_struct *di\n \tqsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);\n \treturn dir->nr;\n }\n+\n+int\n+file_exists(const char *f)\n+{\n+  struct stat sb;\n+  return stat(f, &sb) == 0;\n+}\ndiff --git a/dir.h b/dir.h\nindex 56a1b7f..313f8ab 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -47,5 +47,6 @@ extern int excluded(struct dir_struct *,\n extern void add_excludes_from_file(struct dir_struct *, const char *fname);\n extern void add_exclude(const char *string, const char *base,\n \t\t\tint baselen, struct exclude_list *which);\n+extern int file_exists(const char *);\n \n #endif\ndiff --git a/git-commit.sh b/git-commit.sh\nindex 4cf3fab..10c269a 100755\n--- a/git-commit.sh\n+++ b/git-commit.sh\n@@ -60,26 +60,6 @@ #\n }\n \n run_status () {\n-    (\n-\t# We always show status for the whole tree.\n-\tcd \"$TOP\"\n-\n-\tIS_INITIAL=\"$initial_commit\"\n-\tREFERENCE=HEAD\n-\tcase \"$amend\" in\n-\tt)\n-\t\t# If we are amending the initial commit, there\n-\t\t# is no HEAD^1.\n-\t\tif git-rev-parse --verify \"HEAD^1\" >/dev/null 2>&1\n-\t\tthen\n-\t\t\tREFERENCE=\"HEAD^1\"\n-\t\t\tIS_INITIAL=\n-\t\telse\n-\t\t\tIS_INITIAL=t\n-\t\tfi\n-\t\t;;\n-\tesac\n-\n \t# If TMP_INDEX is defined, that means we are doing\n \t# \"--only\" partial commit, and that index file is used\n \t# to build the tree for the commit.  Otherwise, if\n@@ -96,85 +76,13 @@ run_status () {\n \t    export GIT_INDEX_FILE\n \tfi\n \n-\tcase \"$branch\" in\n-\trefs/heads/master) ;;\n-\t*)  echo \"# On branch $branch\" ;;\n-\tesac\n-\n-\tif test -z \"$IS_INITIAL\"\n-\tthen\n-\t    git-diff-index -M --cached --name-status \\\n-\t\t--diff-filter=MDTCRA $REFERENCE |\n-\t    sed -e '\n-\t\t    s/\\\\/\\\\\\\\/g\n-\t\t    s/ /\\\\ /g\n-\t    ' |\n-\t    report \"Updated but not checked in\" \"will commit\"\n-\t    committable=\"$?\"\n-\telse\n-\t    echo '#\n-# Initial commit\n-#'\n-\t    git-ls-files |\n-\t    sed -e '\n-\t\t    s/\\\\/\\\\\\\\/g\n-\t\t    s/ /\\\\ /g\n-\t\t    s/^/A /\n-\t    ' |\n-\t    report \"Updated but not checked in\" \"will commit\"\n-\n-\t    committable=\"$?\"\n-\tfi\n-\n-\tgit-diff-files  --name-status |\n-\tsed -e '\n-\t\ts/\\\\/\\\\\\\\/g\n-\t\ts/ /\\\\ /g\n-\t' |\n-\treport \"Changed but not updated\" \\\n-\t    \"use git-update-index to mark for commit\"\n-\n-        option=\"\"\n-        if test -z \"$untracked_files\"; then\n-            option=\"--directory --no-empty-directory\"\n-        fi\n-\thdr_shown=\n-\tif test -f \"$GIT_DIR/info/exclude\"\n-\tthen\n-\t    git-ls-files --others $option \\\n-\t\t--exclude-from=\"$GIT_DIR/info/exclude\" \\\n-\t\t--exclude-per-directory=.gitignore\n-\telse\n-\t    git-ls-files --others $option \\\n-\t\t--exclude-per-directory=.gitignore\n-\tfi |\n-\twhile read line; do\n-\t    if [ -z \"$hdr_shown\" ]; then\n-\t\techo '#'\n-\t\techo '# Untracked files:'\n-\t\techo '#   (use \"git add\" to add to commit)'\n-\t\techo '#'\n-\t\thdr_shown=1\n-\t    fi\n-\t    echo \"#\t$line\"\n-\tdone\n-\n-\tif test -n \"$verbose\" -a -z \"$IS_INITIAL\"\n-\tthen\n-\t    git-diff-index --cached -M -p --diff-filter=MDTCRA $REFERENCE\n-\tfi\n-\tcase \"$committable\" in\n-\t0)\n-\t\tcase \"$amend\" in\n-\t\tt)\n-\t\t\techo \"# No changes\" ;;\n-\t\t*)\n-\t\t\techo \"nothing to commit\" ;;\n-\t\tesac\n-\t\texit 1 ;;\n-\tesac\n-\texit 0\n-    )\n+  case \"$status_only\" in\n+    t) color= ;;\n+    *) color=--nocolor ;;\n+  esac\n+  git-runstatus ${color} \\\n+                ${verbose:+--verbose} \\\n+                ${amend:+--amend}\n }\n \n trap '\ndiff --git a/git.c b/git.c\nindex 335f405..495b39a 100644\n--- a/git.c\n+++ b/git.c\n@@ -252,6 +252,7 @@ static void handle_internal_command(int \n \t\t{ \"rev-list\", cmd_rev_list, RUN_SETUP },\n \t\t{ \"rev-parse\", cmd_rev_parse, RUN_SETUP },\n \t\t{ \"rm\", cmd_rm, RUN_SETUP },\n+\t\t{ \"runstatus\", cmd_runstatus, RUN_SETUP },\n \t\t{ \"show-branch\", cmd_show_branch, RUN_SETUP },\n \t\t{ \"show\", cmd_show, RUN_SETUP | USE_PAGER },\n \t\t{ \"stripspace\", cmd_stripspace },\ndiff --git a/status.c b/status.c\nnew file mode 100644\nindex 0000000..82aa881\n--- /dev/null\n+++ b/status.c\n@@ -0,0 +1,283 @@\n+#include \"status.h\"\n+#include \"color.h\"\n+#include \"cache.h\"\n+#include \"object.h\"\n+#include \"dir.h\"\n+#include \"commit.h\"\n+#include \"diff.h\"\n+#include \"revision.h\"\n+#include \"diffcore.h\"\n+\n+int status_use_color = 0;\n+static char status_colors[][COLOR_MAXLEN] = {\n+\t\"\",         /* STATUS_HEADER: normal */\n+\t\"\\033[32m\", /* STATUS_UPDATED: green */\n+\t\"\\033[31m\", /* STATUS_CHANGED: red */\n+\t\"\\033[31m\", /* STATUS_UNTRACKED: red */\n+};\n+\n+static int\n+parse_status_slot(const char *var, int offset) {\n+\tif (!strcasecmp(var+offset, \"header\"))\n+\t\treturn STATUS_HEADER;\n+\tif (!strcasecmp(var+offset, \"updated\"))\n+\t\treturn STATUS_UPDATED;\n+\tif (!strcasecmp(var+offset, \"changed\"))\n+\t\treturn STATUS_CHANGED;\n+\tif (!strcasecmp(var+offset, \"untracked\"))\n+\t\treturn STATUS_UNTRACKED;\n+\tdie(\"bad config variable '%s'\", var);\n+}\n+\n+static const char*\n+color(int slot)\n+{\n+\treturn status_use_color ? status_colors[slot] : \"\";\n+}\n+\n+void\n+status_prepare(struct status *s)\n+{\n+\tunsigned char sha1[20];\n+\tconst char *head;\n+\n+\ts->is_initial = get_sha1(\"HEAD\", sha1) ? 1 : 0;\n+\n+\thead = resolve_ref(git_path(\"HEAD\"), sha1, 0);\n+\ts->branch = head ?\n+\t\t    strdup(head + strlen(get_git_dir()) + 1) :\n+\t\t    NULL;\n+\n+\ts->reference = \"HEAD\";\n+\ts->amend = 0;\n+\ts->verbose = 0;\n+\ts->commitable = 0;\n+}\n+\n+static void\n+status_print_header(const char *main, const char *sub)\n+{\n+\tconst char *c = color(STATUS_HEADER);\n+\tcolor_printf(c, \"# %s:\\n\", main);\n+\tcolor_printf(c, \"#   (%s)\\n\", sub);\n+\tcolor_printf(c, \"#\\n\");\n+}\n+\n+static void\n+status_print_trailer(void)\n+{\n+\tcolor_printf(color(STATUS_HEADER), \"#\\n\");\n+}\n+\n+static void\n+status_print_filepair(int t, struct diff_filepair *p)\n+{\n+\tconst char *c = color(t);\n+\tcolor_printf(color(STATUS_HEADER), \"#\\t\");\n+\tswitch (p->status) {\n+\tcase DIFF_STATUS_ADDED:\n+\t\tcolor_printf(c, \"new file: %s\\n\", p->one->path); break;\n+\tcase DIFF_STATUS_COPIED:\n+\t\tcolor_printf(c, \"copied: %s -> %s\\n\",\n+\t\t\t\tp->one->path, p->two->path);\n+\t\tbreak;\n+\tcase DIFF_STATUS_DELETED:\n+\t\tcolor_printf(c, \"deleted: %s\\n\", p->one->path); break;\n+\tcase DIFF_STATUS_MODIFIED:\n+\t\tcolor_printf(c, \"modified: %s\\n\", p->one->path); break;\n+\tcase DIFF_STATUS_RENAMED:\n+\t\tcolor_printf(c, \"renamed: %s -> %s\\n\",\n+\t\t\t\tp->one->path, p->two->path);\n+\t\tbreak;\n+\tcase DIFF_STATUS_TYPE_CHANGED:\n+\t\tcolor_printf(c, \"typechange: %s\\n\", p->one->path); break;\n+\tcase DIFF_STATUS_UNKNOWN:\n+\t\tcolor_printf(c, \"unknown: %s\\n\", p->one->path); break;\n+\tcase DIFF_STATUS_UNMERGED:\n+\t\tcolor_printf(c, \"unmerged: %s\\n\", p->one->path); break;\n+\tdefault:\n+\t\tdie(\"bug: unhandled diff status %c\", p->status);\n+\t}\n+}\n+\n+static void\n+status_print_updated_cb(struct diff_queue_struct *q,\n+                        struct diff_options *options,\n+                        void *data)\n+{\n+\tstruct status *s = data;\n+\tint shown_header = 0;\n+\tint i;\n+\tif (q->nr) {\n+\t}\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tif (q->queue[i]->status == 'U')\n+\t\t\tcontinue;\n+\t\tif (!shown_header) {\n+\t\t\tstatus_print_header(\"Updated but not checked in\",\n+\t\t\t\t\t\"will commit\");\n+\t\t\ts->commitable = 1;\n+\t\t}\n+\t\tstatus_print_filepair(STATUS_UPDATED, q->queue[i]);\n+\t}\n+\tif (shown_header)\n+\t\tstatus_print_trailer();\n+}\n+\n+static void\n+status_print_changed_cb(struct diff_queue_struct *q,\n+                        struct diff_options *options,\n+                        void *data)\n+{\n+\tint i;\n+\tif (q->nr)\n+\t\tstatus_print_header(\"Changed but not updated\",\n+\t\t\t\t\"use git-update-index to mark for commit\");\n+\tfor (i = 0; i < q->nr; i++)\n+\t\tstatus_print_filepair(STATUS_CHANGED, q->queue[i]);\n+\tif (q->nr)\n+\t\tstatus_print_trailer();\n+}\n+\n+void\n+status_print_initial(struct status *s)\n+{\n+\tint i;\n+\tread_cache();\n+\tif (active_nr) {\n+\t\ts->commitable = 1;\n+\t\tstatus_print_header(\"Updated but not checked in\",\n+\t\t\t\t\"will commit\");\n+\t}\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tcolor_printf(color(STATUS_HEADER), \"#\\t\");\n+\t\tcolor_printf(color(STATUS_UPDATED), \"new file: %s\\n\",\n+\t\t\t\tactive_cache[i]->name);\n+\t}\n+\tif (active_nr)\n+\t\tstatus_print_trailer();\n+}\n+\n+static void\n+status_print_updated(struct status *s)\n+{\n+\tstruct rev_info rev;\n+\tconst char *argv[] = { NULL, NULL, NULL };\n+\targv[1] = s->reference;\n+\tinit_revisions(&rev, NULL);\n+\tsetup_revisions(2, argv, &rev, NULL);\n+\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = status_print_updated_cb;\n+\trev.diffopt.format_callback_data = s;\n+\trev.diffopt.detect_rename = 1;\n+\trun_diff_index(&rev, 1);\n+}\n+\n+static void\n+status_print_changed(struct status *s)\n+{\n+\tstruct rev_info rev;\n+\tconst char *argv[] = { NULL, NULL };\n+\tinit_revisions(&rev, \"\");\n+\tsetup_revisions(1, argv, &rev, NULL);\n+\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = status_print_changed_cb;\n+\trev.diffopt.format_callback_data = s;\n+\trun_diff_files(&rev, 0);\n+}\n+\n+static void\n+status_print_untracked(const struct status *s)\n+{\n+\tstruct dir_struct dir;\n+\tconst char *x;\n+\tint i;\n+\tint shown_header = 0;\n+\n+\tmemset(&dir, 0, sizeof(dir));\n+\n+\tdir.exclude_per_dir = \".gitignore\";\n+\tx = git_path(\"info/exclude\");\n+\tif (file_exists(x))\n+\t\tadd_excludes_from_file(&dir, x);\n+\n+\tread_directory(&dir, \".\", \"\", 0);\n+\tfor(i = 0; i < dir.nr; i++) {\n+\t\t/* check for matching entry, which is unmerged; lifted from\n+\t\t * builtin-ls-files:show_other_files */\n+\t\tstruct dir_entry *ent = dir.entries[i];\n+\t\tint pos = cache_name_pos(ent->name, ent->len);\n+\t\tstruct cache_entry *ce;\n+\t\tif (0 <= pos)\n+\t\t\tdie(\"bug in status_print_untracked\");\n+\t\tpos = -pos - 1;\n+\t\tif (pos < active_nr) {\n+\t\t\tce = active_cache[pos];\n+\t\t\tif (ce_namelen(ce) == ent->len &&\n+\t\t\t    !memcmp(ce->name, ent->name, ent->len))\n+\t\t\t\tcontinue;\n+\t\t}\n+\t\tif (!shown_header) {\n+\t\t\tstatus_print_header(\"Untracked files\",\n+\t\t\t\t\"use \\\"git add\\\" to add to commit\");\n+\t\t\tshown_header = 1;\n+\t\t}\n+\t\tcolor_printf(color(STATUS_HEADER), \"#\\t\");\n+\t\tcolor_printf(color(STATUS_UNTRACKED), \"%.*s\\n\",\n+\t\t\t\tent->len, ent->name);\n+\t}\n+}\n+\n+static void\n+status_print_verbose(struct status *s)\n+{\n+\tstruct rev_info rev;\n+\tconst char *argv[] = { NULL, NULL, NULL };\n+\targv[1] = s->reference;\n+\tinit_revisions(&rev, NULL);\n+\tsetup_revisions(2, argv, &rev, NULL);\n+\trev.diffopt.output_format |= DIFF_FORMAT_PATCH;\n+\trev.diffopt.detect_rename = 1;\n+\trun_diff_index(&rev, 1);\n+}\n+\n+void\n+status_print(struct status *s)\n+{\n+\tif (s->branch && strcmp(s->branch, \"refs/heads/master\"))\n+\t\tcolor_printf(color(STATUS_HEADER),\n+\t\t\t\"# On branch %s\\n\", s->branch);\n+\n+\tif (s->is_initial) {\n+\t\tcolor_printf(color(STATUS_HEADER), \"#\\n\");\n+\t\tcolor_printf(color(STATUS_HEADER), \"# Initial commit\\n\");\n+\t\tcolor_printf(color(STATUS_HEADER), \"#\\n\");\n+\t\tstatus_print_initial(s);\n+\t}\n+\telse {\n+\t\tstatus_print_updated(s);\n+\t\tdiscard_cache();\n+\t}\n+\n+\tstatus_print_changed(s);\n+\tstatus_print_untracked(s);\n+\n+\tif (s->verbose && !s->is_initial)\n+\t\tstatus_print_verbose(s);\n+\tif (!s->commitable)\n+\t\tprintf(\"%s\\n\", s->amend ? \"# No changes\" : \"nothing to commit\");\n+}\n+\n+int\n+git_status_config(const char *k, const char *v)\n+{\n+\tif (!strcmp(k, \"status.color\")) {\n+\t\tstatus_use_color = git_config_colorbool(k, v);\n+\t\treturn 0;\n+\t}\n+\tif (!strncmp(k, \"status.color.\", 13)) {\n+\t\tint slot = parse_status_slot(k, 13);\n+\t\tcolor_parse(v, k, status_colors[slot]);\n+\t}\n+\treturn git_default_config(k, v);\n+}\ndiff --git a/status.h b/status.h\nnew file mode 100644\nindex 0000000..3e60146\n--- /dev/null\n+++ b/status.h\n@@ -0,0 +1,31 @@\n+#ifndef STATUS_H\n+#define STATUS_H\n+\n+enum color_status {\n+\tSTATUS_HEADER,\n+\tSTATUS_UPDATED,\n+\tSTATUS_CHANGED,\n+\tSTATUS_UNTRACKED,\n+};\n+\n+struct status {\n+\tint is_initial;\n+\tchar *branch;\n+\tconst char *reference;\n+\tint commitable;\n+\tint verbose;\n+\tint amend;\n+};\n+\n+int git_status_config(const char *var, const char *value);\n+void status_prepare(struct status *s);\n+void status_print(struct status *s);\n+\n+struct cache_entry;\n+typedef void (*status_cb)(struct cache_entry *);\n+int status_foreach_cached(status_cb cb);\n+int status_foreach_updated(status_cb cb);\n+int status_foreach_changed(status_cb cb);\n+int status_foreach_untracked(status_cb cb);\n+\n+#endif /* STATUS_H */\n-- \n1.4.2.ge490e-dirty\n"},{"id":"26508","messageId":"20060907091028.GA22687@coredump.intra.peff.net","threadId":"5505","inReplyTo":"20060907063621.GC17083@coredump.intra.peff.net","subject":"Re: [PATCH 3/3] git-commit.sh: convert run_status to a C builtin","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-09-07T09:10:29Z","receivedAt":"2006-09-07T09:10:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 07, 2006 at 02:36:21AM -0400, Jeff King wrote:\n\n> +static void\n> +status_print_updated_cb(struct diff_queue_struct *q,\n> +                        struct diff_options *options,\n> +                        void *data)\n> [...]\n> +\t\tif (!shown_header) {\n> +\t\t\tstatus_print_header(\"Updated but not checked in\",\n> +\t\t\t\t\t\"will commit\");\n> +\t\t\ts->commitable = 1;\n> +\t\t}\n\nSorry, this should set shown_header=1. That's what I get for making a\nlast minute change and not testing...\n\n-Peff\n"},{"id":"26551","messageId":"7vzmdbqke3.fsf@assigned-by-dhcp.cox.net","threadId":"5505","inReplyTo":"20060907063621.GC17083@coredump.intra.peff.net","subject":"Re: [PATCH 3/3] git-commit.sh: convert run_status to a C builtin","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-08T00:20:20Z","receivedAt":"2006-09-08T00:20:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> diff --git a/Makefile b/Makefile\n> index 78748cb..d0ba3b5 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -252,7 +252,7 @@ LIB_OBJS = \\\n>  \tfetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \\\n>  \twrite_or_die.o trace.o \\\n>  \talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \\\n> -\tcolor.o\n> +\tcolor.o status.o\n>  \n>  BUILTIN_OBJS = \\\n>  \tbuiltin-add.o \\\n\nAt some point (this does not have to be part of this series), we\nshould demote DIFF_OBJS to just ordinary LIB_OBJS.  They used to\nbe special in that they are used only by handful special\ncommands, but these days more and more things are integrated and\nit outlived its usefulness.\n\n> +static const char runstatus_usage[] =\n> +\"git-runstatus [--color|--nocolor] [--amend] [--verbose]\";\n> +\n> +int cmd_runstatus(int argc, const char **argv, const char *prefix)\n> +{\n> +\tstruct status s;\n> +\tint i;\n> +\n> +\tgit_config(git_status_config);\n> +\tstatus_prepare(&s);\n> +\n> +\tfor (i = 1; i < argc; i++) {\n> +\t\tif (!strcmp(argv[i], \"--color\"))\n> +\t\t\tstatus_use_color = 1;\n> +\t\telse if (!strcmp(argv[i], \"--nocolor\"))\n> +\t\t\tstatus_use_color = 0;\n> +    else if (!strcmp(argv[i], \"--amend\")) {\n> +      s.amend = 1;\n> +      s.reference = \"HEAD^1\";\n> +    }\n> +    else if (!strcmp(argv[i], \"--verbose\"))\n> +      s.verbose = 1;\n> +\t\telse\n> +\t\t\tusage(runstatus_usage);\n> +\t}\n> +\n> +\tstatus_print(&s);\n> +  return s.commitable ? 0 : 1;\n> +}\n\nQuite funny indentation style your MUA likes ;-).\n\n> diff --git a/status.c b/status.c\n> new file mode 100644\n> index 0000000..82aa881\n> --- /dev/null\n> +++ b/status.c\n> @@ -0,0 +1,283 @@\n> +#include \"status.h\"\n\n\"status.h\" and \"struct status\" somehow sounds too broad.\nGranted, \"object.h\" is also broad, but in git context \"object\"\nhas a specific meaning.\n\nHaving said that I cannot come up with a good alternative name.\nIt is not \"project status\" nor \"repository status\".  It is\n\"working tree status\", but that sounds very loooooooooooooooong.\n\n> +\tcolor_printf(color(STATUS_HEADER), \"#\\t\");\n> +\tswitch (p->status) {\n> +\tcase DIFF_STATUS_ADDED:\n> +\t\tcolor_printf(c, \"new file: %s\\n\", p->one->path); break;\n\nVery nicely done.  Especially I liked that you are careful not\nto paint leading '#\\t' (which is noticeable when you use reverse\nas an attribute).\n\n> +static void\n> +status_print_untracked(const struct status *s)\n> +{\n> +\tstruct dir_struct dir;\n> +\tconst char *x;\n> +\tint i;\n> +\tint shown_header = 0;\n> +\n> +\tmemset(&dir, 0, sizeof(dir));\n> +\n> +\tdir.exclude_per_dir = \".gitignore\";\n> +\tx = git_path(\"info/exclude\");\n> +\tif (file_exists(x))\n> +\t\tadd_excludes_from_file(&dir, x);\n> +\n> +\tread_directory(&dir, \".\", \"\", 0);\n> +\tfor(i = 0; i < dir.nr; i++) {\n> +\t\t/* check for matching entry, which is unmerged; lifted from\n> +\t\t * builtin-ls-files:show_other_files */\n> +\t\tstruct dir_entry *ent = dir.entries[i];\n> +\t\tint pos = cache_name_pos(ent->name, ent->len);\n> +\t\tstruct cache_entry *ce;\n> +\t\tif (0 <= pos)\n> +\t\t\tdie(\"bug in status_print_untracked\");\n> +\t\tpos = -pos - 1;\n> +\t\tif (pos < active_nr) {\n> +\t\t\tce = active_cache[pos];\n> +\t\t\tif (ce_namelen(ce) == ent->len &&\n> +\t\t\t    !memcmp(ce->name, ent->name, ent->len))\n> +\t\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!shown_header) {\n> +\t\t\tstatus_print_header(\"Untracked files\",\n> +\t\t\t\t\"use \\\"git add\\\" to add to commit\");\n> +\t\t\tshown_header = 1;\n> +\t\t}\n> +\t\tcolor_printf(color(STATUS_HEADER), \"#\\t\");\n> +\t\tcolor_printf(color(STATUS_UNTRACKED), \"%.*s\\n\",\n> +\t\t\t\tent->len, ent->name);\n> +\t}\n> +}\n\nVery nice code reuse.  I do not mean sarcasm -- the part copied\nand pasted from ls-files is almost trivial to bother factoring\nout.  What's nice is read_directory() does all what is needed to\ndeal with .gitignore files, which I forgot almost all about.\n\n> +int status_foreach_cached(status_cb cb);\n> +int status_foreach_updated(status_cb cb);\n> +int status_foreach_changed(status_cb cb);\n> +int status_foreach_untracked(status_cb cb);\n\nI do not see them defined nor used...\n\nI'll take only [1/3] for now but I am interested in 2 and 3.\n"},{"id":"26561","messageId":"20060908054226.GA19537@coredump.intra.peff.net","threadId":"5505","inReplyTo":"7vzmdbqke3.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/3] git-commit.sh: convert run_status to a C builtin","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-09-08T05:42:26Z","receivedAt":"2006-09-08T05:42:26Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 07, 2006 at 05:20:20PM -0700, Junio C Hamano wrote:\n\n> \"status.h\" and \"struct status\" somehow sounds too broad.\n> Granted, \"object.h\" is also broad, but in git context \"object\"\n> has a specific meaning.\n\nI agree it is quite broad (as is git-runstatus). Conceptually it's\nanother type of diff format, but making it a diff argument doesn't\nreally makes much sense. We're at least not introducing any broadness,\nsince there is already git-status; are we interested in fixing that\nname?\n\nNames for similar concepts from other systems: tree-lint (arch),\ninventory (arch), whatsnew (darcs, perhaps a little too close to\nwhatchanged), status (svn, hg), update -n (cvs, ugh!).\n\n> Having said that I cannot come up with a good alternative name.\n> It is not \"project status\" nor \"repository status\".  It is\n> \"working tree status\", but that sounds very loooooooooooooooong.\n\nwt_status? ucu_status (updated, changed, untracked)?\n\n> Very nicely done.  Especially I liked that you are careful not\n> to paint leading '#\\t' (which is noticeable when you use reverse\n> as an attribute).\n\nYes. I seem to recall some issues raised about color attributes\npersisting over a newline, but I can't find any reference to it now.\nUsing color_printf makes sure every color is 'closed' but it sometimes\nincludes the newline in the colorized portion. Does anybody object to\nthat?\n\n\n> Very nice code reuse.  I do not mean sarcasm -- the part copied\n> and pasted from ls-files is almost trivial to bother factoring\n\nYes, I don't like cutting and pasting, but it seemed more confusing to\ntry factoring it out. It's not a lot of *code*, it's just that\nremembering to pick out unmerged entries (and the weird -pos bit) is\nconfusing.\n\n> out.  What's nice is read_directory() does all what is needed to\n> deal with .gitignore files, which I forgot almost all about.\n\nI just had to write a file_exists to check for .git/gitignore, which was\na little clumsy.\n\n> > +int status_foreach_cached(status_cb cb);\n> > +int status_foreach_updated(status_cb cb);\n> > +int status_foreach_changed(status_cb cb);\n> > +int status_foreach_untracked(status_cb cb);\n> I do not see them defined nor used...\n\nMy fault, they were left in from a previous iteration.\n\n> I'll take only [1/3] for now but I am interested in 2 and 3.\n\nOK. Besides the things you mentioned, what improvements would you like\nto see?\n\n-Peff\n"},{"id":"26562","messageId":"7v64fynbpg.fsf@assigned-by-dhcp.cox.net","threadId":"5505","inReplyTo":"20060908054226.GA19537@coredump.intra.peff.net","subject":"Re: [PATCH 3/3] git-commit.sh: convert run_status to a C builtin","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-08T05:56:11Z","receivedAt":"2006-09-08T05:56:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Sep 07, 2006 at 05:20:20PM -0700, Junio C Hamano wrote:\n>\n>> \"status.h\" and \"struct status\" somehow sounds too broad.\n>> Granted, \"object.h\" is also broad, but in git context \"object\"\n>> has a specific meaning.\n>\n> I agree it is quite broad (as is git-runstatus). Conceptually it's\n> another type of diff format, but making it a diff argument doesn't\n> really makes much sense. We're at least not introducing any broadness,\n> since there is already git-status; are we interested in fixing that\n> name?\n\nThe command name is a name exposed to the end user.  We do not\ncurrently have a command to give \"repository status\", and even\nif we had one such a specialized command for repository\nadministrators would be called git-repository-status so\ngit-status is definitely fine as is.\n\nI just wanted to point it out because I felt the names to\nprogrammers are slightly different matter.\n\n> wt_status? ucu_status (updated, changed, untracked)?\n\nYeah, something along those lines.\n\n>> Very nicely done.  Especially I liked that you are careful not\n>> to paint leading '#\\t' (which is noticeable when you use reverse\n>> as an attribute).\n>\n> Yes. I seem to recall some issues raised about color attributes\n> persisting over a newline, but I can't find any reference to it now.\n> Using color_printf makes sure every color is 'closed' but it sometimes\n> includes the newline in the colorized portion. Does anybody object to\n> that?\n\nIn a distant past I saw some terminals get confused near the\nedge if you do that, but these days everybody is on some sort of\nXterm so it may not matter.  But that would probably be nice to\nfix.\n\n> OK. Besides the things you mentioned, what improvements would you like\n> to see?\n\nBesides the things I mentioned?  I dunno offhand -- otherwise I\nwould have mentioned them ;-).\n"},{"id":"26564","messageId":"20060908073452.GA25343@coredump.intra.peff.net","threadId":"5505","inReplyTo":"7v64fynbpg.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/3] git-commit.sh: convert run_status to a C builtin","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-09-08T07:34:52Z","receivedAt":"2006-09-08T07:34:52Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 07, 2006 at 10:56:11PM -0700, Junio C Hamano wrote:\n\n> I just wanted to point it out because I felt the names to\n> programmers are slightly different matter.\n\nFair enough. Do you want to change git-runstatus? It should ideally not\nbe used by end users at all (and hopefully can eventually go away if\ngit-status and git-commit become builtins).\n\n> > wt_status? ucu_status (updated, changed, untracked)?\n> Yeah, something along those lines.\n\nI think wt_status is the most reasonable of those.\n\n> In a distant past I saw some terminals get confused near the\n> edge if you do that, but these days everybody is on some sort of\n> Xterm so it may not matter.  But that would probably be nice to\n> fix.\n\nOK, it will take a little wrangling with the color_printf interface, but\nit should be doable.\n\n> > OK. Besides the things you mentioned, what improvements would you like\n> > to see?\n> Besides the things I mentioned?  I dunno offhand -- otherwise I\n> would have mentioned them ;-).\n\nHeh. OK, I assumed your previous comment hinted at hidden depths of\ndissatisfaction, but clearly not. :) Patches forthcoming...\n\n-Peff\n"},{"id":"26565","messageId":"20060908080318.GA3771@coredump.intra.peff.net","threadId":"5505","inReplyTo":"20060908073452.GA25343@coredump.intra.peff.net","subject":"[PATCH] Move color option parsing out of diff.c and into color.[ch]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-09-08T08:03:18Z","receivedAt":"2006-09-08T08:03:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The intent is to lib-ify colorizing code so it can be reused.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis is a resend with formatting cleanups and a new function,\ncolor_printf_ln.\n\n Makefile |    3 +\n color.c  |  176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n color.h  |   12 ++++\n diff.c   |  136 +-----------------------------------------------\n 4 files changed, 194 insertions(+), 133 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 7b3114f..78748cb 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -251,7 +251,8 @@ LIB_OBJS = \\\n \ttag.o tree.o usage.o config.o environment.o ctype.o copy.o \\\n \tfetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \\\n \twrite_or_die.o trace.o \\\n-\talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS)\n+\talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \\\n+\tcolor.o\n \n BUILTIN_OBJS = \\\n \tbuiltin-add.o \\\ndiff --git a/color.c b/color.c\nnew file mode 100644\nindex 0000000..a949136\n--- /dev/null\n+++ b/color.c\n@@ -0,0 +1,176 @@\n+#include \"color.h\"\n+#include \"cache.h\"\n+#include \"git-compat-util.h\"\n+\n+#include <stdarg.h>\n+\n+#define COLOR_RESET \"\\033[m\"\n+\n+static int parse_color(const char *name, int len)\n+{\n+\tstatic const char * const color_names[] = {\n+\t\t\"normal\", \"black\", \"red\", \"green\", \"yellow\",\n+\t\t\"blue\", \"magenta\", \"cyan\", \"white\"\n+\t};\n+\tchar *end;\n+\tint i;\n+\tfor (i = 0; i < ARRAY_SIZE(color_names); i++) {\n+\t\tconst char *str = color_names[i];\n+\t\tif (!strncasecmp(name, str, len) && !str[len])\n+\t\t\treturn i - 1;\n+\t}\n+\ti = strtol(name, &end, 10);\n+\tif (*name && !*end && i >= -1 && i <= 255)\n+\t\treturn i;\n+\treturn -2;\n+}\n+\n+static int parse_attr(const char *name, int len)\n+{\n+\tstatic const int attr_values[] = { 1, 2, 4, 5, 7 };\n+\tstatic const char * const attr_names[] = {\n+\t\t\"bold\", \"dim\", \"ul\", \"blink\", \"reverse\"\n+\t};\n+\tint i;\n+\tfor (i = 0; i < ARRAY_SIZE(attr_names); i++) {\n+\t\tconst char *str = attr_names[i];\n+\t\tif (!strncasecmp(name, str, len) && !str[len])\n+\t\t\treturn attr_values[i];\n+\t}\n+\treturn -1;\n+}\n+\n+void color_parse(const char *value, const char *var, char *dst)\n+{\n+\tconst char *ptr = value;\n+\tint attr = -1;\n+\tint fg = -2;\n+\tint bg = -2;\n+\n+\tif (!strcasecmp(value, \"reset\")) {\n+\t\tstrcpy(dst, \"\\033[m\");\n+\t\treturn;\n+\t}\n+\n+\t/* [fg [bg]] [attr] */\n+\twhile (*ptr) {\n+\t\tconst char *word = ptr;\n+\t\tint val, len = 0;\n+\n+\t\twhile (word[len] && !isspace(word[len]))\n+\t\t\tlen++;\n+\n+\t\tptr = word + len;\n+\t\twhile (*ptr && isspace(*ptr))\n+\t\t\tptr++;\n+\n+\t\tval = parse_color(word, len);\n+\t\tif (val >= -1) {\n+\t\t\tif (fg == -2) {\n+\t\t\t\tfg = val;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (bg == -2) {\n+\t\t\t\tbg = val;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tgoto bad;\n+\t\t}\n+\t\tval = parse_attr(word, len);\n+\t\tif (val < 0 || attr != -1)\n+\t\t\tgoto bad;\n+\t\tattr = val;\n+\t}\n+\n+\tif (attr >= 0 || fg >= 0 || bg >= 0) {\n+\t\tint sep = 0;\n+\n+\t\t*dst++ = '\\033';\n+\t\t*dst++ = '[';\n+\t\tif (attr >= 0) {\n+\t\t\t*dst++ = '0' + attr;\n+\t\t\tsep++;\n+\t\t}\n+\t\tif (fg >= 0) {\n+\t\t\tif (sep++)\n+\t\t\t\t*dst++ = ';';\n+\t\t\tif (fg < 8) {\n+\t\t\t\t*dst++ = '3';\n+\t\t\t\t*dst++ = '0' + fg;\n+\t\t\t} else {\n+\t\t\t\tdst += sprintf(dst, \"38;5;%d\", fg);\n+\t\t\t}\n+\t\t}\n+\t\tif (bg >= 0) {\n+\t\t\tif (sep++)\n+\t\t\t\t*dst++ = ';';\n+\t\t\tif (bg < 8) {\n+\t\t\t\t*dst++ = '4';\n+\t\t\t\t*dst++ = '0' + bg;\n+\t\t\t} else {\n+\t\t\t\tdst += sprintf(dst, \"48;5;%d\", bg);\n+\t\t\t}\n+\t\t}\n+\t\t*dst++ = 'm';\n+\t}\n+\t*dst = 0;\n+\treturn;\n+bad:\n+\tdie(\"bad config value '%s' for variable '%s'\", value, var);\n+}\n+\n+int git_config_colorbool(const char *var, const char *value)\n+{\n+\tif (!value)\n+\t\treturn 1;\n+\tif (!strcasecmp(value, \"auto\")) {\n+\t\tif (isatty(1) || (pager_in_use && pager_use_color)) {\n+\t\t\tchar *term = getenv(\"TERM\");\n+\t\t\tif (term && strcmp(term, \"dumb\"))\n+\t\t\t\treturn 1;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\tif (!strcasecmp(value, \"never\"))\n+\t\treturn 0;\n+\tif (!strcasecmp(value, \"always\"))\n+\t\treturn 1;\n+\treturn git_config_bool(var, value);\n+}\n+\n+static int color_vprintf(const char *color, const char *fmt,\n+\t\tva_list args, const char *trail)\n+{\n+\tint r = 0;\n+\n+\tif (*color)\n+\t\tr += printf(\"%s\", color);\n+\tr += vprintf(fmt, args);\n+\tif (trail)\n+\t\tr += printf(\"%s\", trail);\n+\tif (*color)\n+\t\tr += printf(\"%s\", COLOR_RESET);\n+\treturn r;\n+}\n+\n+\n+\n+int color_printf(const char *color, const char *fmt, ...)\n+{\n+\tva_list args;\n+\tint r;\n+\tva_start(args, fmt);\n+\tr = color_vprintf(color, fmt, args, 0);\n+\tva_end(args);\n+\treturn r;\n+}\n+\n+int color_printf_ln(const char *color, const char *fmt, ...)\n+{\n+\tva_list args;\n+\tint r;\n+\tva_start(args, fmt);\n+\tr = color_vprintf(color, fmt, args, \"\\n\");\n+\tva_end(args);\n+\treturn r;\n+}\ndiff --git a/color.h b/color.h\nnew file mode 100644\nindex 0000000..88bb8ff\n--- /dev/null\n+++ b/color.h\n@@ -0,0 +1,12 @@\n+#ifndef COLOR_H\n+#define COLOR_H\n+\n+/* \"\\033[1;38;5;2xx;48;5;2xxm\\0\" is 23 bytes */\n+#define COLOR_MAXLEN 24\n+\n+int git_config_colorbool(const char *var, const char *value);\n+void color_parse(const char *var, const char *value, char *dst);\n+int color_printf(const char *color, const char *fmt, ...);\n+int color_printf_ln(const char *color, const char *fmt, ...);\n+\n+#endif /* COLOR_H */\ndiff --git a/diff.c b/diff.c\nindex a3ebc62..8178c11 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -10,6 +10,7 @@ #include \"diff.h\"\n #include \"diffcore.h\"\n #include \"delta.h\"\n #include \"xdiff-interface.h\"\n+#include \"color.h\"\n \n static int use_size_cache;\n \n@@ -17,8 +18,7 @@ static int diff_detect_rename_default;\n static int diff_rename_limit_default = -1;\n static int diff_use_color_default;\n \n-/* \"\\033[1;38;5;2xx;48;5;2xxm\\0\" is 23 bytes */\n-static char diff_colors[][24] = {\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@@ -45,119 +45,6 @@ static int parse_diff_color_slot(const c\n \tdie(\"bad config variable '%s'\", var);\n }\n \n-static int parse_color(const char *name, int len)\n-{\n-\tstatic const char * const color_names[] = {\n-\t\t\"normal\", \"black\", \"red\", \"green\", \"yellow\",\n-\t\t\"blue\", \"magenta\", \"cyan\", \"white\"\n-\t};\n-\tchar *end;\n-\tint i;\n-\tfor (i = 0; i < ARRAY_SIZE(color_names); i++) {\n-\t\tconst char *str = color_names[i];\n-\t\tif (!strncasecmp(name, str, len) && !str[len])\n-\t\t\treturn i - 1;\n-\t}\n-\ti = strtol(name, &end, 10);\n-\tif (*name && !*end && i >= -1 && i <= 255)\n-\t\treturn i;\n-\treturn -2;\n-}\n-\n-static int parse_attr(const char *name, int len)\n-{\n-\tstatic const int attr_values[] = { 1, 2, 4, 5, 7 };\n-\tstatic const char * const attr_names[] = {\n-\t\t\"bold\", \"dim\", \"ul\", \"blink\", \"reverse\"\n-\t};\n-\tint i;\n-\tfor (i = 0; i < ARRAY_SIZE(attr_names); i++) {\n-\t\tconst char *str = attr_names[i];\n-\t\tif (!strncasecmp(name, str, len) && !str[len])\n-\t\t\treturn attr_values[i];\n-\t}\n-\treturn -1;\n-}\n-\n-static void parse_diff_color_value(const char *value, const char *var, char *dst)\n-{\n-\tconst char *ptr = value;\n-\tint attr = -1;\n-\tint fg = -2;\n-\tint bg = -2;\n-\n-\tif (!strcasecmp(value, \"reset\")) {\n-\t\tstrcpy(dst, \"\\033[m\");\n-\t\treturn;\n-\t}\n-\n-\t/* [fg [bg]] [attr] */\n-\twhile (*ptr) {\n-\t\tconst char *word = ptr;\n-\t\tint val, len = 0;\n-\n-\t\twhile (word[len] && !isspace(word[len]))\n-\t\t\tlen++;\n-\n-\t\tptr = word + len;\n-\t\twhile (*ptr && isspace(*ptr))\n-\t\t\tptr++;\n-\n-\t\tval = parse_color(word, len);\n-\t\tif (val >= -1) {\n-\t\t\tif (fg == -2) {\n-\t\t\t\tfg = val;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (bg == -2) {\n-\t\t\t\tbg = val;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tgoto bad;\n-\t\t}\n-\t\tval = parse_attr(word, len);\n-\t\tif (val < 0 || attr != -1)\n-\t\t\tgoto bad;\n-\t\tattr = val;\n-\t}\n-\n-\tif (attr >= 0 || fg >= 0 || bg >= 0) {\n-\t\tint sep = 0;\n-\n-\t\t*dst++ = '\\033';\n-\t\t*dst++ = '[';\n-\t\tif (attr >= 0) {\n-\t\t\t*dst++ = '0' + attr;\n-\t\t\tsep++;\n-\t\t}\n-\t\tif (fg >= 0) {\n-\t\t\tif (sep++)\n-\t\t\t\t*dst++ = ';';\n-\t\t\tif (fg < 8) {\n-\t\t\t\t*dst++ = '3';\n-\t\t\t\t*dst++ = '0' + fg;\n-\t\t\t} else {\n-\t\t\t\tdst += sprintf(dst, \"38;5;%d\", fg);\n-\t\t\t}\n-\t\t}\n-\t\tif (bg >= 0) {\n-\t\t\tif (sep++)\n-\t\t\t\t*dst++ = ';';\n-\t\t\tif (bg < 8) {\n-\t\t\t\t*dst++ = '4';\n-\t\t\t\t*dst++ = '0' + bg;\n-\t\t\t} else {\n-\t\t\t\tdst += sprintf(dst, \"48;5;%d\", bg);\n-\t\t\t}\n-\t\t}\n-\t\t*dst++ = 'm';\n-\t}\n-\t*dst = 0;\n-\treturn;\n-bad:\n-\tdie(\"bad config value '%s' for variable '%s'\", value, var);\n-}\n-\n /*\n  * These are to give UI layer defaults.\n  * The core-level commands such as git-diff-files should\n@@ -171,22 +58,7 @@ int git_diff_ui_config(const char *var, \n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"diff.color\")) {\n-\t\tif (!value)\n-\t\t\tdiff_use_color_default = 1; /* bool */\n-\t\telse if (!strcasecmp(value, \"auto\")) {\n-\t\t\tdiff_use_color_default = 0;\n-\t\t\tif (isatty(1) || (pager_in_use && pager_use_color)) {\n-\t\t\t\tchar *term = getenv(\"TERM\");\n-\t\t\t\tif (term && strcmp(term, \"dumb\"))\n-\t\t\t\t\tdiff_use_color_default = 1;\n-\t\t\t}\n-\t\t}\n-\t\telse if (!strcasecmp(value, \"never\"))\n-\t\t\tdiff_use_color_default = 0;\n-\t\telse if (!strcasecmp(value, \"always\"))\n-\t\t\tdiff_use_color_default = 1;\n-\t\telse\n-\t\t\tdiff_use_color_default = git_config_bool(var, value);\n+\t\tdiff_use_color_default = git_config_colorbool(var, value);\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"diff.renames\")) {\n@@ -201,7 +73,7 @@ int git_diff_ui_config(const char *var, \n \t}\n \tif (!strncmp(var, \"diff.color.\", 11)) {\n \t\tint slot = parse_diff_color_slot(var, 11);\n-\t\tparse_diff_color_value(value, var, diff_colors[slot]);\n+\t\tcolor_parse(value, var, diff_colors[slot]);\n \t\treturn 0;\n \t}\n \treturn git_default_config(var, value);\n-- \n1.4.2.g5290b\n"},{"id":"26573","messageId":"7vk64eivzj.fsf@assigned-by-dhcp.cox.net","threadId":"5505","inReplyTo":"20060908080318.GA3771@coredump.intra.peff.net","subject":"Re: [PATCH] Move color option parsing out of diff.c and into color.[ch]","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-08T08:49:20Z","receivedAt":"2006-09-08T08:49:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> +static int color_vprintf(const char *color, const char *fmt,\n> +\t\tva_list args, const char *trail)\n> +{\n> +\tint r = 0;\n> +\n> +\tif (*color)\n> +\t\tr += printf(\"%s\", color);\n> +\tr += vprintf(fmt, args);\n> +\tif (trail)\n> +\t\tr += printf(\"%s\", trail);\n> +\tif (*color)\n> +\t\tr += printf(\"%s\", COLOR_RESET);\n> +\treturn r;\n> +}\n\nHmm,... don't you mean RESET first and then trail (which is often \"\\n\")?\n\n> +int color_printf(const char *color, const char *fmt, ...)\n> +{\n> +\tva_list args;\n> +\tint r;\n> +\tva_start(args, fmt);\n> +\tr = color_vprintf(color, fmt, args, 0);\n> +\tva_end(args);\n> +\treturn r;\n> +}\n\nPlease spell NULL not 0 (please do not argue that writing a NULL\npointer as integral constant 0 is perfectly valid C -- we all\nknow that.  This is not the language-lawyers correctness issue,\nbut ../linux-2.6/Documentation/CodingStyle thing).  Using\npointer as boolean seems to be Ok style (e.g. \"if (trail)\" does\nnot have to be written \"if (trail == NULL)\").\n"},{"id":"26577","messageId":"20060908091206.GA5758@coredump.intra.peff.net","threadId":"5505","inReplyTo":"7vk64eivzj.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Move color option parsing out of diff.c and into color.[ch]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-09-08T09:12:06Z","receivedAt":"2006-09-08T09:12:06Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Sep 08, 2006 at 01:49:20AM -0700, Junio C Hamano wrote:\n\n> > +\tif (trail)\n> > +\t\tr += printf(\"%s\", trail);\n> > +\tif (*color)\n> > +\t\tr += printf(\"%s\", COLOR_RESET);\n> > +\treturn r;\n> > +}\n> Hmm,... don't you mean RESET first and then trail (which is often \"\\n\")?\n\nARGH. Yes, sorry about that. I wrote it correctly once, and then\nrefactored it to be wrong. :)\n\n> Please spell NULL not 0 (please do not argue that writing a NULL\n\nSorry, I should clearly go read the linux CodingStyle doc before\nsubjecting you to any more of my patches.\n\nI'm assuming you can mark both of those up yourself rather than having\nme resend?\n\n-Peff\n"},{"id":"26594","messageId":"7vpse6gip5.fsf@assigned-by-dhcp.cox.net","threadId":"5505","inReplyTo":"20060908091206.GA5758@coredump.intra.peff.net","subject":"Re: [PATCH] Move color option parsing out of diff.c and into color.[ch]","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-08T21:19:18Z","receivedAt":"2006-09-08T21:19:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I'm assuming you can mark both of those up yourself rather than having\n> me resend?\n\nSure, that's easy enough.\n\nThanks for the patch.\n"}]}