1/*	$OpenBSD: common.c,v 1.23 2023/03/08 04:43:05 guenther Exp $	*/
2/*	$NetBSD: common.c,v 1.24 2009/12/30 22:37:40 christos Exp $	*/
3
4/*-
5 * Copyright (c) 1992, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "config.h"
37
38/*
39 * common.c: Common Editor functions
40 */
41#include <ctype.h>
42#include <string.h>
43
44#include "el.h"
45#include "common.h"
46#include "fcns.h"
47#include "parse.h"
48#include "vi.h"
49
50/* ed_end_of_file():
51 *	Indicate end of file
52 *	[^D]
53 */
54protected el_action_t
55ed_end_of_file(EditLine *el, wint_t c __attribute__((__unused__)))
56{
57
58	re_goto_bottom(el);
59	*el->el_line.lastchar = '\0';
60	return CC_EOF;
61}
62
63
64/* ed_insert():
65 *	Add character to the line
66 *	Insert a character [bound to all insert keys]
67 */
68protected el_action_t
69ed_insert(EditLine *el, wint_t c)
70{
71	int count = el->el_state.argument;
72
73	if (c == '\0')
74		return CC_ERROR;
75
76	if (el->el_line.lastchar + el->el_state.argument >=
77	    el->el_line.limit) {
78		/* end of buffer space, try to allocate more */
79		if (!ch_enlargebufs(el, (size_t) count))
80			return CC_ERROR;	/* error allocating more */
81	}
82
83	if (count == 1) {
84		if (el->el_state.inputmode == MODE_INSERT
85		    || el->el_line.cursor >= el->el_line.lastchar)
86			c_insert(el, 1);
87
88		*el->el_line.cursor++ = c;
89		re_fastaddc(el);		/* fast refresh for one char. */
90	} else {
91		if (el->el_state.inputmode != MODE_REPLACE_1)
92			c_insert(el, el->el_state.argument);
93
94		while (count-- && el->el_line.cursor < el->el_line.lastchar)
95			*el->el_line.cursor++ = c;
96		re_refresh(el);
97	}
98
99	if (el->el_state.inputmode == MODE_REPLACE_1)
100		return vi_command_mode(el, 0);
101
102	return CC_NORM;
103}
104
105
106/* ed_delete_prev_word():
107 *	Delete from beginning of current word to cursor
108 *	[M-^?] [^W]
109 */
110protected el_action_t
111ed_delete_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
112{
113	wchar_t *cp, *p, *kp;
114
115	if (el->el_line.cursor == el->el_line.buffer)
116		return CC_ERROR;
117
118	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
119	    el->el_state.argument, ce__isword);
120
121	for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
122		*kp++ = *p;
123	el->el_chared.c_kill.last = kp;
124
125	c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */
126	el->el_line.cursor = cp;
127	if (el->el_line.cursor < el->el_line.buffer)
128		el->el_line.cursor = el->el_line.buffer; /* bounds check */
129	return CC_REFRESH;
130}
131
132
133/* ed_delete_next_char():
134 *	Delete character under cursor
135 *	[^D] [x]
136 */
137protected el_action_t
138ed_delete_next_char(EditLine *el, wint_t c)
139{
140#ifdef notdef			/* XXX */
141#define	EL	el->el_line
142	(void) fprintf(el->el_errfile,
143	    "\nD(b: %p(%ls)  c: %p(%ls) last: %p(%ls) limit: %p(%ls)\n",
144	    EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
145	    EL.lastchar, EL.limit, EL.limit);
146#endif
147	if (el->el_line.cursor == el->el_line.lastchar) {
148			/* if I'm at the end */
149		if (el->el_map.type == MAP_VI) {
150			if (el->el_line.cursor == el->el_line.buffer) {
151				/* if I'm also at the beginning */
152#ifdef KSHVI
153				return CC_ERROR;
154#else
155				/* then do an EOF */
156				terminal_writec(el, c);
157				return CC_EOF;
158#endif
159			} else {
160#ifdef KSHVI
161				el->el_line.cursor--;
162#else
163				return CC_ERROR;
164#endif
165			}
166		} else {
167			if (el->el_line.cursor != el->el_line.buffer)
168				el->el_line.cursor--;
169			else
170				return CC_ERROR;
171		}
172	}
173	c_delafter(el, el->el_state.argument);	/* delete after dot */
174	if (el->el_line.cursor >= el->el_line.lastchar &&
175	    el->el_line.cursor > el->el_line.buffer)
176			/* bounds check */
177		el->el_line.cursor = el->el_line.lastchar - 1;
178	return CC_REFRESH;
179}
180
181
182/* ed_kill_line():
183 *	Cut to the end of line
184 *	[^K] [^K]
185 */
186protected el_action_t
187ed_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
188{
189	wchar_t *kp, *cp;
190
191	cp = el->el_line.cursor;
192	kp = el->el_chared.c_kill.buf;
193	while (cp < el->el_line.lastchar)
194		*kp++ = *cp++;	/* copy it */
195	el->el_chared.c_kill.last = kp;
196			/* zap! -- delete to end */
197	el->el_line.lastchar = el->el_line.cursor;
198	return CC_REFRESH;
199}
200
201
202/* ed_move_to_end():
203 *	Move cursor to the end of line
204 *	[^E] [^E]
205 */
206protected el_action_t
207ed_move_to_end(EditLine *el, wint_t c __attribute__((__unused__)))
208{
209
210	el->el_line.cursor = el->el_line.lastchar;
211	if (el->el_map.type == MAP_VI) {
212		if (el->el_chared.c_vcmd.action != NOP) {
213			cv_delfini(el);
214			return CC_REFRESH;
215		}
216#ifdef VI_MOVE
217		el->el_line.cursor--;
218#endif
219	}
220	return CC_CURSOR;
221}
222
223
224/* ed_move_to_beg():
225 *	Move cursor to the beginning of line
226 *	[^A] [^A]
227 */
228protected el_action_t
229ed_move_to_beg(EditLine *el, wint_t c __attribute__((__unused__)))
230{
231
232	el->el_line.cursor = el->el_line.buffer;
233
234	if (el->el_map.type == MAP_VI) {
235			/* We want FIRST non space character */
236		while (iswspace(*el->el_line.cursor))
237			el->el_line.cursor++;
238		if (el->el_chared.c_vcmd.action != NOP) {
239			cv_delfini(el);
240			return CC_REFRESH;
241		}
242	}
243	return CC_CURSOR;
244}
245
246
247/* ed_transpose_chars():
248 *	Exchange the character to the left of the cursor with the one under it
249 *	[^T] [^T]
250 */
251protected el_action_t
252ed_transpose_chars(EditLine *el, wint_t c)
253{
254
255	if (el->el_line.cursor < el->el_line.lastchar) {
256		if (el->el_line.lastchar <= &el->el_line.buffer[1])
257			return CC_ERROR;
258		else
259			el->el_line.cursor++;
260	}
261	if (el->el_line.cursor > &el->el_line.buffer[1]) {
262		/* must have at least two chars entered */
263		c = el->el_line.cursor[-2];
264		el->el_line.cursor[-2] = el->el_line.cursor[-1];
265		el->el_line.cursor[-1] = c;
266		return CC_REFRESH;
267	} else
268		return CC_ERROR;
269}
270
271
272/* ed_next_char():
273 *	Move to the right one character
274 *	[^F] [^F]
275 */
276protected el_action_t
277ed_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
278{
279	wchar_t *lim = el->el_line.lastchar;
280
281	if (el->el_line.cursor >= lim ||
282	    (el->el_line.cursor == lim - 1 &&
283	    el->el_map.type == MAP_VI &&
284	    el->el_chared.c_vcmd.action == NOP))
285		return CC_ERROR;
286
287	el->el_line.cursor += el->el_state.argument;
288	if (el->el_line.cursor > lim)
289		el->el_line.cursor = lim;
290
291	if (el->el_map.type == MAP_VI)
292		if (el->el_chared.c_vcmd.action != NOP) {
293			cv_delfini(el);
294			return CC_REFRESH;
295		}
296	return CC_CURSOR;
297}
298
299
300/* ed_prev_word():
301 *	Move to the beginning of the current word
302 *	[M-b] [b]
303 */
304protected el_action_t
305ed_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
306{
307
308	if (el->el_line.cursor == el->el_line.buffer)
309		return CC_ERROR;
310
311	el->el_line.cursor = c__prev_word(el->el_line.cursor,
312	    el->el_line.buffer,
313	    el->el_state.argument,
314	    ce__isword);
315
316	if (el->el_map.type == MAP_VI)
317		if (el->el_chared.c_vcmd.action != NOP) {
318			cv_delfini(el);
319			return CC_REFRESH;
320		}
321	return CC_CURSOR;
322}
323
324
325/* ed_prev_char():
326 *	Move to the left one character
327 *	[^B] [^B]
328 */
329protected el_action_t
330ed_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
331{
332
333	if (el->el_line.cursor > el->el_line.buffer) {
334		el->el_line.cursor -= el->el_state.argument;
335		if (el->el_line.cursor < el->el_line.buffer)
336			el->el_line.cursor = el->el_line.buffer;
337
338		if (el->el_map.type == MAP_VI)
339			if (el->el_chared.c_vcmd.action != NOP) {
340				cv_delfini(el);
341				return CC_REFRESH;
342			}
343		return CC_CURSOR;
344	} else
345		return CC_ERROR;
346}
347
348
349/* ed_quoted_insert():
350 *	Add the next character typed verbatim
351 *	[^V] [^V]
352 */
353protected el_action_t
354ed_quoted_insert(EditLine *el, wint_t c)
355{
356	int num;
357
358	tty_quotemode(el);
359	num = el_wgetc(el, &c);
360	tty_noquotemode(el);
361	if (num == 1)
362		return ed_insert(el, c);
363	else
364		return ed_end_of_file(el, 0);
365}
366
367
368/* ed_digit():
369 *	Adds to argument or enters a digit
370 */
371protected el_action_t
372ed_digit(EditLine *el, wint_t c)
373{
374
375	if (!iswdigit(c))
376		return CC_ERROR;
377
378	if (el->el_state.doingarg) {
379			/* if doing an arg, add this in... */
380		if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
381			el->el_state.argument = c - '0';
382		else {
383			if (el->el_state.argument > 1000000)
384				return CC_ERROR;
385			el->el_state.argument =
386			    (el->el_state.argument * 10) + (c - '0');
387		}
388		return CC_ARGHACK;
389	}
390
391	return ed_insert(el, c);
392}
393
394
395/* ed_argument_digit():
396 *	Digit that starts argument
397 *	For ESC-n
398 */
399protected el_action_t
400ed_argument_digit(EditLine *el, wint_t c)
401{
402
403	if (!iswdigit(c))
404		return CC_ERROR;
405
406	if (el->el_state.doingarg) {
407		if (el->el_state.argument > 1000000)
408			return CC_ERROR;
409		el->el_state.argument = (el->el_state.argument * 10) +
410		    (c - '0');
411	} else {		/* else starting an argument */
412		el->el_state.argument = c - '0';
413		el->el_state.doingarg = 1;
414	}
415	return CC_ARGHACK;
416}
417
418
419/* ed_unassigned():
420 *	Indicates unbound character
421 *	Bound to keys that are not assigned
422 */
423protected el_action_t
424ed_unassigned(EditLine *el, wint_t c __attribute__((__unused__)))
425{
426
427	return CC_ERROR;
428}
429
430
431/* ed_ignore():
432 *	Input characters that have no effect
433 *	[^C ^O ^Q ^S ^Z ^\ ^]] [^C ^O ^Q ^S ^\]
434 */
435protected el_action_t
436ed_ignore(EditLine *el __attribute__((__unused__)),
437	      wint_t c __attribute__((__unused__)))
438{
439
440	return CC_NORM;
441}
442
443
444/* ed_newline():
445 *	Execute command
446 *	[^J]
447 */
448protected el_action_t
449ed_newline(EditLine *el, wint_t c __attribute__((__unused__)))
450{
451
452	re_goto_bottom(el);
453	*el->el_line.lastchar++ = '\n';
454	*el->el_line.lastchar = '\0';
455	return CC_NEWLINE;
456}
457
458
459/* ed_delete_prev_char():
460 *	Delete the character to the left of the cursor
461 *	[^?]
462 */
463protected el_action_t
464ed_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
465{
466
467	if (el->el_line.cursor <= el->el_line.buffer)
468		return CC_ERROR;
469
470	c_delbefore(el, el->el_state.argument);
471	el->el_line.cursor -= el->el_state.argument;
472	if (el->el_line.cursor < el->el_line.buffer)
473		el->el_line.cursor = el->el_line.buffer;
474	return CC_REFRESH;
475}
476
477
478/* ed_clear_screen():
479 *	Clear screen leaving current line at the top
480 *	[^L]
481 */
482protected el_action_t
483ed_clear_screen(EditLine *el, wint_t c __attribute__((__unused__)))
484{
485
486	terminal_clear_screen(el);	/* clear the whole real screen */
487	re_clear_display(el);	/* reset everything */
488	return CC_REFRESH;
489}
490
491
492/* ed_redisplay():
493 *	Redisplay everything
494 *	^R
495 */
496protected el_action_t
497ed_redisplay(EditLine *el __attribute__((__unused__)),
498	     wint_t c __attribute__((__unused__)))
499{
500
501	return CC_REDISPLAY;
502}
503
504
505/* ed_start_over():
506 *	Erase current line and start from scratch
507 *	[^G]
508 */
509protected el_action_t
510ed_start_over(EditLine *el, wint_t c __attribute__((__unused__)))
511{
512
513	ch_reset(el);
514	return CC_REFRESH;
515}
516
517
518/* ed_sequence_lead_in():
519 *	First character in a bound sequence
520 *	Placeholder for external keys
521 */
522protected el_action_t
523ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
524		    wint_t c __attribute__((__unused__)))
525{
526
527	return CC_NORM;
528}
529
530
531/* ed_prev_history():
532 *	Move to the previous history line
533 *	[^P] [k]
534 */
535protected el_action_t
536ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
537{
538	char beep = 0;
539	int sv_event = el->el_history.eventno;
540
541	el->el_chared.c_undo.len = -1;
542	*el->el_line.lastchar = '\0';		/* just in case */
543
544	if (el->el_history.eventno == 0) {	/* save the current buffer
545						 * away */
546		(void) wcsncpy(el->el_history.buf, el->el_line.buffer,
547		    EL_BUFSIZ);
548		el->el_history.last = el->el_history.buf +
549		    (el->el_line.lastchar - el->el_line.buffer);
550	}
551	el->el_history.eventno += el->el_state.argument;
552
553	if (hist_get(el) == CC_ERROR) {
554		if (el->el_map.type == MAP_VI) {
555			el->el_history.eventno = sv_event;
556		}
557		beep = 1;
558		/* el->el_history.eventno was fixed by first call */
559		(void) hist_get(el);
560	}
561	if (beep)
562		return CC_REFRESH_BEEP;
563	return CC_REFRESH;
564}
565
566
567/* ed_next_history():
568 *	Move to the next history line
569 *	[^N] [j]
570 */
571protected el_action_t
572ed_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
573{
574	el_action_t beep = CC_REFRESH, rval;
575
576	el->el_chared.c_undo.len = -1;
577	*el->el_line.lastchar = '\0';	/* just in case */
578
579	el->el_history.eventno -= el->el_state.argument;
580
581	if (el->el_history.eventno < 0) {
582		el->el_history.eventno = 0;
583		beep = CC_REFRESH_BEEP;
584	}
585	rval = hist_get(el);
586	if (rval == CC_REFRESH)
587		return beep;
588	return rval;
589
590}
591
592
593/* ed_search_prev_history():
594 *	Search previous in history for a line matching the current
595 *	next search history [M-P] [K]
596 */
597protected el_action_t
598ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
599{
600	const wchar_t *hp;
601	int h;
602	int found = 0;
603
604	el->el_chared.c_vcmd.action = NOP;
605	el->el_chared.c_undo.len = -1;
606	*el->el_line.lastchar = '\0';	/* just in case */
607	if (el->el_history.eventno < 0) {
608#ifdef DEBUG_EDIT
609		(void) fprintf(el->el_errfile,
610		    "e_prev_search_hist(): eventno < 0;\n");
611#endif
612		el->el_history.eventno = 0;
613		return CC_ERROR;
614	}
615	if (el->el_history.eventno == 0) {
616		(void) wcsncpy(el->el_history.buf, el->el_line.buffer,
617		    EL_BUFSIZ);
618		el->el_history.last = el->el_history.buf +
619		    (el->el_line.lastchar - el->el_line.buffer);
620	}
621	if (el->el_history.ref == NULL)
622		return CC_ERROR;
623
624	hp = HIST_FIRST(el);
625	if (hp == NULL)
626		return CC_ERROR;
627
628	c_setpat(el);		/* Set search pattern !! */
629
630	for (h = 1; h <= el->el_history.eventno; h++)
631		hp = HIST_NEXT(el);
632
633	while (hp != NULL) {
634#ifdef SDEBUG
635		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
636#endif
637		if ((wcsncmp(hp, el->el_line.buffer, (size_t)
638			    (el->el_line.lastchar - el->el_line.buffer)) ||
639			hp[el->el_line.lastchar - el->el_line.buffer]) &&
640		    c_hmatch(el, hp)) {
641			found = 1;
642			break;
643		}
644		h++;
645		hp = HIST_NEXT(el);
646	}
647
648	if (!found) {
649#ifdef SDEBUG
650		(void) fprintf(el->el_errfile, "not found\n");
651#endif
652		return CC_ERROR;
653	}
654	el->el_history.eventno = h;
655
656	return hist_get(el);
657}
658
659
660/* ed_search_next_history():
661 *	Search next in history for a line matching the current
662 *	[M-N] [J]
663 */
664protected el_action_t
665ed_search_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
666{
667	const wchar_t *hp;
668	int h;
669	int found = 0;
670
671	el->el_chared.c_vcmd.action = NOP;
672	el->el_chared.c_undo.len = -1;
673	*el->el_line.lastchar = '\0';	/* just in case */
674
675	if (el->el_history.eventno == 0)
676		return CC_ERROR;
677
678	if (el->el_history.ref == NULL)
679		return CC_ERROR;
680
681	hp = HIST_FIRST(el);
682	if (hp == NULL)
683		return CC_ERROR;
684
685	c_setpat(el);		/* Set search pattern !! */
686
687	for (h = 1; h < el->el_history.eventno && hp; h++) {
688#ifdef SDEBUG
689		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
690#endif
691		if ((wcsncmp(hp, el->el_line.buffer, (size_t)
692			    (el->el_line.lastchar - el->el_line.buffer)) ||
693			hp[el->el_line.lastchar - el->el_line.buffer]) &&
694		    c_hmatch(el, hp))
695			found = h;
696		hp = HIST_NEXT(el);
697	}
698
699	if (!found) {		/* is it the current history number? */
700		if (!c_hmatch(el, el->el_history.buf)) {
701#ifdef SDEBUG
702			(void) fprintf(el->el_errfile, "not found\n");
703#endif
704			return CC_ERROR;
705		}
706	}
707	el->el_history.eventno = found;
708
709	return hist_get(el);
710}
711
712
713/* ed_prev_line():
714 *	Move up one line
715 *	Could be [k] [^p]
716 */
717protected el_action_t
718ed_prev_line(EditLine *el, wint_t c __attribute__((__unused__)))
719{
720	wchar_t *ptr;
721	int nchars = c_hpos(el);
722
723	/*
724         * Move to the line requested
725         */
726	if (*(ptr = el->el_line.cursor) == '\n')
727		ptr--;
728
729	for (; ptr >= el->el_line.buffer; ptr--)
730		if (*ptr == '\n' && --el->el_state.argument <= 0)
731			break;
732
733	if (el->el_state.argument > 0)
734		return CC_ERROR;
735
736	/*
737         * Move to the beginning of the line
738         */
739	for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
740		continue;
741
742	/*
743         * Move to the character requested
744         */
745	for (ptr++;
746	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
747	    ptr++)
748		continue;
749
750	el->el_line.cursor = ptr;
751	return CC_CURSOR;
752}
753
754
755/* ed_next_line():
756 *	Move down one line
757 *	Could be [j] [^n]
758 */
759protected el_action_t
760ed_next_line(EditLine *el, wint_t c __attribute__((__unused__)))
761{
762	wchar_t *ptr;
763	int nchars = c_hpos(el);
764
765	/*
766         * Move to the line requested
767         */
768	for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
769		if (*ptr == '\n' && --el->el_state.argument <= 0)
770			break;
771
772	if (el->el_state.argument > 0)
773		return CC_ERROR;
774
775	/*
776         * Move to the character requested
777         */
778	for (ptr++;
779	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
780	    ptr++)
781		continue;
782
783	el->el_line.cursor = ptr;
784	return CC_CURSOR;
785}
786
787
788/* ed_command():
789 *	Editline extended command
790 *	[M-X] [:]
791 */
792protected el_action_t
793ed_command(EditLine *el, wint_t c __attribute__((__unused__)))
794{
795	wchar_t tmpbuf[EL_BUFSIZ];
796	int tmplen;
797
798	tmplen = c_gets(el, tmpbuf, L"\n: ");
799	terminal__putc(el, '\n');
800
801	if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
802		terminal_beep(el);
803
804	el->el_map.current = el->el_map.key;
805	re_clear_display(el);
806	return CC_REFRESH;
807}
808