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