xref: /netbsd-src/lib/libedit/emacs.c (revision 5aefcfdc06931dd97e76246d2fe0302f7b3fe094)
1 /*	$NetBSD: emacs.c,v 1.8 2000/09/04 22:06:29 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 #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.8 2000/09/04 22:06:29 lukem 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(EditLine *el, int c)
61 {
62 
63 	if (el->el_line.cursor == el->el_line.lastchar) {
64 					/* if I'm at the end */
65 		if (el->el_line.cursor == el->el_line.buffer) {
66 					/* and the beginning */
67 			term_overwrite(el, STReof, 4);	/* then do a EOF */
68 			term__flush();
69 			return (CC_EOF);
70 		} else {
71 			/*
72 			 * Here we could list completions, but it is an
73 			 * error right now
74 			 */
75 			term_beep(el);
76 			return (CC_ERROR);
77 		}
78 	} else {
79 		c_delafter(el, el->el_state.argument);	/* delete after dot */
80 		if (el->el_line.cursor > el->el_line.lastchar)
81 			el->el_line.cursor = el->el_line.lastchar;
82 				/* bounds check */
83 		return (CC_REFRESH);
84 	}
85 }
86 
87 
88 /* em_delete_next_word():
89  *	Cut from cursor to end of current word
90  *	[M-d]
91  */
92 protected el_action_t
93 /*ARGSUSED*/
94 em_delete_next_word(EditLine *el, int c)
95 {
96 	char *cp, *p, *kp;
97 
98 	if (el->el_line.cursor == el->el_line.lastchar)
99 		return (CC_ERROR);
100 
101 	cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
102 	    el->el_state.argument, ce__isword);
103 
104 	for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
105 				/* save the text */
106 		*kp++ = *p;
107 	el->el_chared.c_kill.last = kp;
108 
109 	c_delafter(el, cp - el->el_line.cursor);	/* delete after dot */
110 	if (el->el_line.cursor > el->el_line.lastchar)
111 		el->el_line.cursor = el->el_line.lastchar;
112 				/* bounds check */
113 	return (CC_REFRESH);
114 }
115 
116 
117 /* em_yank():
118  *	Paste cut buffer at cursor position
119  *	[^Y]
120  */
121 protected el_action_t
122 /*ARGSUSED*/
123 em_yank(EditLine *el, 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(EditLine *el, int c)
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*/
180 em_kill_region(EditLine *el, int c)
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, 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, 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(EditLine *el, int c)
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_traspose():
238  *	Exchange the two characters before the cursor
239  *	Gosling emacs transpose chars [^T]
240  */
241 protected el_action_t
242 em_gosmacs_traspose(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*/
262 em_next_word(EditLine *el, int c)
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 & DELETE) {
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*/
287 em_upper_case(EditLine *el, int c)
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((unsigned char) *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*/
311 em_capitol_case(EditLine *el, int c)
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((unsigned char) *cp)) {
320 			if (islower((unsigned char) *cp))
321 				*cp = toupper(*cp);
322 			cp++;
323 			break;
324 		}
325 	}
326 	for (; cp < ep; cp++)
327 		if (isupper((unsigned char) *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*/
343 em_lower_case(EditLine *el, int c)
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((unsigned char) *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*/
367 em_set_mark(EditLine *el, int c)
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*/
381 em_exchange_mark(EditLine *el, int c)
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*/
398 em_universal_argument(EditLine *el, int c)
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*/
415 em_meta_next(EditLine *el, int c)
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*/
428 em_toggle_overwrite(EditLine *el, int c)
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*/
442 em_copy_prev_word(EditLine *el, int c)
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, 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*/
469 em_inc_search_next(EditLine *el, int c)
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*/
482 em_inc_search_prev(EditLine *el, int c)
483 {
484 
485 	el->el_search.patlen = 0;
486 	return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY));
487 }
488