builtin/grep.c: add '--column' option to 'git-grep(1)'

Teach 'git-grep(1)' a new option, '--column', to show the column number of the first match on a non-context line. This makes it possible to teach 'contrib/git-jump/git-jump' how to seek to the first matching position of a grep match in your editor, and allows similar additional scripting capabilities. For example: $ git grep -n --column foo | head -n3 .clang-format:51:14:# myFunction(foo, bar, baz); .clang-format:64:7:# int foo(); .clang-format:75:8:# void foo() Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Jun 22, 2018 at 10:49 UTC a449f27ffa08de1b01ab5e4fe7daac38f25c9515
3 files changed +101 -1
Documentation/git-grep.txt
+5 -1
@@ -13,7 +13,7 @@ SYNOPSIS
13 [-v | --invert-match] [-h|-H] [--full-name]
14 [-E | --extended-regexp] [-G | --basic-regexp]
15 [-P | --perl-regexp]
16 - [-F | --fixed-strings] [-n | --line-number]
16 + [-F | --fixed-strings] [-n | --line-number] [--column]
17 [-l | --files-with-matches] [-L | --files-without-match]
18 [(-O | --open-files-in-pager) [<pager>]]
19 [-z | --null]
@@ -169,6 +169,10 @@ providing this option will cause it to die.
169 --line-number::
170 Prefix the line number to matching lines.
171
172 +--column::
173 + Prefix the 1-indexed byte-offset of the first match from the start of the
174 + matching line.
175 +
176 -l::
177 --files-with-matches::
178 --name-only::
builtin/grep.c
+1
@@ -828,6 +828,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
828 GREP_PATTERN_TYPE_PCRE),
829 OPT_GROUP(""),
830 OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")),
831 + OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")),
832 OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
833 OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
834 OPT_NEGBIT(0, "full-name", &opt.relative,
t/t7810-grep.sh
+95
@@ -99,6 +99,101 @@ do
99 test_cmp expected actual
100 '
101
102 + test_expect_success "grep -w $L (with --column)" '
103 + {
104 + echo ${HC}file:5:foo mmap bar
105 + echo ${HC}file:14:foo_mmap bar mmap
106 + echo ${HC}file:5:foo mmap bar_mmap
107 + echo ${HC}file:14:foo_mmap bar mmap baz
108 + } >expected &&
109 + git grep --column -w -e mmap $H >actual &&
110 + test_cmp expected actual
111 + '
112 +
113 + test_expect_success "grep -w $L (with --column, extended OR)" '
114 + {
115 + echo ${HC}file:14:foo_mmap bar mmap
116 + echo ${HC}file:19:foo_mmap bar mmap baz
117 + } >expected &&
118 + git grep --column -w -e mmap$ --or -e baz $H >actual &&
119 + test_cmp expected actual
120 + '
121 +
122 + test_expect_success "grep -w $L (with --column, --invert)" '
123 + {
124 + echo ${HC}file:1:foo mmap bar
125 + echo ${HC}file:1:foo_mmap bar
126 + echo ${HC}file:1:foo_mmap bar mmap
127 + echo ${HC}file:1:foo mmap bar_mmap
128 + } >expected &&
129 + git grep --column --invert -w -e baz $H -- file >actual &&
130 + test_cmp expected actual
131 + '
132 +
133 + test_expect_success "grep $L (with --column, --invert, extended OR)" '
134 + {
135 + echo ${HC}hello_world:6:HeLLo_world
136 + } >expected &&
137 + git grep --column --invert -e ll --or --not -e _ $H -- hello_world \
138 + >actual &&
139 + test_cmp expected actual
140 + '
141 +
142 + test_expect_success "grep $L (with --column, --invert, extended AND)" '
143 + {
144 + echo ${HC}hello_world:3:Hello world
145 + echo ${HC}hello_world:3:Hello_world
146 + echo ${HC}hello_world:6:HeLLo_world
147 + } >expected &&
148 + git grep --column --invert --not -e _ --and --not -e ll $H -- hello_world \
149 + >actual &&
150 + test_cmp expected actual
151 + '
152 +
153 + test_expect_success "grep $L (with --column, double-negation)" '
154 + {
155 + echo ${HC}file:1:foo_mmap bar mmap baz
156 + } >expected &&
157 + git grep --column --not \( --not -e foo --or --not -e baz \) $H -- file \
158 + >actual &&
159 + test_cmp expected actual
160 + '
161 +
162 + test_expect_success "grep -w $L (with --column, -C)" '
163 + {
164 + echo ${HC}file:5:foo mmap bar
165 + echo ${HC}file-foo_mmap bar
166 + echo ${HC}file:14:foo_mmap bar mmap
167 + echo ${HC}file:5:foo mmap bar_mmap
168 + echo ${HC}file:14:foo_mmap bar mmap baz
169 + } >expected &&
170 + git grep --column -w -C1 -e mmap $H >actual &&
171 + test_cmp expected actual
172 + '
173 +
174 + test_expect_success "grep -w $L (with --line-number, --column)" '
175 + {
176 + echo ${HC}file:1:5:foo mmap bar
177 + echo ${HC}file:3:14:foo_mmap bar mmap
178 + echo ${HC}file:4:5:foo mmap bar_mmap
179 + echo ${HC}file:5:14:foo_mmap bar mmap baz
180 + } >expected &&
181 + git grep -n --column -w -e mmap $H >actual &&
182 + test_cmp expected actual
183 + '
184 +
185 + test_expect_success "grep -w $L (with non-extended patterns, --column)" '
186 + {
187 + echo ${HC}file:5:foo mmap bar
188 + echo ${HC}file:10:foo_mmap bar
189 + echo ${HC}file:10:foo_mmap bar mmap
190 + echo ${HC}file:5:foo mmap bar_mmap
191 + echo ${HC}file:10:foo_mmap bar mmap baz
192 + } >expected &&
193 + git grep --column -w -e bar -e mmap $H >actual &&
194 + test_cmp expected actual
195 + '
196 +
197 test_expect_success "grep -w $L" '
198 {
199 echo ${HC}file:1:foo mmap bar