xref: /netbsd-src/lib/libedit/emacs.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid[] = "@(#)emacs.c	8.1 (Berkeley) 6/4/93";
39 #endif /* not lint && not SCCSID */
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*/
53 em_delete_or_list(el, c)
54     EditLine *el;
55     int c;
56 {
57     if (el->el_line.cursor == el->el_line.lastchar) {	/* if I'm at the end */
58 #ifdef notyet
59 	if (el->el_line.cursor == el->el_line.buffer) {	/* and the beginning */
60 #endif
61 	    term_overwrite(el, STReof, 4);/* then do a EOF */
62 	    term__flush();
63 	    return CC_EOF;
64 #ifdef notyet
65 	}
66 	else {
67 	    re_goto_bottom(el);
68 	    *el->el_line.lastchar = '\0';		/* just in case */
69 	    return CC_LIST_CHOICES;
70 	}
71 #endif
72     }
73     else {
74 	c_delafter(el, el->el_state.argument);	/* delete after dot */
75 	if (el->el_line.cursor > el->el_line.lastchar)
76 	    el->el_line.cursor = el->el_line.lastchar;	/* bounds check */
77 	return CC_REFRESH;
78     }
79 }
80 
81 
82 /* em_delete_next_word():
83  *	Cut from cursor to end of current word
84  *	[M-d]
85  */
86 protected el_action_t
87 /*ARGSUSED*/
88 em_delete_next_word(el, c)
89     EditLine *el;
90     int c;
91 {
92     char *cp, *p, *kp;
93 
94     if (el->el_line.cursor == el->el_line.lastchar)
95 	return CC_ERROR;
96 
97     cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
98 		      el->el_state.argument, ce__isword);
99 
100     for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
101 	/* save the text */
102 	*kp++ = *p;
103     el->el_chared.c_kill.last = kp;
104 
105     c_delafter(el, cp - el->el_line.cursor);		/* delete after dot */
106     if (el->el_line.cursor > el->el_line.lastchar)
107 	el->el_line.cursor = el->el_line.lastchar;	/* 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*/
118 em_yank(el, c)
119     EditLine *el;
120     int c;
121 {
122     char *kp, *cp;
123 
124     if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
125 	return CC_ERROR;
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, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);
137     /* copy the chars */
138     for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
139 	*cp++ = *kp;
140 
141     /* if an arg, cursor at beginning else cursor at end */
142     if (el->el_state.argument == 1)
143 	el->el_line.cursor = cp;
144 
145     return CC_REFRESH;
146 }
147 
148 
149 /* em_kill_line():
150  *	Cut the entire line and save in cut buffer
151  *	[^U]
152  */
153 protected el_action_t
154 /*ARGSUSED*/
155 em_kill_line(el, c)
156     EditLine *el;
157     int c;
158 {
159     char *kp, *cp;
160 
161     cp = el->el_line.buffer;
162     kp = el->el_chared.c_kill.buf;
163     while (cp < el->el_line.lastchar)
164 	*kp++ = *cp++;		/* copy it */
165     el->el_chared.c_kill.last = kp;
166     el->el_line.lastchar = el->el_line.buffer;	/* zap! -- delete all of it */
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(el, c)
179     EditLine *el;
180     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     }
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(el, c)
215     EditLine *el;
216     int c;
217 {
218     char *kp, *cp;
219 
220     if (el->el_chared.c_kill.mark)
221 	return CC_ERROR;
222 
223     if (el->el_chared.c_kill.mark > el->el_line.cursor) {
224 	cp = el->el_line.cursor;
225 	kp = el->el_chared.c_kill.buf;
226 	while (cp < el->el_chared.c_kill.mark)
227 	    *kp++ = *cp++;	/* copy it */
228 	el->el_chared.c_kill.last = kp;
229     }
230     else {
231 	cp = el->el_chared.c_kill.mark;
232 	kp = el->el_chared.c_kill.buf;
233 	while (cp < el->el_line.cursor)
234 	    *kp++ = *cp++;	/* copy it */
235 	el->el_chared.c_kill.last = kp;
236     }
237     return CC_NORM;
238 }
239 
240 
241 /* em_gosmacs_traspose():
242  *	Exchange the two characters before the cursor
243  *	Gosling emacs transpose chars [^T]
244  */
245 protected el_action_t
246 em_gosmacs_traspose(el, c)
247     EditLine *el;
248     int c;
249 {
250 
251     if (el->el_line.cursor > &el->el_line.buffer[1]) {
252    	/* must have at least two chars entered */
253 	c = el->el_line.cursor[-2];
254 	el->el_line.cursor[-2] = el->el_line.cursor[-1];
255 	el->el_line.cursor[-1] = c;
256 	return CC_REFRESH;
257     }
258     else
259 	return CC_ERROR;
260 }
261 
262 
263 /* em_next_word():
264  *	Move next to end of current word
265  *	[M-f]
266  */
267 protected el_action_t
268 /*ARGSUSED*/
269 em_next_word(el, c)
270     EditLine *el;
271     int c;
272 {
273     if (el->el_line.cursor == el->el_line.lastchar)
274 	return CC_ERROR;
275 
276     el->el_line.cursor = c__next_word(el->el_line.cursor, el->el_line.lastchar,
277 				      el->el_state.argument,
278 				      ce__isword);
279 
280     if (el->el_map.type == MAP_VI)
281 	if (el->el_chared.c_vcmd.action & DELETE) {
282 	    cv_delfini(el);
283 	    return CC_REFRESH;
284 	}
285 
286     return CC_CURSOR;
287 }
288 
289 /* em_upper_case():
290  *	Uppercase the characters from cursor to end of current word
291  *	[M-u]
292  */
293 protected el_action_t
294 /*ARGSUSED*/
295 em_upper_case(el, c)
296     EditLine *el;
297     int c;
298 {
299     char   *cp, *ep;
300 
301     ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
302 		      el->el_state.argument, ce__isword);
303 
304     for (cp = el->el_line.cursor; cp < ep; cp++)
305 	if (islower(*cp))
306 	    *cp = toupper(*cp);
307 
308     el->el_line.cursor = ep;
309     if (el->el_line.cursor > el->el_line.lastchar)
310 	el->el_line.cursor = el->el_line.lastchar;
311     return CC_REFRESH;
312 }
313 
314 
315 /* em_capitol_case():
316  *	Capitalize the characters from cursor to end of current word
317  *	[M-c]
318  */
319 protected el_action_t
320 /*ARGSUSED*/
321 em_capitol_case(el, c)
322     EditLine *el;
323     int c;
324 {
325     char   *cp, *ep;
326 
327     ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
328 		      el->el_state.argument, ce__isword);
329 
330     for (cp = el->el_line.cursor; cp < ep; cp++) {
331 	if (isalpha(*cp)) {
332 	    if (islower(*cp))
333 		*cp = toupper(*cp);
334 	    cp++;
335 	    break;
336 	}
337     }
338     for (; cp < ep; cp++)
339 	if (isupper(*cp))
340 	    *cp = tolower(*cp);
341 
342     el->el_line.cursor = ep;
343     if (el->el_line.cursor > el->el_line.lastchar)
344 	el->el_line.cursor = el->el_line.lastchar;
345     return CC_REFRESH;
346 }
347 
348 /* em_lower_case():
349  *	Lowercase the characters from cursor to end of current word
350  *	[M-l]
351  */
352 protected el_action_t
353 /*ARGSUSED*/
354 em_lower_case(el, c)
355     EditLine *el;
356     int c;
357 {
358     char   *cp, *ep;
359 
360     ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
361 		      el->el_state.argument, ce__isword);
362 
363     for (cp = el->el_line.cursor; cp < ep; cp++)
364 	if (isupper(*cp))
365 	    *cp = tolower(*cp);
366 
367     el->el_line.cursor = ep;
368     if (el->el_line.cursor > el->el_line.lastchar)
369 	el->el_line.cursor = el->el_line.lastchar;
370     return CC_REFRESH;
371 }
372 
373 
374 /* em_set_mark():
375  *	Set the mark at cursor
376  *	[^@]
377  */
378 protected el_action_t
379 /*ARGSUSED*/
380 em_set_mark(el, c)
381     EditLine *el;
382     int c;
383 {
384     el->el_chared.c_kill.mark = el->el_line.cursor;
385     return CC_NORM;
386 }
387 
388 
389 /* em_exchange_mark():
390  *	Exchange the cursor and mark
391  *	[^X^X]
392  */
393 protected el_action_t
394 /*ARGSUSED*/
395 em_exchange_mark(el, c)
396     EditLine *el;
397     int c;
398 {
399     register char *cp;
400 
401     cp = el->el_line.cursor;
402     el->el_line.cursor = el->el_chared.c_kill.mark;
403     el->el_chared.c_kill.mark = cp;
404     return CC_CURSOR;
405 }
406 
407 /* em_universal_argument():
408  *	Universal argument (argument times 4)
409  *	[^U]
410  */
411 protected el_action_t
412 /*ARGSUSED*/
413 em_universal_argument(el, c)
414     EditLine *el;
415     int c;
416 {				/* multiply current argument by 4 */
417     if (el->el_state.argument > 1000000)
418 	return CC_ERROR;
419     el->el_state.doingarg = 1;
420     el->el_state.argument *= 4;
421     return CC_ARGHACK;
422 }
423 
424 /* em_meta_next():
425  *	Add 8th bit to next character typed
426  *	[<ESC>]
427  */
428 protected el_action_t
429 /*ARGSUSED*/
430 em_meta_next(el, c)
431     EditLine *el;
432     int c;
433 {
434     el->el_state.metanext = 1;
435     return CC_ARGHACK;
436 }
437 
438 
439 /* em_toggle_overwrite():
440  *	Switch from insert to overwrite mode or vice versa
441  */
442 protected el_action_t
443 /*ARGSUSED*/
444 em_toggle_overwrite(el, c)
445     EditLine *el;
446     int c;
447 {
448     el->el_state.inputmode =
449 	(el->el_state.inputmode == MODE_INSERT) ? MODE_REPLACE : MODE_INSERT;
450     return CC_NORM;
451 }
452 
453 
454 /* em_copy_prev_word():
455  *	Copy current word to cursor
456  */
457 protected el_action_t
458 /*ARGSUSED*/
459 em_copy_prev_word(el, c)
460     EditLine *el;
461     int c;
462 {
463     char *cp, *oldc, *dp;
464 
465     if (el->el_line.cursor == el->el_line.buffer)
466 	return CC_ERROR;
467 
468     oldc = el->el_line.cursor;
469     /* does a bounds check */
470     cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
471 		      el->el_state.argument, ce__isword);
472 
473     c_insert(el, oldc - cp);
474     for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
475 	*dp++ = *cp;
476 
477     el->el_line.cursor = dp;		/* put cursor at end */
478 
479     return CC_REFRESH;
480 }
481 
482 
483 /* em_inc_search_next():
484  *	Emacs incremental next search
485  */
486 protected el_action_t
487 /*ARGSUSED*/
488 em_inc_search_next(el, c)
489     EditLine *el;
490     int c;
491 {
492     el->el_search.patlen = 0;
493     return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
494 }
495 
496 
497 /* em_inc_search_prev():
498  *	Emacs incremental reverse search
499  */
500 protected el_action_t
501 /*ARGSUSED*/
502 em_inc_search_prev(el, c)
503     EditLine *el;
504     int c;
505 {
506     el->el_search.patlen = 0;
507     return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
508 }
509