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