updated email address.
[cmus.git] / help.c
blob28c3b9ef304e1c1a1a7a40193a28d521f8dc314c
1 /*
2 * help.c, heavily based on filters.c
3 * (c) 2006, <ft@bewatermyfriend.de>
4 */
6 #include "help.h"
7 #include "window.h"
8 #include "search.h"
9 #include "misc.h"
10 #include "xmalloc.h"
11 #include "keys.h"
12 #include "command_mode.h"
14 #include <ctype.h>
16 struct window *help_win;
17 struct searchable *help_searchable;
19 static LIST_HEAD(help_head);
20 static struct list_head *bound_head;
21 static struct list_head *unbound_head;
23 static inline void help_entry_to_iter(struct help_entry *e, struct iter *iter)
25 iter->data0 = &help_head;
26 iter->data1 = e;
27 iter->data2 = NULL;
30 static GENERIC_ITER_PREV(help_get_prev, struct help_entry, node)
31 static GENERIC_ITER_NEXT(help_get_next, struct help_entry, node)
33 static int help_search_get_current(void *data, struct iter *iter)
35 return window_get_sel(help_win, iter);
38 static int help_search_matches(void *data, struct iter *iter, const char *text)
40 int matched = 0;
41 char **words=get_words(text);
42 if (words[0] != NULL) {
43 struct help_entry *ent;
44 int i;
46 ent = iter_to_help_entry(iter);
47 for (i = 0; ; i++) {
48 if (words[i] == NULL) {
49 window_set_sel(help_win, iter);
50 matched = 1;
51 break;
52 } if (ent->type == HE_TEXT) {
53 if (!u_strcasestr(ent->text, words[i]))
54 break;
55 } else if (ent->type == HE_BOUND) {
56 if (!u_strcasestr(key_context_names[ent->binding->ctx], words[i])
57 && !u_strcasestr(ent->binding->cmd, words[i])
58 && !u_strcasestr(ent->binding->key->name, words[i]))
59 break;
60 } else if (ent->type == HE_UNBOUND) {
61 if (!u_strcasestr(ent->command->name, words[i]))
62 break;
66 free_str_array(words);
67 return matched;
70 static const struct searchable_ops help_search_ops = {
71 .get_prev = help_get_prev,
72 .get_next = help_get_next,
73 .get_current = help_search_get_current,
74 .matches = help_search_matches
77 static struct list_head *help_add_text(const char *s)
79 struct help_entry *ent;
80 ent = xnew(struct help_entry, 1);
81 ent->type = HE_TEXT;
82 ent->text = s;
83 list_add_tail(&ent->node, &help_head);
84 return(&ent->node);
87 static void help_add_defaults(void)
89 help_add_text("Current Keybindings");
90 help_add_text("-----------------------------");
91 bound_head = help_add_text("");
92 help_add_text("Unbound Commands");
93 help_add_text("-----------------------------");
94 unbound_head = help_add_text("");
97 void help_remove_unbound(struct command *cmd)
99 struct help_entry *ent;
100 struct iter i;
101 list_for_each_entry(ent, &help_head, node) {
102 if (ent->type != HE_UNBOUND)
103 continue;
104 if (ent->command == cmd) {
105 help_entry_to_iter(ent, &i);
106 window_row_vanishes(help_win, &i);
107 list_del(&ent->node);
108 free(ent);
109 return;
114 void help_add_unbound(struct command *cmd)
116 struct help_entry *ent;
117 struct command *c = cmd;
118 if (c->bc == 0) {
119 ent=xnew(struct help_entry, 1);
120 ent->type=HE_UNBOUND;
121 ent->command=cmd;
122 list_init(&ent->node);
123 list_add_tail(&ent->node, unbound_head);
127 void help_add_all_unbound(void)
129 int i;
130 for (i = 0; commands[i].name; ++i)
131 if (!commands[i].bc)
132 help_add_unbound(&commands[i]);
135 void help_select(void)
137 /* nothing right now */
140 void help_add(const struct binding *bind)
142 struct help_entry *ent;
143 ent = xnew(struct help_entry, 1);
144 ent->type = HE_BOUND;
145 ent->binding = bind;
146 list_add_tail(&ent->node, bound_head);
149 void help_remove(const struct binding *bind)
151 struct help_entry *ent;
152 struct iter i;
153 list_for_each_entry(ent, &help_head, node) {
154 if (ent->binding == bind) {
155 help_entry_to_iter(ent, &i);
156 window_row_vanishes(help_win, &i);
157 list_del(&ent->node);
158 free(ent);
159 return;
164 void help_init(void)
166 struct iter iter;
168 help_win = window_new(help_get_prev, help_get_next);
169 window_set_contents(help_win, &help_head);
170 window_changed(help_win);
171 help_add_defaults();
173 iter.data0 = &help_head;
174 iter.data1 = NULL;
175 iter.data2 = NULL;
176 help_searchable = searchable_new(NULL, &iter, &help_search_ops);
179 void help_exit(void)
181 searchable_free(help_searchable);
182 window_free(help_win);