From: Daniel Ferreira <bnmvco@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, Johannes.Schindelin@gmx.de,
Daniel Ferreira <bnmvco@gmail.com>
Subject: [PATCH 2/3] add--interactive: add builtin helper for interactive add
Date: Fri, 5 May 2017 15:43:39 -0300 [thread overview]
Message-ID: <1494009820-2090-3-git-send-email-bnmvco@gmail.com> (raw)
In-Reply-To: <1494009820-2090-1-git-send-email-bnmvco@gmail.com>
Create a builtin helper for git-add--interactive, which right now is
only able to reproduce git-add--interactive.perl's status_cmd()
function, providing a summarized diff numstat to the user.
This is the first step in an effort to convert git-add--interactive.perl
to a C builtin, in search for better portability, expressibility and
performance (specially on non-POSIX systems like Windows).
Additionally, an eventual complete port of git-add--interactive would
remove the last "big" Git script to have Perl as a dependency, allowing
most Git users to have a NOPERL build running without big losses.
Signed-off-by: Daniel Ferreira <bnmvco@gmail.com>
---
.gitignore | 1 +
Makefile | 1 +
builtin.h | 1 +
builtin/add-interactive--helper.c | 258 ++++++++++++++++++++++++++++++++++++++
git.c | 1 +
5 files changed, 262 insertions(+)
create mode 100644 builtin/add-interactive--helper.c
diff --git a/.gitignore b/.gitignore
index 833ef3b..0d6cfe4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@
/git
/git-add
/git-add--interactive
+/git-add-interactive--helper
/git-am
/git-annotate
/git-apply
diff --git a/Makefile b/Makefile
index e35542e..842fce2 100644
--- a/Makefile
+++ b/Makefile
@@ -873,6 +873,7 @@ LIB_OBJS += xdiff-interface.o
LIB_OBJS += zlib.o
BUILTIN_OBJS += builtin/add.o
+BUILTIN_OBJS += builtin/add-interactive--helper.o
BUILTIN_OBJS += builtin/am.o
BUILTIN_OBJS += builtin/annotate.o
BUILTIN_OBJS += builtin/apply.o
diff --git a/builtin.h b/builtin.h
index 9e4a898..3d6a0ab 100644
--- a/builtin.h
+++ b/builtin.h
@@ -30,6 +30,7 @@ extern int textconv_object(const char *path, unsigned mode, const struct object_
extern int is_builtin(const char *s);
extern int cmd_add(int argc, const char **argv, const char *prefix);
+extern int cmd_add_interactive__helper(int argc, const char **argv, const char *prefix);
extern int cmd_am(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_apply(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add-interactive--helper.c b/builtin/add-interactive--helper.c
new file mode 100644
index 0000000..97ca1b3
--- /dev/null
+++ b/builtin/add-interactive--helper.c
@@ -0,0 +1,258 @@
+#include "builtin.h"
+#include "color.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
+
+#define ADD_INTERACTIVE_HEADER_INDENT " "
+
+enum add_interactive_collection_mode {
+ COLLECTION_MODE_NONE,
+ COLLECTION_MODE_WORKTREE,
+ COLLECTION_MODE_INDEX
+};
+
+struct add_interactive_file_status {
+ int selected;
+
+ char path[PATH_MAX];
+
+ int lines_added_index;
+ int lines_deleted_index;
+ int lines_added_worktree;
+ int lines_deleted_worktree;
+};
+
+struct add_interactive_status {
+ enum add_interactive_collection_mode current_mode;
+
+ const char *reference;
+ struct pathspec pathspec;
+
+ int file_count;
+ struct add_interactive_file_status *files;
+};
+
+static int add_interactive_use_color = -1;
+enum color_add_interactive {
+ ADD_INTERACTIVE_PROMPT,
+ ADD_INTERACTIVE_HEADER,
+ ADD_INTERACTIVE_HELP,
+ ADD_INTERACTIVE_ERROR
+};
+
+static char add_interactive_colors[][COLOR_MAXLEN] = {
+ GIT_COLOR_BOLD_BLUE, /* Prompt */
+ GIT_COLOR_BOLD, /* Header */
+ GIT_COLOR_BOLD_RED, /* Help */
+ GIT_COLOR_BOLD_RED /* Error */
+};
+
+static const char *add_interactive_get_color(enum color_add_interactive ix)
+{
+ if (want_color(add_interactive_use_color))
+ return add_interactive_colors[ix];
+ return "";
+}
+
+static int parse_add_interactive_color_slot(const char *slot)
+{
+ if (!strcasecmp(slot, "prompt"))
+ return ADD_INTERACTIVE_PROMPT;
+ if (!strcasecmp(slot, "header"))
+ return ADD_INTERACTIVE_HEADER;
+ if (!strcasecmp(slot, "help"))
+ return ADD_INTERACTIVE_HELP;
+ if (!strcasecmp(slot, "error"))
+ return ADD_INTERACTIVE_ERROR;
+
+ return -1;
+}
+
+static int git_add_interactive_config(const char *var,
+ const char *value, void *cbdata)
+{
+ const char *name;
+
+ if (!strcmp(var, "color.interactive")) {
+ add_interactive_use_color = git_config_colorbool(var, value);
+ return 0;
+ }
+
+ if (skip_prefix(var, "color.interactive", &name)) {
+ int slot = parse_add_interactive_color_slot(name);
+ if (slot < 0)
+ return 0;
+ if (!value)
+ return config_error_nonbool(var);
+ return color_parse(value, add_interactive_colors[slot]);
+ }
+
+ return git_default_config(var, value, cbdata);
+}
+
+static void add_interactive_status_collect_changed_cb(struct diff_queue_struct *q,
+ struct diff_options *options,
+ void *data)
+{
+ struct add_interactive_status *s = data;
+ struct diffstat_t stat;
+ int i, j;
+
+ if (!q->nr)
+ return;
+
+ memset(&stat, 0, sizeof(struct diffstat_t));
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p;
+ p = q->queue[i];
+ diff_flush_stat(p, options, &stat);
+ }
+
+ for (i = 0; i < stat.nr; i++) {
+ int file_index = s->file_count;
+ for (j = 0; j < s->file_count; j++) {
+ if (!strcmp(s->files[j].path, stat.files[i]->name)) {
+ file_index = j;
+ break;
+ }
+ }
+
+ if (file_index == s->file_count) {
+ s->file_count++;
+ s->files = realloc(s->files,
+ (q->nr + s->file_count) * sizeof(*s->files));
+ memset(&s->files[file_index], 0,
+ sizeof(struct add_interactive_file_status));
+ }
+
+ memcpy(s->files[file_index].path, stat.files[i]->name,
+ strlen(stat.files[i]->name) + 1);
+ if (s->current_mode == COLLECTION_MODE_WORKTREE) {
+ s->files[file_index].lines_added_worktree = stat.files[i]->added;
+ s->files[file_index].lines_deleted_worktree = stat.files[i]->deleted;
+ } else if (s->current_mode == COLLECTION_MODE_INDEX) {
+ s->files[file_index].lines_added_index = stat.files[i]->added;
+ s->files[file_index].lines_deleted_index = stat.files[i]->deleted;
+ }
+ }
+}
+
+static void add_interactive_status_collect_changes_worktree(struct add_interactive_status *s)
+{
+ struct rev_info rev;
+
+ s->current_mode = COLLECTION_MODE_WORKTREE;
+
+ init_revisions(&rev, NULL);
+ setup_revisions(0, NULL, &rev, NULL);
+
+ rev.max_count = 0;
+
+ rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ rev.diffopt.format_callback = add_interactive_status_collect_changed_cb;
+ rev.diffopt.format_callback_data = s;
+
+ run_diff_files(&rev, 0);
+}
+
+static void add_interactive_status_collect_changes_index(struct add_interactive_status *s)
+{
+ struct rev_info rev;
+ struct setup_revision_opt opt;
+
+ s->current_mode = COLLECTION_MODE_INDEX;
+
+ init_revisions(&rev, NULL);
+ memset(&opt, 0, sizeof(opt));
+ opt.def = s->reference;
+ setup_revisions(0, NULL, &rev, &opt);
+
+ rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ rev.diffopt.format_callback = add_interactive_status_collect_changed_cb;
+ rev.diffopt.format_callback_data = s;
+
+ run_diff_index(&rev, 1);
+}
+
+static void list_modified_into_status(struct add_interactive_status *s)
+{
+ add_interactive_status_collect_changes_worktree(s);
+ add_interactive_status_collect_changes_index(s);
+}
+
+static void print_modified(void)
+{
+ int i;
+ struct add_interactive_status s;
+ const char *modified_fmt = _("%12s %12s %s");
+ const char *header_color = add_interactive_get_color(ADD_INTERACTIVE_HEADER);
+ unsigned char sha1[20];
+
+ if (read_cache() < 0)
+ return;
+
+ s.current_mode = COLLECTION_MODE_NONE;
+ s.reference = !get_sha1("HEAD", sha1) ? "HEAD": EMPTY_TREE_SHA1_HEX;
+ s.file_count = 0;
+ s.files = NULL;
+ list_modified_into_status(&s);
+
+ printf(ADD_INTERACTIVE_HEADER_INDENT);
+ color_fprintf(stdout, header_color, modified_fmt, _("staged"),
+ _("unstaged"), _("path"));
+ printf("\n");
+
+ for (i = 0; i < s.file_count; i++) {
+ struct add_interactive_file_status f = s.files[i];
+ char selection = f.selected ? '*' : ' ';
+
+ char worktree_changes[50];
+ char index_changes[50];
+
+ if (f.lines_added_worktree != 0 || f.lines_deleted_worktree != 0)
+ snprintf(worktree_changes, 50, "+%d/-%d", f.lines_added_worktree,
+ f.lines_deleted_worktree);
+ else
+ snprintf(worktree_changes, 50, "%s", _("nothing"));
+
+ if (f.lines_added_index != 0 || f.lines_deleted_index != 0)
+ snprintf(index_changes, 50, "+%d/-%d", f.lines_added_index,
+ f.lines_deleted_index);
+ else
+ snprintf(index_changes, 50, "%s", _("unchanged"));
+
+ printf("%c%2d: ", selection, i + 1);
+ printf(modified_fmt, index_changes, worktree_changes, f.path);
+ printf("\n");
+ }
+}
+
+static void status_cmd(void)
+{
+ print_modified();
+}
+
+static const char add_interactive_helper_usage[] =
+"git add-interactive--helper <command>";
+
+int cmd_add_interactive__helper(int argc, const char **argv, const char *prefix)
+{
+ int i, found_opt = 0;
+
+ git_config(git_add_interactive_config, NULL);
+
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (!strcmp(arg, "--status")) {
+ status_cmd();
+ found_opt = 1;
+ }
+ }
+
+ if (!found_opt)
+ usage(add_interactive_helper_usage);
+
+ return 0;
+}
diff --git a/git.c b/git.c
index 8ff44f0..796971e 100644
--- a/git.c
+++ b/git.c
@@ -391,6 +391,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
static struct cmd_struct commands[] = {
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
+ { "add-interactive--helper", cmd_add_interactive__helper, RUN_SETUP | NEED_WORK_TREE },
{ "am", cmd_am, RUN_SETUP | NEED_WORK_TREE },
{ "annotate", cmd_annotate, RUN_SETUP },
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
--
2.7.4 (Apple Git-66)
next prev parent reply other threads:[~2017-05-05 18:44 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-05 18:43 [PATCH 0/3] Port git-add--interactive.perl:status_cmd to C Daniel Ferreira
2017-05-05 18:43 ` [PATCH 1/3] diff: export diffstat interface Daniel Ferreira
2017-05-05 21:28 ` Johannes Schindelin
2017-05-05 18:43 ` Daniel Ferreira [this message]
2017-05-05 20:16 ` [PATCH 2/3] add--interactive: add builtin helper for interactive add Ævar Arnfjörð Bjarmason
2017-05-05 21:21 ` Johannes Schindelin
2017-05-05 22:09 ` Ævar Arnfjörð Bjarmason
2017-05-05 22:30 ` Johannes Schindelin
2017-05-05 22:49 ` Ævar Arnfjörð Bjarmason
2017-05-08 11:35 ` Johannes Schindelin
2017-05-05 23:13 ` Daniel Ferreira (theiostream)
2017-05-05 23:28 ` Ævar Arnfjörð Bjarmason
2017-05-08 12:15 ` Johannes Schindelin
2017-05-05 18:43 ` [PATCH 3/3] add--interactive: use add-interactive--helper for status_cmd Daniel Ferreira
2017-05-05 22:32 ` Johannes Schindelin
2017-05-05 19:31 ` [PATCH 0/3] Port git-add--interactive.perl:status_cmd to C Ævar Arnfjörð Bjarmason
2017-05-05 22:33 ` Johannes Schindelin
2017-05-05 22:35 ` Jonathan Nieder
2017-05-05 22:38 ` Johannes Schindelin
2017-05-05 23:37 ` Daniel Ferreira (theiostream)
2017-05-08 12:23 ` Johannes Schindelin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1494009820-2090-3-git-send-email-bnmvco@gmail.com \
--to=bnmvco@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).