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