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