prompt: teach read_prompt_incremental() to allow empty input
[tig.git] / src / help.c
blobcfa8224a3ce8bee3bafdf4904a08ff223e54f33f
1 /* Copyright (c) 2006-2015 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 const 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 const char *sep = format_run_request_flags(req);
54 int i;
56 if (draw_field(view, LINE_DEFAULT, key, state->keys_width + 2, ALIGN_RIGHT, FALSE))
57 return TRUE;
59 for (i = 0; req->argv[i]; i++) {
60 if (draw_formatted(view, LINE_HELP_ACTION, "%s%s", sep, req->argv[i]))
61 return TRUE;
62 sep = " ";
65 } else {
66 const struct request_info *req_info = help->data.req_info;
67 const char *key = get_keys(keymap, req_info->request, TRUE);
69 if (draw_field(view, LINE_DEFAULT, key, state->keys_width + 2, ALIGN_RIGHT, FALSE))
70 return TRUE;
72 if (draw_field(view, LINE_HELP_ACTION, enum_name(req_info->name), state->name_width, ALIGN_LEFT, FALSE))
73 return TRUE;
75 draw_text(view, LINE_DEFAULT, req_info->help);
78 return TRUE;
81 bool
82 help_grep(struct view *view, struct line *line)
84 struct help *help = line->data;
85 const struct keymap *keymap = help->keymap;
87 if (line->type == LINE_SECTION) {
88 const char *text[] = { keymap->name, NULL };
90 return grep_text(view, text);
92 } else if (line->type == LINE_HELP_GROUP || !keymap) {
93 const char *text[] = { help->data.text, NULL };
95 return grep_text(view, text);
97 } else if (help->request > REQ_RUN_REQUESTS) {
98 struct run_request *req = get_run_request(help->request);
99 const char *key = get_keys(keymap, help->request, TRUE);
100 char buf[SIZEOF_STR] = "";
101 const char *text[] = { key, buf, NULL };
103 if (!argv_to_string(req->argv, buf, sizeof(buf), " "))
104 return FALSE;
106 return grep_text(view, text);
108 } else {
109 const struct request_info *req_info = help->data.req_info;
110 const char *key = get_keys(keymap, req_info->request, TRUE);
111 const char *text[] = { key, enum_name(req_info->name), req_info->help, NULL };
113 return grep_text(view, text);
117 struct help_request_iterator {
118 struct view *view;
119 struct keymap *keymap;
122 static bool
123 add_help_line(struct view *view, struct help **help_ptr, struct keymap *keymap, enum line_type type)
125 struct help *help;
127 if (!add_line_alloc(view, &help, type, 0, FALSE))
128 return FALSE;
129 help->keymap = keymap;
130 if (help_ptr)
131 *help_ptr = help;
132 return TRUE;
135 static bool
136 help_keys_visitor(void *data, const char *group, struct keymap *keymap,
137 enum request request, const char *key,
138 const struct request_info *req_info, const struct run_request *run_req)
140 struct help_request_iterator *iterator = data;
141 struct view *view = iterator->view;
142 struct help_state *state = view->private;
143 struct help *help;
145 if (iterator->keymap != keymap) {
146 iterator->keymap = keymap;
147 if (!add_help_line(iterator->view, &help, keymap, LINE_SECTION))
148 return FALSE;
151 if (keymap->hidden)
152 return TRUE;
154 if (group) {
155 if (!add_help_line(iterator->view, &help, keymap, LINE_HELP_GROUP))
156 return FALSE;
157 help->data.text = group;
160 if (!add_help_line(view, &help, keymap, LINE_DEFAULT))
161 return FALSE;
163 state->keys_width = MAX(state->keys_width, strlen(key));
164 help->request = request;
166 if (req_info) {
167 state->name_width = MAX(state->name_width, strlen(enum_name(req_info->name)));
168 help->data.req_info = req_info;
171 return TRUE;
174 static bool
175 help_open(struct view *view, enum open_flags flags)
177 struct help_request_iterator iterator = { view };
178 struct help *help;
180 reset_view(view);
182 if (!add_help_line(view, &help, NULL, LINE_HEADER))
183 return FALSE;
184 help->data.text = "Quick reference for tig keybindings:";
186 if (!add_help_line(view, &help, NULL, LINE_DEFAULT))
187 return FALSE;
188 help->data.text = "";
190 return foreach_key(help_keys_visitor, &iterator, TRUE);
193 static enum request
194 help_request(struct view *view, enum request request, struct line *line)
196 struct help *help = line->data;
198 switch (request) {
199 case REQ_ENTER:
200 if (line->type == LINE_SECTION) {
201 struct keymap *keymap = help->keymap;
203 keymap->hidden = !keymap->hidden;
204 refresh_view(view);
206 return REQ_NONE;
208 case REQ_REFRESH:
209 refresh_view(view);
210 return REQ_NONE;
212 default:
213 return request;
217 void
218 help_select(struct view *view, struct line *line)
222 static struct view_ops help_ops = {
223 "line",
225 VIEW_NO_GIT_DIR | VIEW_REFRESH,
226 sizeof(struct help_state),
227 help_open,
228 NULL,
229 help_draw,
230 help_request,
231 help_grep,
232 help_select,
233 NULL,
236 DEFINE_VIEW(help);
238 /* vim: set ts=8 sw=8 noexpandtab: */