{"thread":{"id":"30059","subject":"[PATCH 3/4] grep: move code to print hunk markers after heading","startedAt":"2012-03-26T02:41:41Z","lastAt":"2012-03-27T05:31:26Z","messageCount":15,"participants":["Mark Lodato","Junio C Hamano","René Scharfe","Bert Wesarg"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"187700","messageId":"1332729705-9283-1-git-send-email-lodatom@gmail.com","threadId":"30059","inReplyTo":null,"subject":"[PATCH 0/4] grep: add more information to hunk separators","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2012-03-26T02:41:41Z","receivedAt":"2012-03-26T02:41:41Z","isPatch":true,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"This patch series adds a new `grep --hunk-heading' option that moves the\nfilename and line number to the hunk separator lines (\"--\") rather than at the\nbeginning of each matching (or context) line.  In my opinion, this makes the\noutput easier to read, especially when combined with `--heading'.\n\nI am not sure that \"hunk-heading\" is the best term, so I welcome ideas on\nbetter names.\n\nHere's an example:\n\n    # Current behavior:\n    $ git grep -p -C1 -n list_common -- git.c\n    git.c=531=int main(int argc, const char **argv)\n    --\n    git.c-570-              printf(\"usage: %s\\n\\n\", git_usage_string);\n    git.c:571:              list_common_cmds_help();\n    git.c-572-              printf(\"\\n%s\\n\", git_more_info_string);\n\n    # New option:\n    $ git grep -p -C1 --hunk-heading list_common -- git.c\n    -- git.c:531 --\n    int main(int argc, char argv)\n    -- git.c:570 --\n                    printf(\"usage: %s\\n\\n\", git_usage_string);\n                    list_common_cmds_help();\n                    printf(\"\\n%s\\n\", git_more_info_string);\n\n    # New option with --heading:\n    $ git grep -p -C1 --hunk-heading --heading list_common -- git.c\n    git.c\n    -- 531 --\n    int main(int argc, char argv)\n    -- 570 --\n                    printf(\"usage: %s\\n\\n\", git_usage_string);\n                    list_common_cmds_help();\n                    printf(\"\\n%s\\n\", git_more_info_string);\n\nOriginally, I had envisioned also moving the function name (`-p') to the hunk\nheader, similar to the diff context line.  For example:\n\n    -- git.c:570 -- int main(int argc, char argv)\n                    printf(\"usage: %s\\n\\n\", git_usage_string);\n                    list_common_cmds_help();\n                    printf(\"\\n%s\\n\", git_more_info_string);\n\nAfter implementing this feature, I was not happy with the result and\nsubsequently removed it.  To me, the output was too cluttered and the line\nnumber was ambigous.  For example, in the above, it is not obvious to me that\nline 570 is the \"printf\" line and not the \"int main\" line.  Still, if you\nwould like to see the patch to implement this feature, please let me know.\n\n\nMark Lodato (4):\n  grep doc: add --break / --heading / -W to synopsis\n  add tests for grep --heading with context\n  grep: move code to print hunk markers after heading\n  grep: add --hunk-heading option\n\n Documentation/config.txt     |    3 +\n Documentation/git-grep.txt   |   10 +++\n builtin/grep.c               |   10 ++-\n grep.c                       |   49 ++++++++----\n grep.h                       |    1 +\n t/t7810-grep.sh              |   37 +++++++++\n t/t7812-grep-hunk-heading.sh |  181 ++++++++++++++++++++++++++++++++++++++++++\n 7 files changed, 276 insertions(+), 15 deletions(-)\n create mode 100755 t/t7812-grep-hunk-heading.sh\n\n-- \n1.7.9.2\n"},{"id":"187701","messageId":"1332729705-9283-2-git-send-email-lodatom@gmail.com","threadId":"30059","inReplyTo":"1332729705-9283-1-git-send-email-lodatom@gmail.com","subject":"[PATCH 1/4] grep doc: add --break / --heading / -W to synopsis","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2012-03-26T02:41:42Z","receivedAt":"2012-03-26T02:41:42Z","isPatch":true,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"All of the other options were included in the synopsis, so it makes\nsense to include these as well.\n\nSigned-off-by: Mark Lodato <lodatom@gmail.com>\n---\n Documentation/git-grep.txt |    2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 6a8b1e3..343eadd 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -20,7 +20,9 @@ SYNOPSIS\n \t   [-c | --count] [--all-match] [-q | --quiet]\n \t   [--max-depth <depth>]\n \t   [--color[=<when>] | --no-color]\n+\t   [--break] [--heading] [-p | --show-function]\n \t   [-A <post-context>] [-B <pre-context>] [-C <context>]\n+\t   [-W | --function-context]\n \t   [-f <file>] [-e] <pattern>\n \t   [--and|--or|--not|(|)|-e <pattern>...]\n \t   [ [--exclude-standard] [--cached | --no-index | --untracked] | <tree>...]\n-- \n1.7.9.2\n"},{"id":"187702","messageId":"1332729705-9283-3-git-send-email-lodatom@gmail.com","threadId":"30059","inReplyTo":"1332729705-9283-1-git-send-email-lodatom@gmail.com","subject":"[PATCH 2/4] add tests for grep --heading with context","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2012-03-26T02:41:43Z","receivedAt":"2012-03-26T02:41:43Z","isPatch":true,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"It is easy to make a mistake in the logic that conditionally prints out\nhunk separators in the various combinations of --heading, --break,\nand --context.\n\nSigned-off-by: Mark Lodato <lodatom@gmail.com>\n---\n t/t7810-grep.sh |   37 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 37 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex d9ad633..58c0821 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -901,6 +901,43 @@ test_expect_success 'mimic ack-grep --group' '\n '\n \n cat >expected <<EOF\n+hello.c\n+int main(int argc, const char **argv)\n+{\n+--\n+\t/* char ?? */\n+}\n+--\n+hello_world\n+Hello_world\n+HeLLo_world\n+EOF\n+\n+test_expect_success 'grep --heading with context' '\n+\tgit grep --heading -A1 -e char -e lo_w hello.c hello_world >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+hello.c\n+int main(int argc, const char **argv)\n+{\n+--\n+\t/* char ?? */\n+}\n+\n+hello_world\n+Hello_world\n+HeLLo_world\n+EOF\n+\n+test_expect_success 'grep --break --heading with context' '\n+\tgit grep --break --heading -A1 \\\n+\t\t-e char -e lo_w hello.c hello_world >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n space: line with leading space1\n space: line with leading space2\n space: line with leading space3\n-- \n1.7.9.2\n"},{"id":"187699","messageId":"1332729705-9283-4-git-send-email-lodatom@gmail.com","threadId":"30059","inReplyTo":"1332729705-9283-1-git-send-email-lodatom@gmail.com","subject":"[PATCH 3/4] grep: move code to print hunk markers after heading","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2012-03-26T02:41:44Z","receivedAt":"2012-03-26T02:41:44Z","isPatch":true,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"This commit does not have any effect on the output of the program.\nThe purpose is to distinguish in the code between two kinds of hunk\nseparators: those that occur before the heading and those that occur\nafter.  This step is necessary for the next commit, which will modify\nonly the latter tyep of hunk separators.\n\nSigned-off-by: Mark Lodato <lodatom@gmail.com>\n---\n grep.c |   25 +++++++++++++------------\n 1 file changed, 13 insertions(+), 12 deletions(-)\n\ndiff --git a/grep.c b/grep.c\nindex 190139c..14e0480 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -739,25 +739,26 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,\n {\n \tint rest = eol - bol;\n \tchar *line_color = NULL;\n+\tint show_hunk = (opt->pre_context || opt->post_context ||\n+\t\t\t opt->funcbody);\n \n-\tif (opt->file_break && opt->last_shown == 0) {\n-\t\tif (opt->show_hunk_mark)\n-\t\t\topt->output(opt, \"\\n\", 1);\n-\t} else if (opt->pre_context || opt->post_context || opt->funcbody) {\n-\t\tif (opt->last_shown == 0) {\n-\t\t\tif (opt->show_hunk_mark) {\n-\t\t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n-\t\t\t\topt->output(opt, \"\\n\", 1);\n-\t\t\t}\n-\t\t} else if (lno > opt->last_shown + 1) {\n+\tif (opt->show_hunk_mark && opt->last_shown == 0 &&\n+\t    (opt->file_break || (opt->heading && show_hunk))) {\n+\t\tif (opt->heading && !opt->file_break)\n \t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n-\t\t\topt->output(opt, \"\\n\", 1);\n-\t\t}\n+\t\topt->output(opt, \"\\n\", 1);\n+\t\tshow_hunk = 0;\n \t}\n \tif (opt->heading && opt->last_shown == 0) {\n \t\toutput_color(opt, name, strlen(name), opt->color_filename);\n \t\topt->output(opt, \"\\n\", 1);\n \t}\n+\tif (show_hunk &&\n+\t    ((opt->last_shown == 0 && opt->show_hunk_mark) ||\n+\t     (opt->last_shown != 0 && lno > opt->last_shown + 1))) {\n+\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n+\t\topt->output(opt, \"\\n\", 1);\n+\t}\n \topt->last_shown = lno;\n \n \tif (!opt->heading && opt->pathname) {\n-- \n1.7.9.2\n"},{"id":"187703","messageId":"1332729705-9283-5-git-send-email-lodatom@gmail.com","threadId":"30059","inReplyTo":"1332729705-9283-1-git-send-email-lodatom@gmail.com","subject":"[PATCH 4/4] grep: add --hunk-heading option","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2012-03-26T02:41:45Z","receivedAt":"2012-03-26T02:41:45Z","isPatch":true,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"The purpose of this option is to make the output of grep when showing\ncontext (i.e., -A, -B, -C, or -W) easier to read.  By default, grep\nprints a simple separator (\"--\") between each hunk and then prefixes\neach line within the hunk with the same filename and optionally an\nincrementing line number.  This repeated information is redundant, so\nthe new --hunk-heading option moves it all to the hunk separator line.\nThe idea is similar to the hunk context line of diff.\n\nThe new option can be combined with --heading to provide both the\nfilename and line number of each hunk with minimal visual clutter.\n\nThe new configuration, grep.hunkHeading, can be used to set this option\nby default.\n\nSigned-off-by: Mark Lodato <lodatom@gmail.com>\n---\n Documentation/config.txt     |    3 +\n Documentation/git-grep.txt   |   10 ++-\n builtin/grep.c               |   10 ++-\n grep.c                       |   28 ++++++-\n grep.h                       |    1 +\n t/t7812-grep-hunk-heading.sh |  181 ++++++++++++++++++++++++++++++++++++++++++\n 6 files changed, 227 insertions(+), 6 deletions(-)\n create mode 100755 t/t7812-grep-hunk-heading.sh\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex c081657..ade9503 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1140,6 +1140,9 @@ grep.lineNumber::\n grep.extendedRegexp::\n \tIf set to true, enable '--extended-regexp' option by default.\n \n+grep.hunkHeading::\n+\tIf set to true, enable '--hunk-heading' option by default.\n+\n gpg.program::\n \tUse this custom program instead of \"gpg\" found on $PATH when\n \tmaking or verifying a PGP signature. The program must support the\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 343eadd..26c085b 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -20,7 +20,7 @@ SYNOPSIS\n \t   [-c | --count] [--all-match] [-q | --quiet]\n \t   [--max-depth <depth>]\n \t   [--color[=<when>] | --no-color]\n-\t   [--break] [--heading] [-p | --show-function]\n+\t   [--break] [--heading] [--hunk-heading] [-p | --show-function]\n \t   [-A <post-context>] [-B <pre-context>] [-C <context>]\n \t   [-W | --function-context]\n \t   [-f <file>] [-e] <pattern>\n@@ -43,6 +43,9 @@ grep.lineNumber::\n grep.extendedRegexp::\n \tIf set to true, enable '--extended-regexp' option by default.\n \n+grep.hunkHeading::\n+\tIf set to true, enable '--hunk-heading' option by default.\n+\n \n OPTIONS\n -------\n@@ -173,6 +176,11 @@ OPTIONS\n \tShow the filename above the matches in that file instead of\n \tat the start of each shown line.\n \n+--hunk-heading::\n+\tAppend the filename (if not `--heading` and not `-h`) and line number\n+\t(if not `-n`) to each hunk separator, and suppress printing of the\n+\tfilename at the start of each shown line.\n+\n -p::\n --show-function::\n \tShow the preceding line that contains the function name of\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 643938d..cdafc5a 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -276,6 +276,11 @@ static int grep_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"grep.hunkheading\")) {\n+\t\topt->hunk_heading = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \tif (!strcmp(var, \"grep.linenumber\")) {\n \t\topt->linenum = git_config_bool(var, value);\n \t\treturn 0;\n@@ -740,6 +745,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t\"print empty line between matches from different files\"),\n \t\tOPT_BOOLEAN(0, \"heading\", &opt.heading,\n \t\t\t\"show filename only once above matches from same file\"),\n+\t\tOPT_BOOLEAN(0, \"hunk-heading\", &opt.hunk_heading,\n+\t\t\t\"show filename and line number after hunk separator\"),\n \t\tOPT_GROUP(\"\"),\n \t\tOPT_CALLBACK('C', \"context\", &opt, \"n\",\n \t\t\t\"show <n> context lines before and after matches\",\n@@ -920,8 +927,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n #ifndef NO_PTHREADS\n \tif (use_threads) {\n \t\tif (!(opt.name_only || opt.unmatch_name_only || opt.count)\n+\t\t    && !(opt.hunk_heading && !opt.heading && !opt.file_break)\n \t\t    && (opt.pre_context || opt.post_context ||\n-\t\t\topt.file_break || opt.funcbody))\n+\t\t\topt.file_break || opt.funcbody || opt.hunk_heading))\n \t\t\tskip_first_line = 1;\n \t\tstart_threads(&opt);\n \t}\ndiff --git a/grep.c b/grep.c\nindex 14e0480..f0e00f7 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -747,21 +747,41 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,\n \t\tif (opt->heading && !opt->file_break)\n \t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n \t\topt->output(opt, \"\\n\", 1);\n-\t\tshow_hunk = 0;\n+\t\tif (!opt->hunk_heading)\n+\t\t\tshow_hunk = 0;\n \t}\n \tif (opt->heading && opt->last_shown == 0) {\n \t\toutput_color(opt, name, strlen(name), opt->color_filename);\n \t\topt->output(opt, \"\\n\", 1);\n \t}\n \tif (show_hunk &&\n-\t    ((opt->last_shown == 0 && opt->show_hunk_mark) ||\n+\t    ((opt->last_shown == 0 && (opt->show_hunk_mark || opt->hunk_heading)) ||\n \t     (opt->last_shown != 0 && lno > opt->last_shown + 1))) {\n \t\toutput_color(opt, \"--\", 2, opt->color_sep);\n+\t\tif (opt->hunk_heading &&\n+\t\t    ((!opt->heading && opt->pathname) || !opt->linenum)) {\n+\t\t\topt->output(opt, \" \", 1);\n+\t\t\tif (!opt->heading && opt->pathname) {\n+\t\t\t\toutput_color(opt, name, strlen(name),\n+\t\t\t\t\t     opt->color_filename);\n+\t\t\t\tif (!opt->linenum)\n+\t\t\t\t\toutput_sep(opt, ':');\n+\t\t\t}\n+\t\t\tif (!opt->linenum) {\n+\t\t\t\tchar buf[32];\n+\t\t\t\tsnprintf(buf, sizeof(buf), \"%d\", lno);\n+\t\t\t\toutput_color(opt, buf, strlen(buf),\n+\t\t\t\t\t     opt->color_lineno);\n+\t\t\t}\n+\t\t\topt->output(opt, \" \", 1);\n+\t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n+\t\t}\n \t\topt->output(opt, \"\\n\", 1);\n \t}\n \topt->last_shown = lno;\n \n-\tif (!opt->heading && opt->pathname) {\n+\tif (opt->pathname && !opt->heading &&\n+\t    !(opt->hunk_heading && show_hunk)) {\n \t\toutput_color(opt, name, strlen(name), opt->color_filename);\n \t\toutput_sep(opt, sign);\n \t}\n@@ -1001,7 +1021,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle\n \t\topt->output = std_output;\n \n \tif (opt->pre_context || opt->post_context || opt->file_break ||\n-\t    opt->funcbody) {\n+\t    opt->funcbody || opt->hunk_heading) {\n \t\t/* Show hunk marks, except for the first file. */\n \t\tif (opt->last_shown)\n \t\t\topt->show_hunk_mark = 1;\ndiff --git a/grep.h b/grep.h\nindex 36e49d8..761db2a 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -117,6 +117,7 @@ struct grep_opt {\n \tint show_hunk_mark;\n \tint file_break;\n \tint heading;\n+\tint hunk_heading;\n \tvoid *priv;\n \n \tvoid (*output)(struct grep_opt *opt, const void *data, size_t size);\ndiff --git a/t/t7812-grep-hunk-heading.sh b/t/t7812-grep-hunk-heading.sh\nnew file mode 100755\nindex 0000000..6db9ba6\n--- /dev/null\n+++ b/t/t7812-grep-hunk-heading.sh\n@@ -0,0 +1,181 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2012 Mark Lodato\n+#\n+\n+test_description='git grep --hunk-heading'\n+\n+. ./test-lib.sh\n+\n+cat >one.c <<EOF\n+#include <stdio.h>\n+int main(int argc, const char **argv)\n+{\n+\tprintf(\"Hello world.\\n\");\n+\treturn 0;\n+}\n+EOF\n+\n+cat >two.c <<EOF\n+int hello_int(int x)\n+{\n+\tprintf(\"Hello, %d.\\n\", x);\n+\treturn 0;\n+}\n+\n+int hello_str(const char *s)\n+{\n+\tprintf(\"Hello, %s.\\n\", s);\n+\treturn 0;\n+}\n+EOF\n+\n+test_expect_success 'setup' '\n+\tgit add . &&\n+\tgit commit -m initial\n+'\n+\n+cat >expected <<EOF\n+one.c:\tprintf(\"Hello world.\\n\");\n+two.c:\tprintf(\"Hello, %d.\\n\", x);\n+two.c:\tprintf(\"Hello, %s.\\n\", s);\n+EOF\n+\n+test_expect_success 'grep --hunk-heading without context' '\n+\tgit grep -e Hello --hunk-heading >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+-- one.c:4 --\n+\tprintf(\"Hello world.\\n\");\n+\treturn 0;\n+-- two.c:3 --\n+\tprintf(\"Hello, %d.\\n\", x);\n+\treturn 0;\n+-- two.c:9 --\n+\tprintf(\"Hello, %s.\\n\", s);\n+\treturn 0;\n+EOF\n+\n+test_expect_success 'grep --hunk-heading -A1' '\n+\tgit grep -e Hello -A1 --hunk-heading >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'grep --hunk-heading -B1' '\n+\tgit grep -e return -B1 --hunk-heading >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+<RED>--<RESET> <BLUE>one.c<RESET><RED>:<RESET><GREEN>4<RESET> <RED>--<RESET>\n+\tprintf(\"Hello world.\\n\");\n+\treturn 0;\n+<RED>--<RESET> <BLUE>two.c<RESET><RED>:<RESET><GREEN>3<RESET> <RED>--<RESET>\n+\tprintf(\"Hello, %d.\\n\", x);\n+\treturn 0;\n+<RED>--<RESET> <BLUE>two.c<RESET><RED>:<RESET><GREEN>9<RESET> <RED>--<RESET>\n+\tprintf(\"Hello, %s.\\n\", s);\n+\treturn 0;\n+EOF\n+\n+test_expect_success 'grep --hunk-heading --color' '\n+\ttest_config color.grep.context\t\tnormal &&\n+\ttest_config color.grep.filename\t\t\"blue\" &&\n+\ttest_config color.grep.function\t\tnormal &&\n+\ttest_config color.grep.linenumber\t\"green\" &&\n+\ttest_config color.grep.match\t\tnormal &&\n+\ttest_config color.grep.selected\t\tnormal &&\n+\ttest_config color.grep.separator\t\"red\" &&\n+\n+\tgit grep -e Hello -A1 --hunk-heading --color |\n+\ttest_decode_color >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+-- one.c:4 --\n+\tprintf(\"Hello world.\\n\");\n+\treturn 0;\n+\n+-- two.c:3 --\n+\tprintf(\"Hello, %d.\\n\", x);\n+\treturn 0;\n+-- two.c:9 --\n+\tprintf(\"Hello, %s.\\n\", s);\n+\treturn 0;\n+EOF\n+\n+test_expect_success 'grep --hunk-heading --break' '\n+\tgit grep -e Hello -A1 --hunk-heading --break >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+one.c\n+-- 4 --\n+\tprintf(\"Hello world.\\n\");\n+\treturn 0;\n+--\n+two.c\n+-- 3 --\n+\tprintf(\"Hello, %d.\\n\", x);\n+\treturn 0;\n+-- 9 --\n+\tprintf(\"Hello, %s.\\n\", s);\n+\treturn 0;\n+EOF\n+\n+test_expect_success 'grep --hunk-heading --heading' '\n+\tgit grep -e Hello -A1 --hunk-heading --heading >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+mv expected expected.old\n+sed -e 's/^--$//' expected.old > expected\n+rm expected.old\n+\n+test_expect_success 'grep --hunk-heading --heading --break' '\n+\tgit grep -e Hello -A1 --hunk-heading --heading --break >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+-- one.c --\n+4:\tprintf(\"Hello world.\\n\");\n+5-\treturn 0;\n+-- two.c --\n+3:\tprintf(\"Hello, %d.\\n\", x);\n+4-\treturn 0;\n+-- two.c --\n+9:\tprintf(\"Hello, %s.\\n\", s);\n+10-\treturn 0;\n+EOF\n+\n+test_expect_success 'grep --hunk-heading -n' '\n+\tgit grep -e Hello -A1 --hunk-heading -n >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+one.c\n+--\n+4:\tprintf(\"Hello world.\\n\");\n+5-\treturn 0;\n+--\n+two.c\n+--\n+3:\tprintf(\"Hello, %d.\\n\", x);\n+4-\treturn 0;\n+--\n+9:\tprintf(\"Hello, %s.\\n\", s);\n+10-\treturn 0;\n+EOF\n+\n+test_expect_success 'grep --hunk-heading --heading -n' '\n+\tgit grep -e Hello -A1 --hunk-heading --heading -n >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\n-- \n1.7.9.2\n"},{"id":"187707","messageId":"7vr4wgq6zm.fsf@alter.siamese.dyndns.org","threadId":"30059","inReplyTo":"1332729705-9283-1-git-send-email-lodatom@gmail.com","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-26T05:14:05Z","receivedAt":"2012-03-26T05:14:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Mark Lodato <lodatom@gmail.com> writes:\n\n> Originally, I had envisioned also moving the function name (`-p') to the hunk\n> header, similar to the diff context line.  For example:\n>\n>     -- git.c:570 -- int main(int argc, char argv)\n>                     printf(\"usage: %s\\n\\n\", git_usage_string);\n>                     list_common_cmds_help();\n>                     printf(\"\\n%s\\n\", git_more_info_string);\n>\n> After implementing this feature, I was not happy with the result and\n> subsequently removed it.  To me, the output was too cluttered and the line\n> number was ambigous.  For example, in the above, it is not obvious to me that\n> line 570 is the \"printf\" line and not the \"int main\" line.  Still, if you\n> would like to see the patch to implement this feature, please let me know.\n\nThe worst part of all of the above is that the output becomes utterly\nambiguous and the reader cannot tell if \"-- git.c...\" came because the\nfile had such a line that begin with two dashes in it and grep found it,\nor it is your output format embellishment. It is obvious that these are\nnot meant to be machine parseable, but if the goal is to make the output\nmore useful to the humans, then it may be a better approach to come up\nwith a front end that reads our machine readable output and shows output\nwith its own embellishments. You could even make it an interactive front\nend.\n\nIn other words, I am not yet convinced this belongs to \"git grep\" proper.\n"},{"id":"187731","messageId":"4F709664.1060206@lsrfire.ath.cx","threadId":"30059","inReplyTo":"1332729705-9283-1-git-send-email-lodatom@gmail.com","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-03-26T16:16:36Z","receivedAt":"2012-03-26T16:16:36Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 26.03.2012 04:41, schrieb Mark Lodato:\n> This patch series adds a new `grep --hunk-heading' option that moves the\n> filename and line number to the hunk separator lines (\"--\") rather than at the\n> beginning of each matching (or context) line.  In my opinion, this makes the\n> output easier to read, especially when combined with `--heading'.\n>\n> I am not sure that \"hunk-heading\" is the best term, so I welcome ideas on\n> better names.\n>\n> Here's an example:\n>\n>      # Current behavior:\n>      $ git grep -p -C1 -n list_common -- git.c\n>      git.c=531=int main(int argc, const char **argv)\n>      --\n>      git.c-570-              printf(\"usage: %s\\n\\n\", git_usage_string);\n>      git.c:571:              list_common_cmds_help();\n>      git.c-572-              printf(\"\\n%s\\n\", git_more_info_string);\n>\n>      # New option:\n>      $ git grep -p -C1 --hunk-heading list_common -- git.c\n>      -- git.c:531 --\n>      int main(int argc, char argv)\n>      -- git.c:570 --\n>                      printf(\"usage: %s\\n\\n\", git_usage_string);\n>                      list_common_cmds_help();\n>                      printf(\"\\n%s\\n\", git_more_info_string);\n>\n>      # New option with --heading:\n>      $ git grep -p -C1 --hunk-heading --heading list_common -- git.c\n>      git.c\n>      -- 531 --\n>      int main(int argc, char argv)\n>      -- 570 --\n>                      printf(\"usage: %s\\n\\n\", git_usage_string);\n>                      list_common_cmds_help();\n>                      printf(\"\\n%s\\n\", git_more_info_string);\n>\n> Originally, I had envisioned also moving the function name (`-p') to the hunk\n> header, similar to the diff context line.  For example:\n>\n>      -- git.c:570 -- int main(int argc, char argv)\n>                      printf(\"usage: %s\\n\\n\", git_usage_string);\n>                      list_common_cmds_help();\n>                      printf(\"\\n%s\\n\", git_more_info_string);\n>\n> After implementing this feature, I was not happy with the result and\n> subsequently removed it.  To me, the output was too cluttered and the line\n> number was ambigous.  For example, in the above, it is not obvious to me that\n> line 570 is the \"printf\" line and not the \"int main\" line.  Still, if you\n> would like to see the patch to implement this feature, please let me know.\n\nInteresting.\n\nBy the way, I keep this alias in my config (a single line), to mimic ack \n(http://betterthangrep.com/) -- another way to format results, with \nsimilar goals:\n\n\tack = -c color.grep.filename='bold green' \\\n\t-c color.grep.match='black yellow' grep --break --heading -n\n\nBack to your patch: Why the second set of \"--\" after the line number?  I \ncan see it make sense if a section comment follows, but not without one.\n\nLooking at the above, I thought: We have unified diffs between two \nfiles, we have combined diffs between more than two, what about showing \ngrep results as one-sided unified diffs?  (\"What's the sound of one hand \nclapping?\" :-)\n\n\t--- a/git.c\n\t@ -570,3 @ int main(int argc, const char **argv)\n\t-\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n\t:\t\tlist_common_cmds_help();\n\t-\t\tprintf(\"\\n%s\\n\", git_more_info_string);\n\nPro: Generalization of an established format for showing interesting \nparts of a file.  Less duplication of meta-information.  Markers that \ntell us the kind of the shown lines are kept (\"-\" for context, \":\" for \nmatches).  Machine parsable.\n\nCon: Why the \"a/\" prefix?  One-sided diffs, srsly?\n\nRené\n"},{"id":"187732","messageId":"4F70966B.4050107@lsrfire.ath.cx","threadId":"30059","inReplyTo":"7vr4wgq6zm.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-03-26T16:16:43Z","receivedAt":"2012-03-26T16:16:43Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 26.03.2012 07:14, schrieb Junio C Hamano:\n> Mark Lodato<lodatom@gmail.com>  writes:\n>\n>> Originally, I had envisioned also moving the function name (`-p') to the hunk\n>> header, similar to the diff context line.  For example:\n>>\n>>      -- git.c:570 -- int main(int argc, char argv)\n>>                      printf(\"usage: %s\\n\\n\", git_usage_string);\n>>                      list_common_cmds_help();\n>>                      printf(\"\\n%s\\n\", git_more_info_string);\n>>\n>> After implementing this feature, I was not happy with the result and\n>> subsequently removed it.  To me, the output was too cluttered and the line\n>> number was ambigous.  For example, in the above, it is not obvious to me that\n>> line 570 is the \"printf\" line and not the \"int main\" line.  Still, if you\n>> would like to see the patch to implement this feature, please let me know.\n>\n> The worst part of all of the above is that the output becomes utterly\n> ambiguous and the reader cannot tell if \"-- git.c...\" came because the\n> file had such a line that begin with two dashes in it and grep found it,\n> or it is your output format embellishment. It is obvious that these are\n> not meant to be machine parseable, but if the goal is to make the output\n> more useful to the humans, then it may be a better approach to come up\n> with a front end that reads our machine readable output and shows output\n> with its own embellishments. You could even make it an interactive front\n> end.\n\nHuman readers can differentiate between contents and heading by color; \nseparators are cyan by default.\n\nA separate frontend would probably have to implement match highlighting \nagain.  That's not too hard, but a bit sad.\n\n> In other words, I am not yet convinced this belongs to \"git grep\" proper.\n\nAll in all, I'm not sure either.  But I think the idea to deduplicate \nthe meta-information and give found content more screen real estate is a \ngood one in general.\n\nRené\n"},{"id":"187751","messageId":"7vobrjp7gu.fsf@alter.siamese.dyndns.org","threadId":"30059","inReplyTo":"4F709664.1060206@lsrfire.ath.cx","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-26T18:01:21Z","receivedAt":"2012-03-26T18:01:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n\n> Looking at the above, I thought: We have unified diffs between two\n> files, we have combined diffs between more than two, what about\n> showing grep results as one-sided unified diffs?  (\"What's the sound\n> of one hand clapping?\" :-)\n>\n> \t--- a/git.c\n> \t@ -570,3 @ int main(int argc, const char **argv)\n> \t-\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n> \t:\t\tlist_common_cmds_help();\n> \t-\t\tprintf(\"\\n%s\\n\", git_more_info_string);\n>\n> Pro: Generalization of an established format for showing interesting\n> parts of a file.  Less duplication of meta-information.  Markers that\n> tell us the kind of the shown lines are kept (\"-\" for context, \":\" for\n> matches).  Machine parsable.\n>\n> Con: Why the \"a/\" prefix?  One-sided diffs, srsly?\n\nCute, and I tend to agree that this is probably easier to read if you are\nused to reading unified diffs.\n\nWouldn't it make more sense to replace your '-/:' with ' /=', so that at\nleast ' ' SP retains the meaning of \"this is shown merely to give you\ncontext, it is not a proper part of what you are looking for\"?\n\nThe reasoning behind '=' is that it is not either -/+ as we are not really\ncomparing anything with anything.  It may also make sense to replace the\nper-file header line with \"=== git.c\" to be consistent.  I haven't formed\nan opinion on the prefix yet; there might be a good reason to keep the\ndepth of the path each file appear in this \"grep --unidiff-like\" output\nand \"diff --patch\" output, in which case \"=== a/git.c\" or \"=== ./git.c\"\nmight be give us more uniformity.\n"},{"id":"187752","messageId":"7vk427p79z.fsf@alter.siamese.dyndns.org","threadId":"30059","inReplyTo":"4F70966B.4050107@lsrfire.ath.cx","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-26T18:05:28Z","receivedAt":"2012-03-26T18:05:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n\n> Human readers can differentiate between contents and heading by color;\n> separators are cyan by default.\n\nOK.\n\n> A separate frontend would probably have to implement match\n> highlighting again.  That's not too hard, but a bit sad.\n\nYeah, but at the same time, a separate front-end could do a lot more than\njust grep.  Letting the user pick a function name from the current output\nand run grep again, letting the user highlight the line range and run\nblame (or \"Linus's ultimate content tracking tool\"), etc.\n\n> ...  But I think the idea to deduplicate the meta-information and give\n> found content more screen real estate is a good one in general.\n\nYeah, I found the \"sound of one hand clapping\" in your other message\nsomewhat intriguing ;-).\n"},{"id":"187763","messageId":"CAKPyHN25miyA6A0p3GMX9XrxnqLu0C9H6VjjCy_HvKfqXo4B2g@mail.gmail.com","threadId":"30059","inReplyTo":"7vr4wgq6zm.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2012-03-26T18:48:12Z","receivedAt":"2012-03-26T18:48:12Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"On Mon, Mar 26, 2012 at 07:14, Junio C Hamano <gitster@pobox.com> wrote:\n> Mark Lodato <lodatom@gmail.com> writes:\n>\n>> Originally, I had envisioned also moving the function name (`-p') to the hunk\n>> header, similar to the diff context line.  For example:\n>>\n>>     -- git.c:570 -- int main(int argc, char argv)\n>>                     printf(\"usage: %s\\n\\n\", git_usage_string);\n>>                     list_common_cmds_help();\n>>                     printf(\"\\n%s\\n\", git_more_info_string);\n>>\n>> After implementing this feature, I was not happy with the result and\n>> subsequently removed it.  To me, the output was too cluttered and the line\n>> number was ambigous.  For example, in the above, it is not obvious to me that\n>> line 570 is the \"printf\" line and not the \"int main\" line.  Still, if you\n>> would like to see the patch to implement this feature, please let me know.\n>\n> The worst part of all of the above is that the output becomes utterly\n> ambiguous and the reader cannot tell if \"-- git.c...\" came because the\n> file had such a line that begin with two dashes in it and grep found it,\n> or it is your output format embellishment. It is obvious that these are\n> not meant to be machine parseable, but if the goal is to make the output\n> more useful to the humans, then it may be a better approach to come up\n> with a front end that reads our machine readable output and shows output\n> with its own embellishments. You could even make it an interactive front\n> end.\n\nFYI, I once posted a git-gui grep prototype:\n\n<1289770869-11665-1-git-send-email-bert.wesarg@googlemail.com>\n\nI have since added it to git-gui, see bw/master~2 'git-gui: add grep\ntab' in http://repo.or.cz/w/git-gui/bertw.git.\n\nBert\n\n>\n> In other words, I am not yet convinced this belongs to \"git grep\" proper.\n>\n>\n"},{"id":"187785","messageId":"4F70DBAC.4010609@lsrfire.ath.cx","threadId":"30059","inReplyTo":"7vobrjp7gu.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-03-26T21:12:12Z","receivedAt":"2012-03-26T21:12:12Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 26.03.2012 20:01, schrieb Junio C Hamano:\n> René Scharfe<rene.scharfe@lsrfire.ath.cx>  writes:\n>\n>> Looking at the above, I thought: We have unified diffs between two\n>> files, we have combined diffs between more than two, what about\n>> showing grep results as one-sided unified diffs?  (\"What's the sound\n>> of one hand clapping?\" :-)\n>>\n>> \t--- a/git.c\n>> \t@ -570,3 @ int main(int argc, const char **argv)\n>> \t-\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n>> \t:\t\tlist_common_cmds_help();\n>> \t-\t\tprintf(\"\\n%s\\n\", git_more_info_string);\n>>\n>> Pro: Generalization of an established format for showing interesting\n>> parts of a file.  Less duplication of meta-information.  Markers that\n>> tell us the kind of the shown lines are kept (\"-\" for context, \":\" for\n>> matches).  Machine parsable.\n>>\n>> Con: Why the \"a/\" prefix?  One-sided diffs, srsly?\n>\n> Cute, and I tend to agree that this is probably easier to read if you are\n> used to reading unified diffs.\n>\n> Wouldn't it make more sense to replace your '-/:' with ' /=', so that at\n> least ' ' SP retains the meaning of \"this is shown merely to give you\n> context, it is not a proper part of what you are looking for\"?\n\nAh, good idea, the space makes for a less cluttered output.  For \ncompleteness sake, I have to mention that the current grep output uses \n'-/:/=', however, for context/match/function line (\"especially \ninteresting context\").  Even function lines that happen to fall within \nthe --context are marked with an equal sign.  That's not the case for \nunified diffs; they simply get shown as normal context.\n\n> The reasoning behind '=' is that it is not either -/+ as we are not really\n> comparing anything with anything.\n\nMapping the '-/:/=' of grep to ' /:/=' or ' /:/ ' might be easier to \nunderstand.  However, seeing a line starting with a colon or an equal \nsign feels both strange, because they are normally used as binary \noperators.  Normal grep output shows a filename or a line number before \nthe separator, so it doesn't invoke that strange feeling.\n\nPerhaps mapping to ' /!/ ' is better instead, similar to context diffs?\n\n> It may also make sense to replace the\n> per-file header line with \"=== git.c\" to be consistent.\n\nA context diffs would have '*** git.c', but they are ugly IMHO, overall.\n\nWhat we also could do: Produce a valid unified diff that would remove \nthe matching lines if we were to apply it (or the --reverse, i.e. + \ninstead of -).  Then we wouldn't need to invent a special format, but \nthe output would be a bit more verbose due to the added +++ lines.\n\nI guess it's time to implement these options in order to try them out \nagainst real code.  Won't have time to do so before the second half of \nthe week, however.\n\nRené\n"},{"id":"187787","messageId":"7v8vinnjqy.fsf@alter.siamese.dyndns.org","threadId":"30059","inReplyTo":"4F70DBAC.4010609@lsrfire.ath.cx","subject":"Re: [PATCH 0/4] grep: add more information to hunk separators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-26T21:19:01Z","receivedAt":"2012-03-26T21:19:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n\n> What we also could do: Produce a valid unified diff that would remove\n> the matching lines if we were to apply it (or the --reverse, i.e. +\n> instead of -).  Then we wouldn't need to invent a special format, but\n> the output would be a bit more verbose due to the added +++ lines.\n\nHrm, certainly that is an option that saves a lot of thinking.\n\nAs people tend to learn to focus more on '+' lines when reading patches in\nthe unified context format, the reverse option would produce output that\nis easier to read, I would guess.\n\n> I guess it's time to implement these options in order to try them out\n> against real code.  Won't have time to do so before the second half of\n> the week, however.\n\nThat's OK---we are in no hurry.  Have you heard about pre-release feature\nfreeze already ;-)?\n"},{"id":"187818","messageId":"1332826286-13490-1-git-send-email-lodatom@gmail.com","threadId":"30059","inReplyTo":"1332729705-9283-1-git-send-email-lodatom@gmail.com","subject":"[PATCH 5/4] move sane_truncate_line to utf8_truncate_line","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2012-03-27T05:31:25Z","receivedAt":"2012-03-27T05:31:25Z","isPatch":true,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"Signed-off-by: Mark Lodato <lodatom@gmail.com>\n---\n\nAs promised, here are the additional patches to move the function name to the\nsame line as the hunk header.\n\n diff.c |   14 ++------------\n utf8.c |   13 +++++++++++++\n utf8.h |    2 ++\n 3 files changed, 17 insertions(+), 12 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 377ec1e..74c77bc 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1015,20 +1015,10 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)\n \n static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len)\n {\n-\tconst char *cp;\n-\tunsigned long allot;\n-\tsize_t l = len;\n-\n \tif (ecb->truncate)\n \t\treturn ecb->truncate(line, len);\n-\tcp = line;\n-\tallot = l;\n-\twhile (0 < l) {\n-\t\t(void) utf8_width(&cp, &l);\n-\t\tif (!cp)\n-\t\t\tbreak; /* truncated in the middle? */\n-\t}\n-\treturn allot - l;\n+\telse\n+\t\treturn utf8_truncate_line(line, len);\n }\n \n static void find_lno(const char *line, struct emit_callback *ecbdata)\ndiff --git a/utf8.c b/utf8.c\nindex 8acbc66..d70ee9b 100644\n--- a/utf8.c\n+++ b/utf8.c\n@@ -482,3 +482,16 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e\n \treturn out;\n }\n #endif\n+\n+unsigned long utf8_truncate_line(const char *line, unsigned long len)\n+{\n+\tconst char *cp = line;\n+\tunsigned long allot = len;\n+\tsize_t l = len;\n+\twhile (0 < l) {\n+\t\t(void) utf8_width(&cp, &l);\n+\t\tif (!cp)\n+\t\t\tbreak; /* truncated in the middle? */\n+\t}\n+\treturn allot - l;\n+}\ndiff --git a/utf8.h b/utf8.h\nindex 81f2c82..929e2df 100644\n--- a/utf8.h\n+++ b/utf8.h\n@@ -19,4 +19,6 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e\n #define reencode_string(a,b,c) NULL\n #endif\n \n+unsigned long utf8_truncate_line(const char *line, unsigned long len);\n+\n #endif\n-- \n1.7.9.4\n"},{"id":"187819","messageId":"1332826286-13490-2-git-send-email-lodatom@gmail.com","threadId":"30059","inReplyTo":"1332826286-13490-1-git-send-email-lodatom@gmail.com","subject":"[PATCH 6/4] add grep.hunkHeadingFunction option","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2012-03-27T05:31:26Z","receivedAt":"2012-03-27T05:31:26Z","isPatch":true,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"If set to true, the function line is printed on the same line as the\nfirst hunk header (but only if a hunk header is printed).\n\nSigned-off-by: Mark Lodato <lodatom@gmail.com>\n---\n\nI was not sure if it would be better to have this as a configuration setting,\na command-line option, or both.  It probably doesn't matter for this round,\nsince the main purpose of this post is to get the idea out there so people can\ntry it out this feature see if they like it at all.\n\nThere might have been a better way to implement this.  Currently, we have the\nentire file in memory, so I could have just stored a pointer to the function\nname line, rather than copying it.  Perhaps this would have been better?\n\nAlso, I chose to only print the function name once, rather than duplicating it\non each header, so as to reduce visual clutter.  I can see an argument both\nways, so if you would like to have the function name printed on every header,\njust remove the \"opt->func_line[0] = '\\0'\" from the beginning of\nshow_funcname_line().\n\n\n Documentation/config.txt   |    5 +++++\n Documentation/git-grep.txt |    5 +++++\n builtin/grep.c             |    5 +++++\n grep.c                     |   24 +++++++++++++++++++++++-\n grep.h                     |    3 +++\n 5 files changed, 41 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex ade9503..1e3b5ec 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1143,6 +1143,11 @@ grep.extendedRegexp::\n grep.hunkHeading::\n \tIf set to true, enable '--hunk-heading' option by default.\n \n+grep.hunkHeadingFunction::\n+\tIf set to true, print the function name in the hunk heading rather\n+\tthan on its own line.  This only occurs when hunk headings would have\n+\tbeen shown and '--show-function' is used.\n+\n gpg.program::\n \tUse this custom program instead of \"gpg\" found on $PATH when\n \tmaking or verifying a PGP signature. The program must support the\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 26c085b..a32ac5e 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -46,6 +46,11 @@ grep.extendedRegexp::\n grep.hunkHeading::\n \tIf set to true, enable '--hunk-heading' option by default.\n \n+grep.hunkHeadingFunction::\n+\tIf set to true, print the function name in the hunk heading rather\n+\tthan on its own line.  This only occurs when hunk headings would have\n+\tbeen shown and '--show-function' is used.\n+\n \n OPTIONS\n -------\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex cdafc5a..d4c9f92 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -281,6 +281,11 @@ static int grep_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"grep.hunkheadingfunction\")) {\n+\t\topt->hunk_heading_function = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \tif (!strcmp(var, \"grep.linenumber\")) {\n \t\topt->linenum = git_config_bool(var, value);\n \t\treturn 0;\ndiff --git a/grep.c b/grep.c\nindex f0e00f7..49e66e3 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"grep.h\"\n #include \"userdiff.h\"\n+#include \"utf8.h\"\n #include \"xdiff-interface.h\"\n \n void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat)\n@@ -776,6 +777,12 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,\n \t\t\topt->output(opt, \" \", 1);\n \t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n \t\t}\n+\t\tif (opt->hunk_heading && opt->func_line[0] != '\\0') {\n+\t\t\topt->output(opt, \" \", 1);\n+\t\t\toutput_color(opt, opt->func_line,\n+\t\t\t\t     strlen(opt->func_line),\n+\t\t\t\t     opt->color_function);\n+\t\t}\n \t\topt->output(opt, \"\\n\", 1);\n \t}\n \topt->last_shown = lno;\n@@ -882,6 +889,7 @@ static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bo\n static void show_funcname_line(struct grep_opt *opt, struct grep_source *gs,\n \t\t\t       char *bol, unsigned lno)\n {\n+\topt->func_line[0] = '\\0';\n \twhile (bol > gs->buf) {\n \t\tchar *eol = --bol;\n \n@@ -893,7 +901,18 @@ static void show_funcname_line(struct grep_opt *opt, struct grep_source *gs,\n \t\t\tbreak;\n \n \t\tif (match_funcname(opt, gs, bol, eol)) {\n-\t\t\tshow_line(opt, bol, eol, gs->name, lno, '=');\n+\t\t\tif (opt->hunk_heading_function && opt->hunk_heading &&\n+\t\t\t    opt->funcname &&\n+\t\t\t    (opt->pre_context || opt->post_context ||\n+\t\t\t     opt->funcbody)) {\n+\t\t\t\tunsigned long len = eol - bol;\n+\t\t\t\tif (len > GREP_MAX_FUNCLINE)\n+\t\t\t\t\tlen = GREP_MAX_FUNCLINE;\n+\t\t\t\tlen = utf8_truncate_line(bol, len);\n+\t\t\t\tmemcpy(opt->func_line, bol, len);\n+\t\t\t\topt->func_line[len] = '\\0';\n+\t\t\t} else\n+\t\t\t\tshow_line(opt, bol, eol, gs->name, lno, '=');\n \t\t\tbreak;\n \t\t}\n \t}\n@@ -930,6 +949,8 @@ static void show_pre_context(struct grep_opt *opt, struct grep_source *gs,\n \t/* We need to look even further back to find a function signature. */\n \tif (opt->funcname && funcname_needed)\n \t\tshow_funcname_line(opt, gs, bol, cur);\n+\telse\n+\t\topt->func_line[0] = '\\0';\n \n \t/* Back forward. */\n \twhile (cur < lno) {\n@@ -1034,6 +1055,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle\n \t\t\topt->show_hunk_mark = 1;\n \t}\n \topt->last_shown = 0;\n+\topt->func_line[0] = '\\0';\n \n \tswitch (opt->binary) {\n \tcase GREP_BINARY_DEFAULT:\ndiff --git a/grep.h b/grep.h\nindex 761db2a..8112e07 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -118,6 +118,9 @@ struct grep_opt {\n \tint file_break;\n \tint heading;\n \tint hunk_heading;\n+\tint hunk_heading_function;\n+#define GREP_MAX_FUNCLINE\t80\n+\tchar func_line[GREP_MAX_FUNCLINE+1];\n \tvoid *priv;\n \n \tvoid (*output)(struct grep_opt *opt, const void *data, size_t size);\n-- \n1.7.9.4\n"}]}