2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $NetBSD: refresh.c,v 1.34 2009/12/28 22:15:36 christos Exp $
35 #if !defined(lint) && !defined(SCCSID)
36 static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93";
37 #endif /* not lint && not SCCSID */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
42 * refresh.c: Lower level screen refreshing functions
52 private void re_nextline(EditLine *);
53 private void re_addc(EditLine *, int);
54 private void re_update_line(EditLine *, char *, char *, int);
55 private void re_insert (EditLine *, char *, int, int, char *, int);
56 private void re_delete(EditLine *, char *, int, int, int);
57 private void re_fastputc(EditLine *, int);
58 private void re_clear_eol(EditLine *, int, int, int);
59 private void re__strncopy(char *, char *, size_t);
60 private void re__copy_and_pad(char *, const char *, size_t);
63 private void re_printstr(EditLine *, const char *, char *, char *);
64 #define __F el->el_errfile
65 #define ELRE_ASSERT(a, b, c) do \
66 if (/*CONSTCOND*/ a) { \
70 while (/*CONSTCOND*/0)
71 #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
74 * Print a string on the debugging pty
77 re_printstr(EditLine *el, const char *str, char *f, char *t)
80 ELRE_DEBUG(1, (__F, "%s:\"", str));
82 ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
83 ELRE_DEBUG(1, (__F, "\"\r\n"));
86 #define ELRE_ASSERT(a, b, c)
87 #define ELRE_DEBUG(a, b)
91 * Move to the next line or scroll
94 re_nextline(EditLine *el)
96 el->el_refresh.r_cursor.h = 0; /* reset it. */
99 * If we would overflow (input is longer than terminal size),
100 * emulate scroll by dropping first line and shuffling the rest.
101 * We do this via pointer shuffling - it's safe in this case
102 * and we avoid memcpy().
104 if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
105 int i, lins = el->el_term.t_size.v;
106 char *firstline = el->el_vdisplay[0];
108 for(i = 1; i < lins; i++)
109 el->el_vdisplay[i - 1] = el->el_vdisplay[i];
111 firstline[0] = '\0'; /* empty the string */
112 el->el_vdisplay[i - 1] = firstline;
114 el->el_refresh.r_cursor.v++;
116 ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
117 (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
118 el->el_refresh.r_cursor.v, el->el_term.t_size.v),
123 * Draw c, expanding tabs, control chars etc.
126 re_addc(EditLine *el, int c)
133 if (c == '\n') { /* expand the newline */
134 int oldv = el->el_refresh.r_cursor.v;
135 re_putc(el, '\0', 0); /* assure end of line */
136 if (oldv == el->el_refresh.r_cursor.v) /* XXX */
140 if (c == '\t') { /* expand the tab */
143 if ((el->el_refresh.r_cursor.h & 07) == 0)
144 break; /* go until tab stop */
146 } else if (iscntrl(c)) {
151 /* uncontrolify it; works only for iso8859-1 like sets */
152 re_putc(el, (toascii(c) | 0100), 1);
154 re_putc(el, '\\', 1);
155 re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
156 re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
157 re_putc(el, (c & 07) + '0', 1);
163 * Draw the character given
166 re_putc(EditLine *el, int c, int shift)
169 ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
171 el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
175 el->el_refresh.r_cursor.h++; /* advance to next place */
176 if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
177 /* assure end of line */
178 el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h]
187 * draws the new virtual screen image from the current input
188 * line, then goes line-by-line changing the real image to the new
189 * virtual image. The routine to re-draw a line can be replaced
190 * easily in hopes of a smarter one being placed there.
193 re_refresh(EditLine *el)
202 ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
203 el->el_line.buffer));
205 /* reset the Drawing cursor */
206 el->el_refresh.r_cursor.h = 0;
207 el->el_refresh.r_cursor.v = 0;
209 /* temporarily draw rprompt to calculate its size */
210 prompt_print(el, EL_RPROMPT);
212 /* reset the Drawing cursor */
213 el->el_refresh.r_cursor.h = 0;
214 el->el_refresh.r_cursor.v = 0;
216 if (el->el_line.cursor >= el->el_line.lastchar) {
217 if (el->el_map.current == el->el_map.alt
218 && el->el_line.lastchar != el->el_line.buffer)
219 el->el_line.cursor = el->el_line.lastchar - 1;
221 el->el_line.cursor = el->el_line.lastchar;
224 cur.h = -1; /* set flag in case I'm not set */
227 prompt_print(el, EL_PROMPT);
229 /* draw the current input buffer */
231 termsz = el->el_term.t_size.h * el->el_term.t_size.v;
232 if (el->el_line.lastchar - el->el_line.buffer > termsz) {
234 * If line is longer than terminal, process only part
235 * of line which would influence display.
237 size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
239 st = el->el_line.lastchar - rem
240 - (termsz - (((rem / el->el_term.t_size.v) - 1)
241 * el->el_term.t_size.v));
244 st = el->el_line.buffer;
246 for (cp = st; cp < el->el_line.lastchar; cp++) {
247 if (cp == el->el_line.cursor) {
249 cur.h = el->el_refresh.r_cursor.h;
250 cur.v = el->el_refresh.r_cursor.v;
252 re_addc(el, (unsigned char) *cp);
255 if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
256 cur.h = el->el_refresh.r_cursor.h;
257 cur.v = el->el_refresh.r_cursor.v;
259 rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
260 el->el_rprompt.p_pos.h;
261 if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
262 !el->el_refresh.r_cursor.v && rhdiff > 1) {
264 * have a right-hand side prompt that will fit
265 * on the end of the first line with at least
266 * one character gap to the input buffer.
268 while (--rhdiff > 0) /* pad out with spaces */
270 prompt_print(el, EL_RPROMPT);
272 el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
273 el->el_rprompt.p_pos.v = 0;
276 re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
278 el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
281 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
282 el->el_term.t_size.h, el->el_refresh.r_cursor.h,
283 el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
285 ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
286 for (i = 0; i <= el->el_refresh.r_newcv; i++) {
287 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
288 re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
291 * Copy the new line to be the current one, and pad out with
292 * spaces to the full width of the terminal so that if we try
293 * moving the cursor by writing the character that is at the
294 * end of the screen line, it won't be a NUL or some old
297 re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
298 (size_t) el->el_term.t_size.h);
301 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
302 el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
304 if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
305 for (; i <= el->el_refresh.r_oldcv; i++) {
306 term_move_to_line(el, i);
307 term_move_to_char(el, 0);
308 term_clear_EOL(el, (int) strlen(el->el_display[i]));
310 term_overwrite(el, "C\b", (size_t)2);
311 #endif /* DEBUG_REFRESH */
312 el->el_display[i][0] = '\0';
315 el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
317 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
318 el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
320 term_move_to_line(el, cur.v); /* go to where the cursor is */
321 term_move_to_char(el, cur.h);
326 * used to go to last used screen line
329 re_goto_bottom(EditLine *el)
332 term_move_to_line(el, el->el_refresh.r_oldcv);
333 term__putc(el, '\n');
334 re_clear_display(el);
340 * insert num characters of s into d (in front of the character)
341 * at dat, maximum length of d is dlen
345 re_insert(EditLine *el __unused,
346 char *d, int dat, int dlen, char *s, int num)
352 if (num > dlen - dat)
356 (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
358 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
360 /* open up the space for num chars */
366 d[dlen] = '\0'; /* just in case */
369 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
371 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
373 /* copy the characters */
374 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
378 (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
379 num, dat, dlen, d, s));
380 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
385 * delete num characters d at dat, maximum length of d is dlen
389 re_delete(EditLine *el __unused,
390 char *d, int dat, int dlen, int num)
396 if (dat + num >= dlen) {
401 (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
404 /* open up the space for num chars */
410 d[dlen] = '\0'; /* just in case */
413 (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
419 * Like strncpy without padding.
422 re__strncopy(char *a, char *b, size_t n)
430 * Find the number of characters we need to clear till the end of line
431 * in order to make sure that we have cleared the previous contents of
432 * the line. fx and sx is the number of characters inserted or deleted
433 * int the first or second diff, diff is the difference between the
434 * number of characters between the new and old line.
437 re_clear_eol(EditLine *el, int fx, int sx, int diff)
440 ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
452 ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
453 term_clear_EOL(el, diff);
456 /*****************************************************************
457 re_update_line() is based on finding the middle difference of each line
460 /old first difference
461 /beginning of line | /old last same /old EOL
463 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
464 new: eddie> Oh, my little buggy says to me, as lurgid as
466 \beginning of line | \new last same \new end of line
467 \new first difference
469 all are character pointers for the sake of speed. Special cases for
470 no differences, as well as for end of line additions must be handled.
471 **************************************************************** */
473 /* Minimum at which doing an insert it "worth it". This should be about
474 * half the "cost" of going into insert mode, inserting a character, and
475 * going back out. This should really be calculated from the termcap
476 * data... For the moment, a good number for ANSI terminals.
478 #define MIN_END_KEEP 4
481 re_update_line(EditLine *el, char *old, char *new, int i)
484 char *ofd, *ols, *oe, *nfd, *nls, *ne;
485 char *osb, *ose, *nsb, *nse;
492 for (o = old, n = new; *o && (*o == *n); o++, n++)
498 * Find the end of both old and new
503 * Remove any trailing blanks off of the end, being careful not to
504 * back up past the beginning.
517 /* remove blanks from end of new */
527 * if no diff, continue to next line of redraw
529 if (*ofd == '\0' && *nfd == '\0') {
530 ELRE_DEBUG(1, (__F, "no difference.\r\n"));
534 * find last same pointer
536 while ((o > ofd) && (n > nfd) && (*--o == *--n))
542 * find same begining and same end
550 * case 1: insert: scan from nfd to nls looking for *ofd
553 for (c = *ofd, n = nfd; n < nls; n++) {
556 p < nls && o < ols && *o == *p;
560 * if the new match is longer and it's worth
561 * keeping, then we take it
563 if (((nse - nsb) < (p - n)) &&
564 (2 * (p - n) > n - nfd)) {
574 * case 2: delete: scan from ofd to ols looking for *nfd
577 for (c = *nfd, o = ofd; o < ols; o++) {
580 p < ols && n < nls && *p == *n;
584 * if the new match is longer and it's worth
585 * keeping, then we take it
587 if (((ose - osb) < (p - o)) &&
588 (2 * (p - o) > o - ofd)) {
598 * Pragmatics I: If old trailing whitespace or not enough characters to
599 * save to be worth it, then don't save the last same info.
601 if ((oe - ols) < MIN_END_KEEP) {
606 * Pragmatics II: if the terminal isn't smart enough, make the data
607 * dumber so the smart update doesn't try anything fancy
611 * fx is the number of characters we need to insert/delete: in the
612 * beginning to bring the two same begins together
614 fx = (int)((nsb - nfd) - (osb - ofd));
616 * sx is the number of characters we need to insert/delete: in the
617 * end to bring the two same last parts together
619 sx = (int)((nls - nse) - (ols - ose));
621 if (!EL_CAN_INSERT) {
632 if ((ols - ofd) < (nls - nfd)) {
637 if (!EL_CAN_DELETE) {
648 if ((ols - ofd) > (nls - nfd)) {
654 * Pragmatics III: make sure the middle shifted pointers are correct if
655 * they don't point to anything (we may have moved ols or nls).
657 /* if the change isn't worth it, don't bother */
658 /* was: if (osb == ose) */
659 if ((ose - osb) < MIN_END_KEEP) {
666 * Now that we are done with pragmatics we recompute fx, sx
668 fx = (int)((nsb - nfd) - (osb - ofd));
669 sx = (int)((nls - nse) - (ols - ose));
671 ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
672 ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
673 ofd - old, osb - old, ose - old, ols - old, oe - old));
674 ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
675 nfd - new, nsb - new, nse - new, nls - new, ne - new));
677 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
679 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
681 re_printstr(el, "old- oe", old, oe);
682 re_printstr(el, "new- ne", new, ne);
683 re_printstr(el, "old-ofd", old, ofd);
684 re_printstr(el, "new-nfd", new, nfd);
685 re_printstr(el, "ofd-osb", ofd, osb);
686 re_printstr(el, "nfd-nsb", nfd, nsb);
687 re_printstr(el, "osb-ose", osb, ose);
688 re_printstr(el, "nsb-nse", nsb, nse);
689 re_printstr(el, "ose-ols", ose, ols);
690 re_printstr(el, "nse-nls", nse, nls);
691 re_printstr(el, "ols- oe", ols, oe);
692 re_printstr(el, "nls- ne", nls, ne);
693 #endif /* DEBUG_REFRESH */
696 * el_cursor.v to this line i MUST be in this routine so that if we
697 * don't have to change the line, we don't move to it. el_cursor.h to
700 term_move_to_line(el, i);
703 * at this point we have something like this:
705 * /old /ofd /osb /ose /ols /oe
706 * v.....................v v..................v v........v
707 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
708 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
709 * ^.....................^ ^..................^ ^........^
710 * \new \nfd \nsb \nse \nls \ne
712 * fx is the difference in length between the chars between nfd and
713 * nsb, and the chars between ofd and osb, and is thus the number of
714 * characters to delete if < 0 (new is shorter than old, as above),
715 * or insert (new is longer than short).
717 * sx is the same for the second differences.
721 * if we have a net insert on the first difference, AND inserting the
722 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
723 * character (which is ne if nls != ne, otherwise is nse) off the edge
724 * of the screen (el->el_term.t_size.h) else we do the deletes first
725 * so that we keep everything we need to.
729 * if the last same is the same like the end, there is no last same
730 * part, otherwise we want to keep the last same part set p to the
731 * last useful old character
733 p = (ols != oe) ? oe : ose;
736 * if (There is a diffence in the beginning) && (we need to insert
737 * characters) && (the number of characters to insert is less than
739 * We need to do an insert!
740 * else if (we need to delete characters)
741 * We need to delete characters!
743 * No insert or delete
745 if ((nsb != nfd) && fx > 0 &&
746 ((p - old) + fx <= el->el_term.t_size.h)) {
748 (__F, "first diff insert at %d...\r\n", nfd - new));
750 * Move to the first char to insert, where the first diff is.
752 term_move_to_char(el, (int)(nfd - new));
754 * Check if we have stuff to keep at end
757 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
759 * insert fx chars of new starting at nfd
762 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
763 "ERROR: cannot insert in early first diff\n"));
764 term_insertwrite(el, nfd, fx);
765 re_insert(el, old, (int)(ofd - old),
766 el->el_term.t_size.h, nfd, fx);
769 * write (nsb-nfd) - fx chars of new starting at
772 len = (size_t) ((nsb - nfd) - fx);
773 term_overwrite(el, (nfd + fx), len);
774 re__strncopy(ofd + fx, nfd + fx, len);
776 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
777 len = (size_t)(nsb - nfd);
778 term_overwrite(el, nfd, len);
779 re__strncopy(ofd, nfd, len);
787 (__F, "first diff delete at %d...\r\n", ofd - old));
789 * move to the first char to delete where the first diff is
791 term_move_to_char(el, (int)(ofd - old));
793 * Check if we have stuff to save
796 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
798 * fx is less than zero *always* here but we check
802 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
803 "ERROR: cannot delete in first diff\n"));
804 term_deletechars(el, -fx);
805 re_delete(el, old, (int)(ofd - old),
806 el->el_term.t_size.h, -fx);
809 * write (nsb-nfd) chars of new starting at nfd
811 len = (size_t) (nsb - nfd);
812 term_overwrite(el, nfd, len);
813 re__strncopy(ofd, nfd, len);
817 "but with nothing left to save\r\n"));
819 * write (nsb-nfd) chars of new starting at nfd
821 term_overwrite(el, nfd, (size_t)(nsb - nfd));
822 re_clear_eol(el, fx, sx,
823 (int)((oe - old) - (ne - new)));
832 if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
834 "second diff delete at %d...\r\n", (ose - old) + fx));
836 * Check if we have stuff to delete
839 * fx is the number of characters inserted (+) or deleted (-)
842 term_move_to_char(el, (int)((ose - old) + fx));
844 * Check if we have stuff to save
847 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
849 * Again a duplicate test.
852 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
853 "ERROR: cannot delete in second diff\n"));
854 term_deletechars(el, -sx);
857 * write (nls-nse) chars of new starting at nse
859 term_overwrite(el, nse, (size_t)(nls - nse));
862 "but with nothing left to save\r\n"));
863 term_overwrite(el, nse, (size_t)(nls - nse));
864 re_clear_eol(el, fx, sx,
865 (int)((oe - old) - (ne - new)));
869 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
871 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
872 ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
875 term_move_to_char(el, (int)(nfd - new));
877 * Check if we have stuff to keep at the end
880 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
882 * We have to recalculate fx here because we set it
883 * to zero above as a flag saying that we hadn't done
884 * an early first insert.
886 fx = (int)((nsb - nfd) - (osb - ofd));
889 * insert fx chars of new starting at nfd
891 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
892 "ERROR: cannot insert in late first diff\n"));
893 term_insertwrite(el, nfd, fx);
894 re_insert(el, old, (int)(ofd - old),
895 el->el_term.t_size.h, nfd, fx);
898 * write (nsb-nfd) - fx chars of new starting at
901 len = (size_t) ((nsb - nfd) - fx);
902 term_overwrite(el, (nfd + fx), len);
903 re__strncopy(ofd + fx, nfd + fx, len);
905 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
906 len = (size_t) (nsb - nfd);
907 term_overwrite(el, nfd, len);
908 re__strncopy(ofd, nfd, len);
912 * line is now NEW up to nse
916 "second diff insert at %d...\r\n", (int)(nse - new)));
917 term_move_to_char(el, (int)(nse - new));
919 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
921 /* insert sx chars of new starting at nse */
922 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
923 "ERROR: cannot insert in second diff\n"));
924 term_insertwrite(el, nse, sx);
927 * write (nls-nse) - sx chars of new starting at
930 term_overwrite(el, (nse + sx),
931 (size_t)((nls - nse) - sx));
933 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
934 term_overwrite(el, nse, (size_t)(nls - nse));
937 * No need to do a clear-to-end here because we were
938 * doing a second insert, so we will have over
939 * written all of the old string.
943 ELRE_DEBUG(1, (__F, "done.\r\n"));
947 /* re__copy_and_pad():
948 * Copy string and pad with spaces
951 re__copy_and_pad(char *dst, const char *src, size_t width)
955 for (i = 0; i < width; i++) {
961 for (; i < width; i++)
968 /* re_refresh_cursor():
969 * Move to the new cursor position
972 re_refresh_cursor(EditLine *el)
977 if (el->el_line.cursor >= el->el_line.lastchar) {
978 if (el->el_map.current == el->el_map.alt
979 && el->el_line.lastchar != el->el_line.buffer)
980 el->el_line.cursor = el->el_line.lastchar - 1;
982 el->el_line.cursor = el->el_line.lastchar;
985 /* first we must find where the cursor is... */
986 h = el->el_prompt.p_pos.h;
987 v = el->el_prompt.p_pos.v;
988 th = el->el_term.t_size.h; /* optimize for speed */
990 /* do input buffer to el->el_line.cursor */
991 for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
995 case '\n': /* handle newline in data part too */
999 case '\t': /* if a tab, to next tab stop */
1004 if (iscntrl((unsigned char) c))
1006 else if (!isprint((unsigned char) c))
1007 h += 4; /* octal \xxx */
1013 if (h >= th) { /* check, extra long tabs picked up here also */
1020 term_move_to_line(el, v);
1021 term_move_to_char(el, h);
1027 * Add a character fast.
1030 re_fastputc(EditLine *el, int c)
1034 el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
1035 if (el->el_cursor.h >= el->el_term.t_size.h) {
1036 /* if we must overflow */
1037 el->el_cursor.h = 0;
1040 * If we would overflow (input is longer than terminal size),
1041 * emulate scroll by dropping first line and shuffling the rest.
1042 * We do this via pointer shuffling - it's safe in this case
1043 * and we avoid memcpy().
1045 if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
1046 int i, lins = el->el_term.t_size.v;
1047 char *firstline = el->el_display[0];
1049 for(i = 1; i < lins; i++)
1050 el->el_display[i - 1] = el->el_display[i];
1052 re__copy_and_pad(firstline, "", 0);
1053 el->el_display[i - 1] = firstline;
1056 el->el_refresh.r_oldcv++;
1058 if (EL_HAS_AUTO_MARGINS) {
1059 if (EL_HAS_MAGIC_MARGINS) {
1060 term__putc(el, ' ');
1061 term__putc(el, '\b');
1064 term__putc(el, '\r');
1065 term__putc(el, '\n');
1072 * we added just one char, handle it fast.
1073 * Assumes that screen cursor == real cursor
1076 re_fastaddc(EditLine *el)
1081 c = (unsigned char)el->el_line.cursor[-1];
1083 if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1084 re_refresh(el); /* too hard to handle */
1087 rhdiff = el->el_term.t_size.h - el->el_cursor.h -
1088 el->el_rprompt.p_pos.h;
1089 if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1090 re_refresh(el); /* clear out rprompt if less than 1 char gap */
1092 } /* else (only do at end of line, no TAB) */
1093 if (iscntrl((unsigned char) c)) { /* if control char, do caret */
1094 char mc = (c == 0177) ? '?' : (toascii(c) | 0100);
1095 re_fastputc(el, '^');
1096 re_fastputc(el, mc);
1097 } else if (isprint((unsigned char) c)) { /* normal char */
1100 re_fastputc(el, '\\');
1101 re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0'));
1102 re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0'));
1103 re_fastputc(el, (c & 7) + '0');
1109 /* re_clear_display():
1110 * clear the screen buffers so that new new prompt starts fresh.
1113 re_clear_display(EditLine *el)
1117 el->el_cursor.v = 0;
1118 el->el_cursor.h = 0;
1119 for (i = 0; i < el->el_term.t_size.v; i++)
1120 el->el_display[i][0] = '\0';
1121 el->el_refresh.r_oldcv = 0;
1125 /* re_clear_lines():
1126 * Make sure all lines are *really* blank
1129 re_clear_lines(EditLine *el)
1134 for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
1135 /* for each line on the screen */
1136 term_move_to_line(el, i);
1137 term_move_to_char(el, 0);
1138 term_clear_EOL(el, el->el_term.t_size.h);
1141 term_move_to_line(el, el->el_refresh.r_oldcv);
1142 /* go to last line */
1143 term__putc(el, '\r'); /* go to BOL */
1144 term__putc(el, '\n'); /* go to new line */