prompt: print sort field and order information when toggled
[tig.git] / src / branch.c
blob81cc426127e2c25ad7b521fbff707dd01b6e0725
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/io.h"
15 #include "tig/options.h"
16 #include "tig/parse.h"
17 #include "tig/display.h"
18 #include "tig/view.h"
19 #include "tig/draw.h"
20 #include "tig/git.h"
23 * Branch backend
26 struct branch {
27 const struct ident *author; /* Author of the last commit. */
28 struct time time; /* Date of the last activity. */
29 char title[128]; /* First line of the commit message. */
30 const struct ref *ref; /* Name and commit ID information. */
33 static const struct ref branch_all;
34 #define BRANCH_ALL_NAME "All branches"
35 #define branch_is_all(branch) ((branch)->ref == &branch_all)
37 static const enum sort_field branch_sort_fields[] = {
38 SORT_FIELD_NAME, SORT_FIELD_DATE, SORT_FIELD_AUTHOR
41 static struct sort_state branch_sort_state = SORT_STATE(branch_sort_fields);
43 struct branch_state {
44 char id[SIZEOF_REV];
45 size_t max_ref_length;
48 static int
49 branch_compare(const void *l1, const void *l2)
51 const struct branch *branch1 = ((const struct line *) l1)->data;
52 const struct branch *branch2 = ((const struct line *) l2)->data;
54 if (branch_is_all(branch1))
55 return -1;
56 else if (branch_is_all(branch2))
57 return 1;
59 switch (get_sort_field(branch_sort_state)) {
60 case SORT_FIELD_DATE:
61 return sort_order(branch_sort_state, timecmp(&branch1->time, &branch2->time));
63 case SORT_FIELD_AUTHOR:
64 return sort_order(branch_sort_state, ident_compare(branch1->author, branch2->author));
66 case SORT_FIELD_NAME:
67 default:
68 return sort_order(branch_sort_state, strcmp(branch1->ref->name, branch2->ref->name));
72 static struct sortable branch_sortable = { &branch_sort_state, branch_compare };
74 static bool
75 branch_draw(struct view *view, struct line *line, unsigned int lineno)
77 struct branch_state *state = view->private;
78 struct branch *branch = line->data;
79 enum line_type type = branch_is_all(branch) ? LINE_DEFAULT : get_line_type_from_ref(branch->ref);
80 const char *branch_name = branch_is_all(branch) ? BRANCH_ALL_NAME : branch->ref->name;
82 if (draw_lineno(view, lineno))
83 return TRUE;
85 if (draw_date(view, &branch->time))
86 return TRUE;
88 if (draw_author(view, branch->author))
89 return TRUE;
91 if (draw_field(view, type, branch_name, state->max_ref_length, ALIGN_LEFT, FALSE))
92 return TRUE;
94 if (draw_id(view, branch->ref->id))
95 return TRUE;
97 draw_text(view, LINE_DEFAULT, branch->title);
98 return TRUE;
101 static enum request
102 branch_request(struct view *view, enum request request, struct line *line)
104 struct branch *branch = line->data;
106 switch (request) {
107 case REQ_REFRESH:
108 load_refs(TRUE);
109 refresh_view(view);
110 return REQ_NONE;
112 case REQ_ENTER:
114 const struct ref *ref = branch->ref;
115 const char *all_branches_argv[] = {
116 GIT_MAIN_LOG(encoding_arg, commit_order_arg(), "", branch_is_all(branch) ? "--all" : ref->name, "")
118 struct view *main_view = VIEW(REQ_VIEW_MAIN);
120 open_argv(view, main_view, all_branches_argv, NULL, OPEN_SPLIT);
121 return REQ_NONE;
123 case REQ_JUMP_COMMIT:
125 int lineno;
127 for (lineno = 0; lineno < view->lines; lineno++) {
128 struct branch *branch = view->line[lineno].data;
130 if (!strncasecmp(branch->ref->id, view->env->search, strlen(view->env->search))) {
131 select_view_line(view, lineno);
132 report_clear();
133 return REQ_NONE;
137 default:
138 return request;
142 static bool
143 branch_read(struct view *view, char *line)
145 struct branch_state *state = view->private;
146 const char *title = NULL;
147 const struct ident *author = NULL;
148 struct time time = {};
149 size_t i;
151 if (!line)
152 return TRUE;
154 switch (get_line_type(line)) {
155 case LINE_COMMIT:
156 string_copy_rev_from_commit_line(state->id, line);
157 return TRUE;
159 case LINE_AUTHOR:
160 parse_author_line(line + STRING_SIZE("author "), &author, &time);
161 break;
163 default:
164 title = line + STRING_SIZE("title ");
167 for (i = 0; i < view->lines; i++) {
168 struct branch *branch = view->line[i].data;
170 if (strcmp(branch->ref->id, state->id))
171 continue;
173 if (author) {
174 branch->author = author;
175 branch->time = time;
178 if (title)
179 string_expand(branch->title, sizeof(branch->title), title, 1);
181 view->line[i].dirty = TRUE;
184 return TRUE;
187 static bool
188 branch_open_visitor(void *data, const struct ref *ref)
190 struct view *view = data;
191 struct branch_state *state = view->private;
192 struct branch *branch;
193 bool is_all = ref == &branch_all;
194 size_t ref_length;
196 if (ref->tag || ref->ltag)
197 return TRUE;
199 if (!add_line_alloc(view, &branch, LINE_DEFAULT, 0, is_all))
200 return FALSE;
202 ref_length = is_all ? STRING_SIZE(BRANCH_ALL_NAME) : strlen(ref->name);
203 if (ref_length > state->max_ref_length)
204 state->max_ref_length = ref_length;
206 branch->ref = ref;
207 return TRUE;
210 static bool
211 branch_open(struct view *view, enum open_flags flags)
213 const char *branch_log[] = {
214 "git", "log", encoding_arg, "--no-color", "--date=raw",
215 "--pretty=format:commit %H%nauthor %an <%ae> %ad%ntitle %s",
216 "--all", "--simplify-by-decoration", NULL
219 if (!begin_update(view, NULL, branch_log, OPEN_RELOAD)) {
220 report("Failed to load branch data");
221 return FALSE;
224 branch_open_visitor(view, &branch_all);
225 foreach_ref(branch_open_visitor, view);
227 return TRUE;
230 static bool
231 branch_grep(struct view *view, struct line *line)
233 struct branch *branch = line->data;
234 const char *text[] = {
235 branch->ref->name,
236 mkauthor(branch->author, opt_author_width, opt_show_author),
237 NULL
240 return grep_text(view, text);
243 static void
244 branch_select(struct view *view, struct line *line)
246 struct branch *branch = line->data;
248 if (branch_is_all(branch)) {
249 string_copy(view->ref, BRANCH_ALL_NAME);
250 return;
252 string_copy_rev(view->ref, branch->ref->id);
253 string_copy_rev(view->env->commit, branch->ref->id);
254 string_copy_rev(view->env->head, branch->ref->id);
255 string_copy_rev(view->env->branch, branch->ref->name);
258 struct view_ops branch_ops = {
259 "branch",
260 { "branch" },
261 argv_env.head,
262 VIEW_REFRESH,
263 sizeof(struct branch_state),
264 branch_open,
265 branch_read,
266 branch_draw,
267 branch_request,
268 branch_grep,
269 branch_select,
270 NULL,
271 &branch_sortable,
274 /* vim: set ts=8 sw=8 noexpandtab: */