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