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.26 2003/08/07 16:44:33 agc Exp $
34 * $DragonFly: src/lib/libedit/refresh.c,v 1.5 2005/11/13 11:58:30 corecode 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__strncopy(char *, char *, size_t);
55 private void re__copy_and_pad(char *, const char *, size_t);
58 private void re_printstr(EditLine
*, const char *, char *, char *);
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
, char *f
, char *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)
87 * Draw c, expanding tabs, control chars etc.
90 re_addc(EditLine
*el
, int c
)
97 if (c
== '\n') { /* expand the newline */
98 int oldv
= el
->el_refresh
.r_cursor
.v
;
99 re_putc(el
, '\0', 0); /* assure end of line */
100 if (oldv
== el
->el_refresh
.r_cursor
.v
) { /* XXX */
101 el
->el_refresh
.r_cursor
.h
= 0; /* reset cursor pos */
102 el
->el_refresh
.r_cursor
.v
++;
106 if (c
== '\t') { /* expand the tab */
109 if ((el
->el_refresh
.r_cursor
.h
& 07) == 0)
110 break; /* go until tab stop */
112 } else if (iscntrl(c
)) {
117 /* uncontrolify it; works only for iso8859-1 like sets */
118 re_putc(el
, (c
| 0100), 1);
120 re_putc(el
, '\\', 1);
121 re_putc(el
, (int) ((((unsigned int) c
>> 6) & 07) + '0'), 1);
122 re_putc(el
, (int) ((((unsigned int) c
>> 3) & 07) + '0'), 1);
123 re_putc(el
, (c
& 07) + '0', 1);
129 * Draw the character given
132 re_putc(EditLine
*el
, int c
, int shift
)
135 ELRE_DEBUG(1, (__F
, "printing %3.3o '%c'\r\n", c
, c
));
137 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
][el
->el_refresh
.r_cursor
.h
] = c
;
141 el
->el_refresh
.r_cursor
.h
++; /* advance to next place */
142 if (el
->el_refresh
.r_cursor
.h
>= el
->el_term
.t_size
.h
) {
143 el
->el_vdisplay
[el
->el_refresh
.r_cursor
.v
][el
->el_term
.t_size
.h
] = '\0';
144 /* assure end of line */
145 el
->el_refresh
.r_cursor
.h
= 0; /* reset it. */
148 * If we would overflow (input is longer than terminal size),
149 * emulate scroll by dropping first line and shuffling the rest.
150 * We do this via pointer shuffling - it's safe in this case
151 * and we avoid memcpy().
153 if (el
->el_refresh
.r_cursor
.v
+ 1 >= el
->el_term
.t_size
.v
) {
154 int i
, lins
= el
->el_term
.t_size
.v
;
155 char *firstline
= el
->el_vdisplay
[0];
157 for(i
=1; i
< lins
; i
++)
158 el
->el_vdisplay
[i
-1] = el
->el_vdisplay
[i
];
160 firstline
[0] = '\0'; /* empty the string */
161 el
->el_vdisplay
[i
-1] = firstline
;
163 el
->el_refresh
.r_cursor
.v
++;
165 ELRE_ASSERT(el
->el_refresh
.r_cursor
.v
>= el
->el_term
.t_size
.v
,
166 (__F
, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
167 el
->el_refresh
.r_cursor
.v
, el
->el_term
.t_size
.v
),
174 * draws the new virtual screen image from the current input
175 * line, then goes line-by-line changing the real image to the new
176 * virtual image. The routine to re-draw a line can be replaced
177 * easily in hopes of a smarter one being placed there.
180 re_refresh(EditLine
*el
)
189 ELRE_DEBUG(1, (__F
, "el->el_line.buffer = :%s:\r\n",
190 el
->el_line
.buffer
));
192 /* reset the Drawing cursor */
193 el
->el_refresh
.r_cursor
.h
= 0;
194 el
->el_refresh
.r_cursor
.v
= 0;
196 /* temporarily draw rprompt to calculate its size */
197 prompt_print(el
, EL_RPROMPT
);
199 /* reset the Drawing cursor */
200 el
->el_refresh
.r_cursor
.h
= 0;
201 el
->el_refresh
.r_cursor
.v
= 0;
203 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
204 if (el
->el_map
.current
== el
->el_map
.alt
205 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
206 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
208 el
->el_line
.cursor
= el
->el_line
.lastchar
;
211 cur
.h
= -1; /* set flag in case I'm not set */
214 prompt_print(el
, EL_PROMPT
);
216 /* draw the current input buffer */
218 termsz
= el
->el_term
.t_size
.h
* el
->el_term
.t_size
.v
;
219 if (el
->el_line
.lastchar
- el
->el_line
.buffer
> termsz
) {
221 * If line is longer than terminal, process only part
222 * of line which would influence display.
224 size_t rem
= (el
->el_line
.lastchar
-el
->el_line
.buffer
)%termsz
;
226 st
= el
->el_line
.lastchar
- rem
227 - (termsz
- (((rem
/ el
->el_term
.t_size
.v
) - 1)
228 * el
->el_term
.t_size
.v
));
231 st
= el
->el_line
.buffer
;
233 for (cp
= st
; cp
< el
->el_line
.lastchar
; cp
++) {
234 if (cp
== el
->el_line
.cursor
) {
236 cur
.h
= el
->el_refresh
.r_cursor
.h
;
237 cur
.v
= el
->el_refresh
.r_cursor
.v
;
239 re_addc(el
, (unsigned char) *cp
);
242 if (cur
.h
== -1) { /* if I haven't been set yet, I'm at the end */
243 cur
.h
= el
->el_refresh
.r_cursor
.h
;
244 cur
.v
= el
->el_refresh
.r_cursor
.v
;
246 rhdiff
= el
->el_term
.t_size
.h
- el
->el_refresh
.r_cursor
.h
-
247 el
->el_rprompt
.p_pos
.h
;
248 if (el
->el_rprompt
.p_pos
.h
&& !el
->el_rprompt
.p_pos
.v
&&
249 !el
->el_refresh
.r_cursor
.v
&& rhdiff
> 1) {
251 * have a right-hand side prompt that will fit
252 * on the end of the first line with at least
253 * one character gap to the input buffer.
255 while (--rhdiff
> 0) /* pad out with spaces */
257 prompt_print(el
, EL_RPROMPT
);
259 el
->el_rprompt
.p_pos
.h
= 0; /* flag "not using rprompt" */
260 el
->el_rprompt
.p_pos
.v
= 0;
263 re_putc(el
, '\0', 0); /* make line ended with NUL, no cursor shift */
265 el
->el_refresh
.r_newcv
= el
->el_refresh
.r_cursor
.v
;
268 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
269 el
->el_term
.t_size
.h
, el
->el_refresh
.r_cursor
.h
,
270 el
->el_refresh
.r_cursor
.v
, el
->el_vdisplay
[0]));
272 ELRE_DEBUG(1, (__F
, "updating %d lines.\r\n", el
->el_refresh
.r_newcv
));
273 for (i
= 0; i
<= el
->el_refresh
.r_newcv
; i
++) {
274 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
275 re_update_line(el
, el
->el_display
[i
], el
->el_vdisplay
[i
], i
);
278 * Copy the new line to be the current one, and pad out with
279 * spaces to the full width of the terminal so that if we try
280 * moving the cursor by writing the character that is at the
281 * end of the screen line, it won't be a NUL or some old
284 re__copy_and_pad(el
->el_display
[i
], el
->el_vdisplay
[i
],
285 (size_t) el
->el_term
.t_size
.h
);
288 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
289 el
->el_refresh
.r_cursor
.v
, el
->el_refresh
.r_oldcv
, i
));
291 if (el
->el_refresh
.r_oldcv
> el
->el_refresh
.r_newcv
)
292 for (; i
<= el
->el_refresh
.r_oldcv
; i
++) {
293 term_move_to_line(el
, i
);
294 term_move_to_char(el
, 0);
295 term_clear_EOL(el
, (int) strlen(el
->el_display
[i
]));
297 term_overwrite(el
, "C\b", 2);
298 #endif /* DEBUG_REFRESH */
299 el
->el_display
[i
][0] = '\0';
302 el
->el_refresh
.r_oldcv
= el
->el_refresh
.r_newcv
; /* set for next time */
304 "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
305 el
->el_refresh
.r_cursor
.h
, el
->el_refresh
.r_cursor
.v
,
307 term_move_to_line(el
, cur
.v
); /* go to where the cursor is */
308 term_move_to_char(el
, cur
.h
);
313 * used to go to last used screen line
316 re_goto_bottom(EditLine
*el
)
319 term_move_to_line(el
, el
->el_refresh
.r_oldcv
);
321 re_clear_display(el
);
327 * insert num characters of s into d (in front of the character)
328 * at dat, maximum length of d is dlen
332 re_insert(EditLine
*el
__attribute__((__unused__
)),
333 char *d
, int dat
, int dlen
, char *s
, int num
)
339 if (num
> dlen
- dat
)
343 (__F
, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
345 ELRE_DEBUG(1, (__F
, "s == \"%s\"n", s
));
347 /* open up the space for num chars */
353 d
[dlen
] = '\0'; /* just in case */
356 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
358 ELRE_DEBUG(1, (__F
, "s == \"%s\"n", s
));
360 /* copy the characters */
361 for (a
= d
+ dat
; (a
< d
+ dlen
) && (num
> 0); num
--)
365 (__F
, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
366 num
, dat
, dlen
, d
, s
));
367 ELRE_DEBUG(1, (__F
, "s == \"%s\"n", s
));
372 * delete num characters d at dat, maximum length of d is dlen
376 re_delete(EditLine
*el
__attribute__((__unused__
)),
377 char *d
, int dat
, int dlen
, int num
)
383 if (dat
+ num
>= dlen
) {
388 (__F
, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
391 /* open up the space for num chars */
397 d
[dlen
] = '\0'; /* just in case */
400 (__F
, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
406 * Like strncpy without padding.
409 re__strncopy(char *a
, char *b
, size_t n
)
417 /*****************************************************************
418 re_update_line() is based on finding the middle difference of each line
421 /old first difference
422 /beginning of line | /old last same /old EOL
424 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
425 new: eddie> Oh, my little buggy says to me, as lurgid as
427 \beginning of line | \new last same \new end of line
428 \new first difference
430 all are character pointers for the sake of speed. Special cases for
431 no differences, as well as for end of line additions must be handled.
432 **************************************************************** */
434 /* Minimum at which doing an insert it "worth it". This should be about
435 * half the "cost" of going into insert mode, inserting a character, and
436 * going back out. This should really be calculated from the termcap
437 * data... For the moment, a good number for ANSI terminals.
439 #define MIN_END_KEEP 4
442 re_update_line(EditLine
*el
, char *old
, char *new, int i
)
445 char *ofd
, *ols
, *oe
, *nfd
, *nls
, *ne
;
446 char *osb
, *ose
, *nsb
, *nse
;
452 for (o
= old
, n
= new; *o
&& (*o
== *n
); o
++, n
++)
458 * Find the end of both old and new
463 * Remove any trailing blanks off of the end, being careful not to
464 * back up past the beginning.
477 /* remove blanks from end of new */
487 * if no diff, continue to next line of redraw
489 if (*ofd
== '\0' && *nfd
== '\0') {
490 ELRE_DEBUG(1, (__F
, "no difference.\r\n"));
494 * find last same pointer
496 while ((o
> ofd
) && (n
> nfd
) && (*--o
== *--n
))
502 * find same begining and same end
510 * case 1: insert: scan from nfd to nls looking for *ofd
513 for (c
= *ofd
, n
= nfd
; n
< nls
; n
++) {
516 p
< nls
&& o
< ols
&& *o
== *p
;
520 * if the new match is longer and it's worth
521 * keeping, then we take it
523 if (((nse
- nsb
) < (p
- n
)) &&
524 (2 * (p
- n
) > n
- nfd
)) {
534 * case 2: delete: scan from ofd to ols looking for *nfd
537 for (c
= *nfd
, o
= ofd
; o
< ols
; o
++) {
540 p
< ols
&& n
< nls
&& *p
== *n
;
544 * if the new match is longer and it's worth
545 * keeping, then we take it
547 if (((ose
- osb
) < (p
- o
)) &&
548 (2 * (p
- o
) > o
- ofd
)) {
558 * Pragmatics I: If old trailing whitespace or not enough characters to
559 * save to be worth it, then don't save the last same info.
561 if ((oe
- ols
) < MIN_END_KEEP
) {
566 * Pragmatics II: if the terminal isn't smart enough, make the data
567 * dumber so the smart update doesn't try anything fancy
571 * fx is the number of characters we need to insert/delete: in the
572 * beginning to bring the two same begins together
574 fx
= (nsb
- nfd
) - (osb
- ofd
);
576 * sx is the number of characters we need to insert/delete: in the
577 * end to bring the two same last parts together
579 sx
= (nls
- nse
) - (ols
- ose
);
581 if (!EL_CAN_INSERT
) {
592 if ((ols
- ofd
) < (nls
- nfd
)) {
597 if (!EL_CAN_DELETE
) {
608 if ((ols
- ofd
) > (nls
- nfd
)) {
614 * Pragmatics III: make sure the middle shifted pointers are correct if
615 * they don't point to anything (we may have moved ols or nls).
617 /* if the change isn't worth it, don't bother */
618 /* was: if (osb == ose) */
619 if ((ose
- osb
) < MIN_END_KEEP
) {
626 * Now that we are done with pragmatics we recompute fx, sx
628 fx
= (nsb
- nfd
) - (osb
- ofd
);
629 sx
= (nls
- nse
) - (ols
- ose
);
631 ELRE_DEBUG(1, (__F
, "\n"));
632 ELRE_DEBUG(1, (__F
, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
633 ofd
- old
, osb
- old
, ose
- old
, ols
- old
, oe
- old
));
634 ELRE_DEBUG(1, (__F
, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
635 nfd
- new, nsb
- new, nse
- new, nls
- new, ne
- new));
637 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
639 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
641 re_printstr(el
, "old- oe", old
, oe
);
642 re_printstr(el
, "new- ne", new, ne
);
643 re_printstr(el
, "old-ofd", old
, ofd
);
644 re_printstr(el
, "new-nfd", new, nfd
);
645 re_printstr(el
, "ofd-osb", ofd
, osb
);
646 re_printstr(el
, "nfd-nsb", nfd
, nsb
);
647 re_printstr(el
, "osb-ose", osb
, ose
);
648 re_printstr(el
, "nsb-nse", nsb
, nse
);
649 re_printstr(el
, "ose-ols", ose
, ols
);
650 re_printstr(el
, "nse-nls", nse
, nls
);
651 re_printstr(el
, "ols- oe", ols
, oe
);
652 re_printstr(el
, "nls- ne", nls
, ne
);
653 #endif /* DEBUG_REFRESH */
656 * el_cursor.v to this line i MUST be in this routine so that if we
657 * don't have to change the line, we don't move to it. el_cursor.h to
660 term_move_to_line(el
, i
);
663 * at this point we have something like this:
665 * /old /ofd /osb /ose /ols /oe
666 * v.....................v v..................v v........v
667 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
668 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
669 * ^.....................^ ^..................^ ^........^
670 * \new \nfd \nsb \nse \nls \ne
672 * fx is the difference in length between the chars between nfd and
673 * nsb, and the chars between ofd and osb, and is thus the number of
674 * characters to delete if < 0 (new is shorter than old, as above),
675 * or insert (new is longer than short).
677 * sx is the same for the second differences.
681 * if we have a net insert on the first difference, AND inserting the
682 * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
683 * character (which is ne if nls != ne, otherwise is nse) off the edge
684 * of the screen (el->el_term.t_size.h) else we do the deletes first
685 * so that we keep everything we need to.
689 * if the last same is the same like the end, there is no last same
690 * part, otherwise we want to keep the last same part set p to the
691 * last useful old character
693 p
= (ols
!= oe
) ? oe
: ose
;
696 * if (There is a diffence in the beginning) && (we need to insert
697 * characters) && (the number of characters to insert is less than
699 * We need to do an insert!
700 * else if (we need to delete characters)
701 * We need to delete characters!
703 * No insert or delete
705 if ((nsb
!= nfd
) && fx
> 0 &&
706 ((p
- old
) + fx
<= el
->el_term
.t_size
.h
)) {
708 (__F
, "first diff insert at %d...\r\n", nfd
- new));
710 * Move to the first char to insert, where the first diff is.
712 term_move_to_char(el
, nfd
- new);
714 * Check if we have stuff to keep at end
717 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
719 * insert fx chars of new starting at nfd
722 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
723 "ERROR: cannot insert in early first diff\n"));
724 term_insertwrite(el
, nfd
, fx
);
725 re_insert(el
, old
, ofd
- old
,
726 el
->el_term
.t_size
.h
, nfd
, fx
);
729 * write (nsb-nfd) - fx chars of new starting at
732 term_overwrite(el
, nfd
+ fx
, (nsb
- nfd
) - fx
);
733 re__strncopy(ofd
+ fx
, nfd
+ fx
,
734 (size_t) ((nsb
- nfd
) - fx
));
736 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
737 term_overwrite(el
, nfd
, (nsb
- nfd
));
738 re__strncopy(ofd
, nfd
, (size_t) (nsb
- nfd
));
746 (__F
, "first diff delete at %d...\r\n", ofd
- old
));
748 * move to the first char to delete where the first diff is
750 term_move_to_char(el
, ofd
- old
);
752 * Check if we have stuff to save
755 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
757 * fx is less than zero *always* here but we check
761 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
762 "ERROR: cannot delete in first diff\n"));
763 term_deletechars(el
, -fx
);
764 re_delete(el
, old
, ofd
- old
,
765 el
->el_term
.t_size
.h
, -fx
);
768 * write (nsb-nfd) chars of new starting at nfd
770 term_overwrite(el
, nfd
, (nsb
- nfd
));
771 re__strncopy(ofd
, nfd
, (size_t) (nsb
- nfd
));
775 "but with nothing left to save\r\n"));
777 * write (nsb-nfd) chars of new starting at nfd
779 term_overwrite(el
, nfd
, (nsb
- nfd
));
781 "cleareol %d\n", (oe
- old
) - (ne
- new)));
782 term_clear_EOL(el
, (oe
- old
) - (ne
- new));
791 if (sx
< 0 && (ose
- old
) + fx
< el
->el_term
.t_size
.h
) {
793 "second diff delete at %d...\r\n", (ose
- old
) + fx
));
795 * Check if we have stuff to delete
798 * fx is the number of characters inserted (+) or deleted (-)
801 term_move_to_char(el
, (ose
- old
) + fx
);
803 * Check if we have stuff to save
806 ELRE_DEBUG(1, (__F
, "with stuff to save at end\r\n"));
808 * Again a duplicate test.
811 ELRE_DEBUG(!EL_CAN_DELETE
, (__F
,
812 "ERROR: cannot delete in second diff\n"));
813 term_deletechars(el
, -sx
);
816 * write (nls-nse) chars of new starting at nse
818 term_overwrite(el
, nse
, (nls
- nse
));
821 "but with nothing left to save\r\n"));
822 term_overwrite(el
, nse
, (nls
- nse
));
824 "cleareol %d\n", (oe
- old
) - (ne
- new)));
825 if ((oe
- old
) - (ne
- new) != 0)
826 term_clear_EOL(el
, (oe
- old
) - (ne
- new));
830 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
832 if ((nsb
!= nfd
) && (osb
- ofd
) <= (nsb
- nfd
) && (fx
== 0)) {
833 ELRE_DEBUG(1, (__F
, "late first diff insert at %d...\r\n",
836 term_move_to_char(el
, nfd
- new);
838 * Check if we have stuff to keep at the end
841 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
843 * We have to recalculate fx here because we set it
844 * to zero above as a flag saying that we hadn't done
845 * an early first insert.
847 fx
= (nsb
- nfd
) - (osb
- ofd
);
850 * insert fx chars of new starting at nfd
852 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
853 "ERROR: cannot insert in late first diff\n"));
854 term_insertwrite(el
, nfd
, fx
);
855 re_insert(el
, old
, ofd
- old
,
856 el
->el_term
.t_size
.h
, nfd
, fx
);
859 * write (nsb-nfd) - fx chars of new starting at
862 term_overwrite(el
, nfd
+ fx
, (nsb
- nfd
) - fx
);
863 re__strncopy(ofd
+ fx
, nfd
+ fx
,
864 (size_t) ((nsb
- nfd
) - fx
));
866 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
867 term_overwrite(el
, nfd
, (nsb
- nfd
));
868 re__strncopy(ofd
, nfd
, (size_t) (nsb
- nfd
));
872 * line is now NEW up to nse
876 "second diff insert at %d...\r\n", nse
- new));
877 term_move_to_char(el
, nse
- new);
879 ELRE_DEBUG(1, (__F
, "with stuff to keep at end\r\n"));
881 /* insert sx chars of new starting at nse */
882 ELRE_DEBUG(!EL_CAN_INSERT
, (__F
,
883 "ERROR: cannot insert in second diff\n"));
884 term_insertwrite(el
, nse
, sx
);
887 * write (nls-nse) - sx chars of new starting at
890 term_overwrite(el
, nse
+ sx
, (nls
- nse
) - sx
);
892 ELRE_DEBUG(1, (__F
, "without anything to save\r\n"));
893 term_overwrite(el
, nse
, (nls
- nse
));
896 * No need to do a clear-to-end here because we were
897 * doing a second insert, so we will have over
898 * written all of the old string.
902 ELRE_DEBUG(1, (__F
, "done.\r\n"));
906 /* re__copy_and_pad():
907 * Copy string and pad with spaces
910 re__copy_and_pad(char *dst
, const char *src
, size_t width
)
914 for (i
= 0; i
< width
; i
++) {
920 for (; i
< width
; i
++)
927 /* re_refresh_cursor():
928 * Move to the new cursor position
931 re_refresh_cursor(EditLine
*el
)
936 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
) {
937 if (el
->el_map
.current
== el
->el_map
.alt
938 && el
->el_line
.lastchar
!= el
->el_line
.buffer
)
939 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
941 el
->el_line
.cursor
= el
->el_line
.lastchar
;
944 /* first we must find where the cursor is... */
945 h
= el
->el_prompt
.p_pos
.h
;
946 v
= el
->el_prompt
.p_pos
.v
;
947 th
= el
->el_term
.t_size
.h
; /* optimize for speed */
949 /* do input buffer to el->el_line.cursor */
950 for (cp
= el
->el_line
.buffer
; cp
< el
->el_line
.cursor
; cp
++) {
952 h
++; /* all chars at least this long */
954 if (c
== '\n') {/* handle newline in data part too */
958 if (c
== '\t') { /* if a tab, to next tab stop */
962 } else if (iscntrl((unsigned char) c
)) {
963 /* if control char */
965 if (h
> th
) { /* if overflow, compensate */
969 } else if (!isprint((unsigned char) c
)) {
971 if (h
> th
) { /* if overflow, compensate */
978 if (h
>= th
) { /* check, extra long tabs picked up here also */
985 term_move_to_line(el
, v
);
986 term_move_to_char(el
, h
);
992 * Add a character fast.
995 re_fastputc(EditLine
*el
, int c
)
999 el
->el_display
[el
->el_cursor
.v
][el
->el_cursor
.h
++] = c
;
1000 if (el
->el_cursor
.h
>= el
->el_term
.t_size
.h
) {
1001 /* if we must overflow */
1002 el
->el_cursor
.h
= 0;
1005 * If we would overflow (input is longer than terminal size),
1006 * emulate scroll by dropping first line and shuffling the rest.
1007 * We do this via pointer shuffling - it's safe in this case
1008 * and we avoid memcpy().
1010 if (el
->el_cursor
.v
+ 1 >= el
->el_term
.t_size
.v
) {
1011 int i
, lins
= el
->el_term
.t_size
.v
;
1012 char *firstline
= el
->el_display
[0];
1014 for(i
=1; i
< lins
; i
++)
1015 el
->el_display
[i
-1] = el
->el_display
[i
];
1017 re__copy_and_pad(firstline
, "", 0);
1018 el
->el_display
[i
-1] = firstline
;
1021 el
->el_refresh
.r_oldcv
++;
1023 if (EL_HAS_AUTO_MARGINS
) {
1024 if (EL_HAS_MAGIC_MARGINS
) {
1037 * we added just one char, handle it fast.
1038 * Assumes that screen cursor == real cursor
1041 re_fastaddc(EditLine
*el
)
1046 c
= el
->el_line
.cursor
[-1];
1048 if (c
== '\t' || el
->el_line
.cursor
!= el
->el_line
.lastchar
) {
1049 re_refresh(el
); /* too hard to handle */
1052 rhdiff
= el
->el_term
.t_size
.h
- el
->el_cursor
.h
-
1053 el
->el_rprompt
.p_pos
.h
;
1054 if (el
->el_rprompt
.p_pos
.h
&& rhdiff
< 3) {
1055 re_refresh(el
); /* clear out rprompt if less than 1 char gap */
1057 } /* else (only do at end of line, no TAB) */
1058 if (iscntrl((unsigned char) c
)) { /* if control char, do caret */
1059 char mc
= (c
== '\177') ? '?' : (c
| 0100);
1060 re_fastputc(el
, '^');
1061 re_fastputc(el
, mc
);
1062 } else if (isprint((unsigned char) c
)) { /* normal char */
1065 re_fastputc(el
, '\\');
1066 re_fastputc(el
, (int)(((((unsigned int)c
) >> 6) & 3) + '0'));
1067 re_fastputc(el
, (int)(((((unsigned int)c
) >> 3) & 7) + '0'));
1068 re_fastputc(el
, (c
& 7) + '0');
1074 /* re_clear_display():
1075 * clear the screen buffers so that new new prompt starts fresh.
1078 re_clear_display(EditLine
*el
)
1082 el
->el_cursor
.v
= 0;
1083 el
->el_cursor
.h
= 0;
1084 for (i
= 0; i
< el
->el_term
.t_size
.v
; i
++)
1085 el
->el_display
[i
][0] = '\0';
1086 el
->el_refresh
.r_oldcv
= 0;
1090 /* re_clear_lines():
1091 * Make sure all lines are *really* blank
1094 re_clear_lines(EditLine
*el
)
1099 term_move_to_char(el
, 0);
1100 for (i
= 0; i
<= el
->el_refresh
.r_oldcv
; i
++) {
1101 /* for each line on the screen */
1102 term_move_to_line(el
, i
);
1103 term_clear_EOL(el
, el
->el_term
.t_size
.h
);
1105 term_move_to_line(el
, 0);
1107 term_move_to_line(el
, el
->el_refresh
.r_oldcv
);
1108 /* go to last line */
1109 term__putc('\r'); /* go to BOL */
1110 term__putc('\n'); /* go to new line */