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.27 2005/11/09 22:11:10 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_addc(EditLine *, int);
53 private void re_update_line(EditLine *, char *, char *, int);
54 private void re_insert (EditLine *, char *, int, int, char *, int);
55 private void re_delete(EditLine *, char *, int, int, int);
56 private void re_fastputc(EditLine *, int);
57 private void re_clear_eol(EditLine *, int, int, int);
58 private void re__strncopy(char *, char *, size_t);
59 private void re__copy_and_pad(char *, const char *, size_t);
62 private void re_printstr(EditLine *, const char *, char *, char *);
63 #define __F el->el_errfile
64 #define ELRE_ASSERT(a, b, c) do \
65 if (/*CONSTCOND*/ a) { \
69 while (/*CONSTCOND*/0)
70 #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
73 * Print a string on the debugging pty
76 re_printstr(EditLine *el, const char *str, char *f, char *t)
79 ELRE_DEBUG(1, (__F, "%s:\"", str));
81 ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
82 ELRE_DEBUG(1, (__F, "\"\r\n"));
85 #define ELRE_ASSERT(a, b, c)
86 #define ELRE_DEBUG(a, b)
91 * Draw c, expanding tabs, control chars etc.
94 re_addc(EditLine *el, int c)
101 if (c == '\n') { /* expand the newline */
102 int oldv = el->el_refresh.r_cursor.v;
103 re_putc(el, '\0', 0); /* assure end of line */
104 if (oldv == el->el_refresh.r_cursor.v) { /* XXX */
105 el->el_refresh.r_cursor.h = 0; /* reset cursor pos */
106 el->el_refresh.r_cursor.v++;
110 if (c == '\t') { /* expand the tab */
113 if ((el->el_refresh.r_cursor.h & 07) == 0)
114 break; /* go until tab stop */
116 } else if (iscntrl(c)) {
121 /* uncontrolify it; works only for iso8859-1 like sets */
122 re_putc(el, (toascii(c) | 0100), 1);
124 re_putc(el, '\\', 1);
125 re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
126 re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
127 re_putc(el, (c & 07) + '0', 1);
133 * Draw the character given
136 re_putc(EditLine *el, int c, int shift)
139 ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
141 el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
145 el->el_refresh.r_cursor.h++; /* advance to next place */
146 if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
147 el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0';
148 /* assure end of line */
149 el->el_refresh.r_cursor.h = 0; /* reset it. */
152 * If we would overflow (input is longer than terminal size),
153 * emulate scroll by dropping first line and shuffling the rest.
154 * We do this via pointer shuffling - it's safe in this case
155 * and we avoid memcpy().
157 if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
158 int i, lins = el->el_term.t_size.v;
159 char *firstline = el->el_vdisplay[0];
161 for(i=1; i < lins; i++)
162 el->el_vdisplay[i-1] = el->el_vdisplay[i];
164 firstline[0] = '\0'; /* empty the string */
165 el->el_vdisplay[i-1] = firstline;
167 el->el_refresh.r_cursor.v++;
169 ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
170 (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
171 el->el_refresh.r_cursor.v, el->el_term.t_size.v),
178 * draws the new virtual screen image from the current input
179 * line, then goes line-by-line changing the real image to the new
180 * virtual image. The routine to re-draw a line can be replaced
181 * easily in hopes of a smarter one being placed there.
184 re_refresh(EditLine *el)
193 ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
194 el->el_line.buffer));
196 /* reset the Drawing cursor */
197 el->el_refresh.r_cursor.h = 0;
198 el->el_refresh.r_cursor.v = 0;
200 /* temporarily draw rprompt to calculate its size */
201 prompt_print(el, EL_RPROMPT);
203 /* reset the Drawing cursor */
204 el->el_refresh.r_cursor.h = 0;
205 el->el_refresh.r_cursor.v = 0;
207 if (el->el_line.cursor >= el->el_line.lastchar) {
208 if (el->el_map.current == el->el_map.alt
209 && el->el_line.lastchar != el->el_line.buffer)
210 el->el_line.cursor = el->el_line.lastchar - 1;
212 el->el_line.cursor = el->el_line.lastchar;
215 cur.h = -1; /* set flag in case I'm not set */
218 prompt_print(el, EL_PROMPT);
220 /* draw the current input buffer */
222 termsz = el->el_term.t_size.h * el->el_term.t_size.v;
223 if (el->el_line.lastchar - el->el_line.buffer > termsz) {
225 * If line is longer than terminal, process only part
226 * of line which would influence display.
228 size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
230 st = el->el_line.lastchar - rem
231 - (termsz - (((rem / el->el_term.t_size.v) - 1)
232 * el->el_term.t_size.v));
235 st = el->el_line.buffer;
237 for (cp = st; cp < el->el_line.lastchar; cp++) {
238 if (cp == el->el_line.cursor) {
240 cur.h = el->el_refresh.r_cursor.h;
241 cur.v = el->el_refresh.r_cursor.v;
243 re_addc(el, (unsigned char) *cp);
246 if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
247 cur.h = el->el_refresh.r_cursor.h;
248 cur.v = el->el_refresh.r_cursor.v;
250 rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
251 el->el_rprompt.p_pos.h;
252 if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
253 !el->el_refresh.r_cursor.v && rhdiff > 1) {
255 * have a right-hand side prompt that will fit
256 * on the end of the first line with at least
257 * one character gap to the input buffer.
259 while (--rhdiff > 0) /* pad out with spaces */
261 prompt_print(el, EL_RPROMPT);
263 el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
264 el->el_rprompt.p_pos.v = 0;
267 re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
269 el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
272 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
273 el->el_term.t_size.h, el->el_refresh.r_cursor.h,
274 el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
276 ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
277 for (i = 0; i <= el->el_refresh.r_newcv; i++) {
278 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
279 re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
282 * Copy the new line to be the current one, and pad out with
283 * spaces to the full width of the terminal so that if we try
284 * moving the cursor by writing the character that is at the
285 * end of the screen line, it won't be a NUL or some old
288 re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
289 (size_t) el->el_term.t_size.h);
292 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
293 el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
295 if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
296 for (; i <= el->el_refresh.r_oldcv; i++) {
297 term_move_to_line(el, i);
298 term_move_to_char(el, 0);
299 term_clear_EOL(el, (int) strlen(el->el_display[i]));
301 term_overwrite(el, "C\b", 2);
302 #endif /* DEBUG_REFRESH */
303 el->el_display[i][0] = '\0';
306 el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
308 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
309 el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
311 term_move_to_line(el, cur.v); /* go to where the cursor is */
312 term_move_to_char(el, cur.h);
317 * used to go to last used screen line
320 re_goto_bottom(EditLine *el)
323 term_move_to_line(el, el->el_refresh.r_oldcv);
325 re_clear_display(el);
331 * insert num characters of s into d (in front of the character)
332 * at dat, maximum length of d is dlen
336 re_insert(EditLine *el __unused,
337 char *d, int dat, int dlen, char *s, int num)
343 if (num > dlen - dat)
347 (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
349 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
351 /* open up the space for num chars */
357 d[dlen] = '\0'; /* just in case */
360 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
362 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
364 /* copy the characters */
365 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
369 (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
370 num, dat, dlen, d, s));
371 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
376 * delete num characters d at dat, maximum length of d is dlen
380 re_delete(EditLine *el __unused,
381 char *d, int dat, int dlen, int num)
387 if (dat + num >= dlen) {
392 (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
395 /* open up the space for num chars */
401 d[dlen] = '\0'; /* just in case */
404 (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
410 * Like strncpy without padding.
413 re__strncopy(char *a, char *b, size_t n)
421 * Find the number of characters we need to clear till the end of line
422 * in order to make sure that we have cleared the previous contents of
423 * the line. fx and sx is the number of characters inserted or deleted
424 * int the first or second diff, diff is the difference between the
425 * number of characters between the new and old line.
428 re_clear_eol(EditLine *el, int fx, int sx, int diff)
431 ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
443 ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
444 term_clear_EOL(el, diff);
447 /*****************************************************************
448 re_update_line() is based on finding the middle difference of each line
451 /old first difference
452 /beginning of line | /old last same /old EOL
454 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
455 new: eddie> Oh, my little buggy says to me, as lurgid as
457 \beginning of line | \new last same \new end of line
458 \new first difference
460 all are character pointers for the sake of speed. Special cases for
461 no differences, as well as for end of line additions must be handled.
462 **************************************************************** */
464 /* Minimum at which doing an insert it "worth it". This should be about
465 * half the "cost" of going into insert mode, inserting a character, and
466 * going back out. This should really be calculated from the termcap
467 * data... For the moment, a good number for ANSI terminals.
469 #define MIN_END_KEEP 4
472 re_update_line(EditLine *el, char *old, char *new, int i)
475 char *ofd, *ols, *oe, *nfd, *nls, *ne;
476 char *osb, *ose, *nsb, *nse;
482 for (o = old, n = new; *o && (*o == *n); o++, n++)
488 * Find the end of both old and new
493 * Remove any trailing blanks off of the end, being careful not to
494 * back up past the beginning.
507 /* remove blanks from end of new */
517 * if no diff, continue to next line of redraw
519 if (*ofd == '\0' && *nfd == '\0') {
520 ELRE_DEBUG(1, (__F, "no difference.\r\n"));
524 * find last same pointer
526 while ((o > ofd) && (n > nfd) && (*--o == *--n))
532 * find same begining and same end
540 * case 1: insert: scan from nfd to nls looking for *ofd
543 for (c = *ofd, n = nfd; n < nls; n++) {
546 p < nls && o < ols && *o == *p;
550 * if the new match is longer and it's worth
551 * keeping, then we take it
553 if (((nse - nsb) < (p - n)) &&
554 (2 * (p - n) > n - nfd)) {
564 * case 2: delete: scan from ofd to ols looking for *nfd
567 for (c = *nfd, o = ofd; o < ols; o++) {
570 p < ols && n < nls && *p == *n;
574 * if the new match is longer and it's worth
575 * keeping, then we take it
577 if (((ose - osb) < (p - o)) &&
578 (2 * (p - o) > o - ofd)) {
588 * Pragmatics I: If old trailing whitespace or not enough characters to
589 * save to be worth it, then don't save the last same info.
591 if ((oe - ols) < MIN_END_KEEP) {
596 * Pragmatics II: if the terminal isn't smart enough, make the data
597 * dumber so the smart update doesn't try anything fancy
601 * fx is the number of characters we need to insert/delete: in the
602 * beginning to bring the two same begins together
604 fx = (nsb - nfd) - (osb - ofd);
606 * sx is the number of characters we need to insert/delete: in the
607 * end to bring the two same last parts together
609 sx = (nls - nse) - (ols - ose);
611 if (!EL_CAN_INSERT) {
622 if ((ols - ofd) < (nls - nfd)) {
627 if (!EL_CAN_DELETE) {
638 if ((ols - ofd) > (nls - nfd)) {
644 * Pragmatics III: make sure the middle shifted pointers are correct if
645 * they don't point to anything (we may have moved ols or nls).
647 /* if the change isn't worth it, don't bother */
648 /* was: if (osb == ose) */
649 if ((ose - osb) < MIN_END_KEEP) {
656 * Now that we are done with pragmatics we recompute fx, sx
658 fx = (nsb - nfd) - (osb - ofd);
659 sx = (nls - nse) - (ols - ose);
661 ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
662 ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
663 ofd - old, osb - old, ose - old, ols - old, oe - old));
664 ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
665 nfd - new, nsb - new, nse - new, nls - new, ne - new));
667 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
669 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
671 re_printstr(el, "old- oe", old, oe);
672 re_printstr(el, "new- ne", new, ne);
673 re_printstr(el, "old-ofd", old, ofd);
674 re_printstr(el, "new-nfd", new, nfd);
675 re_printstr(el, "ofd-osb", ofd, osb);
676 re_printstr(el, "nfd-nsb", nfd, nsb);
677 re_printstr(el, "osb-ose", osb, ose);
678 re_printstr(el, "nsb-nse", nsb, nse);
679 re_printstr(el, "ose-ols", ose, ols);
680 re_printstr(el, "nse-nls", nse, nls);
681 re_printstr(el, "ols- oe", ols, oe);
682 re_printstr(el, "nls- ne", nls, ne);
683 #endif /* DEBUG_REFRESH */
686 * el_cursor.v to this line i MUST be in this routine so that if we
687 * don't have to change the line, we don't move to it. el_cursor.h to
690 term_move_to_line(el, i);
693 * at this point we have something like this:
695 * /old /ofd /osb /ose /ols /oe
696 * v.....................v v..................v v........v
697 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
698 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
699 * ^.....................^ ^..................^ ^........^
700 * \new \nfd \nsb \nse \nls \ne
702 * fx is the difference in length between the chars between nfd and
703 * nsb, and the chars between ofd and osb, and is thus the number of
704 * characters to delete if < 0 (new is shorter than old, as above),
705 * or insert (new is longer than short).
707 * sx is the same for the second differences.
711 * if we have a net insert on the first difference, AND inserting the
712 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
713 * character (which is ne if nls != ne, otherwise is nse) off the edge
714 * of the screen (el->el_term.t_size.h) else we do the deletes first
715 * so that we keep everything we need to.
719 * if the last same is the same like the end, there is no last same
720 * part, otherwise we want to keep the last same part set p to the
721 * last useful old character
723 p = (ols != oe) ? oe : ose;
726 * if (There is a diffence in the beginning) && (we need to insert
727 * characters) && (the number of characters to insert is less than
729 * We need to do an insert!
730 * else if (we need to delete characters)
731 * We need to delete characters!
733 * No insert or delete
735 if ((nsb != nfd) && fx > 0 &&
736 ((p - old) + fx <= el->el_term.t_size.h)) {
738 (__F, "first diff insert at %d...\r\n", nfd - new));
740 * Move to the first char to insert, where the first diff is.
742 term_move_to_char(el, nfd - new);
744 * Check if we have stuff to keep at end
747 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
749 * insert fx chars of new starting at nfd
752 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
753 "ERROR: cannot insert in early first diff\n"));
754 term_insertwrite(el, nfd, fx);
755 re_insert(el, old, ofd - old,
756 el->el_term.t_size.h, nfd, fx);
759 * write (nsb-nfd) - fx chars of new starting at
762 term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
763 re__strncopy(ofd + fx, nfd + fx,
764 (size_t) ((nsb - nfd) - fx));
766 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
767 term_overwrite(el, nfd, (nsb - nfd));
768 re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
776 (__F, "first diff delete at %d...\r\n", ofd - old));
778 * move to the first char to delete where the first diff is
780 term_move_to_char(el, ofd - old);
782 * Check if we have stuff to save
785 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
787 * fx is less than zero *always* here but we check
791 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
792 "ERROR: cannot delete in first diff\n"));
793 term_deletechars(el, -fx);
794 re_delete(el, old, ofd - old,
795 el->el_term.t_size.h, -fx);
798 * write (nsb-nfd) chars of new starting at nfd
800 term_overwrite(el, nfd, (nsb - nfd));
801 re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
805 "but with nothing left to save\r\n"));
807 * write (nsb-nfd) chars of new starting at nfd
809 term_overwrite(el, nfd, (nsb - nfd));
810 re_clear_eol(el, fx, sx, (oe - old) - (ne - new));
819 if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
821 "second diff delete at %d...\r\n", (ose - old) + fx));
823 * Check if we have stuff to delete
826 * fx is the number of characters inserted (+) or deleted (-)
829 term_move_to_char(el, (ose - old) + fx);
831 * Check if we have stuff to save
834 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
836 * Again a duplicate test.
839 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
840 "ERROR: cannot delete in second diff\n"));
841 term_deletechars(el, -sx);
844 * write (nls-nse) chars of new starting at nse
846 term_overwrite(el, nse, (nls - nse));
849 "but with nothing left to save\r\n"));
850 term_overwrite(el, nse, (nls - nse));
851 re_clear_eol(el, fx, sx, (oe - old) - (ne - new));
855 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
857 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
858 ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
861 term_move_to_char(el, nfd - new);
863 * Check if we have stuff to keep at the end
866 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
868 * We have to recalculate fx here because we set it
869 * to zero above as a flag saying that we hadn't done
870 * an early first insert.
872 fx = (nsb - nfd) - (osb - ofd);
875 * insert fx chars of new starting at nfd
877 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
878 "ERROR: cannot insert in late first diff\n"));
879 term_insertwrite(el, nfd, fx);
880 re_insert(el, old, ofd - old,
881 el->el_term.t_size.h, nfd, fx);
884 * write (nsb-nfd) - fx chars of new starting at
887 term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
888 re__strncopy(ofd + fx, nfd + fx,
889 (size_t) ((nsb - nfd) - fx));
891 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
892 term_overwrite(el, nfd, (nsb - nfd));
893 re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
897 * line is now NEW up to nse
901 "second diff insert at %d...\r\n", nse - new));
902 term_move_to_char(el, nse - new);
904 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
906 /* insert sx chars of new starting at nse */
907 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
908 "ERROR: cannot insert in second diff\n"));
909 term_insertwrite(el, nse, sx);
912 * write (nls-nse) - sx chars of new starting at
915 term_overwrite(el, nse + sx, (nls - nse) - sx);
917 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
918 term_overwrite(el, nse, (nls - nse));
921 * No need to do a clear-to-end here because we were
922 * doing a second insert, so we will have over
923 * written all of the old string.
927 ELRE_DEBUG(1, (__F, "done.\r\n"));
931 /* re__copy_and_pad():
932 * Copy string and pad with spaces
935 re__copy_and_pad(char *dst, const char *src, size_t width)
939 for (i = 0; i < width; i++) {
945 for (; i < width; i++)
952 /* re_refresh_cursor():
953 * Move to the new cursor position
956 re_refresh_cursor(EditLine *el)
961 if (el->el_line.cursor >= el->el_line.lastchar) {
962 if (el->el_map.current == el->el_map.alt
963 && el->el_line.lastchar != el->el_line.buffer)
964 el->el_line.cursor = el->el_line.lastchar - 1;
966 el->el_line.cursor = el->el_line.lastchar;
969 /* first we must find where the cursor is... */
970 h = el->el_prompt.p_pos.h;
971 v = el->el_prompt.p_pos.v;
972 th = el->el_term.t_size.h; /* optimize for speed */
974 /* do input buffer to el->el_line.cursor */
975 for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
977 h++; /* all chars at least this long */
979 if (c == '\n') {/* handle newline in data part too */
983 if (c == '\t') { /* if a tab, to next tab stop */
987 } else if (iscntrl((unsigned char) c)) {
988 /* if control char */
990 if (h > th) { /* if overflow, compensate */
994 } else if (!isprint((unsigned char) c)) {
996 if (h > th) { /* if overflow, compensate */
1003 if (h >= th) { /* check, extra long tabs picked up here also */
1010 term_move_to_line(el, v);
1011 term_move_to_char(el, h);
1017 * Add a character fast.
1020 re_fastputc(EditLine *el, int c)
1024 el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
1025 if (el->el_cursor.h >= el->el_term.t_size.h) {
1026 /* if we must overflow */
1027 el->el_cursor.h = 0;
1030 * If we would overflow (input is longer than terminal size),
1031 * emulate scroll by dropping first line and shuffling the rest.
1032 * We do this via pointer shuffling - it's safe in this case
1033 * and we avoid memcpy().
1035 if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
1036 int i, lins = el->el_term.t_size.v;
1037 char *firstline = el->el_display[0];
1039 for(i=1; i < lins; i++)
1040 el->el_display[i-1] = el->el_display[i];
1042 re__copy_and_pad(firstline, "", 0);
1043 el->el_display[i-1] = firstline;
1046 el->el_refresh.r_oldcv++;
1048 if (EL_HAS_AUTO_MARGINS) {
1049 if (EL_HAS_MAGIC_MARGINS) {
1062 * we added just one char, handle it fast.
1063 * Assumes that screen cursor == real cursor
1066 re_fastaddc(EditLine *el)
1071 c = (unsigned char)el->el_line.cursor[-1];
1073 if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1074 re_refresh(el); /* too hard to handle */
1077 rhdiff = el->el_term.t_size.h - el->el_cursor.h -
1078 el->el_rprompt.p_pos.h;
1079 if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1080 re_refresh(el); /* clear out rprompt if less than 1 char gap */
1082 } /* else (only do at end of line, no TAB) */
1083 if (iscntrl((unsigned char) c)) { /* if control char, do caret */
1084 char mc = (c == 0177) ? '?' : (toascii(c) | 0100);
1085 re_fastputc(el, '^');
1086 re_fastputc(el, mc);
1087 } else if (isprint((unsigned char) c)) { /* normal char */
1090 re_fastputc(el, '\\');
1091 re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0'));
1092 re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0'));
1093 re_fastputc(el, (c & 7) + '0');
1099 /* re_clear_display():
1100 * clear the screen buffers so that new new prompt starts fresh.
1103 re_clear_display(EditLine *el)
1107 el->el_cursor.v = 0;
1108 el->el_cursor.h = 0;
1109 for (i = 0; i < el->el_term.t_size.v; i++)
1110 el->el_display[i][0] = '\0';
1111 el->el_refresh.r_oldcv = 0;
1115 /* re_clear_lines():
1116 * Make sure all lines are *really* blank
1119 re_clear_lines(EditLine *el)
1124 term_move_to_char(el, 0);
1125 for (i = 0; i <= el->el_refresh.r_oldcv; i++) {
1126 /* for each line on the screen */
1127 term_move_to_line(el, i);
1128 term_clear_EOL(el, el->el_term.t_size.h);
1130 term_move_to_line(el, 0);
1132 term_move_to_line(el, el->el_refresh.r_oldcv);
1133 /* go to last line */
1134 term__putc('\r'); /* go to BOL */
1135 term__putc('\n'); /* go to new line */