Version 0.3.0 from FTP
[asterisk/asterisk.git] / editline / emacs.c
1 /*      $NetBSD: emacs.c,v 1.10 2002/03/18 16:00:52 christos Exp $      */
2
3 /*-
4  * Copyright (c) 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #include "config.h"
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)emacs.c     8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: emacs.c,v 1.10 2002/03/18 16:00:52 christos Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49  * emacs.c: Emacs functions
50  */
51 #include "el.h"
52
53 /* em_delete_or_list():
54  *      Delete character under cursor or list completions if at end of line
55  *      [^D]
56  */
57 protected el_action_t
58 /*ARGSUSED*/
59 em_delete_or_list(EditLine *el, int c)
60 {
61
62         if (el->el_line.cursor == el->el_line.lastchar) {
63                                         /* if I'm at the end */
64                 if (el->el_line.cursor == el->el_line.buffer) {
65                                         /* and the beginning */
66                         term_overwrite(el, STReof, 4);  /* then do a EOF */
67                         term__flush();
68                         return (CC_EOF);
69                 } else {
70                         /*
71                          * Here we could list completions, but it is an
72                          * error right now
73                          */
74                         term_beep(el);
75                         return (CC_ERROR);
76                 }
77         } else {
78                 c_delafter(el, el->el_state.argument);  /* delete after dot */
79                 if (el->el_line.cursor > el->el_line.lastchar)
80                         el->el_line.cursor = el->el_line.lastchar;
81                                 /* bounds check */
82                 return (CC_REFRESH);
83         }
84 }
85
86
87 /* em_delete_next_word():
88  *      Cut from cursor to end of current word
89  *      [M-d]
90  */
91 protected el_action_t
92 /*ARGSUSED*/
93 em_delete_next_word(EditLine *el, int c)
94 {
95         char *cp, *p, *kp;
96
97         if (el->el_line.cursor == el->el_line.lastchar)
98                 return (CC_ERROR);
99
100         cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
101             el->el_state.argument, ce__isword);
102
103         for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
104                                 /* save the text */
105                 *kp++ = *p;
106         el->el_chared.c_kill.last = kp;
107
108         c_delafter(el, cp - el->el_line.cursor);        /* delete after dot */
109         if (el->el_line.cursor > el->el_line.lastchar)
110                 el->el_line.cursor = el->el_line.lastchar;
111                                 /* bounds check */
112         return (CC_REFRESH);
113 }
114
115
116 /* em_yank():
117  *      Paste cut buffer at cursor position
118  *      [^Y]
119  */
120 protected el_action_t
121 /*ARGSUSED*/
122 em_yank(EditLine *el, int c)
123 {
124         char *kp, *cp;
125
126         if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) {
127                 if (!ch_enlargebufs(el, 1))
128                         return (CC_ERROR);
129         }
130
131         if (el->el_line.lastchar +
132             (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
133             el->el_line.limit)
134                 return (CC_ERROR);
135
136         el->el_chared.c_kill.mark = el->el_line.cursor;
137         cp = el->el_line.cursor;
138
139         /* open the space, */
140         c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);
141         /* copy the chars */
142         for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
143                 *cp++ = *kp;
144
145         /* if an arg, cursor at beginning else cursor at end */
146         if (el->el_state.argument == 1)
147                 el->el_line.cursor = cp;
148
149         return (CC_REFRESH);
150 }
151
152
153 /* em_kill_line():
154  *      Cut the entire line and save in cut buffer
155  *      [^U]
156  */
157 protected el_action_t
158 /*ARGSUSED*/
159 em_kill_line(EditLine *el, int c)
160 {
161         char *kp, *cp;
162
163         cp = el->el_line.buffer;
164         kp = el->el_chared.c_kill.buf;
165         while (cp < el->el_line.lastchar)
166                 *kp++ = *cp++;  /* copy it */
167         el->el_chared.c_kill.last = kp;
168                                 /* zap! -- delete all of it */
169         el->el_line.lastchar = el->el_line.buffer;
170         el->el_line.cursor = el->el_line.buffer;
171         return (CC_REFRESH);
172 }
173
174
175 /* em_kill_region():
176  *      Cut area between mark and cursor and save in cut buffer
177  *      [^W]
178  */
179 protected el_action_t
180 /*ARGSUSED*/
181 em_kill_region(EditLine *el, int c)
182 {
183         char *kp, *cp;
184
185         if (!el->el_chared.c_kill.mark)
186                 return (CC_ERROR);
187
188         if (el->el_chared.c_kill.mark > el->el_line.cursor) {
189                 cp = el->el_line.cursor;
190                 kp = el->el_chared.c_kill.buf;
191                 while (cp < el->el_chared.c_kill.mark)
192                         *kp++ = *cp++;  /* copy it */
193                 el->el_chared.c_kill.last = kp;
194                 c_delafter(el, cp - el->el_line.cursor);
195         } else {                /* mark is before cursor */
196                 cp = el->el_chared.c_kill.mark;
197                 kp = el->el_chared.c_kill.buf;
198                 while (cp < el->el_line.cursor)
199                         *kp++ = *cp++;  /* copy it */
200                 el->el_chared.c_kill.last = kp;
201                 c_delbefore(el, cp - el->el_chared.c_kill.mark);
202                 el->el_line.cursor = el->el_chared.c_kill.mark;
203         }
204         return (CC_REFRESH);
205 }
206
207
208 /* em_copy_region():
209  *      Copy area between mark and cursor to cut buffer
210  *      [M-W]
211  */
212 protected el_action_t
213 /*ARGSUSED*/
214 em_copy_region(EditLine *el, int c)
215 {
216         char *kp, *cp;
217
218         if (el->el_chared.c_kill.mark)
219                 return (CC_ERROR);
220
221         if (el->el_chared.c_kill.mark > el->el_line.cursor) {
222                 cp = el->el_line.cursor;
223                 kp = el->el_chared.c_kill.buf;
224                 while (cp < el->el_chared.c_kill.mark)
225                         *kp++ = *cp++;  /* copy it */
226                 el->el_chared.c_kill.last = kp;
227         } else {
228                 cp = el->el_chared.c_kill.mark;
229                 kp = el->el_chared.c_kill.buf;
230                 while (cp < el->el_line.cursor)
231                         *kp++ = *cp++;  /* copy it */
232                 el->el_chared.c_kill.last = kp;
233         }
234         return (CC_NORM);
235 }
236
237
238 /* em_gosmacs_traspose():
239  *      Exchange the two characters before the cursor
240  *      Gosling emacs transpose chars [^T]
241  */
242 protected el_action_t
243 em_gosmacs_traspose(EditLine *el, int c)
244 {
245
246         if (el->el_line.cursor > &el->el_line.buffer[1]) {
247                 /* must have at least two chars entered */
248                 c = el->el_line.cursor[-2];
249                 el->el_line.cursor[-2] = el->el_line.cursor[-1];
250                 el->el_line.cursor[-1] = c;
251                 return (CC_REFRESH);
252         } else
253                 return (CC_ERROR);
254 }
255
256
257 /* em_next_word():
258  *      Move next to end of current word
259  *      [M-f]
260  */
261 protected el_action_t
262 /*ARGSUSED*/
263 em_next_word(EditLine *el, int c)
264 {
265         if (el->el_line.cursor == el->el_line.lastchar)
266                 return (CC_ERROR);
267
268         el->el_line.cursor = c__next_word(el->el_line.cursor,
269             el->el_line.lastchar,
270             el->el_state.argument,
271             ce__isword);
272
273         if (el->el_map.type == MAP_VI)
274                 if (el->el_chared.c_vcmd.action & DELETE) {
275                         cv_delfini(el);
276                         return (CC_REFRESH);
277                 }
278         return (CC_CURSOR);
279 }
280
281
282 /* em_upper_case():
283  *      Uppercase the characters from cursor to end of current word
284  *      [M-u]
285  */
286 protected el_action_t
287 /*ARGSUSED*/
288 em_upper_case(EditLine *el, int c)
289 {
290         char *cp, *ep;
291
292         ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
293             el->el_state.argument, ce__isword);
294
295         for (cp = el->el_line.cursor; cp < ep; cp++)
296                 if (islower((unsigned char) *cp))
297                         *cp = toupper(*cp);
298
299         el->el_line.cursor = ep;
300         if (el->el_line.cursor > el->el_line.lastchar)
301                 el->el_line.cursor = el->el_line.lastchar;
302         return (CC_REFRESH);
303 }
304
305
306 /* em_capitol_case():
307  *      Capitalize the characters from cursor to end of current word
308  *      [M-c]
309  */
310 protected el_action_t
311 /*ARGSUSED*/
312 em_capitol_case(EditLine *el, int c)
313 {
314         char *cp, *ep;
315
316         ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
317             el->el_state.argument, ce__isword);
318
319         for (cp = el->el_line.cursor; cp < ep; cp++) {
320                 if (isalpha((unsigned char) *cp)) {
321                         if (islower((unsigned char) *cp))
322                                 *cp = toupper(*cp);
323                         cp++;
324                         break;
325                 }
326         }
327         for (; cp < ep; cp++)
328                 if (isupper((unsigned char) *cp))
329                         *cp = tolower(*cp);
330
331         el->el_line.cursor = ep;
332         if (el->el_line.cursor > el->el_line.lastchar)
333                 el->el_line.cursor = el->el_line.lastchar;
334         return (CC_REFRESH);
335 }
336
337
338 /* em_lower_case():
339  *      Lowercase the characters from cursor to end of current word
340  *      [M-l]
341  */
342 protected el_action_t
343 /*ARGSUSED*/
344 em_lower_case(EditLine *el, int c)
345 {
346         char *cp, *ep;
347
348         ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
349             el->el_state.argument, ce__isword);
350
351         for (cp = el->el_line.cursor; cp < ep; cp++)
352                 if (isupper((unsigned char) *cp))
353                         *cp = tolower(*cp);
354
355         el->el_line.cursor = ep;
356         if (el->el_line.cursor > el->el_line.lastchar)
357                 el->el_line.cursor = el->el_line.lastchar;
358         return (CC_REFRESH);
359 }
360
361
362 /* em_set_mark():
363  *      Set the mark at cursor
364  *      [^@]
365  */
366 protected el_action_t
367 /*ARGSUSED*/
368 em_set_mark(EditLine *el, int c)
369 {
370
371         el->el_chared.c_kill.mark = el->el_line.cursor;
372         return (CC_NORM);
373 }
374
375
376 /* em_exchange_mark():
377  *      Exchange the cursor and mark
378  *      [^X^X]
379  */
380 protected el_action_t
381 /*ARGSUSED*/
382 em_exchange_mark(EditLine *el, int c)
383 {
384         char *cp;
385
386         cp = el->el_line.cursor;
387         el->el_line.cursor = el->el_chared.c_kill.mark;
388         el->el_chared.c_kill.mark = cp;
389         return (CC_CURSOR);
390 }
391
392
393 /* em_universal_argument():
394  *      Universal argument (argument times 4)
395  *      [^U]
396  */
397 protected el_action_t
398 /*ARGSUSED*/
399 em_universal_argument(EditLine *el, int c)
400 {                               /* multiply current argument by 4 */
401
402         if (el->el_state.argument > 1000000)
403                 return (CC_ERROR);
404         el->el_state.doingarg = 1;
405         el->el_state.argument *= 4;
406         return (CC_ARGHACK);
407 }
408
409
410 /* em_meta_next():
411  *      Add 8th bit to next character typed
412  *      [<ESC>]
413  */
414 protected el_action_t
415 /*ARGSUSED*/
416 em_meta_next(EditLine *el, int c)
417 {
418
419         el->el_state.metanext = 1;
420         return (CC_ARGHACK);
421 }
422
423
424 /* em_toggle_overwrite():
425  *      Switch from insert to overwrite mode or vice versa
426  */
427 protected el_action_t
428 /*ARGSUSED*/
429 em_toggle_overwrite(EditLine *el, int c)
430 {
431
432         el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
433             MODE_REPLACE : MODE_INSERT;
434         return (CC_NORM);
435 }
436
437
438 /* em_copy_prev_word():
439  *      Copy current word to cursor
440  */
441 protected el_action_t
442 /*ARGSUSED*/
443 em_copy_prev_word(EditLine *el, int c)
444 {
445         char *cp, *oldc, *dp;
446
447         if (el->el_line.cursor == el->el_line.buffer)
448                 return (CC_ERROR);
449
450         oldc = el->el_line.cursor;
451         /* does a bounds check */
452         cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
453             el->el_state.argument, ce__isword);
454
455         c_insert(el, oldc - cp);
456         for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
457                 *dp++ = *cp;
458
459         el->el_line.cursor = dp;/* put cursor at end */
460
461         return (CC_REFRESH);
462 }
463
464
465 /* em_inc_search_next():
466  *      Emacs incremental next search
467  */
468 protected el_action_t
469 /*ARGSUSED*/
470 em_inc_search_next(EditLine *el, int c)
471 {
472
473         el->el_search.patlen = 0;
474         return (ce_inc_search(el, ED_SEARCH_NEXT_HISTORY));
475 }
476
477
478 /* em_inc_search_prev():
479  *      Emacs incremental reverse search
480  */
481 protected el_action_t
482 /*ARGSUSED*/
483 em_inc_search_prev(EditLine *el, int c)
484 {
485
486         el->el_search.patlen = 0;
487         return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY));
488 }