blame: (dim rep. metadata lines or fields, decay date coloring)
v2 cover blame: (dim rep. metadata lines or fields, decay date coloring)
This is picking up [1], but presenting it in another approach, as I realized these are orthogonal features:
* dimming repeated lines/fields of information
* giving a quick visual information how old (as a proxy for 'well tested') a line of code is.
Both features are configurable.
Changes from sending it out in November:
* better commit messages
* rebased on master
Any feedback welcome.
Thanks,
Stefan
[1] https://public-inbox.org/git/[email protected]/
Stefan Beller (4):
color.h: document and modernize header builtin/blame: dim uninteresting metadata builtin/blame: add option to color metadata fields separately builtin/blame: highlight recently changed lines
Documentation/config.txt | 23 +++++ builtin/blame.c | 216 ++++++++++++++++++++++++++++++++++++++++++----- color.c | 2 - color.h | 49 ++++++++--- t/t8012-blame-colors.sh | 56 ++++++++++++ 5 files changed, 311 insertions(+), 35 deletions(-) create mode 100755 t/t8012-blame-colors.sh
Signature · 1 line
2.15.1.620.gb9897f4670-goog
PATCH v2 1/4 color.h: document and modernize header
Add documentation explaining the functions in color.h. While at it, mark them extern.
--- color.c | 2 -- color.h | 48 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 15 deletions(-)
color.c +0 -2
@@ -399,8 +399,6 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt,return r; } - -int color_fprintf (FILE *fp,const char *color,const char *fmt, ...) {va_list args;
color.h +35 -13
61 lines not on this page · raw message
Signature · 1 line
2.15.1.620.gb9897f4670-goog
Re: [PATCH 1/4] color.h: document and modernize header
Quoted 7 lines · Stefan Beller
Add documentation explaining the functions in
color.h. While at it, mark them extern.Signed-off-by Stefan Beller <[email protected]>---
color.h extern int color_stdout_is_tty; · line 77
Quoted 9 lines
color.h +3
-3@@ -72,26 +72,48 @@ extern int color_stdout_is_tty;/* -* Set the color buffer (which must be COLOR_MAXLEN bytes) -* to the raw color bytes; this is useful for initializing +* Set the color buffer `dst` (which must be COLOR_MAXLEN bytes) +* to the raw color bytes `color_bytes`; this is useful for initializing * default color variables. */ -void color_set (char *dst,const char *color_bytes); +extern void color_set (char *dst,const char *color_bytes);
I don't see an explanation of what "color bytes" are. From where does one obtain such bytes? How is this function used? The function comment does not particularly answer these questions.
color.h extern int color_stdout_is_tty; · line 89
Quoted 5 lines
color.h +5
-0+/* +* Parses a config option, which can be a boolean or one of +* "never", "auto", "always". Returns the constant for the given setting. +*/ +extern int git_config_colorbool (const char *var,const char *value);
I suppose that "constant for the given setting" means one of GIT_COLOR_NEVER , GIT_COLOR_AUTO, GIT_COLOR_ALWAYS? Perhaps say so explicitly?
Would it also make sense to say that boolean "true" ("yes", etc.) results in GIT_COLOR_ALWAYS and "false" ("no", etc.)" results in GIT_COLOR_NEVER?
Finally, for grammatical consistency with other comments:
s/Parses/Parse
s/Returns/Return/
color.h extern int color_stdout_is_tty; · line 92
Quoted 2 lines
color.h +2
-0+/* Is the output supposed to be colored? Resolve and cache the 'auto' setting */ +extern int want_color (int var);
What is the 'var' argument? How is it interpreted? (...goes and checks implementation...) I guess this documentation should explain that the caller would pass in the result of git_config_colorbool().
Also, the meaning of "Resolve and cache 'auto' setting" stumped me for a while since it's not clear why it's here (or why it's missing the full stop), but I eventually realized that it's describing an implementation detail, which probably doesn't belong in API documentation.
color.h extern int color_stdout_is_tty; · line 99
Quoted 6 lines
color.h +6
-0+/* +* Translate the human readable color string from `value` and into +* terminal color codes and store them in `dst` +*/ +extern int color_parse (const char *value,char *dst); +extern int color_parse_mem (const char *value,int len,char *dst);
What does "human readable" mean in this context? Is it talking about color names or RGB(A) tuples or what?
Also, how does the caller know how large to make 'dst'? At minimum, you should say something about COLOR_MAXLEN.
Finally, for the 'len' case, what happens if 'dst' is too small? This should be documented.
And, the return value of these functions should be discussed.
color.h extern int color_stdout_is_tty; · line 103
Quoted 3 lines
color.h +3
-0+/* +* Print the format string `fmt`, encapsulated by setting and resetting the +* color. Omits the color encapsulation if `color` is NULL.
The "encapsulated by setting and resetting the color" bit is hard to grok. Perhaps instead say something along the lines of:
Output the formatted string in the specified color (and then reset to normal color so subsequent output is uncolored).
color.h extern int color_stdout_is_tty; · line 105
Quoted 2 lines
color.h +2
-0+* The `color_fprintf_ln` prints a new line after resetting the color. +* The `color_print_strbuf` prints the given pre-formatted strbuf instead.
Should the strbuf variation warn that it only outputs content up to the first embedded NUL? (Or should that bug/misfeature be fixed?)
color.h extern int color_stdout_is_tty; · line 115
Quoted 11 lines
color.h +7
-1+*/ __attribute__((format (printf,3 ,4 ))) +extern int color_fprintf (FILE *fp,const char *color,const char *fmt, ...); __attribute__((format (printf,3 ,4 ))) +extern int color_fprintf_ln (FILE *fp,const char *color,const char *fmt, ...); +extern void color_print_strbuf (FILE *fp,const char *color,const struct strbuf *sb); -int color_is_nil (const char *color); +/* +* Check if the given color is GIT_COLOR_NIL that means "no color selected". +* The application needs to replace the color with the actual desired color.
Maybe: s/application/caller/
Quoted 2 lines
color.h +2
-0+*/ +extern int color_is_nil (const char *color);
Re: [PATCH 1/4] color.h: document and modernize header
Quoted 13 lines · Eric Sunshine
Quoted 12 lines · Stefan Beller
Add documentation explaining the functions in
color.h. While at it, mark them extern.Signed-off-by Stefan Beller <[email protected]>---
color.h +2
-2@@ -72,26 +72,48 @@ extern int color_stdout_is_tty;/* -* Set the color buffer (which must be COLOR_MAXLEN bytes) -* to the raw color bytes; this is useful for initializing +* Set the color buffer `dst` (which must be COLOR_MAXLEN bytes) +* to the raw color bytes `color_bytes`; this is useful for initializing
Quoted 8 lines
color.h extern int color_stdout_is_tty; · line 83
Quoted 4 lines
color.h +1
-1* default color variables. */ -void color_set (char *dst,const char *color_bytes); +extern void color_set (char *dst,const char *color_bytes);I don't see an explanation of what "color bytes" are. From where does one obtain such bytes? How is this function used? The function comment does not particularly answer these questions.
Right. This description is bad.
It's implementation is just
xsnprintf(dst, COLOR_MAXLEN, "%s", color_bytes);
Apparently this function is only ever used by grep.c which uses it to fill in struct grep_opt {
...
char color_context[COLOR_MAXLEN];
char color_filename[COLOR_MAXLEN];
char color_function[COLOR_MAXLEN];
char color_lineno[COLOR_MAXLEN];
char color_match_context[COLOR_MAXLEN];
char color_match_selected[COLOR_MAXLEN];
char color_selected[COLOR_MAXLEN];
char color_sep[COLOR_MAXLEN];
...
}I guess I'll drop the documentation for color_set, and put a NEEDSWORK comment there as I'd think we don't need to copy around the colors using snprintf, but either can keep pointers or use xmemdup.
Quoted 10 lines
color.h extern int color_stdout_is_tty; · line 89
Quoted 6 lines
color.h +5
-0+/* +* Parses a config option, which can be a boolean or one of +* "never", "auto", "always". Returns the constant for the given setting. +*/ +extern int git_config_colorbool (const char *var,const char *value);I suppose that "constant for the given setting" means one of
GIT_COLOR_NEVER,GIT_COLOR_AUTO,GIT_COLOR_ALWAYS? Perhaps say so explicitly?
Maybe I should fix the code as well. Currently it only returns one of 0 (=GIT_COLOR_NEVER), 1 (=GIT_COLOR_ALWAYS) and GIT_COLOR_AUTO.
Quoted 3 lines
Would it also make sense to say that boolean "true" ("yes", etc.) results in
GIT_COLOR_ALWAYSand "false" ("no", etc.)" results inGIT_COLOR_NEVER?
done.
Quoted 4 lines
Finally, for grammatical consistency with other comments:
s/Parses/Parse
s/Returns/Return/
done
Quoted 8 lines
color.h extern int color_stdout_is_tty; · line 92
Quoted 3 lines
color.h +2
-0+/* Is the output supposed to be colored? Resolve and cache the 'auto' setting */ +extern int want_color (int var);What is the 'var' argument? How is it interpreted? (...goes and checks implementation...) I guess this documentation should explain that the caller would pass in the result of
git_config_colorbool().
Quoted 5 lines
Also, the meaning of "Resolve and cache 'auto' setting" stumped me for a while since it's not clear why it's here (or why it's missing the full stop), but I eventually realized that it's describing an implementation detail, which probably doesn't belong in API documentation.
done
Quoted 23 lines
color.h extern int color_stdout_is_tty; · line 99
Quoted 7 lines
color.h +6
-0+/* +* Translate the human readable color string from `value` and into +* terminal color codes and store them in `dst` +*/ +extern int color_parse (const char *value,char *dst); +extern int color_parse_mem (const char *value,int len,char *dst);What does "human readable" mean in this context? Is it talking about color names or RGB(A) tuples or what?
Also, how does the caller know how large to make 'dst'? At minimum, you should say something about
COLOR_MAXLEN.Finally, for the 'len' case, what happens if 'dst' is too small? This should be documented.
And, the return value of these functions should be discussed.
color.h extern int color_stdout_is_tty; · line 103
Quoted 3 lines
color.h +3
-0+/* +* Print the format string `fmt`, encapsulated by setting and resetting the +* color. Omits the color encapsulation if `color` is NULL.
Quoted 6 lines
The "encapsulated by setting and resetting the color" bit is hard to grok. Perhaps instead say something along the lines of:
Output the formatted string in the specified color (and then reset to normal color so subsequent output is uncolored).
sounds good.
Quoted 6 lines
color.h extern int color_stdout_is_tty; · line 105
Quoted 3 lines
color.h +2
-0+* The `color_fprintf_ln` prints a new line after resetting the color. +* The `color_print_strbuf` prints the given pre-formatted strbuf instead. Should the strbuf variation warn that it only outputs content up to the first embedded NUL? (Or should that bug/misfeature be fixed?)
added.
Quoted 8 lines
Quoted 8 lines
color.h +4
-0+*/ __attribute__((format (printf,3 ,4 ))) +extern int color_fprintf (FILE *fp,const char *color,const char *fmt, ...); __attribute__((format (printf,3 ,4 ))) +extern int color_fprintf_ln (FILE *fp,const char *color,const char *fmt, ...); +extern void color_print_strbuf (FILE *fp,const char *color,const struct strbuf *sb);
Quoted 6 lines
color.h extern int color_stdout_is_tty; · line 115
Quoted 4 lines
color.h +3
-1-int color_is_nil (const char *color); +/* +* Check if the given color is GIT_COLOR_NIL that means "no color selected". +* The application needs to replace the color with the actual desired color. Maybe: s/application/caller/
done
Quoted 3 lines
Quoted 3 lines
color.h +2
-0+*/ +extern int color_is_nil (const char *color);
PATCH v2 2/4 builtin/blame: dim uninteresting metadata
In reply to Stefan BellerWhen using git-blame lots of lines contain redundant information, for example in hunks that consist of multiple lines, the metadata (commit name, author, date) are repeated. A reader may not be interested in those, so offer an option to color the information that is repeated from the previous line differently.
--- Documentation/config.txt | 5 ++++ builtin/blame.c | 68 ++++++++++++++++++++++++++++++++++++++---------- color.h | 1 + t/t8012-blame-colors.sh | 18 +++++++++++++ 4 files changed, 78 insertions(+), 14 deletions(-) create mode 100755 t/t8012-blame-colors.sh
Documentation/config.txt +5 -0
@@ -1216,6 +1216,11 @@ color.status.<slot>:: status short-format), or `unmerged` (files which have unmerged changes). +color.blame.repeatedMeta:: + Use the customized color for the part of git-blame output that + is repeated meta information per line (such as commit id, + author name, date and timezone). Defaults to dark gray. + color.ui:: This variable determines the default value for variables such as `color.diff` and `color.grep` that control the use of color
builtin/blame.c +54 -14
142 lines not on this page · raw message
color.h +1 -0
@@ -30,6 +30,7 @@ struct strbuf;#define GIT_COLOR_BLUE "\033[34m"#define GIT_COLOR_MAGENTA "\033[35m"#define GIT_COLOR_CYAN "\033[36m" +#define GIT_COLOR_DARK "\033[1;30m"#define GIT_COLOR_BOLD_RED "\033[1;31m"#define GIT_COLOR_BOLD_GREEN "\033[1;32m"#define GIT_COLOR_BOLD_YELLOW "\033[1;33m"
t/t8012-blame-colors.sh new file +18 -0
@@ -0,0 +1,18 @@ +#!/bin/sh + +test_description='colored git blame' +. ./test-lib.sh + +PROG='git blame -c' +. "$TEST_DIRECTORY"/annotate-tests.sh + +test_expect_success 'colored blame colors continuous lines' ' + git blame --abbrev=12 --color-lines hello.c >actual.raw && + test_decode_color <actual.raw >actual && + grep "<BOLD;BLACK>(F" actual > F.expect && + grep "<BOLD;BLACK>(H" actual > H.expect && + test_line_count = 2 F.expect && + test_line_count = 3 H.expect +' + +test_done
Signature · 1 line
2.15.1.620.gb9897f4670-goog
Re: [PATCH 2/4] builtin/blame: dim uninteresting metadata
Quoted 21 lines · Stefan Beller
When using git-blame lots of lines contain redundant information, for example in hunks that consist of multiple lines, the metadata (commit name, author, date) are repeated. A reader may not be interested in those, so offer an option to color the information that is repeated from the previous line differently.
Signed-off-by Stefan Beller <[email protected]>---
builtin/blame.c +11
-0@@ -367,6 +370,28 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, +static inline void colors_unset (const char **use_color,const char **reset_color) +{ + *use_color ="" ; + *reset_color ="" ; +} + +static inline void colors_set (const char **use_color,const char **reset_color) +{ + *use_color = repeated_meta_color; + *reset_color =GIT_COLOR_RESET ; +}
builtin/blame.c static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, · line 390
Quoted 10 lines
builtin/blame.c +10
-0+ +static void setup_line_color (int opt,int cnt, +const char **use_color, +const char **reset_color) +{ +colors_unset (use_color, reset_color); + +if ((opt &OUTPUT_COLOR_LINE ) && cnt >0 ) +colors_set (use_color, reset_color); +}
I'm not convinced that this colors_unset() / colors_set() / setup_line_color() abstraction is buying much. With this abstraction, I found the code more difficult to reason about than if the colors were just set/unset manually in the code which needs the colors. I *could* perhaps imagine setup_line_color() existing as a separate function since it is slightly more complex than the other two, but as it has only a single caller through all patches, even that may not be sufficient to warrant its existence.
builtin/blame.c static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int · line 411
Quoted 5 lines
builtin/blame.c +1
-0@@ -383,6 +408,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, intfor (cnt =0 ; cnt < ent->num_lines; cnt++) {char ch;int length = (opt &OUTPUT_LONG_OBJECT_NAME ) ?GIT_SHA1_HEXSZ : abbrev; +const char *col, *rcol;
I can't help but read these as "column" and "[r]column"; the former, especially, is just too ingrained to interpret it any other way. Perhaps call these "color" and "reset" instead?
builtin/blame.c static int git_blame_config(const char *var, const char *value, void *cb) · line 639
Quoted 5 lines
builtin/blame.c +4
-0@@ -607,6 +636,12 @@ static int git_blame_config(const char *var, const char *value, void *cb) +if (!strcmp (var,"color.blame.repeatedmeta" )) { +if (color_parse_mem (value,strlen (value), repeated_meta_color)) +warning (_ ("ignore invalid color '%s' in color.blame.repeatedMeta" ), + value);
Does this need to say "ignore"? If you drop that word, you still have a valid warning message.
builtin/blame.c int cmd_blame(int argc, const char **argv, const char *prefix) · line 719
Quoted 7 lines
builtin/blame.c +3
-0+return 0 ; + }@@ -681,6 +716,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)OPT_BIT ('s' ,NULL , &output_option,N_ ("Suppress author name and timestamp (Default: off)" ),OUTPUT_NO_AUTHOR ),OPT_BIT ('e' ,"show-email" , &output_option,N_ ("Show author email instead of name (Default: off)" ),OUTPUT_SHOW_EMAIL ),OPT_BIT ('w' ,NULL , &xdl_opts,N_ ("Ignore whitespace differences" ),XDF_IGNORE_WHITESPACE ), + OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line"), OUTPUT_COLOR_LINE),
Not sure what this help message means. Do you mean "color redundant ... _differently_ ..."? Or "_dim_ redundant..."?
t/t8012-blame-colors.sh line 9
Quoted 11 lines
t/t8012-blame-colors.sh +9
-0@@ -0,0 +1,18 @@ +#!/bin/sh + +test_description='colored git blame' +. ./test-lib.sh + +PROG='git blame -c' +. "$TEST_DIRECTORY"/annotate-tests.sh + +test_expect_success 'colored blame colors continuous lines' '
What are "continuous lines"? Did you mean "contiguous"?
Quoted 7 lines
t/t8012-blame-colors.sh +7
-0+ git blame --abbrev=12 --color-lines hello.c >actual.raw && + test_decode_color <actual.raw >actual && + grep "<BOLD;BLACK>(F" actual > F.expect && + grep "<BOLD;BLACK>(H" actual > H.expect && + test_line_count = 2 F.expect && + test_line_count = 3 H.expect +'
Re: [PATCH 2/4] builtin/blame: dim uninteresting metadata
Quoted 33 lines · Eric Sunshine
Quoted 21 lines · Stefan Beller
When using git-blame lots of lines contain redundant information, for example in hunks that consist of multiple lines, the metadata (commit name, author, date) are repeated. A reader may not be interested in those, so offer an option to color the information that is repeated from the previous line differently.
Signed-off-by Stefan Beller <[email protected]>---
builtin/blame.c +11
-0@@ -367,6 +370,28 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, +static inline void colors_unset (const char **use_color,const char **reset_color) +{ + *use_color ="" ; + *reset_color ="" ; +} + +static inline void colors_set (const char **use_color,const char **reset_color) +{ + *use_color = repeated_meta_color; + *reset_color =GIT_COLOR_RESET ; +}builtin/blame.c static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, · line 390
Quoted 10 lines
builtin/blame.c +10
-0+ +static void setup_line_color (int opt,int cnt, +const char **use_color, +const char **reset_color) +{ +colors_unset (use_color, reset_color); + +if ((opt &OUTPUT_COLOR_LINE ) && cnt >0 ) +colors_set (use_color, reset_color); +}
Quoted 8 lines
I'm not convinced that this
colors_unset()/colors_set()/setup_line_color()abstraction is buying much. With this abstraction, I found the code more difficult to reason about than if the colors were just set/unset manually in the code which needs the colors. I *could* perhaps imaginesetup_line_color()existing as a separate function since it is slightly more complex than the other two, but as it has only a single caller through all patches, even that may not be sufficient to warrant its existence.
Have you viewed this patch in context of the following patch? Originally I was convinced an abstraction was not needed, but as the next patch shows, a helper per field seems handy.
Quoted 10 lines
builtin/blame.c static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int · line 411
Quoted 6 lines
builtin/blame.c +1
-0@@ -383,6 +408,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, intfor (cnt =0 ; cnt < ent->num_lines; cnt++) {char ch;int length = (opt &OUTPUT_LONG_OBJECT_NAME ) ?GIT_SHA1_HEXSZ : abbrev; +const char *col, *rcol;I can't help but read these as "column" and "[r]column"; the former, especially, is just too ingrained to interpret it any other way. Perhaps call these "color" and "reset" instead?
will fix.
Quoted 9 lines
builtin/blame.c static int git_blame_config(const char *var, const char *value, void *cb) · line 639
Quoted 6 lines
builtin/blame.c +4
-0@@ -607,6 +636,12 @@ static int git_blame_config(const char *var, const char *value, void *cb) +if (!strcmp (var,"color.blame.repeatedmeta" )) { +if (color_parse_mem (value,strlen (value), repeated_meta_color)) +warning (_ ("ignore invalid color '%s' in color.blame.repeatedMeta" ), + value);Does this need to say "ignore"? If you drop that word, you still have a valid warning message.
dropped 'ignore'.
Quoted 11 lines
builtin/blame.c int cmd_blame(int argc, const char **argv, const char *prefix) · line 719
Quoted 8 lines
builtin/blame.c +3
-0+return 0 ; + }@@ -681,6 +716,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)OPT_BIT ('s' ,NULL , &output_option,N_ ("Suppress author name and timestamp (Default: off)" ),OUTPUT_NO_AUTHOR ),OPT_BIT ('e' ,"show-email" , &output_option,N_ ("Show author email instead of name (Default: off)" ),OUTPUT_SHOW_EMAIL ),OPT_BIT ('w' ,NULL , &xdl_opts,N_ ("Ignore whitespace differences" ),XDF_IGNORE_WHITESPACE ), + OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line"), OUTPUT_COLOR_LINE),Not sure what this help message means. Do you mean "color redundant ... _differently_ ..."? Or "_dim_ redundant..."?
Originally (in a patch set a couple months back) I had 'dim', but Junio seems to have an interesting color setup, such that he would not call it dimming IIRC, hence I think I wanted to say color _differently_. Fixed.
Quoted 5 lines
Quoted 5 lines
t/t8012-blame-colors.sh +3
-0@@ -0,0 +1,18 @@ +#!/bin/sh + +test_description='colored git blame'
Quoted 8 lines
t/t8012-blame-colors.sh line 9
Quoted 6 lines
t/t8012-blame-colors.sh +6
-0+. ./test-lib.sh + +PROG='git blame -c' +. "$TEST_DIRECTORY"/annotate-tests.sh + +test_expect_success 'colored blame colors continuous lines' 'What are "continuous lines"? Did you mean "contiguous"?
Thanks for hinting at the subtle difference!
Thanks for the review!
(I will drop the abstraction and see how it goes)
Stefan
Re: [PATCH 2/4] builtin/blame: dim uninteresting metadata
Quoted 23 lines · Stefan Beller
Quoted 13 lines · Eric Sunshine
builtin/blame.c static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, · line 383
Quoted 11 lines · Stefan Beller
builtin/blame.c +11
-0+static inline void colors_unset (const char **use_color,const char **reset_color) +{ + *use_color ="" ; + *reset_color ="" ; +} + +static inline void colors_set (const char **use_color,const char **reset_color) +{ + *use_color = repeated_meta_color; + *reset_color =GIT_COLOR_RESET ; +}Quoted 8 lines
I'm not convinced that this
colors_unset()/colors_set()/setup_line_color()abstraction is buying much. With this abstraction, I found the code more difficult to reason about than if the colors were just set/unset manually in the code which needs the colors. I *could* perhaps imaginesetup_line_color()existing as a separate function since it is slightly more complex than the other two, but as it has only a single caller through all patches, even that may not be sufficient to warrant its existence.
Quoted 3 lines
Have you viewed this patch in context of the following patch? Originally I was convinced an abstraction was not needed, but as the next patch shows, a helper per field seems handy.
I did take the other patch into consideration when making the observation, and I still found the code more difficult to reason about than if these minor bits of code had merely been inlined into the callers. I neglected to mention previously that part of the problem may be that these function names do not do a good job of conveying what is being done, thus I repeatedly had to consult the function implementations while reading callers in order to understand what was going on.
Re: [PATCH 2/4] builtin/blame: dim uninteresting metadata
Quoted 28 lines · Eric Sunshine
Quoted 23 lines · Stefan Beller
Quoted 13 lines · Eric Sunshine
builtin/blame.c static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, · line 383
Quoted 11 lines · Stefan Beller
builtin/blame.c +11
-0+static inline void colors_unset (const char **use_color,const char **reset_color) +{ + *use_color ="" ; + *reset_color ="" ; +} + +static inline void colors_set (const char **use_color,const char **reset_color) +{ + *use_color = repeated_meta_color; + *reset_color =GIT_COLOR_RESET ; +}Quoted 8 lines
I'm not convinced that this
colors_unset()/colors_set()/setup_line_color()abstraction is buying much. With this abstraction, I found the code more difficult to reason about than if the colors were just set/unset manually in the code which needs the colors. I *could* perhaps imaginesetup_line_color()existing as a separate function since it is slightly more complex than the other two, but as it has only a single caller through all patches, even that may not be sufficient to warrant its existence.Quoted 3 lines
Have you viewed this patch in context of the following patch? Originally I was convinced an abstraction was not needed, but as the next patch shows, a helper per field seems handy.
Quoted 8 lines
I did take the other patch into consideration when making the observation, and I still found the code more difficult to reason about than if these minor bits of code had merely been inlined into the callers. I neglected to mention previously that part of the problem may be that these function names do not do a good job of conveying what is being done, thus I repeatedly had to consult the function implementations while reading callers in order to understand what was going on.
I asked the question before rewriting and resending, and now I agree that we do not want to have these small helpers.
Thanks,
Stefan
PATCH v2 3/4 builtin/blame: add option to color metadata fields separately
In reply to Stefan BellerUnlike the previous commit, this dims colors for each metadata field individually.
--- builtin/blame.c | 82 +++++++++++++++++++++++++++++++++++++++++++------ t/t8012-blame-colors.sh | 38 +++++++++++++++++++++++ 2 files changed, 111 insertions(+), 9 deletions(-)
builtin/blame.c +73 -9
@@ -323,6 +323,7 @@ static const char *format_time(timestamp_t time, const char *tz_str,#define OUTPUT_SHOW_EMAIL 0400#define OUTPUT_LINE_PORCELAIN 01000#define OUTPUT_COLOR_LINE 02000 +#define OUTPUT_COLOR_FIELDS 04000static void emit_porcelain_details (struct blame_origin *suspect,int repeat) {
@@ -370,6 +371,33 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,putchar ('\n' ); } +static int had_same_field_previously (int opt,int field, +struct blame_entry *ent, +struct blame_entry *prev) +{ +struct commit_info ci, prev_ci; + +switch (field) { +case OUTPUT_SHOW_SCORE : +return ent->score == prev->score; +case OUTPUT_SHOW_NAME : +return prev->suspect && + !strcmp (ent->suspect->path, prev->suspect->path); +case OUTPUT_SHOW_NUMBER : +return ent->s_lno == prev->s_lno + prev->num_lines -1 ; + +case OUTPUT_NO_AUTHOR : +get_commit_info (ent->suspect->commit, &ci,1 ); +get_commit_info (prev->suspect->commit, &prev_ci,1 ); +return ((opt &OUTPUT_SHOW_EMAIL ) && + !strcmp (ci.author_mail.buf, prev_ci.author_mail.buf)) || + !strcmp (ci.author.buf, prev_ci.author.buf); +default : +BUG ("unknown field" ); + } +return 0 ; +} +static inline void colors_unset (const char **use_color,const char **reset_color) { *use_color ="" ;
@@ -382,17 +410,36 @@ static inline void colors_set(const char **use_color, const char **reset_color) *reset_color =GIT_COLOR_RESET ; } +static void setup_field_color (int opt,int cnt,int field, +struct blame_entry *ent, +struct blame_entry *prev, +const char **use_color, +const char **reset_color) +{ +if (!(opt &OUTPUT_COLOR_FIELDS )) +return ; + +if ((cnt >0 || + (prev &&had_same_field_previously (opt, field, ent, prev)))) +colors_set (use_color, reset_color); +else +colors_unset (use_color, reset_color); +} +static void setup_line_color (int opt,int cnt,const char **use_color,const char **reset_color) {colors_unset (use_color, reset_color); -if ((opt &OUTPUT_COLOR_LINE ) && cnt >0 ) +if ((opt & (OUTPUT_COLOR_LINE |OUTPUT_COLOR_FIELDS )) && cnt >0 )colors_set (use_color, reset_color); } -static void emit_other (struct blame_scoreboard *sb,struct blame_entry *ent,int opt) +static void emit_other (struct blame_scoreboard *sb, +struct blame_entry *ent, +struct blame_entry *prev, +int opt) {int cnt;const char *cp;
@@ -432,18 +479,27 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int show_raw_time), ent->lno + 1 + cnt); }else { -if (opt &OUTPUT_SHOW_SCORE ) +if (opt &OUTPUT_SHOW_SCORE ) { +setup_field_color (opt, cnt,OUTPUT_SHOW_SCORE , + ent, prev, &col, &rcol);printf (" %s%*d %02d%s" , col, max_score_digits, ent->score, ent->suspect->refcnt, rcol); -if (opt &OUTPUT_SHOW_NAME ) + } +if (opt &OUTPUT_SHOW_NAME ) { +setup_field_color (opt, cnt,OUTPUT_SHOW_NAME , + ent, prev, &col, &rcol);printf (" %s%-*.*s%s" , col, longest_file, longest_file, suspect->path, rcol); -if (opt &OUTPUT_SHOW_NUMBER ) + } +if (opt &OUTPUT_SHOW_NUMBER ) { +setup_field_color (opt, cnt,OUTPUT_SHOW_NUMBER , + ent, prev, &col, &rcol);printf (" %s%*d%s" , col, max_orig_digits, ent->s_lno +1 + cnt, rcol); + }if (!(opt &OUTPUT_NO_AUTHOR )) {const char *name;int pad;
@@ -452,6 +508,8 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, intelse name = ci.author.buf; pad = longest_author -utf8_strwidth (name); +setup_field_color (opt, cnt,OUTPUT_NO_AUTHOR , + ent, prev, &col, &rcol); printf(" %s(%s%*s %10s%s", col, name, pad, "", format_time(ci.author_time,
@@ -477,7 +535,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, intstatic void output (struct blame_scoreboard *sb,int option) { -struct blame_entry *ent; +struct blame_entry *ent, *prev =NULL ;if (option &OUTPUT_PORCELAIN ) {for (ent = sb->ent; ent; ent = ent->next) {
@@ -499,7 +557,8 @@ static void output(struct blame_scoreboard *sb, int option)if (option &OUTPUT_PORCELAIN )emit_porcelain (sb, ent, option);else { -emit_other (sb, ent, option); +emit_other (sb, ent, prev, option); + prev = ent; } } }
@@ -717,6 +776,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)OPT_BIT ('e' ,"show-email" , &output_option,N_ ("Show author email instead of name (Default: off)" ),OUTPUT_SHOW_EMAIL ),OPT_BIT ('w' ,NULL , &xdl_opts,N_ ("Ignore whitespace differences" ),XDF_IGNORE_WHITESPACE ),OPT_BIT (0 ,"color-lines" , &output_option,N_ ("color redundant metadata from previous line" ),OUTPUT_COLOR_LINE ), + OPT_BIT(0, "color-fields", &output_option, N_("color redundant metadata fields from previous line"), OUTPUT_COLOR_FIELDS),/* * The following two options are parsed by parse_revision_opt()
@@ -775,6 +835,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix) revs.diffopt.flags.follow_renames =0 ; argc =parse_options_end (&ctx); +if ((output_option &OUTPUT_COLOR_LINE ) && + (output_option &OUTPUT_COLOR_FIELDS )) +die (_ ("cannot ask for colored lines and fields at the same time" )); +if (incremental || (output_option &OUTPUT_PORCELAIN )) {if (show_progress >0 )die (_ ("--progress can't be used with --incremental or porcelain formats" ));
@@ -978,8 +1042,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)if (!(output_option &OUTPUT_PORCELAIN )) {find_alignment (&sb, &output_option); -if ((output_option &OUTPUT_COLOR_LINE ) && - !repeated_meta_color) +if (!repeated_meta_color && + (output_option & (OUTPUT_COLOR_LINE |OUTPUT_COLOR_FIELDS ))) repeated_meta_color =GIT_COLOR_DARK ; }
t/t8012-blame-colors.sh +38 -0
@@ -15,4 +15,42 @@ test_expect_success 'colored blame colors continuous lines' ' test_line_count = 3 H.expect ' +test_expect_success 'colored blame colors continuous fields' ' + + git mv hello.c world.c && + git commit -a -m "moved file" && + cat <<-EOF >> world.c && + void world() + { + puts("world"); + } + EOF + git add world.c && + GIT_AUTHOR_NAME="F" GIT_AUTHOR_EMAIL="[email protected]" \ + git commit -m "forgot to add changes to moved file" && + + git blame --abbrev=12 --color-fields world.c >actual.raw && + test_decode_color <actual.raw >actual && + + grep "<BOLD;BLACK>hello.c" actual > colored_hello.expect && + grep "hello.c" actual > all_hello.expect && + test_line_count = 9 colored_hello.expect && + test_line_count = 10 all_hello.expect && + + grep "<BOLD;BLACK>world.c" actual > colored_world.expect && + grep "world.c" actual > all_world.expect && + test_line_count = 3 colored_world.expect && + test_line_count = 4 all_world.expect && + + grep "(F" actual > all_F.expect && + grep "<BOLD;BLACK>(F" actual > colored_F.expect && + test_line_count = 8 all_F.expect && + test_line_count = 5 colored_F.expect && + + grep "(H" actual > all_H.expect && + grep "<BOLD;BLACK>(H" actual > colored_H.expect && + test_line_count = 5 all_H.expect && + test_line_count = 3 colored_H.expect +' + test_done
Signature · 1 line
2.15.1.620.gb9897f4670-goog
PATCH v2 4/4 builtin/blame: highlight recently changed lines
In reply to Stefan BellerChoose a different color for dates and imitate a 'temperature cool down' for the dates.
Originally I had planned to have the temperature cooldown dependent on the age of the project or file for example, as that might scale better, but that can be added on top of this commit, e.g. instead of giving a date, you could imagine giving a percentage that would be the linearly interpolated between now and the beginning of the file.
--- Documentation/config.txt | 18 ++++++++++++ builtin/blame.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-)
Documentation/config.txt +18 -0
@@ -1221,6 +1221,24 @@ color.blame.repeatedMeta:: is repeated meta information per line (such as commit id, author name, date and timezone). Defaults to dark gray. +color.blame.highlightRecent:: + This can be used to color the author and date of a blame line. + This overrides `color.blame.repeatedMeta` setting, which colors + repetitions. ++ +This setting should be set to a comma-separated list of color and date settings, +starting and ending with a color, the dates should be set from oldest to newest. +The metadata will be colored given the colors if the the line was introduced +before the given timestamp, overwriting older timestamped colors. ++ +Instead of an absolute timestamp relative timestamps work as well, e.g. +2.weeks.ago is valid to address anything older than 2 weeks. ++ +It defaults to "blue,12 month ago,white,1 month ago,red", which colors +everything older than one year blue, recent changes between one month and +one year old are kept white, and lines introduced within the last month are +colored red. + color.ui:: This variable determines the default value for variables such as `color.diff` and `color.grep` that control the use of color
builtin/blame.c +73 -1
134 lines not on this page · raw message
Signature · 1 line
2.15.1.620.gb9897f4670-goog
Re: [PATCH 4/4] builtin/blame: highlight recently changed lines
Quoted 2 lines · Stefan Beller
Choose a different color for dates and imitate a 'temperature cool down' for the dates.
s/for the dates/depending upon age/
builtin/blame.c int cmd_blame(int argc, const char **argv, const char *prefix) · line 847
Quoted 6 lines
[...]Signed-off-by Stefan Beller <[email protected]>---
builtin/blame.c +1
-0@@ -777,6 +847,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) + OPT_BIT(0, "heated-lines", &output_option, N_("color lines by date"), OUTPUT_HEATED_LINES),
s/date/age/