Add workaround for system dependent date comparison
[tig.git] / src / grep.c
blob1d7b97638576830fc9f6243805828d7439503b65
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 #define grep_view_lineno(grep) ((grep)->lineno > 0 ? (grep)->lineno - 1 : 0)
37 static struct grep_line *
38 grep_get_line(const struct line *line)
40 static struct grep_line grep_line;
42 if (line->type == LINE_DEFAULT)
43 return line->data;
45 grep_line.file = line->type == LINE_DELIMITER ? "" : get_path(line->data);
46 return &grep_line;
49 static bool
50 grep_get_column_data(struct view *view, const struct line *line, struct view_column_data *column_data)
52 struct grep_line *grep = grep_get_line(line);
54 if (line->type == LINE_DELIMITER) {
55 static struct view_column separator_column;
57 separator_column.type = VIEW_COLUMN_TEXT;
58 column_data->section = &separator_column;
59 column_data->text = "--";
60 return TRUE;
63 if (*grep->file && !grep->lineno) {
64 static struct view_column file_name_column;
66 file_name_column.type = VIEW_COLUMN_FILE_NAME;
67 file_name_column.opt.file_name.display = FILENAME_ALWAYS;
69 column_data->section = &file_name_column;
72 column_data->line_number = &grep->lineno;
73 column_data->file_name = grep->file;
74 column_data->text = grep->text;
75 return TRUE;
78 static void
79 grep_select(struct view *view, struct line *line)
81 struct grep_line *grep = grep_get_line(line);
83 if (!*grep->file)
84 return;
85 view->env->ref[0] = 0;
86 string_ncopy(view->env->file, grep->file, strlen(grep->file));
87 string_ncopy(view->ref, grep->file, strlen(grep->file));
90 static const char *grep_args[] = {
91 "git", "grep", "--no-color", "-n", "-z", "--full-name", NULL
94 static const char **grep_argv;
96 static bool
97 grep_prompt(void)
99 const char *argv[SIZEOF_ARG];
100 int argc = 0;
101 char *grep = read_prompt("grep: ");
103 if (!grep || !argv_from_string_no_quotes(argv, &argc, grep))
104 return FALSE;
105 if (grep_argv)
106 argv_free(grep_argv);
107 return argv_append_array(&grep_argv, argv);
110 void
111 open_grep_view(struct view *prev)
113 struct view *view = &grep_view;
114 bool in_grep_view = prev == view;
116 if ((!prev && is_initial_view(view)) || (view->lines && !in_grep_view)) {
117 open_view(prev, view, OPEN_DEFAULT);
118 } else {
119 if (grep_prompt())
120 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_argv;
132 opt_cmdline_argv = 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_view_lineno(grep))
166 select_view_line(file_view, grep_view_lineno(grep));
168 } else {
169 const char *file_argv[] = { repo.cdup, grep->file, NULL };
171 clear_position(&file_view->pos);
172 view->env->lineno = grep_view_lineno(grep);
173 view->env->blob[0] = 0;
174 open_argv(view, file_view, file_argv, repo.cdup, OPEN_SPLIT | OPEN_RELOAD);
176 state->last_file = grep->file;
177 return REQ_NONE;
179 case REQ_EDIT:
180 if (!*grep->file)
181 return request;
182 open_editor(grep->file, grep->lineno);
183 return REQ_NONE;
185 case REQ_VIEW_BLAME:
186 view->env->ref[0] = 0;
187 view->env->lineno = grep_view_lineno(grep);
188 return request;
190 default:
191 return request;
195 static bool
196 grep_read(struct view *view, struct buffer *buf)
198 struct grep_state *state = view->private;
199 struct grep_line *grep;
200 char *lineno, *text;
201 struct line *line;
202 const char *file;
203 size_t textlen;
205 if (!buf) {
206 state->last_file = NULL;
207 return TRUE;
210 if (!strcmp(buf->data, "--"))
211 return add_line_nodata(view, LINE_DELIMITER) != NULL;
213 lineno = io_memchr(buf, buf->data, 0);
214 text = io_memchr(buf, lineno, 0);
216 if (!lineno || !text)
217 return FALSE;
219 textlen = strlen(text);
221 file = get_path(buf->data);
222 if (!file)
223 return FALSE;
225 if (!state->no_file_group && file != state->last_file &&
226 !add_line_text(view, file, LINE_FILE))
227 return FALSE;
229 line = add_line_alloc(view, &grep, LINE_DEFAULT, textlen, FALSE);
230 if (!line)
231 return FALSE;
233 grep->file = file;
234 grep->lineno = atoi(lineno);
235 strncpy(grep->text, text, textlen);
236 grep->text[textlen] = 0;
237 view_column_info_update(view, line);
239 state->last_file = file;
241 return TRUE;
244 static struct view_ops grep_ops = {
245 "line",
247 VIEW_REFRESH | VIEW_GREP_LIKE,
248 sizeof(struct grep_state),
249 grep_open,
250 grep_read,
251 view_column_draw,
252 grep_request,
253 view_column_grep,
254 grep_select,
255 NULL,
256 view_column_bit(FILE_NAME) | view_column_bit(LINE_NUMBER) |
257 view_column_bit(TEXT),
258 grep_get_column_data,
261 DEFINE_VIEW(grep);
263 /* vim: set ts=8 sw=8 noexpandtab: */