1 /* $NetBSD: refresh.c,v 1.57 2020/03/30 06:54:37 ryo 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.57 2020/03/30 06:54:37 ryo Exp $");
42 #endif /* not lint && not SCCSID */
45 * refresh.c: Lower level screen refreshing functions
54 static void re_nextline(EditLine *);
55 static void re_addc(EditLine *, wint_t);
56 static void re_update_line(EditLine *, wchar_t *, wchar_t *, int);
57 static void re_insert (EditLine *, wchar_t *, int, int, wchar_t *, int);
58 static void re_delete(EditLine *, wchar_t *, int, int, int);
59 static void re_fastputc(EditLine *, wint_t);
60 static void re_clear_eol(EditLine *, int, int, int);
61 static void re__strncopy(wchar_t *, wchar_t *, size_t);
62 static void re__copy_and_pad(wchar_t *, const wchar_t *, size_t);
65 static void re_printstr(EditLine *, const char *, wchar_t *, wchar_t *);
66 #define __F el->el_errfile
67 #define ELRE_ASSERT(a, b, c) do \
68 if (/*CONSTCOND*/ a) { \
72 while (/*CONSTCOND*/0)
73 #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
76 * Print a string on the debugging pty
79 re_printstr(EditLine *el, const char *str, wchar_t *f, wchar_t *t)
82 ELRE_DEBUG(1, (__F, "%s:\"", str));
84 ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
85 ELRE_DEBUG(1, (__F, "\"\r\n"));
88 #define ELRE_ASSERT(a, b, c)
89 #define ELRE_DEBUG(a, b)
93 * Move to the next line or scroll
96 re_nextline(EditLine *el)
98 el->el_refresh.r_cursor.h = 0; /* reset it. */
101 * If we would overflow (input is longer than terminal size),
102 * emulate scroll by dropping first line and shuffling the rest.
103 * We do this via pointer shuffling - it's safe in this case
104 * and we avoid memcpy().
106 if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) {
107 int i, lins = el->el_terminal.t_size.v;
108 wchar_t *firstline = el->el_vdisplay[0];
110 for(i = 1; i < lins; i++)
111 el->el_vdisplay[i - 1] = el->el_vdisplay[i];
113 firstline[0] = '\0'; /* empty the string */
114 el->el_vdisplay[i - 1] = firstline;
116 el->el_refresh.r_cursor.v++;
118 ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v,
119 (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
120 el->el_refresh.r_cursor.v, el->el_terminal.t_size.v),
125 * Draw c, expanding tabs, control chars etc.
128 re_addc(EditLine *el, wint_t c)
130 switch (ct_chr_class(c)) {
131 case CHTYPE_TAB: /* expand the tab */
134 if ((el->el_refresh.r_cursor.h & 07) == 0)
135 break; /* go until tab stop */
139 int oldv = el->el_refresh.r_cursor.v;
140 re_putc(el, '\0', 0); /* assure end of line */
141 if (oldv == el->el_refresh.r_cursor.v) /* XXX */
149 wchar_t visbuf[VISUAL_WIDTH_MAX];
151 ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
152 for (i = 0; n-- > 0; ++i)
153 re_putc(el, visbuf[i], 1);
160 * Place the literal string given
163 re_putliteral(EditLine *el, const wchar_t *begin, const wchar_t *end)
165 coord_t *cur = &el->el_refresh.r_cursor;
167 int sizeh = el->el_terminal.t_size.h;
170 c = literal_add(el, begin, end, &w);
171 if (c == 0 || w <= 0)
173 el->el_vdisplay[cur->v][cur->h] = c;
176 if (i > sizeh - cur->h) /* avoid overflow */
179 el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR;
182 if (cur->h >= sizeh) {
183 /* assure end of line */
184 el->el_vdisplay[cur->v][sizeh] = '\0';
190 * Draw the character given
193 re_putc(EditLine *el, wint_t c, int shift)
195 coord_t *cur = &el->el_refresh.r_cursor;
196 int i, w = wcwidth(c);
197 int sizeh = el->el_terminal.t_size.h;
199 ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c));
203 while (shift && (cur->h + w > sizeh))
206 el->el_vdisplay[cur->v][cur->h] = c;
207 /* assumes !shift is only used for single-column chars */
210 el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR;
215 cur->h += w; /* advance to next place */
216 if (cur->h >= sizeh) {
217 /* assure end of line */
218 el->el_vdisplay[cur->v][sizeh] = '\0';
225 * draws the new virtual screen image from the current input
226 * line, then goes line-by-line changing the real image to the new
227 * virtual image. The routine to re-draw a line can be replaced
228 * easily in hopes of a smarter one being placed there.
231 re_refresh(EditLine *el)
240 ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%ls:\r\n",
241 el->el_line.buffer));
244 /* reset the Drawing cursor */
245 el->el_refresh.r_cursor.h = 0;
246 el->el_refresh.r_cursor.v = 0;
248 terminal_move_to_char(el, 0);
250 /* temporarily draw rprompt to calculate its size */
251 prompt_print(el, EL_RPROMPT);
253 /* reset the Drawing cursor */
254 el->el_refresh.r_cursor.h = 0;
255 el->el_refresh.r_cursor.v = 0;
257 if (el->el_line.cursor >= el->el_line.lastchar) {
258 if (el->el_map.current == el->el_map.alt
259 && el->el_line.lastchar != el->el_line.buffer)
260 el->el_line.cursor = el->el_line.lastchar - 1;
262 el->el_line.cursor = el->el_line.lastchar;
265 cur.h = -1; /* set flag in case I'm not set */
268 prompt_print(el, EL_PROMPT);
270 /* draw the current input buffer */
272 termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v;
273 if (el->el_line.lastchar - el->el_line.buffer > termsz) {
275 * If line is longer than terminal, process only part
276 * of line which would influence display.
278 size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
280 st = el->el_line.lastchar - rem
281 - (termsz - (((rem / el->el_terminal.t_size.v) - 1)
282 * el->el_terminal.t_size.v));
285 st = el->el_line.buffer;
287 for (cp = st; cp < el->el_line.lastchar; cp++) {
288 if (cp == el->el_line.cursor) {
289 int w = wcwidth(*cp);
291 cur.h = el->el_refresh.r_cursor.h;
292 cur.v = el->el_refresh.r_cursor.v;
293 /* handle being at a linebroken doublewidth char */
294 if (w > 1 && el->el_refresh.r_cursor.h + w >
295 el->el_terminal.t_size.h) {
303 if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
304 cur.h = el->el_refresh.r_cursor.h;
305 cur.v = el->el_refresh.r_cursor.v;
307 rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h -
308 el->el_rprompt.p_pos.h;
309 if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
310 !el->el_refresh.r_cursor.v && rhdiff > 1) {
312 * have a right-hand side prompt that will fit
313 * on the end of the first line with at least
314 * one character gap to the input buffer.
316 while (--rhdiff > 0) /* pad out with spaces */
318 prompt_print(el, EL_RPROMPT);
320 el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
321 el->el_rprompt.p_pos.v = 0;
324 re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
326 el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
329 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
330 el->el_terminal.t_size.h, el->el_refresh.r_cursor.h,
331 el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0],
334 ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
335 for (i = 0; i <= el->el_refresh.r_newcv; i++) {
336 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
337 re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
340 * Copy the new line to be the current one, and pad out with
341 * spaces to the full width of the terminal so that if we try
342 * moving the cursor by writing the character that is at the
343 * end of the screen line, it won't be a NUL or some old
346 re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
347 (size_t) el->el_terminal.t_size.h);
350 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
351 el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
353 if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
354 for (; i <= el->el_refresh.r_oldcv; i++) {
355 terminal_move_to_line(el, i);
356 terminal_move_to_char(el, 0);
357 /* This wcslen should be safe even with MB_FILL_CHARs */
358 terminal_clear_EOL(el, (int) wcslen(el->el_display[i]));
360 terminal_overwrite(el, L"C\b", 2);
361 #endif /* DEBUG_REFRESH */
362 el->el_display[i][0] = '\0';
365 el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
367 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
368 el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
370 terminal_move_to_line(el, cur.v); /* go to where the cursor is */
371 terminal_move_to_char(el, cur.h);
376 * used to go to last used screen line
379 re_goto_bottom(EditLine *el)
382 terminal_move_to_line(el, el->el_refresh.r_oldcv);
383 terminal__putc(el, '\n');
384 re_clear_display(el);
390 * insert num characters of s into d (in front of the character)
391 * at dat, maximum length of d is dlen
395 re_insert(EditLine *el __attribute__((__unused__)),
396 wchar_t *d, int dat, int dlen, wchar_t *s, int num)
402 if (num > dlen - dat)
406 (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
407 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
408 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
411 /* open up the space for num chars */
417 d[dlen] = '\0'; /* just in case */
421 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
422 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
423 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
426 /* copy the characters */
427 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
431 /* ct_encode_string() uses a static buffer, so we can't conveniently
432 * encode both d & s here */
434 (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
435 num, dat, dlen, d, s));
436 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
442 * delete num characters d at dat, maximum length of d is dlen
446 re_delete(EditLine *el __attribute__((__unused__)),
447 wchar_t *d, int dat, int dlen, int num)
453 if (dat + num >= dlen) {
458 (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
459 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
461 /* open up the space for num chars */
467 d[dlen] = '\0'; /* just in case */
470 (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
471 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
476 * Like strncpy without padding.
479 re__strncopy(wchar_t *a, wchar_t *b, size_t n)
487 * Find the number of characters we need to clear till the end of line
488 * in order to make sure that we have cleared the previous contents of
489 * the line. fx and sx is the number of characters inserted or deleted
490 * in the first or second diff, diff is the difference between the
491 * number of characters between the new and old line.
494 re_clear_eol(EditLine *el, int fx, int sx, int diff)
497 ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
509 ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
510 terminal_clear_EOL(el, diff);
513 /*****************************************************************
514 re_update_line() is based on finding the middle difference of each line
517 /old first difference
518 /beginning of line | /old last same /old EOL
520 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
521 new: eddie> Oh, my little buggy says to me, as lurgid as
523 \beginning of line | \new last same \new end of line
524 \new first difference
526 all are character pointers for the sake of speed. Special cases for
527 no differences, as well as for end of line additions must be handled.
528 **************************************************************** */
530 /* Minimum at which doing an insert it "worth it". This should be about
531 * half the "cost" of going into insert mode, inserting a character, and
532 * going back out. This should really be calculated from the termcap
533 * data... For the moment, a good number for ANSI terminals.
535 #define MIN_END_KEEP 4
538 re_update_line(EditLine *el, wchar_t *old, wchar_t *new, int i)
540 wchar_t *o, *n, *p, c;
541 wchar_t *ofd, *ols, *oe, *nfd, *nls, *ne;
542 wchar_t *osb, *ose, *nsb, *nse;
549 for (o = old, n = new; *o && (*o == *n); o++, n++)
555 * Find the end of both old and new
560 * Remove any trailing blanks off of the end, being careful not to
561 * back up past the beginning.
574 /* remove blanks from end of new */
584 * if no diff, continue to next line of redraw
586 if (*ofd == '\0' && *nfd == '\0') {
587 ELRE_DEBUG(1, (__F, "no difference.\r\n"));
591 * find last same pointer
593 while ((o > ofd) && (n > nfd) && (*--o == *--n))
599 * find same beginning and same end
607 * case 1: insert: scan from nfd to nls looking for *ofd
610 for (c = *ofd, n = nfd; n < nls; n++) {
613 p < nls && o < ols && *o == *p;
617 * if the new match is longer and it's worth
618 * keeping, then we take it
620 if (((nse - nsb) < (p - n)) &&
621 (2 * (p - n) > n - nfd)) {
631 * case 2: delete: scan from ofd to ols looking for *nfd
634 for (c = *nfd, o = ofd; o < ols; o++) {
637 p < ols && n < nls && *p == *n;
641 * if the new match is longer and it's worth
642 * keeping, then we take it
644 if (((ose - osb) < (p - o)) &&
645 (2 * (p - o) > o - ofd)) {
655 * Pragmatics I: If old trailing whitespace or not enough characters to
656 * save to be worth it, then don't save the last same info.
658 if ((oe - ols) < MIN_END_KEEP) {
663 * Pragmatics II: if the terminal isn't smart enough, make the data
664 * dumber so the smart update doesn't try anything fancy
668 * fx is the number of characters we need to insert/delete: in the
669 * beginning to bring the two same begins together
671 fx = (int)((nsb - nfd) - (osb - ofd));
673 * sx is the number of characters we need to insert/delete: in the
674 * end to bring the two same last parts together
676 sx = (int)((nls - nse) - (ols - ose));
678 if (!EL_CAN_INSERT) {
689 if ((ols - ofd) < (nls - nfd)) {
694 if (!EL_CAN_DELETE) {
705 if ((ols - ofd) > (nls - nfd)) {
711 * Pragmatics III: make sure the middle shifted pointers are correct if
712 * they don't point to anything (we may have moved ols or nls).
714 /* if the change isn't worth it, don't bother */
715 /* was: if (osb == ose) */
716 if ((ose - osb) < MIN_END_KEEP) {
723 * Now that we are done with pragmatics we recompute fx, sx
725 fx = (int)((nsb - nfd) - (osb - ofd));
726 sx = (int)((nls - nse) - (ols - ose));
728 ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
729 ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
730 ofd - old, osb - old, ose - old, ols - old, oe - old));
731 ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
732 nfd - new, nsb - new, nse - new, nls - new, ne - new));
734 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
736 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
738 re_printstr(el, "old- oe", old, oe);
739 re_printstr(el, "new- ne", new, ne);
740 re_printstr(el, "old-ofd", old, ofd);
741 re_printstr(el, "new-nfd", new, nfd);
742 re_printstr(el, "ofd-osb", ofd, osb);
743 re_printstr(el, "nfd-nsb", nfd, nsb);
744 re_printstr(el, "osb-ose", osb, ose);
745 re_printstr(el, "nsb-nse", nsb, nse);
746 re_printstr(el, "ose-ols", ose, ols);
747 re_printstr(el, "nse-nls", nse, nls);
748 re_printstr(el, "ols- oe", ols, oe);
749 re_printstr(el, "nls- ne", nls, ne);
750 #endif /* DEBUG_REFRESH */
753 * el_cursor.v to this line i MUST be in this routine so that if we
754 * don't have to change the line, we don't move to it. el_cursor.h to
757 terminal_move_to_line(el, i);
760 * at this point we have something like this:
762 * /old /ofd /osb /ose /ols /oe
763 * v.....................v v..................v v........v
764 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
765 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
766 * ^.....................^ ^..................^ ^........^
767 * \new \nfd \nsb \nse \nls \ne
769 * fx is the difference in length between the chars between nfd and
770 * nsb, and the chars between ofd and osb, and is thus the number of
771 * characters to delete if < 0 (new is shorter than old, as above),
772 * or insert (new is longer than short).
774 * sx is the same for the second differences.
778 * if we have a net insert on the first difference, AND inserting the
779 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
780 * character (which is ne if nls != ne, otherwise is nse) off the edge
781 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
782 * so that we keep everything we need to.
786 * if the last same is the same like the end, there is no last same
787 * part, otherwise we want to keep the last same part set p to the
788 * last useful old character
790 p = (ols != oe) ? oe : ose;
793 * if (There is a diffence in the beginning) && (we need to insert
794 * characters) && (the number of characters to insert is less than
796 * We need to do an insert!
797 * else if (we need to delete characters)
798 * We need to delete characters!
800 * No insert or delete
802 if ((nsb != nfd) && fx > 0 &&
803 ((p - old) + fx <= el->el_terminal.t_size.h)) {
805 (__F, "first diff insert at %td...\r\n", nfd - new));
807 * Move to the first char to insert, where the first diff is.
809 terminal_move_to_char(el, (int)(nfd - new));
811 * Check if we have stuff to keep at end
814 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
816 * insert fx chars of new starting at nfd
819 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
820 "ERROR: cannot insert in early first diff\n"));
821 terminal_insertwrite(el, nfd, fx);
822 re_insert(el, old, (int)(ofd - old),
823 el->el_terminal.t_size.h, nfd, fx);
826 * write (nsb-nfd) - fx chars of new starting at
829 len = (size_t) ((nsb - nfd) - fx);
830 terminal_overwrite(el, (nfd + fx), len);
831 re__strncopy(ofd + fx, nfd + fx, len);
833 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
834 len = (size_t)(nsb - nfd);
835 terminal_overwrite(el, nfd, len);
836 re__strncopy(ofd, nfd, len);
844 (__F, "first diff delete at %td...\r\n", ofd - old));
846 * move to the first char to delete where the first diff is
848 terminal_move_to_char(el, (int)(ofd - old));
850 * Check if we have stuff to save
853 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
855 * fx is less than zero *always* here but we check
859 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
860 "ERROR: cannot delete in first diff\n"));
861 terminal_deletechars(el, -fx);
862 re_delete(el, old, (int)(ofd - old),
863 el->el_terminal.t_size.h, -fx);
866 * write (nsb-nfd) chars of new starting at nfd
868 len = (size_t) (nsb - nfd);
869 terminal_overwrite(el, nfd, len);
870 re__strncopy(ofd, nfd, len);
874 "but with nothing left to save\r\n"));
876 * write (nsb-nfd) chars of new starting at nfd
878 terminal_overwrite(el, nfd, (size_t)(nsb - nfd));
879 re_clear_eol(el, fx, sx,
880 (int)((oe - old) - (ne - new)));
889 if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) {
891 "second diff delete at %td...\r\n", (ose - old) + fx));
893 * Check if we have stuff to delete
896 * fx is the number of characters inserted (+) or deleted (-)
899 terminal_move_to_char(el, (int)((ose - old) + fx));
901 * Check if we have stuff to save
904 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
906 * Again a duplicate test.
909 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
910 "ERROR: cannot delete in second diff\n"));
911 terminal_deletechars(el, -sx);
914 * write (nls-nse) chars of new starting at nse
916 terminal_overwrite(el, nse, (size_t)(nls - nse));
919 "but with nothing left to save\r\n"));
920 terminal_overwrite(el, nse, (size_t)(nls - nse));
921 re_clear_eol(el, fx, sx,
922 (int)((oe - old) - (ne - new)));
926 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
928 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
929 ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n",
932 terminal_move_to_char(el, (int)(nfd - new));
934 * Check if we have stuff to keep at the end
937 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
939 * We have to recalculate fx here because we set it
940 * to zero above as a flag saying that we hadn't done
941 * an early first insert.
943 fx = (int)((nsb - nfd) - (osb - ofd));
946 * insert fx chars of new starting at nfd
948 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
949 "ERROR: cannot insert in late first diff\n"));
950 terminal_insertwrite(el, nfd, fx);
951 re_insert(el, old, (int)(ofd - old),
952 el->el_terminal.t_size.h, nfd, fx);
955 * write (nsb-nfd) - fx chars of new starting at
958 len = (size_t) ((nsb - nfd) - fx);
959 terminal_overwrite(el, (nfd + fx), len);
960 re__strncopy(ofd + fx, nfd + fx, len);
962 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
963 len = (size_t) (nsb - nfd);
964 terminal_overwrite(el, nfd, len);
965 re__strncopy(ofd, nfd, len);
969 * line is now NEW up to nse
973 "second diff insert at %d...\r\n", (int)(nse - new)));
974 terminal_move_to_char(el, (int)(nse - new));
976 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
978 /* insert sx chars of new starting at nse */
979 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
980 "ERROR: cannot insert in second diff\n"));
981 terminal_insertwrite(el, nse, sx);
984 * write (nls-nse) - sx chars of new starting at
987 terminal_overwrite(el, (nse + sx),
988 (size_t)((nls - nse) - sx));
990 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
991 terminal_overwrite(el, nse, (size_t)(nls - nse));
994 * No need to do a clear-to-end here because we were
995 * doing a second insert, so we will have over
996 * written all of the old string.
1000 ELRE_DEBUG(1, (__F, "done.\r\n"));
1004 /* re__copy_and_pad():
1005 * Copy string and pad with spaces
1008 re__copy_and_pad(wchar_t *dst, const wchar_t *src, size_t width)
1012 for (i = 0; i < width; i++) {
1018 for (; i < width; i++)
1025 /* re_refresh_cursor():
1026 * Move to the new cursor position
1028 libedit_private void
1029 re_refresh_cursor(EditLine *el)
1034 if (el->el_line.cursor >= el->el_line.lastchar) {
1035 if (el->el_map.current == el->el_map.alt
1036 && el->el_line.lastchar != el->el_line.buffer)
1037 el->el_line.cursor = el->el_line.lastchar - 1;
1039 el->el_line.cursor = el->el_line.lastchar;
1042 /* first we must find where the cursor is... */
1043 h = el->el_prompt.p_pos.h;
1044 v = el->el_prompt.p_pos.v;
1045 th = el->el_terminal.t_size.h; /* optimize for speed */
1047 /* do input buffer to el->el_line.cursor */
1048 for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
1049 switch (ct_chr_class(*cp)) {
1050 case CHTYPE_NL: /* handle newline in data part too */
1054 case CHTYPE_TAB: /* if a tab, to next tab stop */
1060 if (w > 1 && h + w > th) { /* won't fit on line */
1064 h += ct_visual_width(*cp);
1068 if (h >= th) { /* check, extra long tabs picked up here also */
1073 /* if we have a next character, and it's a doublewidth one, we need to
1074 * check whether we need to linebreak for it to fit */
1075 if (cp < el->el_line.lastchar && (w = wcwidth(*cp)) > 1)
1082 terminal_move_to_line(el, v);
1083 terminal_move_to_char(el, h);
1084 terminal__flush(el);
1089 * Add a character fast.
1092 re_fastputc(EditLine *el, wint_t c)
1098 while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h)
1099 re_fastputc(el, ' ');
1101 terminal__putc(el, c);
1102 el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
1104 el->el_display[el->el_cursor.v][el->el_cursor.h++]
1107 if (el->el_cursor.h >= el->el_terminal.t_size.h) {
1108 /* if we must overflow */
1109 el->el_cursor.h = 0;
1112 * If we would overflow (input is longer than terminal size),
1113 * emulate scroll by dropping first line and shuffling the rest.
1114 * We do this via pointer shuffling - it's safe in this case
1115 * and we avoid memcpy().
1117 if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) {
1118 int i, lins = el->el_terminal.t_size.v;
1120 lastline = el->el_display[0];
1121 for(i = 1; i < lins; i++)
1122 el->el_display[i - 1] = el->el_display[i];
1124 el->el_display[i - 1] = lastline;
1127 lastline = el->el_display[++el->el_refresh.r_oldcv];
1129 re__copy_and_pad(lastline, L"", (size_t)el->el_terminal.t_size.h);
1131 if (EL_HAS_AUTO_MARGINS) {
1132 if (EL_HAS_MAGIC_MARGINS) {
1133 terminal__putc(el, ' ');
1134 terminal__putc(el, '\b');
1137 terminal__putc(el, '\r');
1138 terminal__putc(el, '\n');
1145 * we added just one char, handle it fast.
1146 * Assumes that screen cursor == real cursor
1148 libedit_private void
1149 re_fastaddc(EditLine *el)
1154 c = el->el_line.cursor[-1];
1156 if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1157 re_refresh(el); /* too hard to handle */
1160 rhdiff = el->el_terminal.t_size.h - el->el_cursor.h -
1161 el->el_rprompt.p_pos.h;
1162 if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1163 re_refresh(el); /* clear out rprompt if less than 1 char gap */
1165 } /* else (only do at end of line, no TAB) */
1166 switch (ct_chr_class(c)) {
1167 case CHTYPE_TAB: /* already handled, should never happen here */
1173 case CHTYPE_ASCIICTL:
1174 case CHTYPE_NONPRINT: {
1175 wchar_t visbuf[VISUAL_WIDTH_MAX];
1177 ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
1178 for (i = 0; n-- > 0; ++i)
1179 re_fastputc(el, visbuf[i]);
1183 terminal__flush(el);
1187 /* re_clear_display():
1188 * clear the screen buffers so that new new prompt starts fresh.
1190 libedit_private void
1191 re_clear_display(EditLine *el)
1195 el->el_cursor.v = 0;
1196 el->el_cursor.h = 0;
1197 for (i = 0; i < el->el_terminal.t_size.v; i++)
1198 el->el_display[i][0] = '\0';
1199 el->el_refresh.r_oldcv = 0;
1203 /* re_clear_lines():
1204 * Make sure all lines are *really* blank
1206 libedit_private void
1207 re_clear_lines(EditLine *el)
1212 for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
1213 /* for each line on the screen */
1214 terminal_move_to_line(el, i);
1215 terminal_move_to_char(el, 0);
1216 terminal_clear_EOL(el, el->el_terminal.t_size.h);
1219 terminal_move_to_line(el, el->el_refresh.r_oldcv);
1220 /* go to last line */
1221 terminal__putc(el, '\r'); /* go to BOL */
1222 terminal__putc(el, '\n'); /* go to new line */