From: "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>,
Junio C Hamano <gitster@pobox.com>,
Johannes Schindelin <johannes.schindelin@gmx.de>
Subject: [PATCH 03/19] built-in add -p: show colored hunks by default
Date: Fri, 13 Dec 2019 08:07:50 +0000 [thread overview]
Message-ID: <438e6519fb7e81c451ebba3ea9efffc26b4c7a17.1576224486.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.173.git.1576224486.gitgitgadget@gmail.com>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Just like the Perl version, we now generate two diffs if `color.diff` is
set: one with and one without color. Then we parse them in parallel and
record which hunks start at which offsets in both.
Note that this is a (slight) deviation from the way the Perl version did
it: we are no longer reading the output of `diff-files` line by line
(which is more natural for Perl than for C), but in one go, and parse
everything later, so we might just as well do it in synchrony.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
add-patch.c | 79 +++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 62 insertions(+), 17 deletions(-)
diff --git a/add-patch.c b/add-patch.c
index d1b1a080e4..79eefa9505 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -4,9 +4,10 @@
#include "run-command.h"
#include "argv-array.h"
#include "pathspec.h"
+#include "color.h"
struct hunk {
- size_t start, end;
+ size_t start, end, colored_start, colored_end;
enum { UNDECIDED_HUNK = 0, SKIP_HUNK, USE_HUNK } use;
};
@@ -15,7 +16,7 @@ struct add_p_state {
struct strbuf answer, buf;
/* parsed diff */
- struct strbuf plain;
+ struct strbuf plain, colored;
struct hunk head;
struct hunk *hunk;
size_t hunk_nr, hunk_alloc;
@@ -39,26 +40,50 @@ static void setup_child_process(struct add_p_state *s,
static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
{
- struct strbuf *plain = &s->plain;
+ struct argv_array args = ARGV_ARRAY_INIT;
+ struct strbuf *plain = &s->plain, *colored = NULL;
struct child_process cp = CHILD_PROCESS_INIT;
- char *p, *pend;
- size_t i;
+ char *p, *pend, *colored_p = NULL, *colored_pend = NULL;
+ size_t i, color_arg_index;
struct hunk *hunk = NULL;
int res;
/* Use `--no-color` explicitly, just in case `diff.color = always`. */
- setup_child_process(s, &cp,
- "diff-files", "-p", "--no-color", "--", NULL);
+ argv_array_pushl(&args, "diff-files", "-p", "--no-color", "--", NULL);
+ color_arg_index = args.argc - 2;
for (i = 0; i < ps->nr; i++)
- argv_array_push(&cp.args, ps->items[i].original);
+ argv_array_push(&args, ps->items[i].original);
+ setup_child_process(s, &cp, NULL);
+ cp.argv = args.argv;
res = capture_command(&cp, plain, 0);
- if (res)
+ if (res) {
+ argv_array_clear(&args);
return error(_("could not parse diff"));
- if (!plain->len)
+ }
+ if (!plain->len) {
+ argv_array_clear(&args);
return 0;
+ }
strbuf_complete_line(plain);
+ if (want_color_fd(1, -1)) {
+ struct child_process colored_cp = CHILD_PROCESS_INIT;
+
+ setup_child_process(s, &colored_cp, NULL);
+ xsnprintf((char *)args.argv[color_arg_index], 8, "--color");
+ colored_cp.argv = args.argv;
+ colored = &s->colored;
+ res = capture_command(&colored_cp, colored, 0);
+ argv_array_clear(&args);
+ if (res)
+ return error(_("could not parse colored diff"));
+ strbuf_complete_line(colored);
+ colored_p = colored->buf;
+ colored_pend = colored_p + colored->len;
+ }
+ argv_array_clear(&args);
+
/* parse hunks */
p = plain->buf;
pend = p + plain->len;
@@ -82,20 +107,37 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
memset(hunk, 0, sizeof(*hunk));
hunk->start = p - plain->buf;
+ if (colored)
+ hunk->colored_start = colored_p - colored->buf;
}
p = eol == pend ? pend : eol + 1;
hunk->end = p - plain->buf;
+
+ if (colored) {
+ char *colored_eol = memchr(colored_p, '\n',
+ colored_pend - colored_p);
+ if (colored_eol)
+ colored_p = colored_eol + 1;
+ else
+ colored_p = colored_pend;
+
+ hunk->colored_end = colored_p - colored->buf;
+ }
}
return 0;
}
static void render_hunk(struct add_p_state *s, struct hunk *hunk,
- struct strbuf *out)
+ int colored, struct strbuf *out)
{
- strbuf_add(out, s->plain.buf + hunk->start,
- hunk->end - hunk->start);
+ if (colored)
+ strbuf_add(out, s->colored.buf + hunk->colored_start,
+ hunk->colored_end - hunk->colored_start);
+ else
+ strbuf_add(out, s->plain.buf + hunk->start,
+ hunk->end - hunk->start);
}
static void reassemble_patch(struct add_p_state *s, struct strbuf *out)
@@ -103,12 +145,12 @@ static void reassemble_patch(struct add_p_state *s, struct strbuf *out)
struct hunk *hunk;
size_t i;
- render_hunk(s, &s->head, out);
+ render_hunk(s, &s->head, 0, out);
for (i = 0; i < s->hunk_nr; i++) {
hunk = s->hunk + i;
if (hunk->use == USE_HUNK)
- render_hunk(s, hunk, out);
+ render_hunk(s, hunk, 0, out);
}
}
@@ -130,12 +172,13 @@ static int patch_update_file(struct add_p_state *s)
struct hunk *hunk;
char ch;
struct child_process cp = CHILD_PROCESS_INIT;
+ int colored = !!s->colored.len;
if (!s->hunk_nr)
return 0;
strbuf_reset(&s->buf);
- render_hunk(s, &s->head, &s->buf);
+ render_hunk(s, &s->head, colored, &s->buf);
fputs(s->buf.buf, stdout);
for (;;) {
if (hunk_index >= s->hunk_nr)
@@ -162,7 +205,7 @@ static int patch_update_file(struct add_p_state *s)
break;
strbuf_reset(&s->buf);
- render_hunk(s, hunk, &s->buf);
+ render_hunk(s, hunk, colored, &s->buf);
fputs(s->buf.buf, stdout);
strbuf_reset(&s->buf);
@@ -252,6 +295,7 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
NULL, NULL, NULL) < 0 ||
parse_diff(&s, ps) < 0) {
strbuf_release(&s.plain);
+ strbuf_release(&s.colored);
return -1;
}
@@ -261,5 +305,6 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
strbuf_release(&s.answer);
strbuf_release(&s.buf);
strbuf_release(&s.plain);
+ strbuf_release(&s.colored);
return 0;
}
--
gitgitgadget
next prev parent reply other threads:[~2019-12-13 8:08 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-13 8:07 [PATCH 00/19] Implement the git add --patch backend in C Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 01/19] built-in add -i: start implementing the `patch` functionality " Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 02/19] built-in add -i: wire up the new C code for the `patch` command Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` Johannes Schindelin via GitGitGadget [this message]
2019-12-13 8:07 ` [PATCH 04/19] built-in add -p: adjust hunk headers as needed Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 05/19] built-in add -p: color the prompt and the help text Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 06/19] built-in add -p: offer a helpful error message when hunk navigation failed Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 07/19] built-in add -p: support multi-file diffs Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 08/19] built-in add -p: handle deleted empty files Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 09/19] built-in app -p: allow selecting a mode change as a "hunk" Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 10/19] built-in add -p: show different prompts for mode changes and deletions Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 11/19] built-in add -p: implement the hunk splitting feature Johannes Schindelin via GitGitGadget
2019-12-13 8:07 ` [PATCH 12/19] built-in add -p: coalesce hunks after splitting them Johannes Schindelin via GitGitGadget
2019-12-13 8:08 ` [PATCH 13/19] strbuf: add a helper function to call the editor "on an strbuf" Johannes Schindelin via GitGitGadget
2019-12-13 8:08 ` [PATCH 14/19] built-in add -p: implement hunk editing Johannes Schindelin via GitGitGadget
2019-12-13 8:08 ` [PATCH 15/19] built-in add -p: implement the 'g' ("goto") command Johannes Schindelin via GitGitGadget
2019-12-13 8:08 ` [PATCH 16/19] built-in add -p: implement the '/' ("search regex") command Johannes Schindelin via GitGitGadget
2019-12-13 8:08 ` [PATCH 17/19] built-in add -p: implement the 'q' ("quit") command Johannes Schindelin via GitGitGadget
2019-12-13 8:08 ` [PATCH 18/19] built-in add -p: only show the applicable parts of the help text Johannes Schindelin via GitGitGadget
2019-12-13 8:08 ` [PATCH 19/19] built-in add -p: show helpful hint when nothing can be staged Johannes Schindelin via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=438e6519fb7e81c451ebba3ea9efffc26b4c7a17.1576224486.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=johannes.schindelin@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).