xref: /netbsd/lib/libedit/emacs.c (revision c4a72b64)
1 /*	$NetBSD: emacs.c,v 1.12 2002/11/15 14:32: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. 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 "config.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.12 2002/11/15 14:32:33 christos Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47 
48 /*
49  * emacs.c: Emacs functions
50  */
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(EditLine *el, int c)
60 {
61 
62 	if (el->el_line.cursor == el->el_line.lastchar) {
63 					/* if I'm at the end */
64 		if (el->el_line.cursor == el->el_line.buffer) {
65 					/* and the beginning */
66 			term_overwrite(el, STReof, 4);	/* then do a EOF */
67 			term__flush();
68 			return (CC_EOF);
69 		} else {
70 			/*
71 			 * Here we could list completions, but it is an
72 			 * error right now
73 			 */
74 			term_beep(el);
75 			return (CC_ERROR);
76 		}
77 	} else {
78 		c_delafter(el, el->el_state.argument);	/* delete after dot */
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*/
93 em_delete_next_word(EditLine *el, int c)
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, 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*/
122 em_yank(EditLine *el, int c)
123 {
124 	char *kp, *cp;
125 
126 	if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) {
127 		if (!ch_enlargebufs(el, 1))
128 			return (CC_ERROR);
129 	}
130 
131 	if (el->el_line.lastchar +
132 	    (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
133 	    el->el_line.limit)
134 		return (CC_ERROR);
135 
136 	el->el_chared.c_kill.mark = el->el_line.cursor;
137 	cp = el->el_line.cursor;
138 
139 	/* open the space, */
140 	c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);
141 	/* copy the chars */
142 	for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
143 		*cp++ = *kp;
144 
145 	/* if an arg, cursor at beginning else cursor at end */
146 	if (el->el_state.argument == 1)
147 		el->el_line.cursor = cp;
148 
149 	return (CC_REFRESH);
150 }
151 
152 
153 /* em_kill_line():
154  *	Cut the entire line and save in cut buffer
155  *	[^U]
156  */
157 protected el_action_t
158 /*ARGSUSED*/
159 em_kill_line(EditLine *el, 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 				/* zap! -- delete all of it */
169 	el->el_line.lastchar = el->el_line.buffer;
170 	el->el_line.cursor = el->el_line.buffer;
171 	return (CC_REFRESH);
172 }
173 
174 
175 /* em_kill_region():
176  *	Cut area between mark and cursor and save in cut buffer
177  *	[^W]
178  */
179 protected el_action_t
180 /*ARGSUSED*/
181 em_kill_region(EditLine *el, int c)
182 {
183 	char *kp, *cp;
184 
185 	if (!el->el_chared.c_kill.mark)
186 		return (CC_ERROR);
187 
188 	if (el->el_chared.c_kill.mark > el->el_line.cursor) {
189 		cp = el->el_line.cursor;
190 		kp = el->el_chared.c_kill.buf;
191 		while (cp < el->el_chared.c_kill.mark)
192 			*kp++ = *cp++;	/* copy it */
193 		el->el_chared.c_kill.last = kp;
194 		c_delafter(el, cp - el->el_line.cursor);
195 	} else {		/* mark is before cursor */
196 		cp = el->el_chared.c_kill.mark;
197 		kp = el->el_chared.c_kill.buf;
198 		while (cp < el->el_line.cursor)
199 			*kp++ = *cp++;	/* copy it */
200 		el->el_chared.c_kill.last = kp;
201 		c_delbefore(el, cp - el->el_chared.c_kill.mark);
202 		el->el_line.cursor = el->el_chared.c_kill.mark;
203 	}
204 	return (CC_REFRESH);
205 }
206 
207 
208 /* em_copy_region():
209  *	Copy area between mark and cursor to cut buffer
210  *	[M-W]
211  */
212 protected el_action_t
213 /*ARGSUSED*/
214 em_copy_region(EditLine *el, int c)
215 {
216 	char *kp, *cp;
217 
218 	if (!el->el_chared.c_kill.mark)
219 		return (CC_ERROR);
220 
221 	if (el->el_chared.c_kill.mark > el->el_line.cursor) {
222 		cp = el->el_line.cursor;
223 		kp = el->el_chared.c_kill.buf;
224 		while (cp < el->el_chared.c_kill.mark)
225 			*kp++ = *cp++;	/* copy it */
226 		el->el_chared.c_kill.last = kp;
227 	} else {
228 		cp = el->el_chared.c_kill.mark;
229 		kp = el->el_chared.c_kill.buf;
230 		while (cp < el->el_line.cursor)
231 			*kp++ = *cp++;	/* copy it */
232 		el->el_chared.c_kill.last = kp;
233 	}
234 	return (CC_NORM);
235 }
236 
237 
238 /* em_gosmacs_traspose():
239  *	Exchange the two characters before the cursor
240  *	Gosling emacs transpose chars [^T]
241  */
242 protected el_action_t
243 em_gosmacs_traspose(EditLine *el, int c)
244 {
245 
246 	if (el->el_line.cursor > &el->el_line.buffer[1]) {
247 		/* must have at least two chars entered */
248 		c = el->el_line.cursor[-2];
249 		el->el_line.cursor[-2] = el->el_line.cursor[-1];
250 		el->el_line.cursor[-1] = c;
251 		return (CC_REFRESH);
252 	} else
253 		return (CC_ERROR);
254 }
255 
256 
257 /* em_next_word():
258  *	Move next to end of current word
259  *	[M-f]
260  */
261 protected el_action_t
262 /*ARGSUSED*/
263 em_next_word(EditLine *el, int c)
264 {
265 	if (el->el_line.cursor == el->el_line.lastchar)
266 		return (CC_ERROR);
267 
268 	el->el_line.cursor = c__next_word(el->el_line.cursor,
269 	    el->el_line.lastchar,
270 	    el->el_state.argument,
271 	    ce__isword);
272 
273 	if (el->el_map.type == MAP_VI)
274 		if (el->el_chared.c_vcmd.action != NOP) {
275 			cv_delfini(el);
276 			return (CC_REFRESH);
277 		}
278 	return (CC_CURSOR);
279 }
280 
281 
282 /* em_upper_case():
283  *	Uppercase the characters from cursor to end of current word
284  *	[M-u]
285  */
286 protected el_action_t
287 /*ARGSUSED*/
288 em_upper_case(EditLine *el, int c)
289 {
290 	char *cp, *ep;
291 
292 	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
293 	    el->el_state.argument, ce__isword);
294 
295 	for (cp = el->el_line.cursor; cp < ep; cp++)
296 		if (islower((unsigned char) *cp))
297 			*cp = toupper(*cp);
298 
299 	el->el_line.cursor = ep;
300 	if (el->el_line.cursor > el->el_line.lastchar)
301 		el->el_line.cursor = el->el_line.lastchar;
302 	return (CC_REFRESH);
303 }
304 
305 
306 /* em_capitol_case():
307  *	Capitalize the characters from cursor to end of current word
308  *	[M-c]
309  */
310 protected el_action_t
311 /*ARGSUSED*/
312 em_capitol_case(EditLine *el, int c)
313 {
314 	char *cp, *ep;
315 
316 	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
317 	    el->el_state.argument, ce__isword);
318 
319 	for (cp = el->el_line.cursor; cp < ep; cp++) {
320 		if (isalpha((unsigned char) *cp)) {
321 			if (islower((unsigned char) *cp))
322 				*cp = toupper(*cp);
323 			cp++;
324 			break;
325 		}
326 	}
327 	for (; cp < ep; cp++)
328 		if (isupper((unsigned char) *cp))
329 			*cp = tolower(*cp);
330 
331 	el->el_line.cursor = ep;
332 	if (el->el_line.cursor > el->el_line.lastchar)
333 		el->el_line.cursor = el->el_line.lastchar;
334 	return (CC_REFRESH);
335 }
336 
337 
338 /* em_lower_case():
339  *	Lowercase the characters from cursor to end of current word
340  *	[M-l]
341  */
342 protected el_action_t
343 /*ARGSUSED*/
344 em_lower_case(EditLine *el, int c)
345 {
346 	char *cp, *ep;
347 
348 	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
349 	    el->el_state.argument, ce__isword);
350 
351 	for (cp = el->el_line.cursor; cp < ep; cp++)
352 		if (isupper((unsigned char) *cp))
353 			*cp = tolower(*cp);
354 
355 	el->el_line.cursor = ep;
356 	if (el->el_line.cursor > el->el_line.lastchar)
357 		el->el_line.cursor = el->el_line.lastchar;
358 	return (CC_REFRESH);
359 }
360 
361 
362 /* em_set_mark():
363  *	Set the mark at cursor
364  *	[^@]
365  */
366 protected el_action_t
367 /*ARGSUSED*/
368 em_set_mark(EditLine *el, int c)
369 {
370 
371 	el->el_chared.c_kill.mark = el->el_line.cursor;
372 	return (CC_NORM);
373 }
374 
375 
376 /* em_exchange_mark():
377  *	Exchange the cursor and mark
378  *	[^X^X]
379  */
380 protected el_action_t
381 /*ARGSUSED*/
382 em_exchange_mark(EditLine *el, int c)
383 {
384 	char *cp;
385 
386 	cp = el->el_line.cursor;
387 	el->el_line.cursor = el->el_chared.c_kill.mark;
388 	el->el_chared.c_kill.mark = cp;
389 	return (CC_CURSOR);
390 }
391 
392 
393 /* em_universal_argument():
394  *	Universal argument (argument times 4)
395  *	[^U]
396  */
397 protected el_action_t
398 /*ARGSUSED*/
399 em_universal_argument(EditLine *el, int c)
400 {				/* multiply current argument by 4 */
401 
402 	if (el->el_state.argument > 1000000)
403 		return (CC_ERROR);
404 	el->el_state.doingarg = 1;
405 	el->el_state.argument *= 4;
406 	return (CC_ARGHACK);
407 }
408 
409 
410 /* em_meta_next():
411  *	Add 8th bit to next character typed
412  *	[<ESC>]
413  */
414 protected el_action_t
415 /*ARGSUSED*/
416 em_meta_next(EditLine *el, int c)
417 {
418 
419 	el->el_state.metanext = 1;
420 	return (CC_ARGHACK);
421 }
422 
423 
424 /* em_toggle_overwrite():
425  *	Switch from insert to overwrite mode or vice versa
426  */
427 protected el_action_t
428 /*ARGSUSED*/
429 em_toggle_overwrite(EditLine *el, int c)
430 {
431 
432 	el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
433 	    MODE_REPLACE : MODE_INSERT;
434 	return (CC_NORM);
435 }
436 
437 
438 /* em_copy_prev_word():
439  *	Copy current word to cursor
440  */
441 protected el_action_t
442 /*ARGSUSED*/
443 em_copy_prev_word(EditLine *el, int c)
444 {
445 	char *cp, *oldc, *dp;
446 
447 	if (el->el_line.cursor == el->el_line.buffer)
448 		return (CC_ERROR);
449 
450 	oldc = el->el_line.cursor;
451 	/* does a bounds check */
452 	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
453 	    el->el_state.argument, ce__isword);
454 
455 	c_insert(el, oldc - cp);
456 	for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
457 		*dp++ = *cp;
458 
459 	el->el_line.cursor = dp;/* put cursor at end */
460 
461 	return (CC_REFRESH);
462 }
463 
464 
465 /* em_inc_search_next():
466  *	Emacs incremental next search
467  */
468 protected el_action_t
469 /*ARGSUSED*/
470 em_inc_search_next(EditLine *el, int c)
471 {
472 
473 	el->el_search.patlen = 0;
474 	return (ce_inc_search(el, ED_SEARCH_NEXT_HISTORY));
475 }
476 
477 
478 /* em_inc_search_prev():
479  *	Emacs incremental reverse search
480  */
481 protected el_action_t
482 /*ARGSUSED*/
483 em_inc_search_prev(EditLine *el, int c)
484 {
485 
486 	el->el_search.patlen = 0;
487 	return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY));
488 }
489