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