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