| 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 |
} |
|---|