Re: [PATCH 0/2] Re: [PATCH v3 14/20] diff: add an internal option to dual-color diffs of diffs

2018-07-21 Thread Johannes Schindelin
Hi Stefan,

On Tue, 10 Jul 2018, Stefan Beller wrote:

> This is developed on top of 4a68b95ce2a6 (your series here)
> 
> This is an attempt to explain the previous email better,
> specially the second (yet unfinished) patch, but the resulting
> emit_line_0 is way clearer in my mind, dropping the 'first' character
> and instead having a 'char *sign' that (a) we can color differently for
> dual color and (b) can have multiple chars, the refactoring for the multiple
> chars would need to happen at a slightly higher level.
> 
> Feel free to draw inspiration from here, but if not that is fine, too
> (as I did not fully understand the word diffing problem yet, this may add a
> burden instead of just taking these patches).
> I can send up a cleanup series after yours lands, as well.

We discussed this on IRC a couple of days ago, and I think that this patch
pair was designed under the assumption that the dual color mode would use
diff markers of the same color, always. However, the dual color mode is
about *inverting* the color of the first marker (and using the marker
itself to determine the color) and then using a potentially *different*
color on the second marker (using *that* marker to determine the color).
Example:

-+ Hello

So I allowed myself to focus on trying to wrap my head around the way the
whitespace flags work, and how to adjust the code in cache.h/diff.c/diff.h
to replace the relatively simple workaround by a full blown correct patch
(which is sadly a *lot* larger).

Ciao,
Dscho


[PATCH 0/2] Re: [PATCH v3 14/20] diff: add an internal option to dual-color diffs of diffs

2018-07-10 Thread Stefan Beller
This is developed on top of 4a68b95ce2a6 (your series here)

This is an attempt to explain the previous email better,
specially the second (yet unfinished) patch, but the resulting
emit_line_0 is way clearer in my mind, dropping the 'first' character
and instead having a 'char *sign' that (a) we can color differently for
dual color and (b) can have multiple chars, the refactoring for the multiple
chars would need to happen at a slightly higher level.

Feel free to draw inspiration from here, but if not that is fine, too
(as I did not fully understand the word diffing problem yet, this may add a
burden instead of just taking these patches).
I can send up a cleanup series after yours lands, as well.

Thanks,
Stefan

Stefan Beller (2):
  diff.c: convert emit_line_ws_markup to take string for sign
  WIP diff.c: clarify emit_line_0

 diff.c | 84 --
 1 file changed, 40 insertions(+), 44 deletions(-)

-- 
2.18.0.203.gfac676dfb9-goog



Re: [PATCH v3 14/20] diff: add an internal option to dual-color diffs of diffs

2018-07-09 Thread Stefan Beller
On Tue, Jul 3, 2018 at 4:27 AM Johannes Schindelin via GitGitGadget
 wrote:
