1 /*
2 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "enter.h"
20
21 #include <termios.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <ctype.h>
29
30 #ifndef URLVIEW
31
32 /* global vars used for the string-history routines */
33 static char **Hist = NULL;
34 static short HistCur = 0;
35 static short HistLast = 0;
36
mutt_init_history(void)37 void mutt_init_history (void)
38 {
39 int i;
40 static int OldSize = 0;
41
42 if (Hist)
43 {
44 for (i = 0 ; i < OldSize ; i ++)
45 safe_free ((void **) &Hist[i]);
46 safe_free ((void **) &Hist);
47 }
48
49 if (HistSize)
50 Hist = safe_calloc (HistSize, sizeof (char *));
51 HistCur = 0;
52 HistLast = 0;
53 OldSize = HistSize;
54 }
55
sh_add(char * s)56 static void sh_add (char *s)
57 {
58 int prev;
59
60 if (!HistSize)
61 return; /* disabled */
62
63 if (*s)
64 {
65 prev = HistLast - 1;
66 if (prev < 0) prev = HistSize - 1;
67 if (!Hist[prev] || strcmp (Hist[prev], s) != 0)
68 {
69 safe_free ((void **) &Hist[HistLast]);
70 Hist[HistLast++] = safe_strdup (s);
71 if (HistLast > HistSize - 1)
72 HistLast = 0;
73 }
74 }
75 HistCur = HistLast; /* reset to the last entry */
76 }
77
sh_next(void)78 static char *sh_next (void)
79 {
80 int next;
81
82 if (!HistSize)
83 return (""); /* disabled */
84
85 next = HistCur + 1;
86 if (next > HistLast - 1)
87 next = 0;
88 if (Hist[next])
89 HistCur = next;
90 return (Hist[HistCur] ? Hist[HistCur] : "");
91 }
92
sh_prev(void)93 static char *sh_prev (void)
94 {
95 int prev;
96
97 if (!HistSize)
98 return (""); /* disabled */
99
100 prev = HistCur - 1;
101 if (prev < 0)
102 {
103 prev = HistLast - 1;
104 if (prev < 0)
105 {
106 prev = HistSize - 1;
107 while (prev > 0 && Hist[prev] == NULL)
108 prev--;
109 }
110 }
111 if (Hist[prev])
112 HistCur = prev;
113 return (Hist[HistCur] ? Hist[HistCur] : "");
114 }
115 #endif /* ! URLVIEW */
116
117 /* redraw flags for mutt_enter_string() */
118 enum
119 {
120 M_REDRAW_INIT = 1, /* recalculate lengths */
121 M_REDRAW_LINE, /* redraw entire line */
122 M_REDRAW_EOL, /* redraw from current position to eol */
123 M_REDRAW_PREV_EOL /* redraw from curpos-1 to eol */
124 };
125
126 /* Returns:
127 * 1 need to redraw the screen and call me again
128 * 0 if input was given
129 * -1 if abort.
130 *
131 */
mutt_enter_string(unsigned char * buf,size_t buflen,int y,int x,int flags)132 int mutt_enter_string (unsigned char *buf, size_t buflen, int y, int x,
133 int flags)
134 {
135 int curpos = 0; /* the location of the cursor */
136 int lastchar = 0; /* offset of the last char in the string */
137 int begin = 0; /* first character displayed on the line */
138 int ch; /* last typed character */
139 int width = COLS - x - 1; /* width of field */
140 int redraw = M_REDRAW_INIT; /* when/what to redraw */
141 int pass = (flags == M_PASS);
142 int j;
143
144 FOREVER
145 {
146 if (redraw)
147 {
148 if (redraw == M_REDRAW_INIT)
149 {
150 /* full redraw */
151 lastchar = curpos = strlen ((char *) buf);
152 begin = lastchar - width;
153 }
154 if (begin < 0)
155 begin = 0;
156 switch (redraw)
157 {
158 case M_REDRAW_PREV_EOL:
159 j = curpos - 1;
160 break;
161 case M_REDRAW_EOL:
162 j = curpos;
163 break;
164 default:
165 j = begin;
166 }
167 move (y, x + j - begin);
168 for (; j < lastchar && j < begin + width; j++)
169 addch (buf[j]);
170 clrtoeol ();
171 if (redraw != M_REDRAW_INIT)
172 move (y, x + curpos - begin);
173 redraw = 0;
174 }
175 refresh ();
176
177 /* first look to see if a keypress is an editor operation. km_dokey()
178 * returns 0 if there is no entry in the keymap, so restore the last
179 * keypress and continue normally.
180 */
181 if ((ch = km_dokey (MENU_EDITOR)) == -1)
182 {
183 buf[curpos] = 0;
184 return (-1);
185 }
186
187 if (ch != 0)
188 {
189 switch (ch)
190 {
191 case OP_EDITOR_BACKSPACE:
192 if (curpos == 0)
193 {
194 BEEP ();
195 break;
196 }
197 for (j = curpos ; j < lastchar ; j++)
198 buf[j - 1] = buf[j];
199 curpos--;
200 lastchar--;
201 if (!pass)
202 {
203 if (curpos > begin)
204 {
205 if (lastchar == curpos)
206 {
207 move (y, x + curpos - begin);
208 delch ();
209 }
210 else
211 redraw = M_REDRAW_EOL;
212 }
213 else
214 {
215 begin -= width / 2;
216 redraw = M_REDRAW_LINE;
217 }
218 }
219 break;
220 case OP_EDITOR_BOL:
221 /* reposition the cursor at the begininning of the line */
222 curpos = 0;
223 if (!pass)
224 {
225 if (begin)
226 {
227 /* the first char is not displayed, so readjust */
228 begin = 0;
229 redraw = M_REDRAW_LINE;
230 }
231 else
232 move (y, x);
233 }
234 break;
235 case OP_EDITOR_EOL:
236 curpos = lastchar;
237 if (!pass)
238 {
239 if (lastchar < begin + width)
240 move (y, x + lastchar - begin);
241 else
242 {
243 begin = lastchar - width / 2;
244 redraw = M_REDRAW_LINE;
245 }
246 }
247 break;
248 case OP_EDITOR_KILL_LINE:
249 lastchar = curpos = 0;
250 if (!pass)
251 {
252 begin = 0;
253 redraw = M_REDRAW_LINE;
254 }
255 break;
256 case OP_EDITOR_KILL_EOL:
257 lastchar = curpos;
258 if (!pass)
259 clrtoeol ();
260 break;
261 case OP_EDITOR_BACKWARD_CHAR:
262 if (curpos == 0)
263 {
264 BEEP ();
265 }
266 else
267 {
268 curpos--;
269 if (!pass)
270 {
271 if (curpos < begin)
272 {
273 begin -= width / 2;
274 redraw = M_REDRAW_LINE;
275 }
276 else
277 move (y, x + curpos - begin);
278 }
279 }
280 break;
281 case OP_EDITOR_FORWARD_CHAR:
282 if (curpos == lastchar)
283 {
284 BEEP ();
285 }
286 else
287 {
288 curpos++;
289 if (!pass)
290 {
291 if (curpos >= begin + width)
292 {
293 begin = curpos - width / 2;
294 redraw = M_REDRAW_LINE;
295 }
296 else
297 move (y, x + curpos - begin);
298 }
299 }
300 break;
301 case OP_EDITOR_DELETE_CHAR:
302 if (curpos != lastchar)
303 {
304 for (j = curpos; j < lastchar; j++)
305 buf[j] = buf[j + 1];
306 lastchar--;
307 if (!pass)
308 redraw = M_REDRAW_EOL;
309 }
310 else
311 BEEP ();
312 break;
313 case OP_EDITOR_KILL_WORD:
314 /* delete to begining of word */
315 if (curpos != 0)
316 {
317 j = curpos;
318 while (j > 0 && ISSPACE (buf[j - 1]))
319 j--;
320 if (j > 0)
321 {
322 if (isalnum (buf[j - 1]))
323 {
324 for (j--; j > 0 && isalnum (buf[j - 1]); j--)
325 ;
326 }
327 else
328 j--;
329 }
330 ch = j; /* save current position */
331 while (curpos < lastchar)
332 buf[j++] = buf[curpos++];
333 lastchar = j;
334 curpos = ch; /* restore current position */
335 /* update screen */
336 if (!pass)
337 {
338 if (curpos < begin)
339 {
340 begin = curpos - width / 2;
341 redraw = M_REDRAW_LINE;
342 }
343 else
344 redraw = M_REDRAW_EOL;
345 }
346 }
347 break;
348 default:
349 BEEP ();
350 }
351 }
352 else
353 {
354 /* use the raw keypress */
355 ch = LastKey;
356
357 if (CI_is_return (ch))
358 {
359 buf[lastchar] = 0;
360 return (0);
361 }
362 else if (IsPrint (ch) && ((size_t)(lastchar + 1) < buflen))
363 {
364 for (j = lastchar; j > curpos; j--)
365 buf[j] = buf[j - 1];
366 buf[curpos++] = ch;
367 lastchar++;
368
369 if (!pass)
370 {
371 if (curpos >= begin + width)
372 {
373 begin = curpos - width / 2;
374 redraw = M_REDRAW_LINE;
375 }
376 else if (curpos == lastchar)
377 addch (ch);
378 else
379 redraw = M_REDRAW_PREV_EOL;
380 }
381 }
382 else
383 {
384 mutt_flushinp ();
385 BEEP ();
386 }
387 }
388 }
389 /* not reached */
390 }
391