emacs.c revision 8870
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)
38static 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 */
51protected el_action_t
52/*ARGSUSED*/
53em_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	if (el->el_line.cursor == el->el_line.buffer) {	/* and the beginning */
59	    term_overwrite(el, STReof, 4);/* then do a EOF */
60	    term__flush();
61	    return CC_EOF;
62	}
63	else {
64	    /* Here we could list completions, but it is an error right now */
65	    term_beep(el);
66	    return CC_ERROR;
67	}
68    }
69    else {
70	c_delafter(el, el->el_state.argument);	/* delete after dot */
71	if (el->el_line.cursor > el->el_line.lastchar)
72	    el->el_line.cursor = el->el_line.lastchar;	/* bounds check */
73	return CC_REFRESH;
74    }
75}
76
77
78/* em_delete_next_word():
79 *	Cut from cursor to end of current word
80 *	[M-d]
81 */
82protected el_action_t
83/*ARGSUSED*/
84em_delete_next_word(el, c)
85    EditLine *el;
86    int c;
87{
88    char *cp, *p, *kp;
89
90    if (el->el_line.cursor == el->el_line.lastchar)
91	return CC_ERROR;
92
93    cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
94		      el->el_state.argument, ce__isword);
95
96    for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
97	/* save the text */
98	*kp++ = *p;
99    el->el_chared.c_kill.last = kp;
100
101    c_delafter(el, cp - el->el_line.cursor);		/* delete after dot */
102    if (el->el_line.cursor > el->el_line.lastchar)
103	el->el_line.cursor = el->el_line.lastchar;	/* bounds check */
104    return CC_REFRESH;
105}
106
107
108/* em_yank():
109 *	Paste cut buffer at cursor position
110 *	[^Y]
111 */
112protected el_action_t
113/*ARGSUSED*/
114em_yank(el, c)
115    EditLine *el;
116    int c;
117{
118    char *kp, *cp;
119
120    if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
121	return CC_ERROR;
122
123    if (el->el_line.lastchar +
124	(el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
125	el->el_line.limit)
126	return CC_ERROR;
127
128    el->el_chared.c_kill.mark = el->el_line.cursor;
129    cp = el->el_line.cursor;
130
131    /* open the space, */
132    c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);
133    /* copy the chars */
134    for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
135	*cp++ = *kp;
136
137    /* if an arg, cursor at beginning else cursor at end */
138    if (el->el_state.argument == 1)
139	el->el_line.cursor = cp;
140
141    return CC_REFRESH;
142}
143
144
145/* em_kill_line():
146 *	Cut the entire line and save in cut buffer
147 *	[^U]
148 */
149protected el_action_t
150/*ARGSUSED*/
151em_kill_line(el, c)
152    EditLine *el;
153    int c;
154{
155    char *kp, *cp;
156
157    cp = el->el_line.buffer;
158    kp = el->el_chared.c_kill.buf;
159    while (cp < el->el_line.lastchar)
160	*kp++ = *cp++;		/* copy it */
161    el->el_chared.c_kill.last = kp;
162    el->el_line.lastchar = el->el_line.buffer;	/* zap! -- delete all of it */
163    el->el_line.cursor = el->el_line.buffer;
164    return CC_REFRESH;
165}
166
167
168/* em_kill_region():
169 *	Cut area between mark and cursor and save in cut buffer
170 *	[^W]
171 */
172protected el_action_t
173/*ARGSUSED*/
174em_kill_region(el, c)
175    EditLine *el;
176    int c;
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, cp - el->el_line.cursor);
190    }
191    else {			/* mark is before cursor */
192	cp = el->el_chared.c_kill.mark;
193	kp = el->el_chared.c_kill.buf;
194	while (cp < el->el_line.cursor)
195	    *kp++ = *cp++;	/* copy it */
196	el->el_chared.c_kill.last = kp;
197	c_delbefore(el, cp - el->el_chared.c_kill.mark);
198	el->el_line.cursor = el->el_chared.c_kill.mark;
199    }
200    return CC_REFRESH;
201}
202
203
204/* em_copy_region():
205 *	Copy area between mark and cursor to cut buffer
206 *	[M-W]
207 */
208protected el_action_t
209/*ARGSUSED*/
210em_copy_region(el, c)
211    EditLine *el;
212    int c;
213{
214    char *kp, *cp;
215
216    if (el->el_chared.c_kill.mark)
217	return CC_ERROR;
218
219    if (el->el_chared.c_kill.mark > el->el_line.cursor) {
220	cp = el->el_line.cursor;
221	kp = el->el_chared.c_kill.buf;
222	while (cp < el->el_chared.c_kill.mark)
223	    *kp++ = *cp++;	/* copy it */
224	el->el_chared.c_kill.last = kp;
225    }
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_traspose():
238 *	Exchange the two characters before the cursor
239 *	Gosling emacs transpose chars [^T]
240 */
241protected el_action_t
242em_gosmacs_traspose(el, c)
243    EditLine *el;
244    int c;
245{
246
247    if (el->el_line.cursor > &el->el_line.buffer[1]) {
248   	/* must have at least two chars entered */
249	c = el->el_line.cursor[-2];
250	el->el_line.cursor[-2] = el->el_line.cursor[-1];
251	el->el_line.cursor[-1] = c;
252	return CC_REFRESH;
253    }
254    else
255	return CC_ERROR;
256}
257
258
259/* em_next_word():
260 *	Move next to end of current word
261 *	[M-f]
262 */
263protected el_action_t
264/*ARGSUSED*/
265em_next_word(el, c)
266    EditLine *el;
267    int c;
268{
269    if (el->el_line.cursor == el->el_line.lastchar)
270	return CC_ERROR;
271
272    el->el_line.cursor = c__next_word(el->el_line.cursor, el->el_line.lastchar,
273				      el->el_state.argument,
274				      ce__isword);
275
276    if (el->el_map.type == MAP_VI)
277	if (el->el_chared.c_vcmd.action & DELETE) {
278	    cv_delfini(el);
279	    return CC_REFRESH;
280	}
281
282    return CC_CURSOR;
283}
284
285/* em_upper_case():
286 *	Uppercase the characters from cursor to end of current word
287 *	[M-u]
288 */
289protected el_action_t
290/*ARGSUSED*/
291em_upper_case(el, c)
292    EditLine *el;
293    int c;
294{
295    char   *cp, *ep;
296
297    ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
298		      el->el_state.argument, ce__isword);
299
300    for (cp = el->el_line.cursor; cp < ep; cp++)
301	if (islower(*cp))
302	    *cp = toupper(*cp);
303
304    el->el_line.cursor = ep;
305    if (el->el_line.cursor > el->el_line.lastchar)
306	el->el_line.cursor = el->el_line.lastchar;
307    return CC_REFRESH;
308}
309
310
311/* em_capitol_case():
312 *	Capitalize the characters from cursor to end of current word
313 *	[M-c]
314 */
315protected el_action_t
316/*ARGSUSED*/
317em_capitol_case(el, c)
318    EditLine *el;
319    int c;
320{
321    char   *cp, *ep;
322
323    ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
324		      el->el_state.argument, ce__isword);
325
326    for (cp = el->el_line.cursor; cp < ep; cp++) {
327	if (isalpha(*cp)) {
328	    if (islower(*cp))
329		*cp = toupper(*cp);
330	    cp++;
331	    break;
332	}
333    }
334    for (; cp < ep; cp++)
335	if (isupper(*cp))
336	    *cp = tolower(*cp);
337
338    el->el_line.cursor = ep;
339    if (el->el_line.cursor > el->el_line.lastchar)
340	el->el_line.cursor = el->el_line.lastchar;
341    return CC_REFRESH;
342}
343
344/* em_lower_case():
345 *	Lowercase the characters from cursor to end of current word
346 *	[M-l]
347 */
348protected el_action_t
349/*ARGSUSED*/
350em_lower_case(el, c)
351    EditLine *el;
352    int c;
353{
354    char   *cp, *ep;
355
356    ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
357		      el->el_state.argument, ce__isword);
358
359    for (cp = el->el_line.cursor; cp < ep; cp++)
360	if (isupper(*cp))
361	    *cp = tolower(*cp);
362
363    el->el_line.cursor = ep;
364    if (el->el_line.cursor > el->el_line.lastchar)
365	el->el_line.cursor = el->el_line.lastchar;
366    return CC_REFRESH;
367}
368
369
370/* em_set_mark():
371 *	Set the mark at cursor
372 *	[^@]
373 */
374protected el_action_t
375/*ARGSUSED*/
376em_set_mark(el, c)
377    EditLine *el;
378    int c;
379{
380    el->el_chared.c_kill.mark = el->el_line.cursor;
381    return CC_NORM;
382}
383
384
385/* em_exchange_mark():
386 *	Exchange the cursor and mark
387 *	[^X^X]
388 */
389protected el_action_t
390/*ARGSUSED*/
391em_exchange_mark(el, c)
392    EditLine *el;
393    int c;
394{
395    register char *cp;
396
397    cp = el->el_line.cursor;
398    el->el_line.cursor = el->el_chared.c_kill.mark;
399    el->el_chared.c_kill.mark = cp;
400    return CC_CURSOR;
401}
402
403/* em_universal_argument():
404 *	Universal argument (argument times 4)
405 *	[^U]
406 */
407protected el_action_t
408/*ARGSUSED*/
409em_universal_argument(el, c)
410    EditLine *el;
411    int c;
412{				/* multiply current argument by 4 */
413    if (el->el_state.argument > 1000000)
414	return CC_ERROR;
415    el->el_state.doingarg = 1;
416    el->el_state.argument *= 4;
417    return CC_ARGHACK;
418}
419
420/* em_meta_next():
421 *	Add 8th bit to next character typed
422 *	[<ESC>]
423 */
424protected el_action_t
425/*ARGSUSED*/
426em_meta_next(el, c)
427    EditLine *el;
428    int c;
429{
430    el->el_state.metanext = 1;
431    return CC_ARGHACK;
432}
433
434
435/* em_toggle_overwrite():
436 *	Switch from insert to overwrite mode or vice versa
437 */
438protected el_action_t
439/*ARGSUSED*/
440em_toggle_overwrite(el, c)
441    EditLine *el;
442    int c;
443{
444    el->el_state.inputmode =
445	(el->el_state.inputmode == MODE_INSERT) ? MODE_REPLACE : MODE_INSERT;
446    return CC_NORM;
447}
448
449
450/* em_copy_prev_word():
451 *	Copy current word to cursor
452 */
453protected el_action_t
454/*ARGSUSED*/
455em_copy_prev_word(el, c)
456    EditLine *el;
457    int c;
458{
459    char *cp, *oldc, *dp;
460
461    if (el->el_line.cursor == el->el_line.buffer)
462	return CC_ERROR;
463
464    oldc = el->el_line.cursor;
465    /* does a bounds check */
466    cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
467		      el->el_state.argument, ce__isword);
468
469    c_insert(el, oldc - cp);
470    for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
471	*dp++ = *cp;
472
473    el->el_line.cursor = dp;		/* put cursor at end */
474
475    return CC_REFRESH;
476}
477
478
479/* em_inc_search_next():
480 *	Emacs incremental next search
481 */
482protected el_action_t
483/*ARGSUSED*/
484em_inc_search_next(el, c)
485    EditLine *el;
486    int c;
487{
488    el->el_search.patlen = 0;
489    return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
490}
491
492
493/* em_inc_search_prev():
494 *	Emacs incremental reverse search
495 */
496protected el_action_t
497/*ARGSUSED*/
498em_inc_search_prev(el, c)
499    EditLine *el;
500    int c;
501{
502    el->el_search.patlen = 0;
503    return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
504}
505