Introduce common section color
[tig.git] / src / help.c
blobc2b40f30717bf431bafa7e5cdbce2f95732657fc
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/argv.h"
15 #include "tig/view.h"
16 #include "tig/draw.h"
19 * Help backend
22 struct help_state {
23 int keys_width;
24 int name_width;
27 struct help {
28 struct keymap *keymap;
29 enum request request;
30 union {
31 const char *text;
32 const struct request_info *req_info;
33 } data;
36 static bool
37 help_draw(struct view *view, struct line *line, unsigned int lineno)
39 struct help *help = line->data;
40 struct keymap *keymap = help->keymap;
41 struct help_state *state = view->private;
43 if (line->type == LINE_SECTION) {
44 draw_formatted(view, line->type, "[%c] %s bindings",
45 keymap->hidden ? '+' : '-', keymap->name);
47 } else if (line->type == LINE_HELP_GROUP || !keymap) {
48 draw_text(view, line->type, help->data.text);
50 } else if (help->request > REQ_RUN_REQUESTS) {
51 struct run_request *req = get_run_request(help->request);
52 const char *key = get_keys(keymap, help->request, TRUE);
53 char flags[8] = { req->flags.internal ? ':' : '!', 0 };
54 const char *sep = flags;
55 int flagspos = req->flags.internal ? 1 : 0;
56 int i;
58 if (draw_field(view, LINE_DEFAULT, key, state->keys_width + 2, ALIGN_RIGHT, FALSE))
59 return TRUE;
61 if (req->flags.silent)
62 flags[flagspos++] = '@';
63 if (req->flags.confirm)
64 flags[flagspos++] = '?';
65 if (req->flags.exit)
66 flags[flagspos++] = '<';
67 if (flagspos > 1)
68 flags[flagspos++] = 0;
70 for (i = 0; req->argv[i]; i++) {
71 if (draw_formatted(view, LINE_HELP_ACTION, "%s%s", sep, req->argv[i]))
72 return TRUE;
73 sep = " ";
76 } else {
77 const struct request_info *req_info = help->data.req_info;
78 const char *key = get_keys(keymap, req_info->request, TRUE);
80 if (draw_field(view, LINE_DEFAULT, key, state->keys_width + 2, ALIGN_RIGHT, FALSE))
81 return TRUE;
83 if (draw_field(view, LINE_HELP_ACTION, enum_name(req_info->name), state->name_width, ALIGN_LEFT, FALSE))
84 return TRUE;
86 draw_text(view, LINE_DEFAULT, req_info->help);
89 return TRUE;
92 bool
93 help_grep(struct view *view, struct line *line)
95 struct help *help = line->data;
96 struct keymap *keymap = help->keymap;
98 if (line->type == LINE_SECTION) {
99 const char *text[] = { keymap->name, NULL };
101 return grep_text(view, text);
103 } else if (line->type == LINE_HELP_GROUP || !keymap) {
104 const char *text[] = { help->data.text, NULL };
106 return grep_text(view, text);
108 } else if (help->request > REQ_RUN_REQUESTS) {
109 struct run_request *req = get_run_request(help->request);
110 const char *key = get_keys(keymap, help->request, TRUE);
111 char buf[SIZEOF_STR] = "";
112 const char *text[] = { key, buf, NULL };
114 if (!argv_to_string(req->argv, buf, sizeof(buf), " "))
115 return FALSE;
117 return grep_text(view, text);
119 } else {
120 const struct request_info *req_info = help->data.req_info;
121 const char *key = get_keys(keymap, req_info->request, TRUE);
122 const char *text[] = { key, enum_name(req_info->name), req_info->help, NULL };
124 return grep_text(view, text);
128 struct help_request_iterator {
129 struct view *view;
130 struct keymap *keymap;
131 bool add_title;
132 const char *group;
135 static bool
136 add_help_line(struct view *view, struct help **help_ptr, struct keymap *keymap, enum line_type type)
138 struct help *help;
140 if (!add_line_alloc(view, &help, type, 0, FALSE))
141 return FALSE;
142 help->keymap = keymap;
143 if (help_ptr)
144 *help_ptr = help;
145 return TRUE;
148 static bool
149 add_help_headers(struct help_request_iterator *iterator, const char *group)
151 struct help *help;
153 if (iterator->add_title) {
154 iterator->add_title = FALSE;
155 if (!add_help_line(iterator->view, &help, iterator->keymap, LINE_SECTION) ||
156 iterator->keymap->hidden)
157 return FALSE;
160 if (iterator->group != group) {
161 iterator->group = group;
162 if (!add_help_line(iterator->view, &help, iterator->keymap, LINE_HELP_GROUP))
163 return FALSE;
164 help->data.text = group;
167 return TRUE;
170 static bool
171 help_open_keymap(void *data, const struct request_info *req_info, const char *group)
173 struct help_request_iterator *iterator = data;
174 struct help_state *state = iterator->view->private;
175 struct keymap *keymap = iterator->keymap;
176 const char *key = get_keys(keymap, req_info->request, TRUE);
177 struct help *help;
179 if (req_info->request == REQ_NONE || !key || !*key)
180 return TRUE;
182 if (!add_help_headers(iterator, group) ||
183 !add_help_line(iterator->view, &help, iterator->keymap, LINE_DEFAULT))
184 return FALSE;
186 state->keys_width = MAX(state->keys_width, strlen(key));
187 state->name_width = MAX(state->name_width, strlen(enum_name(req_info->name)));
189 help->data.req_info = req_info;
190 help->request = req_info->request;
192 return TRUE;
195 static void
196 help_open_keymap_run_requests(struct help_request_iterator *iterator, bool internal)
198 struct view *view = iterator->view;
199 struct help_state *state = view->private;
200 struct keymap *keymap = iterator->keymap;
201 const char *group = internal ? "Internal commands: " : "External commands:";
202 enum request request = REQ_RUN_REQUESTS + 1;
203 struct help *help;
205 for (; TRUE; request++) {
206 struct run_request *req = get_run_request(request);
207 const char *key;
209 if (!req)
210 break;
212 if (req->flags.internal != !!internal ||
213 req->keymap != keymap ||
214 !*(key = get_keys(keymap, request, TRUE)))
215 continue;
217 if (!add_help_headers(iterator, group) ||
218 !add_help_line(view, &help, keymap, LINE_DEFAULT))
219 return;
221 state->keys_width = MAX(state->keys_width, strlen(key));
223 help->request = request;
227 static bool
228 help_open(struct view *view, enum open_flags flags)
230 struct keymap *keymap;
231 struct help *help;
232 int i;
234 reset_view(view);
236 if (!add_help_line(view, &help, NULL, LINE_HEADER))
237 return FALSE;
238 help->data.text = "Quick reference for tig keybindings:";
240 if (!add_help_line(view, &help, NULL, LINE_DEFAULT))
241 return FALSE;
242 help->data.text = "";
244 for (i = 0; (keymap = get_keymap_by_index(i)); i++) {
245 struct help_request_iterator iterator = { view, keymap, TRUE };
247 if (foreach_request(help_open_keymap, &iterator)) {
248 help_open_keymap_run_requests(&iterator, TRUE);
249 help_open_keymap_run_requests(&iterator, FALSE);
253 return TRUE;
256 static enum request
257 help_request(struct view *view, enum request request, struct line *line)
259 struct help *help = line->data;
261 switch (request) {
262 case REQ_ENTER:
263 if (line->type == LINE_SECTION) {
264 struct keymap *keymap = help->keymap;
266 keymap->hidden = !keymap->hidden;
267 refresh_view(view);
269 return REQ_NONE;
271 case REQ_REFRESH:
272 refresh_view(view);
273 return REQ_NONE;
275 default:
276 return request;
280 void
281 help_select(struct view *view, struct line *line)
285 static struct view_ops help_ops = {
286 "line",
288 VIEW_NO_GIT_DIR,
289 sizeof(struct help_state),
290 help_open,
291 NULL,
292 help_draw,
293 help_request,
294 help_grep,
295 help_select,
296 NULL,
299 DEFINE_VIEW(help);
301 /* vim: set ts=8 sw=8 noexpandtab: */