1 /* $NetBSD: refresh.c,v 1.37 2011/07/29 23:44:45 christos Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
36 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93";
40 __RCSID("$NetBSD: refresh.c,v 1.37 2011/07/29 23:44:45 christos Exp $");
42 #endif /* not lint && not SCCSID */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
47 * refresh.c: Lower level screen refreshing functions
56 private void re_nextline(EditLine *);
57 private void re_addc(EditLine *, Int);
58 private void re_update_line(EditLine *, Char *, Char *, int);
59 private void re_insert (EditLine *, Char *, int, int, Char *, int);
60 private void re_delete(EditLine *, Char *, int, int, int);
61 private void re_fastputc(EditLine *, Int);
62 private void re_clear_eol(EditLine *, int, int, int);
63 private void re__strncopy(Char *, Char *, size_t);
64 private void re__copy_and_pad(Char *, const Char *, size_t);
67 private void re_printstr(EditLine *, const char *, char *, char *);
68 #define __F el->el_errfile
69 #define ELRE_ASSERT(a, b, c) do \
70 if (/*CONSTCOND*/ a) { \
74 while (/*CONSTCOND*/0)
75 #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
78 * Print a string on the debugging pty
81 re_printstr(EditLine *el, const char *str, char *f, char *t)
84 ELRE_DEBUG(1, (__F, "%s:\"", str));
86 ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
87 ELRE_DEBUG(1, (__F, "\"\r\n"));
90 #define ELRE_ASSERT(a, b, c)
91 #define ELRE_DEBUG(a, b)
95 * Move to the next line or scroll
98 re_nextline(EditLine *el)
100 el->el_refresh.r_cursor.h = 0; /* reset it. */
103 * If we would overflow (input is longer than terminal size),
104 * emulate scroll by dropping first line and shuffling the rest.
105 * We do this via pointer shuffling - it's safe in this case
106 * and we avoid memcpy().
108 if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) {
109 int i, lins = el->el_terminal.t_size.v;
110 Char *firstline = el->el_vdisplay[0];
112 for(i = 1; i < lins; i++)
113 el->el_vdisplay[i - 1] = el->el_vdisplay[i];
115 firstline[0] = '\0'; /* empty the string */
116 el->el_vdisplay[i - 1] = firstline;
118 el->el_refresh.r_cursor.v++;
120 ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v,
121 (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
122 el->el_refresh.r_cursor.v, el->el_terminal.t_size.v),
127 * Draw c, expanding tabs, control chars etc.
130 re_addc(EditLine *el, Int c)
132 switch (ct_chr_class((Char)c)) {
133 case CHTYPE_TAB: /* expand the tab */
136 if ((el->el_refresh.r_cursor.h & 07) == 0)
137 break; /* go until tab stop */
141 int oldv = el->el_refresh.r_cursor.v;
142 re_putc(el, '\0', 0); /* assure end of line */
143 if (oldv == el->el_refresh.r_cursor.v) /* XXX */
151 Char visbuf[VISUAL_WIDTH_MAX];
153 ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c);
154 for (i = 0; n-- > 0; ++i)
155 re_putc(el, visbuf[i], 1);
163 * Draw the character given
166 re_putc(EditLine *el, Int c, int shift)
169 ELRE_DEBUG(1, (__F, "printing %5x '%c'\r\n", c, c));
171 while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h))
174 el->el_vdisplay[el->el_refresh.r_cursor.v]
175 [el->el_refresh.r_cursor.h] = c;
176 /* assumes !shift is only used for single-column chars */
179 el->el_vdisplay[el->el_refresh.r_cursor.v]
180 [el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR;
185 el->el_refresh.r_cursor.h += w; /* advance to next place */
186 if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) {
187 /* assure end of line */
188 el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h]
196 * draws the new virtual screen image from the current input
197 * line, then goes line-by-line changing the real image to the new
198 * virtual image. The routine to re-draw a line can be replaced
199 * easily in hopes of a smarter one being placed there.
202 re_refresh(EditLine *el)
211 ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
212 el->el_line.buffer));
214 /* reset the Drawing cursor */
215 el->el_refresh.r_cursor.h = 0;
216 el->el_refresh.r_cursor.v = 0;
218 /* temporarily draw rprompt to calculate its size */
219 prompt_print(el, EL_RPROMPT);
221 /* reset the Drawing cursor */
222 el->el_refresh.r_cursor.h = 0;
223 el->el_refresh.r_cursor.v = 0;
225 if (el->el_line.cursor >= el->el_line.lastchar) {
226 if (el->el_map.current == el->el_map.alt
227 && el->el_line.lastchar != el->el_line.buffer)
228 el->el_line.cursor = el->el_line.lastchar - 1;
230 el->el_line.cursor = el->el_line.lastchar;
233 cur.h = -1; /* set flag in case I'm not set */
236 prompt_print(el, EL_PROMPT);
238 /* draw the current input buffer */
240 termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v;
241 if (el->el_line.lastchar - el->el_line.buffer > termsz) {
243 * If line is longer than terminal, process only part
244 * of line which would influence display.
246 size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
248 st = el->el_line.lastchar - rem
249 - (termsz - (((rem / el->el_terminal.t_size.v) - 1)
250 * el->el_terminal.t_size.v));
253 st = el->el_line.buffer;
255 for (cp = st; cp < el->el_line.lastchar; cp++) {
256 if (cp == el->el_line.cursor) {
259 cur.h = el->el_refresh.r_cursor.h;
260 cur.v = el->el_refresh.r_cursor.v;
261 /* handle being at a linebroken doublewidth char */
262 if (w > 1 && el->el_refresh.r_cursor.h + w >
263 el->el_terminal.t_size.h) {
271 if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
272 cur.h = el->el_refresh.r_cursor.h;
273 cur.v = el->el_refresh.r_cursor.v;
275 rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h -
276 el->el_rprompt.p_pos.h;
277 if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
278 !el->el_refresh.r_cursor.v && rhdiff > 1) {
280 * have a right-hand side prompt that will fit
281 * on the end of the first line with at least
282 * one character gap to the input buffer.
284 while (--rhdiff > 0) /* pad out with spaces */
286 prompt_print(el, EL_RPROMPT);
288 el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
289 el->el_rprompt.p_pos.v = 0;
292 re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
294 el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
297 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
298 el->el_terminal.t_size.h, el->el_refresh.r_cursor.h,
299 el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0])));
301 ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
302 for (i = 0; i <= el->el_refresh.r_newcv; i++) {
303 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
304 re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
307 * Copy the new line to be the current one, and pad out with
308 * spaces to the full width of the terminal so that if we try
309 * moving the cursor by writing the character that is at the
310 * end of the screen line, it won't be a NUL or some old
313 re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
314 (size_t) el->el_terminal.t_size.h);
317 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
318 el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
320 if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
321 for (; i <= el->el_refresh.r_oldcv; i++) {
322 terminal_move_to_line(el, i);
323 terminal_move_to_char(el, 0);
324 /* This Strlen should be safe even with MB_FILL_CHARs */
325 terminal_clear_EOL(el, (int) Strlen(el->el_display[i]));
327 terminal_overwrite(el, "C\b", (size_t)2);
328 #endif /* DEBUG_REFRESH */
329 el->el_display[i][0] = '\0';
332 el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
334 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
335 el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
337 terminal_move_to_line(el, cur.v); /* go to where the cursor is */
338 terminal_move_to_char(el, cur.h);
343 * used to go to last used screen line
346 re_goto_bottom(EditLine *el)
349 terminal_move_to_line(el, el->el_refresh.r_oldcv);
350 terminal__putc(el, '\n');
351 re_clear_display(el);
357 * insert num characters of s into d (in front of the character)
358 * at dat, maximum length of d is dlen
362 re_insert(EditLine *el __attribute__((__unused__)),
363 Char *d, int dat, int dlen, Char *s, int num)
369 if (num > dlen - dat)
373 (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
374 num, dat, dlen, ct_encode_string(d)));
375 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s)));
377 /* open up the space for num chars */
383 d[dlen] = '\0'; /* just in case */
387 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
388 num, dat, dlen, ct_encode_string(d)));
389 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s)));
391 /* copy the characters */
392 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
396 /* ct_encode_string() uses a static buffer, so we can't conveniently
397 * encode both d & s here */
399 (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
400 num, dat, dlen, d, s));
401 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
407 * delete num characters d at dat, maximum length of d is dlen
411 re_delete(EditLine *el __attribute__((__unused__)),
412 Char *d, int dat, int dlen, int num)
418 if (dat + num >= dlen) {
423 (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
424 num, dat, dlen, ct_encode_string(d)));
426 /* open up the space for num chars */
432 d[dlen] = '\0'; /* just in case */
435 (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
436 num, dat, dlen, ct_encode_string(d)));
441 * Like strncpy without padding.
444 re__strncopy(Char *a, Char *b, size_t n)
452 * Find the number of characters we need to clear till the end of line
453 * in order to make sure that we have cleared the previous contents of
454 * the line. fx and sx is the number of characters inserted or deleted
455 * in the first or second diff, diff is the difference between the
456 * number of characters between the new and old line.
459 re_clear_eol(EditLine *el, int fx, int sx, int diff)
462 ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
474 ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
475 terminal_clear_EOL(el, diff);
478 /*****************************************************************
479 re_update_line() is based on finding the middle difference of each line
482 /old first difference
483 /beginning of line | /old last same /old EOL
485 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
486 new: eddie> Oh, my little buggy says to me, as lurgid as
488 \beginning of line | \new last same \new end of line
489 \new first difference
491 all are character pointers for the sake of speed. Special cases for
492 no differences, as well as for end of line additions must be handled.
493 **************************************************************** */
495 /* Minimum at which doing an insert it "worth it". This should be about
496 * half the "cost" of going into insert mode, inserting a character, and
497 * going back out. This should really be calculated from the termcap
498 * data... For the moment, a good number for ANSI terminals.
500 #define MIN_END_KEEP 4
503 re_update_line(EditLine *el, Char *old, Char *new, int i)
506 Char *ofd, *ols, *oe, *nfd, *nls, *ne;
507 Char *osb, *ose, *nsb, *nse;
514 for (o = old, n = new; *o && (*o == *n); o++, n++)
520 * Find the end of both old and new
525 * Remove any trailing blanks off of the end, being careful not to
526 * back up past the beginning.
539 /* remove blanks from end of new */
549 * if no diff, continue to next line of redraw
551 if (*ofd == '\0' && *nfd == '\0') {
552 ELRE_DEBUG(1, (__F, "no difference.\r\n"));
556 * find last same pointer
558 while ((o > ofd) && (n > nfd) && (*--o == *--n))
564 * find same beginning and same end
572 * case 1: insert: scan from nfd to nls looking for *ofd
575 for (c = *ofd, n = nfd; n < nls; n++) {
578 p < nls && o < ols && *o == *p;
582 * if the new match is longer and it's worth
583 * keeping, then we take it
585 if (((nse - nsb) < (p - n)) &&
586 (2 * (p - n) > n - nfd)) {
596 * case 2: delete: scan from ofd to ols looking for *nfd
599 for (c = *nfd, o = ofd; o < ols; o++) {
602 p < ols && n < nls && *p == *n;
606 * if the new match is longer and it's worth
607 * keeping, then we take it
609 if (((ose - osb) < (p - o)) &&
610 (2 * (p - o) > o - ofd)) {
620 * Pragmatics I: If old trailing whitespace or not enough characters to
621 * save to be worth it, then don't save the last same info.
623 if ((oe - ols) < MIN_END_KEEP) {
628 * Pragmatics II: if the terminal isn't smart enough, make the data
629 * dumber so the smart update doesn't try anything fancy
633 * fx is the number of characters we need to insert/delete: in the
634 * beginning to bring the two same begins together
636 fx = (int)((nsb - nfd) - (osb - ofd));
638 * sx is the number of characters we need to insert/delete: in the
639 * end to bring the two same last parts together
641 sx = (int)((nls - nse) - (ols - ose));
643 if (!EL_CAN_INSERT) {
654 if ((ols - ofd) < (nls - nfd)) {
659 if (!EL_CAN_DELETE) {
670 if ((ols - ofd) > (nls - nfd)) {
676 * Pragmatics III: make sure the middle shifted pointers are correct if
677 * they don't point to anything (we may have moved ols or nls).
679 /* if the change isn't worth it, don't bother */
680 /* was: if (osb == ose) */
681 if ((ose - osb) < MIN_END_KEEP) {
688 * Now that we are done with pragmatics we recompute fx, sx
690 fx = (int)((nsb - nfd) - (osb - ofd));
691 sx = (int)((nls - nse) - (ols - ose));
693 ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
694 ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
695 ofd - old, osb - old, ose - old, ols - old, oe - old));
696 ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
697 nfd - new, nsb - new, nse - new, nls - new, ne - new));
699 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
701 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
703 re_printstr(el, "old- oe", old, oe);
704 re_printstr(el, "new- ne", new, ne);
705 re_printstr(el, "old-ofd", old, ofd);
706 re_printstr(el, "new-nfd", new, nfd);
707 re_printstr(el, "ofd-osb", ofd, osb);
708 re_printstr(el, "nfd-nsb", nfd, nsb);
709 re_printstr(el, "osb-ose", osb, ose);
710 re_printstr(el, "nsb-nse", nsb, nse);
711 re_printstr(el, "ose-ols", ose, ols);
712 re_printstr(el, "nse-nls", nse, nls);
713 re_printstr(el, "ols- oe", ols, oe);
714 re_printstr(el, "nls- ne", nls, ne);
715 #endif /* DEBUG_REFRESH */
718 * el_cursor.v to this line i MUST be in this routine so that if we
719 * don't have to change the line, we don't move to it. el_cursor.h to
722 terminal_move_to_line(el, i);
725 * at this point we have something like this:
727 * /old /ofd /osb /ose /ols /oe
728 * v.....................v v..................v v........v
729 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
730 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
731 * ^.....................^ ^..................^ ^........^
732 * \new \nfd \nsb \nse \nls \ne
734 * fx is the difference in length between the chars between nfd and
735 * nsb, and the chars between ofd and osb, and is thus the number of
736 * characters to delete if < 0 (new is shorter than old, as above),
737 * or insert (new is longer than short).
739 * sx is the same for the second differences.
743 * if we have a net insert on the first difference, AND inserting the
744 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
745 * character (which is ne if nls != ne, otherwise is nse) off the edge
746 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
747 * so that we keep everything we need to.
751 * if the last same is the same like the end, there is no last same
752 * part, otherwise we want to keep the last same part set p to the
753 * last useful old character
755 p = (ols != oe) ? oe : ose;
758 * if (There is a diffence in the beginning) && (we need to insert
759 * characters) && (the number of characters to insert is less than
761 * We need to do an insert!
762 * else if (we need to delete characters)
763 * We need to delete characters!
765 * No insert or delete
767 if ((nsb != nfd) && fx > 0 &&
768 ((p - old) + fx <= el->el_terminal.t_size.h)) {
770 (__F, "first diff insert at %d...\r\n", nfd - new));
772 * Move to the first char to insert, where the first diff is.
774 terminal_move_to_char(el, (int)(nfd - new));
776 * Check if we have stuff to keep at end
779 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
781 * insert fx chars of new starting at nfd
784 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
785 "ERROR: cannot insert in early first diff\n"));
786 terminal_insertwrite(el, nfd, fx);
787 re_insert(el, old, (int)(ofd - old),
788 el->el_terminal.t_size.h, nfd, fx);
791 * write (nsb-nfd) - fx chars of new starting at
794 len = (size_t) ((nsb - nfd) - fx);
795 terminal_overwrite(el, (nfd + fx), len);
796 re__strncopy(ofd + fx, nfd + fx, len);
798 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
799 len = (size_t)(nsb - nfd);
800 terminal_overwrite(el, nfd, len);
801 re__strncopy(ofd, nfd, len);
809 (__F, "first diff delete at %d...\r\n", ofd - old));
811 * move to the first char to delete where the first diff is
813 terminal_move_to_char(el, (int)(ofd - old));
815 * Check if we have stuff to save
818 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
820 * fx is less than zero *always* here but we check
824 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
825 "ERROR: cannot delete in first diff\n"));
826 terminal_deletechars(el, -fx);
827 re_delete(el, old, (int)(ofd - old),
828 el->el_terminal.t_size.h, -fx);
831 * write (nsb-nfd) chars of new starting at nfd
833 len = (size_t) (nsb - nfd);
834 terminal_overwrite(el, nfd, len);
835 re__strncopy(ofd, nfd, len);
839 "but with nothing left to save\r\n"));
841 * write (nsb-nfd) chars of new starting at nfd
843 terminal_overwrite(el, nfd, (size_t)(nsb - nfd));
844 re_clear_eol(el, fx, sx,
845 (int)((oe - old) - (ne - new)));
854 if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) {
856 "second diff delete at %d...\r\n", (ose - old) + fx));
858 * Check if we have stuff to delete
861 * fx is the number of characters inserted (+) or deleted (-)
864 terminal_move_to_char(el, (int)((ose - old) + fx));
866 * Check if we have stuff to save
869 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
871 * Again a duplicate test.
874 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
875 "ERROR: cannot delete in second diff\n"));
876 terminal_deletechars(el, -sx);
879 * write (nls-nse) chars of new starting at nse
881 terminal_overwrite(el, nse, (size_t)(nls - nse));
884 "but with nothing left to save\r\n"));
885 terminal_overwrite(el, nse, (size_t)(nls - nse));
886 re_clear_eol(el, fx, sx,
887 (int)((oe - old) - (ne - new)));
891 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
893 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
894 ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
897 terminal_move_to_char(el, (int)(nfd - new));
899 * Check if we have stuff to keep at the end
902 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
904 * We have to recalculate fx here because we set it
905 * to zero above as a flag saying that we hadn't done
906 * an early first insert.
908 fx = (int)((nsb - nfd) - (osb - ofd));
911 * insert fx chars of new starting at nfd
913 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
914 "ERROR: cannot insert in late first diff\n"));
915 terminal_insertwrite(el, nfd, fx);
916 re_insert(el, old, (int)(ofd - old),
917 el->el_terminal.t_size.h, nfd, fx);
920 * write (nsb-nfd) - fx chars of new starting at
923 len = (size_t) ((nsb - nfd) - fx);
924 terminal_overwrite(el, (nfd + fx), len);
925 re__strncopy(ofd + fx, nfd + fx, len);
927 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
928 len = (size_t) (nsb - nfd);
929 terminal_overwrite(el, nfd, len);
930 re__strncopy(ofd, nfd, len);
934 * line is now NEW up to nse
938 "second diff insert at %d...\r\n", (int)(nse - new)));
939 terminal_move_to_char(el, (int)(nse - new));
941 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
943 /* insert sx chars of new starting at nse */
944 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
945 "ERROR: cannot insert in second diff\n"));
946 terminal_insertwrite(el, nse, sx);
949 * write (nls-nse) - sx chars of new starting at
952 terminal_overwrite(el, (nse + sx),
953 (size_t)((nls - nse) - sx));
955 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
956 terminal_overwrite(el, nse, (size_t)(nls - nse));
959 * No need to do a clear-to-end here because we were
960 * doing a second insert, so we will have over
961 * written all of the old string.
965 ELRE_DEBUG(1, (__F, "done.\r\n"));
969 /* re__copy_and_pad():
970 * Copy string and pad with spaces
973 re__copy_and_pad(Char *dst, const Char *src, size_t width)
977 for (i = 0; i < width; i++) {
983 for (; i < width; i++)
990 /* re_refresh_cursor():
991 * Move to the new cursor position
994 re_refresh_cursor(EditLine *el)
999 if (el->el_line.cursor >= el->el_line.lastchar) {
1000 if (el->el_map.current == el->el_map.alt
1001 && el->el_line.lastchar != el->el_line.buffer)
1002 el->el_line.cursor = el->el_line.lastchar - 1;
1004 el->el_line.cursor = el->el_line.lastchar;
1007 /* first we must find where the cursor is... */
1008 h = el->el_prompt.p_pos.h;
1009 v = el->el_prompt.p_pos.v;
1010 th = el->el_terminal.t_size.h; /* optimize for speed */
1012 /* do input buffer to el->el_line.cursor */
1013 for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
1014 switch (ct_chr_class(*cp)) {
1015 case CHTYPE_NL: /* handle newline in data part too */
1019 case CHTYPE_TAB: /* if a tab, to next tab stop */
1025 if (w > 1 && h + w > th) { /* won't fit on line */
1029 h += ct_visual_width(*cp);
1033 if (h >= th) { /* check, extra long tabs picked up here also */
1038 /* if we have a next character, and it's a doublewidth one, we need to
1039 * check whether we need to linebreak for it to fit */
1040 if (cp < el->el_line.lastchar && (w = Width(*cp)) > 1)
1047 terminal_move_to_line(el, v);
1048 terminal_move_to_char(el, h);
1049 terminal__flush(el);
1054 * Add a character fast.
1057 re_fastputc(EditLine *el, Int c)
1059 int w = Width((Char)c);
1060 while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h)
1061 re_fastputc(el, ' ');
1063 terminal__putc(el, c);
1064 el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
1066 el->el_display[el->el_cursor.v][el->el_cursor.h++]
1069 if (el->el_cursor.h >= el->el_terminal.t_size.h) {
1070 /* if we must overflow */
1071 el->el_cursor.h = 0;
1074 * If we would overflow (input is longer than terminal size),
1075 * emulate scroll by dropping first line and shuffling the rest.
1076 * We do this via pointer shuffling - it's safe in this case
1077 * and we avoid memcpy().
1079 if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) {
1080 int i, lins = el->el_terminal.t_size.v;
1081 Char *firstline = el->el_display[0];
1083 for(i = 1; i < lins; i++)
1084 el->el_display[i - 1] = el->el_display[i];
1086 re__copy_and_pad(firstline, STR(""), (size_t)0);
1087 el->el_display[i - 1] = firstline;
1090 el->el_refresh.r_oldcv++;
1092 if (EL_HAS_AUTO_MARGINS) {
1093 if (EL_HAS_MAGIC_MARGINS) {
1094 terminal__putc(el, ' ');
1095 terminal__putc(el, '\b');
1098 terminal__putc(el, '\r');
1099 terminal__putc(el, '\n');
1106 * we added just one char, handle it fast.
1107 * Assumes that screen cursor == real cursor
1110 re_fastaddc(EditLine *el)
1115 c = el->el_line.cursor[-1];
1117 if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1118 re_refresh(el); /* too hard to handle */
1121 rhdiff = el->el_terminal.t_size.h - el->el_cursor.h -
1122 el->el_rprompt.p_pos.h;
1123 if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1124 re_refresh(el); /* clear out rprompt if less than 1 char gap */
1126 } /* else (only do at end of line, no TAB) */
1127 switch (ct_chr_class(c)) {
1128 case CHTYPE_TAB: /* already handled, should never happen here */
1134 case CHTYPE_ASCIICTL:
1135 case CHTYPE_NONPRINT: {
1136 Char visbuf[VISUAL_WIDTH_MAX];
1138 ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c);
1139 for (i = 0; n-- > 0; ++i)
1140 re_fastputc(el, visbuf[i]);
1144 terminal__flush(el);
1148 /* re_clear_display():
1149 * clear the screen buffers so that new new prompt starts fresh.
1152 re_clear_display(EditLine *el)
1156 el->el_cursor.v = 0;
1157 el->el_cursor.h = 0;
1158 for (i = 0; i < el->el_terminal.t_size.v; i++)
1159 el->el_display[i][0] = '\0';
1160 el->el_refresh.r_oldcv = 0;
1164 /* re_clear_lines():
1165 * Make sure all lines are *really* blank
1168 re_clear_lines(EditLine *el)
1173 for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
1174 /* for each line on the screen */
1175 terminal_move_to_line(el, i);
1176 terminal_move_to_char(el, 0);
1177 terminal_clear_EOL(el, el->el_terminal.t_size.h);
1180 terminal_move_to_line(el, el->el_refresh.r_oldcv);
1181 /* go to last line */
1182 terminal__putc(el, '\r'); /* go to BOL */
1183 terminal__putc(el, '\n'); /* go to new line */