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