support for binding :commands to keys
[cmus.git] / cmus / search_mode.c
blob77f812171cd1ea3a47d220076665c0c527551cb2
1 /*
2 * Copyright 2004 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include <search_mode.h>
21 #include <cmdline.h>
22 #include <history.h>
23 #include <ui_curses.h>
24 #include <search.h>
25 #include <xmalloc.h>
26 #include <xstrjoin.h>
27 #include <misc.h>
28 #include <pl.h>
30 #include <curses.h>
31 #include <ctype.h>
33 /* this is set in ui_curses.c */
34 enum search_direction search_direction = SEARCH_FORWARD;
36 /* current search string, this is set _only_ when user presses enter
37 * this string is used when 'n' or 'N' is pressed
38 * incremental search does not use this, it uses cmdline.line directly
40 char *search_str = NULL;
41 int search_restricted = 0;
43 static int search_found = 0;
44 static struct history search_history;
45 static char *search_history_filename;
46 static char *history_search_text = NULL;
48 static void update_search_line(const char *text, int restricted)
50 int len = strlen(text);
51 char ch = search_direction == SEARCH_FORWARD ? '/' : '?';
52 char *buf, *ptr;
54 buf = xnew(char, len + 2);
55 ptr = buf;
56 if (restricted)
57 *ptr++ = ch;
58 memcpy(ptr, text, len + 1);
59 cmdline_set_text(buf);
60 free(buf);
63 static int search_line_empty(void)
65 char ch;
67 if (cmdline.clen == 0)
68 return 1;
69 if (cmdline.clen > 1)
70 return 0;
71 ch = search_direction == SEARCH_FORWARD ? '/' : '?';
72 return cmdline.line[0] == ch;
75 static void parse_line(const char **text, int *restricted)
77 char ch = search_direction == SEARCH_FORWARD ? '/' : '?';
78 int r = 0;
80 if (cmdline.line[0] == ch) {
81 /* //WORDS or ??WORDS */
82 r = 1;
84 *text = cmdline.line + r;
85 *restricted = r;
88 static void reset_history_search(void)
90 history_reset_search(&search_history);
91 free(history_search_text);
92 history_search_text = NULL;
95 static void backspace(void)
97 if (cmdline.clen > 0) {
98 cmdline_backspace();
99 } else {
100 ui_curses_input_mode = NORMAL_MODE;
104 void search_mode_ch(uchar ch)
106 const char *text;
107 int restricted;
109 switch (ch) {
110 case 0x1B:
111 parse_line(&text, &restricted);
112 if (text[0]) {
113 history_add_line(&search_history, text);
114 cmdline_clear();
116 ui_curses_input_mode = NORMAL_MODE;
117 break;
118 case 0x0A:
119 parse_line(&text, &restricted);
120 if (text[0] == 0) {
121 /* cmdline is "/", "?", "//" or "??" */
122 if (search_str) {
123 /* use old search string */
124 search_restricted = restricted;
125 search_found = search_next(searchable, search_str, search_direction);
127 } else {
128 /* set new search string and add it to the history */
129 free(search_str);
130 search_str = xstrdup(text);
131 history_add_line(&search_history, text);
133 /* search not yet done if up or down arrow was pressed */
134 search_restricted = restricted;
135 search_found = search(searchable, search_str, search_direction, 0);
137 cmdline_clear();
138 if (!search_found)
139 ui_curses_search_not_found();
140 ui_curses_input_mode = NORMAL_MODE;
141 break;
142 case 127:
143 backspace();
144 break;
145 default:
146 if (ch < 0x20) {
147 return;
148 } else {
149 /* start from beginning if this is first char */
150 int beginning = search_line_empty();
152 /* save old value
154 * don't set search_{str,restricted} here because
155 * search can be cancelled by pressing ESC
157 restricted = search_restricted;
159 cmdline_insert_ch(ch);
160 parse_line(&text, &search_restricted);
161 search_found = search(searchable, text, search_direction, beginning);
163 /* restore old value */
164 search_restricted = restricted;
166 break;
168 reset_history_search();
171 void search_mode_key(int key)
173 const char *text;
174 int restricted;
176 switch (key) {
177 case KEY_DC:
178 /* save old value */
179 restricted = search_restricted;
181 cmdline_delete_ch();
182 parse_line(&text, &search_restricted);
183 if (text[0])
184 search_found = search(searchable, text, search_direction, 0);
186 /* restore old value */
187 search_restricted = restricted;
188 break;
189 case KEY_BACKSPACE:
190 backspace();
191 break;
192 case KEY_LEFT:
193 cmdline_move_left();
194 return;
195 case KEY_RIGHT:
196 cmdline_move_right();
197 return;
198 case KEY_HOME:
199 cmdline_move_home();
200 return;
201 case KEY_END:
202 cmdline_move_end();
203 return;
204 case KEY_UP:
205 parse_line(&text, &restricted);
206 if (history_search_text == NULL)
207 history_search_text = xstrdup(text);
208 text = history_search_forward(&search_history, history_search_text);
209 if (text)
210 update_search_line(text, restricted);
211 return;
212 case KEY_DOWN:
213 if (history_search_text) {
214 parse_line(&text, &restricted);
215 text = history_search_backward(&search_history, history_search_text);
216 if (text) {
217 update_search_line(text, restricted);
218 } else {
219 update_search_line(history_search_text, restricted);
222 return;
223 default:
224 return;
226 reset_history_search();
229 void search_mode_init(void)
231 search_history_filename = xstrjoin(cmus_cache_dir, "/ui_curses_search_history");
232 history_load(&search_history, search_history_filename, 100);
235 void search_mode_exit(void)
237 history_save(&search_history);
238 free(search_history_filename);