>
> From: Johannes Schindelin 
>
> When diffing diffs, it can be quite daunting to figure out what the heck
> is going on, as there are nested +/- signs.
>
> Let's make this easier by adding a flag in diff_options that allows
> color-coding the outer diff sign with inverted colors, so that the
> preimage and postimage is colored like the diff it is.
>
> Of course, this really only makes sense when the preimage and postimage
> *are* diffs. So let's not expose this flag via a command-line option for
> now.
>
> This is a feature that was invented by git-tbdiff, and it will be used
> by `git range-diff` in the next commit, by offering it via a new option:
> `--dual-color`.
>
> Signed-off-by: Johannes Schindelin 
> ---
>  diff.c | 83 +++---
>  diff.h |  1 +
>  2 files changed, 69 insertions(+), 15 deletions(-)
>
> diff --git a/diff.c b/diff.c
> index 8c568cbe0..26445ffa1 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -562,14 +562,18 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t 
> *mf2,
> ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
>  }
>
> -static void emit_line_0(struct diff_options *o, const char *set, const char 
> *reset,
> +static void emit_line_0(struct diff_options *o,
> +   const char *set, unsigned reverse, const char *reset,
> int first, const char *line, int len)
>  {
> int has_trailing_newline, has_trailing_carriage_return;
> int nofirst;
> FILE *file = o->file;
>
> -   fputs(diff_line_prefix(o), file);
> +   if (first)
> +   fputs(diff_line_prefix(o), file);
> +   else if (!len)
> +   return;

This case is not a problem for empty lines in e.g. "git-log --line-prefix"
because first would contain the LF.

> if (len == 0) {
> has_trailing_newline = (first == '\n');
> @@ -587,8 +591,10 @@ static void emit_line_0(struct diff_options *o, const 
> char *set, const char *res
> }
>
> if (len || !nofirst) {
> +   if (reverse && want_color(o->use_color))
> +   fputs(GIT_COLOR_REVERSE, file);

Would it make sense to have the function signature take a char* for reverse
and we pass in diff_get_color(o, GIT_COLOR_REVERSE), that would align
with the set and reset color passed in?

> fputs(set, file);
> -   if (!nofirst)
> +   if (first && !nofirst)
> fputc(first, file);

'first' is line[0] and comes from user data, so I think this could change
the output of diffs that has lines with the NUL character first in a line
as then that character would be silently eaten?

The 'nofirst' (which is a bad name) is used to detect if we do not
want to double print the first character in case of an empty line.
(Before this series we always had 'first' as a valid character, now we also
have 0 encoded for "do not print anything?"

> @@ -962,7 +968,8 @@ static void dim_moved_lines(struct diff_options *o)
>
>  static void emit_line_ws_markup(struct diff_options *o,
> const char *set, const char *reset,
> -   const char *line, int len, char sign,
> +   const char *line, int len,
> +   const char *set_sign, char sign,
> unsigned ws_rule, int blank_at_eof)
>  {
> const char *ws = NULL;
> @@ -973,14 +980,20 @@ static void emit_line_ws_markup(struct diff_options *o,
> ws = NULL;
> }
>
> -   if (!ws)
> -   emit_line_0(o, set, reset, sign, line, len);
> -   else if (blank_at_eof)
> +   if (!ws && !set_sign)
> +   emit_line_0(o, set, 0, reset, sign, line, len);
> +   else if (!ws) {
> +   /* Emit just the prefix, then the rest. */
> +   emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
> +   sign, "", 0);
> +   emit_line_0(o, set, 0, reset, 0, line, len);

(FYI:)
My long term vision for the emit_line_* functions was to have them actually
line oriented, and here we observe that the preimage already breaks
this assumption but just uses it as it sees fit.
I added that wart when refactoring the diff code to use the emit_ functionality
as I wanted to stay backwards compatible.

The actual issue is that each emit_line_0 will encapsulate its content
with its designated color and then end it with a reset. Looking at t4015
a common occurrence is output like:

  +{

which we'd add one more layer to it now when set_sign is set.

I think this is ok for now (I value having this series land over insisting
on the perfect code), but just wanted to note my concern.

Ideally we'd refactor to only call emit_line once per line and when
the set sign (and the newly introduced 

[PATCH v3 14/20] diff: add an internal option to dual-color diffs of diffs

2018-07-03 Thread Johannes Schindelin via GitGitGadget
From: Johannes Schindelin 

When diffing diffs, it can be quite daunting to figure out what the heck
is going on, as there are nested +/- signs.

Let's make this easier by adding a flag in diff_options that allows
color-coding the outer diff sign with inverted colors, so that the
preimage and postimage is colored like the diff it is.

Of course, this really only makes sense when the preimage and postimage
*are* diffs. So let's not expose this flag via a command-line option for
now.

This is a feature that was invented by git-tbdiff, and it will be used
by `git range-diff` in the next commit, by offering it via a new option:
`--dual-color`.

Signed-off-by: Johannes Schindelin 
---
 diff.c | 83 +++---
 diff.h |  1 +
 2 files changed, 69 insertions(+), 15 deletions(-)

diff --git a/diff.c b/diff.c
index 8c568cbe0..26445ffa1 100644
--- a/diff.c
+++ b/diff.c
@@ -562,14 +562,18 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t 
*mf2,
ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
 }
 
-static void emit_line_0(struct diff_options *o, const char *set, const char 
*reset,
+static void emit_line_0(struct diff_options *o,
+   const char *set, unsigned reverse, const char *reset,
int first, const char *line, int len)
 {
int has_trailing_newline, has_trailing_carriage_return;
int nofirst;
FILE *file = o->file;
 
-   fputs(diff_line_prefix(o), file);
+   if (first)
+   fputs(diff_line_prefix(o), file);
+   else if (!len)
+   return;
 
if (len == 0) {
has_trailing_newline = (first == '\n');
@@ -587,8 +591,10 @@ static void emit_line_0(struct diff_options *o, const char 
*set, const char *res
}
 
if (len || !nofirst) {
+   if (reverse && want_color(o->use_color))
+   fputs(GIT_COLOR_REVERSE, file);
fputs(set, file);
-   if (!nofirst)
+   if (first && !nofirst)
fputc(first, file);
fwrite(line, len, 1, file);
fputs(reset, file);
@@ -602,7 +608,7 @@ static void emit_line_0(struct diff_options *o, const char 
*set, const char *res
 static void emit_line(struct diff_options *o, const char *set, const char 
*reset,
  const char *line, int len)
 {
-   emit_line_0(o, set, reset, line[0], line+1, len-1);
+   emit_line_0(o, set, 0, reset, line[0], line+1, len-1);
 }
 
 enum diff_symbol {
@@ -962,7 +968,8 @@ static void dim_moved_lines(struct diff_options *o)
 
 static void emit_line_ws_markup(struct diff_options *o,
const char *set, const char *reset,
-   const char *line, int len, char sign,
+   const char *line, int len,
+   const char *set_sign, char sign,
unsigned ws_rule, int blank_at_eof)
 {
const char *ws = NULL;
@@ -973,14 +980,20 @@ static void emit_line_ws_markup(struct diff_options *o,
ws = NULL;
}
 
-   if (!ws)
-   emit_line_0(o, set, reset, sign, line, len);
-   else if (blank_at_eof)
+   if (!ws && !set_sign)
+   emit_line_0(o, set, 0, reset, sign, line, len);
+   else if (!ws) {
+   /* Emit just the prefix, then the rest. */
+   emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
+   sign, "", 0);
+   emit_line_0(o, set, 0, reset, 0, line, len);
+   } else if (blank_at_eof)
/* Blank line at EOF - paint '+' as well */
-   emit_line_0(o, ws, reset, sign, line, len);
+   emit_line_0(o, ws, 0, reset, sign, line, len);
else {
/* Emit just the prefix, then the rest. */
-   emit_line_0(o, set, reset, sign, "", 0);
+   emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
+   sign, "", 0);
ws_check_emit(line, len, ws_rule,
  o->file, set, reset, ws);
}
@@ -990,7 +1003,7 @@ static void emit_diff_symbol_from_struct(struct 
diff_options *o,
 struct emitted_diff_symbol *eds)
 {
static const char *nneof = " No newline at end of file\n";
-   const char *context, *reset, *set, *meta, *fraginfo;
+   const char *context, *reset, *set, *set_sign, *meta, *fraginfo;
struct strbuf sb = STRBUF_INIT;
 
enum diff_symbol s = eds->s;
@@ -1003,7 +1016,7 @@ static void emit_diff_symbol_from_struct(struct 
diff_options *o,
context = diff_get_color_opt(o, DIFF_CONTEXT);
reset = diff_get_color_opt(o, DIFF_RESET);
putc('\n', o->file);
-   emit_line_0(o, context, reset, '\\',
+