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