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