1 /* $NetBSD: refresh.c,v 1.56 2019/01/04 03:03:44 uwe 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.56 2019/01/04 03:03:44 uwe Exp $");
42 #endif /* not lint && not SCCSID */
45 * refresh.c: Lower level screen refreshing functions
53 static void re_nextline(EditLine *);
54 static void re_addc(EditLine *, wint_t);
55 static void re_update_line(EditLine *, wchar_t *, wchar_t *, int);
56 static void re_insert (EditLine *, wchar_t *, int, int, wchar_t *, int);
57 static void re_delete(EditLine *, wchar_t *, int, int, int);
58 static void re_fastputc(EditLine *, wint_t);
59 static void re_clear_eol(EditLine *, int, int, int);
60 static void re__strncopy(wchar_t *, wchar_t *, size_t);
61 static void re__copy_and_pad(wchar_t *, const wchar_t *, size_t);
64 static void re_printstr(EditLine *, const char *, wchar_t *, wchar_t *);
65 #define __F el->el_errfile
66 #define ELRE_ASSERT(a, b, c) do \
67 if (/*CONSTCOND*/ a) { \
71 while (/*CONSTCOND*/0)
72 #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
75 * Print a string on the debugging pty
78 re_printstr(EditLine *el, const char *str, wchar_t *f, wchar_t *t)
81 ELRE_DEBUG(1, (__F, "%s:\"", str));
83 ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
84 ELRE_DEBUG(1, (__F, "\"\r\n"));
87 #define ELRE_ASSERT(a, b, c)
88 #define ELRE_DEBUG(a, b)
92 * Move to the next line or scroll
95 re_nextline(EditLine *el)
97 el->el_refresh.r_cursor.h = 0; /* reset it. */
100 * If we would overflow (input is longer than terminal size),
101 * emulate scroll by dropping first line and shuffling the rest.
102 * We do this via pointer shuffling - it's safe in this case
103 * and we avoid memcpy().
105 if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) {
106 int i, lins = el->el_terminal.t_size.v;
107 wchar_t *firstline = el->el_vdisplay[0];
109 for(i = 1; i < lins; i++)
110 el->el_vdisplay[i - 1] = el->el_vdisplay[i];
112 firstline[0] = '\0'; /* empty the string */
113 el->el_vdisplay[i - 1] = firstline;
115 el->el_refresh.r_cursor.v++;
117 ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v,
118 (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
119 el->el_refresh.r_cursor.v, el->el_terminal.t_size.v),
124 * Draw c, expanding tabs, control chars etc.
127 re_addc(EditLine *el, wint_t c)
129 switch (ct_chr_class(c)) {
130 case CHTYPE_TAB: /* expand the tab */
133 if ((el->el_refresh.r_cursor.h & 07) == 0)
134 break; /* go until tab stop */
138 int oldv = el->el_refresh.r_cursor.v;
139 re_putc(el, '\0', 0); /* assure end of line */
140 if (oldv == el->el_refresh.r_cursor.v) /* XXX */
148 wchar_t visbuf[VISUAL_WIDTH_MAX];
150 ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
151 for (i = 0; n-- > 0; ++i)
152 re_putc(el, visbuf[i], 1);
159 * Place the literal string given
162 re_putliteral(EditLine *el, const wchar_t *begin, const wchar_t *end)
164 coord_t *cur = &el->el_refresh.r_cursor;
166 int sizeh = el->el_terminal.t_size.h;
169 c = literal_add(el, begin, end, &w);
170 if (c == 0 || w <= 0)
172 el->el_vdisplay[cur->v][cur->h] = c;
175 if (i > sizeh - cur->h) /* avoid overflow */
178 el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR;
181 if (cur->h >= sizeh) {
182 /* assure end of line */
183 el->el_vdisplay[cur->v][sizeh] = '\0';
189 * Draw the character given
192 re_putc(EditLine *el, wint_t c, int shift)
194 coord_t *cur = &el->el_refresh.r_cursor;
195 int i, w = wcwidth(c);
196 int sizeh = el->el_terminal.t_size.h;
198 ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c));
202 while (shift && (cur->h + w > sizeh))
205 el->el_vdisplay[cur->v][cur->h] = c;
206 /* assumes !shift is only used for single-column chars */
209 el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR;
214 cur->h += w; /* advance to next place */
215 if (cur->h >= sizeh) {
216 /* assure end of line */
217 el->el_vdisplay[cur->v][sizeh] = '\0';
224 * draws the new virtual screen image from the current input
225 * line, then goes line-by-line changing the real image to the new
226 * virtual image. The routine to re-draw a line can be replaced
227 * easily in hopes of a smarter one being placed there.
230 re_refresh(EditLine *el)
239 ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%ls:\r\n",
240 el->el_line.buffer));
243 /* reset the Drawing cursor */
244 el->el_refresh.r_cursor.h = 0;
245 el->el_refresh.r_cursor.v = 0;
247 terminal_move_to_char(el, 0);
249 /* temporarily draw rprompt to calculate its size */
250 prompt_print(el, EL_RPROMPT);
252 /* reset the Drawing cursor */
253 el->el_refresh.r_cursor.h = 0;
254 el->el_refresh.r_cursor.v = 0;
256 if (el->el_line.cursor >= el->el_line.lastchar) {
257 if (el->el_map.current == el->el_map.alt
258 && el->el_line.lastchar != el->el_line.buffer)
259 el->el_line.cursor = el->el_line.lastchar - 1;
261 el->el_line.cursor = el->el_line.lastchar;
264 cur.h = -1; /* set flag in case I'm not set */
267 prompt_print(el, EL_PROMPT);
269 /* draw the current input buffer */
271 termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v;
272 if (el->el_line.lastchar - el->el_line.buffer > termsz) {
274 * If line is longer than terminal, process only part
275 * of line which would influence display.
277 size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
279 st = el->el_line.lastchar - rem
280 - (termsz - (((rem / el->el_terminal.t_size.v) - 1)
281 * el->el_terminal.t_size.v));
284 st = el->el_line.buffer;
286 for (cp = st; cp < el->el_line.lastchar; cp++) {
287 if (cp == el->el_line.cursor) {
288 int w = wcwidth(*cp);
290 cur.h = el->el_refresh.r_cursor.h;
291 cur.v = el->el_refresh.r_cursor.v;
292 /* handle being at a linebroken doublewidth char */
293 if (w > 1 && el->el_refresh.r_cursor.h + w >
294 el->el_terminal.t_size.h) {
302 if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
303 cur.h = el->el_refresh.r_cursor.h;
304 cur.v = el->el_refresh.r_cursor.v;
306 rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h -
307 el->el_rprompt.p_pos.h;
308 if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
309 !el->el_refresh.r_cursor.v && rhdiff > 1) {
311 * have a right-hand side prompt that will fit
312 * on the end of the first line with at least
313 * one character gap to the input buffer.
315 while (--rhdiff > 0) /* pad out with spaces */
317 prompt_print(el, EL_RPROMPT);
319 el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
320 el->el_rprompt.p_pos.v = 0;
323 re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
325 el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
328 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
329 el->el_terminal.t_size.h, el->el_refresh.r_cursor.h,
330 el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0],
333 ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
334 for (i = 0; i <= el->el_refresh.r_newcv; i++) {
335 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
336 re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
339 * Copy the new line to be the current one, and pad out with
340 * spaces to the full width of the terminal so that if we try
341 * moving the cursor by writing the character that is at the
342 * end of the screen line, it won't be a NUL or some old
345 re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
346 (size_t) el->el_terminal.t_size.h);
349 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
350 el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
352 if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
353 for (; i <= el->el_refresh.r_oldcv; i++) {
354 terminal_move_to_line(el, i);
355 terminal_move_to_char(el, 0);
356 /* This wcslen should be safe even with MB_FILL_CHARs */
357 terminal_clear_EOL(el, (int) wcslen(el->el_display[i]));
359 terminal_overwrite(el, L"C\b", 2);
360 #endif /* DEBUG_REFRESH */
361 el->el_display[i][0] = '\0';
364 el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
366 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
367 el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
369 terminal_move_to_line(el, cur.v); /* go to where the cursor is */
370 terminal_move_to_char(el, cur.h);
375 * used to go to last used screen line
378 re_goto_bottom(EditLine *el)
381 terminal_move_to_line(el, el->el_refresh.r_oldcv);
382 terminal__putc(el, '\n');
383 re_clear_display(el);
389 * insert num characters of s into d (in front of the character)
390 * at dat, maximum length of d is dlen
394 re_insert(EditLine *el __attribute__((__unused__)),
395 wchar_t *d, int dat, int dlen, wchar_t *s, int num)
401 if (num > dlen - dat)
405 (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
406 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
407 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
410 /* open up the space for num chars */
416 d[dlen] = '\0'; /* just in case */
420 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
421 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
422 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
425 /* copy the characters */
426 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
430 /* ct_encode_string() uses a static buffer, so we can't conveniently
431 * encode both d & s here */
433 (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
434 num, dat, dlen, d, s));
435 ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
441 * delete num characters d at dat, maximum length of d is dlen
445 re_delete(EditLine *el __attribute__((__unused__)),
446 wchar_t *d, int dat, int dlen, int num)
452 if (dat + num >= dlen) {
457 (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
458 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
460 /* open up the space for num chars */
466 d[dlen] = '\0'; /* just in case */
469 (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
470 num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
475 * Like strncpy without padding.
478 re__strncopy(wchar_t *a, wchar_t *b, size_t n)
486 * Find the number of characters we need to clear till the end of line
487 * in order to make sure that we have cleared the previous contents of
488 * the line. fx and sx is the number of characters inserted or deleted
489 * in the first or second diff, diff is the difference between the
490 * number of characters between the new and old line.
493 re_clear_eol(EditLine *el, int fx, int sx, int diff)
496 ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
508 ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
509 terminal_clear_EOL(el, diff);
512 /*****************************************************************
513 re_update_line() is based on finding the middle difference of each line
516 /old first difference
517 /beginning of line | /old last same /old EOL
519 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
520 new: eddie> Oh, my little buggy says to me, as lurgid as
522 \beginning of line | \new last same \new end of line
523 \new first difference
525 all are character pointers for the sake of speed. Special cases for
526 no differences, as well as for end of line additions must be handled.
527 **************************************************************** */
529 /* Minimum at which doing an insert it "worth it". This should be about
530 * half the "cost" of going into insert mode, inserting a character, and
531 * going back out. This should really be calculated from the termcap
532 * data... For the moment, a good number for ANSI terminals.
534 #define MIN_END_KEEP 4
537 re_update_line(EditLine *el, wchar_t *old, wchar_t *new, int i)
539 wchar_t *o, *n, *p, c;
540 wchar_t *ofd, *ols, *oe, *nfd, *nls, *ne;
541 wchar_t *osb, *ose, *nsb, *nse;
548 for (o = old, n = new; *o && (*o == *n); o++, n++)
554 * Find the end of both old and new
559 * Remove any trailing blanks off of the end, being careful not to
560 * back up past the beginning.
573 /* remove blanks from end of new */
583 * if no diff, continue to next line of redraw
585 if (*ofd == '\0' && *nfd == '\0') {
586 ELRE_DEBUG(1, (__F, "no difference.\r\n"));
590 * find last same pointer
592 while ((o > ofd) && (n > nfd) && (*--o == *--n))
598 * find same beginning and same end
606 * case 1: insert: scan from nfd to nls looking for *ofd
609 for (c = *ofd, n = nfd; n < nls; n++) {
612 p < nls && o < ols && *o == *p;
616 * if the new match is longer and it's worth
617 * keeping, then we take it
619 if (((nse - nsb) < (p - n)) &&
620 (2 * (p - n) > n - nfd)) {
630 * case 2: delete: scan from ofd to ols looking for *nfd
633 for (c = *nfd, o = ofd; o < ols; o++) {
636 p < ols && n < nls && *p == *n;
640 * if the new match is longer and it's worth
641 * keeping, then we take it
643 if (((ose - osb) < (p - o)) &&
644 (2 * (p - o) > o - ofd)) {
654 * Pragmatics I: If old trailing whitespace or not enough characters to
655 * save to be worth it, then don't save the last same info.
657 if ((oe - ols) < MIN_END_KEEP) {
662 * Pragmatics II: if the terminal isn't smart enough, make the data
663 * dumber so the smart update doesn't try anything fancy
667 * fx is the number of characters we need to insert/delete: in the
668 * beginning to bring the two same begins together
670 fx = (int)((nsb - nfd) - (osb - ofd));
672 * sx is the number of characters we need to insert/delete: in the
673 * end to bring the two same last parts together
675 sx = (int)((nls - nse) - (ols - ose));
677 if (!EL_CAN_INSERT) {
688 if ((ols - ofd) < (nls - nfd)) {
693 if (!EL_CAN_DELETE) {
704 if ((ols - ofd) > (nls - nfd)) {
710 * Pragmatics III: make sure the middle shifted pointers are correct if
711 * they don't point to anything (we may have moved ols or nls).
713 /* if the change isn't worth it, don't bother */
714 /* was: if (osb == ose) */
715 if ((ose - osb) < MIN_END_KEEP) {
722 * Now that we are done with pragmatics we recompute fx, sx
724 fx = (int)((nsb - nfd) - (osb - ofd));
725 sx = (int)((nls - nse) - (ols - ose));
727 ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
728 ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
729 ofd - old, osb - old, ose - old, ols - old, oe - old));
730 ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
731 nfd - new, nsb - new, nse - new, nls - new, ne - new));
733 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
735 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
737 re_printstr(el, "old- oe", old, oe);
738 re_printstr(el, "new- ne", new, ne);
739 re_printstr(el, "old-ofd", old, ofd);
740 re_printstr(el, "new-nfd", new, nfd);
741 re_printstr(el, "ofd-osb", ofd, osb);
742 re_printstr(el, "nfd-nsb", nfd, nsb);
743 re_printstr(el, "osb-ose", osb, ose);
744 re_printstr(el, "nsb-nse", nsb, nse);
745 re_printstr(el, "ose-ols", ose, ols);
746 re_printstr(el, "nse-nls", nse, nls);
747 re_printstr(el, "ols- oe", ols, oe);
748 re_printstr(el, "nls- ne", nls, ne);
749 #endif /* DEBUG_REFRESH */
752 * el_cursor.v to this line i MUST be in this routine so that if we
753 * don't have to change the line, we don't move to it. el_cursor.h to
756 terminal_move_to_line(el, i);
759 * at this point we have something like this:
761 * /old /ofd /osb /ose /ols /oe
762 * v.....................v v..................v v........v
763 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
764 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
765 * ^.....................^ ^..................^ ^........^
766 * \new \nfd \nsb \nse \nls \ne
768 * fx is the difference in length between the chars between nfd and
769 * nsb, and the chars between ofd and osb, and is thus the number of
770 * characters to delete if < 0 (new is shorter than old, as above),
771 * or insert (new is longer than short).
773 * sx is the same for the second differences.
777 * if we have a net insert on the first difference, AND inserting the
778 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
779 * character (which is ne if nls != ne, otherwise is nse) off the edge
780 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
781 * so that we keep everything we need to.
785 * if the last same is the same like the end, there is no last same
786 * part, otherwise we want to keep the last same part set p to the
787 * last useful old character
789 p = (ols != oe) ? oe : ose;
792 * if (There is a diffence in the beginning) && (we need to insert
793 * characters) && (the number of characters to insert is less than
795 * We need to do an insert!
796 * else if (we need to delete characters)
797 * We need to delete characters!
799 * No insert or delete
801 if ((nsb != nfd) && fx > 0 &&
802 ((p - old) + fx <= el->el_terminal.t_size.h)) {
804 (__F, "first diff insert at %td...\r\n", nfd - new));
806 * Move to the first char to insert, where the first diff is.
808 terminal_move_to_char(el, (int)(nfd - new));
810 * Check if we have stuff to keep at end
813 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
815 * insert fx chars of new starting at nfd
818 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
819 "ERROR: cannot insert in early first diff\n"));
820 terminal_insertwrite(el, nfd, fx);
821 re_insert(el, old, (int)(ofd - old),
822 el->el_terminal.t_size.h, nfd, fx);
825 * write (nsb-nfd) - fx chars of new starting at
828 len = (size_t) ((nsb - nfd) - fx);
829 terminal_overwrite(el, (nfd + fx), len);
830 re__strncopy(ofd + fx, nfd + fx, len);
832 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
833 len = (size_t)(nsb - nfd);
834 terminal_overwrite(el, nfd, len);
835 re__strncopy(ofd, nfd, len);
843 (__F, "first diff delete at %td...\r\n", ofd - old));
845 * move to the first char to delete where the first diff is
847 terminal_move_to_char(el, (int)(ofd - old));
849 * Check if we have stuff to save
852 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
854 * fx is less than zero *always* here but we check
858 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
859 "ERROR: cannot delete in first diff\n"));
860 terminal_deletechars(el, -fx);
861 re_delete(el, old, (int)(ofd - old),
862 el->el_terminal.t_size.h, -fx);
865 * write (nsb-nfd) chars of new starting at nfd
867 len = (size_t) (nsb - nfd);
868 terminal_overwrite(el, nfd, len);
869 re__strncopy(ofd, nfd, len);
873 "but with nothing left to save\r\n"));
875 * write (nsb-nfd) chars of new starting at nfd
877 terminal_overwrite(el, nfd, (size_t)(nsb - nfd));
878 re_clear_eol(el, fx, sx,
879 (int)((oe - old) - (ne - new)));
888 if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) {
890 "second diff delete at %td...\r\n", (ose - old) + fx));
892 * Check if we have stuff to delete
895 * fx is the number of characters inserted (+) or deleted (-)
898 terminal_move_to_char(el, (int)((ose - old) + fx));
900 * Check if we have stuff to save
903 ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
905 * Again a duplicate test.
908 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
909 "ERROR: cannot delete in second diff\n"));
910 terminal_deletechars(el, -sx);
913 * write (nls-nse) chars of new starting at nse
915 terminal_overwrite(el, nse, (size_t)(nls - nse));
918 "but with nothing left to save\r\n"));
919 terminal_overwrite(el, nse, (size_t)(nls - nse));
920 re_clear_eol(el, fx, sx,
921 (int)((oe - old) - (ne - new)));
925 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
927 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
928 ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n",
931 terminal_move_to_char(el, (int)(nfd - new));
933 * Check if we have stuff to keep at the end
936 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
938 * We have to recalculate fx here because we set it
939 * to zero above as a flag saying that we hadn't done
940 * an early first insert.
942 fx = (int)((nsb - nfd) - (osb - ofd));
945 * insert fx chars of new starting at nfd
947 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
948 "ERROR: cannot insert in late first diff\n"));
949 terminal_insertwrite(el, nfd, fx);
950 re_insert(el, old, (int)(ofd - old),
951 el->el_terminal.t_size.h, nfd, fx);
954 * write (nsb-nfd) - fx chars of new starting at
957 len = (size_t) ((nsb - nfd) - fx);
958 terminal_overwrite(el, (nfd + fx), len);
959 re__strncopy(ofd + fx, nfd + fx, len);
961 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
962 len = (size_t) (nsb - nfd);
963 terminal_overwrite(el, nfd, len);
964 re__strncopy(ofd, nfd, len);
968 * line is now NEW up to nse
972 "second diff insert at %d...\r\n", (int)(nse - new)));
973 terminal_move_to_char(el, (int)(nse - new));
975 ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
977 /* insert sx chars of new starting at nse */
978 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
979 "ERROR: cannot insert in second diff\n"));
980 terminal_insertwrite(el, nse, sx);
983 * write (nls-nse) - sx chars of new starting at
986 terminal_overwrite(el, (nse + sx),
987 (size_t)((nls - nse) - sx));
989 ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
990 terminal_overwrite(el, nse, (size_t)(nls - nse));
993 * No need to do a clear-to-end here because we were
994 * doing a second insert, so we will have over
995 * written all of the old string.
999 ELRE_DEBUG(1, (__F, "done.\r\n"));
1003 /* re__copy_and_pad():
1004 * Copy string and pad with spaces
1007 re__copy_and_pad(wchar_t *dst, const wchar_t *src, size_t width)
1011 for (i = 0; i < width; i++) {
1017 for (; i < width; i++)
1024 /* re_refresh_cursor():
1025 * Move to the new cursor position
1027 libedit_private void
1028 re_refresh_cursor(EditLine *el)
1033 if (el->el_line.cursor >= el->el_line.lastchar) {
1034 if (el->el_map.current == el->el_map.alt
1035 && el->el_line.lastchar != el->el_line.buffer)
1036 el->el_line.cursor = el->el_line.lastchar - 1;
1038 el->el_line.cursor = el->el_line.lastchar;
1041 /* first we must find where the cursor is... */
1042 h = el->el_prompt.p_pos.h;
1043 v = el->el_prompt.p_pos.v;
1044 th = el->el_terminal.t_size.h; /* optimize for speed */
1046 /* do input buffer to el->el_line.cursor */
1047 for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
1048 switch (ct_chr_class(*cp)) {
1049 case CHTYPE_NL: /* handle newline in data part too */
1053 case CHTYPE_TAB: /* if a tab, to next tab stop */
1059 if (w > 1 && h + w > th) { /* won't fit on line */
1063 h += ct_visual_width(*cp);
1067 if (h >= th) { /* check, extra long tabs picked up here also */
1072 /* if we have a next character, and it's a doublewidth one, we need to
1073 * check whether we need to linebreak for it to fit */
1074 if (cp < el->el_line.lastchar && (w = wcwidth(*cp)) > 1)
1081 terminal_move_to_line(el, v);
1082 terminal_move_to_char(el, h);
1083 terminal__flush(el);
1088 * Add a character fast.
1091 re_fastputc(EditLine *el, wint_t c)
1097 while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h)
1098 re_fastputc(el, ' ');
1100 terminal__putc(el, c);
1101 el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
1103 el->el_display[el->el_cursor.v][el->el_cursor.h++]
1106 if (el->el_cursor.h >= el->el_terminal.t_size.h) {
1107 /* if we must overflow */
1108 el->el_cursor.h = 0;
1111 * If we would overflow (input is longer than terminal size),
1112 * emulate scroll by dropping first line and shuffling the rest.
1113 * We do this via pointer shuffling - it's safe in this case
1114 * and we avoid memcpy().
1116 if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) {
1117 int i, lins = el->el_terminal.t_size.v;
1119 lastline = el->el_display[0];
1120 for(i = 1; i < lins; i++)
1121 el->el_display[i - 1] = el->el_display[i];
1123 el->el_display[i - 1] = lastline;
1126 lastline = el->el_display[++el->el_refresh.r_oldcv];
1128 re__copy_and_pad(lastline, L"", (size_t)el->el_terminal.t_size.h);
1130 if (EL_HAS_AUTO_MARGINS) {
1131 if (EL_HAS_MAGIC_MARGINS) {
1132 terminal__putc(el, ' ');
1133 terminal__putc(el, '\b');
1136 terminal__putc(el, '\r');
1137 terminal__putc(el, '\n');
1144 * we added just one char, handle it fast.
1145 * Assumes that screen cursor == real cursor
1147 libedit_private void
1148 re_fastaddc(EditLine *el)
1153 c = el->el_line.cursor[-1];
1155 if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1156 re_refresh(el); /* too hard to handle */
1159 rhdiff = el->el_terminal.t_size.h - el->el_cursor.h -
1160 el->el_rprompt.p_pos.h;
1161 if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1162 re_refresh(el); /* clear out rprompt if less than 1 char gap */
1164 } /* else (only do at end of line, no TAB) */
1165 switch (ct_chr_class(c)) {
1166 case CHTYPE_TAB: /* already handled, should never happen here */
1172 case CHTYPE_ASCIICTL:
1173 case CHTYPE_NONPRINT: {
1174 wchar_t visbuf[VISUAL_WIDTH_MAX];
1176 ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
1177 for (i = 0; n-- > 0; ++i)
1178 re_fastputc(el, visbuf[i]);
1182 terminal__flush(el);
1186 /* re_clear_display():
1187 * clear the screen buffers so that new new prompt starts fresh.
1189 libedit_private void
1190 re_clear_display(EditLine *el)
1194 el->el_cursor.v = 0;
1195 el->el_cursor.h = 0;
1196 for (i = 0; i < el->el_terminal.t_size.v; i++)
1197 el->el_display[i][0] = '\0';
1198 el->el_refresh.r_oldcv = 0;
1202 /* re_clear_lines():
1203 * Make sure all lines are *really* blank
1205 libedit_private void
1206 re_clear_lines(EditLine *el)
1211 for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
1212 /* for each line on the screen */
1213 terminal_move_to_line(el, i);
1214 terminal_move_to_char(el, 0);
1215 terminal_clear_EOL(el, el->el_terminal.t_size.h);
1218 terminal_move_to_line(el, el->el_refresh.r_oldcv);
1219 /* go to last line */
1220 terminal__putc(el, '\r'); /* go to BOL */
1221 terminal__putc(el, '\n'); /* go to new line */