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