Add :exec prompt command and inline test commands that uses key bindings
[tig.git] / src / log.c
blob1606f876e3c5c18be7f1cc1aee3bad4287136bb4
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/display.h"
16 #include "tig/draw.h"
17 #include "tig/log.h"
18 #include "tig/diff.h"
19 #include "tig/pager.h"
21 struct log_state {
22 /* Used for tracking when we need to recalculate the previous
23 * commit, for example when the user scrolls up or uses the page
24 * up/down in the log view. */
25 int last_lineno;
26 size_t graph_indent;
27 enum line_type last_type;
28 bool commit_title_read;
29 bool after_commit_header;
30 bool reading_diff_stat;
33 static inline void
34 log_copy_rev(struct view *view, struct line *line)
36 const char *text = line->data;
37 size_t offset = get_graph_indent(text);
39 string_copy_rev_from_commit_line(view->ref, text + offset);
42 static void
43 log_select(struct view *view, struct line *line)
45 struct log_state *state = view->private;
46 int last_lineno = state->last_lineno;
48 if (!last_lineno || abs(last_lineno - line->lineno) > 1
49 || (state->last_type == LINE_COMMIT && last_lineno > line->lineno)) {
50 struct line *commit_line = find_prev_line_by_type(view, line, LINE_COMMIT);
52 if (commit_line)
53 log_copy_rev(view, commit_line);
56 if (line->type == LINE_COMMIT && !view_has_flags(view, VIEW_NO_REF))
57 log_copy_rev(view, line);
58 string_copy_rev(view->env->commit, view->ref);
59 state->last_lineno = line->lineno;
60 state->last_type = line->type;
63 static bool
64 log_open(struct view *view, enum open_flags flags)
66 const char *log_argv[] = {
67 "git", "log", encoding_arg, commit_order_arg(), "--cc",
68 "--stat", "%(logargs)", "%(cmdlineargs)", "%(revargs)",
69 "--no-color", "--", "%(fileargs)", NULL
72 return begin_update(view, NULL, log_argv, flags);
75 static enum request
76 log_request(struct view *view, enum request request, struct line *line)
78 switch (request) {
79 case REQ_REFRESH:
80 load_refs(TRUE);
81 refresh_view(view);
82 return REQ_NONE;
84 case REQ_ENTER:
85 if (!display[1] || strcmp(display[1]->vid, view->ref))
86 open_diff_view(view, OPEN_SPLIT);
87 return REQ_NONE;
89 default:
90 return request;
94 static bool
95 log_read(struct view *view, struct buffer *buf)
97 struct line *line = NULL;
98 enum line_type type;
99 struct log_state *state = view->private;
100 size_t len;
101 char *commit;
102 char *data;
104 if (!buf)
105 return TRUE;
107 data = buf->data;
108 commit = strstr(data, "commit ");
109 if (commit && get_graph_indent(data) == commit - data)
110 state->graph_indent = commit - data;
112 type = get_line_type(data + state->graph_indent);
113 len = strlen(data + state->graph_indent);
115 if (type == LINE_COMMIT)
116 state->commit_title_read = TRUE;
117 else if (state->commit_title_read && len < 1) {
118 state->commit_title_read = FALSE;
119 state->after_commit_header = TRUE;
120 } else if (state->after_commit_header && len < 1) {
121 state->after_commit_header = FALSE;
122 state->reading_diff_stat = TRUE;
123 } else if (state->reading_diff_stat) {
124 line = diff_common_add_diff_stat(view, data, state->graph_indent);
125 if (line) {
126 if (state->graph_indent)
127 line->graph_indent = 1;
128 return TRUE;
130 state->reading_diff_stat = FALSE;
133 if (!pager_common_read(view, data, type, &line))
134 return FALSE;
135 if (line && state->graph_indent)
136 line->graph_indent = 1;
137 return TRUE;
140 static struct view_ops log_ops = {
141 "line",
142 argv_env.head,
143 VIEW_ADD_PAGER_REFS | VIEW_OPEN_DIFF | VIEW_SEND_CHILD_ENTER | VIEW_LOG_LIKE | VIEW_REFRESH,
144 sizeof(struct log_state),
145 log_open,
146 log_read,
147 view_column_draw,
148 log_request,
149 view_column_grep,
150 log_select,
151 NULL,
152 view_column_bit(LINE_NUMBER) | view_column_bit(TEXT),
153 pager_get_column_data,
156 DEFINE_VIEW(log);
158 /* vim: set ts=8 sw=8 noexpandtab: */