Add option to install Tig with Homebrew
[tig.git] / src / grep.c
blob5e671cc297bd301e6f2003e93fb83a2684b444b5
1 /* Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include "tig/refdb.h"
15 #include "tig/options.h"
16 #include "tig/parse.h"
17 #include "tig/repo.h"
18 #include "tig/display.h"
19 #include "tig/prompt.h"
20 #include "tig/draw.h"
21 #include "tig/blob.h"
22 #include "tig/grep.h"
24 struct grep_line {
25 const char *file;
26 unsigned long lineno;
27 char text[1];
30 struct grep_state {
31 const char *last_file;
32 bool no_file_group;
35 static struct grep_line *
36 grep_get_line(const struct line *line)
38 static struct grep_line grep_line;
40 if (line->type == LINE_DEFAULT)
41 return line->data;
43 grep_line.file = line->type == LINE_DELIMITER ? "" : get_path(line->data);
44 return &grep_line;
47 static bool
48 grep_get_column_data(struct view *view, const struct line *line, struct view_column_data *column_data)
50 struct grep_line *grep = grep_get_line(line);
52 if (line->type == LINE_DELIMITER) {
53 static struct view_column separator_column;
55 separator_column.type = VIEW_COLUMN_TEXT;
56 column_data->section = &separator_column;
57 column_data->text = "--";
58 return TRUE;
61 if (*grep->file && !*grep->text) {
62 static struct view_column file_name_column;
64 file_name_column.type = VIEW_COLUMN_FILE_NAME;
65 file_name_column.opt.file_name.display = FILENAME_ALWAYS;
67 column_data->section = &file_name_column;
70 column_data->line_number = &grep->lineno;
71 column_data->file_name = grep->file;
72 column_data->text = grep->text;
73 return TRUE;
76 static void
77 grep_select(struct view *view, struct line *line)
79 struct grep_line *grep = grep_get_line(line);
81 if (!*grep->file)
82 return;
83 view->env->ref[0] = 0;
84 string_ncopy(view->env->file, grep->file, strlen(grep->file));
85 string_ncopy(view->ref, grep->file, strlen(grep->file));
88 static const char *grep_args[] = {
89 "git", "grep", "--no-color", "-n", "-z", "--full-name", NULL
92 static const char **grep_argv;
94 static bool
95 grep_prompt(void)
97 const char *argv[SIZEOF_ARG];
98 int argc = 0;
99 char *grep = read_prompt("grep: ");
101 if (!grep || !argv_from_string_no_quotes(argv, &argc, grep))
102 return FALSE;
103 if (grep_argv)
104 argv_free(grep_argv);
105 return argv_append_array(&grep_argv, argv);
108 void
109 open_grep_view(struct view *prev)
111 struct view *view = &grep_view;
112 bool in_grep_view = prev == view;
114 if ((!prev && is_initial_view(view)) || (view->lines && !in_grep_view)) {
115 open_view(prev, view, OPEN_DEFAULT);
116 } else {
117 if (grep_prompt()) {
118 clear_position(&view->pos);
119 open_view(prev, view, OPEN_RELOAD);
124 static bool
125 grep_open(struct view *view, enum open_flags flags)
127 struct grep_state *state = view->private;
128 const char **argv = NULL;
130 if (is_initial_view(view)) {
131 grep_argv = opt_cmdline_args;
132 opt_cmdline_args = NULL;
135 if (!argv_append_array(&argv, grep_args) ||
136 !argv_append_array(&argv, grep_argv))
137 return FALSE;
140 struct view_column *column = get_view_column(view, VIEW_COLUMN_FILE_NAME);
142 state->no_file_group = !column || column->opt.file_name.display != FILENAME_NO;
145 return begin_update(view, NULL, argv, flags);
148 static enum request
149 grep_request(struct view *view, enum request request, struct line *line)
151 struct grep_state *state = view->private;
152 struct grep_line *grep = grep_get_line(line);
153 struct view *file_view = &blob_view;
155 switch (request) {
156 case REQ_REFRESH:
157 refresh_view(view);
158 return REQ_NONE;
160 case REQ_ENTER:
161 if (!*grep->file)
162 return REQ_NONE;
163 if (file_view->parent == view && file_view->prev == view &&
164 state->last_file == grep->file && view_is_displayed(file_view)) {
165 if (*grep->text) {
166 select_view_line(file_view, grep->lineno);
167 update_view_title(file_view);
170 } else {
171 const char *file_argv[] = { repo.cdup, grep->file, NULL };
173 clear_position(&file_view->pos);
174 view->env->lineno = grep->lineno;
175 view->env->blob[0] = 0;
176 open_argv(view, file_view, file_argv, repo.cdup, OPEN_SPLIT | OPEN_RELOAD);
178 state->last_file = grep->file;
179 return REQ_NONE;
181 case REQ_EDIT:
182 if (!*grep->file)
183 return request;
184 open_editor(grep->file, grep->lineno + 1);
185 return REQ_NONE;
187 case REQ_VIEW_BLAME:
188 view->env->ref[0] = 0;
189 view->env->lineno = grep->lineno;
190 return request;
192 default:
193 return request;
197 static bool
198 grep_read(struct view *view, struct buffer *buf)
200 struct grep_state *state = view->private;
201 struct grep_line *grep;
202 char *lineno, *text;
203 struct line *line;
204 const char *file;
205 size_t textlen;
207 if (!buf) {
208 state->last_file = NULL;
209 if (!view->lines) {
210 view->ref[0] = 0;
211 report("No matches found");
213 return TRUE;
216 if (!strcmp(buf->data, "--"))
217 return add_line_nodata(view, LINE_DELIMITER) != NULL;
219 lineno = io_memchr(buf, buf->data, 0);
220 text = io_memchr(buf, lineno, 0);
223 * No data indicates binary file matches, e.g.:
224 * > git grep vertical- -- test
225 * test/graph/20-tig-all-long-test:● │ Add "auto" vertical-split
226 * Binary file test/graph/20-tig-all-long-test.in matches
228 if (!lineno || !text)
229 return TRUE;
231 textlen = strlen(text);
233 file = get_path(buf->data);
234 if (!file)
235 return FALSE;
237 if (!state->no_file_group && file != state->last_file &&
238 !add_line_text(view, file, LINE_FILE))
239 return FALSE;
241 line = add_line_alloc(view, &grep, LINE_DEFAULT, textlen, FALSE);
242 if (!line)
243 return FALSE;
245 grep->file = file;
246 grep->lineno = atoi(lineno);
247 if (grep->lineno > 0)
248 grep->lineno -= 1;
249 strncpy(grep->text, text, textlen);
250 grep->text[textlen] = 0;
251 view_column_info_update(view, line);
253 state->last_file = file;
255 return TRUE;
258 static struct view_ops grep_ops = {
259 "line",
261 VIEW_REFRESH | VIEW_GREP_LIKE,
262 sizeof(struct grep_state),
263 grep_open,
264 grep_read,
265 view_column_draw,
266 grep_request,
267 view_column_grep,
268 grep_select,
269 NULL,
270 view_column_bit(FILE_NAME) | view_column_bit(LINE_NUMBER) |
271 view_column_bit(TEXT),
272 grep_get_column_data,
275 DEFINE_VIEW(grep);
277 /* vim: set ts=8 sw=8 noexpandtab: */