From patchwork Fri Nov 29 21:11:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11267601 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E771517E0 for ; Fri, 29 Nov 2019 21:11:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C3432217BA for ; Fri, 29 Nov 2019 21:11:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="c4q4nhgW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727184AbfK2VLy (ORCPT ); Fri, 29 Nov 2019 16:11:54 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:44700 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727166AbfK2VLx (ORCPT ); Fri, 29 Nov 2019 16:11:53 -0500 Received: by mail-wr1-f66.google.com with SMTP id q10so520428wrm.11 for ; Fri, 29 Nov 2019 13:11:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=Cr1NQtKfgGkbYNQal4RtVYegfd0J2myrq2tipAyCtKs=; b=c4q4nhgWJjOTZrJwK4rsVs5cdQKG2XrtHImejrURVvl/GlcFw4oNiTLP7JAPsKiy8U Jt78apaBjaoMwnTXbgNb704KlCySstp+gfcopKIwUBsJw/SBj2SvGgwUC3BQKH57YDgR nTwvwMorZ70X9uq6s7QS8LNkSyUuGp9ttGKq3VswZL9C3rCj9B3zzy7y3Fs8zHseeT3j 7cVZ676d0iaZfqRH6Og393uvT7mJFeIufiMqivx99OO/fIVTghoLyrPKubWge97qqKZW gwOn5EbPj6uOIr31UFbbKlyi4UJ+NJg8uaLxKY6zRrDukxBD3zhlgMRQjIS61Id7sVD8 zTqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=Cr1NQtKfgGkbYNQal4RtVYegfd0J2myrq2tipAyCtKs=; b=REBSGOBeXJ9+nLacZIqOGOiQ5G8XRAvE6Qy2DO6QrG9dshggX2mVPXoUktOJzzAl7F QF5tigrChTRZ7+yNnDZweiuNiNIIKgJvy/v2ygMic/unDWkkCFbiqVKfkm7V6yZdEJEy +h9PbgpMHQ4ujxfjldHC3ioyQSFK6VJzrcaGEG1oIEdrRiXTp7E9XEt03coYAmTmqIK/ 1h/NHrPIqVm/mdci3oxuxvtGk+N0BqESGdodtB9rgG5LrAvZioMpEHW/ls0WuYygQliT s2fhJzSpLAeDfTmbvGS72ZApHaqywJVesdrqDuUumB0wK36zVB004FE+oP3RHvxQftvo PYWA== X-Gm-Message-State: APjAAAXlYsqSYDvZlt7nBIuLK7kOqQRtumkQiZsgXU5wccognAzVe4JI OCgmsz1qwZUauG86hfOe7wtCcehh X-Google-Smtp-Source: APXvYqxWTUyp8wrnaqyZgA6NXW9JVZMgKqXyfYVOBGIH234sdRqKnGxewxSRNEhAGIgXS+oiw6JzUQ== X-Received: by 2002:adf:db86:: with SMTP id u6mr59407929wri.318.1575061911749; Fri, 29 Nov 2019 13:11:51 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id b186sm14262927wmb.21.2019.11.29.13.11.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 29 Nov 2019 13:11:51 -0800 (PST) Message-Id: <1e02bf2d63e99a6416238999b646998af960bc4b.1575061909.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 29 Nov 2019 21:11:41 +0000 Subject: [PATCH v2 1/9] add-interactive: make sure to release `rev.prune_data` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin During a review, Junio Hamano pointed out that the `rev.prune_data` was copied from another pathspec but never cleaned up. Signed-off-by: Johannes Schindelin --- add-interactive.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/add-interactive.c b/add-interactive.c index d6cb98cd40..de2fccb0ef 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -435,6 +435,9 @@ static int get_modified_files(struct repository *r, struct string_list *files, rev.diffopt.flags.ignore_dirty_submodules = 1; run_diff_files(&rev, 0); } + + if (ps) + clear_pathspec(&rev.prune_data); } hashmap_free_entries(&s.file_map, struct pathname_entry, ent); From patchwork Fri Nov 15 12:36:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11246297 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D8CC76C1 for ; Fri, 15 Nov 2019 12:36:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B0FC02073C for ; Fri, 15 Nov 2019 12:36:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GCH5qui2" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727630AbfKOMg3 (ORCPT ); Fri, 15 Nov 2019 07:36:29 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:37322 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727614AbfKOMg2 (ORCPT ); Fri, 15 Nov 2019 07:36:28 -0500 Received: by mail-wr1-f65.google.com with SMTP id t1so10826925wrv.4 for ; Fri, 15 Nov 2019 04:36:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=XPb3MLdgwnEvsfcxAQOGY8ntP8rXuAYYjibPqJjc+u0=; b=GCH5qui2Qrrvtx8fJCmMfbWcijmnuv7dWjnN0ZMIMRgtGgLyH1c/dm5PYctZ5p4tSt 6l3J1QpUup3TUsxeI+53t+UN/QPxdrIyJ0nJ6ivRbyVKIAss1D4FIgztDgeUG7u3qDsh scdsGHKqbRfQuIdoWkCBk8BoLmXkXFeyb3tvzgPqYvqY6Jd5Hp4VPSt26ZdLC7PefsoL OUnP+dVh4yXU4fyQ83qzxWbhTuwFUuYXpdLZwvPA4QKhB2/2UM/CTjUcAK1zKQSCuNv0 3DY1/LEucX+qXMT+VAAFotd6B9XlfEv6D1qClQRjxxXmW4F0RIXKPmlNWeRgoc/lNzxN U5mA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=XPb3MLdgwnEvsfcxAQOGY8ntP8rXuAYYjibPqJjc+u0=; b=ddsLPg8JxQaI3jluo7Q+V6uO8+PMUC1NOBXmJGTaBS8kD2xLVadxxzN7B0/MEOBn7O KqNA3mS6oFikUFOoMmwK1DEMoP5sRmHMEBSwb+bOiu0VLJQoUuSeA/c3CPFWsnCezpIu JOHYxPduodZb3YVoIwi3wpMXhpkbeGNqEpRi1elI3MEg2LBgTGu0T1akAAmY/0weZVUa Z+Up9z++y1Sk/IIdZCQ4BcQ0ozSkQFfqW3u4ucdtcdXTvU0pzkG7lPxbayyj5U0MZp2g lVftVk/6rcnRwOe2pQOp5sQd4+wTZjlTrApv5CcQT0I2KcXPZ3bNRN4MhUWfdE207N86 Q4IA== X-Gm-Message-State: APjAAAWMyw3KMkvtm3qd3weAh7uuRfOySMkGgcQIYCO2WgDkvGFYfAPf PNnqU3yYDG/12w1b8o3+0FVJgng+ X-Google-Smtp-Source: APXvYqxFhqFHs99dDDxBPqqiYrMnmnhAuCtF3rnbe8opQNY4o27/cPfEoc14PyXH9OjkHRTcLLL9YA== X-Received: by 2002:a5d:5411:: with SMTP id g17mr14634887wrv.360.1573821384946; Fri, 15 Nov 2019 04:36:24 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z14sm10959630wrl.60.2019.11.15.04.36.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Nov 2019 04:36:24 -0800 (PST) Message-Id: In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 15 Nov 2019 12:36:16 +0000 Subject: [PATCH 2/8] built-in add -i: prepare for multi-selection commands Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin The `upgrade`, `revert` and `add-untracked` commands allow selecting multiple entries. Let's extend the `list_and_choose()` function to accommodate those use cases. Signed-off-by: Johannes Schindelin --- add-interactive.c | 114 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 25 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index 8ec930ac15..33a751150a 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -72,15 +72,17 @@ static void init_add_i_state(struct add_i_state *s, struct repository *r) struct prefix_item_list { struct string_list items; struct string_list sorted; + int *selected; /* for multi-selections */ size_t min_length, max_length; }; #define PREFIX_ITEM_LIST_INIT \ - { STRING_LIST_INIT_DUP, STRING_LIST_INIT_NODUP, 1, 4 } + { STRING_LIST_INIT_DUP, STRING_LIST_INIT_NODUP, NULL, 1, 4 } static void prefix_item_list_clear(struct prefix_item_list *list) { string_list_clear(&list->items, 1); string_list_clear(&list->sorted, 0); + FREE_AND_NULL(list->selected); } static void extend_prefix_length(struct string_list_item *p, @@ -182,11 +184,12 @@ static ssize_t find_unique(const char *string, struct prefix_item_list *list) struct list_options { int columns; const char *header; - void (*print_item)(int i, struct string_list_item *item, void *print_item_data); + void (*print_item)(int i, int selected, struct string_list_item *item, + void *print_item_data); void *print_item_data; }; -static void list(struct add_i_state *s, struct string_list *list, +static void list(struct add_i_state *s, struct string_list *list, int *selected, struct list_options *opts) { int i, last_lf = 0; @@ -199,7 +202,8 @@ static void list(struct add_i_state *s, struct string_list *list, "%s", opts->header); for (i = 0; i < list->nr; i++) { - opts->print_item(i, list->items + i, opts->print_item_data); + opts->print_item(i, selected ? selected[i] : 0, list->items + i, + opts->print_item_data); if ((opts->columns) && ((i + 1) % (opts->columns))) { putchar('\t'); @@ -218,6 +222,10 @@ struct list_and_choose_options { struct list_options list_opts; const char *prompt; + enum { + SINGLETON = (1<<0), + IMMEDIATE = (1<<1), + } flags; void (*print_help)(struct add_i_state *s); }; @@ -225,7 +233,8 @@ struct list_and_choose_options { #define LIST_AND_CHOOSE_QUIT (-2) /* - * Returns the selected index. + * Returns the selected index in singleton mode, the number of selected items + * otherwise. * * If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF, * `LIST_AND_CHOOSE_QUIT` is returned. @@ -234,8 +243,19 @@ static ssize_t list_and_choose(struct add_i_state *s, struct prefix_item_list *items, struct list_and_choose_options *opts) { + int singleton = opts->flags & SINGLETON; + int immediate = opts->flags & IMMEDIATE; + struct strbuf input = STRBUF_INIT; - ssize_t res = LIST_AND_CHOOSE_ERROR; + ssize_t res = singleton ? LIST_AND_CHOOSE_ERROR : 0; + + if (!singleton) { + free(items->selected); + CALLOC_ARRAY(items->selected, items->items.nr); + } + + if (singleton && !immediate) + BUG("singleton requires immediate"); find_unique_prefixes(items); @@ -244,15 +264,16 @@ static ssize_t list_and_choose(struct add_i_state *s, strbuf_reset(&input); - list(s, &items->items, &opts->list_opts); + list(s, &items->items, items->selected, &opts->list_opts); color_fprintf(stdout, s->prompt_color, "%s", opts->prompt); - fputs("> ", stdout); + fputs(singleton ? "> " : ">> ", stdout); fflush(stdout); if (strbuf_getline(&input, stdin) == EOF) { putchar('\n'); - res = LIST_AND_CHOOSE_QUIT; + if (immediate) + res = LIST_AND_CHOOSE_QUIT; break; } strbuf_trim(&input); @@ -268,7 +289,9 @@ static ssize_t list_and_choose(struct add_i_state *s, p = input.buf; for (;;) { size_t sep = strcspn(p, " \t\r\n,"); - ssize_t index = -1; + int choose = 1; + /* `from` is inclusive, `to` is exclusive */ + ssize_t from = -1, to = -1; if (!sep) { if (!*p) @@ -277,29 +300,69 @@ static ssize_t list_and_choose(struct add_i_state *s, continue; } - if (isdigit(*p)) { + /* Input that begins with '-'; de-select */ + if (*p == '-') { + choose = 0; + p++; + sep--; + } + + if (sep == 1 && *p == '*') { + from = 0; + to = items->items.nr; + } else if (isdigit(*p)) { char *endp; - index = strtoul(p, &endp, 10) - 1; - if (endp != p + sep) - index = -1; + /* + * A range can be specified like 5-7 or 5-. + * + * Note: `from` is 0-based while the user input + * is 1-based, hence we have to decrement by + * one. We do not have to decrement `to` even + * if it is 0-based because it is an exclusive + * boundary. + */ + from = strtoul(p, &endp, 10) - 1; + if (endp == p + sep) + to = from + 1; + else if (*endp == '-') { + to = strtoul(++endp, &endp, 10); + /* extra characters after the range? */ + if (endp != p + sep) + from = -1; + } } p[sep] = '\0'; - if (index < 0) - index = find_unique(p, items); + if (from < 0) { + from = find_unique(p, items); + if (from >= 0) + to = from + 1; + } - if (index < 0 || index >= items->items.nr) + if (from < 0 || from >= items->items.nr || + (singleton && from + 1 != to)) { color_fprintf_ln(stdout, s->error_color, _("Huh (%s)?"), p); - else { - res = index; + break; + } else if (singleton) { + res = from; break; } + if (to > items->items.nr) + to = items->items.nr; + + for (; from < to; from++) + if (items->selected[from] != choose) { + items->selected[from] = choose; + res += choose ? +1 : -1; + } + p += sep + 1; } - if (res != LIST_AND_CHOOSE_ERROR) + if ((immediate && res != LIST_AND_CHOOSE_ERROR) || + !strcmp(input.buf, "*")) break; } @@ -496,7 +559,7 @@ struct print_file_item_data { struct strbuf buf, index, worktree; }; -static void print_file_item(int i, struct string_list_item *item, +static void print_file_item(int i, int selected, struct string_list_item *item, void *print_file_item_data) { struct file_item *c = item->util; @@ -511,7 +574,7 @@ static void print_file_item(int i, struct string_list_item *item, strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf, item->string); - printf(" %2d: %s", i + 1, d->buf.buf); + printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf); } static int run_status(struct add_i_state *s, const struct pathspec *ps, @@ -520,7 +583,7 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps, if (get_modified_files(s->r, NO_FILTER, files, ps) < 0) return -1; - list(s, files, opts); + list(s, files, NULL, opts); putchar('\n'); return 0; @@ -559,7 +622,8 @@ struct print_command_item_data { const char *color, *reset; }; -static void print_command_item(int i, struct string_list_item *item, +static void print_command_item(int i, int selected, + struct string_list_item *item, void *print_command_item_data) { struct print_command_item_data *d = print_command_item_data; @@ -592,7 +656,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) struct print_command_item_data data = { "[", "]" }; struct list_and_choose_options main_loop_opts = { { 4, N_("*** Commands ***"), print_command_item, &data }, - N_("What now"), command_prompt_help + N_("What now"), SINGLETON | IMMEDIATE, command_prompt_help }; struct { const char *string; From patchwork Fri Nov 15 12:36:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11246285 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 01E296C1 for ; Fri, 15 Nov 2019 12:36:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C5C0A2073C for ; Fri, 15 Nov 2019 12:36:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pDLWP7jK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727632AbfKOMga (ORCPT ); Fri, 15 Nov 2019 07:36:30 -0500 Received: from mail-wm1-f67.google.com ([209.85.128.67]:40350 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727442AbfKOMg2 (ORCPT ); Fri, 15 Nov 2019 07:36:28 -0500 Received: by mail-wm1-f67.google.com with SMTP id f3so10220227wmc.5 for ; Fri, 15 Nov 2019 04:36:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=VPbAcpL2CY0Y5pC2arNgvPDbxKGEVP64d1UGElFoqBA=; b=pDLWP7jKKF4KBf7rFuimHWqra9mRPClzA2bs8dbDxQa9xlX1UUD7K63mmqjSijqBlm RbznqP88LVedX3BwW60YhifDG99wAzA+7RtZj4vpCzy2+ZOv3mgXQt33aLgUHOfGPEVX jBiieOoKxoc8u9gBmOAM7z7mSnom5vm1mTM/BuDn81xMrHdYqOC6j/mVI+Lvsf2STAzE 2mNsbbmHV4HBOx2x60fM1kfaACX2JFMCwqLRcwgnYYbUAYN/NcsrT3Vt9jPpKDOtgQvA mxByHBv7FHDKhi/5opnGUqsu/6BtfIB93NA2XV0HOhpRMmWAcdCP/ASYdt+pR1oxVMEE hFew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=VPbAcpL2CY0Y5pC2arNgvPDbxKGEVP64d1UGElFoqBA=; b=oKHmRBG6CslKCs0Sx8C5ksE6WHGVL6h0HTUngH6ttqHXhhACT8OLMiZtrYg+UgQaTi 0z3We0hSHYz2Dltb84yTfQQfNqmzL3RV6Aq3pxMEyTaYjKbJ8kyhJyDszfSTrHTssxGx XuN6H0F8ao93cHamuzbyj+Ri5Gsg7J6+JTplPuBBm4PYiZ0/7K9yxliJ6yKBGQSJt3AC EfBWjPfpN404xUfMhA5cwNrUFuL6wAYwal6vdtzDXxZuUegMfID5g/bnvIamqQTz7t5Z QfPnoOiRis75i+Qd/2ybHcmFshp0bL6xBoXVjxlUKGjhRoChrr0AITCR4fMjxOic54sS pnWQ== X-Gm-Message-State: APjAAAW0Bnc+bovn2l+6Y9hnE0I41pWHvPMZFFQPl9832AvA7EKKoLgD 8sHUnLNomP8Xhh4p3IB0roRGdeqK X-Google-Smtp-Source: APXvYqwGq0d/f3d6J7He1oZGgaFcJ8HZvaJZ5h4RRpOlmiS6yE/BIf0+qm0xIRmbDzaC5F6G+4Pw0g== X-Received: by 2002:a7b:cd0f:: with SMTP id f15mr2676846wmj.127.1573821385590; Fri, 15 Nov 2019 04:36:25 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 76sm10446529wma.0.2019.11.15.04.36.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Nov 2019 04:36:25 -0800 (PST) Message-Id: In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 15 Nov 2019 12:36:17 +0000 Subject: [PATCH 3/8] built-in add -i: implement the `update` command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin After `status` and `help`, it is now time to port the `update` command to C, the second command that is shown in the main loop menu of `git add -i`. This `git add -i` command is the first one which lets the user choose a subset of a list of files, and as such, this patch lays the groundwork for the other commands of that category: - It teaches the `print_file_item()` function to show a unique prefix if we found any (the code to find it had been added already in the previous patch where we colored the unique prefixes of the main loop commands, but that patch uses the `print_command_item()` function to display the menu items). - This patch also adds the help text that is shown when the user input to select items from the shown list could not be parsed. - As `get_modified_files()` clears the list of files, it now has to take care of clearing the _full_ `prefix_item_list` lest the `sorted` and `selected` fields go stale and inconsistent. Signed-off-by: Johannes Schindelin --- add-interactive.c | 130 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 110 insertions(+), 20 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index 33a751150a..b0bda0cd2d 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -6,6 +6,7 @@ #include "revision.h" #include "refs.h" #include "string-list.h" +#include "lockfile.h" struct add_i_state { struct repository *r; @@ -376,6 +377,7 @@ struct adddel { }; struct file_item { + size_t prefix_length; struct adddel index, worktree; }; @@ -470,7 +472,7 @@ enum modified_files_filter { static int get_modified_files(struct repository *r, enum modified_files_filter filter, - struct string_list *files, + struct prefix_item_list *files, const struct pathspec *ps) { struct object_id head_oid; @@ -483,8 +485,8 @@ static int get_modified_files(struct repository *r, repo_read_index_preload(r, ps, 0) < 0) return error(_("could not read index")); - string_list_clear(files, 1); - s.files = files; + prefix_item_list_clear(files); + s.files = &files->items; hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0); for (i = 0; i < 2; i++) { @@ -520,7 +522,7 @@ static int get_modified_files(struct repository *r, hashmap_free_entries(&s.file_map, struct pathname_entry, ent); /* While the diffs are ordered already, we ran *two* diffs... */ - string_list_sort(files); + string_list_sort(&files->items); return 0; } @@ -555,8 +557,8 @@ static int is_valid_prefix(const char *prefix, size_t prefix_len) } struct print_file_item_data { - const char *modified_fmt; - struct strbuf buf, index, worktree; + const char *modified_fmt, *color, *reset; + struct strbuf buf, name, index, worktree; }; static void print_file_item(int i, int selected, struct string_list_item *item, @@ -564,34 +566,96 @@ static void print_file_item(int i, int selected, struct string_list_item *item, { struct file_item *c = item->util; struct print_file_item_data *d = print_file_item_data; + const char *highlighted = NULL; strbuf_reset(&d->index); strbuf_reset(&d->worktree); strbuf_reset(&d->buf); + /* Format the item with the prefix highlighted. */ + if (c->prefix_length > 0 && + is_valid_prefix(item->string, c->prefix_length)) { + strbuf_reset(&d->name); + strbuf_addf(&d->name, "%s%.*s%s%s", d->color, + (int)c->prefix_length, item->string, d->reset, + item->string + c->prefix_length); + highlighted = d->name.buf; + } + render_adddel(&d->worktree, &c->worktree, _("nothing")); render_adddel(&d->index, &c->index, _("unchanged")); - strbuf_addf(&d->buf, d->modified_fmt, - d->index.buf, d->worktree.buf, item->string); + + strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf, + highlighted ? highlighted : item->string); printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf); } static int run_status(struct add_i_state *s, const struct pathspec *ps, - struct string_list *files, struct list_options *opts) + struct prefix_item_list *files, + struct list_and_choose_options *opts) { if (get_modified_files(s->r, NO_FILTER, files, ps) < 0) return -1; - list(s, files, NULL, opts); + list(s, &files->items, NULL, &opts->list_opts); putchar('\n'); return 0; } +static int run_update(struct add_i_state *s, const struct pathspec *ps, + struct prefix_item_list *files, + struct list_and_choose_options *opts) +{ + int res = 0, fd; + size_t count, i; + struct lock_file index_lock; + + if (get_modified_files(s->r, WORKTREE_ONLY, files, ps) < 0) + return -1; + + if (!files->items.nr) { + putchar('\n'); + return 0; + } + + opts->prompt = N_("Update"); + count = list_and_choose(s, files, opts); + if (count <= 0) { + putchar('\n'); + return 0; + } + + fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR); + if (fd < 0) { + putchar('\n'); + return -1; + } + + for (i = 0; i < files->items.nr; i++) { + const char *name = files->items.items[i].string; + if (files->selected[i] && + add_file_to_index(s->r->index, name, 0) < 0) { + res = error(_("could not stage '%s'"), name); + break; + } + } + + if (!res && write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0) + res = error(_("could not write index")); + + if (!res) + printf(Q_("updated %d path\n", + "updated %d paths\n", count), (int)count); + + putchar('\n'); + return res; +} + static int run_help(struct add_i_state *s, const struct pathspec *unused_ps, - struct string_list *unused_files, - struct list_options *unused_opts) + struct prefix_item_list *unused_files, + struct list_and_choose_options *unused_opts) { color_fprintf_ln(stdout, s->help_color, "status - %s", _("show paths with changes")); @@ -609,9 +673,29 @@ static int run_help(struct add_i_state *s, const struct pathspec *unused_ps, return 0; } +static void choose_prompt_help(struct add_i_state *s) +{ + color_fprintf_ln(stdout, s->help_color, "%s", + _("Prompt help:")); + color_fprintf_ln(stdout, s->help_color, "1 - %s", + _("select a single item")); + color_fprintf_ln(stdout, s->help_color, "3-5 - %s", + _("select a range of items")); + color_fprintf_ln(stdout, s->help_color, "2-3,6-9 - %s", + _("select multiple ranges")); + color_fprintf_ln(stdout, s->help_color, "foo - %s", + _("select item based on unique prefix")); + color_fprintf_ln(stdout, s->help_color, "-... - %s", + _("unselect specified items")); + color_fprintf_ln(stdout, s->help_color, "* - %s", + _("choose all items")); + color_fprintf_ln(stdout, s->help_color, " - %s", + _("(empty) finish selecting")); +} + typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps, - struct string_list *files, - struct list_options *opts); + struct prefix_item_list *files, + struct list_and_choose_options *opts); struct command_item { size_t prefix_length; @@ -663,18 +747,21 @@ int run_add_i(struct repository *r, const struct pathspec *ps) command_t command; } command_list[] = { { "status", run_status }, + { "update", run_update }, { "help", run_help }, }; struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT; struct print_file_item_data print_file_item_data = { - "%12s %12s %s", STRBUF_INIT, STRBUF_INIT, STRBUF_INIT + "%12s %12s %s", NULL, NULL, + STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; - struct list_options opts = { - 0, NULL, print_file_item, &print_file_item_data + struct list_and_choose_options opts = { + { 0, NULL, print_file_item, &print_file_item_data }, + NULL, 0, choose_prompt_help }; struct strbuf header = STRBUF_INIT; - struct string_list files = STRING_LIST_INIT_DUP; + struct prefix_item_list files = PREFIX_ITEM_LIST_INIT; ssize_t i; int res = 0; @@ -695,11 +782,13 @@ int run_add_i(struct repository *r, const struct pathspec *ps) data.color = s.prompt_color; data.reset = s.reset_color; } + print_file_item_data.color = data.color; + print_file_item_data.reset = data.reset; strbuf_addstr(&header, " "); strbuf_addf(&header, print_file_item_data.modified_fmt, _("staged"), _("unstaged"), _("path")); - opts.header = header.buf; + opts.list_opts.header = header.buf; if (discard_index(r->index) < 0 || repo_read_index(r) < 0 || @@ -723,8 +812,9 @@ int run_add_i(struct repository *r, const struct pathspec *ps) } } - string_list_clear(&files, 1); + prefix_item_list_clear(&files); strbuf_release(&print_file_item_data.buf); + strbuf_release(&print_file_item_data.name); strbuf_release(&print_file_item_data.index); strbuf_release(&print_file_item_data.worktree); strbuf_release(&header); From patchwork Fri Nov 15 12:36:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11246289 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 18D86138C for ; Fri, 15 Nov 2019 12:36:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EFBF62073C for ; Fri, 15 Nov 2019 12:36:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CIOUd/8G" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727641AbfKOMga (ORCPT ); Fri, 15 Nov 2019 07:36:30 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:33804 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727272AbfKOMg3 (ORCPT ); Fri, 15 Nov 2019 07:36:29 -0500 Received: by mail-wr1-f67.google.com with SMTP id e6so10845015wrw.1 for ; Fri, 15 Nov 2019 04:36:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=WYyMXuw7hO4USLhsFbwckPai4JubVXMA6ECZykRTltk=; b=CIOUd/8GikrRznFeB3crGBnUbePP/Pc1NmiieMLz0kpCKM5O/U6J1Q5GybnX8U6aBk 2RKyK3oruPo45WOb3+/SB9SDT2sQg6Q+VSKk06jfJxq1JldRX9Cx+6xMaECmieBwlCcI ViLIM1qV+BJQCFprlntY7TKN11Ex7fEfN7TAilMnRlE4BCA5zVZIQidYBV8PDNXoO/56 iFMaWq9uEvjArYCQekpcTLr7zqbJqJ2zXdiXNOKVWv50WSagxHWSQ1TlgC1w2m5EmIAi A4+ihAHkurt5Uwe/eInV3XfLQ/wOH9J/g8QsYI/lOFyf1i/m9XAyBhK1a2DHNAKeJbIT Yhgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=WYyMXuw7hO4USLhsFbwckPai4JubVXMA6ECZykRTltk=; b=Ggv+I0rM39GbrVPgYmsqUIUiG9o/29KaWOCjnZSBDghUtH5B8bjK7At6TnY4RKjaq8 sSgaFDibmFxlHzD7QwBoAdlLE7P8f151UeMhGXyxokLLl4xyQuGvei+SfXbpihQGV7qo l+GqG2RwCY68+GpzlVqiBNo/vZc02dOPEffdqwlFj20CVbowMa0ppsDp7ABigmJ2rRc0 fXj62CwvASy8BFvdRcrp0JBNYqEs18mTqII14JxswCZhSKbN19mq3M8o8UbCEsMu1DTG PdUAEcKbFPHpfdatQJPfDPLndVY8itWzrk/I/VNWaF02sN9GA8/Or6U7C0lovHnpRiRi HdKA== X-Gm-Message-State: APjAAAXQ3KHmIr03E/aQ+wGoj4Goeqz5i8cXSFFP1f+SEXuwHwv0rmId ljBKRaqICVZ7fvFhqy/FlHghICCE X-Google-Smtp-Source: APXvYqxyvnzk0FCdg0gOxz/n40Qlb+8+hAzJHauZdQpEU+BoFRgGPxcW9N0nxlRW0OhbzPWg9VWD5Q== X-Received: by 2002:a05:6000:1605:: with SMTP id u5mr14300293wrb.252.1573821386226; Fri, 15 Nov 2019 04:36:26 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i13sm10829932wrp.12.2019.11.15.04.36.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Nov 2019 04:36:25 -0800 (PST) Message-Id: <5c31bbd24ab937f5906f967f007d5bcd305779e2.1573821382.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 15 Nov 2019 12:36:18 +0000 Subject: [PATCH 4/8] built-in add -i: re-implement `revert` in C Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin This is a relatively straight-forward port from the Perl version, with the notable exception that we imitate `git reset -- ` in the C version rather than the convoluted `git ls-tree HEAD -- | git update-index --index-info` followed by `git update-index --force-remove -- ` for the missed ones. While at it, we fix the pretty obvious bug where the `revert` command offers to unstage files that do not have staged changes. Signed-off-by: Johannes Schindelin --- add-interactive.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/add-interactive.c b/add-interactive.c index b0bda0cd2d..191a10b97d 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -653,6 +653,114 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps, return res; } +static void revert_from_diff(struct diff_queue_struct *q, + struct diff_options *opt, void *data) +{ + int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; + + for (i = 0; i < q->nr; i++) { + struct diff_filespec *one = q->queue[i]->one; + struct cache_entry *ce; + + if (!(one->mode && !is_null_oid(&one->oid))) { + remove_file_from_index(opt->repo->index, one->path); + printf(_("note: %s is untracked now.\n"), one->path); + } else { + ce = make_cache_entry(opt->repo->index, one->mode, + &one->oid, one->path, 0, 0); + if (!ce) + die(_("make_cache_entry failed for path '%s'"), + one->path); + add_index_entry(opt->repo->index, ce, add_flags); + } + } +} + +static int run_revert(struct add_i_state *s, const struct pathspec *ps, + struct prefix_item_list *files, + struct list_and_choose_options *opts) +{ + int res = 0, fd; + size_t count, i, j; + + struct object_id oid; + int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid, + NULL); + struct lock_file index_lock; + const char **paths; + struct tree *tree; + struct diff_options diffopt = { NULL }; + + if (get_modified_files(s->r, INDEX_ONLY, files, ps) < 0) + return -1; + + if (!files->items.nr) { + putchar('\n'); + return 0; + } + + opts->prompt = N_("Revert"); + count = list_and_choose(s, files, opts); + if (count <= 0) + goto finish_revert; + + fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR); + if (fd < 0) { + res = -1; + goto finish_revert; + } + + if (is_initial) + oidcpy(&oid, s->r->hash_algo->empty_tree); + else { + tree = parse_tree_indirect(&oid); + if (!tree) { + res = error(_("Could not parse HEAD^{tree}")); + goto finish_revert; + } + oidcpy(&oid, &tree->object.oid); + } + + ALLOC_ARRAY(paths, count + 1); + for (i = j = 0; i < files->items.nr; i++) + if (files->selected[i]) + paths[j++] = files->items.items[i].string; + paths[j] = NULL; + + parse_pathspec(&diffopt.pathspec, 0, + PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH, + NULL, paths); + + diffopt.output_format = DIFF_FORMAT_CALLBACK; + diffopt.format_callback = revert_from_diff; + diffopt.flags.override_submodule_config = 1; + diffopt.repo = s->r; + + if (do_diff_cache(&oid, &diffopt)) + res = -1; + else { + diffcore_std(&diffopt); + diff_flush(&diffopt); + } + free(paths); + clear_pathspec(&diffopt.pathspec); + + if (!res && write_locked_index(s->r->index, &index_lock, + COMMIT_LOCK) < 0) + res = -1; + else + res = repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0, 1, + NULL, NULL, NULL); + + if (!res) + printf(Q_("reverted %d path\n", + "reverted %d paths\n", count), (int)count); + +finish_revert: + putchar('\n'); + return res; +} + static int run_help(struct add_i_state *s, const struct pathspec *unused_ps, struct prefix_item_list *unused_files, struct list_and_choose_options *unused_opts) @@ -748,6 +856,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) } command_list[] = { { "status", run_status }, { "update", run_update }, + { "revert", run_revert }, { "help", run_help }, }; struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT; From patchwork Fri Nov 15 12:36:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11246287 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 58DFD13BD for ; Fri, 15 Nov 2019 12:36:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3A37F2073C for ; Fri, 15 Nov 2019 12:36:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="F/dr83pr" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727640AbfKOMga (ORCPT ); Fri, 15 Nov 2019 07:36:30 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:44976 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727329AbfKOMg2 (ORCPT ); Fri, 15 Nov 2019 07:36:28 -0500 Received: by mail-wr1-f67.google.com with SMTP id f2so10812634wrs.11 for ; Fri, 15 Nov 2019 04:36:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=J1l9QLkhOQh4CM7g9oRmHlHkJ4wZCjYjwkmuadOnwQQ=; b=F/dr83prdLfkaXRZEB6qyNySJaYW5kHtUmEQqQsdYv1vggwu2WFTfPPZfPX707bA7f yW6jLgCnNlKL0zjzF4ckXHcqg5PT11BzMaBqmPffusF5ioSlEoHqdVw/z9QnUxmYKwE2 ayNGNoRF3ZyCFfLzjbtYuw6A0d2w2FyApYrIrXDdS5sXH2lnIU9Pno7I0cyezdGc+IZn EDEN6vXqXZ+OcAv65krXXtSdkJTsQr6PgKS6f8lzdj/4/qexioEx8GYG5WEZPGajpSlF RXWi2IgoWv9gZ49QVoq+PyblnBlDuDADzIV2fIjczPDz9SlWX2yyztFQ7f/LjJEOoY0z 640A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=J1l9QLkhOQh4CM7g9oRmHlHkJ4wZCjYjwkmuadOnwQQ=; b=PVxEWgASWesTF8UAAybpppqDgxOSYjNCP4Ec3hoaPOh6no/kXclq8LNozXNxj5mcs1 1Zr0f+2uI/e00/8AS3Z7qJ6Tdr/6RbV1fCm9Avz8dBCcMoklWr545+weAsKe1/kBTEXF qEpTwkUfaUxC5VvGD6X+cnUcDwSP6bKtD6uZfoJk+MHS4huTRXibi+z5g1YZ9qn9mL1C Q1ybuGFZnRD1b1ux9IVu+HzJCQCERNgcgaVZQUhqgPGJGHSQKU6IY+yHk90+5II2yt2x snB5Z4VtLhmIUnFkoUvKCR2yZTyxX3onpod2ObwTx1vX05pofLn01LjbZm8EQqYHswOy ZqaQ== X-Gm-Message-State: APjAAAVQb8FjiY+eHX+OrpbHkJrYwxe1lo+6/t/0jcXygVdyzqHu4my3 fhpOLcit9FEv9Q5pHDkkzs8kp7lL X-Google-Smtp-Source: APXvYqy43e59cGUOzlxiEuVnQqAdIyg9iDUAq4uSH4AyIQSTFBksFH0Tj0/RELPsLeBpSZLa8PIG/g== X-Received: by 2002:adf:fe0c:: with SMTP id n12mr14802847wrr.174.1573821386976; Fri, 15 Nov 2019 04:36:26 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v81sm10293941wmg.4.2019.11.15.04.36.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Nov 2019 04:36:26 -0800 (PST) Message-Id: <5c498795b354c8483f9344662085a8f8cca4580f.1573821382.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 15 Nov 2019 12:36:19 +0000 Subject: [PATCH 5/8] built-in add -i: re-implement `add-untracked` in C Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin This is yet another command, ported to C. It builds nicely on the support functions introduced for other commands, with the notable difference that only names are displayed for untracked files, no file type or diff summary. Signed-off-by: Johannes Schindelin --- add-interactive.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/add-interactive.c b/add-interactive.c index 191a10b97d..9ed4455a86 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -7,6 +7,7 @@ #include "refs.h" #include "string-list.h" #include "lockfile.h" +#include "dir.h" struct add_i_state { struct repository *r; @@ -559,6 +560,7 @@ static int is_valid_prefix(const char *prefix, size_t prefix_len) struct print_file_item_data { const char *modified_fmt, *color, *reset; struct strbuf buf, name, index, worktree; + unsigned only_names:1; }; static void print_file_item(int i, int selected, struct string_list_item *item, @@ -582,6 +584,12 @@ static void print_file_item(int i, int selected, struct string_list_item *item, highlighted = d->name.buf; } + if (d->only_names) { + printf("%c%2d: %s", selected ? '*' : ' ', i + 1, + highlighted ? highlighted : item->string); + return; + } + render_adddel(&d->worktree, &c->worktree, _("nothing")); render_adddel(&d->index, &c->index, _("unchanged")); @@ -761,6 +769,88 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps, return res; } +static int get_untracked_files(struct repository *r, + struct prefix_item_list *files, + const struct pathspec *ps) +{ + struct dir_struct dir = { 0 }; + size_t i; + struct strbuf buf = STRBUF_INIT; + + if (repo_read_index(r) < 0) + return error(_("could not read index")); + + prefix_item_list_clear(files); + setup_standard_excludes(&dir); + add_pattern_list(&dir, EXC_CMDL, "--exclude option"); + fill_directory(&dir, r->index, ps); + + for (i = 0; i < dir.nr; i++) { + struct dir_entry *ent = dir.entries[i]; + + if (index_name_is_other(r->index, ent->name, ent->len)) { + strbuf_reset(&buf); + strbuf_add(&buf, ent->name, ent->len); + add_file_item(&files->items, buf.buf); + } + } + + strbuf_release(&buf); + return 0; +} + +static int run_add_untracked(struct add_i_state *s, const struct pathspec *ps, + struct prefix_item_list *files, + struct list_and_choose_options *opts) +{ + struct print_file_item_data *d = opts->list_opts.print_item_data; + int res = 0, fd; + size_t count, i; + struct lock_file index_lock; + + if (get_untracked_files(s->r, files, ps) < 0) + return -1; + + if (!files->items.nr) { + printf(_("No untracked files.\n")); + goto finish_add_untracked; + } + + opts->prompt = N_("Add untracked"); + d->only_names = 1; + count = list_and_choose(s, files, opts); + d->only_names = 0; + if (count <= 0) + goto finish_add_untracked; + + fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR); + if (fd < 0) { + res = -1; + goto finish_add_untracked; + } + + for (i = 0; i < files->items.nr; i++) { + const char *name = files->items.items[i].string; + if (files->selected[i] && + add_file_to_index(s->r->index, name, 0) < 0) { + res = error(_("could not stage '%s'"), name); + break; + } + } + + if (!res && + write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0) + res = error(_("could not write index")); + + if (!res) + printf(Q_("added %d path\n", + "added %d paths\n", count), (int)count); + +finish_add_untracked: + putchar('\n'); + return res; +} + static int run_help(struct add_i_state *s, const struct pathspec *unused_ps, struct prefix_item_list *unused_files, struct list_and_choose_options *unused_opts) @@ -857,6 +947,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) { "status", run_status }, { "update", run_update }, { "revert", run_revert }, + { "add untracked", run_add_untracked }, { "help", run_help }, }; struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT; From patchwork Fri Nov 15 12:36:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11246291 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C744D138C for ; Fri, 15 Nov 2019 12:36:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9F4B42073C for ; Fri, 15 Nov 2019 12:36:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eq4u0ygj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727643AbfKOMgc (ORCPT ); Fri, 15 Nov 2019 07:36:32 -0500 Received: from mail-wm1-f68.google.com ([209.85.128.68]:50775 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727621AbfKOMga (ORCPT ); Fri, 15 Nov 2019 07:36:30 -0500 Received: by mail-wm1-f68.google.com with SMTP id l17so9497253wmh.0 for ; Fri, 15 Nov 2019 04:36:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=eVaQ1Y6X4IxTHV6yN1mrAR/Srf8HR3WZcCUPhD+bVSY=; b=eq4u0ygjGn0mmjOyrvQJp1+Hhc8k2vqduXo5FCgsrVhvsEi7rV/eHU/JhzwtK510yB B6k7VEgL7MM0ZM1awImtnTrx+XZXRILufZVqf+U24cwvo9bDppYQMYN60rv9RzPxd3p+ iUNXUHKJNyyOm+EILFNvbMXF9TOOrfiA/k67d9JdEq27S115ilfW5GJoMSvhA3AcGmSa JGaS+IeMd5Z7jy0UwTef9tRvRXKcsPhB/SvXEkjVlCH0xIIoya+Xqg2DkxlbKyjTjdnP S6S5cfeDYjdsMkCVU9hNieKBi8RUwUeE0qdoKRO2wtNcRNt4U/ma4yIy09MxlQPXhwVJ XAAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=eVaQ1Y6X4IxTHV6yN1mrAR/Srf8HR3WZcCUPhD+bVSY=; b=cPKZtyKqhPKTZogj0pUoCn1PpF402yoxiEAg2hvRla/W7akst43myuG0Qlf2ob1EmB 4wPqkh56tBRKhvr85hjVrQgisjWyQHSGp9sz+wP3ltMFQnXwe7lu7j+w53TYBRN++4tk bCKMBMgUrUUmKh3b6GIrkACrD800TJl1ZXi3SoKtZGAM6ZwExy3Aj0jYnOLZmemvjFiN Zp/L3vb+OLYxtfcnN+qjNAYJz6cafP79qii8vjjoD2krjSdbMIeKycxxdonf6UNPSrUH 70j8zq8nMEPtHdQd0Otu/Bpazx++9rM/WzqjyRJK37EnyS0HO04CmSyRAjsNPd9GekTq 0NBg== X-Gm-Message-State: APjAAAXIzDyMRW8+lgsCeM9Oq0FUL42UDpj4I/fPh/Lj+BIMk4PZfJxF 41esuzNCWT72jcjCMONhxMy17rfV X-Google-Smtp-Source: APXvYqyqtNO8zhXja4g89fjlA5gIpsgq4pZAEahEKThAKjMtZ5mXFJTJ/dyH2PUEgF2V6R0H9KFiHQ== X-Received: by 2002:a05:600c:214c:: with SMTP id v12mr14111169wml.124.1573821387804; Fri, 15 Nov 2019 04:36:27 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id x9sm10891366wru.32.2019.11.15.04.36.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Nov 2019 04:36:27 -0800 (PST) Message-Id: <0c8a71e2e861f2ef657a363cc3da198f9062bf95.1573821382.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 15 Nov 2019 12:36:20 +0000 Subject: [PATCH 6/8] built-in add -i: implement the `patch` command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin Well, it is not a full implementation yet. In the interest of making this easy to review (and easy to keep bugs out), we still hand off to the Perl script to do the actual work. The `patch` functionality actually makes up for more than half of the 1,800+ lines of `git-add--interactive.perl`. It will be ported from Perl to C incrementally, later. Signed-off-by: Johannes Schindelin --- add-interactive.c | 91 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 7 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index 9ed4455a86..fb8124fc57 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -8,6 +8,7 @@ #include "string-list.h" #include "lockfile.h" #include "dir.h" +#include "run-command.h" struct add_i_state { struct repository *r; @@ -374,7 +375,7 @@ static ssize_t list_and_choose(struct add_i_state *s, struct adddel { uintmax_t add, del; - unsigned seen:1, binary:1; + unsigned seen:1, unmerged:1, binary:1; }; struct file_item { @@ -414,6 +415,7 @@ struct collection_status { const char *reference; unsigned skip_unseen:1; + size_t unmerged_count, binary_count; struct string_list *files; struct hashmap file_map; }; @@ -436,7 +438,7 @@ static void collect_changes_cb(struct diff_queue_struct *q, int hash = strhash(name); struct pathname_entry *entry; struct file_item *file_item; - struct adddel *adddel; + struct adddel *adddel, *other_adddel; entry = hashmap_get_entry_from_hash(&s->file_map, hash, name, struct pathname_entry, ent); @@ -456,11 +458,21 @@ static void collect_changes_cb(struct diff_queue_struct *q, file_item = entry->item; adddel = s->phase == FROM_INDEX ? &file_item->index : &file_item->worktree; + other_adddel = s->phase == FROM_INDEX ? + &file_item->worktree : &file_item->index; adddel->seen = 1; adddel->add = stat.files[i]->added; adddel->del = stat.files[i]->deleted; - if (stat.files[i]->is_binary) + if (stat.files[i]->is_binary) { + if (!other_adddel->binary) + s->binary_count++; adddel->binary = 1; + } + if (stat.files[i]->is_unmerged) { + if (!other_adddel->unmerged) + s->unmerged_count++; + adddel->unmerged = 1; + } } free_diffstat_info(&stat); } @@ -474,7 +486,9 @@ enum modified_files_filter { static int get_modified_files(struct repository *r, enum modified_files_filter filter, struct prefix_item_list *files, - const struct pathspec *ps) + const struct pathspec *ps, + size_t *unmerged_count, + size_t *binary_count) { struct object_id head_oid; int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, @@ -521,6 +535,10 @@ static int get_modified_files(struct repository *r, } } hashmap_free_entries(&s.file_map, struct pathname_entry, ent); + if (unmerged_count) + *unmerged_count = s.unmerged_count; + if (binary_count) + *binary_count = s.binary_count; /* While the diffs are ordered already, we ran *two* diffs... */ string_list_sort(&files->items); @@ -603,7 +621,7 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps, struct prefix_item_list *files, struct list_and_choose_options *opts) { - if (get_modified_files(s->r, NO_FILTER, files, ps) < 0) + if (get_modified_files(s->r, NO_FILTER, files, ps, NULL, NULL) < 0) return -1; list(s, &files->items, NULL, &opts->list_opts); @@ -620,7 +638,7 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps, size_t count, i; struct lock_file index_lock; - if (get_modified_files(s->r, WORKTREE_ONLY, files, ps) < 0) + if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, NULL, NULL) < 0) return -1; if (!files->items.nr) { @@ -699,7 +717,7 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps, struct tree *tree; struct diff_options diffopt = { NULL }; - if (get_modified_files(s->r, INDEX_ONLY, files, ps) < 0) + if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0) return -1; if (!files->items.nr) { @@ -851,6 +869,64 @@ static int run_add_untracked(struct add_i_state *s, const struct pathspec *ps, return res; } +static int run_patch(struct add_i_state *s, const struct pathspec *ps, + struct prefix_item_list *files, + struct list_and_choose_options *opts) +{ + int res = 0; + ssize_t count, i, j; + size_t unmerged_count = 0, binary_count = 0; + + if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, + &unmerged_count, &binary_count) < 0) + return -1; + + if (unmerged_count || binary_count) { + for (i = j = 0; i < files->items.nr; i++) { + struct file_item *item = files->items.items[i].util; + + if (item->index.binary || item->worktree.binary) { + free(item); + free(files->items.items[i].string); + } else if (item->index.unmerged || + item->worktree.unmerged) { + color_fprintf_ln(stderr, s->error_color, + _("ignoring unmerged: %s"), + files->items.items[i].string); + free(item); + free(files->items.items[i].string); + } else + files->items.items[j++] = files->items.items[i]; + } + files->items.nr = j; + } + + if (!files->items.nr) { + if (binary_count) + fprintf(stderr, _("Only binary files changed.\n")); + else + fprintf(stderr, _("No changes.\n")); + return 0; + } + + opts->prompt = N_("Patch update"); + count = list_and_choose(s, files, opts); + if (count >= 0) { + struct argv_array args = ARGV_ARRAY_INIT; + + argv_array_pushl(&args, "git", "add--interactive", "--patch", + "--", NULL); + for (i = 0; i < files->items.nr; i++) + if (files->selected[i]) + argv_array_push(&args, + files->items.items[i].string); + res = run_command_v_opt(args.argv, 0); + argv_array_clear(&args); + } + + return res; +} + static int run_help(struct add_i_state *s, const struct pathspec *unused_ps, struct prefix_item_list *unused_files, struct list_and_choose_options *unused_opts) @@ -948,6 +1024,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) { "update", run_update }, { "revert", run_revert }, { "add untracked", run_add_untracked }, + { "patch", run_patch }, { "help", run_help }, }; struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT; From patchwork Fri Nov 15 12:36:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11246295 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 87E1E138C for ; Fri, 15 Nov 2019 12:36:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 697E82073C for ; Fri, 15 Nov 2019 12:36:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="dIGuTlX+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727647AbfKOMge (ORCPT ); Fri, 15 Nov 2019 07:36:34 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:46722 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727628AbfKOMga (ORCPT ); Fri, 15 Nov 2019 07:36:30 -0500 Received: by mail-wr1-f65.google.com with SMTP id b3so10794459wrs.13 for ; Fri, 15 Nov 2019 04:36:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=+aeG46lF7Hex/vXHBat13Ws6AAx+3WqVKgob/BMugWY=; b=dIGuTlX++H2MQVjP30NjP60pRX7ql+eD4c7snDMaSzNkRAHc5d3EqDQYDpKtmtfr/p ODXmAmn9DE929Mu/N+7qSfehROEgjuQdbpDIc9HZaRuSgNjoVsv1gE2xL4yW8DzG+FrF iuOL/W90ZbCIffgQOvOOF267iWFFe/V+9vi/Cp/31jWUbzPOFKe9SyLPC7wqMI4ZGtOd t3Rnsk4Qao+WLU+Tm//MW297daNEniBG4uDG+kemrOoCQBfNEk5EyWUF/PJAFfqLBeIX +faCziv++8ePhWrOWe49lkW+CoSPmLy+6TLzSV8b2UqnRoevmZc6WQ0f8ztk4sto8kPo AUiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=+aeG46lF7Hex/vXHBat13Ws6AAx+3WqVKgob/BMugWY=; b=GEawtmogi3ZeE+qb9W0bCqo2sPL9/8yXUIYXCsuwA6W53jOsK5Htv7v4vQKxZeQxAT m7Mxo2aexUEUV5aRi3RcRRFk1FYwTR0oEjEsjmQgCPFwPUoKGH7S43pCau8BPTpOuPf+ eAANPQofHhYE1U+MURKf5YF/eiDiJqAvqul6QNEMbOJ1z8mR3IKNLG9ZiWUnWxUZOZhY XlXbDhgJYJ/jM6grH2rzldrXEdAKeNTVDTdGcbjt7o606g7xTY4A4R2wEpNaMH28yDjP ngALuOFe7YSnva1t+SjSVqwlsGM0PoEfiPStdKB/jEmisxpflkB7YFOadosbl29zVzRY ZK+g== X-Gm-Message-State: APjAAAVfG3eco0ag8AsLzXG4oVthG8ROUqAIWSep+fetR1PQZkX5HdkL YYAHDmDf7rAmjrkrg69xq0OuMyp1 X-Google-Smtp-Source: APXvYqzeBSIjBHU0SvPuB7M7L7LRumfxwWZzp0yXlfh6428dgze0E4gq/R2jKMhj6de4fcUFNjnSRg== X-Received: by 2002:adf:e4c5:: with SMTP id v5mr12223302wrm.106.1573821388621; Fri, 15 Nov 2019 04:36:28 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id u4sm11157788wrq.22.2019.11.15.04.36.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Nov 2019 04:36:28 -0800 (PST) Message-Id: <499f3f19e026a60e050f2ed1bb2d820febc6b0a0.1573821382.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 15 Nov 2019 12:36:21 +0000 Subject: [PATCH 7/8] built-in add -i: re-implement the `diff` command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin It is not only laziness that we simply spawn `git diff -p --cached` here: this command needs to use the pager, and the pager needs to exit when the diff is done. Currently we do not have any way to make that happen if we run the diff in-process. So let's just spawn. Signed-off-by: Johannes Schindelin --- add-interactive.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/add-interactive.c b/add-interactive.c index fb8124fc57..f33075b202 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -927,6 +927,47 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps, return res; } +static int run_diff(struct add_i_state *s, const struct pathspec *ps, + struct prefix_item_list *files, + struct list_and_choose_options *opts) +{ + int res = 0; + ssize_t count, i; + + struct object_id oid; + int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid, + NULL); + if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0) + return -1; + + if (!files->items.nr) { + putchar('\n'); + return 0; + } + + opts->prompt = N_("Review diff"); + opts->flags = IMMEDIATE; + count = list_and_choose(s, files, opts); + opts->flags = 0; + if (count >= 0) { + struct argv_array args = ARGV_ARRAY_INIT; + + argv_array_pushl(&args, "git", "diff", "-p", "--cached", + oid_to_hex(!is_initial ? &oid : + s->r->hash_algo->empty_tree), + "--", NULL); + for (i = 0; i < files->items.nr; i++) + if (files->selected[i]) + argv_array_push(&args, + files->items.items[i].string); + res = run_command_v_opt(args.argv, 0); + argv_array_clear(&args); + } + + putchar('\n'); + return res; +} + static int run_help(struct add_i_state *s, const struct pathspec *unused_ps, struct prefix_item_list *unused_files, struct list_and_choose_options *unused_opts) @@ -1025,6 +1066,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) { "revert", run_revert }, { "add untracked", run_add_untracked }, { "patch", run_patch }, + { "diff", run_diff }, { "help", run_help }, }; struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT; From patchwork Fri Nov 15 12:36:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11246293 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id ED41D6C1 for ; Fri, 15 Nov 2019 12:36:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CF5522073C for ; Fri, 15 Nov 2019 12:36:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="tF+Gb6H0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727645AbfKOMgd (ORCPT ); Fri, 15 Nov 2019 07:36:33 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:55663 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727442AbfKOMgb (ORCPT ); Fri, 15 Nov 2019 07:36:31 -0500 Received: by mail-wm1-f65.google.com with SMTP id b11so9507946wmb.5 for ; Fri, 15 Nov 2019 04:36:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=egjDdnZjtOAgHkbz5V54VeouNoBxPkgOvpgATvnzIVs=; b=tF+Gb6H0KBC89UZBH9RkqpJ3RYrY8DvS914Ha7cvFoBqXV3jvta1NikOELcq3/hemq ByWs2C7K2+xqTQQwprs8DfW6bVDLmeFnjfW1zPQ9yUxYvBNIZboswQgL3Oz+k9f0ZJGe o8BZqf3MhHzErYMKOd2ACI9J9PlLctbIysgtoLBTz7mBzjUQvVADtZUlHB8rGEtWhFIZ juj/e+O+e52NrtK1JGLfiCprtHfTTOLhHVwS2Cu8eDnQeu6Zz5MK3/BA2/YMs8Se/lZ/ UjljCeK0LQJYHCRiTMJlAn1SGiiNB8SmcWkYi67xek9pJ3DIZora0MSNoizw1Al8TyyK 6YkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=egjDdnZjtOAgHkbz5V54VeouNoBxPkgOvpgATvnzIVs=; b=TSy3mKuGplTeAaRbNKhYnVtXivRDEkywzoqW65dGTb1cuAW9c+GGZNFDC67HNNmE64 TGsxR/CkTJJWkL7J0Rn2aJvXK2uSThRICmxhkPINfjdPMFrO+CnzjQ1bnaieHgl8vrSu h07huhEYOpn7l2t3Q2gLawHuIukzTTFdgO+SgaJJNRgocsG2zj8tve2cs5zCb0xeynSk C1fjk7nMnKJ9nKTrSiXHjKJHqZdCqeZ3yWagC5M8EUbYH12YVofazApKAmFHU9aGiDti /RHrUyyT3v5L53PKlWXAtXzGPmINxEUqxUWxY5cJaJYsXt3AGNdZQWuj8/WtRnyTKCqg rMAQ== X-Gm-Message-State: APjAAAVXIHT8kk5IaBjzv+JCgxmHnty4wXSvKKUvXgqCNeHgq+N1xHJB LgGUFgSwGiVDk5a88xCCrVOIrIlC X-Google-Smtp-Source: APXvYqw1FTtMmpHZw3QNrKGZICT3JrjybWr1bi7c8NFMYDBwh8jMUIC2Wvs2RX9SvwxciljUGw9/WA== X-Received: by 2002:a1c:9d89:: with SMTP id g131mr11552483wme.81.1573821389408; Fri, 15 Nov 2019 04:36:29 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id f14sm10909868wrv.17.2019.11.15.04.36.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Nov 2019 04:36:28 -0800 (PST) Message-Id: In-Reply-To: References: From: "Johannes Schindelin via GitGitGadget" Date: Fri, 15 Nov 2019 12:36:22 +0000 Subject: [PATCH 8/8] built-in add -i: offer the `quit` command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Johannes Schindelin , Junio C Hamano , Johannes Schindelin Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin We do not really want to `exit()` here, of course, as this is safely libified code. Signed-off-by: Johannes Schindelin --- add-interactive.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index f33075b202..40bec9acbe 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -1067,6 +1067,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) { "add untracked", run_add_untracked }, { "patch", run_patch }, { "diff", run_diff }, + { "quit", NULL }, { "help", run_help }, }; struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT; @@ -1118,17 +1119,22 @@ int run_add_i(struct repository *r, const struct pathspec *ps) res = run_status(&s, ps, &files, &opts); for (;;) { + struct command_item *util; + i = list_and_choose(&s, &commands, &main_loop_opts); - if (i == LIST_AND_CHOOSE_QUIT) { + if (i < 0 || i >= commands.items.nr) + util = NULL; + else + util = commands.items.items[i].util; + + if (i == LIST_AND_CHOOSE_QUIT || (util && !util->command)) { printf(_("Bye.\n")); res = 0; break; } - if (i != LIST_AND_CHOOSE_ERROR) { - struct command_item *util = - commands.items.items[i].util; + + if (util) res = util->command(&s, ps, &files, &opts); - } } prefix_item_list_clear(&files);