2 * help.c, heavily based on filters.c
3 * (c) 2006, <ft@bewatermyfriend.org>
12 #include "command_mode.h"
13 #include "ui_curses.h"
19 struct window
*help_win
;
20 struct searchable
*help_searchable
;
22 static LIST_HEAD(help_head
);
23 static struct list_head
*bound_head
;
24 static struct list_head
*bound_tail
;
25 static struct list_head
*unbound_head
;
26 static struct list_head
*unbound_tail
;
28 static inline void help_entry_to_iter(struct help_entry
*e
, struct iter
*iter
)
30 iter
->data0
= &help_head
;
35 static GENERIC_ITER_PREV(help_get_prev
, struct help_entry
, node
)
36 static GENERIC_ITER_NEXT(help_get_next
, struct help_entry
, node
)
38 static int help_search_get_current(void *data
, struct iter
*iter
)
40 return window_get_sel(help_win
, iter
);
43 static int help_search_matches(void *data
, struct iter
*iter
, const char *text
)
46 char **words
= get_words(text
);
48 if (words
[0] != NULL
) {
49 struct help_entry
*ent
;
52 ent
= iter_to_help_entry(iter
);
54 if (words
[i
] == NULL
) {
55 window_set_sel(help_win
, iter
);
59 if (ent
->type
== HE_TEXT
) {
60 if (!u_strcasestr(ent
->text
, words
[i
]))
62 } else if (ent
->type
== HE_BOUND
) {
63 if (!u_strcasestr(ent
->binding
->cmd
, words
[i
]) &&
64 !u_strcasestr(ent
->binding
->key
->name
, words
[i
]))
66 } else if (ent
->type
== HE_UNBOUND
) {
67 if (!u_strcasestr(ent
->command
->name
, words
[i
]))
69 } else if (ent
->type
== HE_OPTION
) {
70 if (!u_strcasestr(ent
->option
->name
, words
[i
]))
75 free_str_array(words
);
79 static const struct searchable_ops help_search_ops
= {
80 .get_prev
= help_get_prev
,
81 .get_next
= help_get_next
,
82 .get_current
= help_search_get_current
,
83 .matches
= help_search_matches
86 static void help_add_text(const char *s
)
88 struct help_entry
*ent
;
89 ent
= xnew(struct help_entry
, 1);
92 list_add_tail(&ent
->node
, &help_head
);
95 static void help_add_defaults(void)
99 help_add_text("Keybindings");
100 help_add_text("-----------");
101 bound_head
= help_head
.prev
;
103 help_add_text("Unbound Commands");
104 help_add_text("----------------");
105 unbound_head
= help_head
.prev
;
107 help_add_text("Options");
108 help_add_text("-------");
110 list_for_each_entry(opt
, &option_head
, node
) {
111 struct help_entry
*ent
= xnew(struct help_entry
, 1);
113 ent
->type
= HE_OPTION
;
115 list_add_tail(&ent
->node
, &help_head
);
118 bound_tail
= bound_head
->next
;
119 unbound_tail
= unbound_head
->next
;
122 void help_remove_unbound(struct command
*cmd
)
124 struct help_entry
*ent
;
126 list_for_each_entry(ent
, &help_head
, node
) {
127 if (ent
->type
!= HE_UNBOUND
)
129 if (ent
->command
== cmd
) {
130 help_entry_to_iter(ent
, &i
);
131 window_row_vanishes(help_win
, &i
);
132 list_del(&ent
->node
);
139 static void list_add_sorted(struct list_head
*new, struct list_head
*head
,
140 struct list_head
*tail
,
141 int (*cmp
)(struct list_head
*, struct list_head
*))
143 struct list_head
*item
= tail
->prev
;
145 while (item
!= head
) {
146 if (cmp(new, item
) >= 0)
154 static int bound_cmp(struct list_head
*ai
, struct list_head
*bi
)
156 struct help_entry
*a
= container_of(ai
, struct help_entry
, node
);
157 struct help_entry
*b
= container_of(bi
, struct help_entry
, node
);
158 int ret
= a
->binding
->ctx
- b
->binding
->ctx
;
161 ret
= strcmp(a
->binding
->key
->name
, b
->binding
->key
->name
);
165 static int unbound_cmp(struct list_head
*ai
, struct list_head
*bi
)
167 struct help_entry
*a
= container_of(ai
, struct help_entry
, node
);
168 struct help_entry
*b
= container_of(bi
, struct help_entry
, node
);
170 return strcmp(a
->command
->name
, b
->command
->name
);
173 void help_add_unbound(struct command
*cmd
)
175 struct help_entry
*ent
;
177 ent
= xnew(struct help_entry
, 1);
178 ent
->type
= HE_UNBOUND
;
180 list_add_sorted(&ent
->node
, unbound_head
, unbound_tail
, unbound_cmp
);
183 void help_add_all_unbound(void)
186 for (i
= 0; commands
[i
].name
; ++i
)
188 help_add_unbound(&commands
[i
]);
191 void help_select(void)
194 struct help_entry
*ent
;
197 if (!window_get_sel(help_win
, &sel
))
200 ent
= iter_to_help_entry(&sel
);
203 snprintf(buf
, sizeof(buf
), "bind -f %s %s %s",
204 key_context_names
[ent
->binding
->ctx
],
205 ent
->binding
->key
->name
,
207 cmdline_set_text(buf
);
208 enter_command_mode();
211 snprintf(buf
, sizeof(buf
), "set %s=", ent
->option
->name
);
212 ent
->option
->get(ent
->option
->id
, buf
+ strlen(buf
));
213 cmdline_set_text(buf
);
214 enter_command_mode();
221 void help_toggle(void)
224 struct help_entry
*ent
;
226 if (!window_get_sel(help_win
, &sel
))
229 ent
= iter_to_help_entry(&sel
);
232 if (ent
->option
->toggle
) {
233 ent
->option
->toggle(ent
->option
->id
);
234 help_win
->changed
= 1;
242 void help_remove(void)
245 struct help_entry
*ent
;
247 if (!window_get_sel(help_win
, &sel
))
250 ent
= iter_to_help_entry(&sel
);
253 if (yes_no_query("Remove selected binding? [y/N]"))
254 key_unbind(key_context_names
[ent
->binding
->ctx
],
255 ent
->binding
->key
->name
, 0);
262 void help_add_bound(const struct binding
*bind
)
264 struct help_entry
*ent
;
265 ent
= xnew(struct help_entry
, 1);
266 ent
->type
= HE_BOUND
;
268 list_add_sorted(&ent
->node
, bound_head
, bound_tail
, bound_cmp
);
271 void help_remove_bound(const struct binding
*bind
)
273 struct help_entry
*ent
;
275 list_for_each_entry(ent
, &help_head
, node
) {
276 if (ent
->binding
== bind
) {
277 help_entry_to_iter(ent
, &i
);
278 window_row_vanishes(help_win
, &i
);
279 list_del(&ent
->node
);
290 help_win
= window_new(help_get_prev
, help_get_next
);
291 window_set_contents(help_win
, &help_head
);
292 window_changed(help_win
);
295 iter
.data0
= &help_head
;
298 help_searchable
= searchable_new(NULL
, &iter
, &help_search_ops
);
303 searchable_free(help_searchable
);
304 window_free(help_win
);