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