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