root/src/noitedit/refresh.c

Revision 2c4eb5b5fbb052c18d52a989026b447982cc17c3, 29.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 7 years ago)

pull header-space into the noitedir dir, this makes it stand apart from libedit more trivially.

  • Property mode set to 100644
Line 
1 /*      $NetBSD: refresh.c,v 1.17 2001/04/13 00:53:11 lukem Exp $       */
2
3 /*-
4  * Copyright (c) 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #include "noitedit/compat.h"
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)refresh.c   8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: refresh.c,v 1.17 2001/04/13 00:53:11 lukem Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49  * refresh.c: Lower level screen refreshing functions
50  */
51 #include "noitedit/sys.h"
52 #include <stdio.h>
53 #include <ctype.h>
54 #if HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 #include <string.h>
58
59 #include "noitedit/el.h"
60
61 private void    re_addc(EditLine *, int);
62 private void    re_update_line(EditLine *, char *, char *, int);
63 private void    re_insert (EditLine *, char *, int, int, char *, int);
64 private void    re_delete(EditLine *, char *, int, int, int);
65 private void    re_fastputc(EditLine *, int);
66 private void    re__strncopy(char *, char *, size_t);
67 private void    re__copy_and_pad(char *, char *, size_t);
68
69 #ifdef DEBUG_REFRESH
70 private void    re_printstr(EditLine *, char *, char *, char *);
71 #define __F el->el_errfile
72 #define ELRE_ASSERT(a, b, c)    do                              \
73                                     if (a) {                    \
74                                         (void) fprintf b;       \
75                                         c;                      \
76                                     }                           \
77                                 while (0)
78 #define ELRE_DEBUG(a, b)        ELRE_ASSERT(a,b,;)
79
80 /* re_printstr():
81  *      Print a string on the debugging pty
82  */
83 private void
84 re_printstr(EditLine *el, char *str, char *f, char *t)
85 {
86
87         ELRE_DEBUG(1, (__F, "%s:\"", str));
88         while (f < t)
89                 ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
90         ELRE_DEBUG(1, (__F, "\"\r\n"));
91 }
92 #else
93 #define ELRE_ASSERT(a, b, c)
94 #define ELRE_DEBUG(a, b)
95 #endif
96
97
98 /* re_addc():
99  *      Draw c, expanding tabs, control chars etc.
100  */
101 private void
102 re_addc(EditLine *el, int c)
103 {
104
105         if (isprint(c)) {
106                 re_putc(el, c, 1);
107                 return;
108         }
109         if (c == '\n') {                                /* expand the newline */
110                 int oldv = el->el_refresh.r_cursor.v;
111                 re_putc(el, '\0', 0);                   /* assure end of line */
112                 if (oldv == el->el_refresh.r_cursor.v) { /* XXX */
113                         el->el_refresh.r_cursor.h = 0;  /* reset cursor pos */
114                         el->el_refresh.r_cursor.v++;
115                 }
116                 return;
117         }
118         if (c == '\t') {                                /* expand the tab */
119                 for (;;) {
120                         re_putc(el, ' ', 1);
121                         if ((el->el_refresh.r_cursor.h & 07) == 0)
122                                 break;                  /* go until tab stop */
123                 }
124         } else if (iscntrl(c)) {
125                 re_putc(el, '^', 1);
126                 if (c == '\177')
127                         re_putc(el, '?', 1);
128                 else
129                     /* uncontrolify it; works only for iso8859-1 like sets */
130                         re_putc(el, (c | 0100), 1);
131         } else {
132                 re_putc(el, '\\', 1);
133                 re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
134                 re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
135                 re_putc(el, (c & 07) + '0', 1);
136         }
137 }
138
139
140 /* re_putc():
141  *      Draw the character given
142  */
143 protected void
144 re_putc(EditLine *el, int c, int shift)
145 {
146
147         ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
148
149         el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
150         if (!shift)
151                 return;
152
153         el->el_refresh.r_cursor.h++;    /* advance to next place */
154         if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
155                 el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0';
156                 /* assure end of line */
157                 el->el_refresh.r_cursor.h = 0;  /* reset it. */
158
159                 /*
160                  * If we would overflow (input is longer than terminal size),
161                  * emulate scroll by dropping first line and shuffling the rest.
162                  * We do this via pointer shuffling - it's safe in this case
163                  * and we avoid memcpy().
164                  */
165                 if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
166                         int i, lins = el->el_term.t_size.v;
167                         char *firstline = el->el_vdisplay[0];
168
169                         for(i=1; i < lins; i++)
170                                 el->el_vdisplay[i-1] = el->el_vdisplay[i];
171
172                         firstline[0] = '\0';            /* empty the string */ 
173                         el->el_vdisplay[i-1] = firstline;
174                 } else
175                         el->el_refresh.r_cursor.v++;
176
177                 ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
178                     (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
179                     el->el_refresh.r_cursor.v, el->el_term.t_size.v),
180                     abort());
181         }
182 }
183
184
185 /* re_refresh():
186  *      draws the new virtual screen image from the current input
187  *      line, then goes line-by-line changing the real image to the new
188  *      virtual image. The routine to re-draw a line can be replaced
189  *      easily in hopes of a smarter one being placed there.
190  */
191 protected void
192 re_refresh(EditLine *el)
193 {
194         int i, rhdiff;
195         char *cp, *st;
196         coord_t cur;
197 #ifdef notyet
198         size_t termsz;
199 #endif
200
201         ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
202             el->el_line.buffer));
203
204         /* reset the Drawing cursor */
205         el->el_refresh.r_cursor.h = 0;
206         el->el_refresh.r_cursor.v = 0;
207
208         /* temporarily draw rprompt to calculate its size */
209         prompt_print(el, EL_RPROMPT);
210
211         /* reset the Drawing cursor */
212         el->el_refresh.r_cursor.h = 0;
213         el->el_refresh.r_cursor.v = 0;
214
215         cur.h = -1;             /* set flag in case I'm not set */
216         cur.v = 0;
217
218         prompt_print(el, EL_PROMPT);
219
220         /* draw the current input buffer */
221 #if notyet
222         termsz = el->el_term.t_size.h * el->el_term.t_size.v;
223         if (el->el_line.lastchar - el->el_line.buffer > termsz) {
224                 /*
225                  * If line is longer than terminal, process only part
226                  * of line which would influence display.
227                  */
228                 size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
229
230                 st = el->el_line.lastchar - rem
231                         - (termsz - (((rem / el->el_term.t_size.v) - 1)
232                                         * el->el_term.t_size.v));
233         } else
234 #endif
235                 st = el->el_line.buffer;
236
237         for (cp = st; cp < el->el_line.lastchar; cp++) {
238                 if (cp == el->el_line.cursor) {
239                         /* save for later */
240                         cur.h = el->el_refresh.r_cursor.h;
241                         cur.v = el->el_refresh.r_cursor.v;
242                 }
243                 re_addc(el, (unsigned char) *cp);
244         }
245
246         if (cur.h == -1) {      /* if I haven't been set yet, I'm at the end */
247                 cur.h = el->el_refresh.r_cursor.h;
248                 cur.v = el->el_refresh.r_cursor.v;
249         }
250         rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
251             el->el_rprompt.p_pos.h;
252         if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
253             !el->el_refresh.r_cursor.v && rhdiff > 1) {
254                 /*
255                  * have a right-hand side prompt that will fit
256                  * on the end of the first line with at least
257                  * one character gap to the input buffer.
258                  */
259                 while (--rhdiff > 0)    /* pad out with spaces */
260                         re_putc(el, ' ', 1);
261                 prompt_print(el, EL_RPROMPT);
262         } else {
263                 el->el_rprompt.p_pos.h = 0;     /* flag "not using rprompt" */
264                 el->el_rprompt.p_pos.v = 0;
265         }
266
267         re_putc(el, '\0', 0);   /* make line ended with NUL, no cursor shift */
268
269         el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
270
271         ELRE_DEBUG(1, (__F,
272                 "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
273                 el->el_term.t_size.h, el->el_refresh.r_cursor.h,
274                 el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
275
276         ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
277         for (i = 0; i <= el->el_refresh.r_newcv; i++) {
278                 /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
279                 re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
280
281                 /*
282                  * Copy the new line to be the current one, and pad out with
283                  * spaces to the full width of the terminal so that if we try
284                  * moving the cursor by writing the character that is at the
285                  * end of the screen line, it won't be a NUL or some old
286                  * leftover stuff.
287                  */
288                 re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
289                     (size_t) el->el_term.t_size.h);
290         }
291         ELRE_DEBUG(1, (__F,
292         "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
293             el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
294
295         if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
296                 for (; i <= el->el_refresh.r_oldcv; i++) {
297                         term_move_to_line(el, i);
298                         term_move_to_char(el, 0);
299                         term_clear_EOL(el, (int) strlen(el->el_display[i]));
300 #ifdef DEBUG_REFRESH
301                         term_overwrite(el, "C\b", 2);
302 #endif /* DEBUG_REFRESH */
303                         el->el_display[i][0] = '\0';
304                 }
305
306         el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
307         ELRE_DEBUG(1, (__F,
308             "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
309             el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
310             cur.h, cur.v));
311         term_move_to_line(el, cur.v);   /* go to where the cursor is */
312         term_move_to_char(el, cur.h);
313 }
314
315
316 /* re_goto_bottom():
317  *       used to go to last used screen line
318  */
319 protected void
320 re_goto_bottom(EditLine *el)
321 {
322
323         term_move_to_line(el, el->el_refresh.r_oldcv);
324         term__putc('\r');
325         term__putc('\n');
326         re_clear_display(el);
327         term__flush();
328 }
329
330
331 /* re_insert():
332  *      insert num characters of s into d (in front of the character)
333  *      at dat, maximum length of d is dlen
334  */
335 private void
336 /*ARGSUSED*/
337 re_insert(EditLine *el, char *d, int dat, int dlen, char *s, int num)
338 {
339         char *a, *b;
340
341         if (num <= 0)
342                 return;
343         if (num > dlen - dat)
344                 num = dlen - dat;
345
346         ELRE_DEBUG(1,
347             (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
348             num, dat, dlen, d));
349         ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
350
351         /* open up the space for num chars */
352         if (num > 0) {
353                 b = d + dlen - 1;
354                 a = b - num;
355                 while (a >= &d[dat])
356                         *b-- = *a--;
357                 d[dlen] = '\0'; /* just in case */
358         }
359         ELRE_DEBUG(1, (__F,
360                 "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
361                 num, dat, dlen, d));
362         ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
363
364         /* copy the characters */
365         for (a = d + dat; (a < d + dlen) && (num > 0); num--)
366                 *a++ = *s++;
367
368         ELRE_DEBUG(1,
369             (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
370             num, dat, dlen, d, s));
371         ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
372 }
373
374
375 /* re_delete():
376  *      delete num characters d at dat, maximum length of d is dlen
377  */
378 private void
379 /*ARGSUSED*/
380 re_delete(EditLine *el, char *d, int dat, int dlen, int num)
381 {
382         char *a, *b;
383
384         if (num <= 0)
385                 return;
386         if (dat + num >= dlen) {
387                 d[dat] = '\0';
388                 return;
389         }
390         ELRE_DEBUG(1,
391             (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
392             num, dat, dlen, d));
393
394         /* open up the space for num chars */
395         if (num > 0) {
396                 b = d + dat;
397                 a = b + num;
398                 while (a < &d[dlen])
399                         *b++ = *a++;
400                 d[dlen] = '\0'; /* just in case */
401         }
402         ELRE_DEBUG(1,
403             (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
404             num, dat, dlen, d));
405 }
406
407
408 /* re__strncopy():
409  *      Like strncpy without padding.
410  */
411 private void
412 re__strncopy(char *a, char *b, size_t n)
413 {
414
415         while (n-- && *b)
416                 *a++ = *b++;
417 }
418
419
420 /*****************************************************************
421     re_update_line() is based on finding the middle difference of each line
422     on the screen; vis:
423
424                              /old first difference
425         /beginning of line   |              /old last same       /old EOL
426         v                    v              v                    v
427 old:    eddie> Oh, my little gruntle-buggy is to me, as lurgid as
428 new:    eddie> Oh, my little buggy says to me, as lurgid as
429         ^                    ^        ^                    ^
430         \beginning of line   |        \new last same       \new end of line
431                              \new first difference
432
433     all are character pointers for the sake of speed.  Special cases for
434     no differences, as well as for end of line additions must be handled.
435 **************************************************************** */
436
437 /* Minimum at which doing an insert it "worth it".  This should be about
438  * half the "cost" of going into insert mode, inserting a character, and
439  * going back out.  This should really be calculated from the termcap
440  * data...  For the moment, a good number for ANSI terminals.
441  */
442 #define MIN_END_KEEP    4
443
444 private void
445 re_update_line(EditLine *el, char *old, char *new, int i)
446 {
447         char *o, *n, *p, c;
448         char *ofd, *ols, *oe, *nfd, *nls, *ne;
449         char *osb, *ose, *nsb, *nse;
450         int fx, sx;
451
452         /*
453          * find first diff
454          */
455         for (o = old, n = new; *o && (*o == *n); o++, n++)
456                 continue;
457         ofd = o;
458         nfd = n;
459
460         /*
461          * Find the end of both old and new
462          */
463         while (*o)
464                 o++;
465         /*
466          * Remove any trailing blanks off of the end, being careful not to
467          * back up past the beginning.
468          */
469         while (ofd < o) {
470                 if (o[-1] != ' ')
471                         break;
472                 o--;
473         }
474         oe = o;
475         *oe = '\0';
476
477         while (*n)
478                 n++;
479
480         /* remove blanks from end of new */
481         while (nfd < n) {
482                 if (n[-1] != ' ')
483                         break;
484                 n--;
485         }
486         ne = n;
487         *ne = '\0';
488
489         /*
490          * if no diff, continue to next line of redraw
491          */
492         if (*ofd == '\0' && *nfd == '\0') {
493                 ELRE_DEBUG(1, (__F, "no difference.\r\n"));
494                 return;
495         }
496         /*
497          * find last same pointer
498          */
499         while ((o > ofd) && (n > nfd) && (*--o == *--n))
500                 continue;
501         ols = ++o;
502         nls = ++n;
503
504         /*
505          * find same begining and same end
506          */
507         osb = ols;
508         nsb = nls;
509         ose = ols;
510         nse = nls;
511
512         /*
513          * case 1: insert: scan from nfd to nls looking for *ofd
514          */
515         if (*ofd) {
516                 for (c = *ofd, n = nfd; n < nls; n++) {
517                         if (c == *n) {
518                                 for (o = ofd, p = n;
519                                     p < nls && o < ols && *o == *p;
520                                     o++, p++)
521                                         continue;
522                                 /*
523                                  * if the new match is longer and it's worth
524                                  * keeping, then we take it
525                                  */
526                                 if (((nse - nsb) < (p - n)) &&
527                                     (2 * (p - n) > n - nfd)) {
528                                         nsb = n;
529                                         nse = p;
530                                         osb = ofd;
531                                         ose = o;
532                                 }
533                         }
534                 }
535         }
536         /*
537          * case 2: delete: scan from ofd to ols looking for *nfd
538          */
539         if (*nfd) {
540                 for (c = *nfd, o = ofd; o < ols; o++) {
541                         if (c == *o) {
542                                 for (n = nfd, p = o;
543                                     p < ols && n < nls && *p == *n;
544                                     p++, n++)
545                                         continue;
546                                 /*
547                                  * if the new match is longer and it's worth
548                                  * keeping, then we take it
549                                  */
550                                 if (((ose - osb) < (p - o)) &&
551                                     (2 * (p - o) > o - ofd)) {
552                                         nsb = nfd;
553                                         nse = n;
554                                         osb = o;
555                                         ose = p;
556                                 }
557                         }
558                 }
559         }
560         /*
561          * Pragmatics I: If old trailing whitespace or not enough characters to
562          * save to be worth it, then don't save the last same info.
563          */
564         if ((oe - ols) < MIN_END_KEEP) {
565                 ols = oe;
566                 nls = ne;
567         }
568         /*
569          * Pragmatics II: if the terminal isn't smart enough, make the data
570          * dumber so the smart update doesn't try anything fancy
571          */
572
573         /*
574          * fx is the number of characters we need to insert/delete: in the
575          * beginning to bring the two same begins together
576          */
577         fx = (nsb - nfd) - (osb - ofd);
578         /*
579          * sx is the number of characters we need to insert/delete: in the
580          * end to bring the two same last parts together
581          */
582         sx = (nls - nse) - (ols - ose);
583
584         if (!EL_CAN_INSERT) {
585                 if (fx > 0) {
586                         osb = ols;
587                         ose = ols;
588                         nsb = nls;
589                         nse = nls;
590                 }
591                 if (sx > 0) {
592                         ols = oe;
593                         nls = ne;
594                 }
595                 if ((ols - ofd) < (nls - nfd)) {
596                         ols = oe;
597                         nls = ne;
598                 }
599         }
600         if (!EL_CAN_DELETE) {
601                 if (fx < 0) {
602                         osb = ols;
603                         ose = ols;
604                         nsb = nls;
605                         nse = nls;
606                 }
607                 if (sx < 0) {
608                         ols = oe;
609                         nls = ne;
610                 }
611                 if ((ols - ofd) > (nls - nfd)) {
612                         ols = oe;
613                         nls = ne;
614                 }
615         }
616         /*
617          * Pragmatics III: make sure the middle shifted pointers are correct if
618          * they don't point to anything (we may have moved ols or nls).
619          */
620         /* if the change isn't worth it, don't bother */
621         /* was: if (osb == ose) */
622         if ((ose - osb) < MIN_END_KEEP) {
623                 osb = ols;
624                 ose = ols;
625                 nsb = nls;
626                 nse = nls;
627         }
628         /*
629          * Now that we are done with pragmatics we recompute fx, sx
630          */
631         fx = (nsb - nfd) - (osb - ofd);
632         sx = (nls - nse) - (ols - ose);
633
634         ELRE_DEBUG(1, (__F, "\n"));
635         ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
636                 ofd - old, osb - old, ose - old, ols - old, oe - old));
637         ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
638                 nfd - new, nsb - new, nse - new, nls - new, ne - new));
639         ELRE_DEBUG(1, (__F,
640                 "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
641         ELRE_DEBUG(1, (__F,
642                 "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
643 #ifdef DEBUG_REFRESH
644         re_printstr(el, "old- oe", old, oe);
645         re_printstr(el, "new- ne", new, ne);
646         re_printstr(el, "old-ofd", old, ofd);
647         re_printstr(el, "new-nfd", new, nfd);
648         re_printstr(el, "ofd-osb", ofd, osb);
649         re_printstr(el, "nfd-nsb", nfd, nsb);
650         re_printstr(el, "osb-ose", osb, ose);
651         re_printstr(el, "nsb-nse", nsb, nse);
652         re_printstr(el, "ose-ols", ose, ols);
653         re_printstr(el, "nse-nls", nse, nls);
654         re_printstr(el, "ols- oe", ols, oe);
655         re_printstr(el, "nls- ne", nls, ne);
656 #endif /* DEBUG_REFRESH */
657
658         /*
659          * el_cursor.v to this line i MUST be in this routine so that if we
660          * don't have to change the line, we don't move to it. el_cursor.h to
661          * first diff char
662          */
663         term_move_to_line(el, i);
664
665         /*
666          * at this point we have something like this:
667          *
668          * /old                  /ofd    /osb               /ose    /ols     /oe
669          * v.....................v       v..................v       v........v
670          * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
671          * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
672          * ^.....................^     ^..................^       ^........^
673          * \new                  \nfd  \nsb               \nse     \nls    \ne
674          *
675          * fx is the difference in length between the chars between nfd and
676          * nsb, and the chars between ofd and osb, and is thus the number of
677          * characters to delete if < 0 (new is shorter than old, as above),
678          * or insert (new is longer than short).
679          *
680          * sx is the same for the second differences.
681          */
682
683         /*
684          * if we have a net insert on the first difference, AND inserting the
685          * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
686          * character (which is ne if nls != ne, otherwise is nse) off the edge
687          * of the screen (el->el_term.t_size.h) else we do the deletes first
688          * so that we keep everything we need to.
689          */
690
691         /*
692          * if the last same is the same like the end, there is no last same
693          * part, otherwise we want to keep the last same part set p to the
694          * last useful old character
695          */
696         p = (ols != oe) ? oe : ose;
697
698         /*
699          * if (There is a diffence in the beginning) && (we need to insert
700          *   characters) && (the number of characters to insert is less than
701          *   the term width)
702          *      We need to do an insert!
703          * else if (we need to delete characters)
704          *      We need to delete characters!
705          * else
706          *      No insert or delete
707          */
708         if ((nsb != nfd) && fx > 0 &&
709             ((p - old) + fx <= el->el_term.t_size.h)) {
710                 ELRE_DEBUG(1,
711                     (__F, "first diff insert at %d...\r\n", nfd - new));
712                 /*
713                  * Move to the first char to insert, where the first diff is.
714                  */
715                 term_move_to_char(el, nfd - new);
716                 /*
717                  * Check if we have stuff to keep at end
718                  */
719                 if (nsb != ne) {
720                         ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
721                         /*
722                          * insert fx chars of new starting at nfd
723                          */
724                         if (fx > 0) {
725                                 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
726                                 "ERROR: cannot insert in early first diff\n"));
727                                 term_insertwrite(el, nfd, fx);
728                                 re_insert(el, old, ofd - old,
729                                     el->el_term.t_size.h, nfd, fx);
730                         }
731                         /*
732                          * write (nsb-nfd) - fx chars of new starting at
733                          * (nfd + fx)
734                          */
735                         term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
736                         re__strncopy(ofd + fx, nfd + fx,
737                             (size_t) ((nsb - nfd) - fx));
738                 } else {
739                         ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
740                         term_overwrite(el, nfd, (nsb - nfd));
741                         re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
742                         /*
743                          * Done
744                          */
745                         return;
746                 }
747         } else if (fx < 0) {
748                 ELRE_DEBUG(1,
749                     (__F, "first diff delete at %d...\r\n", ofd - old));
750                 /*
751                  * move to the first char to delete where the first diff is
752                  */
753                 term_move_to_char(el, ofd - old);
754                 /*
755                  * Check if we have stuff to save
756                  */
757                 if (osb != oe) {
758                         ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
759                         /*
760                          * fx is less than zero *always* here but we check
761                          * for code symmetry
762                          */
763                         if (fx < 0) {
764                                 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
765                                     "ERROR: cannot delete in first diff\n"));
766                                 term_deletechars(el, -fx);
767                                 re_delete(el, old, ofd - old,
768                                     el->el_term.t_size.h, -fx);
769                         }
770                         /*
771                          * write (nsb-nfd) chars of new starting at nfd
772                          */
773                         term_overwrite(el, nfd, (nsb - nfd));
774                         re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
775
776                 } else {
777                         ELRE_DEBUG(1, (__F,
778                             "but with nothing left to save\r\n"));
779                         /*
780                          * write (nsb-nfd) chars of new starting at nfd
781                          */
782                         term_overwrite(el, nfd, (nsb - nfd));
783                         ELRE_DEBUG(1, (__F,
784                             "cleareol %d\n", (oe - old) - (ne - new)));
785                         term_clear_EOL(el, (oe - old) - (ne - new));
786                         /*
787                          * Done
788                          */
789                         return;
790                 }
791         } else
792                 fx = 0;
793
794         if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
795                 ELRE_DEBUG(1, (__F,
796                     "second diff delete at %d...\r\n", (ose - old) + fx));
797                 /*
798                  * Check if we have stuff to delete
799                  */
800                 /*
801                  * fx is the number of characters inserted (+) or deleted (-)
802                  */
803
804                 term_move_to_char(el, (ose - old) + fx);
805                 /*
806                  * Check if we have stuff to save
807                  */
808                 if (ols != oe) {
809                         ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
810                         /*
811                          * Again a duplicate test.
812                          */
813                         if (sx < 0) {
814                                 ELRE_DEBUG(!EL_CAN_DELETE, (__F,
815                                     "ERROR: cannot delete in second diff\n"));
816                                 term_deletechars(el, -sx);
817                         }
818                         /*
819                          * write (nls-nse) chars of new starting at nse
820                          */
821                         term_overwrite(el, nse, (nls - nse));
822                 } else {
823                         ELRE_DEBUG(1, (__F,
824                             "but with nothing left to save\r\n"));
825                         term_overwrite(el, nse, (nls - nse));
826                         ELRE_DEBUG(1, (__F,
827                             "cleareol %d\n", (oe - old) - (ne - new)));
828                         if ((oe - old) - (ne - new) != 0)
829                                 term_clear_EOL(el, (oe - old) - (ne - new));
830                 }
831         }
832         /*
833          * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
834          */
835         if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
836                 ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
837                     nfd - new));
838
839                 term_move_to_char(el, nfd - new);
840                 /*
841                  * Check if we have stuff to keep at the end
842                  */
843                 if (nsb != ne) {
844                         ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
845                         /*
846                          * We have to recalculate fx here because we set it
847                          * to zero above as a flag saying that we hadn't done
848                          * an early first insert.
849                          */
850                         fx = (nsb - nfd) - (osb - ofd);
851                         if (fx > 0) {
852                                 /*
853                                  * insert fx chars of new starting at nfd
854                                  */
855                                 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
856                                  "ERROR: cannot insert in late first diff\n"));
857                                 term_insertwrite(el, nfd, fx);
858                                 re_insert(el, old, ofd - old,
859                                     el->el_term.t_size.h, nfd, fx);
860                         }
861                         /*
862                          * write (nsb-nfd) - fx chars of new starting at
863                          * (nfd + fx)
864                          */
865                         term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
866                         re__strncopy(ofd + fx, nfd + fx,
867                             (size_t) ((nsb - nfd) - fx));
868                 } else {
869                         ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
870                         term_overwrite(el, nfd, (nsb - nfd));
871                         re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
872                 }
873         }
874         /*
875          * line is now NEW up to nse
876          */
877         if (sx >= 0) {
878                 ELRE_DEBUG(1, (__F,
879                     "second diff insert at %d...\r\n", nse - new));
880                 term_move_to_char(el, nse - new);
881                 if (ols != oe) {
882                         ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
883                         if (sx > 0) {
884                                 /* insert sx chars of new starting at nse */
885                                 ELRE_DEBUG(!EL_CAN_INSERT, (__F,
886                                     "ERROR: cannot insert in second diff\n"));
887                                 term_insertwrite(el, nse, sx);
888                         }
889                         /*
890                          * write (nls-nse) - sx chars of new starting at
891                          * (nse + sx)
892                          */
893                         term_overwrite(el, nse + sx, (nls - nse) - sx);
894                 } else {
895                         ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
896                         term_overwrite(el, nse, (nls - nse));
897
898                         /*
899                          * No need to do a clear-to-end here because we were
900                          * doing a second insert, so we will have over
901                          * written all of the old string.
902                          */
903                 }
904         }
905         ELRE_DEBUG(1, (__F, "done.\r\n"));
906 }
907
908
909 /* re__copy_and_pad():
910  *      Copy string and pad with spaces
911  */
912 private void
913 re__copy_and_pad(char *dst, char *src, size_t width)
914 {
915         int i;
916
917         for (i = 0; i < width; i++) {
918                 if (*src == '\0')
919                         break;
920                 *dst++ = *src++;
921         }
922
923         for (; i < width; i++)
924                 *dst++ = ' ';
925
926         *dst = '\0';
927 }
928
929
930 /* re_refresh_cursor():
931  *      Move to the new cursor position
932  */
933 protected void
934 re_refresh_cursor(EditLine *el)
935 {
936         char *cp, c;
937         int h, v, th;
938
939         /* first we must find where the cursor is... */
940         h = el->el_prompt.p_pos.h;
941         v = el->el_prompt.p_pos.v;
942         th = el->el_term.t_size.h;      /* optimize for speed */
943
944         /* do input buffer to el->el_line.cursor */
945         for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
946                 c = *cp;
947                 h++;            /* all chars at least this long */
948
949                 if (c == '\n') {/* handle newline in data part too */
950                         h = 0;
951                         v++;
952                 } else {
953                         if (c == '\t') {        /* if a tab, to next tab stop */
954                                 while (h & 07) {
955                                         h++;
956                                 }
957                         } else if (iscntrl((unsigned char) c)) {
958                                                 /* if control char */
959                                 h++;
960                                 if (h > th) {   /* if overflow, compensate */
961                                         h = 1;
962                                         v++;
963                                 }
964                         } else if (!isprint((unsigned char) c)) {
965                                 h += 3;
966                                 if (h > th) {   /* if overflow, compensate */
967                                         h = h - th;
968                                         v++;
969                                 }
970                         }
971                 }
972
973                 if (h >= th) {  /* check, extra long tabs picked up here also */
974                         h = 0;
975                         v++;
976                 }
977         }
978
979         /* now go there */
980         term_move_to_line(el, v);
981         term_move_to_char(el, h);
982         term__flush();
983 }
984
985
986 /* re_fastputc():
987  *      Add a character fast.
988  */
989 private void
990 re_fastputc(EditLine *el, int c)
991 {
992
993         term__putc(c);
994         el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
995         if (el->el_cursor.h >= el->el_term.t_size.h) {
996                 /* if we must overflow */
997                 el->el_cursor.h = 0;
998
999                 /*
1000                  * If we would overflow (input is longer than terminal size),
1001                  * emulate scroll by dropping first line and shuffling the rest.
1002                  * We do this via pointer shuffling - it's safe in this case
1003                  * and we avoid memcpy().
1004                  */
1005                 if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
1006                         int i, lins = el->el_term.t_size.v;
1007                         char *firstline = el->el_display[0];
1008        
1009                         for(i=1; i < lins; i++)
1010                                 el->el_display[i-1] = el->el_display[i];
1011
1012                         re__copy_and_pad(firstline, "", 0);
1013                         el->el_display[i-1] = firstline;
1014                 } else {
1015                         el->el_cursor.v++;
1016                         el->el_refresh.r_oldcv++;
1017                 }
1018                 if (EL_HAS_AUTO_MARGINS) {
1019                         if (EL_HAS_MAGIC_MARGINS) {
1020                                 term__putc(' ');
1021                                 term__putc('\b');
1022                         }
1023                 } else {
1024                         term__putc('\r');
1025                         term__putc('\n');
1026                 }
1027         }
1028 }
1029
1030
1031 /* re_fastaddc():
1032  *      we added just one char, handle it fast.
1033  *      Assumes that screen cursor == real cursor
1034  */
1035 protected void
1036 re_fastaddc(EditLine *el)
1037 {
1038         char c;
1039         int rhdiff;
1040
1041         c = el->el_line.cursor[-1];
1042
1043         if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1044                 re_refresh(el); /* too hard to handle */
1045                 return;
1046         }
1047         rhdiff = el->el_term.t_size.h - el->el_cursor.h -
1048             el->el_rprompt.p_pos.h;
1049         if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1050                 re_refresh(el); /* clear out rprompt if less than 1 char gap */
1051                 return;
1052         }                       /* else (only do at end of line, no TAB) */
1053         if (iscntrl((unsigned char) c)) {       /* if control char, do caret */
1054                 char mc = (c == '\177') ? '?' : (c | 0100);
1055                 re_fastputc(el, '^');
1056                 re_fastputc(el, mc);
1057         } else if (isprint((unsigned char) c)) {        /* normal char */
1058                 re_fastputc(el, c);
1059         } else {
1060                 re_fastputc(el, '\\');
1061                 re_fastputc(el, (int) ((((unsigned int) c >> 6) & 7) + '0'));
1062                 re_fastputc(el, (int) ((((unsigned int) c >> 3) & 7) + '0'));
1063                 re_fastputc(el, (c & 7) + '0');
1064         }
1065         term__flush();
1066 }
1067
1068
1069 /* re_clear_display():
1070  *      clear the screen buffers so that new new prompt starts fresh.
1071  */
1072 protected void
1073 re_clear_display(EditLine *el)
1074 {
1075         int i;
1076
1077         el->el_cursor.v = 0;
1078         el->el_cursor.h = 0;
1079         for (i = 0; i < el->el_term.t_size.v; i++)
1080                 el->el_display[i][0] = '\0';
1081         el->el_refresh.r_oldcv = 0;
1082 }
1083
1084
1085 /* re_clear_lines():
1086  *      Make sure all lines are *really* blank
1087  */
1088 protected void
1089 re_clear_lines(EditLine *el)
1090 {
1091
1092         if (EL_CAN_CEOL) {
1093                 int i;
1094                 term_move_to_char(el, 0);
1095                 for (i = 0; i <= el->el_refresh.r_oldcv; i++) {
1096                         /* for each line on the screen */
1097                         term_move_to_line(el, i);
1098                         term_clear_EOL(el, el->el_term.t_size.h);
1099                 }
1100                 term_move_to_line(el, 0);
1101         } else {
1102                 term_move_to_line(el, el->el_refresh.r_oldcv);
1103                                         /* go to last line */
1104                 term__putc('\r');       /* go to BOL */
1105                 term__putc('\n');       /* go to new line */
1106         }
1107 }
Note: See TracBrowser for help on using the browser.