Add option to install Tig with Homebrew
[tig.git] / src / help.c
blob7853941853771c0d6f8472a450f9437b59540529
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 return FALSE;
159 if (iterator->keymap->hidden)
160 return FALSE;
162 if (iterator->group != group) {
163 iterator->group = group;
164 if (!add_help_line(iterator->view, &help, iterator->keymap, LINE_HELP_GROUP))
165 return FALSE;
166 help->data.text = group;
169 return TRUE;
172 static bool
173 help_open_keymap(void *data, const struct request_info *req_info, const char *group)
175 struct help_request_iterator *iterator = data;
176 struct help_state *state = iterator->view->private;
177 struct keymap *keymap = iterator->keymap;
178 const char *key = get_keys(keymap, req_info->request, TRUE);
179 struct help *help;
181 if (req_info->request == REQ_NONE || !key || !*key)
182 return TRUE;
184 if (!add_help_headers(iterator, group) ||
185 !add_help_line(iterator->view, &help, iterator->keymap, LINE_DEFAULT))
186 return FALSE;
188 state->keys_width = MAX(state->keys_width, strlen(key));
189 state->name_width = MAX(state->name_width, strlen(enum_name(req_info->name)));
191 help->data.req_info = req_info;
192 help->request = req_info->request;
194 return TRUE;
197 static void
198 help_open_keymap_run_requests(struct help_request_iterator *iterator, bool internal, bool toggles)
200 struct view *view = iterator->view;
201 struct help_state *state = view->private;
202 struct keymap *keymap = iterator->keymap;
203 const char *group = !internal ? "External commands:" :
204 toggles ? "Option toggling:" :
205 "Internal commands:";
206 enum request request = REQ_RUN_REQUESTS + 1;
207 struct help *help;
209 for (; TRUE; request++) {
210 struct run_request *req = get_run_request(request);
211 const char *key;
213 if (!req)
214 break;
216 if (req->flags.internal != !!internal ||
217 req->keymap != keymap ||
218 !*(key = get_keys(keymap, request, TRUE)))
219 continue;
221 if (toggles != !strcmp(req->argv[0], "toggle"))
222 continue;
224 if (!add_help_headers(iterator, group) ||
225 !add_help_line(view, &help, keymap, LINE_DEFAULT))
226 return;
228 state->keys_width = MAX(state->keys_width, strlen(key));
230 help->request = request;
234 static bool
235 help_open(struct view *view, enum open_flags flags)
237 struct keymap *keymap;
238 struct help *help;
239 int i;
241 reset_view(view);
243 if (!add_help_line(view, &help, NULL, LINE_HEADER))
244 return FALSE;
245 help->data.text = "Quick reference for tig keybindings:";
247 if (!add_help_line(view, &help, NULL, LINE_DEFAULT))
248 return FALSE;
249 help->data.text = "";
251 for (i = 0; (keymap = get_keymap_by_index(i)); i++) {
252 struct help_request_iterator iterator = { view, keymap, TRUE };
254 if (foreach_request(help_open_keymap, &iterator)) {
255 help_open_keymap_run_requests(&iterator, TRUE, TRUE);
256 help_open_keymap_run_requests(&iterator, TRUE, FALSE);
257 help_open_keymap_run_requests(&iterator, FALSE, FALSE);
261 return TRUE;
264 static enum request
265 help_request(struct view *view, enum request request, struct line *line)
267 struct help *help = line->data;
269 switch (request) {
270 case REQ_ENTER:
271 if (line->type == LINE_SECTION) {
272 struct keymap *keymap = help->keymap;
274 keymap->hidden = !keymap->hidden;
275 refresh_view(view);
277 return REQ_NONE;
279 case REQ_REFRESH:
280 refresh_view(view);
281 return REQ_NONE;
283 default:
284 return request;
288 void
289 help_select(struct view *view, struct line *line)
293 static struct view_ops help_ops = {
294 "line",
296 VIEW_NO_GIT_DIR | VIEW_REFRESH,
297 sizeof(struct help_state),
298 help_open,
299 NULL,
300 help_draw,
301 help_request,
302 help_grep,
303 help_select,
304 NULL,
307 DEFINE_VIEW(help);
309 /* vim: set ts=8 sw=8 noexpandtab: */