/ lib / libedit / src / emacs.c
emacs.c
  1  /*	$NetBSD: emacs.c,v 1.23 2009/12/30 22:37:40 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.23 2009/12/30 22:37:40 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*/
 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  			term_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  			term_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*/
 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*/
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*/
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*/
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*/
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
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*/
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*/
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*/
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*/
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*/
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*/
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*/
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*/
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*/
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*/
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*/
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*/
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*/
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  }