2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * @(#)refresh.c 8.1 (Berkeley) 6/4/93
33 * $NetBSD: refresh.c,v 1.27 2005/11/09 22:11:10 christos Exp $
34 * $DragonFly: src/lib/libedit/refresh.c,v 1.6 2007/05/05 00:27:39 pavalos Exp $
40 * refresh.c: Lower level screen refreshing functions
49 private void re_addc(EditLine
*, int);
50 private void re_update_line(EditLine
*, char *, char *, int);
51 private void re_insert (EditLine
*, char *, int, int, char *, int);
52 private void re_delete(EditLine
*, char *, int, int, int);
53 private void re_fastputc(EditLine
*, int);
54 private void re_clear_eol(EditLine
*, int, int, int);
55 private void re__strncopy(char *, char *, size_t);
56 private void re__copy_and_pad(char *, const char *, size_t);
59 private void re_printstr(EditLine
*, const char *, char *, char *);
60 #define __F el->el_errfile
61 #define ELRE_ASSERT(a, b, c) do \
62 if (/*CONSTCOND*/ a) { \
66 while (/*CONSTCOND*/0)
67 #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
70 * Print a string on the debugging pty
73 re_printstr(EditLine
*el
, const char *str
, char *f
, char *t
)
76 ELRE_DEBUG(1, (__F
, "%s:\"", str
));
78 ELRE_DEBUG(1, (__F
, "%c", *f
++ & 0177));
79 ELRE_DEBUG(1, (__F
, "\"\r\n"));
82 #define ELRE_ASSERT(a, b, c)
83 #define ELRE_DEBUG(a, b)
88 * Draw c, expanding tabs, control chars etc.
91 re_addc(EditLine
*el
, int c
)
98 if (c
== '\n') { /* expand the newline */
99 int oldv
= el
->el_refresh
.r_cursor
.v
;
100 re_putc(el
, '\0', 0); /* assure end of line */
101 if (oldv
== el
->el_refresh
.r_cursor
.v
) { /* XXX */
102 el
->el_refresh
.r_cursor
.h
= 0; /* reset cursor pos */
103 el
->el_refresh
.r_cursor
.v
++;
107 if (c
== '\t') { /* expand the tab */
110 if ((el
->el_refresh
.r_cursor
.h
& 07) == 0)
111 break; /* go until tab stop */
113 } else if (iscntrl(c
)) {
118 /* uncontrolify it; works only for iso8859-1 like sets */
119 re_putc(el
, (c
| 0100), 1);
121 re_putc(el
, '\\', 1);
122 re_putc(el
, (int) ((((unsigned int) c
>> 6) & 07) + '0'), 1);
123 re_putc(el
, (int) ((((unsigned int) c
>> 3) & 07) + '0'), 1);
124 re_putc(el
, (c
& 07) + '0', 1);
130 * Draw the character given
133 re_putc(EditLine
*el
, int c
, int shift
)
136 ELRE_DEBUG(1, (__F
, "printing %3.3o '%c'\r\n", c
, c
));
138 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
][el
->el_refresh
.r_cursor
.h
] = c
;
142 el
->el_refresh
.r_cursor
.h
++; /* advance to next place */
143 if (el
->el_refresh
.r_cursor
.h
>= el
->el_term
.t_size
.h
) {
144 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
][el
->el_term
.t_size
.h
] = '\0';
145 /* assure end of line */
146 el
->el_refresh
.r_cursor
.h
= 0; /* reset it. */
149 * If we would overflow (input is longer than terminal size),
150 * emulate scroll by dropping first line and shuffling the rest.
151 * We do this via pointer shuffling - it's safe in this case
152 * and we avoid memcpy().
154 if (el
->el_refresh
.r_cursor
.v
+ 1 >= el
->el_term
.t_size
.v
) {
155 int i
, lins
= el
->el_term
.t_size
.v
;
156 char *firstline
= el
->el_vdisplay
[0];
158 for(i
=1; i
< lins
; i
++)
159 el
->el_vdisplay
[i
-1] = el
->el_vdisplay
[i
];
161 firstline
[0] = '\0'; /* empty the string */
162 el
->el_vdisplay
[i
-1] = firstline
;
164 el
->el_refresh
.r_cursor
.v
++;
166 ELRE_ASSERT(el
->el_refresh
.r_cursor
.v
>= el
->el_term
.t_size
.v
,
167 (__F
, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
168 el
->el_refresh
.r_cursor
.v
, el
->el_term
.t_size
.v
),
175 * draws the new virtual screen image from the current input
176 * line, then goes line-by-line changing the real image to the new
177 * virtual image. The routine to re-draw a line can be replaced
178 * easily in hopes of a smarter one being placed there.
181 re_refresh(EditLine
*el
)
190 ELRE_DEBUG(1, (__F
, "el->el_line.buffer = :%s:\r\n",
191 el
->el_line
.buffer
));
193 /* reset the Drawing cursor */
194 el
->el_refresh
.r_cursor
.h
= 0;
195 el
->el_refresh
.r_cursor
.v
= 0;
197 /* temporarily draw rprompt to calculate its size */
198 prompt_print(el
, EL_RPROMPT
);
200 /* reset the Drawing cursor */
201 el
->el_refresh
.r_cursor
.h
= 0;
202 el
->el_refresh
.r_cursor
.v
= 0;
204 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
205 if (el
->el_map
.current
== el
->el_map
.alt
206 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
207 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
209 el
->el_line
.cursor
= el
->el_line
.lastchar
;
212 cur
.h
= -1; /* set flag in case I'm not set */
215 prompt_print(el
, EL_PROMPT
);
217 /* draw the current input buffer */
219 termsz
= el
->el_term
.t_size
.h
* el
->el_term
.t_size
.v
;
220 if (el
->el_line
.lastchar
- el
->el_line
.buffer
> termsz
) {
222 * If line is longer than terminal, process only part
223 * of line which would influence display.
225 size_t rem
= (el
->el_line
.lastchar
-el
->el_line
.buffer
)%termsz
;
227 st
= el
->el_line
.lastchar
- rem
228 - (termsz
- (((rem
/ el
->el_term
.t_size
.v
) - 1)
229 * el
->el_term
.t_size
.v
));
232 st
= el
->el_line
.buffer
;
234 for (cp
= st
; cp
< el
->el_line
.lastchar
; cp
++) {
235 if (cp
== el
->el_line
.cursor
) {
237 cur
.h
= el
->el_refresh
.r_cursor
.h
;
238 cur
.v
= el
->el_refresh
.r_cursor
.v
;
240 re_addc(el
, (unsigned char) *cp
);
243 if (cur
.h
== -1) { /* if I haven't been set yet, I'm at the end */
244 cur
.h
= el
->el_refresh
.r_cursor
.h
;
245 cur
.v
= el
->el_refresh
.r_cursor
.v
;
247 rhdiff
= el
->el_term
.t_size
.h
- el
->el_refresh
.r_cursor
.h
-
248 el
->el_rprompt
.p_pos
.h
;
249 if (el
->el_rprompt
.p_pos
.h
&& !el
->el_rprompt
.p_pos
.v
&&
250 !el
->el_refresh
.r_cursor
.v
&& rhdiff
> 1) {
252 * have a right-hand side prompt that will fit
253 * on the end of the first line with at least
254 * one character gap to the input buffer.
256 while (--rhdiff
> 0) /* pad out with spaces */
258 prompt_print(el
, EL_RPROMPT
);
260 el
->el_rprompt
.p_pos
.h
= 0; /* flag "not using rprompt" */
261 el
->el_rprompt
.p_pos
.v
= 0;
264 re_putc(el
, '\0', 0); /* make line ended with NUL, no cursor shift */
266 el
->el_refresh
.r_newcv
= el
->el_refresh
.r_cursor
.v
;
269 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
270 el
->el_term
.t_size
.h
, el
->el_refresh
.r_cursor
.h
,
271 el
->el_refresh
.r_cursor
.v
, el
->el_vdisplay
[0]));
273 ELRE_DEBUG(1, (__F
, "updating %d lines.\r\n", el
->el_refresh
.r_newcv
));
274 for (i
= 0; i
<= el
->el_refresh
.r_newcv
; i
++) {
275 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
276 re_update_line(el
, el
->el_display
[i
], el
->el_vdisplay
[i
], i
);
279 * Copy the new line to be the current one, and pad out with
280 * spaces to the full width of the terminal so that if we try
281 * moving the cursor by writing the character that is at the
282 * end of the screen line, it won't be a NUL or some old
285 re__copy_and_pad(el
->el_display
[i
], el
->el_vdisplay
[i
],
286 (size_t) el
->el_term
.t_size
.h
);
289 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
290 el
->el_refresh
.r_cursor
.v
, el
->el_refresh
.r_oldcv
, i
));
292 if (el
->el_refresh
.r_oldcv
> el
->el_refresh
.r_newcv
)
293 for (; i
<= el
->el_refresh
.r_oldcv
; i
++) {
294 term_move_to_line(el
, i
);
295 term_move_to_char(el
, 0);
296 term_clear_EOL(el
, (int) strlen(el
->el_display
[i
]));
298 term_overwrite(el
, "C\b", 2);
299 #endif /* DEBUG_REFRESH */
300 el
->el_display
[i
][0] = '\0';
303 el
->el_refresh
.r_oldcv
= el
->el_refresh
.r_newcv
; /* set for next time */
305 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
306 el
->el_refresh
.r_cursor
.h
, el
->el_refresh
.r_cursor
.v
,
308 term_move_to_line(el
, cur
.v
); /* go to where the cursor is */
309 term_move_to_char(el
, cur
.h
);
314 * used to go to last used screen line
317 re_goto_bottom(EditLine
*el
)
320 term_move_to_line(el
, el
->el_refresh
.r_oldcv
);
322 re_clear_display(el
);
328 * insert num characters of s into d (in front of the character)
329 * at dat, maximum length of d is dlen
333 re_insert(EditLine
*el
__attribute__((__unused__
)),
334 char *d
, int dat
, int dlen
, char *s
, int num
)
340 if (num
> dlen
- dat
)
344 (__F
, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
346 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", s
));
348 /* open up the space for num chars */
354 d
[dlen
] = '\0'; /* just in case */
357 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
359 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", s
));
361 /* copy the characters */
362 for (a
= d
+ dat
; (a
< d
+ dlen
) && (num
> 0); num
--)
366 (__F
, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
367 num
, dat
, dlen
, d
, s
));
368 ELRE_DEBUG(1, (__F
, "s == \"%s\"\n", s
));
373 * delete num characters d at dat, maximum length of d is dlen
377 re_delete(EditLine
*el
__attribute__((__unused__
)),
378 char *d
, int dat
, int dlen
, int num
)
384 if (dat
+ num
>= dlen
) {
389 (__F
, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
392 /* open up the space for num chars */
398 d
[dlen
] = '\0'; /* just in case */
401 (__F
, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
407 * Like strncpy without padding.
410 re__strncopy(char *a
, char *b
, size_t n
)
418 * Find the number of characters we need to clear till the end of line
419 * in order to make sure that we have cleared the previous contents of
420 * the line. fx and sx is the number of characters inserted or deleted
421 * int the first or second diff, diff is the difference between the
422 * number of characters between the new and old line.
425 re_clear_eol(EditLine
*el
, int fx
, int sx
, int diff
)
428 ELRE_DEBUG(1, (__F
, "re_clear_eol sx %d, fx %d, diff %d\n",
440 ELRE_DEBUG(1, (__F
, "re_clear_eol %d\n", diff
));
441 term_clear_EOL(el
, diff
);
444 /*****************************************************************
445 re_update_line() is based on finding the middle difference of each line
448 /old first difference
449 /beginning of line | /old last same /old EOL
451 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
452 new: eddie> Oh, my little buggy says to me, as lurgid as
454 \beginning of line | \new last same \new end of line
455 \new first difference
457 all are character pointers for the sake of speed. Special cases for
458 no differences, as well as for end of line additions must be handled.
459 **************************************************************** */
461 /* Minimum at which doing an insert it "worth it". This should be about
462 * half the "cost" of going into insert mode, inserting a character, and
463 * going back out. This should really be calculated from the termcap
464 * data... For the moment, a good number for ANSI terminals.
466 #define MIN_END_KEEP 4
469 re_update_line(EditLine
*el
, char *old
, char *new, int i
)
472 char *ofd
, *ols
, *oe
, *nfd
, *nls
, *ne
;
473 char *osb
, *ose
, *nsb
, *nse
;
479 for (o
= old
, n
= new; *o
&& (*o
== *n
); o
++, n
++)
485 * Find the end of both old and new
490 * Remove any trailing blanks off of the end, being careful not to
491 * back up past the beginning.
504 /* remove blanks from end of new */
514 * if no diff, continue to next line of redraw
516 if (*ofd
== '\0' && *nfd
== '\0') {
517 ELRE_DEBUG(1, (__F
, "no difference.\r\n"));
521 * find last same pointer
523 while ((o
> ofd
) && (n
> nfd
) && (*--o
== *--n
))
529 * find same begining and same end
537 * case 1: insert: scan from nfd to nls looking for *ofd
540 for (c
= *ofd
, n
= nfd
; n
< nls
; n
++) {
543 p
< nls
&& o
< ols
&& *o
== *p
;
547 * if the new match is longer and it's worth
548 * keeping, then we take it
550 if (((nse
- nsb
) < (p
- n
)) &&
551 (2 * (p
- n
) > n
- nfd
)) {
561 * case 2: delete: scan from ofd to ols looking for *nfd
564 for (c
= *nfd
, o
= ofd
; o
< ols
; o
++) {
567 p
< ols
&& n
< nls
&& *p
== *n
;
571 * if the new match is longer and it's worth
572 * keeping, then we take it
574 if (((ose
- osb
) < (p
- o
)) &&
575 (2 * (p
- o
) > o
- ofd
)) {
585 * Pragmatics I: If old trailing whitespace or not enough characters to
586 * save to be worth it, then don't save the last same info.
588 if ((oe
- ols
) < MIN_END_KEEP
) {
593 * Pragmatics II: if the terminal isn't smart enough, make the data
594 * dumber so the smart update doesn't try anything fancy
598 * fx is the number of characters we need to insert/delete: in the
599 * beginning to bring the two same begins together
601 fx
= (nsb
- nfd
) - (osb
- ofd
);
603 * sx is the number of characters we need to insert/delete: in the
604 * end to bring the two same last parts together
606 sx
= (nls
- nse
) - (ols
- ose
);
608 if (!EL_CAN_INSERT
) {
619 if ((ols
- ofd
) < (nls
- nfd
)) {
624 if (!EL_CAN_DELETE
) {
635 if ((ols
- ofd
) > (nls
- nfd
)) {
641 * Pragmatics III: make sure the middle shifted pointers are correct if
642 * they don't point to anything (we may have moved ols or nls).
644 /* if the change isn't worth it, don't bother */
645 /* was: if (osb == ose) */
646 if ((ose
- osb
) < MIN_END_KEEP
) {
653 * Now that we are done with pragmatics we recompute fx, sx
655 fx
= (nsb
- nfd
) - (osb
- ofd
);
656 sx
= (nls
- nse
) - (ols
- ose
);
658 ELRE_DEBUG(1, (__F
, "fx %d, sx %d\n", fx
, sx
));
659 ELRE_DEBUG(1, (__F
, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
660 ofd
- old
, osb
- old
, ose
- old
, ols
- old
, oe
- old
));
661 ELRE_DEBUG(1, (__F
, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
662 nfd
- new, nsb
- new, nse
- new, nls
- new, ne
- new));
664 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
666 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
668 re_printstr(el
, "old- oe", old
, oe
);
669 re_printstr(el
, "new- ne", new, ne
);
670 re_printstr(el
, "old-ofd", old
, ofd
);
671 re_printstr(el
, "new-nfd", new, nfd
);
672 re_printstr(el
, "ofd-osb", ofd
, osb
);
673 re_printstr(el
, "nfd-nsb", nfd
, nsb
);
674 re_printstr(el
, "osb-ose", osb
, ose
);
675 re_printstr(el
, "nsb-nse", nsb
, nse
);
676 re_printstr(el
, "ose-ols", ose
, ols
);
677 re_printstr(el
, "nse-nls", nse
, nls
);
678 re_printstr(el
, "ols- oe", ols
, oe
);
679 re_printstr(el
, "nls- ne", nls
, ne
);
680 #endif /* DEBUG_REFRESH */
683 * el_cursor.v to this line i MUST be in this routine so that if we
684 * don't have to change the line, we don't move to it. el_cursor.h to
687 term_move_to_line(el
, i
);
690 * at this point we have something like this:
692 * /old /ofd /osb /ose /ols /oe
693 * v.....................v v..................v v........v
694 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
695 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
696 * ^.....................^ ^..................^ ^........^
697 * \new \nfd \nsb \nse \nls \ne
699 * fx is the difference in length between the chars between nfd and
700 * nsb, and the chars between ofd and osb, and is thus the number of
701 * characters to delete if < 0 (new is shorter than old, as above),
702 * or insert (new is longer than short).
704 * sx is the same for the second differences.
708 * if we have a net insert on the first difference, AND inserting the
709 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
710 * character (which is ne if nls != ne, otherwise is nse) off the edge
711 * of the screen (el->el_term.t_size.h) else we do the deletes first
712 * so that we keep everything we need to.
716 * if the last same is the same like the end, there is no last same
717 * part, otherwise we want to keep the last same part set p to the
718 * last useful old character
720 p
= (ols
!= oe
) ? oe
: ose
;
723 * if (There is a diffence in the beginning) && (we need to insert
724 * characters) && (the number of characters to insert is less than
726 * We need to do an insert!
727 * else if (we need to delete characters)
728 * We need to delete characters!
730 * No insert or delete
732 if ((nsb
!= nfd
) && fx
> 0 &&
733 ((p
- old
) + fx
<= el
->el_term
.t_size
.h
)) {
735 (__F
, "first diff insert at %d...\r\n", nfd
- new));
737 * Move to the first char to insert, where the first diff is.
739 term_move_to_char(el
, nfd
- new);
741 * Check if we have stuff to keep at end
744 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
746 * insert fx chars of new starting at nfd
749 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
750 "ERROR: cannot insert in early first diff\n"));
751 term_insertwrite(el
, nfd
, fx
);
752 re_insert(el
, old
, ofd
- old
,
753 el
->el_term
.t_size
.h
, nfd
, fx
);
756 * write (nsb-nfd) - fx chars of new starting at
759 term_overwrite(el
, nfd
+ fx
, (nsb
- nfd
) - fx
);
760 re__strncopy(ofd
+ fx
, nfd
+ fx
,
761 (size_t) ((nsb
- nfd
) - fx
));
763 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
764 term_overwrite(el
, nfd
, (nsb
- nfd
));
765 re__strncopy(ofd
, nfd
, (size_t) (nsb
- nfd
));
773 (__F
, "first diff delete at %d...\r\n", ofd
- old
));
775 * move to the first char to delete where the first diff is
777 term_move_to_char(el
, ofd
- old
);
779 * Check if we have stuff to save
782 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
784 * fx is less than zero *always* here but we check
788 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
789 "ERROR: cannot delete in first diff\n"));
790 term_deletechars(el
, -fx
);
791 re_delete(el
, old
, ofd
- old
,
792 el
->el_term
.t_size
.h
, -fx
);
795 * write (nsb-nfd) chars of new starting at nfd
797 term_overwrite(el
, nfd
, (nsb
- nfd
));
798 re__strncopy(ofd
, nfd
, (size_t) (nsb
- nfd
));
802 "but with nothing left to save\r\n"));
804 * write (nsb-nfd) chars of new starting at nfd
806 term_overwrite(el
, nfd
, (nsb
- nfd
));
807 re_clear_eol(el
, fx
, sx
, (oe
- old
) - (ne
- new));
816 if (sx
< 0 && (ose
- old
) + fx
< el
->el_term
.t_size
.h
) {
818 "second diff delete at %d...\r\n", (ose
- old
) + fx
));
820 * Check if we have stuff to delete
823 * fx is the number of characters inserted (+) or deleted (-)
826 term_move_to_char(el
, (ose
- old
) + fx
);
828 * Check if we have stuff to save
831 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
833 * Again a duplicate test.
836 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
837 "ERROR: cannot delete in second diff\n"));
838 term_deletechars(el
, -sx
);
841 * write (nls-nse) chars of new starting at nse
843 term_overwrite(el
, nse
, (nls
- nse
));
846 "but with nothing left to save\r\n"));
847 term_overwrite(el
, nse
, (nls
- nse
));
848 re_clear_eol(el
, fx
, sx
, (oe
- old
) - (ne
- new));
852 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
854 if ((nsb
!= nfd
) && (osb
- ofd
) <= (nsb
- nfd
) && (fx
== 0)) {
855 ELRE_DEBUG(1, (__F
, "late first diff insert at %d...\r\n",
858 term_move_to_char(el
, nfd
- new);
860 * Check if we have stuff to keep at the end
863 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
865 * We have to recalculate fx here because we set it
866 * to zero above as a flag saying that we hadn't done
867 * an early first insert.
869 fx
= (nsb
- nfd
) - (osb
- ofd
);
872 * insert fx chars of new starting at nfd
874 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
875 "ERROR: cannot insert in late first diff\n"));
876 term_insertwrite(el
, nfd
, fx
);
877 re_insert(el
, old
, ofd
- old
,
878 el
->el_term
.t_size
.h
, nfd
, fx
);
881 * write (nsb-nfd) - fx chars of new starting at
884 term_overwrite(el
, nfd
+ fx
, (nsb
- nfd
) - fx
);
885 re__strncopy(ofd
+ fx
, nfd
+ fx
,
886 (size_t) ((nsb
- nfd
) - fx
));
888 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
889 term_overwrite(el
, nfd
, (nsb
- nfd
));
890 re__strncopy(ofd
, nfd
, (size_t) (nsb
- nfd
));
894 * line is now NEW up to nse
898 "second diff insert at %d...\r\n", nse
- new));
899 term_move_to_char(el
, nse
- new);
901 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
903 /* insert sx chars of new starting at nse */
904 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
905 "ERROR: cannot insert in second diff\n"));
906 term_insertwrite(el
, nse
, sx
);
909 * write (nls-nse) - sx chars of new starting at
912 term_overwrite(el
, nse
+ sx
, (nls
- nse
) - sx
);
914 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
915 term_overwrite(el
, nse
, (nls
- nse
));
918 * No need to do a clear-to-end here because we were
919 * doing a second insert, so we will have over
920 * written all of the old string.
924 ELRE_DEBUG(1, (__F
, "done.\r\n"));
928 /* re__copy_and_pad():
929 * Copy string and pad with spaces
932 re__copy_and_pad(char *dst
, const char *src
, size_t width
)
936 for (i
= 0; i
< width
; i
++) {
942 for (; i
< width
; i
++)
949 /* re_refresh_cursor():
950 * Move to the new cursor position
953 re_refresh_cursor(EditLine
*el
)
958 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
959 if (el
->el_map
.current
== el
->el_map
.alt
960 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
961 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
963 el
->el_line
.cursor
= el
->el_line
.lastchar
;
966 /* first we must find where the cursor is... */
967 h
= el
->el_prompt
.p_pos
.h
;
968 v
= el
->el_prompt
.p_pos
.v
;
969 th
= el
->el_term
.t_size
.h
; /* optimize for speed */
971 /* do input buffer to el->el_line.cursor */
972 for (cp
= el
->el_line
.buffer
; cp
< el
->el_line
.cursor
; cp
++) {
974 h
++; /* all chars at least this long */
976 if (c
== '\n') {/* handle newline in data part too */
980 if (c
== '\t') { /* if a tab, to next tab stop */
984 } else if (iscntrl((unsigned char) c
)) {
985 /* if control char */
987 if (h
> th
) { /* if overflow, compensate */
991 } else if (!isprint((unsigned char) c
)) {
993 if (h
> th
) { /* if overflow, compensate */
1000 if (h
>= th
) { /* check, extra long tabs picked up here also */
1007 term_move_to_line(el
, v
);
1008 term_move_to_char(el
, h
);
1014 * Add a character fast.
1017 re_fastputc(EditLine
*el
, int c
)
1021 el
->el_display
[el
->el_cursor
.v
][el
->el_cursor
.h
++] = c
;
1022 if (el
->el_cursor
.h
>= el
->el_term
.t_size
.h
) {
1023 /* if we must overflow */
1024 el
->el_cursor
.h
= 0;
1027 * If we would overflow (input is longer than terminal size),
1028 * emulate scroll by dropping first line and shuffling the rest.
1029 * We do this via pointer shuffling - it's safe in this case
1030 * and we avoid memcpy().
1032 if (el
->el_cursor
.v
+ 1 >= el
->el_term
.t_size
.v
) {
1033 int i
, lins
= el
->el_term
.t_size
.v
;
1034 char *firstline
= el
->el_display
[0];
1036 for(i
=1; i
< lins
; i
++)
1037 el
->el_display
[i
-1] = el
->el_display
[i
];
1039 re__copy_and_pad(firstline
, "", 0);
1040 el
->el_display
[i
-1] = firstline
;
1043 el
->el_refresh
.r_oldcv
++;
1045 if (EL_HAS_AUTO_MARGINS
) {
1046 if (EL_HAS_MAGIC_MARGINS
) {
1059 * we added just one char, handle it fast.
1060 * Assumes that screen cursor == real cursor
1063 re_fastaddc(EditLine
*el
)
1068 c
= el
->el_line
.cursor
[-1];
1070 if (c
== '\t' || el
->el_line
.cursor
!= el
->el_line
.lastchar
) {
1071 re_refresh(el
); /* too hard to handle */
1074 rhdiff
= el
->el_term
.t_size
.h
- el
->el_cursor
.h
-
1075 el
->el_rprompt
.p_pos
.h
;
1076 if (el
->el_rprompt
.p_pos
.h
&& rhdiff
< 3) {
1077 re_refresh(el
); /* clear out rprompt if less than 1 char gap */
1079 } /* else (only do at end of line, no TAB) */
1080 if (iscntrl((unsigned char) c
)) { /* if control char, do caret */
1081 char mc
= (c
== '\177') ? '?' : (c
| 0100);
1082 re_fastputc(el
, '^');
1083 re_fastputc(el
, mc
);
1084 } else if (isprint((unsigned char) c
)) { /* normal char */
1087 re_fastputc(el
, '\\');
1088 re_fastputc(el
, (int)(((((unsigned int)c
) >> 6) & 3) + '0'));
1089 re_fastputc(el
, (int)(((((unsigned int)c
) >> 3) & 7) + '0'));
1090 re_fastputc(el
, (c
& 7) + '0');
1096 /* re_clear_display():
1097 * clear the screen buffers so that new new prompt starts fresh.
1100 re_clear_display(EditLine
*el
)
1104 el
->el_cursor
.v
= 0;
1105 el
->el_cursor
.h
= 0;
1106 for (i
= 0; i
< el
->el_term
.t_size
.v
; i
++)
1107 el
->el_display
[i
][0] = '\0';
1108 el
->el_refresh
.r_oldcv
= 0;
1112 /* re_clear_lines():
1113 * Make sure all lines are *really* blank
1116 re_clear_lines(EditLine
*el
)
1121 term_move_to_char(el
, 0);
1122 for (i
= 0; i
<= el
->el_refresh
.r_oldcv
; i
++) {
1123 /* for each line on the screen */
1124 term_move_to_line(el
, i
);
1125 term_clear_EOL(el
, el
->el_term
.t_size
.h
);
1127 term_move_to_line(el
, 0);
1129 term_move_to_line(el
, el
->el_refresh
.r_oldcv
);
1130 /* go to last line */
1131 term__putc('\r'); /* go to BOL */
1132 term__putc('\n'); /* go to new line */