xref: /NextBSD/lib/libedit/emacs.c (revision 287e3b14e9552995def1802ec9c5034f4adf28ec)
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*/
em_delete_or_list(EditLine * el,Int c)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*/
em_delete_next_word(EditLine * el,Int c)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*/
em_yank(EditLine * el,Int c)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*/
em_kill_line(EditLine * el,Int c)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*/
em_kill_region(EditLine * el,Int c)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*/
em_copy_region(EditLine * el,Int c)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
em_gosmacs_transpose(EditLine * el,Int c)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*/
em_next_word(EditLine * el,Int c)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*/
em_upper_case(EditLine * el,Int c)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*/
em_capitol_case(EditLine * el,Int c)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*/
em_lower_case(EditLine * el,Int c)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*/
em_set_mark(EditLine * el,Int c)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*/
em_exchange_mark(EditLine * el,Int c)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*/
em_universal_argument(EditLine * el,Int c)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*/
em_meta_next(EditLine * el,Int c)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*/
em_toggle_overwrite(EditLine * el,Int c)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*/
em_copy_prev_word(EditLine * el,Int c)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*/
em_inc_search_next(EditLine * el,Int c)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*/
em_inc_search_prev(EditLine * el,Int c)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*/
em_delete_prev_char(EditLine * el,Int c)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 }
511