1 /* $NetBSD: refresh.c,v 1.51 2016/05/09 21:46:56 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.51 2016/05/09 21:46:56 christos 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);
160 * Draw the character given
163 re_putc(EditLine
*el
, wint_t c
, int shift
)
165 int i
, w
= wcwidth(c
);
166 ELRE_DEBUG(1, (__F
, "printing %5x '%lc'\r\n", c
, c
));
170 while (shift
&& (el
->el_refresh
.r_cursor
.h
+ w
> el
->el_terminal
.t_size
.h
))
173 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
]
174 [el
->el_refresh
.r_cursor
.h
] = c
;
175 /* assumes !shift is only used for single-column chars */
178 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
]
179 [el
->el_refresh
.r_cursor
.h
+ i
] = MB_FILL_CHAR
;
184 el
->el_refresh
.r_cursor
.h
+= w
; /* advance to next place */
185 if (el
->el_refresh
.r_cursor
.h
>= el
->el_terminal
.t_size
.h
) {
186 /* assure end of line */
187 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
][el
->el_terminal
.t_size
.h
]
195 * draws the new virtual screen image from the current input
196 * line, then goes line-by-line changing the real image to the new
197 * virtual image. The routine to re-draw a line can be replaced
198 * easily in hopes of a smarter one being placed there.
201 re_refresh(EditLine
*el
)
210 ELRE_DEBUG(1, (__F
, "el->el_line.buffer = :%ls:\r\n",
211 el
->el_line
.buffer
));
213 /* reset the Drawing cursor */
214 el
->el_refresh
.r_cursor
.h
= 0;
215 el
->el_refresh
.r_cursor
.v
= 0;
217 /* temporarily draw rprompt to calculate its size */
218 prompt_print(el
, EL_RPROMPT
);
220 /* reset the Drawing cursor */
221 el
->el_refresh
.r_cursor
.h
= 0;
222 el
->el_refresh
.r_cursor
.v
= 0;
224 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
225 if (el
->el_map
.current
== el
->el_map
.alt
226 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
227 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
229 el
->el_line
.cursor
= el
->el_line
.lastchar
;
232 cur
.h
= -1; /* set flag in case I'm not set */
235 prompt_print(el
, EL_PROMPT
);
237 /* draw the current input buffer */
239 termsz
= el
->el_terminal
.t_size
.h
* el
->el_terminal
.t_size
.v
;
240 if (el
->el_line
.lastchar
- el
->el_line
.buffer
> termsz
) {
242 * If line is longer than terminal, process only part
243 * of line which would influence display.
245 size_t rem
= (el
->el_line
.lastchar
-el
->el_line
.buffer
)%termsz
;
247 st
= el
->el_line
.lastchar
- rem
248 - (termsz
- (((rem
/ el
->el_terminal
.t_size
.v
) - 1)
249 * el
->el_terminal
.t_size
.v
));
252 st
= el
->el_line
.buffer
;
254 for (cp
= st
; cp
< el
->el_line
.lastchar
; cp
++) {
255 if (cp
== el
->el_line
.cursor
) {
256 int w
= wcwidth(*cp
);
258 cur
.h
= el
->el_refresh
.r_cursor
.h
;
259 cur
.v
= el
->el_refresh
.r_cursor
.v
;
260 /* handle being at a linebroken doublewidth char */
261 if (w
> 1 && el
->el_refresh
.r_cursor
.h
+ w
>
262 el
->el_terminal
.t_size
.h
) {
270 if (cur
.h
== -1) { /* if I haven't been set yet, I'm at the end */
271 cur
.h
= el
->el_refresh
.r_cursor
.h
;
272 cur
.v
= el
->el_refresh
.r_cursor
.v
;
274 rhdiff
= el
->el_terminal
.t_size
.h
- el
->el_refresh
.r_cursor
.h
-
275 el
->el_rprompt
.p_pos
.h
;
276 if (el
->el_rprompt
.p_pos
.h
&& !el
->el_rprompt
.p_pos
.v
&&
277 !el
->el_refresh
.r_cursor
.v
&& rhdiff
> 1) {
279 * have a right-hand side prompt that will fit
280 * on the end of the first line with at least
281 * one character gap to the input buffer.
283 while (--rhdiff
> 0) /* pad out with spaces */
285 prompt_print(el
, EL_RPROMPT
);
287 el
->el_rprompt
.p_pos
.h
= 0; /* flag "not using rprompt" */
288 el
->el_rprompt
.p_pos
.v
= 0;
291 re_putc(el
, '\0', 0); /* make line ended with NUL, no cursor shift */
293 el
->el_refresh
.r_newcv
= el
->el_refresh
.r_cursor
.v
;
296 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
297 el
->el_terminal
.t_size
.h
, el
->el_refresh
.r_cursor
.h
,
298 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 wcslen should be safe even with MB_FILL_CHARs */
325 terminal_clear_EOL(el
, (int) wcslen(el
->el_display
[i
]));
327 terminal_overwrite(el
, L
"C\b", 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 wchar_t *d
, int dat
, int dlen
, wchar_t *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
, &el
->el_scratch
)));
375 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", ct_encode_string(s
,
378 /* open up the space for num chars */
384 d
[dlen
] = '\0'; /* just in case */
388 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
389 num
, dat
, dlen
, ct_encode_string(d
, &el
->el_scratch
)));
390 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", ct_encode_string(s
,
393 /* copy the characters */
394 for (a
= d
+ dat
; (a
< d
+ dlen
) && (num
> 0); num
--)
398 /* ct_encode_string() uses a static buffer, so we can't conveniently
399 * encode both d & s here */
401 (__F
, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
402 num
, dat
, dlen
, d
, s
));
403 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", s
));
409 * delete num characters d at dat, maximum length of d is dlen
413 re_delete(EditLine
*el
__attribute__((__unused__
)),
414 wchar_t *d
, int dat
, int dlen
, int num
)
420 if (dat
+ num
>= dlen
) {
425 (__F
, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
426 num
, dat
, dlen
, ct_encode_string(d
, &el
->el_scratch
)));
428 /* open up the space for num chars */
434 d
[dlen
] = '\0'; /* just in case */
437 (__F
, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
438 num
, dat
, dlen
, ct_encode_string(d
, &el
->el_scratch
)));
443 * Like strncpy without padding.
446 re__strncopy(wchar_t *a
, wchar_t *b
, size_t n
)
454 * Find the number of characters we need to clear till the end of line
455 * in order to make sure that we have cleared the previous contents of
456 * the line. fx and sx is the number of characters inserted or deleted
457 * in the first or second diff, diff is the difference between the
458 * number of characters between the new and old line.
461 re_clear_eol(EditLine
*el
, int fx
, int sx
, int diff
)
464 ELRE_DEBUG(1, (__F
, "re_clear_eol sx %d, fx %d, diff %d\n",
476 ELRE_DEBUG(1, (__F
, "re_clear_eol %d\n", diff
));
477 terminal_clear_EOL(el
, diff
);
480 /*****************************************************************
481 re_update_line() is based on finding the middle difference of each line
484 /old first difference
485 /beginning of line | /old last same /old EOL
487 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
488 new: eddie> Oh, my little buggy says to me, as lurgid as
490 \beginning of line | \new last same \new end of line
491 \new first difference
493 all are character pointers for the sake of speed. Special cases for
494 no differences, as well as for end of line additions must be handled.
495 **************************************************************** */
497 /* Minimum at which doing an insert it "worth it". This should be about
498 * half the "cost" of going into insert mode, inserting a character, and
499 * going back out. This should really be calculated from the termcap
500 * data... For the moment, a good number for ANSI terminals.
502 #define MIN_END_KEEP 4
505 re_update_line(EditLine
*el
, wchar_t *old
, wchar_t *new, int i
)
507 wchar_t *o
, *n
, *p
, c
;
508 wchar_t *ofd
, *ols
, *oe
, *nfd
, *nls
, *ne
;
509 wchar_t *osb
, *ose
, *nsb
, *nse
;
516 for (o
= old
, n
= new; *o
&& (*o
== *n
); o
++, n
++)
522 * Find the end of both old and new
527 * Remove any trailing blanks off of the end, being careful not to
528 * back up past the beginning.
541 /* remove blanks from end of new */
551 * if no diff, continue to next line of redraw
553 if (*ofd
== '\0' && *nfd
== '\0') {
554 ELRE_DEBUG(1, (__F
, "no difference.\r\n"));
558 * find last same pointer
560 while ((o
> ofd
) && (n
> nfd
) && (*--o
== *--n
))
566 * find same beginning and same end
574 * case 1: insert: scan from nfd to nls looking for *ofd
577 for (c
= *ofd
, n
= nfd
; n
< nls
; n
++) {
580 p
< nls
&& o
< ols
&& *o
== *p
;
584 * if the new match is longer and it's worth
585 * keeping, then we take it
587 if (((nse
- nsb
) < (p
- n
)) &&
588 (2 * (p
- n
) > n
- nfd
)) {
598 * case 2: delete: scan from ofd to ols looking for *nfd
601 for (c
= *nfd
, o
= ofd
; o
< ols
; o
++) {
604 p
< ols
&& n
< nls
&& *p
== *n
;
608 * if the new match is longer and it's worth
609 * keeping, then we take it
611 if (((ose
- osb
) < (p
- o
)) &&
612 (2 * (p
- o
) > o
- ofd
)) {
622 * Pragmatics I: If old trailing whitespace or not enough characters to
623 * save to be worth it, then don't save the last same info.
625 if ((oe
- ols
) < MIN_END_KEEP
) {
630 * Pragmatics II: if the terminal isn't smart enough, make the data
631 * dumber so the smart update doesn't try anything fancy
635 * fx is the number of characters we need to insert/delete: in the
636 * beginning to bring the two same begins together
638 fx
= (int)((nsb
- nfd
) - (osb
- ofd
));
640 * sx is the number of characters we need to insert/delete: in the
641 * end to bring the two same last parts together
643 sx
= (int)((nls
- nse
) - (ols
- ose
));
645 if (!EL_CAN_INSERT
) {
656 if ((ols
- ofd
) < (nls
- nfd
)) {
661 if (!EL_CAN_DELETE
) {
672 if ((ols
- ofd
) > (nls
- nfd
)) {
678 * Pragmatics III: make sure the middle shifted pointers are correct if
679 * they don't point to anything (we may have moved ols or nls).
681 /* if the change isn't worth it, don't bother */
682 /* was: if (osb == ose) */
683 if ((ose
- osb
) < MIN_END_KEEP
) {
690 * Now that we are done with pragmatics we recompute fx, sx
692 fx
= (int)((nsb
- nfd
) - (osb
- ofd
));
693 sx
= (int)((nls
- nse
) - (ols
- ose
));
695 ELRE_DEBUG(1, (__F
, "fx %d, sx %d\n", fx
, sx
));
696 ELRE_DEBUG(1, (__F
, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
697 ofd
- old
, osb
- old
, ose
- old
, ols
- old
, oe
- old
));
698 ELRE_DEBUG(1, (__F
, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
699 nfd
- new, nsb
- new, nse
- new, nls
- new, ne
- new));
701 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
703 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
705 re_printstr(el
, "old- oe", old
, oe
);
706 re_printstr(el
, "new- ne", new, ne
);
707 re_printstr(el
, "old-ofd", old
, ofd
);
708 re_printstr(el
, "new-nfd", new, nfd
);
709 re_printstr(el
, "ofd-osb", ofd
, osb
);
710 re_printstr(el
, "nfd-nsb", nfd
, nsb
);
711 re_printstr(el
, "osb-ose", osb
, ose
);
712 re_printstr(el
, "nsb-nse", nsb
, nse
);
713 re_printstr(el
, "ose-ols", ose
, ols
);
714 re_printstr(el
, "nse-nls", nse
, nls
);
715 re_printstr(el
, "ols- oe", ols
, oe
);
716 re_printstr(el
, "nls- ne", nls
, ne
);
717 #endif /* DEBUG_REFRESH */
720 * el_cursor.v to this line i MUST be in this routine so that if we
721 * don't have to change the line, we don't move to it. el_cursor.h to
724 terminal_move_to_line(el
, i
);
727 * at this point we have something like this:
729 * /old /ofd /osb /ose /ols /oe
730 * v.....................v v..................v v........v
731 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
732 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
733 * ^.....................^ ^..................^ ^........^
734 * \new \nfd \nsb \nse \nls \ne
736 * fx is the difference in length between the chars between nfd and
737 * nsb, and the chars between ofd and osb, and is thus the number of
738 * characters to delete if < 0 (new is shorter than old, as above),
739 * or insert (new is longer than short).
741 * sx is the same for the second differences.
745 * if we have a net insert on the first difference, AND inserting the
746 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
747 * character (which is ne if nls != ne, otherwise is nse) off the edge
748 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
749 * so that we keep everything we need to.
753 * if the last same is the same like the end, there is no last same
754 * part, otherwise we want to keep the last same part set p to the
755 * last useful old character
757 p
= (ols
!= oe
) ? oe
: ose
;
760 * if (There is a diffence in the beginning) && (we need to insert
761 * characters) && (the number of characters to insert is less than
763 * We need to do an insert!
764 * else if (we need to delete characters)
765 * We need to delete characters!
767 * No insert or delete
769 if ((nsb
!= nfd
) && fx
> 0 &&
770 ((p
- old
) + fx
<= el
->el_terminal
.t_size
.h
)) {
772 (__F
, "first diff insert at %td...\r\n", nfd
- new));
774 * Move to the first char to insert, where the first diff is.
776 terminal_move_to_char(el
, (int)(nfd
- new));
778 * Check if we have stuff to keep at end
781 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
783 * insert fx chars of new starting at nfd
786 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
787 "ERROR: cannot insert in early first diff\n"));
788 terminal_insertwrite(el
, nfd
, fx
);
789 re_insert(el
, old
, (int)(ofd
- old
),
790 el
->el_terminal
.t_size
.h
, nfd
, fx
);
793 * write (nsb-nfd) - fx chars of new starting at
796 len
= (size_t) ((nsb
- nfd
) - fx
);
797 terminal_overwrite(el
, (nfd
+ fx
), len
);
798 re__strncopy(ofd
+ fx
, nfd
+ fx
, len
);
800 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
801 len
= (size_t)(nsb
- nfd
);
802 terminal_overwrite(el
, nfd
, len
);
803 re__strncopy(ofd
, nfd
, len
);
811 (__F
, "first diff delete at %td...\r\n", ofd
- old
));
813 * move to the first char to delete where the first diff is
815 terminal_move_to_char(el
, (int)(ofd
- old
));
817 * Check if we have stuff to save
820 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
822 * fx is less than zero *always* here but we check
826 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
827 "ERROR: cannot delete in first diff\n"));
828 terminal_deletechars(el
, -fx
);
829 re_delete(el
, old
, (int)(ofd
- old
),
830 el
->el_terminal
.t_size
.h
, -fx
);
833 * write (nsb-nfd) chars of new starting at nfd
835 len
= (size_t) (nsb
- nfd
);
836 terminal_overwrite(el
, nfd
, len
);
837 re__strncopy(ofd
, nfd
, len
);
841 "but with nothing left to save\r\n"));
843 * write (nsb-nfd) chars of new starting at nfd
845 terminal_overwrite(el
, nfd
, (size_t)(nsb
- nfd
));
846 re_clear_eol(el
, fx
, sx
,
847 (int)((oe
- old
) - (ne
- new)));
856 if (sx
< 0 && (ose
- old
) + fx
< el
->el_terminal
.t_size
.h
) {
858 "second diff delete at %td...\r\n", (ose
- old
) + fx
));
860 * Check if we have stuff to delete
863 * fx is the number of characters inserted (+) or deleted (-)
866 terminal_move_to_char(el
, (int)((ose
- old
) + fx
));
868 * Check if we have stuff to save
871 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
873 * Again a duplicate test.
876 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
877 "ERROR: cannot delete in second diff\n"));
878 terminal_deletechars(el
, -sx
);
881 * write (nls-nse) chars of new starting at nse
883 terminal_overwrite(el
, nse
, (size_t)(nls
- nse
));
886 "but with nothing left to save\r\n"));
887 terminal_overwrite(el
, nse
, (size_t)(nls
- nse
));
888 re_clear_eol(el
, fx
, sx
,
889 (int)((oe
- old
) - (ne
- new)));
893 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
895 if ((nsb
!= nfd
) && (osb
- ofd
) <= (nsb
- nfd
) && (fx
== 0)) {
896 ELRE_DEBUG(1, (__F
, "late first diff insert at %td...\r\n",
899 terminal_move_to_char(el
, (int)(nfd
- new));
901 * Check if we have stuff to keep at the end
904 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
906 * We have to recalculate fx here because we set it
907 * to zero above as a flag saying that we hadn't done
908 * an early first insert.
910 fx
= (int)((nsb
- nfd
) - (osb
- ofd
));
913 * insert fx chars of new starting at nfd
915 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
916 "ERROR: cannot insert in late first diff\n"));
917 terminal_insertwrite(el
, nfd
, fx
);
918 re_insert(el
, old
, (int)(ofd
- old
),
919 el
->el_terminal
.t_size
.h
, nfd
, fx
);
922 * write (nsb-nfd) - fx chars of new starting at
925 len
= (size_t) ((nsb
- nfd
) - fx
);
926 terminal_overwrite(el
, (nfd
+ fx
), len
);
927 re__strncopy(ofd
+ fx
, nfd
+ fx
, len
);
929 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
930 len
= (size_t) (nsb
- nfd
);
931 terminal_overwrite(el
, nfd
, len
);
932 re__strncopy(ofd
, nfd
, len
);
936 * line is now NEW up to nse
940 "second diff insert at %d...\r\n", (int)(nse
- new)));
941 terminal_move_to_char(el
, (int)(nse
- new));
943 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
945 /* insert sx chars of new starting at nse */
946 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
947 "ERROR: cannot insert in second diff\n"));
948 terminal_insertwrite(el
, nse
, sx
);
951 * write (nls-nse) - sx chars of new starting at
954 terminal_overwrite(el
, (nse
+ sx
),
955 (size_t)((nls
- nse
) - sx
));
957 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
958 terminal_overwrite(el
, nse
, (size_t)(nls
- nse
));
961 * No need to do a clear-to-end here because we were
962 * doing a second insert, so we will have over
963 * written all of the old string.
967 ELRE_DEBUG(1, (__F
, "done.\r\n"));
971 /* re__copy_and_pad():
972 * Copy string and pad with spaces
975 re__copy_and_pad(wchar_t *dst
, const wchar_t *src
, size_t width
)
979 for (i
= 0; i
< width
; i
++) {
985 for (; i
< width
; i
++)
992 /* re_refresh_cursor():
993 * Move to the new cursor position
996 re_refresh_cursor(EditLine
*el
)
1001 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
1002 if (el
->el_map
.current
== el
->el_map
.alt
1003 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
1004 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
1006 el
->el_line
.cursor
= el
->el_line
.lastchar
;
1009 /* first we must find where the cursor is... */
1010 h
= el
->el_prompt
.p_pos
.h
;
1011 v
= el
->el_prompt
.p_pos
.v
;
1012 th
= el
->el_terminal
.t_size
.h
; /* optimize for speed */
1014 /* do input buffer to el->el_line.cursor */
1015 for (cp
= el
->el_line
.buffer
; cp
< el
->el_line
.cursor
; cp
++) {
1016 switch (ct_chr_class(*cp
)) {
1017 case CHTYPE_NL
: /* handle newline in data part too */
1021 case CHTYPE_TAB
: /* if a tab, to next tab stop */
1027 if (w
> 1 && h
+ w
> th
) { /* won't fit on line */
1031 h
+= ct_visual_width(*cp
);
1035 if (h
>= th
) { /* check, extra long tabs picked up here also */
1040 /* if we have a next character, and it's a doublewidth one, we need to
1041 * check whether we need to linebreak for it to fit */
1042 if (cp
< el
->el_line
.lastchar
&& (w
= wcwidth(*cp
)) > 1)
1049 terminal_move_to_line(el
, v
);
1050 terminal_move_to_char(el
, h
);
1051 terminal__flush(el
);
1056 * Add a character fast.
1059 re_fastputc(EditLine
*el
, wint_t c
)
1062 while (w
> 1 && el
->el_cursor
.h
+ w
> el
->el_terminal
.t_size
.h
)
1063 re_fastputc(el
, ' ');
1065 terminal__putc(el
, c
);
1066 el
->el_display
[el
->el_cursor
.v
][el
->el_cursor
.h
++] = c
;
1068 el
->el_display
[el
->el_cursor
.v
][el
->el_cursor
.h
++]
1071 if (el
->el_cursor
.h
>= el
->el_terminal
.t_size
.h
) {
1072 /* if we must overflow */
1073 el
->el_cursor
.h
= 0;
1076 * If we would overflow (input is longer than terminal size),
1077 * emulate scroll by dropping first line and shuffling the rest.
1078 * We do this via pointer shuffling - it's safe in this case
1079 * and we avoid memcpy().
1081 if (el
->el_cursor
.v
+ 1 >= el
->el_terminal
.t_size
.v
) {
1082 int i
, lins
= el
->el_terminal
.t_size
.v
;
1083 wchar_t *firstline
= el
->el_display
[0];
1085 for(i
= 1; i
< lins
; i
++)
1086 el
->el_display
[i
- 1] = el
->el_display
[i
];
1088 re__copy_and_pad(firstline
, L
"", (size_t)0);
1089 el
->el_display
[i
- 1] = firstline
;
1092 el
->el_refresh
.r_oldcv
++;
1094 if (EL_HAS_AUTO_MARGINS
) {
1095 if (EL_HAS_MAGIC_MARGINS
) {
1096 terminal__putc(el
, ' ');
1097 terminal__putc(el
, '\b');
1100 terminal__putc(el
, '\r');
1101 terminal__putc(el
, '\n');
1108 * we added just one char, handle it fast.
1109 * Assumes that screen cursor == real cursor
1111 libedit_private
void
1112 re_fastaddc(EditLine
*el
)
1117 c
= el
->el_line
.cursor
[-1];
1119 if (c
== '\t' || el
->el_line
.cursor
!= el
->el_line
.lastchar
) {
1120 re_refresh(el
); /* too hard to handle */
1123 rhdiff
= el
->el_terminal
.t_size
.h
- el
->el_cursor
.h
-
1124 el
->el_rprompt
.p_pos
.h
;
1125 if (el
->el_rprompt
.p_pos
.h
&& rhdiff
< 3) {
1126 re_refresh(el
); /* clear out rprompt if less than 1 char gap */
1128 } /* else (only do at end of line, no TAB) */
1129 switch (ct_chr_class(c
)) {
1130 case CHTYPE_TAB
: /* already handled, should never happen here */
1136 case CHTYPE_ASCIICTL
:
1137 case CHTYPE_NONPRINT
: {
1138 wchar_t visbuf
[VISUAL_WIDTH_MAX
];
1140 ct_visual_char(visbuf
, VISUAL_WIDTH_MAX
, c
);
1141 for (i
= 0; n
-- > 0; ++i
)
1142 re_fastputc(el
, visbuf
[i
]);
1146 terminal__flush(el
);
1150 /* re_clear_display():
1151 * clear the screen buffers so that new new prompt starts fresh.
1153 libedit_private
void
1154 re_clear_display(EditLine
*el
)
1158 el
->el_cursor
.v
= 0;
1159 el
->el_cursor
.h
= 0;
1160 for (i
= 0; i
< el
->el_terminal
.t_size
.v
; i
++)
1161 el
->el_display
[i
][0] = '\0';
1162 el
->el_refresh
.r_oldcv
= 0;
1166 /* re_clear_lines():
1167 * Make sure all lines are *really* blank
1169 libedit_private
void
1170 re_clear_lines(EditLine
*el
)
1175 for (i
= el
->el_refresh
.r_oldcv
; i
>= 0; i
--) {
1176 /* for each line on the screen */
1177 terminal_move_to_line(el
, i
);
1178 terminal_move_to_char(el
, 0);
1179 terminal_clear_EOL(el
, el
->el_terminal
.t_size
.h
);
1182 terminal_move_to_line(el
, el
->el_refresh
.r_oldcv
);
1183 /* go to last line */
1184 terminal__putc(el
, '\r'); /* go to BOL */
1185 terminal__putc(el
, '\n'); /* go to new line */