{"thread":{"id":"18227","subject":"[PATCH 2/2] grep Added --blame so that grep can show result tagged with blame entries","startedAt":"2009-03-09T13:20:35Z","lastAt":"2009-03-09T21:22:39Z","messageCount":2,"participants":["pi song","René Scharfe"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"107454","messageId":"49B517A3.9050209@gmail.com","threadId":"18227","inReplyTo":null,"subject":"[PATCH 2/2] grep Added --blame so that grep can show result tagged with blame entries","fromName":"pi song","fromEmail":"pi.songs@gmail.com","sentAt":"2009-03-09T13:20:35Z","receivedAt":"2009-03-09T13:20:35Z","isPatch":true,"sender":{"key":"pi.songs@gmail.com","avatar":null},"body":"This part:-\n1) Implementation & man for grep --blame option\n\nSigned-off-by: Pi Song <pi.songs@gmail.com>\n---\n Documentation/git-grep.txt |    5 ++\n builtin-grep.c             |   10 ++++-\n grep.c                     |   98 \n++++++++++++++++++++++++++++++++++++-------\n grep.h                     |    1 +\n 4 files changed, 96 insertions(+), 18 deletions(-)\n\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 553da6c..23dae7f 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -18,6 +18,7 @@ SYNOPSIS\n        [-z | --null]\n        [-c | --count] [--all-match]\n        [-A <post-context>] [-B <pre-context>] [-C <context>]\n+       [-b | --blame ]\n        [-f <file>] [-e] <pattern>\n        [--and|--or|--not|(|)|-e <pattern>...] [<tree>...]\n        [--] [<path>...]\n@@ -105,6 +106,10 @@ OPTIONS\n     Instead of showing every matched line, show the number of\n     lines that match.\n \n+-b::\n+--blame::\n+    Show blame of every matched line and context\n+\n -[ABC] <context>::\n     Show `context` trailing (`A` -- after), or leading (`B`\n     -- before), or both (`C` -- context) lines, and place a\ndiff --git a/builtin-grep.c b/builtin-grep.c\nindex 3f12ba3..c6cffa0 100644\n--- a/builtin-grep.c\n+++ b/builtin-grep.c\n@@ -630,6 +630,11 @@ int cmd_grep(int argc, const char **argv, const \nchar *prefix)\n             opt.word_regexp = 1;\n             continue;\n         }\n+                if (!strcmp(\"-b\", arg) ||\n+            !strcmp(\"--blame\", arg)) {\n+            opt.include_blame = 1;\n+            continue;\n+        }\n         if (!prefixcmp(arg, \"-A\") ||\n             !prefixcmp(arg, \"-B\") ||\n             !prefixcmp(arg, \"-C\") ||\ndiff --git a/grep.c b/grep.c\nindex 062b2b6..0514384 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1,3 +1,4 @@\n+#include \"blame.h\"\n #include \"cache.h\"\n #include \"grep.h\"\n #include \"xdiff-interface.h\"\n@@ -252,14 +253,17 @@ static int word_char(char ch)\n }\n \n static void show_line(struct grep_opt *opt, const char *bol, const char \n*eol,\n-              const char *name, unsigned lno, char sign)\n+              const char *name, unsigned lno, char sign,\n+                      char sign2, char* suspect)\n {\n     if (opt->null_following_name)\n         sign = '\\0';\n     if (opt->pathname)\n         printf(\"%s%c\", name, sign);\n+        if ((opt->include_blame) && (suspect!=NULL))\n+        printf(\"%s%c\", suspect);\n     if (opt->linenum)\n-        printf(\"%d%c\", lno, sign);\n+        printf(\"%d%c\", lno, sign2);\n     printf(\"%.*s\\n\", (int)(eol-bol), bol);\n }\n \n@@ -442,6 +446,14 @@ static int match_line(struct grep_opt *opt, char \n*bol, char *eol,\n     return 0;\n }\n \n+static int setup_revision_by_revId(char *revId, struct rev_info *revs)\n+{\n+    const char *args[] = {\"grep\", revId};\n+    init_revisions(revs, NULL);\n+    setup_revisions(2, args, revs, NULL);\n+    return 1 ;\n+};\n+\n static int grep_buffer_1(struct grep_opt *opt, const char *name,\n              char *buf, unsigned long size, int collect_hits)\n {\n@@ -457,6 +469,7 @@ static int grep_buffer_1(struct grep_opt *opt, const \nchar *name,\n     int binary_match_only = 0;\n     const char *hunk_mark = \"\";\n     unsigned count = 0;\n+        int blame_calculated = 0 ;\n     enum grep_context ctx = GREP_CONTEXT_HEAD;\n \n     if (buffer_is_binary(buf, size)) {\n@@ -477,6 +490,8 @@ static int grep_buffer_1(struct grep_opt *opt, const \nchar *name,\n     if (opt->pre_context || opt->post_context)\n         hunk_mark = \"--\\n\";\n \n+        /* List of blame tags */\n+        struct blame_tag *blame_tags  = NULL;\n     while (left) {\n         char *eol, ch;\n         int hit;\n@@ -505,6 +520,35 @@ static int grep_buffer_1(struct grep_opt *opt, \nconst char *name,\n                 return 0;\n             goto next_line;\n         }\n+\n+                /* Calculate blame if necessary */\n+                if (hit && opt->include_blame && !blame_calculated)\n+                {\n+                    struct blame_stat blame_stat ;\n+                    struct rev_info revs;\n+                    char filename[128] ;\n+                    char revId[41] ;\n+                    char *splitterPtr ;\n+                   \n+                    if ((splitterPtr=strstr(name, \":\")) != NULL)\n+                    {\n+                        strcpy(filename, splitterPtr + 1) ;\n+                        strncpy(revId, name, splitterPtr - name) ;\n+                        revId[40] = '\\0' ;\n+                        setup_revision_by_revId(revId, &revs) ;\n+                    }\n+                    else\n+                    {\n+                        const char *args[] = {};\n+                        strcpy(filename, name) ;\n+                        init_revisions(&revs, NULL);\n+                        setup_revisions(0, args, &revs, NULL);\n+                    }\n+\n+                    blame_tags = retrieve_blame_tags(&revs, \n&blame_stat, filename) ;\n+                    blame_calculated = 1 ;\n+                }\n+\n         if (hit) {\n             count++;\n             if (opt->status_only)\n@@ -533,30 +577,47 @@ static int grep_buffer_1(struct grep_opt *opt, \nconst char *name,\n                     from = last_shown + 1;\n                 if (last_shown && from != last_shown + 1)\n                     fputs(hunk_mark, stdout);\n-                while (from < lno) {\n+\n+                                /* This prints the precontext*/\n+                while (from < lno)\n+                                {\n                     pcl = &prev[lno-from-1];\n                     show_line(opt, pcl->bol, pcl->eol,\n-                          name, from, '-');\n+                          name, from, ':', '-',\n+                                                  blame_tags==NULL?\n+                                                  NULL: \nblame_tags[from-1].author);\n                     from++;\n                 }\n                 last_shown = lno-1;\n             }\n             if (last_shown && lno != last_shown + 1)\n                 fputs(hunk_mark, stdout);\n-            if (!opt->count)\n-                show_line(opt, bol, eol, name, lno, ':');\n+\n+            if (!opt->count) {\n+                                /* The matching line */\n+                                show_line(opt, bol, eol, name, lno,\n+                                          ':', ':',\n+                                        blame_tags==NULL?\n+                                        NULL:blame_tags[lno-1].author);\n+                        }\n+               \n             last_shown = last_hit = lno;\n         }\n-        else if (last_hit &&\n-             lno <= last_hit + opt->post_context) {\n-            /* If the last hit is within the post context,\n-             * we need to show this line.\n-             */\n-            if (last_shown && lno != last_shown + 1)\n-                fputs(hunk_mark, stdout);\n-            show_line(opt, bol, eol, name, lno, '-');\n-            last_shown = lno;\n-        }\n+                else if (last_hit && lno <= last_hit + opt->post_context)\n+                {\n+                            /* If the last hit is within the post context,\n+                             * we need to show this line.\n+                             */\n+                            if (last_shown && lno != last_shown + 1)\n+                                    fputs(hunk_mark, stdout);\n+\n+                            show_line(opt, bol, eol, name, lno, ':', '-',\n+                                     blame_tags==NULL?\n+                                     NULL:blame_tags[lno-1].author);\n+                           \n+                            last_shown = lno;\n+                }\n+\n         if (opt->pre_context) {\n             memmove(prev+1, prev,\n                 (opt->pre_context-1) * sizeof(*prev));\n@@ -572,6 +633,11 @@ static int grep_buffer_1(struct grep_opt *opt, \nconst char *name,\n         lno++;\n     }\n \n+        if (blame_calculated)\n+        {\n+                free(blame_tags) ;\n+        }\n+\n     free(prev);\n     if (collect_hits)\n         return 0;\ndiff --git a/grep.h b/grep.h\nindex 5102ce3..2e12e03 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -79,6 +79,7 @@ struct grep_opt {\n     int regflags;\n     unsigned pre_context;\n     unsigned post_context;\n+        unsigned include_blame;\n };\n \n extern void append_grep_pattern(struct grep_opt *opt, const char *pat, \nconst char *origin, int no, enum grep_pat_token t);\n-- \n1.5.4.3\n"},{"id":"107506","messageId":"49B5889F.9060902@lsrfire.ath.cx","threadId":"18227","inReplyTo":"49B517A3.9050209@gmail.com","subject":"Re: [PATCH 2/2] grep Added --blame so that grep can show result tagged with blame entries","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2009-03-09T21:22:39Z","receivedAt":"2009-03-09T21:22:39Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"pi song schrieb:\n> This part:-\n> 1) Implementation & man for grep --blame option\n\nI read the list via Gmane and I can't find patch 1/2.  But if this here\nis part 1, perhaps there is no \"1/2\"?\n\n> \n> Signed-off-by: Pi Song <pi.songs@gmail.com>\n> ---\n> Documentation/git-grep.txt |    5 ++\n> builtin-grep.c             |   10 ++++-\n> grep.c                     |   98\n> ++++++++++++++++++++++++++++++++++++-------\n> grep.h                     |    1 +\n> 4 files changed, 96 insertions(+), 18 deletions(-)\n> \n> diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\n> index 553da6c..23dae7f 100644\n> --- a/Documentation/git-grep.txt\n> +++ b/Documentation/git-grep.txt\n> @@ -18,6 +18,7 @@ SYNOPSIS\n>        [-z | --null]\n>        [-c | --count] [--all-match]\n>        [-A <post-context>] [-B <pre-context>] [-C <context>]\n> +       [-b | --blame ]\n\nYour mailer seems to have butchered all tabs.  There is a paragraph in\nDocumentation/SubmittingPatches about Gmail; seeing your email address I\nthink it might interest you.\n\n>        [-f <file>] [-e] <pattern>\n>        [--and|--or|--not|(|)|-e <pattern>...] [<tree>...]\n>        [--] [<path>...]\n> @@ -105,6 +106,10 @@ OPTIONS\n>     Instead of showing every matched line, show the number of\n>     lines that match.\n> \n> +-b::\n> +--blame::\n> +    Show blame of every matched line and context\n> +\n\nSounds interesting and useful.\n\n> -[ABC] <context>::\n>     Show `context` trailing (`A` -- after), or leading (`B`\n>     -- before), or both (`C` -- context) lines, and place a\n> diff --git a/builtin-grep.c b/builtin-grep.c\n> index 3f12ba3..c6cffa0 100644\n> --- a/builtin-grep.c\n> +++ b/builtin-grep.c\n> @@ -630,6 +630,11 @@ int cmd_grep(int argc, const char **argv, const\n> char *prefix)\n>             opt.word_regexp = 1;\n>             continue;\n>         }\n> +                if (!strcmp(\"-b\", arg) ||\n> +            !strcmp(\"--blame\", arg)) {\n> +            opt.include_blame = 1;\n> +            continue;\n> +        }\n>         if (!prefixcmp(arg, \"-A\") ||\n>             !prefixcmp(arg, \"-B\") ||\n>             !prefixcmp(arg, \"-C\") ||\n> diff --git a/grep.c b/grep.c\n> index 062b2b6..0514384 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -1,3 +1,4 @@\n> +#include \"blame.h\"\n> #include \"cache.h\"\n> #include \"grep.h\"\n> #include \"xdiff-interface.h\"\n> @@ -252,14 +253,17 @@ static int word_char(char ch)\n> }\n> \n> static void show_line(struct grep_opt *opt, const char *bol, const char\n> *eol,\n> -              const char *name, unsigned lno, char sign)\n> +              const char *name, unsigned lno, char sign,\n> +                      char sign2, char* suspect)\n> {\n>     if (opt->null_following_name)\n>         sign = '\\0';\n>     if (opt->pathname)\n>         printf(\"%s%c\", name, sign);\n> +        if ((opt->include_blame) && (suspect!=NULL))\n> +        printf(\"%s%c\", suspect);\n>     if (opt->linenum)\n> -        printf(\"%d%c\", lno, sign);\n> +        printf(\"%d%c\", lno, sign2);\n>     printf(\"%.*s\\n\", (int)(eol-bol), bol);\n> }\n\nPlease be aware of recent changes to that code to add match coloring (in\nnext and pu).  Could you please rebase your changes on top of next?\n\n> \n> @@ -442,6 +446,14 @@ static int match_line(struct grep_opt *opt, char\n> *bol, char *eol,\n>     return 0;\n> }\n> \n> +static int setup_revision_by_revId(char *revId, struct rev_info *revs)\n> +{\n> +    const char *args[] = {\"grep\", revId};\n> +    init_revisions(revs, NULL);\n> +    setup_revisions(2, args, revs, NULL);\n> +    return 1 ;\n> +};\n> +\n> static int grep_buffer_1(struct grep_opt *opt, const char *name,\n>              char *buf, unsigned long size, int collect_hits)\n> {\n> @@ -457,6 +469,7 @@ static int grep_buffer_1(struct grep_opt *opt, const\n> char *name,\n>     int binary_match_only = 0;\n>     const char *hunk_mark = \"\";\n>     unsigned count = 0;\n> +        int blame_calculated = 0 ;\n>     enum grep_context ctx = GREP_CONTEXT_HEAD;\n> \n>     if (buffer_is_binary(buf, size)) {\n> @@ -477,6 +490,8 @@ static int grep_buffer_1(struct grep_opt *opt, const\n> char *name,\n>     if (opt->pre_context || opt->post_context)\n>         hunk_mark = \"--\\n\";\n> \n> +        /* List of blame tags */\n> +        struct blame_tag *blame_tags  = NULL;\n\nPlease put declarations at the start of a block to make the code\ncompatible with older (non-C99) compilers.\n\n>     while (left) {\n>         char *eol, ch;\n>         int hit;\n> @@ -505,6 +520,35 @@ static int grep_buffer_1(struct grep_opt *opt,\n> const char *name,\n>                 return 0;\n>             goto next_line;\n>         }\n> +\n> +                /* Calculate blame if necessary */\n> +                if (hit && opt->include_blame && !blame_calculated)\n> +                {\n\nStyle:\n\tif (condition) {\n\t\n> +                    struct blame_stat blame_stat ;\n> +                    struct rev_info revs;\n> +                    char filename[128] ;\n> +                    char revId[41] ;\n> +                    char *splitterPtr ;\n> +                   +                    if ((splitterPtr=strstr(name,\n> \":\")) != NULL)\n> +                    {\n> +                        strcpy(filename, splitterPtr + 1) ;\n> +                        strncpy(revId, name, splitterPtr - name) ;\n> +                        revId[40] = '\\0' ;\n> +                        setup_revision_by_revId(revId, &revs) ;\n> +                    }\n> +                    else\n> +                    {\n\nStyle:\n\t} else {\n\n> +                        const char *args[] = {};\n> +                        strcpy(filename, name) ;\n> +                        init_revisions(&revs, NULL);\n> +                        setup_revisions(0, args, &revs, NULL);\n> +                    }\n> +\n> +                    blame_tags = retrieve_blame_tags(&revs,\n> &blame_stat, filename) ;\n\nretrieve_blame_tags() doesn't exist currently, so I guess it is\nintroduced in patch 1/2.\n\n> +                    blame_calculated = 1 ;\n> +                }\n> +\n>         if (hit) {\n>             count++;\n>             if (opt->status_only)\n> @@ -533,30 +577,47 @@ static int grep_buffer_1(struct grep_opt *opt,\n> const char *name,\n>                     from = last_shown + 1;\n>                 if (last_shown && from != last_shown + 1)\n>                     fputs(hunk_mark, stdout);\n> -                while (from < lno) {\n> +\n> +                                /* This prints the precontext*/\n> +                while (from < lno)\n> +                                {\n\nStyle:\n\twhile (condition) {\n\n>                     pcl = &prev[lno-from-1];\n>                     show_line(opt, pcl->bol, pcl->eol,\n> -                          name, from, '-');\n> +                          name, from, ':', '-',\n> +                                                  blame_tags==NULL?\n> +                                                  NULL:\n> blame_tags[from-1].author);\n>                     from++;\n>                 }\n>                 last_shown = lno-1;\n>             }\n>             if (last_shown && lno != last_shown + 1)\n>                 fputs(hunk_mark, stdout);\n> -            if (!opt->count)\n> -                show_line(opt, bol, eol, name, lno, ':');\n> +\n> +            if (!opt->count) {\n> +                                /* The matching line */\n> +                                show_line(opt, bol, eol, name, lno,\n> +                                          ':', ':',\n> +                                        blame_tags==NULL?\n> +                                        NULL:blame_tags[lno-1].author);\n> +                        }\n> +                           last_shown = last_hit = lno;\n>         }\n> -        else if (last_hit &&\n> -             lno <= last_hit + opt->post_context) {\n> -            /* If the last hit is within the post context,\n> -             * we need to show this line.\n> -             */\n> -            if (last_shown && lno != last_shown + 1)\n> -                fputs(hunk_mark, stdout);\n> -            show_line(opt, bol, eol, name, lno, '-');\n> -            last_shown = lno;\n> -        }\n> +                else if (last_hit && lno <= last_hit + opt->post_context)\n> +                {\n> +                            /* If the last hit is within the post context,\n> +                             * we need to show this line.\n> +                             */\n> +                            if (last_shown && lno != last_shown + 1)\n> +                                    fputs(hunk_mark, stdout);\n> +\n> +                            show_line(opt, bol, eol, name, lno, ':', '-',\n> +                                     blame_tags==NULL?\n> +                                     NULL:blame_tags[lno-1].author);\n> +                           +                            last_shown = lno;\n> +                }\n> +\n>         if (opt->pre_context) {\n>             memmove(prev+1, prev,\n>                 (opt->pre_context-1) * sizeof(*prev));\n> @@ -572,6 +633,11 @@ static int grep_buffer_1(struct grep_opt *opt,\n> const char *name,\n>         lno++;\n>     }\n> \n> +        if (blame_calculated)\n> +        {\n> +                free(blame_tags) ;\n> +        }\n> +\n\nStyle:\n\tif (condition)\n\t\tsingle_line_expression;\n\n>     free(prev);\n>     if (collect_hits)\n>         return 0;\n> diff --git a/grep.h b/grep.h\n> index 5102ce3..2e12e03 100644\n> --- a/grep.h\n> +++ b/grep.h\n> @@ -79,6 +79,7 @@ struct grep_opt {\n>     int regflags;\n>     unsigned pre_context;\n>     unsigned post_context;\n> +        unsigned include_blame;\n> };\n> \n> extern void append_grep_pattern(struct grep_opt *opt, const char *pat,\n> const char *origin, int no, enum grep_pat_token t);\n"}]}