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