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