1 /* $OpenBSD: refresh.c,v 1.21 2017/07/26 12:10:56 schwarze Exp $ */
2 /* $NetBSD: refresh.c,v 1.50 2016/05/02 16:35:17 christos Exp $ */
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * refresh.c: Lower level screen refreshing functions
47 static void re_nextline(EditLine
*);
48 static void re_addc(EditLine
*, wint_t);
49 static void re_update_line(EditLine
*, wchar_t *, wchar_t *, int);
50 static void re_insert (EditLine
*, wchar_t *, int, int, wchar_t *, int);
51 static void re_delete(EditLine
*, wchar_t *, int, int, int);
52 static void re_fastputc(EditLine
*, wint_t);
53 static void re_clear_eol(EditLine
*, int, int, int);
54 static void re__strncopy(wchar_t *, wchar_t *, size_t);
55 static void re__copy_and_pad(wchar_t *, const wchar_t *, size_t);
58 static void re_printstr(EditLine
*, const char *, wchar_t *, wchar_t *);
59 #define __F el->el_errfile
60 #define ELRE_ASSERT(a, b, c) do \
61 if (/*CONSTCOND*/ a) { \
65 while (/*CONSTCOND*/0)
66 #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
69 * Print a string on the debugging pty
72 re_printstr(EditLine
*el
, const char *str
, wchar_t *f
, wchar_t *t
)
75 ELRE_DEBUG(1, (__F
, "%s:\"", str
));
77 ELRE_DEBUG(1, (__F
, "%c", *f
++ & 0177));
78 ELRE_DEBUG(1, (__F
, "\"\r\n"));
81 #define ELRE_ASSERT(a, b, c)
82 #define ELRE_DEBUG(a, b)
86 * Move to the next line or scroll
89 re_nextline(EditLine
*el
)
91 el
->el_refresh
.r_cursor
.h
= 0; /* reset it. */
94 * If we would overflow (input is longer than terminal size),
95 * emulate scroll by dropping first line and shuffling the rest.
96 * We do this via pointer shuffling - it's safe in this case
97 * and we avoid memcpy().
99 if (el
->el_refresh
.r_cursor
.v
+ 1 >= el
->el_terminal
.t_size
.v
) {
100 int i
, lins
= el
->el_terminal
.t_size
.v
;
101 wchar_t *firstline
= el
->el_vdisplay
[0];
103 for(i
= 1; i
< lins
; i
++)
104 el
->el_vdisplay
[i
- 1] = el
->el_vdisplay
[i
];
106 firstline
[0] = '\0'; /* empty the string */
107 el
->el_vdisplay
[i
- 1] = firstline
;
109 el
->el_refresh
.r_cursor
.v
++;
111 ELRE_ASSERT(el
->el_refresh
.r_cursor
.v
>= el
->el_terminal
.t_size
.v
,
112 (__F
, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
113 el
->el_refresh
.r_cursor
.v
, el
->el_terminal
.t_size
.v
),
118 * Draw c, expanding tabs, control chars etc.
121 re_addc(EditLine
*el
, wint_t c
)
123 switch (ct_chr_class(c
)) {
124 case CHTYPE_TAB
: /* expand the tab */
127 if ((el
->el_refresh
.r_cursor
.h
& 07) == 0)
128 break; /* go until tab stop */
132 int oldv
= el
->el_refresh
.r_cursor
.v
;
133 re_putc(el
, '\0', 0); /* assure end of line */
134 if (oldv
== el
->el_refresh
.r_cursor
.v
) /* XXX */
142 wchar_t visbuf
[VISUAL_WIDTH_MAX
];
144 ct_visual_char(visbuf
, VISUAL_WIDTH_MAX
, c
);
145 for (i
= 0; n
-- > 0; ++i
)
146 re_putc(el
, visbuf
[i
], 1);
154 * Draw the character given
157 re_putc(EditLine
*el
, wint_t c
, int shift
)
159 int i
, w
= wcwidth(c
);
160 ELRE_DEBUG(1, (__F
, "printing %5x '%lc'\r\n", c
, c
));
164 while (shift
&& (el
->el_refresh
.r_cursor
.h
+ w
> el
->el_terminal
.t_size
.h
))
167 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
]
168 [el
->el_refresh
.r_cursor
.h
] = c
;
169 /* assumes !shift is only used for single-column chars */
172 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
]
173 [el
->el_refresh
.r_cursor
.h
+ i
] = MB_FILL_CHAR
;
178 el
->el_refresh
.r_cursor
.h
+= w
; /* advance to next place */
179 if (el
->el_refresh
.r_cursor
.h
>= el
->el_terminal
.t_size
.h
) {
180 /* assure end of line */
181 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
][el
->el_terminal
.t_size
.h
]
189 * draws the new virtual screen image from the current input
190 * line, then goes line-by-line changing the real image to the new
191 * virtual image. The routine to re-draw a line can be replaced
192 * easily in hopes of a smarter one being placed there.
195 re_refresh(EditLine
*el
)
204 ELRE_DEBUG(1, (__F
, "el->el_line.buffer = :%ls:\r\n",
205 el
->el_line
.buffer
));
207 /* reset the Drawing cursor */
208 el
->el_refresh
.r_cursor
.h
= 0;
209 el
->el_refresh
.r_cursor
.v
= 0;
211 /* temporarily draw rprompt to calculate its size */
212 prompt_print(el
, EL_RPROMPT
);
214 /* reset the Drawing cursor */
215 el
->el_refresh
.r_cursor
.h
= 0;
216 el
->el_refresh
.r_cursor
.v
= 0;
218 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
219 if (el
->el_map
.current
== el
->el_map
.alt
220 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
221 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
223 el
->el_line
.cursor
= el
->el_line
.lastchar
;
226 cur
.h
= -1; /* set flag in case I'm not set */
229 prompt_print(el
, EL_PROMPT
);
231 /* draw the current input buffer */
233 termsz
= el
->el_terminal
.t_size
.h
* el
->el_terminal
.t_size
.v
;
234 if (el
->el_line
.lastchar
- el
->el_line
.buffer
> termsz
) {
236 * If line is longer than terminal, process only part
237 * of line which would influence display.
239 size_t rem
= (el
->el_line
.lastchar
-el
->el_line
.buffer
)%termsz
;
241 st
= el
->el_line
.lastchar
- rem
242 - (termsz
- (((rem
/ el
->el_terminal
.t_size
.v
) - 1)
243 * el
->el_terminal
.t_size
.v
));
246 st
= el
->el_line
.buffer
;
248 for (cp
= st
; cp
< el
->el_line
.lastchar
; cp
++) {
249 if (cp
== el
->el_line
.cursor
) {
250 int w
= wcwidth(*cp
);
252 cur
.h
= el
->el_refresh
.r_cursor
.h
;
253 cur
.v
= el
->el_refresh
.r_cursor
.v
;
254 /* handle being at a linebroken doublewidth char */
255 if (w
> 1 && el
->el_refresh
.r_cursor
.h
+ w
>
256 el
->el_terminal
.t_size
.h
) {
264 if (cur
.h
== -1) { /* if I haven't been set yet, I'm at the end */
265 cur
.h
= el
->el_refresh
.r_cursor
.h
;
266 cur
.v
= el
->el_refresh
.r_cursor
.v
;
268 rhdiff
= el
->el_terminal
.t_size
.h
- el
->el_refresh
.r_cursor
.h
-
269 el
->el_rprompt
.p_pos
.h
;
270 if (el
->el_rprompt
.p_pos
.h
&& !el
->el_rprompt
.p_pos
.v
&&
271 !el
->el_refresh
.r_cursor
.v
&& rhdiff
> 1) {
273 * have a right-hand side prompt that will fit
274 * on the end of the first line with at least
275 * one character gap to the input buffer.
277 while (--rhdiff
> 0) /* pad out with spaces */
279 prompt_print(el
, EL_RPROMPT
);
281 el
->el_rprompt
.p_pos
.h
= 0; /* flag "not using rprompt" */
282 el
->el_rprompt
.p_pos
.v
= 0;
285 re_putc(el
, '\0', 0); /* make line ended with NUL, no cursor shift */
287 el
->el_refresh
.r_newcv
= el
->el_refresh
.r_cursor
.v
;
290 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
291 el
->el_terminal
.t_size
.h
, el
->el_refresh
.r_cursor
.h
,
292 el
->el_refresh
.r_cursor
.v
, ct_encode_string(el
->el_vdisplay
[0],
295 ELRE_DEBUG(1, (__F
, "updating %d lines.\r\n", el
->el_refresh
.r_newcv
));
296 for (i
= 0; i
<= el
->el_refresh
.r_newcv
; i
++) {
297 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
298 re_update_line(el
, el
->el_display
[i
], el
->el_vdisplay
[i
], i
);
301 * Copy the new line to be the current one, and pad out with
302 * spaces to the full width of the terminal so that if we try
303 * moving the cursor by writing the character that is at the
304 * end of the screen line, it won't be a NUL or some old
307 re__copy_and_pad(el
->el_display
[i
], el
->el_vdisplay
[i
],
308 (size_t) el
->el_terminal
.t_size
.h
);
311 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
312 el
->el_refresh
.r_cursor
.v
, el
->el_refresh
.r_oldcv
, i
));
314 if (el
->el_refresh
.r_oldcv
> el
->el_refresh
.r_newcv
)
315 for (; i
<= el
->el_refresh
.r_oldcv
; i
++) {
316 terminal_move_to_line(el
, i
);
317 terminal_move_to_char(el
, 0);
318 /* This wcslen should be safe even with MB_FILL_CHARs */
319 terminal_clear_EOL(el
, (int) wcslen(el
->el_display
[i
]));
321 terminal_overwrite(el
, L
"C\b", 2);
322 #endif /* DEBUG_REFRESH */
323 el
->el_display
[i
][0] = '\0';
326 el
->el_refresh
.r_oldcv
= el
->el_refresh
.r_newcv
; /* set for next time */
328 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
329 el
->el_refresh
.r_cursor
.h
, el
->el_refresh
.r_cursor
.v
,
331 terminal_move_to_line(el
, cur
.v
); /* go to where the cursor is */
332 terminal_move_to_char(el
, cur
.h
);
337 * used to go to last used screen line
340 re_goto_bottom(EditLine
*el
)
343 terminal_move_to_line(el
, el
->el_refresh
.r_oldcv
);
344 terminal__putc(el
, '\n');
345 re_clear_display(el
);
351 * insert num characters of s into d (in front of the character)
352 * at dat, maximum length of d is dlen
356 re_insert(EditLine
*el
__attribute__((__unused__
)),
357 wchar_t *d
, int dat
, int dlen
, wchar_t *s
, int num
)
363 if (num
> dlen
- dat
)
367 (__F
, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
368 num
, dat
, dlen
, ct_encode_string(d
, &el
->el_scratch
)));
369 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", ct_encode_string(s
,
372 /* open up the space for num chars */
378 d
[dlen
] = '\0'; /* just in case */
382 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
383 num
, dat
, dlen
, ct_encode_string(d
, &el
->el_scratch
)));
384 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", ct_encode_string(s
,
387 /* copy the characters */
388 for (a
= d
+ dat
; (a
< d
+ dlen
) && (num
> 0); num
--)
392 /* ct_encode_string() uses a static buffer, so we can't conveniently
393 * encode both d & s here */
395 (__F
, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
396 num
, dat
, dlen
, d
, s
));
397 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", s
));
403 * delete num characters d at dat, maximum length of d is dlen
407 re_delete(EditLine
*el
__attribute__((__unused__
)),
408 wchar_t *d
, int dat
, int dlen
, int num
)
414 if (dat
+ num
>= dlen
) {
419 (__F
, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
420 num
, dat
, dlen
, ct_encode_string(d
, &el
->el_scratch
)));
422 /* open up the space for num chars */
428 d
[dlen
] = '\0'; /* just in case */
431 (__F
, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
432 num
, dat
, dlen
, ct_encode_string(d
, &el
->el_scratch
)));
437 * Like strncpy without padding.
440 re__strncopy(wchar_t *a
, wchar_t *b
, size_t n
)
448 * Find the number of characters we need to clear till the end of line
449 * in order to make sure that we have cleared the previous contents of
450 * the line. fx and sx is the number of characters inserted or deleted
451 * in the first or second diff, diff is the difference between the
452 * number of characters between the new and old line.
455 re_clear_eol(EditLine
*el
, int fx
, int sx
, int diff
)
458 ELRE_DEBUG(1, (__F
, "re_clear_eol sx %d, fx %d, diff %d\n",
470 ELRE_DEBUG(1, (__F
, "re_clear_eol %d\n", diff
));
471 terminal_clear_EOL(el
, diff
);
474 /*****************************************************************
475 re_update_line() is based on finding the middle difference of each line
478 /old first difference
479 /beginning of line | /old last same /old EOL
481 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
482 new: eddie> Oh, my little buggy says to me, as lurgid as
484 \beginning of line | \new last same \new end of line
485 \new first difference
487 all are character pointers for the sake of speed. Special cases for
488 no differences, as well as for end of line additions must be handled.
489 **************************************************************** */
491 /* Minimum at which doing an insert it "worth it". This should be about
492 * half the "cost" of going into insert mode, inserting a character, and
493 * going back out. This should really be calculated from the termcap
494 * data... For the moment, a good number for ANSI terminals.
496 #define MIN_END_KEEP 4
499 re_update_line(EditLine
*el
, wchar_t *old
, wchar_t *new, int i
)
501 wchar_t *o
, *n
, *p
, c
;
502 wchar_t *ofd
, *ols
, *oe
, *nfd
, *nls
, *ne
;
503 wchar_t *osb
, *ose
, *nsb
, *nse
;
510 for (o
= old
, n
= new; *o
&& (*o
== *n
); o
++, n
++)
516 * Find the end of both old and new
521 * Remove any trailing blanks off of the end, being careful not to
522 * back up past the beginning.
535 /* remove blanks from end of new */
545 * if no diff, continue to next line of redraw
547 if (*ofd
== '\0' && *nfd
== '\0') {
548 ELRE_DEBUG(1, (__F
, "no difference.\r\n"));
552 * find last same pointer
554 while ((o
> ofd
) && (n
> nfd
) && (*--o
== *--n
))
560 * find same beginning and same end
568 * case 1: insert: scan from nfd to nls looking for *ofd
571 for (c
= *ofd
, n
= nfd
; n
< nls
; n
++) {
574 p
< nls
&& o
< ols
&& *o
== *p
;
578 * if the new match is longer and it's worth
579 * keeping, then we take it
581 if (((nse
- nsb
) < (p
- n
)) &&
582 (2 * (p
- n
) > n
- nfd
)) {
592 * case 2: delete: scan from ofd to ols looking for *nfd
595 for (c
= *nfd
, o
= ofd
; o
< ols
; o
++) {
598 p
< ols
&& n
< nls
&& *p
== *n
;
602 * if the new match is longer and it's worth
603 * keeping, then we take it
605 if (((ose
- osb
) < (p
- o
)) &&
606 (2 * (p
- o
) > o
- ofd
)) {
616 * Pragmatics I: If old trailing whitespace or not enough characters to
617 * save to be worth it, then don't save the last same info.
619 if ((oe
- ols
) < MIN_END_KEEP
) {
624 * Pragmatics II: if the terminal isn't smart enough, make the data
625 * dumber so the smart update doesn't try anything fancy
629 * fx is the number of characters we need to insert/delete: in the
630 * beginning to bring the two same begins together
632 fx
= (int)((nsb
- nfd
) - (osb
- ofd
));
634 * sx is the number of characters we need to insert/delete: in the
635 * end to bring the two same last parts together
637 sx
= (int)((nls
- nse
) - (ols
- ose
));
639 if (!EL_CAN_INSERT
) {
650 if ((ols
- ofd
) < (nls
- nfd
)) {
655 if (!EL_CAN_DELETE
) {
666 if ((ols
- ofd
) > (nls
- nfd
)) {
672 * Pragmatics III: make sure the middle shifted pointers are correct if
673 * they don't point to anything (we may have moved ols or nls).
675 /* if the change isn't worth it, don't bother */
676 /* was: if (osb == ose) */
677 if ((ose
- osb
) < MIN_END_KEEP
) {
684 * Now that we are done with pragmatics we recompute fx, sx
686 fx
= (int)((nsb
- nfd
) - (osb
- ofd
));
687 sx
= (int)((nls
- nse
) - (ols
- ose
));
689 ELRE_DEBUG(1, (__F
, "fx %d, sx %d\n", fx
, sx
));
690 ELRE_DEBUG(1, (__F
, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
691 ofd
- old
, osb
- old
, ose
- old
, ols
- old
, oe
- old
));
692 ELRE_DEBUG(1, (__F
, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
693 nfd
- new, nsb
- new, nse
- new, nls
- new, ne
- new));
695 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
697 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
699 re_printstr(el
, "old- oe", old
, oe
);
700 re_printstr(el
, "new- ne", new, ne
);
701 re_printstr(el
, "old-ofd", old
, ofd
);
702 re_printstr(el
, "new-nfd", new, nfd
);
703 re_printstr(el
, "ofd-osb", ofd
, osb
);
704 re_printstr(el
, "nfd-nsb", nfd
, nsb
);
705 re_printstr(el
, "osb-ose", osb
, ose
);
706 re_printstr(el
, "nsb-nse", nsb
, nse
);
707 re_printstr(el
, "ose-ols", ose
, ols
);
708 re_printstr(el
, "nse-nls", nse
, nls
);
709 re_printstr(el
, "ols- oe", ols
, oe
);
710 re_printstr(el
, "nls- ne", nls
, ne
);
711 #endif /* DEBUG_REFRESH */
714 * el_cursor.v to this line i MUST be in this routine so that if we
715 * don't have to change the line, we don't move to it. el_cursor.h to
718 terminal_move_to_line(el
, i
);
721 * at this point we have something like this:
723 * /old /ofd /osb /ose /ols /oe
724 * v.....................v v..................v v........v
725 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
726 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
727 * ^.....................^ ^..................^ ^........^
728 * \new \nfd \nsb \nse \nls \ne
730 * fx is the difference in length between the chars between nfd and
731 * nsb, and the chars between ofd and osb, and is thus the number of
732 * characters to delete if < 0 (new is shorter than old, as above),
733 * or insert (new is longer than short).
735 * sx is the same for the second differences.
739 * if we have a net insert on the first difference, AND inserting the
740 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
741 * character (which is ne if nls != ne, otherwise is nse) off the edge
742 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
743 * so that we keep everything we need to.
747 * if the last same is the same like the end, there is no last same
748 * part, otherwise we want to keep the last same part set p to the
749 * last useful old character
751 p
= (ols
!= oe
) ? oe
: ose
;
754 * if (There is a diffence in the beginning) && (we need to insert
755 * characters) && (the number of characters to insert is less than
757 * We need to do an insert!
758 * else if (we need to delete characters)
759 * We need to delete characters!
761 * No insert or delete
763 if ((nsb
!= nfd
) && fx
> 0 &&
764 ((p
- old
) + fx
<= el
->el_terminal
.t_size
.h
)) {
766 (__F
, "first diff insert at %td...\r\n", nfd
- new));
768 * Move to the first char to insert, where the first diff is.
770 terminal_move_to_char(el
, (int)(nfd
- new));
772 * Check if we have stuff to keep at end
775 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
777 * insert fx chars of new starting at nfd
780 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
781 "ERROR: cannot insert in early first diff\n"));
782 terminal_insertwrite(el
, nfd
, fx
);
783 re_insert(el
, old
, (int)(ofd
- old
),
784 el
->el_terminal
.t_size
.h
, nfd
, fx
);
787 * write (nsb-nfd) - fx chars of new starting at
790 len
= (size_t) ((nsb
- nfd
) - fx
);
791 terminal_overwrite(el
, (nfd
+ fx
), len
);
792 re__strncopy(ofd
+ fx
, nfd
+ fx
, len
);
794 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
795 len
= (size_t)(nsb
- nfd
);
796 terminal_overwrite(el
, nfd
, len
);
797 re__strncopy(ofd
, nfd
, len
);
805 (__F
, "first diff delete at %td...\r\n", ofd
- old
));
807 * move to the first char to delete where the first diff is
809 terminal_move_to_char(el
, (int)(ofd
- old
));
811 * Check if we have stuff to save
814 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
816 * fx is less than zero *always* here but we check
820 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
821 "ERROR: cannot delete in first diff\n"));
822 terminal_deletechars(el
, -fx
);
823 re_delete(el
, old
, (int)(ofd
- old
),
824 el
->el_terminal
.t_size
.h
, -fx
);
827 * write (nsb-nfd) chars of new starting at nfd
829 len
= (size_t) (nsb
- nfd
);
830 terminal_overwrite(el
, nfd
, len
);
831 re__strncopy(ofd
, nfd
, len
);
835 "but with nothing left to save\r\n"));
837 * write (nsb-nfd) chars of new starting at nfd
839 terminal_overwrite(el
, nfd
, (size_t)(nsb
- nfd
));
840 re_clear_eol(el
, fx
, sx
,
841 (int)((oe
- old
) - (ne
- new)));
850 if (sx
< 0 && (ose
- old
) + fx
< el
->el_terminal
.t_size
.h
) {
852 "second diff delete at %td...\r\n", (ose
- old
) + fx
));
854 * Check if we have stuff to delete
857 * fx is the number of characters inserted (+) or deleted (-)
860 terminal_move_to_char(el
, (int)((ose
- old
) + fx
));
862 * Check if we have stuff to save
865 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
867 * Again a duplicate test.
870 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
871 "ERROR: cannot delete in second diff\n"));
872 terminal_deletechars(el
, -sx
);
875 * write (nls-nse) chars of new starting at nse
877 terminal_overwrite(el
, nse
, (size_t)(nls
- nse
));
880 "but with nothing left to save\r\n"));
881 terminal_overwrite(el
, nse
, (size_t)(nls
- nse
));
882 re_clear_eol(el
, fx
, sx
,
883 (int)((oe
- old
) - (ne
- new)));
887 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
889 if ((nsb
!= nfd
) && (osb
- ofd
) <= (nsb
- nfd
) && (fx
== 0)) {
890 ELRE_DEBUG(1, (__F
, "late first diff insert at %td...\r\n",
893 terminal_move_to_char(el
, (int)(nfd
- new));
895 * Check if we have stuff to keep at the end
898 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
900 * We have to recalculate fx here because we set it
901 * to zero above as a flag saying that we hadn't done
902 * an early first insert.
904 fx
= (int)((nsb
- nfd
) - (osb
- ofd
));
907 * insert fx chars of new starting at nfd
909 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
910 "ERROR: cannot insert in late first diff\n"));
911 terminal_insertwrite(el
, nfd
, fx
);
912 re_insert(el
, old
, (int)(ofd
- old
),
913 el
->el_terminal
.t_size
.h
, nfd
, fx
);
916 * write (nsb-nfd) - fx chars of new starting at
919 len
= (size_t) ((nsb
- nfd
) - fx
);
920 terminal_overwrite(el
, (nfd
+ fx
), len
);
921 re__strncopy(ofd
+ fx
, nfd
+ fx
, len
);
923 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
924 len
= (size_t) (nsb
- nfd
);
925 terminal_overwrite(el
, nfd
, len
);
926 re__strncopy(ofd
, nfd
, len
);
930 * line is now NEW up to nse
934 "second diff insert at %d...\r\n", (int)(nse
- new)));
935 terminal_move_to_char(el
, (int)(nse
- new));
937 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
939 /* insert sx chars of new starting at nse */
940 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
941 "ERROR: cannot insert in second diff\n"));
942 terminal_insertwrite(el
, nse
, sx
);
945 * write (nls-nse) - sx chars of new starting at
948 terminal_overwrite(el
, (nse
+ sx
),
949 (size_t)((nls
- nse
) - sx
));
951 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
952 terminal_overwrite(el
, nse
, (size_t)(nls
- nse
));
955 * No need to do a clear-to-end here because we were
956 * doing a second insert, so we will have over
957 * written all of the old string.
961 ELRE_DEBUG(1, (__F
, "done.\r\n"));
965 /* re__copy_and_pad():
966 * Copy string and pad with spaces
969 re__copy_and_pad(wchar_t *dst
, const wchar_t *src
, size_t width
)
973 for (i
= 0; i
< width
; i
++) {
979 for (; i
< width
; i
++)
986 /* re_refresh_cursor():
987 * Move to the new cursor position
990 re_refresh_cursor(EditLine
*el
)
995 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
996 if (el
->el_map
.current
== el
->el_map
.alt
997 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
998 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
1000 el
->el_line
.cursor
= el
->el_line
.lastchar
;
1003 /* first we must find where the cursor is... */
1004 h
= el
->el_prompt
.p_pos
.h
;
1005 v
= el
->el_prompt
.p_pos
.v
;
1006 th
= el
->el_terminal
.t_size
.h
; /* optimize for speed */
1008 /* do input buffer to el->el_line.cursor */
1009 for (cp
= el
->el_line
.buffer
; cp
< el
->el_line
.cursor
; cp
++) {
1010 switch (ct_chr_class(*cp
)) {
1011 case CHTYPE_NL
: /* handle newline in data part too */
1015 case CHTYPE_TAB
: /* if a tab, to next tab stop */
1021 if (w
> 1 && h
+ w
> th
) { /* won't fit on line */
1025 h
+= ct_visual_width(*cp
);
1029 if (h
>= th
) { /* check, extra long tabs picked up here also */
1034 /* if we have a next character, and it's a doublewidth one, we need to
1035 * check whether we need to linebreak for it to fit */
1036 if (cp
< el
->el_line
.lastchar
&& (w
= wcwidth(*cp
)) > 1)
1043 terminal_move_to_line(el
, v
);
1044 terminal_move_to_char(el
, h
);
1045 terminal__flush(el
);
1050 * Add a character fast.
1053 re_fastputc(EditLine
*el
, wint_t c
)
1059 while (w
> 1 && el
->el_cursor
.h
+ w
> el
->el_terminal
.t_size
.h
)
1060 re_fastputc(el
, ' ');
1062 terminal__putc(el
, c
);
1063 el
->el_display
[el
->el_cursor
.v
][el
->el_cursor
.h
++] = c
;
1065 el
->el_display
[el
->el_cursor
.v
][el
->el_cursor
.h
++]
1068 if (el
->el_cursor
.h
>= el
->el_terminal
.t_size
.h
) {
1069 /* if we must overflow */
1070 el
->el_cursor
.h
= 0;
1073 * If we would overflow (input is longer than terminal size),
1074 * emulate scroll by dropping first line and shuffling the rest.
1075 * We do this via pointer shuffling - it's safe in this case
1076 * and we avoid memcpy().
1078 if (el
->el_cursor
.v
+ 1 >= el
->el_terminal
.t_size
.v
) {
1079 int i
, lins
= el
->el_terminal
.t_size
.v
;
1080 lastline
= el
->el_display
[0];
1081 for(i
= 1; i
< lins
; i
++)
1082 el
->el_display
[i
- 1] = el
->el_display
[i
];
1083 el
->el_display
[i
- 1] = lastline
;
1086 lastline
= el
->el_display
[el
->el_refresh
.r_oldcv
++];
1088 re__copy_and_pad(lastline
, L
"", el
->el_terminal
.t_size
.h
);
1090 if (EL_HAS_AUTO_MARGINS
) {
1091 if (EL_HAS_MAGIC_MARGINS
) {
1092 terminal__putc(el
, ' ');
1093 terminal__putc(el
, '\b');
1096 terminal__putc(el
, '\r');
1097 terminal__putc(el
, '\n');
1104 * we added just one char, handle it fast.
1105 * Assumes that screen cursor == real cursor
1108 re_fastaddc(EditLine
*el
)
1113 c
= el
->el_line
.cursor
[-1];
1115 if (c
== '\t' || el
->el_line
.cursor
!= el
->el_line
.lastchar
) {
1116 re_refresh(el
); /* too hard to handle */
1119 rhdiff
= el
->el_terminal
.t_size
.h
- el
->el_cursor
.h
-
1120 el
->el_rprompt
.p_pos
.h
;
1121 if (el
->el_rprompt
.p_pos
.h
&& rhdiff
< 3) {
1122 re_refresh(el
); /* clear out rprompt if less than 1 char gap */
1124 } /* else (only do at end of line, no TAB) */
1125 switch (ct_chr_class(c
)) {
1126 case CHTYPE_TAB
: /* already handled, should never happen here */
1132 case CHTYPE_ASCIICTL
:
1133 case CHTYPE_NONPRINT
: {
1134 wchar_t visbuf
[VISUAL_WIDTH_MAX
];
1136 ct_visual_char(visbuf
, VISUAL_WIDTH_MAX
, c
);
1137 for (i
= 0; n
-- > 0; ++i
)
1138 re_fastputc(el
, visbuf
[i
]);
1142 terminal__flush(el
);
1146 /* re_clear_display():
1147 * clear the screen buffers so that new new prompt starts fresh.
1150 re_clear_display(EditLine
*el
)
1154 el
->el_cursor
.v
= 0;
1155 el
->el_cursor
.h
= 0;
1156 for (i
= 0; i
< el
->el_terminal
.t_size
.v
; i
++)
1157 el
->el_display
[i
][0] = '\0';
1158 el
->el_refresh
.r_oldcv
= 0;
1162 /* re_clear_lines():
1163 * Make sure all lines are *really* blank
1166 re_clear_lines(EditLine
*el
)
1171 for (i
= el
->el_refresh
.r_oldcv
; i
>= 0; i
--) {
1172 /* for each line on the screen */
1173 terminal_move_to_line(el
, i
);
1174 terminal_move_to_char(el
, 0);
1175 terminal_clear_EOL(el
, el
->el_terminal
.t_size
.h
);
1178 terminal_move_to_line(el
, el
->el_refresh
.r_oldcv
);
1179 /* go to last line */
1180 terminal__putc(el
, '\r'); /* go to BOL */
1181 terminal__putc(el
, '\n'); /* go to new line */