From patchwork Wed Apr 10 17:37:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894475 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8A94A1805 for ; Wed, 10 Apr 2019 17:37:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6565F28496 for ; Wed, 10 Apr 2019 17:37:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 597B728B0A; Wed, 10 Apr 2019 17:37:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A089228535 for ; Wed, 10 Apr 2019 17:37:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729641AbfDJRhx (ORCPT ); Wed, 10 Apr 2019 13:37:53 -0400 Received: from mail-ed1-f65.google.com ([209.85.208.65]:46604 "EHLO mail-ed1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729055AbfDJRhx (ORCPT ); Wed, 10 Apr 2019 13:37:53 -0400 Received: by mail-ed1-f65.google.com with SMTP id d1so2758368edd.13 for ; Wed, 10 Apr 2019 10:37:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=QBNY+zM+g0Jzt9KVZ0RFyjAcM0/7a17ywCCrd1K+glM=; b=VZVulx1OhQF3owETkn4X3KxnmWE8Fmk6JA2AsZA5ndDDERDP85Vck9a0/LOg0K25QG hS0vWQyk+6yYQkGz6YMujid8hQKzFoyazcDNp2lXjsmzNRFMBEpVChE0wwk8OStGUTlV 4DGPrGGTu7xc3qfus1OmdROzfSfjN3dN1om9xHqBPE9SzAPH3Unkz+orsoVFo+K3JgfH 9KkVQ9vLLe2eb8oUZlqQ1u6nwLapBbmjoOYS84sQPDP+aLVd1f5OZG+b+gpJAy7KgUJn kPbXnsqTf9Qbuz8UJ7Zg2mmyZ2XNPzwyKWYXfEWw6gMloxgeIPtNCfkKYTAXdrgC5gGc 9w6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=QBNY+zM+g0Jzt9KVZ0RFyjAcM0/7a17ywCCrd1K+glM=; b=NkvJtRx6UUdIOZri7s+uYYaArD9ReEMuKPgSdZRTrAS9uUr5nSiWIEBScozyi5GuTY 8IWgqbke6yiRvMUuK9GX+3DrGJDRjvr6lN+vVulc/Cj5DtcDrZMUrYY2XcdjsqmsumoC FhpkpVP5Sa+r/z3NSwP5mUAueF68jqhjHWZmOnyVw1eqeikTWmEnqqyFAqUArBH7G0wU PhdobWE+Fyprs0/jz55j80EbyTG5PLNYuMEapjRrtffUwFzux3aJEcL7Z6WvPHOpbBLX O/ShDAzOuBLtORgu/Ccg1gqf6VIkb52McnQWrQQpSD5hhx/PFdKGtXF2lzwUG4fjuOPN HfYw== X-Gm-Message-State: APjAAAXfY1JL+i8x93jf0lAPXZEQRzHTfur0Jm/w3bAEOpvDEl3ggXcJ cCtiJj9UOGS+PprD8w+YMAPgwOca X-Google-Smtp-Source: APXvYqyw2CjLBD1sEmAfMa8GdIthonzy7udEXZNc3H8sQOtDA3qrw6mYE0yPBp3rqPeb/VDdWUe+sQ== X-Received: by 2002:aa7:d3d8:: with SMTP id o24mr28635737edr.53.1554917871024; Wed, 10 Apr 2019 10:37:51 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id c7sm10464206edt.70.2019.04.10.10.37.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:50 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:50 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:38 GMT Message-Id: <12978dc248a2cd07c90559691b8a2add84f45394.1554917868.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Subject: [PATCH 01/11] Start to implement a built-in version of `git add --interactive` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Johannes Schindelin This is hardly the first conversion of a Git command that is implemented as a script to a built-in. So far, the most successful strategy for such conversions has been to add a built-in helper and call that for more and more functionality from the script, as more and more parts are converted. With the interactive add, we choose a different strategy. The sole reason for this is that on Windows (where such a conversion has the most benefits in terms of speed and robustness) we face the very specific problem that a `system()` call in Perl seems to close `stdin` in the parent process when the spawned process consumes even one character from `stdin`. And that just does not work for us here, as it would stop the main loop as soon as any interactive command was performed by the helper. Which is almost all of the commands in `git add -i`. It is almost as if Perl told us once again that it does not want us to use it on Windows. Instead, we follow the opposite route where we start with a bare-bones version of the built-in interactive add, guarded by the new `add.interactive.useBuiltin` config variable, and then add more and more functionality to it, until it is feature complete. At this point, the built-in version of `git add -i` only states that it cannot do anything yet ;-) Signed-off-by: Johannes Schindelin --- Documentation/config/add.txt | 5 +++++ Makefile | 1 + add-interactive.c | 13 +++++++++++++ add-interactive.h | 10 ++++++++++ builtin/add.c | 16 +++++++++++++++- t/README | 4 ++++ 6 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 add-interactive.c create mode 100644 add-interactive.h diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt index 4d753f006e..c9f748f81c 100644 --- a/Documentation/config/add.txt +++ b/Documentation/config/add.txt @@ -5,3 +5,8 @@ add.ignore-errors (deprecated):: option of linkgit:git-add[1]. `add.ignore-errors` is deprecated, as it does not follow the usual naming convention for configuration variables. + +add.interactive.useBuiltin:: + [EXPERIMENTAL] Set to `true` to use the experimental built-in + implementation of the interactive version of linkgit:git-add[1] + instead of the Perl script version. Is `false` by default. diff --git a/Makefile b/Makefile index c5240942f2..18e656a32f 100644 --- a/Makefile +++ b/Makefile @@ -848,6 +848,7 @@ LIB_H = $(shell $(FIND) . \ -name '*.h' -print) LIB_OBJS += abspath.o +LIB_OBJS += add-interactive.o LIB_OBJS += advice.o LIB_OBJS += alias.o LIB_OBJS += alloc.o diff --git a/add-interactive.c b/add-interactive.c new file mode 100644 index 0000000000..540bf185d8 --- /dev/null +++ b/add-interactive.c @@ -0,0 +1,13 @@ +#include "cache.h" +#include "add-interactive.h" +#include "config.h" + +int add_i_config(const char *var, const char *value, void *cb) +{ + return git_default_config(var, value, cb); +} + +int run_add_i(struct repository *r, const struct pathspec *ps) +{ + die(_("No commands are available in the built-in `git add -i` yet!")); +} diff --git a/add-interactive.h b/add-interactive.h new file mode 100644 index 0000000000..e6e6e051eb --- /dev/null +++ b/add-interactive.h @@ -0,0 +1,10 @@ +#ifndef ADD_INTERACTIVE_H +#define ADD_INTERACTIVE_H + +int add_i_config(const char *var, const char *value, void *cb); + +struct repository; +struct pathspec; +int run_add_i(struct repository *r, const struct pathspec *ps); + +#endif diff --git a/builtin/add.c b/builtin/add.c index db2dfa4350..5a32a755c8 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -20,6 +20,7 @@ #include "bulk-checkin.h" #include "argv-array.h" #include "submodule.h" +#include "add-interactive.h" static const char * const builtin_add_usage[] = { N_("git add [] [--] ..."), @@ -28,6 +29,7 @@ static const char * const builtin_add_usage[] = { static int patch_interactive, add_interactive, edit_interactive; static int take_worktree_changes; static int add_renormalize; +static int use_builtin_add_i; struct update_callback_data { int flags; @@ -186,6 +188,9 @@ int run_add_interactive(const char *revision, const char *patch_mode, int status, i; struct argv_array argv = ARGV_ARRAY_INIT; + if (use_builtin_add_i && !patch_mode) + return !!run_add_i(the_repository, pathspec); + argv_array_push(&argv, "add--interactive"); if (patch_mode) argv_array_push(&argv, patch_mode); @@ -319,7 +324,12 @@ static int add_config(const char *var, const char *value, void *cb) ignore_add_errors = git_config_bool(var, value); return 0; } - return git_default_config(var, value, cb); + if (!strcmp(var, "add.interactive.usebuiltin")) { + use_builtin_add_i = git_config_bool(var, value); + return 0; + } + + return add_i_config(var, value, cb); } static const char embedded_advice[] = N_( @@ -394,8 +404,12 @@ int cmd_add(int argc, const char **argv, const char *prefix) int require_pathspec; char *seen = NULL; struct lock_file lock_file = LOCK_INIT; + int use_builtin_add_i_env = + git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1); git_config(add_config, NULL); + if (use_builtin_add_i_env >= 0) + use_builtin_add_i = use_builtin_add_i_env; argc = parse_options(argc, argv, prefix, builtin_add_options, builtin_add_usage, PARSE_OPT_KEEP_ARGV0); diff --git a/t/README b/t/README index 886bbec5bc..6408a1847e 100644 --- a/t/README +++ b/t/README @@ -383,6 +383,10 @@ GIT_TEST_REBASE_USE_BUILTIN=, when false, disables the builtin version of git-rebase. See 'rebase.useBuiltin' in git-config(1). +GIT_TEST_ADD_I_USE_BUILTIN=, when true, enables the +builtin version of git add -i. See 'add.interactive.useBuiltin' in +git-config(1). + GIT_TEST_INDEX_THREADS= enables exercising the multi-threaded loading of the index for the whole test suite by bypassing the default number of cache entries and thread minimums. Setting this to 1 will make the From patchwork Wed Apr 10 17:37:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894477 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3FB6317E1 for ; Wed, 10 Apr 2019 17:37:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D16528535 for ; Wed, 10 Apr 2019 17:37:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0E4E928B4D; Wed, 10 Apr 2019 17:37:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 996BD28AE3 for ; Wed, 10 Apr 2019 17:37:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729662AbfDJRhz (ORCPT ); Wed, 10 Apr 2019 13:37:55 -0400 Received: from mail-ed1-f67.google.com ([209.85.208.67]:43213 "EHLO mail-ed1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727659AbfDJRhy (ORCPT ); Wed, 10 Apr 2019 13:37:54 -0400 Received: by mail-ed1-f67.google.com with SMTP id w3so2770633edu.10 for ; Wed, 10 Apr 2019 10:37:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=NmPrKBH95W/J/xZgv+G4CsKw6zBPtFdY24F+BBhsbJU=; b=iXroslVWMzwofEKZbLv73F4uwCKcp07ER4xfD9B4FLdOs4PJuHlnZ7u6PppvRFbRQI 2Hu+HOooUfMTa57QpLCyVWG2CX5Rqf3I3OPwe0Gh7l3NCEbaTh6nhG84/NI+kHPhbSfm P8j4QW22xTY3DQmwSF7cZmqVOY0MBJT+tQh1COCIaXOFpkcs76QS4dJR61VzVZokfvhZ HvAgAfVIR5FTGTsnmth2AS0i4FLPtBCyM+vCzBC6Xk8Sn9gmphD2rcV5bC0t4hjSdvPZ IATKS88tr9WPpaAX/3u9QUqWXoflvTRqK03uK4asjD8VC00rFsi+L++Rb7vCx/6QSrY5 Vzcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=NmPrKBH95W/J/xZgv+G4CsKw6zBPtFdY24F+BBhsbJU=; b=i1TS+ESgsC+EvKB3ikwVNKCwpcUEUJrk0Cy+Ty0lVBjg6b8l1d1U8ttmK+brRqPLFN jMv/sdx2bZyMCE9m3ks8K5+5u5wumRl6l5aPP1eR/wmEewKoyoRB0IqHHPlBFYzexyOU 1ps9ejOghS/N5Mkr/X2jil0EAi1cJWZbY2Gh9XFM2GEjaCEgdWzKCsuVygtzG22yZU9N cTj3/Xokdbs6iQBwuOyLlBC/5Mj2H+QY48SZdmi3Boyeg/YBDuk+TgOO3xRuerqYd++/ XaH6NkQn5rvTNX4wBsw4j07UkUcMwW0EPHKZnbEucODJGczavA+3r/pTMc63vEjXCv4H LsqQ== X-Gm-Message-State: APjAAAX0yA3CaeaTsqK3+2kqr45KVqIZNd1tahRD0CJIvDJdwUxdN2gy JScOoSFL7M2s6E6UDlleILgUASHt X-Google-Smtp-Source: APXvYqx+8c8wRKleUMkWljstFWSJaGSVDO1431apSE3dt5Rgqqkm0rtsYcnTuLDieCy4ld29mJa99g== X-Received: by 2002:a05:6402:501:: with SMTP id m1mr15279161edv.216.1554917872080; Wed, 10 Apr 2019 10:37:52 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id q20sm6673867ejb.65.2019.04.10.10.37.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:51 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:51 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:39 GMT Message-Id: <06ba1ae34462c201b19b617ee23e76886928b387.1554917868.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Daniel Ferreira via GitGitGadget" Subject: [PATCH 02/11] diff: export diffstat interface Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Daniel Ferreira Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Daniel Ferreira Make the diffstat interface (namely, the diffstat_t struct and compute_diffstat) no longer be internal to diff.c and allow it to be used by other parts of git. This is helpful for code that may want to easily extract information from files using the diff machinery, while flushing it differently from how the show_* functions used by diff_flush() do it. One example is the builtin implementation of git-add--interactive's status. Signed-off-by: Daniel Ferreira Signed-off-by: Slavica Djukic Signed-off-by: Johannes Schindelin --- diff.c | 37 +++++++++++++++---------------------- diff.h | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/diff.c b/diff.c index 5306c48652..daa5f3a736 100644 --- a/diff.c +++ b/diff.c @@ -2489,22 +2489,6 @@ static void pprint_rename(struct strbuf *name, const char *a, const char *b) } } -struct diffstat_t { - int nr; - int alloc; - struct diffstat_file { - char *from_name; - char *name; - char *print_name; - const char *comments; - unsigned is_unmerged:1; - unsigned is_binary:1; - unsigned is_renamed:1; - unsigned is_interesting:1; - uintmax_t added, deleted; - } **files; -}; - static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat, const char *name_a, const char *name_b) @@ -6001,12 +5985,7 @@ void diff_flush(struct diff_options *options) dirstat_by_line) { struct diffstat_t diffstat; - memset(&diffstat, 0, sizeof(struct diffstat_t)); - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - if (check_pair_status(p)) - diff_flush_stat(p, options, &diffstat); - } + compute_diffstat(options, &diffstat, q); if (output_format & DIFF_FORMAT_NUMSTAT) show_numstat(&diffstat, options); if (output_format & DIFF_FORMAT_DIFFSTAT) @@ -6306,6 +6285,20 @@ static int is_submodule_ignored(const char *path, struct diff_options *options) return ignored; } +void compute_diffstat(struct diff_options *options, + struct diffstat_t *diffstat, + struct diff_queue_struct *q) +{ + int i; + + memset(diffstat, 0, sizeof(struct diffstat_t)); + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + if (check_pair_status(p)) + diff_flush_stat(p, options, diffstat); + } +} + void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const struct object_id *oid, diff --git a/diff.h b/diff.h index b512d0477a..ae9bedfab8 100644 --- a/diff.h +++ b/diff.h @@ -240,6 +240,22 @@ void diff_emit_submodule_error(struct diff_options *o, const char *err); void diff_emit_submodule_pipethrough(struct diff_options *o, const char *line, int len); +struct diffstat_t { + int nr; + int alloc; + struct diffstat_file { + char *from_name; + char *name; + char *print_name; + const char *comments; + unsigned is_unmerged:1; + unsigned is_binary:1; + unsigned is_renamed:1; + unsigned is_interesting:1; + uintmax_t added, deleted; + } **files; +}; + enum color_diff { DIFF_RESET = 0, DIFF_CONTEXT = 1, @@ -328,6 +344,9 @@ void diff_change(struct diff_options *, struct diff_filepair *diff_unmerge(struct diff_options *, const char *path); +void compute_diffstat(struct diff_options *options, struct diffstat_t *diffstat, + struct diff_queue_struct *q); + #define DIFF_SETUP_REVERSE 1 #define DIFF_SETUP_USE_SIZE_CACHE 4 From patchwork Wed Apr 10 17:37:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894481 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8C9E817E6 for ; Wed, 10 Apr 2019 17:37:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6803228AE3 for ; Wed, 10 Apr 2019 17:37:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5C53228B0A; Wed, 10 Apr 2019 17:37:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A420E28AE3 for ; Wed, 10 Apr 2019 17:37:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729673AbfDJRh4 (ORCPT ); Wed, 10 Apr 2019 13:37:56 -0400 Received: from mail-ed1-f66.google.com ([209.85.208.66]:34836 "EHLO mail-ed1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729055AbfDJRhz (ORCPT ); Wed, 10 Apr 2019 13:37:55 -0400 Received: by mail-ed1-f66.google.com with SMTP id s39so2808972edb.2 for ; Wed, 10 Apr 2019 10:37:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=ie5qnom5tZ96WWYFZU5f21HqipoVHe7op3gtqxt/IVM=; b=hVr43GiZVwrvIQJBdknww/ThQbpvcqJuzv+6XTejtqCD4MgW+JtvqCeVY2UdKhYZU5 e3bfArnlejQTAJDmN9w5oulEF6ZEpzkhMKMkBrz3z/bmr605QNIQu+WE4dj/g53539Vt 0G0YAweIK44yhHsCz7yv3/tDzhqFCs7T3QLhUUXaO0fZSsXXkBfe83yqj9FAvEKluVMw 2PvCt9Fubsy3z2cSnTMlDDgijQN1y7P92nn/tnTajWtvqyLvOFpExCNVXVp2f5O6Q5Zz y2krPfGEy9xrAE0IhbHrXUVtKGTLQ+GLZzqiapPPnpufxDh1+XcSv5IwjIjnYQbRE2X8 mSLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=ie5qnom5tZ96WWYFZU5f21HqipoVHe7op3gtqxt/IVM=; b=PJUgjLMULrylpX2FvbIBhlKhi40EwKZyASU5BP4YANG6w8d76bSHUEimGZ4KvMHzxj wZNxKiL6I5MIQrpNcncx12SAj15gKA/PXacoPgpOf1N+/Hxy9YAHHR37tR3Z2F//geAZ nG2lwlE1295aGtKVYFe/+SIr+82e8Q7g2+p6/2CQbZw1I19LNoTLIiU4f9+AcaTnFTDz Zjf21JakJl20u19ZR6tw8EMR3r3+SrnJbvEbHZC7fM/w4l7JedogCM1RLVrzCXIQbDZz EZAXfOAQiKONl1lo/iF+iFKE9E2yEl5cE8/fSJZ0fAUg4sBNEeDkrkbj/NK+dc1ng2VR yC3w== X-Gm-Message-State: APjAAAVLnIx/oSNH9GfMd4yLvajeOUHFktJ0dAdwWPYauyDYb2K3nkN6 QPCi53eYiuXFMX5sU9E8Qhe1yBl6 X-Google-Smtp-Source: APXvYqwCF9sHu/ZgfqnvEw2+vJK4g/lxV1evE3QSXcsIgD+C+hZzii4P3GHFmi4o4EjcQG01KebqpA== X-Received: by 2002:a17:906:5014:: with SMTP id s20mr23993949ejj.174.1554917872971; Wed, 10 Apr 2019 10:37:52 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id k5sm4192908ejv.83.2019.04.10.10.37.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:52 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:52 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:40 GMT Message-Id: In-Reply-To: References: From: "Daniel Ferreira via GitGitGadget" Subject: [PATCH 03/11] built-in add -i: implement the `status` command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Daniel Ferreira Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Daniel Ferreira This implements the `status` command of `git add -i`. The data structures introduced in this commit will be extended as needed later. At this point, we re-implement only part of the `list_and_choose()` function of the Perl script `git-add--interactive.perl` and call it `list()`. It does not yet color anything, or do columns, or allow user input. Over the course of the next commits, we will introduce a `list_and_choose()` function that uses `list()` to display the list of options and let the user choose one or more of the displayed items. This will be used to implement the main loop of the built-in `git add -i`, at which point the new `status` command can actually be used. Note that we pass the list of items as a `struct item **` as opposed to a `struct item *`, to allow for the actual items to contain much more information than merely the name. Signed-off-by: Daniel Ferreira Signed-off-by: Slavica Djukic Signed-off-by: Johannes Schindelin --- add-interactive.c | 265 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 264 insertions(+), 1 deletion(-) diff --git a/add-interactive.c b/add-interactive.c index 540bf185d8..f627a56eeb 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -1,13 +1,276 @@ #include "cache.h" #include "add-interactive.h" #include "config.h" +#include "diffcore.h" +#include "revision.h" +#include "refs.h" int add_i_config(const char *var, const char *value, void *cb) { return git_default_config(var, value, cb); } +struct item { + const char *name; +}; + +struct list_options { + const char *header; + void (*print_item)(int i, struct item *item, void *print_item_data); + void *print_item_data; +}; + +static void list(struct item **list, size_t nr, struct list_options *opts) +{ + int i; + + if (!nr) + return; + + if (opts->header) + printf("%s\n", opts->header); + + for (i = 0; i < nr; i++) { + opts->print_item(i, list[i], opts->print_item_data); + putchar('\n'); + } +} + +struct adddel { + uintmax_t add, del; + unsigned seen:1, binary:1; +}; + +struct file_list { + struct file_item { + struct item item; + struct adddel index, worktree; + } **file; + size_t nr, alloc; +}; + +static void add_file_item(struct file_list *list, const char *name) +{ + struct file_item *item; + + FLEXPTR_ALLOC_STR(item, item.name, name); + + ALLOC_GROW(list->file, list->nr + 1, list->alloc); + list->file[list->nr++] = item; +} + +static void reset_file_list(struct file_list *list) +{ + size_t i; + + for (i = 0; i < list->nr; i++) + free(list->file[i]); + list->nr = 0; +} + +static void release_file_list(struct file_list *list) +{ + reset_file_list(list); + FREE_AND_NULL(list->file); + list->alloc = 0; +} + +static int file_item_cmp(const void *a, const void *b) +{ + const struct file_item * const *f1 = a; + const struct file_item * const *f2 = b; + + return strcmp((*f1)->item.name, (*f2)->item.name); +} + +struct pathname_entry { + struct hashmap_entry ent; + size_t index; + char pathname[FLEX_ARRAY]; +}; + +static int pathname_entry_cmp(const void *unused_cmp_data, + const void *entry, const void *entry_or_key, + const void *pathname) +{ + const struct pathname_entry *e1 = entry, *e2 = entry_or_key; + + return strcmp(e1->pathname, + pathname ? (const char *)pathname : e2->pathname); +} + +struct collection_status { + enum { FROM_WORKTREE = 0, FROM_INDEX = 1 } phase; + + const char *reference; + + struct file_list *list; + struct hashmap file_map; +}; + +static void collect_changes_cb(struct diff_queue_struct *q, + struct diff_options *options, + void *data) +{ + struct collection_status *s = data; + struct diffstat_t stat = { 0 }; + int i; + + if (!q->nr) + return; + + compute_diffstat(options, &stat, q); + + for (i = 0; i < stat.nr; i++) { + const char *name = stat.files[i]->name; + int hash = strhash(name); + struct pathname_entry *entry; + size_t file_index; + struct file_item *file; + struct adddel *adddel; + + entry = hashmap_get_from_hash(&s->file_map, hash, name); + if (entry) + file_index = entry->index; + else { + FLEX_ALLOC_STR(entry, pathname, name); + hashmap_entry_init(entry, hash); + entry->index = file_index = s->list->nr; + hashmap_add(&s->file_map, entry); + + add_file_item(s->list, name); + } + file = s->list->file[file_index]; + + adddel = s->phase == FROM_INDEX ? &file->index : &file->worktree; + adddel->seen = 1; + adddel->add = stat.files[i]->added; + adddel->del = stat.files[i]->deleted; + if (stat.files[i]->is_binary) + adddel->binary = 1; + } +} + +static int get_modified_files(struct repository *r, struct file_list *list, + const struct pathspec *ps) +{ + struct object_id head_oid; + int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, + &head_oid, NULL); + struct collection_status s = { FROM_WORKTREE }; + + if (repo_read_index_preload(r, ps, 0) < 0) + return error(_("could not read index")); + + s.list = list; + hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0); + + for (s.phase = FROM_WORKTREE; s.phase <= FROM_INDEX; s.phase++) { + struct rev_info rev; + struct setup_revision_opt opt = { 0 }; + + opt.def = is_initial ? + empty_tree_oid_hex() : oid_to_hex(&head_oid); + + init_revisions(&rev, NULL); + setup_revisions(0, NULL, &rev, &opt); + + rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; + rev.diffopt.format_callback = collect_changes_cb; + rev.diffopt.format_callback_data = &s; + + if (ps) + copy_pathspec(&rev.prune_data, ps); + + if (s.phase == FROM_INDEX) + run_diff_index(&rev, 1); + else { + rev.diffopt.flags.ignore_dirty_submodules = 1; + run_diff_files(&rev, 0); + } + } + hashmap_free(&s.file_map, 1); + + /* While the diffs are ordered already, we ran *two* diffs... */ + QSORT(list->file, list->nr, file_item_cmp); + + return 0; +} + +static void populate_wi_changes(struct strbuf *buf, + struct adddel *ad, const char *no_changes) +{ + if (ad->binary) + strbuf_addstr(buf, _("binary")); + else if (ad->seen) + strbuf_addf(buf, "+%"PRIuMAX"/-%"PRIuMAX, + (uintmax_t)ad->add, (uintmax_t)ad->del); + else + strbuf_addstr(buf, no_changes); +} + +struct print_file_item_data { + const char *modified_fmt; + struct strbuf buf, index, worktree; +}; + +static void print_file_item(int i, struct item *item, + void *print_file_item_data) +{ + struct file_item *c = (struct file_item *)item; + struct print_file_item_data *d = print_file_item_data; + + strbuf_reset(&d->index); + strbuf_reset(&d->worktree); + strbuf_reset(&d->buf); + + populate_wi_changes(&d->worktree, &c->worktree, _("nothing")); + populate_wi_changes(&d->index, &c->index, _("unchanged")); + strbuf_addf(&d->buf, d->modified_fmt, + d->index.buf, d->worktree.buf, item->name); + + printf(" %2d: %s", i + 1, d->buf.buf); +} + +static int run_status(struct repository *r, const struct pathspec *ps, + struct file_list *files, struct list_options *opts) +{ + reset_file_list(files); + + if (get_modified_files(r, files, ps) < 0) + return -1; + + if (files->nr) + list((struct item **)files->file, files->nr, opts); + putchar('\n'); + + return 0; +} + int run_add_i(struct repository *r, const struct pathspec *ps) { - die(_("No commands are available in the built-in `git add -i` yet!")); + struct print_file_item_data print_file_item_data = { + "%12s %12s %s", STRBUF_INIT, STRBUF_INIT, STRBUF_INIT + }; + struct list_options opts = { + NULL, print_file_item, &print_file_item_data + }; + struct strbuf header = STRBUF_INIT; + struct file_list files = { NULL }; + int res = 0; + + strbuf_addstr(&header, " "); + strbuf_addf(&header, print_file_item_data.modified_fmt, + _("staged"), _("unstaged"), _("path")); + opts.header = header.buf; + + res = run_status(r, ps, &files, &opts); + + release_file_list(&files); + strbuf_release(&print_file_item_data.buf); + strbuf_release(&print_file_item_data.index); + strbuf_release(&print_file_item_data.worktree); + strbuf_release(&header); + + return res; } From patchwork Wed Apr 10 17:37:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894479 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A333F17E1 for ; Wed, 10 Apr 2019 17:37:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 80AD128AE3 for ; Wed, 10 Apr 2019 17:37:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 74CE128B0A; Wed, 10 Apr 2019 17:37:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1585928AE3 for ; Wed, 10 Apr 2019 17:37:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729678AbfDJRh5 (ORCPT ); Wed, 10 Apr 2019 13:37:57 -0400 Received: from mail-ed1-f67.google.com ([209.85.208.67]:34752 "EHLO mail-ed1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729655AbfDJRh4 (ORCPT ); Wed, 10 Apr 2019 13:37:56 -0400 Received: by mail-ed1-f67.google.com with SMTP id x14so2814746eds.1 for ; Wed, 10 Apr 2019 10:37:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=xlQ44cEW8g8+h+YkNNfpEFl7iqnx2b9UReJ1Qvue5RU=; b=S/VCnW8sFUNafj6NR+dBEliVFJdcn+jBhSVQ9258rFthx7fU3TEgShwyPIQYrUDWev QvLfIA/1C+Zdf+UYDkT+Nwv8ixNpHycfyWRx3MgYKSnQbCf5viRgUWt1XZVmUDp5wqQ3 g5fRsA890Jjj9zvRE06+Tgo3m93ZC+pGMGgF7vIpylGHXRenwYzosPK4rW0HLno2R7/e bLgClieKTPoFLpzdiZL7QRGERpR0hmDvOPCOgMb/eiJI9AySbDgGnFjojeSrEhz6Zdrl o550AnIRJlkdcruqBcmswwnOKgGKAvNZqVAS6r2kg46M6SDsw9QGTXG+9AfdXSUL4MCC 0xIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=xlQ44cEW8g8+h+YkNNfpEFl7iqnx2b9UReJ1Qvue5RU=; b=Hum2Emq55k1PX+TQHDudkoBmQCZuSSf7EXEm+oGgxQ6RGdOI1ZN+aZbJlbHk7A8p3A NsxgGrs2mgBHeQRFtb3tEP8+RZZqeUUSCU9RLJdz+C85q1YLKX9IcNlvS+zlFX/u20VC qOhCd0hkuiCztg3pSnrfbC+YaldxursyenDgnJryWcjmnduiVQmw3lCB8GWM4kooKtew ViDSPpLczSlRLa0ePGRNYHBRnBHiF+WBcW6cqCWjjFQ0b+WRqsJ/SXBeA29EkHElSe7t kywLebzR8HVQpF2q6gF0mSo6NOShrDkXLgVCvHYDAxpsfFcflmM3HJiRP2CYhZ8fZlNp 1rrg== X-Gm-Message-State: APjAAAUwZJ4DNkkRVP+UA/55CZP3q2iFa+3HfndPhKx1480pNWwZHDYf U3EbyCjIM4fPzeqMNDc5zxNSpd8X X-Google-Smtp-Source: APXvYqx5D5CJFxW9YTFuRPrhfUDAXvHzG27aRgq75tFD/o5crbQUkBNcpWRf+amt62JicmgEpicsBQ== X-Received: by 2002:a17:906:37cb:: with SMTP id o11mr25049464ejc.199.1554917873793; Wed, 10 Apr 2019 10:37:53 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id l63sm1278456ede.22.2019.04.10.10.37.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:53 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:53 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:41 GMT Message-Id: In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Subject: [PATCH 04/11] built-in add -i: refresh the index before running `status` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Johannes Schindelin This is what the Perl version does, and therefore it is what the built-in version should do, too. Signed-off-by: Johannes Schindelin --- add-interactive.c | 4 +++- repository.c | 19 +++++++++++++++++++ repository.h | 7 +++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/add-interactive.c b/add-interactive.c index f627a56eeb..d971b58552 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -264,7 +264,9 @@ int run_add_i(struct repository *r, const struct pathspec *ps) _("staged"), _("unstaged"), _("path")); opts.header = header.buf; - res = run_status(r, ps, &files, &opts); + repo_refresh_and_write_index(r, REFRESH_QUIET, 1); + if (run_status(r, ps, &files, &opts) < 0) + res = -1; release_file_list(&files); strbuf_release(&print_file_item_data.buf); diff --git a/repository.c b/repository.c index 65e6f8b8fd..c90f310093 100644 --- a/repository.c +++ b/repository.c @@ -272,3 +272,22 @@ int repo_hold_locked_index(struct repository *repo, BUG("the repo hasn't been setup"); return hold_lock_file_for_update(lf, repo->index_file, flags); } + +int repo_refresh_and_write_index(struct repository *r, + unsigned int flags, int gentle) +{ + struct lock_file lock_file = LOCK_INIT; + int fd; + + if (repo_read_index_preload(r, NULL, 0) < 0) + return error(_("could not read index")); + fd = repo_hold_locked_index(r, &lock_file, 0); + if (!gentle && fd < 0) + return error(_("could not lock index for writing")); + refresh_index(r->index, flags, NULL, NULL, NULL); + if (0 <= fd) + repo_update_index_if_able(r, &lock_file); + rollback_lock_file(&lock_file); + + return 0; +} diff --git a/repository.h b/repository.h index 8981649d43..fb49e0e328 100644 --- a/repository.h +++ b/repository.h @@ -154,5 +154,12 @@ int repo_read_index_unmerged(struct repository *); */ void repo_update_index_if_able(struct repository *, struct lock_file *); +/* + * Refresh the index and write it out. If the index file could not be + * locked, error out, except in gentle mode. The flags will be passed + * through to refresh_index(). + */ +int repo_refresh_and_write_index(struct repository *r, + unsigned int flags, int gentle); #endif /* REPOSITORY_H */ From patchwork Wed Apr 10 17:37:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894483 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BBC0717E6 for ; Wed, 10 Apr 2019 17:38:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98A2E28AE3 for ; Wed, 10 Apr 2019 17:38:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8CF2628B0A; Wed, 10 Apr 2019 17:38:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2F64628AE3 for ; Wed, 10 Apr 2019 17:38:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729711AbfDJRiA (ORCPT ); Wed, 10 Apr 2019 13:38:00 -0400 Received: from mail-ed1-f68.google.com ([209.85.208.68]:34754 "EHLO mail-ed1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729660AbfDJRh4 (ORCPT ); Wed, 10 Apr 2019 13:37:56 -0400 Received: by mail-ed1-f68.google.com with SMTP id x14so2814795eds.1 for ; Wed, 10 Apr 2019 10:37:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=yWirg5v6fuZl0to3sdCOyFAvFYKD32E8HlXBuqhxkhA=; b=qe57E74j7OE0XnqQq/RCsPFH+xnR5bmqe5BSJ2r4n3xFB59OnSuCL49h1/5cSth3W/ MRz1dRxQVAGVTMFSAdISkjSwFtsUTAy3OWQsaFsBuaArX9JyTttl/udh+3P8FO5FTm5c 01snClyF7ZUPUMHZz40UC+eqYxkjui/jt8/wgibMMq41tvHnKJVve7Puys9sLrxOw+YR E/S9LKANHXb+MZmcbHz4VtxjibV4g7UiAwureKMTJuNW7C6kYuRtzTQhZKzfkDvzuuuq h2NCb6dTbfPVXXh8wilhVl6boAzjj4nxreuk0YFvy3/tUqIoq6i9yq/odGd3Qkm1lw7C Skeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=yWirg5v6fuZl0to3sdCOyFAvFYKD32E8HlXBuqhxkhA=; b=Jgth8e2Z9mjNDOMcUCTx3fdZVsBGl9ZF9xCk/ZC83pR3zjRfbWOiRKZ2LGRQ9Yv8TC e/F/01OOpmAll6oIcCtT7lW5ucaBrcCEh5qGCdZb5iSU1/0wLjFoD6SUIdTkj4prclKP zJkyna6DMGkgZfu1T1kj9nYnNiZ/7jgGqyH2uc0lGHdaJpRV7PSE1tqExplScCjT8ffQ OXcGzsZsu4ivNt/04Pe8RPMjSEObaJZb2lxKQdmeTauxSUMNdc3c8eTJn1mzdIxLTEFE 3XKhWXZho26X6r1frOdkDDbdi+Suj77z8bhuTVRhGos3bL6EfvVAOVCD/9f4E1LeAlhG mFzw== X-Gm-Message-State: APjAAAVAvzqkRTKnaEeZrRTFlWnNmU2PnKARLeCnxDUmJjMU+bbyT8tN k7DJvAc5PBAsWkRoz6xpFsFhWR2A X-Google-Smtp-Source: APXvYqxWte379svjWmbB/Zr9JrNWv48HkgaGWetMaxWkjmBC0+MU383fadU16cwyEDscFS/5aOWQMQ== X-Received: by 2002:aa7:ce8b:: with SMTP id y11mr13373966edv.149.1554917874677; Wed, 10 Apr 2019 10:37:54 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id b10sm436381edi.28.2019.04.10.10.37.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:54 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:54 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:42 GMT Message-Id: In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Subject: [PATCH 05/11] built-in add -i: color the header in the `status` command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Johannes Schindelin For simplicity, we only implemented the `status` command without colors. This patch starts adding color, matching what the Perl script `git-add--interactive.perl` does. Original-Patch-By: Daniel Ferreira Signed-off-by: Slavica Djukic Signed-off-by: Johannes Schindelin --- add-interactive.c | 51 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index d971b58552..79adc58321 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -1,13 +1,56 @@ #include "cache.h" #include "add-interactive.h" #include "config.h" +#include "color.h" +#include "config.h" #include "diffcore.h" #include "revision.h" #include "refs.h" +static int use_color = -1; + +enum color_add_i { + COLOR_HEADER = 0, +}; + +static char list_colors[][COLOR_MAXLEN] = { + GIT_COLOR_BOLD, /* Header */ +}; + +static const char *get_add_i_color(enum color_add_i ix) +{ + if (want_color(use_color)) + return list_colors[ix]; + return ""; +} + +static int parse_color_slot(const char *slot) +{ + if (!strcasecmp(slot, "header")) + return COLOR_HEADER; + + return -1; +} + int add_i_config(const char *var, const char *value, void *cb) { - return git_default_config(var, value, cb); + const char *name; + + if (!strcmp(var, "color.interactive")) { + use_color = git_config_colorbool(var, value); + return 0; + } + + if (skip_prefix(var, "color.interactive.", &name)) { + int slot = parse_color_slot(name); + if (slot < 0) + return 0; + if (!value) + return config_error_nonbool(var); + return color_parse(value, list_colors[slot]); + } + + return git_color_default_config(var, value, cb); } struct item { @@ -27,8 +70,10 @@ static void list(struct item **list, size_t nr, struct list_options *opts) if (!nr) return; - if (opts->header) - printf("%s\n", opts->header); + if (opts->header) { + const char *header_color = get_add_i_color(COLOR_HEADER); + color_fprintf_ln(stdout, header_color, "%s", opts->header); + } for (i = 0; i < nr; i++) { opts->print_item(i, list[i], opts->print_item_data); From patchwork Wed Apr 10 17:37:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894485 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B549317E1 for ; Wed, 10 Apr 2019 17:38:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9206528AE3 for ; Wed, 10 Apr 2019 17:38:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8622428B0A; Wed, 10 Apr 2019 17:38:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F126D28AE3 for ; Wed, 10 Apr 2019 17:38:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729702AbfDJRh7 (ORCPT ); Wed, 10 Apr 2019 13:37:59 -0400 Received: from mail-ed1-f66.google.com ([209.85.208.66]:38872 "EHLO mail-ed1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729670AbfDJRh5 (ORCPT ); Wed, 10 Apr 2019 13:37:57 -0400 Received: by mail-ed1-f66.google.com with SMTP id d13so2793794edr.5 for ; Wed, 10 Apr 2019 10:37:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=wGECj64P2K9dvBshKB4z1BenSdgxSXocr8ywWHrl11g=; b=Apm0tz9mfRwtoWlPK+ODvcC5APO/DklaHWytgPJ2Fg56VqLm6mapmX7/vcilESOM/F JClLoAEVPvjUT8aYgQJtq+CXopflcOQVMMBYKukrgJjSg+23y9IfCMKx8Rh5a5k5j4Zv PyruueB8qLJuJ57U0CLdPbc0lLbZ+ivFB5m+gZjuFODgiXbOEqB6UpWI6Op9xYdJXcaN b+VfqPqMsERxxurSl1gXzMgjseimT/9NJMkOY5rGjlXtlZMwDTwZPu1m5RfEjfJU1EKc lIM3JJ8uS2lhSMJA4yrk/PMUQ2StvSn1Fy1UlK1GLOp3gTDFWTCDpuRW3BpL8UGHTBAb NUbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=wGECj64P2K9dvBshKB4z1BenSdgxSXocr8ywWHrl11g=; b=AOq7FuaJJkBjxpNEpALxYgG1xYVMtwARAenDZLgIqyxeu9gt+A2JVNar5cPuQAGFgJ Ivy2U3NXb6sdMQ0qx+sxM8lTSb1bjMb1eBXhEhfFKXiXo7nF6EvaSOS8qLrCV7JeV/+1 coajmqOD3HBmBruCRPDQ9kNMOtpUZysquCT3USBo2YEUZQpA8SrjX4VsFUAV1g94dYHM YGzEYymgciGi4B2wg5QCTstoLAfdyKS3iW4LHLiecb7mbBLizkCnxtKcaMAuTzCNs7lg Fm9+WsY63ZtZ1qZHp8zfcvyW1Y8xOzidk6BKwraC9tuiLvUlco/wTc2EUpRL/uCE7jZm i2xg== X-Gm-Message-State: APjAAAVwd8wdV7ro5Xhs+jUIZbIvBwdJuCyLDLHfnL16IWHWHL4MH3Xw Z+nV5r8J+pKljp3iCfTCcEp/o86T X-Google-Smtp-Source: APXvYqwNkQOu7x/bjxJshy1r0f20DOnIm0YCBDC3m62UivA5lyFnGySfhdelETMOg6XzRegVSOlLYA== X-Received: by 2002:a50:978e:: with SMTP id e14mr27798221edb.217.1554917875530; Wed, 10 Apr 2019 10:37:55 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id f32sm10757585edf.59.2019.04.10.10.37.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:55 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:55 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:43 GMT Message-Id: <93b3151b6c8abeeab0674919badae72e39eea68d.1554917868.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Subject: [PATCH 06/11] built-in add -i: implement the main loop Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Johannes Schindelin The reason why we did not start with the main loop to begin with is that it is the first user of `list_and_choose()`, which uses the `list()` function that we conveniently introduced for use by the `status` command. Apart from the "and choose" part, there are more differences between the way the `status` command calls the `list_and_choose()` function in the Perl version of `git add -i` compared to the other callers of said function. The most important ones: - The list is not only shown, but the user is also asked to make a choice, possibly selecting multiple entries. - The list of items is prefixed with a marker indicating what items have been selected, if multi-selection is allowed. - Initially, for each item a unique prefix (if there exists any within the given parameters) is determined, and shown in the list, and accepted as a shortcut for the selection. These features will be implemented later, except the part where the user can choose a command. At this stage, though, the built-in `git add -i` still only supports the `status` command, with the remaining commands to follow over the course of the next commits. In addition, we also modify `list()` to support displaying the commands in columns, even if there is currently only one. The Perl script `git-add--interactive.perl` mixed the purposes of the "list" and the "and choose" part into the same function. In the C version, we will keep them separate instead, calling the `list()` function from the `list_and_choose()` function. Note that we only have a prompt ending in a single ">" at this stage; later commits will add commands that display a double ">>" to indicate that the user is in a different loop than the main one. Signed-off-by: Johannes Schindelin --- add-interactive.c | 122 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 2 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index 79adc58321..c8bd62369e 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -58,6 +58,7 @@ struct item { }; struct list_options { + int columns; const char *header; void (*print_item)(int i, struct item *item, void *print_item_data); void *print_item_data; @@ -65,7 +66,7 @@ struct list_options { static void list(struct item **list, size_t nr, struct list_options *opts) { - int i; + int i, last_lf = 0; if (!nr) return; @@ -77,8 +78,90 @@ static void list(struct item **list, size_t nr, struct list_options *opts) for (i = 0; i < nr; i++) { opts->print_item(i, list[i], opts->print_item_data); + + if ((opts->columns) && ((i + 1) % (opts->columns))) { + putchar('\t'); + last_lf = 0; + } + else { + putchar('\n'); + last_lf = 1; + } + } + + if (!last_lf) putchar('\n'); +} +struct list_and_choose_options { + struct list_options list_opts; + + const char *prompt; +}; + +/* + * Returns the selected index. + */ +static ssize_t list_and_choose(struct item **items, size_t nr, + struct list_and_choose_options *opts) +{ + struct strbuf input = STRBUF_INIT; + ssize_t res = -1; + + for (;;) { + char *p, *endp; + + strbuf_reset(&input); + + list(items, nr, &opts->list_opts); + + printf("%s%s", opts->prompt, "> "); + fflush(stdout); + + if (strbuf_getline(&input, stdin) == EOF) { + putchar('\n'); + res = -2; + break; + } + strbuf_trim(&input); + + if (!input.len) + break; + + p = input.buf; + for (;;) { + size_t sep = strcspn(p, " \t\r\n,"); + ssize_t index = -1; + + if (!sep) { + if (!*p) + break; + p++; + continue; + } + + if (isdigit(*p)) { + index = strtoul(p, &endp, 10) - 1; + if (endp != p + sep) + index = -1; + } + + p[sep] = '\0'; + if (index < 0 || index >= nr) + printf(_("Huh (%s)?\n"), p); + else { + res = index; + break; + } + + p += sep + 1; + } + + if (res >= 0) + break; } + + strbuf_release(&input); + return res; } struct adddel { @@ -292,16 +375,39 @@ static int run_status(struct repository *r, const struct pathspec *ps, return 0; } +static void print_command_item(int i, struct item *item, + void *print_command_item_data) +{ + printf(" %2d: %s", i + 1, item->name); +} + +struct command_item { + struct item item; + int (*command)(struct repository *r, const struct pathspec *ps, + struct file_list *files, struct list_options *opts); +}; + int run_add_i(struct repository *r, const struct pathspec *ps) { + struct list_and_choose_options main_loop_opts = { + { 4, N_("*** Commands ***"), print_command_item, NULL }, + N_("What now") + }; + struct command_item + status = { { "status" }, run_status }; + struct command_item *commands[] = { + &status + }; + struct print_file_item_data print_file_item_data = { "%12s %12s %s", STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; struct list_options opts = { - NULL, print_file_item, &print_file_item_data + 0, NULL, print_file_item, &print_file_item_data }; struct strbuf header = STRBUF_INIT; struct file_list files = { NULL }; + ssize_t i; int res = 0; strbuf_addstr(&header, " "); @@ -313,6 +419,18 @@ int run_add_i(struct repository *r, const struct pathspec *ps) if (run_status(r, ps, &files, &opts) < 0) res = -1; + for (;;) { + i = list_and_choose((struct item **)commands, + ARRAY_SIZE(commands), &main_loop_opts); + if (i < -1) { + printf(_("Bye.\n")); + res = 0; + break; + } + if (i >= 0) + res = commands[i]->command(r, ps, &files, &opts); + } + release_file_list(&files); strbuf_release(&print_file_item_data.buf); strbuf_release(&print_file_item_data.index); From patchwork Wed Apr 10 17:37:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894491 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 17D9417E6 for ; Wed, 10 Apr 2019 17:38:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E837228AE3 for ; Wed, 10 Apr 2019 17:38:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DCC1A28AE7; Wed, 10 Apr 2019 17:38:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 183E128B2D for ; Wed, 10 Apr 2019 17:38:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729365AbfDJRiD (ORCPT ); Wed, 10 Apr 2019 13:38:03 -0400 Received: from mail-ed1-f68.google.com ([209.85.208.68]:42279 "EHLO mail-ed1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729686AbfDJRh7 (ORCPT ); Wed, 10 Apr 2019 13:37:59 -0400 Received: by mail-ed1-f68.google.com with SMTP id x61so2767685edc.9 for ; Wed, 10 Apr 2019 10:37:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=cdblAUKb1BRCIE4qquMZH5t9/Ta5EkwHhGee4Xpbjf8=; b=qitn+TmE9uAHmc7QrNOdgphsvkLJ4bqy+z6m6O6ZN0IhkmqDefHiaUm5DjnOotNI0q zYSsrHtQI9ujpt5erSCXyZ9FU4e6auhRqv+XT5pMfx1vhvSG93haHbwy4KCUMyQ53IY0 G//6gK3O3zc4cVz0Q/mG9p2caBz/ICWMcOt2BcP81H3n4FgWuXCYeYatm2riO8SB1xfE rmdJUWrqKfCYqFakbTWWKkbmtlqhuAEKjHGbHZbGXFTAWdqgTLDUb+aJzzMeFQfk3dtl ws/wndylLb3Bz9E7SnGbOy9H5aeBQPT9K+V8cyy7KooE/Ssmg0wd7qQFrSF05x3TW1rd imsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=cdblAUKb1BRCIE4qquMZH5t9/Ta5EkwHhGee4Xpbjf8=; b=TFCcfXUXVdvHe2+TK6ym26NhAALt2HQIazAoxKLEPBTxn1UDkL7GZIVegDULfUJY2J Flkyak2md2QqXVfrOOnXPHstSdfe6KAU3NL0esy5Ww71UYlHVjv4k3ZzNQgndoTrZZ4u H/c4tYgsuU5iUENxafL4ImzVOI3TLkK7ElUKC/VpIrPMenlwK3I8fO5gbHWYevjuvsTx GcQlmXItjkJnl2kOeuwb4qzJ3sKFkuizkVnLZn9vVP1FK1hzjik+F6yC8c/TEeLQzx/m vHX2teJQg8hUEmwvtFVQdLFHsco8cS14/C/AlXAVKUsqPGv/0JDDf/XX/dn4mWYkJ1Wp jBJg== X-Gm-Message-State: APjAAAWW82dWLvCpbEmGyGEyPno2797Ar0MOR2ojYwzaxGLCbssKlV40 ff2kxFVeX+zPifxY1W9dZSsJtk5D X-Google-Smtp-Source: APXvYqxqPiQ4GEFTP9LyJvwcs2rsT420ske76kKNGXEwQn7m5wfMztRR+ehXdO6zhhtKnQBVnNfF3w== X-Received: by 2002:a50:ba8a:: with SMTP id x10mr9465917ede.209.1554917876464; Wed, 10 Apr 2019 10:37:56 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id h11sm4387653eds.44.2019.04.10.10.37.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:55 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:55 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:44 GMT Message-Id: In-Reply-To: References: From: "Slavica Djukic via GitGitGadget" Subject: [PATCH 07/11] Add a function to determine unique prefixes for a list of strings Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Slavica Djukic Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Slavica Djukic In the `git add -i` command, we show unique prefixes of the commands and files, to give an indication what prefix would select them. Naturally, the C implementation looks a lot different than the Perl implementation: in Perl, a trie is much easier implemented, while we already have a pretty neat hashmap implementation in C that we use for the purpose of storing (not necessarily unique) prefixes. The idea: for each item that we add, we generate prefixes starting with the first letter, then the first two letters, then three, etc, until we find a prefix that is unique (or until the prefix length would be longer than we want). If we encounter a previously-unique prefix on the way, we adjust that item's prefix to make it unique again (or we mark it as having no unique prefix if we failed to find one). These partial prefixes are stored in a hash map (for quick lookup times). To make sure that this function works as expected, we add a test using a special-purpose test helper that was added for that purpose. Note: We expect the list of prefix items to be passed in as a list of pointers rather than as regular list to avoid having to copy information (the actual items will most likely contain more information than just the name and the length of the unique prefix, but passing in `struct prefix_item *` would not allow for that). Signed-off-by: Slavica Djukic Signed-off-by: Johannes Schindelin --- Makefile | 2 + prefix-map.c | 111 +++++++++++++++++++++++++++++++++++++ prefix-map.h | 40 +++++++++++++ t/helper/test-prefix-map.c | 58 +++++++++++++++++++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/t0016-prefix-map.sh | 10 ++++ 7 files changed, 223 insertions(+) create mode 100644 prefix-map.c create mode 100644 prefix-map.h create mode 100644 t/helper/test-prefix-map.c create mode 100755 t/t0016-prefix-map.sh diff --git a/Makefile b/Makefile index 18e656a32f..8299b3f17d 100644 --- a/Makefile +++ b/Makefile @@ -754,6 +754,7 @@ TEST_BUILTINS_OBJS += test-online-cpus.o TEST_BUILTINS_OBJS += test-parse-options.o TEST_BUILTINS_OBJS += test-path-utils.o TEST_BUILTINS_OBJS += test-pkt-line.o +TEST_BUILTINS_OBJS += test-prefix-map.o TEST_BUILTINS_OBJS += test-prio-queue.o TEST_BUILTINS_OBJS += test-reach.o TEST_BUILTINS_OBJS += test-read-cache.o @@ -967,6 +968,7 @@ LIB_OBJS += patch-ids.o LIB_OBJS += path.o LIB_OBJS += pathspec.o LIB_OBJS += pkt-line.o +LIB_OBJS += prefix-map.o LIB_OBJS += preload-index.o LIB_OBJS += pretty.o LIB_OBJS += prio-queue.o diff --git a/prefix-map.c b/prefix-map.c new file mode 100644 index 0000000000..3c5ae4ae0a --- /dev/null +++ b/prefix-map.c @@ -0,0 +1,111 @@ +#include "cache.h" +#include "prefix-map.h" + +static int map_cmp(const void *unused_cmp_data, + const void *entry, + const void *entry_or_key, + const void *unused_keydata) +{ + const struct prefix_map_entry *a = entry; + const struct prefix_map_entry *b = entry_or_key; + + return a->prefix_length != b->prefix_length || + strncmp(a->name, b->name, a->prefix_length); +} + +static void add_prefix_entry(struct hashmap *map, const char *name, + size_t prefix_length, struct prefix_item *item) +{ + struct prefix_map_entry *result = xmalloc(sizeof(*result)); + result->name = name; + result->prefix_length = prefix_length; + result->item = item; + hashmap_entry_init(result, memhash(name, prefix_length)); + hashmap_add(map, result); +} + +static void init_prefix_map(struct prefix_map *prefix_map, + int min_prefix_length, int max_prefix_length) +{ + hashmap_init(&prefix_map->map, map_cmp, NULL, 0); + prefix_map->min_length = min_prefix_length; + prefix_map->max_length = max_prefix_length; +} + +static void add_prefix_item(struct prefix_map *prefix_map, + struct prefix_item *item) +{ + struct prefix_map_entry *e = xmalloc(sizeof(*e)), *e2; + int j; + + e->item = item; + e->name = e->item->name; + + for (j = prefix_map->min_length; j <= prefix_map->max_length; j++) { + if (!isascii(e->name[j])) { + free(e); + break; + } + + e->prefix_length = j; + hashmap_entry_init(e, memhash(e->name, j)); + e2 = hashmap_get(&prefix_map->map, e, NULL); + if (!e2) { + /* prefix is unique so far */ + e->item->prefix_length = j; + hashmap_add(&prefix_map->map, e); + break; + } + + if (!e2->item) + continue; /* non-unique prefix */ + + if (j != e2->item->prefix_length) + BUG("unexpected prefix length: %d != %d", + (int)j, (int)e2->item->prefix_length); + + /* skip common prefix */ + for (; j < prefix_map->max_length && e->name[j]; j++) { + if (e->item->name[j] != e2->item->name[j]) + break; + add_prefix_entry(&prefix_map->map, e->name, j + 1, + NULL); + } + + /* e2 no longer refers to a unique prefix */ + if (j < prefix_map->max_length && e2->name[j]) { + /* found a new unique prefix for e2's item */ + e2->item->prefix_length = j + 1; + add_prefix_entry(&prefix_map->map, e2->name, j + 1, + e2->item); + } + else + e2->item->prefix_length = 0; + e2->item = NULL; + + if (j < prefix_map->max_length && e->name[j]) { + /* found a unique prefix for the item */ + e->item->prefix_length = j + 1; + add_prefix_entry(&prefix_map->map, e->name, j + 1, + e->item); + } else { + /* item has no (short enough) unique prefix */ + e->item->prefix_length = 0; + free(e); + } + + break; + } +} + +void find_unique_prefixes(struct prefix_item **list, size_t nr, + int min_length, int max_length) +{ + int i; + struct prefix_map prefix_map; + + init_prefix_map(&prefix_map, min_length, max_length); + for (i = 0; i < nr; i++) + add_prefix_item(&prefix_map, list[i]); + hashmap_free(&prefix_map.map, 1); +} diff --git a/prefix-map.h b/prefix-map.h new file mode 100644 index 0000000000..ce3b8a4a32 --- /dev/null +++ b/prefix-map.h @@ -0,0 +1,40 @@ +#ifndef PREFIX_MAP_H +#define PREFIX_MAP_H + +#include "hashmap.h" + +struct prefix_item { + const char *name; + size_t prefix_length; +}; + +struct prefix_map_entry { + struct hashmap_entry e; + const char *name; + size_t prefix_length; + /* if item is NULL, the prefix is not unique */ + struct prefix_item *item; +}; + +struct prefix_map { + struct hashmap map; + int min_length, max_length; +}; + +/* + * Find unique prefixes in a given list of strings. + * + * Typically, the `struct prefix_item` information will be but a field in the + * actual item struct; For this reason, the `list` parameter is specified as a + * list of pointers to the items. + * + * The `min_length`/`max_length` parameters define what length the unique + * prefixes should have. + * + * If no unique prefix could be found for a given item, its `prefix_length` + * will be set to 0. + */ +void find_unique_prefixes(struct prefix_item **list, size_t nr, + int min_length, int max_length); + +#endif diff --git a/t/helper/test-prefix-map.c b/t/helper/test-prefix-map.c new file mode 100644 index 0000000000..3f1c90eaf0 --- /dev/null +++ b/t/helper/test-prefix-map.c @@ -0,0 +1,58 @@ +#include "test-tool.h" +#include "cache.h" +#include "prefix-map.h" + +static size_t test_count, failed_count; + +static void check(int succeeded, const char *file, size_t line_no, + const char *fmt, ...) +{ + va_list ap; + + test_count++; + if (succeeded) + return; + + va_start(ap, fmt); + fprintf(stderr, "%s:%d: ", file, (int)line_no); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); + + failed_count++; +} + +#define EXPECT_SIZE_T_EQUALS(expect, actual, hint) \ + check(expect == actual, __FILE__, __LINE__, \ + "size_t's do not match: %" \ + PRIdMAX " != %" PRIdMAX " (%s) (%s)", \ + (intmax_t)expect, (intmax_t)actual, #actual, hint) + +int cmd__prefix_map(int argc, const char **argv) +{ +#define NR 5 + struct prefix_item items[NR] = { + { "unique" }, + { "hell" }, + { "hello" }, + { "wok" }, + { "world" }, + }; + struct prefix_item *list[NR] = { + items, items + 1, items + 2, items + 3, items + 4 + }; + + find_unique_prefixes(list, NR, 1, 3); + +#define EXPECT_PREFIX_LENGTH_EQUALS(expect, index) \ + EXPECT_SIZE_T_EQUALS(expect, list[index]->prefix_length, \ + list[index]->name) + + EXPECT_PREFIX_LENGTH_EQUALS(1, 0); + EXPECT_PREFIX_LENGTH_EQUALS(0, 1); + EXPECT_PREFIX_LENGTH_EQUALS(0, 2); + EXPECT_PREFIX_LENGTH_EQUALS(3, 3); + EXPECT_PREFIX_LENGTH_EQUALS(3, 4); + + return !!failed_count; +} diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 99db7409b8..d6a92a8699 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -32,6 +32,7 @@ static struct test_cmd cmds[] = { { "parse-options", cmd__parse_options }, { "path-utils", cmd__path_utils }, { "pkt-line", cmd__pkt_line }, + { "prefix-map", cmd__prefix_map }, { "prio-queue", cmd__prio_queue }, { "reach", cmd__reach }, { "read-cache", cmd__read_cache }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 25abed1cf2..33a089ee4e 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -29,6 +29,7 @@ int cmd__online_cpus(int argc, const char **argv); int cmd__parse_options(int argc, const char **argv); int cmd__path_utils(int argc, const char **argv); int cmd__pkt_line(int argc, const char **argv); +int cmd__prefix_map(int argc, const char **argv); int cmd__prio_queue(int argc, const char **argv); int cmd__reach(int argc, const char **argv); int cmd__read_cache(int argc, const char **argv); diff --git a/t/t0016-prefix-map.sh b/t/t0016-prefix-map.sh new file mode 100755 index 0000000000..187fa92aec --- /dev/null +++ b/t/t0016-prefix-map.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +test_description='basic tests for prefix map' +. ./test-lib.sh + +test_expect_success 'prefix map' ' + test-tool prefix-map +' + +test_done From patchwork Wed Apr 10 17:37:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894489 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 29E9F17E6 for ; Wed, 10 Apr 2019 17:38:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 065A728AE3 for ; Wed, 10 Apr 2019 17:38:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EEEAC28B0A; Wed, 10 Apr 2019 17:38:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6B7E128AE3 for ; Wed, 10 Apr 2019 17:38:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729729AbfDJRiD (ORCPT ); Wed, 10 Apr 2019 13:38:03 -0400 Received: from mail-ed1-f67.google.com ([209.85.208.67]:44899 "EHLO mail-ed1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729655AbfDJRh7 (ORCPT ); Wed, 10 Apr 2019 13:37:59 -0400 Received: by mail-ed1-f67.google.com with SMTP id d11so2763329edp.11 for ; Wed, 10 Apr 2019 10:37:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=pRNh/ztFrKB40bwoePW1Bf5Lnj9AMgB3ybTo5lQDG3k=; b=EZgyrUfr/x3vvRnr8V78N4BGlJ9r/WXABmdcPKcRL9EuSEib5PzO3C/NeFS83ZuI+G QLgeAQU/LwPBWbhA3JCsWlCKRHpvOFQgQGTijk16MV3uwdNVM95O2as6/AmBOrdMeA+W Zs+y8EnSufnbbyme3gqp7Qo5EOfUlvZz/quXTAvkyHgDA7qb6EdvIM7bHmTsAAakwh+f KdIs8jX+rxBB3HR9J0VBRPLBR18u3kmcII4mz0XJ2OCpuAATI4OqKLJyXn5d0j26L5qU VbOfP+bOF8cp0KnZXOURH3QgnOFbZmcRkonBR7wqTjkXnX64KkDvGcz+BgBaDVfV0OLj TbWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=pRNh/ztFrKB40bwoePW1Bf5Lnj9AMgB3ybTo5lQDG3k=; b=R0zVtBxd0VJcf4YBZ4fXlN92SZPSdPNSZhu8WbBmafTfQ4mRo8IUzG/Wl9D17VftPs V3EiKwS2AElDwFqbJTumZSY3freh1qRIy7epkplfHxDldDsIrC1CZdO6ohRQHUaP8YJe loWHaHdlo2heBijzDeLha4VtJeyILugJrGcu1XmdxQlQFvXmcA/z3hLW7W9F9quBW9uE fyfoBE1JBXEEEz4XvDcxFLdUHUxt8Jdh1+Eb2GnpGy5Kfd7pra7QIcz1AHGO60haN41Q KYT2y0eE3S54xT9TyGofEJgM/BdbZQDTuFytKrulJ2qpRK9W8mczm1xhI+f6dhCsRKjn 0vSw== X-Gm-Message-State: APjAAAVMh5d5FaM/B1I2H63CfxrUyk5XcgCaETv5moIuFfRiCKlF+EXh gYA6/GEo67v3uTy8nC3n1bZW7pUe X-Google-Smtp-Source: APXvYqxbpWgXpm1SnxDNqylp9GUn8M5T3Mwo4HdvyV6QPRSHLJjMwwaSlJg2sUkwcIiyzK9ZQI2DhA== X-Received: by 2002:a17:906:aece:: with SMTP id me14mr25301781ejb.0.1554917877318; Wed, 10 Apr 2019 10:37:57 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id r1sm1338490edx.12.2019.04.10.10.37.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:56 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:56 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:45 GMT Message-Id: <56acc31e962e5985c7ad2119b7e6d86f7647e786.1554917868.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Slavica Djukic via GitGitGadget" Subject: [PATCH 08/11] built-in add -i: show unique prefixes of the commands Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Slavica Djukic Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Slavica Djukic Just like in the Perl script `git-add--interactive.perl`, for each command a unique prefix is determined (if there exists any within the given parameters), and shown in the list, and accepted as a shortcut for the command. We use the prefix map implementation that we just added in the previous commit for that purpose. Signed-off-by: Slavica Djukic Signed-off-by: Johannes Schindelin --- add-interactive.c | 70 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index c8bd62369e..62ce446dd9 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -6,6 +6,7 @@ #include "diffcore.h" #include "revision.h" #include "refs.h" +#include "prefix-map.h" static int use_color = -1; @@ -53,18 +54,33 @@ int add_i_config(const char *var, const char *value, void *cb) return git_color_default_config(var, value, cb); } -struct item { - const char *name; -}; +static ssize_t find_unique(const char *string, + struct prefix_item **list, size_t nr) +{ + ssize_t found = -1, i; + + for (i = 0; i < nr; i++) { + struct prefix_item *item = list[i]; + if (!starts_with(item->name, string)) + continue; + if (found >= 0) + return -1; + found = i; + } + + return found; +} struct list_options { int columns; const char *header; - void (*print_item)(int i, struct item *item, void *print_item_data); + void (*print_item)(int i, struct prefix_item *item, + void *print_item_data); void *print_item_data; }; -static void list(struct item **list, size_t nr, struct list_options *opts) +static void list(struct prefix_item **list, size_t nr, + struct list_options *opts) { int i, last_lf = 0; @@ -101,12 +117,14 @@ struct list_and_choose_options { /* * Returns the selected index. */ -static ssize_t list_and_choose(struct item **items, size_t nr, +static ssize_t list_and_choose(struct prefix_item **items, size_t nr, struct list_and_choose_options *opts) { struct strbuf input = STRBUF_INIT; ssize_t res = -1; + find_unique_prefixes(items, nr, 1, 4); + for (;;) { char *p, *endp; @@ -146,6 +164,9 @@ static ssize_t list_and_choose(struct item **items, size_t nr, } p[sep] = '\0'; + if (index < 0) + index = find_unique(p, items, nr); + if (index < 0 || index >= nr) printf(_("Huh (%s)?\n"), p); else { @@ -171,7 +192,7 @@ struct adddel { struct file_list { struct file_item { - struct item item; + struct prefix_item item; struct adddel index, worktree; } **file; size_t nr, alloc; @@ -337,12 +358,29 @@ static void populate_wi_changes(struct strbuf *buf, strbuf_addstr(buf, no_changes); } +/* filters out prefixes which have special meaning to list_and_choose() */ +static int is_valid_prefix(const char *prefix, size_t prefix_len) +{ + return prefix_len && prefix && + /* + * We expect `prefix` to be NUL terminated, therefore this + * `strcspn()` call is okay, even if it might do much more + * work than strictly necessary. + */ + strcspn(prefix, " \t\r\n,") >= prefix_len && /* separators */ + *prefix != '-' && /* deselection */ + !isdigit(*prefix) && /* selection */ + (prefix_len != 1 || + (*prefix != '*' && /* "all" wildcard */ + *prefix != '?')); /* prompt help */ +} + struct print_file_item_data { const char *modified_fmt; struct strbuf buf, index, worktree; }; -static void print_file_item(int i, struct item *item, +static void print_file_item(int i, struct prefix_item *item, void *print_file_item_data) { struct file_item *c = (struct file_item *)item; @@ -369,20 +407,26 @@ static int run_status(struct repository *r, const struct pathspec *ps, return -1; if (files->nr) - list((struct item **)files->file, files->nr, opts); + list((struct prefix_item **)files->file, files->nr, opts); putchar('\n'); return 0; } -static void print_command_item(int i, struct item *item, +static void print_command_item(int i, struct prefix_item *item, void *print_command_item_data) { - printf(" %2d: %s", i + 1, item->name); + if (!item->prefix_length || + !is_valid_prefix(item->name, item->prefix_length)) + printf(" %2d: %s", i + 1, item->name); + else + printf(" %3d: [%.*s]%s", i + 1, + (int)item->prefix_length, item->name, + item->name + item->prefix_length); } struct command_item { - struct item item; + struct prefix_item item; int (*command)(struct repository *r, const struct pathspec *ps, struct file_list *files, struct list_options *opts); }; @@ -420,7 +464,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) res = -1; for (;;) { - i = list_and_choose((struct item **)commands, + i = list_and_choose((struct prefix_item **)commands, ARRAY_SIZE(commands), &main_loop_opts); if (i < -1) { printf(_("Bye.\n")); From patchwork Wed Apr 10 17:37:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894487 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6353817E1 for ; Wed, 10 Apr 2019 17:38:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 40B3B28AE3 for ; Wed, 10 Apr 2019 17:38:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 34D8028B0A; Wed, 10 Apr 2019 17:38:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CC7E228AE3 for ; Wed, 10 Apr 2019 17:38:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729721AbfDJRiD (ORCPT ); Wed, 10 Apr 2019 13:38:03 -0400 Received: from mail-ed1-f65.google.com ([209.85.208.65]:36906 "EHLO mail-ed1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729687AbfDJRiA (ORCPT ); Wed, 10 Apr 2019 13:38:00 -0400 Received: by mail-ed1-f65.google.com with SMTP id f53so1220394ede.4 for ; Wed, 10 Apr 2019 10:37:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=VGa1TGfOv9y6bEt+6hgkdmnHLmKqG/XMqv3vvT4xQNo=; b=V405BHSgWwN6mjn4KtVfnNcg2Z3IjWAZ4KgvAKe9vFBkMj1IztJoZKejSqffXYfAuw ofYGuKRs8rM6vuTSEsvjuDqMDPKEhpf+EhYdx5z+46Vn5OkAY+4A3DOhjUEl6nyaZloo daxUtDwmhrDpm6jx5IwtLy2jVHwf5Hx9tcMOwzxxqXf8fdeQ29SQpo26fF4qpkJ2edOM eX1U8vUR0MIEHZ/YMR7J3ii+ivThnF3enpW3wUQUQ6reKkreBvvrmp67E9Kc4EE6xiMj 5vrTX8CZJp6EZEzbJGFL6HSVrbvF/jRlptTX/nP/TeT9MdkUue894huzODxKcpFqs5IF ygbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=VGa1TGfOv9y6bEt+6hgkdmnHLmKqG/XMqv3vvT4xQNo=; b=tNfKahNzgFbIuBiapo21X/DaSYuap0mPUZFmBNHVW0fZefJu9+3rslQSABCMtIA9bI ki0tMP1MSSECssyybgGhLGpS463WMYhB28ZNZg1as1bL9EhQ+8+/AQYdoE6H0EETatMJ ToePvbUXz5mQjv3XbmBltnxhMh446oSym1qTzh4sAlkfDsUr4ybK5fire6bRVP2jvazJ XuPTikEW4pQcUFimx8o4qnsSY6nywU7v6ihbwrfsmW3QtK+mlUXbpxhji03sRGo/csVT knG7/YIVa94bQLKSB3fGxxUm6NSNUOSCKf9aTI51JV9zb7Z0eLzWhakz2sXkhV+UZV54 9zdQ== X-Gm-Message-State: APjAAAVu9c3Wm7ikx7Nl2lvm1Jmo/a4T5U8uk5JpyCEzbBRO9uegV97V wBT2L6hRllQZUsyx2uFsv5GfmZhw X-Google-Smtp-Source: APXvYqyYv7A55QtuLDK9UR9oDbXWD79MF1NZ8Daop0RkHSlQb+soLBISlcWuY4o3th4hX9DzpFeTng== X-Received: by 2002:a17:906:7010:: with SMTP id n16mr6660749ejj.271.1554917878208; Wed, 10 Apr 2019 10:37:58 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i26sm3921662ejc.51.2019.04.10.10.37.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:57 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:57 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:46 GMT Message-Id: In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Subject: [PATCH 09/11] built-in add -i: support `?` (prompt help) Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Johannes Schindelin With this change, we print out the same colored help text that the Perl-based `git add -i` prints in the main loop when question mark is entered. Signed-off-by: Johannes Schindelin --- add-interactive.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/add-interactive.c b/add-interactive.c index 62ce446dd9..03d0770013 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -12,10 +12,12 @@ static int use_color = -1; enum color_add_i { COLOR_HEADER = 0, + COLOR_HELP, }; static char list_colors[][COLOR_MAXLEN] = { GIT_COLOR_BOLD, /* Header */ + GIT_COLOR_BOLD_RED, /* Help */ }; static const char *get_add_i_color(enum color_add_i ix) @@ -29,6 +31,8 @@ static int parse_color_slot(const char *slot) { if (!strcasecmp(slot, "header")) return COLOR_HEADER; + if (!strcasecmp(slot, "help")) + return COLOR_HELP; return -1; } @@ -112,6 +116,7 @@ struct list_and_choose_options { struct list_options list_opts; const char *prompt; + void (*print_help)(void); }; /* @@ -145,6 +150,11 @@ static ssize_t list_and_choose(struct prefix_item **items, size_t nr, if (!input.len) break; + if (!strcmp(input.buf, "?")) { + opts->print_help(); + continue; + } + p = input.buf; for (;;) { size_t sep = strcspn(p, " \t\r\n,"); @@ -431,11 +441,23 @@ struct command_item { struct file_list *files, struct list_options *opts); }; +static void command_prompt_help(void) +{ + const char *help_color = get_add_i_color(COLOR_HELP); + color_fprintf_ln(stdout, help_color, "%s", _("Prompt help:")); + color_fprintf_ln(stdout, help_color, "1 - %s", + _("select a numbered item")); + color_fprintf_ln(stdout, help_color, "foo - %s", + _("select item based on unique prefix")); + color_fprintf_ln(stdout, help_color, " - %s", + _("(empty) select nothing")); +} + int run_add_i(struct repository *r, const struct pathspec *ps) { struct list_and_choose_options main_loop_opts = { { 4, N_("*** Commands ***"), print_command_item, NULL }, - N_("What now") + N_("What now"), command_prompt_help }; struct command_item status = { { "status" }, run_status }; From patchwork Wed Apr 10 17:37:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894493 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7B52D17E1 for ; Wed, 10 Apr 2019 17:38:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 58690288E8 for ; Wed, 10 Apr 2019 17:38:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4CC5F28AE7; Wed, 10 Apr 2019 17:38:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D73AB288E8 for ; Wed, 10 Apr 2019 17:38:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729719AbfDJRiC (ORCPT ); Wed, 10 Apr 2019 13:38:02 -0400 Received: from mail-ed1-f68.google.com ([209.85.208.68]:40541 "EHLO mail-ed1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729698AbfDJRiA (ORCPT ); Wed, 10 Apr 2019 13:38:00 -0400 Received: by mail-ed1-f68.google.com with SMTP id h22so2780313edw.7 for ; Wed, 10 Apr 2019 10:37:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=fdswRMC4oucqvXAVxi1kpHDZut5vtM+fkzoXOH31Fqo=; b=mlvLU/ge7jduDfQXm5O7WEwTcA47mdCbGjZPaI1Vi2Td7L5KuLZgnJFIOb/HTcoxcG hX6uHRu4FjKVBsM6xp61PuXcMEbLmrFXf4WCTNbBndtNc+6NXGuaryGPLAjCyD2QR4b/ VFz/jnwDt3WKHla1CMslEqX7+luIcff09g453YbopmascjvCyZjNhAOAnHCNIyhdB1Cs H2kjYUCuv1SbqrtPp0/SCBEbAacBtSWh2jKHSIHVAHMSvCNqHODrwtiSOWPu+6jsvor9 kLdzj91DvAPni2D9HMZzk2wFrpAzYItGlydU+upQstXBlC7Mi2UWGNAlVFnXFvhX8RKM 1P3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=fdswRMC4oucqvXAVxi1kpHDZut5vtM+fkzoXOH31Fqo=; b=EM5Ipfhhc4RGrGl2R0oa3VUQiprKu76pwyiaUMNHmtGOfMTsQprEQp7PuyxtAsbIEh CSpuwGgMsL6h0Pqz7haiva7R1PExsJM96ATPbQF93/YQ4VGF0EKezLmKg10i8giBzBTo 8jI7D5bq/+GMhi18FEMxz4FLn0vNLxMl4MMmxfJRJZSJtuCd6ypt5OgxWtIY+owN88Iu BoxBMQ2VLfiNa78O/EPqdUDuvtoHQoVFL1lnwxIi5X67YR5fewtIP8vGS3ZWyvwPAAgi rLjz9qeiGhrOX8GrVmOD6BAOd7W1u2VIHATTACP8y812DUwull2IfwjbzUPt7+g04aNw FphA== X-Gm-Message-State: APjAAAXbgI+4Us6dFMVr6Zem7EpIVjQ4ZTKyRuQcvcIMBCeVGUCIou7W l9duWgkAG3kSwgTJetWNHsKo+AOx X-Google-Smtp-Source: APXvYqyga0cH9fOm4JEYWpGEyVrbQt9ZfUCKI76f3QOUKHbiBvSdn6x9+Y2mPw980+mdyziEu8z3MQ== X-Received: by 2002:a50:9ea5:: with SMTP id a34mr16019660edf.191.1554917879027; Wed, 10 Apr 2019 10:37:59 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id p16sm10460866eds.61.2019.04.10.10.37.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:58 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:58 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:47 GMT Message-Id: <3e1a88d9c038818fb0d53483e6d9c569d687b38e.1554917868.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Slavica Djukic via GitGitGadget" Subject: [PATCH 10/11] built-in add -i: use color in the main loop Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Slavica Djukic Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Slavica Djukic The error messages as well as the unique prefixes are colored in `git add -i` by default; We need to do the same in the built-in version. Signed-off-by: Slavica Djukic Signed-off-by: Johannes Schindelin --- add-interactive.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index 03d0770013..a1550d9b9f 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -13,11 +13,17 @@ static int use_color = -1; enum color_add_i { COLOR_HEADER = 0, COLOR_HELP, + COLOR_PROMPT, + COLOR_ERROR, + COLOR_RESET, }; static char list_colors[][COLOR_MAXLEN] = { GIT_COLOR_BOLD, /* Header */ GIT_COLOR_BOLD_RED, /* Help */ + GIT_COLOR_BOLD_BLUE, /* Prompt */ + GIT_COLOR_BOLD_RED, /* Error */ + GIT_COLOR_RESET, /* Reset */ }; static const char *get_add_i_color(enum color_add_i ix) @@ -33,6 +39,12 @@ static int parse_color_slot(const char *slot) return COLOR_HEADER; if (!strcasecmp(slot, "help")) return COLOR_HELP; + if (!strcasecmp(slot, "prompt")) + return COLOR_PROMPT; + if (!strcasecmp(slot, "error")) + return COLOR_ERROR; + if (!strcasecmp(slot, "reset")) + return COLOR_RESET; return -1; } @@ -125,6 +137,8 @@ struct list_and_choose_options { static ssize_t list_and_choose(struct prefix_item **items, size_t nr, struct list_and_choose_options *opts) { + const char *prompt_color = get_add_i_color(COLOR_PROMPT); + const char *error_color = get_add_i_color(COLOR_ERROR); struct strbuf input = STRBUF_INIT; ssize_t res = -1; @@ -137,7 +151,8 @@ static ssize_t list_and_choose(struct prefix_item **items, size_t nr, list(items, nr, &opts->list_opts); - printf("%s%s", opts->prompt, "> "); + color_fprintf(stdout, prompt_color, "%s", opts->prompt); + fputs("> ", stdout); fflush(stdout); if (strbuf_getline(&input, stdin) == EOF) { @@ -178,7 +193,8 @@ static ssize_t list_and_choose(struct prefix_item **items, size_t nr, index = find_unique(p, items, nr); if (index < 0 || index >= nr) - printf(_("Huh (%s)?\n"), p); + color_fprintf_ln(stdout, error_color, + _("Huh (%s)?"), p); else { res = index; break; @@ -423,15 +439,21 @@ static int run_status(struct repository *r, const struct pathspec *ps, return 0; } +struct print_command_item_data { + const char *color, *reset; +}; + static void print_command_item(int i, struct prefix_item *item, void *print_command_item_data) { + struct print_command_item_data *d = print_command_item_data; + if (!item->prefix_length || !is_valid_prefix(item->name, item->prefix_length)) printf(" %2d: %s", i + 1, item->name); else - printf(" %3d: [%.*s]%s", i + 1, - (int)item->prefix_length, item->name, + printf(" %2d: %s%.*s%s%s", i + 1, + d->color, (int)item->prefix_length, item->name, d->reset, item->name + item->prefix_length); } @@ -455,8 +477,16 @@ static void command_prompt_help(void) int run_add_i(struct repository *r, const struct pathspec *ps) { + struct print_command_item_data data = { + /* + * When color was asked for, use the prompt color for + * highlighting, otherwise use square brackets. + */ + want_color(use_color) ? get_add_i_color(COLOR_PROMPT) : "[", + want_color(use_color) ? get_add_i_color(COLOR_RESET) : "]" + }; struct list_and_choose_options main_loop_opts = { - { 4, N_("*** Commands ***"), print_command_item, NULL }, + { 4, N_("*** Commands ***"), print_command_item, &data }, N_("What now"), command_prompt_help }; struct command_item From patchwork Wed Apr 10 17:37:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Arver via GitGitGadget X-Patchwork-Id: 10894495 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E4D9917E6 for ; Wed, 10 Apr 2019 17:38:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C2165288E8 for ; Wed, 10 Apr 2019 17:38:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B6B8628AE7; Wed, 10 Apr 2019 17:38:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2D9C3288E8 for ; Wed, 10 Apr 2019 17:38:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729735AbfDJRiI (ORCPT ); Wed, 10 Apr 2019 13:38:08 -0400 Received: from mail-ed1-f65.google.com ([209.85.208.65]:36664 "EHLO mail-ed1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729660AbfDJRiC (ORCPT ); Wed, 10 Apr 2019 13:38:02 -0400 Received: by mail-ed1-f65.google.com with SMTP id u57so2151679edm.3 for ; Wed, 10 Apr 2019 10:38:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:message-id:in-reply-to:references:from:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=DtjJwGlqWAmz2GQrgZaQ3BoKO9TUM2pqgcQ4qFfHgU4=; b=TBwa9gUOF6LtDyXhhUqekuxVI0vlf2EK39KcXPJX+qhFwdT8kDRkY9BX/DRUodjKqv JmaUgwbAUn8fd8GIdL73qyxl4nLAdY2mApHTZGI0Jz3AiuUQJTFoVrXP0iioWNHyM0/h lNgsZcvOLzfJ17RQuPRzaltRpyHThLueuTrpY+RXelxuEQ2WBHUJ8zQS4VltuQ0O8+2s VtQctEPU4kW0YotmyrUQhTUcei7E5gtzuOD7Q0i3Q9TH18b7uIzJWFJrV5knwhyKTVnE brxHFyll8Ac43jtHe6cMC1/8L7scKWvOXrWCRluKNTNXdCXr3O9t78qdsmo6Pyp7BAZ4 uY3Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:in-reply-to:references:from :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=DtjJwGlqWAmz2GQrgZaQ3BoKO9TUM2pqgcQ4qFfHgU4=; b=HopR/4VpikEMNNGcyUe2mi0uyxzJEQzjFfrl9R/TlSgD1nNbCygqnBJUJA33DZI1e6 jswFIdPlN6pQHkLeYq7inWl3+VvFT+bZsDX9Jd8SW86ErzgVRR/Lh6l7KVvAIG7lzwuc +cKIpA2PUFvL3v7bo/RFDHmNIvIDBjwaeNe3m2AJmccx0t7Yk9e2eOJhi1NVvvRqgfE3 4uwW5DGJOEtVv9xVZ8mfdU/wUROoPxjWNTN935MLpQUVUoUI13w9l9D3i2U2YQXA3acu kCQAXWoIVRFuswnAQ9l+TCKWs84QZ8q/hJcEbxkKrRmZLkanLFZwtzru1sH8TVrStI7z BsdA== X-Gm-Message-State: APjAAAWotI04X7WYRrKVc/CGWFmJEeWT1IG7vZiDxi9bK/Rsmx6niH/L c7MIot1DIG2fftpduFBjJGsaxKOT X-Google-Smtp-Source: APXvYqy4AHajVaCAemCWpsc2xUT22FnPeunQAtq4meIJtO/0MYrho6pLVMMOZ6nX6OlF9fNJs6BHkA== X-Received: by 2002:a17:906:4c45:: with SMTP id d5mr4623296ejw.133.1554917879868; Wed, 10 Apr 2019 10:37:59 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 10sm1119144ejn.37.2019.04.10.10.37.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 10:37:59 -0700 (PDT) Date: Wed, 10 Apr 2019 10:37:59 -0700 (PDT) X-Google-Original-Date: Wed, 10 Apr 2019 17:37:48 GMT Message-Id: <481e3316d5a2486dbfef32fca9e096a8eb9a64ee.1554917868.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Subject: [PATCH 11/11] built-in add -i: implement the `help` command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Johannes Schindelin This imitates the code to show the help text from the Perl script `git-add--interactive.perl` in the built-in version. To make sure that it renders exactly like the Perl version of `git add -i`, we also add a test case for that to `t3701-add-interactive.sh`. Signed-off-by: Slavica Djukic Signed-off-by: Johannes Schindelin --- add-interactive.c | 27 +++++++++++++++++++++++++-- t/t3701-add-interactive.sh | 24 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index a1550d9b9f..a6baf57e20 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -439,6 +439,27 @@ static int run_status(struct repository *r, const struct pathspec *ps, return 0; } +static int run_help(struct repository *r, const struct pathspec *ps, + struct file_list *files, struct list_options *opts) +{ + const char *help_color = get_add_i_color(COLOR_HELP); + + color_fprintf_ln(stdout, help_color, "status - %s", + _("show paths with changes")); + color_fprintf_ln(stdout, help_color, "update - %s", + _("add working tree state to the staged set of changes")); + color_fprintf_ln(stdout, help_color, "revert - %s", + _("revert staged set of changes back to the HEAD version")); + color_fprintf_ln(stdout, help_color, "patch - %s", + _("pick hunks and update selectively")); + color_fprintf_ln(stdout, help_color, "diff - %s", + _("view diff between HEAD and index")); + color_fprintf_ln(stdout, help_color, "add untracked - %s", + _("add contents of untracked files to the staged set of changes")); + + return 0; +} + struct print_command_item_data { const char *color, *reset; }; @@ -490,9 +511,11 @@ int run_add_i(struct repository *r, const struct pathspec *ps) N_("What now"), command_prompt_help }; struct command_item - status = { { "status" }, run_status }; + status = { { "status" }, run_status }, + help = { { "help" }, run_help }; struct command_item *commands[] = { - &status + &status, + &help }; struct print_file_item_data print_file_item_data = { diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 65dfbc033a..91aaef2932 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -639,4 +639,28 @@ test_expect_success 'add -p patch editing works with pathological context lines' test_cmp expected-2 actual ' +test_expect_success 'show help from add--helper' ' + git reset --hard && + cat >expect <<-EOF && + + *** Commands *** + 1: status 2: update 3: revert 4: add untracked + 5: patch 6: diff 7: quit 8: help + What now> status - show paths with changes + update - add working tree state to the staged set of changes + revert - revert staged set of changes back to the HEAD version + patch - pick hunks and update selectively + diff - view diff between HEAD and index + add untracked - add contents of untracked files to the staged set of changes + *** Commands *** + 1: status 2: update 3: revert 4: add untracked + 5: patch 6: diff 7: quit 8: help + What now>$SP + Bye. + EOF + test_write_lines h | GIT_PAGER_IN_USE=true TERM=vt100 git add -i >actual.colored && + test_decode_color actual && + test_i18ncmp expect actual +' + test_done