Import NetBSD's LibEdit version 2012-03-11 on vendor branch
[dragonfly.git] / contrib / libedit / src / emacs.c
1 /*      $NetBSD: emacs.c,v 1.25 2011/07/29 15:16:33 christos Exp $      */
2
3 /*-
4  * Copyright (c) 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)emacs.c     8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: emacs.c,v 1.25 2011/07/29 15:16:33 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43
44 /*
45  * emacs.c: Emacs functions
46  */
47 #include "el.h"
48
49 /* em_delete_or_list():
50  *      Delete character under cursor or list completions if at end of line
51  *      [^D]
52  */
53 protected el_action_t
54 /*ARGSUSED*/
55 em_delete_or_list(EditLine *el, Int c)
56 {
57
58         if (el->el_line.cursor == el->el_line.lastchar) {
59                                         /* if I'm at the end */
60                 if (el->el_line.cursor == el->el_line.buffer) {
61                                         /* and the beginning */
62                         terminal_writec(el, c); /* then do an EOF */
63                         return CC_EOF;
64                 } else {
65                         /*
66                          * Here we could list completions, but it is an
67                          * error right now
68                          */
69                         terminal_beep(el);
70                         return CC_ERROR;
71                 }
72         } else {
73                 if (el->el_state.doingarg)
74                         c_delafter(el, el->el_state.argument);
75                 else
76                         c_delafter1(el);
77                 if (el->el_line.cursor > el->el_line.lastchar)
78                         el->el_line.cursor = el->el_line.lastchar;
79                                 /* bounds check */
80                 return CC_REFRESH;
81         }
82 }
83
84
85 /* em_delete_next_word():
86  *      Cut from cursor to end of current word
87  *      [M-d]
88  */
89 protected el_action_t
90 /*ARGSUSED*/
91 em_delete_next_word(EditLine *el, Int c __attribute__((__unused__)))
92 {
93         Char *cp, *p, *kp;
94
95         if (el->el_line.cursor == el->el_line.lastchar)
96                 return CC_ERROR;
97
98         cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
99             el->el_state.argument, ce__isword);
100
101         for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
102                                 /* save the text */
103                 *kp++ = *p;
104         el->el_chared.c_kill.last = kp;
105
106         c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */
107         if (el->el_line.cursor > el->el_line.lastchar)
108                 el->el_line.cursor = el->el_line.lastchar;
109                                 /* bounds check */
110         return CC_REFRESH;
111 }
112
113
114 /* em_yank():
115  *      Paste cut buffer at cursor position
116  *      [^Y]
117  */
118 protected el_action_t
119 /*ARGSUSED*/
120 em_yank(EditLine *el, Int c __attribute__((__unused__)))
121 {
122         Char *kp, *cp;
123
124         if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
125                 return CC_NORM;
126
127         if (el->el_line.lastchar +
128             (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
129             el->el_line.limit)
130                 return CC_ERROR;
131
132         el->el_chared.c_kill.mark = el->el_line.cursor;
133         cp = el->el_line.cursor;
134
135         /* open the space, */
136         c_insert(el,
137             (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf));
138         /* copy the chars */
139         for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
140                 *cp++ = *kp;
141
142         /* if an arg, cursor at beginning else cursor at end */
143         if (el->el_state.argument == 1)
144                 el->el_line.cursor = cp;
145
146         return CC_REFRESH;
147 }
148
149
150 /* em_kill_line():
151  *      Cut the entire line and save in cut buffer
152  *      [^U]
153  */
154 protected el_action_t
155 /*ARGSUSED*/
156 em_kill_line(EditLine *el, Int c __attribute__((__unused__)))
157 {
158         Char *kp, *cp;
159
160         cp = el->el_line.buffer;
161         kp = el->el_chared.c_kill.buf;
162         while (cp < el->el_line.lastchar)
163                 *kp++ = *cp++;  /* copy it */
164         el->el_chared.c_kill.last = kp;
165                                 /* zap! -- delete all of it */
166         el->el_line.lastchar = el->el_line.buffer;
167         el->el_line.cursor = el->el_line.buffer;
168         return CC_REFRESH;
169 }
170
171
172 /* em_kill_region():
173  *      Cut area between mark and cursor and save in cut buffer
174  *      [^W]
175  */
176 protected el_action_t
177 /*ARGSUSED*/
178 em_kill_region(EditLine *el, Int c __attribute__((__unused__)))
179 {
180         Char *kp, *cp;
181
182         if (!el->el_chared.c_kill.mark)
183                 return CC_ERROR;
184
185         if (el->el_chared.c_kill.mark > el->el_line.cursor) {
186                 cp = el->el_line.cursor;
187                 kp = el->el_chared.c_kill.buf;
188                 while (cp < el->el_chared.c_kill.mark)
189                         *kp++ = *cp++;  /* copy it */
190                 el->el_chared.c_kill.last = kp;
191                 c_delafter(el, (int)(cp - el->el_line.cursor));
192         } else {                /* mark is before cursor */
193                 cp = el->el_chared.c_kill.mark;
194                 kp = el->el_chared.c_kill.buf;
195                 while (cp < el->el_line.cursor)
196                         *kp++ = *cp++;  /* copy it */
197                 el->el_chared.c_kill.last = kp;
198                 c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark));
199                 el->el_line.cursor = el->el_chared.c_kill.mark;
200         }
201         return CC_REFRESH;
202 }
203
204
205 /* em_copy_region():
206  *      Copy area between mark and cursor to cut buffer
207  *      [M-W]
208  */
209 protected el_action_t
210 /*ARGSUSED*/
211 em_copy_region(EditLine *el, Int c __attribute__((__unused__)))
212 {
213         Char *kp, *cp;
214
215         if (!el->el_chared.c_kill.mark)
216                 return CC_ERROR;
217
218         if (el->el_chared.c_kill.mark > el->el_line.cursor) {
219                 cp = el->el_line.cursor;
220                 kp = el->el_chared.c_kill.buf;
221                 while (cp < el->el_chared.c_kill.mark)
222                         *kp++ = *cp++;  /* copy it */
223                 el->el_chared.c_kill.last = kp;
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_transpose():
236  *      Exchange the two characters before the cursor
237  *      Gosling emacs transpose chars [^T]
238  */
239 protected el_action_t
240 em_gosmacs_transpose(EditLine *el, Int c)
241 {
242
243         if (el->el_line.cursor > &el->el_line.buffer[1]) {
244                 /* must have at least two chars entered */
245                 c = el->el_line.cursor[-2];
246                 el->el_line.cursor[-2] = el->el_line.cursor[-1];
247                 el->el_line.cursor[-1] = c;
248                 return CC_REFRESH;
249         } else
250                 return CC_ERROR;
251 }
252
253
254 /* em_next_word():
255  *      Move next to end of current word
256  *      [M-f]
257  */
258 protected el_action_t
259 /*ARGSUSED*/
260 em_next_word(EditLine *el, Int c __attribute__((__unused__)))
261 {
262         if (el->el_line.cursor == el->el_line.lastchar)
263                 return CC_ERROR;
264
265         el->el_line.cursor = c__next_word(el->el_line.cursor,
266             el->el_line.lastchar,
267             el->el_state.argument,
268             ce__isword);
269
270         if (el->el_map.type == MAP_VI)
271                 if (el->el_chared.c_vcmd.action != NOP) {
272                         cv_delfini(el);
273                         return CC_REFRESH;
274                 }
275         return CC_CURSOR;
276 }
277
278
279 /* em_upper_case():
280  *      Uppercase the characters from cursor to end of current word
281  *      [M-u]
282  */
283 protected el_action_t
284 /*ARGSUSED*/
285 em_upper_case(EditLine *el, Int c __attribute__((__unused__)))
286 {
287         Char *cp, *ep;
288
289         ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
290             el->el_state.argument, ce__isword);
291
292         for (cp = el->el_line.cursor; cp < ep; cp++)
293                 if (Islower(*cp))
294                         *cp = Toupper(*cp);
295
296         el->el_line.cursor = ep;
297         if (el->el_line.cursor > el->el_line.lastchar)
298                 el->el_line.cursor = el->el_line.lastchar;
299         return CC_REFRESH;
300 }
301
302
303 /* em_capitol_case():
304  *      Capitalize the characters from cursor to end of current word
305  *      [M-c]
306  */
307 protected el_action_t
308 /*ARGSUSED*/
309 em_capitol_case(EditLine *el, Int c __attribute__((__unused__)))
310 {
311         Char *cp, *ep;
312
313         ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
314             el->el_state.argument, ce__isword);
315
316         for (cp = el->el_line.cursor; cp < ep; cp++) {
317                 if (Isalpha(*cp)) {
318                         if (Islower(*cp))
319                                 *cp = Toupper(*cp);
320                         cp++;
321                         break;
322                 }
323         }
324         for (; cp < ep; cp++)
325                 if (Isupper(*cp))
326                         *cp = Tolower(*cp);
327
328         el->el_line.cursor = ep;
329         if (el->el_line.cursor > el->el_line.lastchar)
330                 el->el_line.cursor = el->el_line.lastchar;
331         return CC_REFRESH;
332 }
333
334
335 /* em_lower_case():
336  *      Lowercase the characters from cursor to end of current word
337  *      [M-l]
338  */
339 protected el_action_t
340 /*ARGSUSED*/
341 em_lower_case(EditLine *el, Int c __attribute__((__unused__)))
342 {
343         Char *cp, *ep;
344
345         ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
346             el->el_state.argument, ce__isword);
347
348         for (cp = el->el_line.cursor; cp < ep; cp++)
349                 if (Isupper(*cp))
350                         *cp = Tolower(*cp);
351
352         el->el_line.cursor = ep;
353         if (el->el_line.cursor > el->el_line.lastchar)
354                 el->el_line.cursor = el->el_line.lastchar;
355         return CC_REFRESH;
356 }
357
358
359 /* em_set_mark():
360  *      Set the mark at cursor
361  *      [^@]
362  */
363 protected el_action_t
364 /*ARGSUSED*/
365 em_set_mark(EditLine *el, Int c __attribute__((__unused__)))
366 {
367
368         el->el_chared.c_kill.mark = el->el_line.cursor;
369         return CC_NORM;
370 }
371
372
373 /* em_exchange_mark():
374  *      Exchange the cursor and mark
375  *      [^X^X]
376  */
377 protected el_action_t
378 /*ARGSUSED*/
379 em_exchange_mark(EditLine *el, Int c __attribute__((__unused__)))
380 {
381         Char *cp;
382
383         cp = el->el_line.cursor;
384         el->el_line.cursor = el->el_chared.c_kill.mark;
385         el->el_chared.c_kill.mark = cp;
386         return CC_CURSOR;
387 }
388
389
390 /* em_universal_argument():
391  *      Universal argument (argument times 4)
392  *      [^U]
393  */
394 protected el_action_t
395 /*ARGSUSED*/
396 em_universal_argument(EditLine *el, Int c __attribute__((__unused__)))
397 {                               /* multiply current argument by 4 */
398
399         if (el->el_state.argument > 1000000)
400                 return CC_ERROR;
401         el->el_state.doingarg = 1;
402         el->el_state.argument *= 4;
403         return CC_ARGHACK;
404 }
405
406
407 /* em_meta_next():
408  *      Add 8th bit to next character typed
409  *      [<ESC>]
410  */
411 protected el_action_t
412 /*ARGSUSED*/
413 em_meta_next(EditLine *el, Int c __attribute__((__unused__)))
414 {
415
416         el->el_state.metanext = 1;
417         return CC_ARGHACK;
418 }
419
420
421 /* em_toggle_overwrite():
422  *      Switch from insert to overwrite mode or vice versa
423  */
424 protected el_action_t
425 /*ARGSUSED*/
426 em_toggle_overwrite(EditLine *el, Int c __attribute__((__unused__)))
427 {
428
429         el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
430             MODE_REPLACE : MODE_INSERT;
431         return CC_NORM;
432 }
433
434
435 /* em_copy_prev_word():
436  *      Copy current word to cursor
437  */
438 protected el_action_t
439 /*ARGSUSED*/
440 em_copy_prev_word(EditLine *el, Int c __attribute__((__unused__)))
441 {
442         Char *cp, *oldc, *dp;
443
444         if (el->el_line.cursor == el->el_line.buffer)
445                 return CC_ERROR;
446
447         oldc = el->el_line.cursor;
448         /* does a bounds check */
449         cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
450             el->el_state.argument, ce__isword);
451
452         c_insert(el, (int)(oldc - cp));
453         for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
454                 *dp++ = *cp;
455
456         el->el_line.cursor = dp;/* put cursor at end */
457
458         return CC_REFRESH;
459 }
460
461
462 /* em_inc_search_next():
463  *      Emacs incremental next search
464  */
465 protected el_action_t
466 /*ARGSUSED*/
467 em_inc_search_next(EditLine *el, Int c __attribute__((__unused__)))
468 {
469
470         el->el_search.patlen = 0;
471         return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
472 }
473
474
475 /* em_inc_search_prev():
476  *      Emacs incremental reverse search
477  */
478 protected el_action_t
479 /*ARGSUSED*/
480 em_inc_search_prev(EditLine *el, Int c __attribute__((__unused__)))
481 {
482
483         el->el_search.patlen = 0;
484         return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
485 }
486
487
488 /* em_delete_prev_char():
489  *      Delete the character to the left of the cursor
490  *      [^?]
491  */
492 protected el_action_t
493 /*ARGSUSED*/
494 em_delete_prev_char(EditLine *el, Int c __attribute__((__unused__)))
495 {
496
497         if (el->el_line.cursor <= el->el_line.buffer)
498                 return CC_ERROR;
499
500         if (el->el_state.doingarg)
501                 c_delbefore(el, el->el_state.argument);
502         else
503                 c_delbefore1(el);
504         el->el_line.cursor -= el->el_state.argument;
505         if (el->el_line.cursor < el->el_line.buffer)
506                 el->el_line.cursor = el->el_line.buffer;
507         return CC_REFRESH;
508 }