emacs.c revision 84260
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 *	$NetBSD: emacs.c,v 1.8 2000/09/04 22:06:29 lukem Exp $
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/lib/libedit/emacs.c 84260 2001-10-01 08:41:27Z obrien $");
41#if !defined(lint) && !defined(SCCSID)
42static char sccsid[] = "@(#)emacs.c	8.1 (Berkeley) 6/4/93";
43#endif /* not lint && not SCCSID */
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/lib/libedit/emacs.c 84260 2001-10-01 08:41:27Z obrien $");
46
47/*
48 * emacs.c: Emacs functions
49 */
50#include "sys.h"
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 */
57protected el_action_t
58/*ARGSUSED*/
59em_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 */
91protected el_action_t
92/*ARGSUSED*/
93em_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 */
120protected el_action_t
121/*ARGSUSED*/
122em_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 */
157protected el_action_t
158/*ARGSUSED*/
159em_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 */
179protected el_action_t
180/*ARGSUSED*/
181em_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 */
212protected el_action_t
213/*ARGSUSED*/
214em_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 */
242protected el_action_t
243em_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 */
261protected el_action_t
262/*ARGSUSED*/
263em_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 & DELETE) {
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 */
286protected el_action_t
287/*ARGSUSED*/
288em_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((unsigned char) *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 */
310protected el_action_t
311/*ARGSUSED*/
312em_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((unsigned char) *cp);
323			cp++;
324			break;
325		}
326	}
327	for (; cp < ep; cp++)
328		if (isupper((unsigned char) *cp))
329			*cp = tolower((unsigned char) *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 */
342protected el_action_t
343/*ARGSUSED*/
344em_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((unsigned char) *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 */
366protected el_action_t
367/*ARGSUSED*/
368em_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 */
380protected el_action_t
381/*ARGSUSED*/
382em_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 */
397protected el_action_t
398/*ARGSUSED*/
399em_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 */
414protected el_action_t
415/*ARGSUSED*/
416em_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 */
427protected el_action_t
428/*ARGSUSED*/
429em_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 */
441protected el_action_t
442/*ARGSUSED*/
443em_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 */
468protected el_action_t
469/*ARGSUSED*/
470em_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 */
481protected el_action_t
482/*ARGSUSED*/
483em_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