flac: Saner EOF handling
[cmus.git] / search_mode.c
blobfe89851e58368ce17482124372ff83db13dc2cd6
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 "lib.h"
30 #include <ctype.h>
32 #if defined(__sun__)
33 #include <ncurses.h>
34 #else
35 #include <curses.h>
36 #endif
38 /* this is set in ui_curses.c */
39 enum search_direction search_direction = SEARCH_FORWARD;
41 /* current search string, this is set _only_ when user presses enter
42 * this string is used when 'n' or 'N' is pressed
43 * incremental search does not use this, it uses cmdline.line directly
45 char *search_str = NULL;
46 int search_restricted = 0;
48 static struct history search_history;
49 static char *search_history_filename;
50 static char *history_search_text = NULL;
52 static void update_search_line(const char *text, int restricted)
54 int len = strlen(text);
55 char ch = search_direction == SEARCH_FORWARD ? '/' : '?';
56 char *buf, *ptr;
58 buf = xnew(char, len + 2);
59 ptr = buf;
60 if (restricted)
61 *ptr++ = ch;
62 memcpy(ptr, text, len + 1);
63 cmdline_set_text(buf);
64 free(buf);
67 static int search_line_empty(void)
69 char ch;
71 if (cmdline.clen == 0)
72 return 1;
73 if (cmdline.clen > 1)
74 return 0;
75 ch = search_direction == SEARCH_FORWARD ? '/' : '?';
76 return cmdline.line[0] == ch;
79 static void parse_line(const char **text, int *restricted)
81 char ch = search_direction == SEARCH_FORWARD ? '/' : '?';
82 int r = 0;
84 if (cmdline.line[0] == ch) {
85 /* //WORDS or ??WORDS */
86 r = 1;
88 *text = cmdline.line + r;
89 *restricted = r;
92 static void reset_history_search(void)
94 history_reset_search(&search_history);
95 free(history_search_text);
96 history_search_text = NULL;
99 static void backspace(void)
101 if (cmdline.clen > 0) {
102 cmdline_backspace();
103 } else {
104 input_mode = NORMAL_MODE;
108 static void delete(void)
110 /* save old value */
111 int restricted = search_restricted;
112 const char *text;
114 cmdline_delete_ch();
115 parse_line(&text, &search_restricted);
116 if (text[0])
117 search(searchable, text, search_direction, 0);
119 /* restore old value */
120 search_restricted = restricted;
123 void search_text(const char *text, int restricted, int beginning)
125 if (text[0] == 0) {
126 /* cmdline is "/", "?", "//" or "??" */
127 if (search_str) {
128 /* use old search string */
129 search_restricted = restricted;
130 if (!search_next(searchable, search_str, search_direction))
131 search_not_found();
133 } else {
134 /* set new search string and add it to the history */
135 free(search_str);
136 search_str = xstrdup(text);
137 history_add_line(&search_history, text);
139 /* search not yet done if up or down arrow was pressed */
140 search_restricted = restricted;
141 if (!search(searchable, search_str, search_direction, beginning))
142 search_not_found();
146 void search_mode_ch(uchar ch)
148 const char *text;
149 int restricted;
151 switch (ch) {
152 case 0x01: // ^A
153 cmdline_move_home();
154 break;
155 case 0x02: // ^B
156 cmdline_move_left();
157 break;
158 case 0x04: // ^D
159 delete();
160 break;
161 case 0x05: // ^E
162 cmdline_move_end();
163 break;
164 case 0x06: // ^F
165 cmdline_move_right();
166 break;
167 case 0x03: // ^C
168 case 0x07: // ^G
169 case 0x1B: // ESC
170 parse_line(&text, &restricted);
171 if (text[0]) {
172 history_add_line(&search_history, text);
173 cmdline_clear();
175 input_mode = NORMAL_MODE;
176 break;
177 case 0x0A:
178 parse_line(&text, &restricted);
179 search_text(text, restricted, 0);
180 cmdline_clear();
181 input_mode = NORMAL_MODE;
182 break;
183 case 0x0B:
184 cmdline_clear_end();
185 break;
186 case 0x15:
187 cmdline_backspace_to_bol();
188 break;
189 case 0x08: // ^H
190 case 127:
191 backspace();
192 break;
193 default:
194 if (ch < 0x20) {
195 return;
196 } else {
197 /* start from beginning if this is first char */
198 int beginning = search_line_empty();
200 /* save old value
202 * don't set search_{str,restricted} here because
203 * search can be cancelled by pressing ESC
205 restricted = search_restricted;
207 cmdline_insert_ch(ch);
208 parse_line(&text, &search_restricted);
209 search(searchable, text, search_direction, beginning);
211 /* restore old value */
212 search_restricted = restricted;
214 break;
216 reset_history_search();
219 void search_mode_key(int key)
221 const char *text;
222 int restricted;
224 switch (key) {
225 case KEY_DC:
226 delete();
227 break;
228 case KEY_BACKSPACE:
229 backspace();
230 break;
231 case KEY_LEFT:
232 cmdline_move_left();
233 return;
234 case KEY_RIGHT:
235 cmdline_move_right();
236 return;
237 case KEY_HOME:
238 cmdline_move_home();
239 return;
240 case KEY_END:
241 cmdline_move_end();
242 return;
243 case KEY_UP:
244 parse_line(&text, &restricted);
245 if (history_search_text == NULL)
246 history_search_text = xstrdup(text);
247 text = history_search_forward(&search_history, history_search_text);
248 if (text)
249 update_search_line(text, restricted);
250 return;
251 case KEY_DOWN:
252 if (history_search_text) {
253 parse_line(&text, &restricted);
254 text = history_search_backward(&search_history, history_search_text);
255 if (text) {
256 update_search_line(text, restricted);
257 } else {
258 update_search_line(history_search_text, restricted);
261 return;
262 default:
263 return;
265 reset_history_search();
268 void search_mode_init(void)
270 search_history_filename = xstrjoin(cmus_config_dir, "/search-history");
271 history_load(&search_history, search_history_filename, 100);
274 void search_mode_exit(void)
276 history_save(&search_history);
277 free(search_history_filename);