Initial import from FreeBSD RELENG_4:
[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
37 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid[] = "@(#)emacs.c     8.1 (Berkeley) 6/4/93";
39 #endif /* not lint && not SCCSID */
40
41 /*
42  * emacs.c: Emacs functions
43  */
44 #include "sys.h"
45 #include "el.h"
46
47 /* em_delete_or_list():
48  *      Delete character under cursor or list completions if at end of line
49  *      [^D]
50  */
51 protected el_action_t
52 /*ARGSUSED*/
53 em_delete_or_list(el, c)
54     EditLine *el;
55     int c;
56 {
57     if (el->el_line.cursor == el->el_line.lastchar) {   /* if I'm at the end */
58         if (el->el_line.cursor == el->el_line.buffer) { /* and the beginning */
59             term_overwrite(el, STReof, 4);/* then do a EOF */
60             term__flush();
61             return CC_EOF;
62         }
63         else {
64             /* Here we could list completions, but it is an error right now */
65             term_beep(el);
66             return CC_ERROR;
67         }
68     }
69     else {
70         c_delafter(el, el->el_state.argument);  /* delete after dot */
71         if (el->el_line.cursor > el->el_line.lastchar)
72             el->el_line.cursor = el->el_line.lastchar;  /* bounds check */
73         return CC_REFRESH;
74     }
75 }
76
77
78 /* em_delete_next_word():
79  *      Cut from cursor to end of current word
80  *      [M-d]
81  */
82 protected el_action_t
83 /*ARGSUSED*/
84 em_delete_next_word(el, c)
85     EditLine *el;
86     int c;
87 {
88     char *cp, *p, *kp;
89
90     if (el->el_line.cursor == el->el_line.lastchar)
91         return CC_ERROR;
92
93     cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
94                       el->el_state.argument, ce__isword);
95
96     for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
97         /* save the text */
98         *kp++ = *p;
99     el->el_chared.c_kill.last = kp;
100
101     c_delafter(el, cp - el->el_line.cursor);            /* delete after dot */
102     if (el->el_line.cursor > el->el_line.lastchar)
103         el->el_line.cursor = el->el_line.lastchar;      /* bounds check */
104     return CC_REFRESH;
105 }
106
107
108 /* em_yank():
109  *      Paste cut buffer at cursor position
110  *      [^Y]
111  */
112 protected el_action_t
113 /*ARGSUSED*/
114 em_yank(el, c)
115     EditLine *el;
116     int c;
117 {
118     char *kp, *cp;
119
120     if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
121         return CC_ERROR;
122
123     if (el->el_line.lastchar +
124         (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
125         el->el_line.limit)
126         return CC_ERROR;
127
128     el->el_chared.c_kill.mark = el->el_line.cursor;
129     cp = el->el_line.cursor;
130
131     /* open the space, */
132     c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);
133     /* copy the chars */
134     for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
135         *cp++ = *kp;
136
137     /* if an arg, cursor at beginning else cursor at end */
138     if (el->el_state.argument == 1)
139         el->el_line.cursor = cp;
140
141     return CC_REFRESH;
142 }
143
144
145 /* em_kill_line():
146  *      Cut the entire line and save in cut buffer
147  *      [^U]
148  */
149 protected el_action_t
150 /*ARGSUSED*/
151 em_kill_line(el, c)
152     EditLine *el;
153     int c;
154 {
155     char *kp, *cp;
156
157     cp = el->el_line.buffer;
158     kp = el->el_chared.c_kill.buf;
159     while (cp < el->el_line.lastchar)
160         *kp++ = *cp++;          /* copy it */
161     el->el_chared.c_kill.last = kp;
162     el->el_line.lastchar = el->el_line.buffer;  /* zap! -- delete all of it */
163     el->el_line.cursor = el->el_line.buffer;
164     return CC_REFRESH;
165 }
166
167
168 /* em_kill_region():
169  *      Cut area between mark and cursor and save in cut buffer
170  *      [^W]
171  */
172 protected el_action_t
173 /*ARGSUSED*/
174 em_kill_region(el, c)
175     EditLine *el;
176     int c;
177 {
178     char *kp, *cp;
179
180     if (!el->el_chared.c_kill.mark)
181         return CC_ERROR;
182
183     if (el->el_chared.c_kill.mark > el->el_line.cursor) {
184         cp = el->el_line.cursor;
185         kp = el->el_chared.c_kill.buf;
186         while (cp < el->el_chared.c_kill.mark)
187             *kp++ = *cp++;      /* copy it */
188         el->el_chared.c_kill.last = kp;
189         c_delafter(el, cp - el->el_line.cursor);
190     }
191     else {                      /* mark is before cursor */
192         cp = el->el_chared.c_kill.mark;
193         kp = el->el_chared.c_kill.buf;
194         while (cp < el->el_line.cursor)
195             *kp++ = *cp++;      /* copy it */
196         el->el_chared.c_kill.last = kp;
197         c_delbefore(el, cp - el->el_chared.c_kill.mark);
198         el->el_line.cursor = el->el_chared.c_kill.mark;
199     }
200     return CC_REFRESH;
201 }
202
203
204 /* em_copy_region():
205  *      Copy area between mark and cursor to cut buffer
206  *      [M-W]
207  */
208 protected el_action_t
209 /*ARGSUSED*/
210 em_copy_region(el, c)
211     EditLine *el;
212     int c;
213 {
214     char *kp, *cp;
215
216     if (el->el_chared.c_kill.mark)
217         return CC_ERROR;
218
219     if (el->el_chared.c_kill.mark > el->el_line.cursor) {
220         cp = el->el_line.cursor;
221         kp = el->el_chared.c_kill.buf;
222         while (cp < el->el_chared.c_kill.mark)
223             *kp++ = *cp++;      /* copy it */
224         el->el_chared.c_kill.last = kp;
225     }
226     else {
227         cp = el->el_chared.c_kill.mark;
228         kp = el->el_chared.c_kill.buf;
229         while (cp < el->el_line.cursor)
230             *kp++ = *cp++;      /* copy it */
231         el->el_chared.c_kill.last = kp;
232     }
233     return CC_NORM;
234 }
235
236
237 /* em_gosmacs_traspose():
238  *      Exchange the two characters before the cursor
239  *      Gosling emacs transpose chars [^T]
240  */
241 protected el_action_t
242 em_gosmacs_traspose(el, c)
243     EditLine *el;
244     int c;
245 {
246
247     if (el->el_line.cursor > &el->el_line.buffer[1]) {
248         /* must have at least two chars entered */
249         c = el->el_line.cursor[-2];
250         el->el_line.cursor[-2] = el->el_line.cursor[-1];
251         el->el_line.cursor[-1] = c;
252         return CC_REFRESH;
253     }
254     else
255         return CC_ERROR;
256 }
257
258
259 /* em_next_word():
260  *      Move next to end of current word
261  *      [M-f]
262  */
263 protected el_action_t
264 /*ARGSUSED*/
265 em_next_word(el, c)
266     EditLine *el;
267     int c;
268 {
269     if (el->el_line.cursor == el->el_line.lastchar)
270         return CC_ERROR;
271
272     el->el_line.cursor = c__next_word(el->el_line.cursor, el->el_line.lastchar,
273                                       el->el_state.argument,
274                                       ce__isword);
275
276     if (el->el_map.type == MAP_VI)
277         if (el->el_chared.c_vcmd.action & DELETE) {
278             cv_delfini(el);
279             return CC_REFRESH;
280         }
281
282     return CC_CURSOR;
283 }
284
285 /* em_upper_case():
286  *      Uppercase the characters from cursor to end of current word
287  *      [M-u]
288  */
289 protected el_action_t
290 /*ARGSUSED*/
291 em_upper_case(el, c)
292     EditLine *el;
293     int c;
294 {
295     char   *cp, *ep;
296
297     ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
298                       el->el_state.argument, ce__isword);
299
300     for (cp = el->el_line.cursor; cp < ep; cp++)
301         if (islower((unsigned char)*cp))
302             *cp = toupper((unsigned char)*cp);
303
304     el->el_line.cursor = ep;
305     if (el->el_line.cursor > el->el_line.lastchar)
306         el->el_line.cursor = el->el_line.lastchar;
307     return CC_REFRESH;
308 }
309
310
311 /* em_capitol_case():
312  *      Capitalize the characters from cursor to end of current word
313  *      [M-c]
314  */
315 protected el_action_t
316 /*ARGSUSED*/
317 em_capitol_case(el, c)
318     EditLine *el;
319     int c;
320 {
321     char   *cp, *ep;
322
323     ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
324                       el->el_state.argument, ce__isword);
325
326     for (cp = el->el_line.cursor; cp < ep; cp++) {
327         if (isalpha((unsigned char)*cp)) {
328             if (islower((unsigned char)*cp))
329                 *cp = toupper((unsigned char)*cp);
330             cp++;
331             break;
332         }
333     }
334     for (; cp < ep; cp++)
335         if (isupper((unsigned char)*cp))
336             *cp = tolower((unsigned char)*cp);
337
338     el->el_line.cursor = ep;
339     if (el->el_line.cursor > el->el_line.lastchar)
340         el->el_line.cursor = el->el_line.lastchar;
341     return CC_REFRESH;
342 }
343
344 /* em_lower_case():
345  *      Lowercase the characters from cursor to end of current word
346  *      [M-l]
347  */
348 protected el_action_t
349 /*ARGSUSED*/
350 em_lower_case(el, c)
351     EditLine *el;
352     int c;
353 {
354     char   *cp, *ep;
355
356     ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
357                       el->el_state.argument, ce__isword);
358
359     for (cp = el->el_line.cursor; cp < ep; cp++)
360         if (isupper((unsigned char)*cp))
361             *cp = tolower((unsigned char)*cp);
362
363     el->el_line.cursor = ep;
364     if (el->el_line.cursor > el->el_line.lastchar)
365         el->el_line.cursor = el->el_line.lastchar;
366     return CC_REFRESH;
367 }
368
369
370 /* em_set_mark():
371  *      Set the mark at cursor
372  *      [^@]
373  */
374 protected el_action_t
375 /*ARGSUSED*/
376 em_set_mark(el, c)
377     EditLine *el;
378     int c;
379 {
380     el->el_chared.c_kill.mark = el->el_line.cursor;
381     return CC_NORM;
382 }
383
384
385 /* em_exchange_mark():
386  *      Exchange the cursor and mark
387  *      [^X^X]
388  */
389 protected el_action_t
390 /*ARGSUSED*/
391 em_exchange_mark(el, c)
392     EditLine *el;
393     int c;
394 {
395     register char *cp;
396
397     cp = el->el_line.cursor;
398     el->el_line.cursor = el->el_chared.c_kill.mark;
399     el->el_chared.c_kill.mark = cp;
400     return CC_CURSOR;
401 }
402
403 /* em_universal_argument():
404  *      Universal argument (argument times 4)
405  *      [^U]
406  */
407 protected el_action_t
408 /*ARGSUSED*/
409 em_universal_argument(el, c)
410     EditLine *el;
411     int c;
412 {                               /* multiply current argument by 4 */
413     if (el->el_state.argument > 1000000)
414         return CC_ERROR;
415     el->el_state.doingarg = 1;
416     el->el_state.argument *= 4;
417     return CC_ARGHACK;
418 }
419
420 /* em_meta_next():
421  *      Add 8th bit to next character typed
422  *      [<ESC>]
423  */
424 protected el_action_t
425 /*ARGSUSED*/
426 em_meta_next(el, c)
427     EditLine *el;
428     int c;
429 {
430     el->el_state.metanext = 1;
431     return CC_ARGHACK;
432 }
433
434
435 /* em_toggle_overwrite():
436  *      Switch from insert to overwrite mode or vice versa
437  */
438 protected el_action_t
439 /*ARGSUSED*/
440 em_toggle_overwrite(el, c)
441     EditLine *el;
442     int c;
443 {
444     el->el_state.inputmode =
445         (el->el_state.inputmode == MODE_INSERT) ? MODE_REPLACE : MODE_INSERT;
446     return CC_NORM;
447 }
448
449
450 /* em_copy_prev_word():
451  *      Copy current word to cursor
452  */
453 protected el_action_t
454 /*ARGSUSED*/
455 em_copy_prev_word(el, c)
456     EditLine *el;
457     int c;
458 {
459     char *cp, *oldc, *dp;
460
461     if (el->el_line.cursor == el->el_line.buffer)
462         return CC_ERROR;
463
464     oldc = el->el_line.cursor;
465     /* does a bounds check */
466     cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
467                       el->el_state.argument, ce__isword);
468
469     c_insert(el, oldc - cp);
470     for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
471         *dp++ = *cp;
472
473     el->el_line.cursor = dp;            /* put cursor at end */
474
475     return CC_REFRESH;
476 }
477
478
479 /* em_inc_search_next():
480  *      Emacs incremental next search
481  */
482 protected el_action_t
483 /*ARGSUSED*/
484 em_inc_search_next(el, c)
485     EditLine *el;
486     int c;
487 {
488     el->el_search.patlen = 0;
489     return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
490 }
491
492
493 /* em_inc_search_prev():
494  *      Emacs incremental reverse search
495  */
496 protected el_action_t
497 /*ARGSUSED*/
498 em_inc_search_prev(el, c)
499     EditLine *el;
500     int c;
501 {
502     el->el_search.patlen = 0;
503     return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
504 }