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