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