1/* 2 * zle_refresh.c - screen update 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1992-1997 Paul Falstad 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Paul Falstad or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Paul Falstad and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Paul Falstad and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Paul Falstad and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zle.mdh" 31 32#ifdef MULTIBYTE_SUPPORT 33/* 34 * Handling for glyphs that contain more than one wide character, 35 * if ZLE_COMBINING_CHARS is set. Each glyph is one character with 36 * non-zero width followed by an arbitrary (but typically small) 37 * number of characters that have zero width (combining characters). 38 * 39 * The allocated size for each array is given by ?mw_size; nmw_ind 40 * is the next free element, i.e. nmwbuf[nmw_ind] will be the next 41 * element to be written (we never insert into omwbuf). We initialise 42 * nmw_ind to 1 to avoid the index stored in the character looking like a 43 * NULL. This wastees a word but it's safer than messing with pointers. 44 * 45 * The layout of the buffer is as a string of entries that consist of multiple 46 * elements of the allocated array with no boundary (the code keeps track of 47 * where each entry starts). Note distinction between (logical) entries and 48 * (array) elements. Each entry consists of an element giving the total 49 * number of wide characters for the entry (there are N+1 wide characters, 50 * where N >= 1 is the number of trailing zero width characters), followed by 51 * those characters. 52 */ 53static REFRESH_CHAR 54 *omwbuf = NULL, /* old multiword glyph buffer */ 55 *nmwbuf = NULL; /* new multiword glyph buffer */ 56#endif 57 58/* 59 * Compare if two characters are equal. 60 */ 61#ifdef MULTIBYTE_SUPPORT 62/* 63 * We may need to compare values in multiword arrays. As the arrays are 64 * different for the old and new video arrays, it is vital that the comparison 65 * always be done in the correct order: an element of the old video array, 66 * followed by an element of the new one. In this case, having ascertained 67 * that both elements are multiword (because they have the some attributes), 68 * we do the character comparison in two stages: first we check that the 69 * lengths are the same, then we check that the characters stored are the 70 * same. This ensures we can't read past the end of either array. If either 71 * character is a constant, then TXT_MULTIWORD_MASK is guaranteed not to be 72 * set and this doesn't matter. 73 */ 74#define ZR_equal(oldzr, newzr) \ 75 ((oldzr).atr == (newzr).atr && \ 76 (((oldzr).atr & TXT_MULTIWORD_MASK) ? \ 77 (omwbuf[(oldzr).chr] == nmwbuf[(newzr).chr] && \ 78 !memcmp(omwbuf + (oldzr).chr + 1, nmwbuf + (newzr).chr + 1, \ 79 omwbuf[(oldzr).chr] * sizeof(*omwbuf))) : \ 80 (oldzr).chr == (newzr).chr)) 81#else 82#define ZR_equal(zr1, zr2) ((zr1).chr == (zr2).chr && (zr1).atr == (zr2).atr) 83#endif 84 85static void 86ZR_memset(REFRESH_ELEMENT *dst, REFRESH_ELEMENT rc, int len) 87{ 88 while (len--) 89 *dst++ = rc; 90} 91 92#define ZR_memcpy(d, s, l) memcpy((d), (s), (l)*sizeof(REFRESH_ELEMENT)) 93 94static void 95ZR_strcpy(REFRESH_ELEMENT *dst, const REFRESH_ELEMENT *src) 96{ 97 while ((*dst++ = *src++).chr != ZWC('\0')) 98 ; 99} 100 101static size_t 102ZR_strlen(const REFRESH_ELEMENT *wstr) 103{ 104 int len = 0; 105 106 while (wstr++->chr != ZWC('\0')) 107 len++; 108 109 return len; 110} 111 112/* 113 * Simplified strcmp: we don't need the sign, just whether 114 * the strings and their attributes are equal. 115 * 116 * In the multibyte case, the two elements must be in the order 117 * element from old video array, element from new video array. 118 */ 119static int 120ZR_strncmp(const REFRESH_ELEMENT *oldwstr, const REFRESH_ELEMENT *newwstr, 121 int len) 122{ 123 while (len--) { 124 if ((!(oldwstr->atr & TXT_MULTIWORD_MASK) && !oldwstr->chr) || 125 (!(newwstr->atr & TXT_MULTIWORD_MASK) && !newwstr->chr)) 126 return !ZR_equal(*oldwstr, *newwstr); 127 if (!ZR_equal(*oldwstr, *newwstr)) 128 return 1; 129 oldwstr++; 130 newwstr++; 131 } 132 133 return 0; 134} 135 136#include "zle_refresh.pro" 137 138/* 139 * Expanded prompts. 140 * 141 * These are always output from the start, except in the special 142 * case where we are sure each character in the prompt corresponds 143 * to a character on screen. 144 */ 145 146/**/ 147char *lpromptbuf, *rpromptbuf; 148 149/* Text attributes after displaying prompts */ 150 151/**/ 152unsigned pmpt_attr, rpmpt_attr; 153 154/* number of lines displayed */ 155 156/**/ 157mod_export int nlnct; 158 159/* Most lines of the buffer we've shown at once with the current list * 160 * showing. == 0 if there is no list. == -1 if a new list has just * 161 * been put on the screen. == -2 if zrefresh() needs to put up a new * 162 * list. */ 163 164/**/ 165mod_export int showinglist; 166 167/* > 0 if a completion list is displayed below the prompt, 168 * < 0 if a list is displayed above the prompt. */ 169 170/**/ 171mod_export int listshown; 172 173/* Length of last list displayed (if it is below the prompt). */ 174 175/**/ 176mod_export int lastlistlen; 177 178/* Non-zero if ALWAYS_LAST_PROMPT has been used, meaning that the * 179 * screen below the buffer display should not be cleared by * 180 * zrefresh(), but should be by trashzle(). */ 181 182/**/ 183mod_export int clearflag; 184 185/* Non-zero if zrefresh() should clear the list below the prompt. */ 186 187/**/ 188mod_export int clearlist; 189 190/* Zle in trashed state - updates may be subtly altered */ 191 192/**/ 193int trashedzle; 194 195/* 196 * Information used by PREDISPLAY and POSTDISPLAY parameters which 197 * add non-editable text to that being displayed. 198 */ 199/**/ 200ZLE_STRING_T predisplay, postdisplay; 201/**/ 202int predisplaylen, postdisplaylen; 203 204 205/* 206 * Attributes used by default on the command line, and 207 * attributes for highlighting special (unprintable) characters 208 * displayed on screen. 209 */ 210 211static int default_atr_on, special_atr_on; 212 213/* 214 * Array of region highlights, no special termination. 215 * The first element (0) always describes the region between 216 * point and mark. Any other elements are set by the user 217 * via the parameter region_highlight. 218 */ 219 220/**/ 221struct region_highlight *region_highlights; 222 223/* 224 * Number of elements in region_highlights. 225 * This includes the special elements above. 226 */ 227/**/ 228int n_region_highlights; 229 230/* 231 * Flag that highlighting of the region is active. 232 */ 233/**/ 234int region_active; 235 236/* 237 * Name of function to use to output termcap values, if defined. 238 */ 239/**/ 240char *tcout_func_name; 241 242#ifdef HAVE_SELECT 243/* cost of last update */ 244/**/ 245int cost; 246 247# define SELECT_ADD_COST(X) (cost += X) 248# define zputc(a) (zwcputc(a, NULL), cost++) 249# define zwrite(a, b) (zwcwrite((a), (b)), \ 250 cost += ((b) * ZLE_CHAR_SIZE)) 251#else 252# define SELECT_ADD_COST(X) 253# define zputc(a) zwcputc(a, NULL) 254# define zwrite(a, b) zwcwrite((a), (b)) 255#endif 256 257static const REFRESH_ELEMENT zr_cr = { ZWC('\r'), 0 }; 258static const REFRESH_ELEMENT zr_dt = { ZWC('.'), 0 }; 259static const REFRESH_ELEMENT zr_nl = { ZWC('\n'), 0 }; 260static const REFRESH_ELEMENT zr_sp = { ZWC(' '), 0 }; 261static const REFRESH_ELEMENT zr_ht = { ZWC('\t'), 0 }; 262static const REFRESH_ELEMENT zr_zr = { ZWC('\0'), 0 }; 263 264/* 265 * Constant arrays to be copied into place: these are memcpy'd, 266 * so don't have terminating NULLs. 267 */ 268static const REFRESH_ELEMENT zr_end_ellipsis[] = { 269 { ZWC(' '), 0 }, 270 { ZWC('<'), 0 }, 271 { ZWC('.'), 0 }, 272 { ZWC('.'), 0 }, 273 { ZWC('.'), 0 }, 274 { ZWC('.'), 0 }, 275 { ZWC(' '), 0 }, 276}; 277#define ZR_END_ELLIPSIS_SIZE \ 278 ((int)(sizeof(zr_end_ellipsis)/sizeof(zr_end_ellipsis[0]))) 279 280static const REFRESH_ELEMENT zr_mid_ellipsis1[] = { 281 { ZWC(' '), 0 }, 282 { ZWC('<'), 0 }, 283 { ZWC('.'), 0 }, 284 { ZWC('.'), 0 }, 285 { ZWC('.'), 0 }, 286 { ZWC('.'), 0 }, 287}; 288#define ZR_MID_ELLIPSIS1_SIZE \ 289 ((int)(sizeof(zr_mid_ellipsis1)/sizeof(zr_mid_ellipsis1[0]))) 290 291static const REFRESH_ELEMENT zr_mid_ellipsis2[] = { 292 { ZWC('>'), 0 }, 293 { ZWC(' '), 0 }, 294}; 295#define ZR_MID_ELLIPSIS2_SIZE \ 296 ((int)(sizeof(zr_mid_ellipsis2)/sizeof(zr_mid_ellipsis2[0]))) 297 298static const REFRESH_ELEMENT zr_start_ellipsis[] = { 299 { ZWC('>'), 0 }, 300 { ZWC('.'), 0 }, 301 { ZWC('.'), 0 }, 302 { ZWC('.'), 0 }, 303 { ZWC('.'), 0 }, 304}; 305#define ZR_START_ELLIPSIS_SIZE \ 306 ((int)(sizeof(zr_start_ellipsis)/sizeof(zr_start_ellipsis[0]))) 307 308/* 309 * Parse the variable zle_highlight to decide how to highlight characters 310 * and regions. Set defaults for anything not explicitly covered. 311 */ 312 313/**/ 314static void 315zle_set_highlight(void) 316{ 317 char **atrs = getaparam("zle_highlight"); 318 int special_atr_on_set = 0; 319 int region_atr_on_set = 0; 320 int isearch_atr_on_set = 0; 321 int suffix_atr_on_set = 0; 322 struct region_highlight *rhp; 323 324 special_atr_on = default_atr_on = 0; 325 if (!region_highlights) { 326 region_highlights = (struct region_highlight *) 327 zshcalloc(N_SPECIAL_HIGHLIGHTS*sizeof(struct region_highlight)); 328 n_region_highlights = N_SPECIAL_HIGHLIGHTS; 329 } else { 330 for (rhp = region_highlights; 331 rhp < region_highlights + N_SPECIAL_HIGHLIGHTS; 332 rhp++) { 333 rhp->atr = 0; 334 } 335 } 336 337 if (atrs) { 338 for (; *atrs; atrs++) { 339 if (!strcmp(*atrs, "none")) { 340 /* reset attributes for consistency... usually unnecessary */ 341 special_atr_on = default_atr_on = 0; 342 special_atr_on_set = region_atr_on_set = 343 isearch_atr_on_set = suffix_atr_on_set = 1; 344 } else if (strpfx("default:", *atrs)) { 345 match_highlight(*atrs + 8, &default_atr_on); 346 } else if (strpfx("special:", *atrs)) { 347 match_highlight(*atrs + 8, &special_atr_on); 348 special_atr_on_set = 1; 349 } else if (strpfx("region:", *atrs)) { 350 match_highlight(*atrs + 7, ®ion_highlights[0].atr); 351 region_atr_on_set = 1; 352 } else if (strpfx("isearch:", *atrs)) { 353 match_highlight(*atrs + 8, &(region_highlights[1].atr)); 354 isearch_atr_on_set = 1; 355 } else if (strpfx("suffix:", *atrs)) { 356 match_highlight(*atrs + 7, &(region_highlights[2].atr)); 357 suffix_atr_on_set = 1; 358 } 359 } 360 } 361 362 /* Defaults */ 363 if (!special_atr_on_set) 364 special_atr_on = TXTSTANDOUT; 365 if (!region_atr_on_set) 366 region_highlights[0].atr = TXTSTANDOUT; 367 if (!isearch_atr_on_set) 368 region_highlights[1].atr = TXTUNDERLINE; 369 if (!suffix_atr_on_set) 370 region_highlights[2].atr = TXTBOLDFACE; 371 372 allocate_colour_buffer(); 373} 374 375 376/**/ 377static void 378zle_free_highlight(void) 379{ 380 free_colour_buffer(); 381} 382 383/* 384 * Interface to the region_highlight ZLE parameter. 385 * Converts betwen a format like "P32 42 underline,bold" to 386 * the format in the region_highlights variable. Note that 387 * the region_highlights variable stores the internal (point/mark) 388 * region in element zero. 389 */ 390 391/**/ 392char ** 393get_region_highlight(UNUSED(Param pm)) 394{ 395 int arrsize = n_region_highlights; 396 char **retarr, **arrp; 397 struct region_highlight *rhp; 398 399 /* region_highlights may not have been set yet */ 400 if (arrsize) 401 arrsize -= N_SPECIAL_HIGHLIGHTS; 402 arrp = retarr = (char **)zhalloc((arrsize+1)*sizeof(char *)); 403 404 /* ignore special highlighting */ 405 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 406 arrsize--; 407 rhp++, arrp++) { 408 char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE]; 409 int atrlen = 0, alloclen; 410 411 sprintf(digbuf1, "%d", rhp->start); 412 sprintf(digbuf2, "%d", rhp->end); 413 414 atrlen = output_highlight(rhp->atr, NULL); 415 alloclen = atrlen + strlen(digbuf1) + strlen(digbuf2) + 416 3; /* 2 spaces, 1 0 */ 417 if (rhp->flags & ZRH_PREDISPLAY) 418 alloclen += 2; /* "P " */ 419 *arrp = (char *)zhalloc(alloclen * sizeof(char)); 420 /* 421 * On input we allow a space after the flags. 422 * I haven't put a space here because I think it's 423 * marginally easier to have the output always split 424 * into three words, and then check the first to 425 * see if there are flags. However, it's arguable. 426 */ 427 sprintf(*arrp, "%s%s %s ", 428 (rhp->flags & ZRH_PREDISPLAY) ? "P" : "", 429 digbuf1, digbuf2); 430 (void)output_highlight(rhp->atr, *arrp + strlen(*arrp)); 431 } 432 *arrp = '\0'; 433 return retarr; 434} 435 436 437/* 438 * The parameter system requires the pm argument, but this 439 * may be NULL if called directly. 440 */ 441 442/**/ 443void 444set_region_highlight(UNUSED(Param pm), char **aval) 445{ 446 int len; 447 struct region_highlight *rhp; 448 449 len = aval ? arrlen(aval) : 0; 450 if (n_region_highlights != len + N_SPECIAL_HIGHLIGHTS) { 451 /* no null termination, but include special highlighting at start */ 452 n_region_highlights = len + N_SPECIAL_HIGHLIGHTS; 453 region_highlights = (struct region_highlight *) 454 zrealloc(region_highlights, 455 sizeof(struct region_highlight) * n_region_highlights); 456 } 457 458 if (!aval) 459 return; 460 461 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 462 *aval; 463 rhp++, aval++) { 464 char *strp, *oldstrp; 465 466 oldstrp = *aval; 467 if (*oldstrp == 'P') { 468 rhp->flags = ZRH_PREDISPLAY; 469 oldstrp++; 470 } 471 else 472 rhp->flags = 0; 473 while (inblank(*oldstrp)) 474 oldstrp++; 475 476 rhp->start = (int)zstrtol(oldstrp, &strp, 10); 477 if (strp == oldstrp) 478 rhp->start = -1; 479 480 while (inblank(*strp)) 481 strp++; 482 483 oldstrp = strp; 484 rhp->end = (int)zstrtol(strp, &strp, 10); 485 if (strp == oldstrp) 486 rhp->end = -1; 487 488 while (inblank(*strp)) 489 strp++; 490 491 match_highlight(strp, &rhp->atr); 492 } 493} 494 495 496/**/ 497void 498unset_region_highlight(Param pm, int exp) 499{ 500 if (exp) { 501 set_region_highlight(pm, NULL); 502 stdunsetfn(pm, exp); 503 } 504} 505 506 507/* The last attributes that were on. */ 508static int lastatr; 509 510/* 511 * Clear the last attributes that we set: used when we're going 512 * to be outputting stuff that shouldn't show up as text. 513 */ 514static void 515clearattributes(void) 516{ 517 if (lastatr) { 518 settextattributes(TXT_ATTR_OFF_FROM_ON(lastatr)); 519 lastatr = 0; 520 } 521} 522 523/* 524 * Output a termcap capability, clearing any text attributes so 525 * as not to mess up the display. 526 */ 527 528static void 529tcoutclear(int cap) 530{ 531 clearattributes(); 532 tcout(cap); 533} 534 535/* 536 * Output the character. This must come from the new video 537 * buffer, nbuf, since we access the multiword buffer nmwbuf 538 * directly. 539 * 540 * curatrp may be NULL, otherwise points to an integer specifying 541 * what attributes were turned on for a character output immediately 542 * before, in order to optimise output of attribute changes. 543 */ 544 545/**/ 546void 547zwcputc(const REFRESH_ELEMENT *c, int *curatrp) 548{ 549 /* 550 * Safety: turn attributes off if last heard of turned on. 551 * This differs from *curatrp, which is an optimisation for 552 * writing lots of stuff at once. 553 */ 554#ifdef MULTIBYTE_SUPPORT 555 mbstate_t mbstate; 556 int i; 557 VARARR(char, mbtmp, MB_CUR_MAX + 1); 558#endif 559 560 if (lastatr & ~c->atr) { 561 /* Stuff on we don't want, turn it off */ 562 settextattributes(TXT_ATTR_OFF_FROM_ON(lastatr & ~c->atr)); 563 lastatr = 0; 564 } 565 566 /* 567 * Don't output "on" attributes in a string of characters with 568 * the same attributes. Be careful in case a different colour 569 * needs setting. 570 */ 571 if ((c->atr & TXT_ATTR_ON_MASK) && 572 (!curatrp || 573 ((*curatrp & TXT_ATTR_ON_VALUES_MASK) != 574 (c->atr & TXT_ATTR_ON_VALUES_MASK)))) { 575 /* Record just the control flags we might need to turn off... */ 576 lastatr = c->atr & TXT_ATTR_ON_MASK; 577 /* ...but set including the values for colour attributes */ 578 settextattributes(c->atr & TXT_ATTR_ON_VALUES_MASK); 579 } 580 581#ifdef MULTIBYTE_SUPPORT 582 if (c->atr & TXT_MULTIWORD_MASK) { 583 /* Multiword glyph stored in nmwbuf */ 584 int nchars = nmwbuf[c->chr]; 585 REFRESH_CHAR *wcptr = nmwbuf + c->chr + 1; 586 587 memset(&mbstate, 0, sizeof(mbstate_t)); 588 while (nchars--) { 589 if ((i = wcrtomb(mbtmp, (wchar_t)*wcptr++, &mbstate)) > 0) 590 fwrite(mbtmp, i, 1, shout); 591 } 592 } else if (c->chr != WEOF) { 593 memset(&mbstate, 0, sizeof(mbstate_t)); 594 if ((i = wcrtomb(mbtmp, (wchar_t)c->chr, &mbstate)) > 0) 595 fwrite(mbtmp, i, 1, shout); 596 } 597#else 598 fputc(c->chr, shout); 599#endif 600 601 /* 602 * Always output "off" attributes since we only turn off at 603 * the end of a chunk of highlighted text. 604 */ 605 if (c->atr & TXT_ATTR_OFF_MASK) { 606 settextattributes(c->atr & TXT_ATTR_OFF_MASK); 607 lastatr &= ~((c->atr & TXT_ATTR_OFF_MASK) >> TXT_ATTR_OFF_ON_SHIFT); 608 } 609 if (curatrp) { 610 /* 611 * Remember the current attributes: those that are turned 612 * on, less those that are turned off again. Include 613 * colour attributes here in case the colour changes to 614 * another non-default one. 615 */ 616 *curatrp = (c->atr & TXT_ATTR_ON_VALUES_MASK) & 617 ~((c->atr & TXT_ATTR_OFF_MASK) >> TXT_ATTR_OFF_ON_SHIFT); 618 } 619} 620 621static int 622zwcwrite(const REFRESH_STRING s, size_t i) 623{ 624 size_t j; 625 int curatr = 0; 626 627 for (j = 0; j < i; j++) 628 zwcputc(s + j, &curatr); 629 return i; /* TODO something better for error indication */ 630} 631 632/* Oct/Nov 94: <mason> some code savagely redesigned to fix several bugs - 633 refreshline() & tc_rightcurs() majorly rewritten; zrefresh() fixed - 634 I've put my fingers into just about every routine in here - 635 any queries about updates to mason@primenet.com.au */ 636 637static REFRESH_STRING 638 *nbuf = NULL, /* new video buffer line-by-line array */ 639 *obuf = NULL; /* old video buffer line-by-line array */ 640static int more_start, /* more text before start of screen? */ 641 more_end, /* more stuff after end of screen? */ 642 olnct, /* previous number of lines */ 643 ovln, /* previous video cursor position line */ 644 lpromptw, rpromptw, /* prompt widths on screen */ 645 lpromptwof, /* left prompt width with real end position */ 646 lprompth, /* lines taken up by the prompt */ 647 rprompth, /* right prompt height */ 648 vcs, vln, /* video cursor position column & line */ 649 vmaxln, /* video maximum number of lines */ 650 winw, winh, rwinh, /* window width & height */ 651 winpos, /* singlelinezle: line's position in window */ 652 winprompt, /* singlelinezle: part of lprompt showing */ 653 winw_alloc = -1, /* allocated window width */ 654 winh_alloc = -1; /* allocates window height */ 655#ifdef MULTIBYTE_SUPPORT 656static int 657 omw_size, /* allocated size of omwbuf */ 658 nmw_size, /* allocated size of nmwbuf */ 659 nmw_ind; /* next insert point in nmw_ind */ 660#endif 661 662/* 663 * Number of words to allocate in one go for the multiword buffers. 664 */ 665#define DEF_MWBUF_ALLOC (32) 666 667static void 668freevideo(void) 669{ 670 if (nbuf) { 671 int ln; 672 for (ln = 0; ln != winh_alloc; ln++) { 673 zfree(nbuf[ln], (winw_alloc + 2) * sizeof(**nbuf)); 674 zfree(obuf[ln], (winw_alloc + 2) * sizeof(**obuf)); 675 } 676 free(nbuf); 677 free(obuf); 678#ifdef MULTIBYTE_SUPPORT 679 zfree(nmwbuf, nmw_size * sizeof(*nmwbuf)); 680 zfree(omwbuf, omw_size * sizeof(*omwbuf)); 681 omw_size = nmw_size = 0; 682 nmw_ind = 1; 683#endif 684 nbuf = NULL; 685 obuf = NULL; 686 winw_alloc = -1; 687 winh_alloc = -1; 688 } 689} 690 691/**/ 692void 693resetvideo(void) 694{ 695 int ln; 696 697 winw = zterm_columns; /* terminal width */ 698 if (termflags & TERM_SHORT) 699 winh = 1; 700 else 701 winh = (zterm_lines < 2) ? 24 : zterm_lines; 702 rwinh = zterm_lines; /* keep the real number of lines */ 703 vln = vmaxln = winprompt = 0; 704 winpos = -1; 705 if (winw_alloc != winw || winh_alloc != winh) { 706 freevideo(); 707 nbuf = (REFRESH_STRING *)zshcalloc((winh + 1) * sizeof(*nbuf)); 708 obuf = (REFRESH_STRING *)zshcalloc((winh + 1) * sizeof(*obuf)); 709 nbuf[0] = (REFRESH_STRING)zalloc((winw + 2) * sizeof(**nbuf)); 710 obuf[0] = (REFRESH_STRING)zalloc((winw + 2) * sizeof(**obuf)); 711 712#ifdef MULTIBYTE_SUPPORT 713 nmw_size = DEF_MWBUF_ALLOC; 714 nmw_ind = 1; 715 nmwbuf = (REFRESH_CHAR *)zalloc(nmw_size * sizeof(*nmwbuf)); 716 717 omw_size = DEF_MWBUF_ALLOC; 718 omwbuf = (REFRESH_CHAR *)zalloc(omw_size * sizeof(*omwbuf)); 719#endif 720 721 winw_alloc = winw; 722 winh_alloc = winh; 723 } 724 for (ln = 0; ln != winh + 1; ln++) { 725 if (nbuf[ln]) { 726 nbuf[ln][0] = zr_nl; 727 nbuf[ln][1] = zr_zr; 728 } 729 if (obuf[ln]) { 730 obuf[ln][0] = zr_nl; 731 obuf[ln][1] = zr_zr; 732 } 733 } 734 735 /* 736 * countprompt() now correctly handles multibyte input. 737 */ 738 countprompt(lpromptbuf, &lpromptwof, &lprompth, 1); 739 countprompt(rpromptbuf, &rpromptw, &rprompth, 0); 740 if (lpromptwof != winw) 741 lpromptw = lpromptwof; 742 else { 743 lpromptw = 0; 744 lprompth++; 745 } 746 747 if (lpromptw) { 748 ZR_memset(nbuf[0], zr_sp, lpromptw); 749 ZR_memset(obuf[0], zr_sp, lpromptw); 750 nbuf[0][lpromptw] = obuf[0][lpromptw] = zr_zr; 751 } 752 753 vcs = lpromptw; 754 olnct = nlnct = 0; 755 if (showinglist > 0) 756 showinglist = -2; 757 trashedzle = 0; 758} 759 760/* 761 * Nov 96: <mason> changed to single line scroll 762 */ 763 764/**/ 765static void 766scrollwindow(int tline) 767{ 768 int t0; 769 REFRESH_STRING s; 770 771 s = nbuf[tline]; 772 for (t0 = tline; t0 < winh - 1; t0++) 773 nbuf[t0] = nbuf[t0 + 1]; 774 nbuf[winh - 1] = s; 775 if (!tline) 776 more_start = 1; 777 return; 778} 779 780/* 781 * Parameters in zrefresh used for communicating with next-line functions. 782 */ 783struct rparams { 784 int canscroll; /* number of lines we are allowed to scroll */ 785 int ln; /* current line we're working on */ 786 int more_status; /* more stuff in status line */ 787 int nvcs; /* video cursor column */ 788 int nvln; /* video cursor line */ 789 int tosln; /* tmp in statusline stuff */ 790 REFRESH_STRING s; /* pointer into the video buffer */ 791 REFRESH_STRING sen; /* pointer to end of the video buffer (eol) */ 792}; 793typedef struct rparams *Rparams; 794 795static int cleareol, /* clear to end-of-line (if can't cleareod) */ 796 clearf, /* alwayslastprompt used immediately before */ 797 put_rpmpt, /* whether we should display right-prompt */ 798 oput_rpmpt, /* whether displayed right-prompt last time */ 799 oxtabs, /* oxtabs - tabs expand to spaces if set */ 800 numscrolls, onumscrolls; 801 802/* 803 * Go to the next line in the main display area. Return 1 if we should abort 804 * processing the line loop at this point, else 0. 805 * 806 * If wrapped is non-zero, text wrapped, so output newline. 807 * Otherwise, text not wrapped, so output null. 808 */ 809static int 810nextline(Rparams rpms, int wrapped) 811{ 812 nbuf[rpms->ln][winw+1] = wrapped ? zr_nl : zr_zr; 813 *rpms->s = zr_zr; 814 if (rpms->ln != winh - 1) 815 rpms->ln++; 816 else { 817 if (!rpms->canscroll) { 818 if (rpms->nvln != -1 && rpms->nvln != winh - 1 819 && (numscrolls != onumscrolls - 1 820 || rpms->nvln <= winh / 2)) 821 return 1; 822 numscrolls++; 823 rpms->canscroll = winh / 2; 824 } 825 rpms->canscroll--; 826 scrollwindow(0); 827 if (rpms->nvln != -1) 828 rpms->nvln--; 829 } 830 if (!nbuf[rpms->ln]) 831 nbuf[rpms->ln] = (REFRESH_STRING)zalloc((winw + 2) * sizeof(**nbuf)); 832 rpms->s = nbuf[rpms->ln]; 833 rpms->sen = rpms->s + winw; 834 835 return 0; 836} 837 838 839/* 840 * Go to the next line in the status area. 841 */ 842static void 843snextline(Rparams rpms) 844{ 845 *rpms->s = zr_zr; 846 if (rpms->ln != winh - 1) 847 rpms->ln++; 848 else 849 if (rpms->tosln > rpms->ln) { 850 rpms->tosln--; 851 if (rpms->nvln > 1) { 852 scrollwindow(0); 853 rpms->nvln--; 854 } else 855 more_end = 1; 856 } else if (rpms->tosln > 2 && rpms->nvln > 1) { 857 rpms->tosln--; 858 if (rpms->tosln <= rpms->nvln) { 859 scrollwindow(0); 860 rpms->nvln--; 861 } else { 862 scrollwindow(rpms->tosln); 863 more_end = 1; 864 } 865 } else { 866 rpms->more_status = 1; 867 scrollwindow(rpms->tosln + 1); 868 } 869 if (!nbuf[rpms->ln]) 870 nbuf[rpms->ln] = (REFRESH_STRING)zalloc((winw + 2) * sizeof(**nbuf)); 871 rpms->s = nbuf[rpms->ln]; 872 rpms->sen = rpms->s + winw; 873} 874 875 876/**/ 877static void 878settextattributes(int atr) 879{ 880 if (txtchangeisset(atr, TXTNOBOLDFACE)) 881 tsetcap(TCALLATTRSOFF, 0); 882 if (txtchangeisset(atr, TXTNOSTANDOUT)) 883 tsetcap(TCSTANDOUTEND, 0); 884 if (txtchangeisset(atr, TXTNOUNDERLINE)) 885 tsetcap(TCUNDERLINEEND, 0); 886 if (txtchangeisset(atr, TXTBOLDFACE)) 887 tsetcap(TCBOLDFACEBEG, 0); 888 if (txtchangeisset(atr, TXTSTANDOUT)) 889 tsetcap(TCSTANDOUTBEG, 0); 890 if (txtchangeisset(atr, TXTUNDERLINE)) 891 tsetcap(TCUNDERLINEBEG, 0); 892 if (txtchangeisset(atr, TXTFGCOLOUR|TXTNOFGCOLOUR)) 893 set_colour_attribute(atr, COL_SEQ_FG, 0); 894 if (txtchangeisset(atr, TXTBGCOLOUR|TXTNOBGCOLOUR)) 895 set_colour_attribute(atr, COL_SEQ_BG, 0); 896} 897 898#ifdef MULTIBYTE_SUPPORT 899/* 900 * Add a multiword glyph at the screen location base. 901 * tptr points to the source and there are ichars characters. 902 */ 903static void 904addmultiword(REFRESH_ELEMENT *base, ZLE_STRING_T tptr, int ichars) 905{ 906 /* Number of characters needed in buffer incl. count */ 907 int iadd = ichars + 1, icnt; 908 REFRESH_CHAR *nmwptr; 909 base->atr |= TXT_MULTIWORD_MASK; 910 /* check allocation */ 911 if (nmw_ind + iadd > nmw_size) { 912 /* need more space in buffer */ 913 int mw_more = (iadd > DEF_MWBUF_ALLOC) ? iadd : 914 DEF_MWBUF_ALLOC; 915 nmwbuf = (REFRESH_CHAR *) 916 zrealloc(nmwbuf, (nmw_size += mw_more) * 917 sizeof(*nmwbuf)); 918 } 919 /* make buffer entry: count, then characters */ 920 nmwptr = nmwbuf + nmw_ind; 921 *nmwptr++ = ichars; 922 for (icnt = 0; icnt < ichars; icnt++) 923 *nmwptr++ = tptr[icnt]; 924 /* save index and update */ 925 base->chr = (wint_t)nmw_ind; 926 nmw_ind += iadd; 927} 928#endif 929 930 931/* 932 * Swap the old and new video buffers, plus any associated multiword 933 * buffers. The new buffer becomes the old one; the new new buffer 934 * will be filled with the command line next time. 935 */ 936static void 937bufswap(void) 938{ 939 REFRESH_STRING *qbuf; 940#ifdef MULTIBYTE_SUPPORT 941 REFRESH_CHAR *qmwbuf; 942 int itmp; 943#endif 944 945 qbuf = nbuf; 946 nbuf = obuf; 947 obuf = qbuf; 948 949#ifdef MULTIBYTE_SUPPORT 950/* likewise multiword buffers */ 951 qmwbuf = nmwbuf; 952 nmwbuf = omwbuf; 953 omwbuf = qmwbuf; 954 955 itmp = nmw_size; 956 nmw_size = omw_size; 957 omw_size = itmp; 958 959 nmw_ind = 1; 960#endif 961} 962 963 964/**/ 965mod_export void 966zrefresh(void) 967{ 968 static int inlist; /* avoiding recursion */ 969 int iln; /* current line as index in loops */ 970 int t0 = -1; /* tmp */ 971 ZLE_STRING_T tmpline, /* line with added pre/post text */ 972 t, /* pointer into the real buffer */ 973 scs, /* pointer to cursor position in real buffer */ 974 u; /* pointer for status line stuff */ 975 int tmpcs, tmpll; /* ditto cursor position and line length */ 976 int tmppos; /* t - tmpline */ 977 int tmpalloced; /* flag to free tmpline when finished */ 978 int remetafy; /* flag that zle line is metafied */ 979 int txtchange; /* attributes set after prompts */ 980 int rprompt_off; /* Offset of rprompt from right of screen */ 981 struct rparams rpms; 982#ifdef MULTIBYTE_SUPPORT 983 int width; /* width of wide character */ 984#endif 985 986 987 /* If this is called from listmatches() (indirectly via trashzle()), and * 988 * that was called from the end of zrefresh(), then we don't need to do * 989 * anything. All this `inlist' code is actually unnecessary, but it * 990 * improves speed a little in a common case. */ 991 if (inlist) 992 return; 993 994 /* 995 * zrefresh() is called from all over the place, so we can't 996 * be sure if the line is metafied for completion or not. 997 */ 998 if (zlemetaline != NULL) { 999 remetafy = 1; 1000 unmetafy_line(); 1001 } 1002 else 1003 remetafy = 0; 1004 1005 if (predisplaylen || postdisplaylen) { 1006 /* There is extra text to display at the start or end of the line */ 1007 tmpline = zalloc((zlell + predisplaylen + postdisplaylen)*sizeof(*tmpline)); 1008 if (predisplaylen) 1009 ZS_memcpy(tmpline, predisplay, predisplaylen); 1010 if (zlell) 1011 ZS_memcpy(tmpline+predisplaylen, zleline, zlell); 1012 if (postdisplaylen) 1013 ZS_memcpy(tmpline+predisplaylen+zlell, postdisplay, 1014 postdisplaylen); 1015 1016 tmpcs = zlecs + predisplaylen; 1017 tmpll = predisplaylen + zlell + postdisplaylen; 1018 tmpalloced = 1; 1019 } else { 1020 tmpline = zleline; 1021 tmpcs = zlecs; 1022 tmpll = zlell; 1023 tmpalloced = 0; 1024 } 1025 1026 /* this will create region_highlights if it's still NULL */ 1027 zle_set_highlight(); 1028 1029 /* check for region between point ($CURSOR) and mark ($MARK) */ 1030 if (region_active) { 1031 if (zlecs <= mark) { 1032 region_highlights[0].start = zlecs; 1033 region_highlights[0].end = mark; 1034 } else { 1035 region_highlights[0].start = mark; 1036 region_highlights[0].end = zlecs; 1037 } 1038 } else { 1039 region_highlights[0].start = region_highlights[0].end = -1; 1040 } 1041 /* check for isearch string to highlight */ 1042 if (isearch_active) { 1043 region_highlights[1].start = isearch_startpos; 1044 region_highlights[1].end = isearch_endpos; 1045 } else { 1046 region_highlights[1].start = region_highlights[1].end = -1; 1047 } 1048 /* check for an active completion suffix */ 1049 if (suffixnoinslen) { 1050 region_highlights[2].start = zlecs - suffixnoinslen; 1051 region_highlights[2].end = zlecs; 1052 } else { 1053 region_highlights[2].start = region_highlights[2].end = -1; 1054 } 1055 1056 if (clearlist && listshown > 0) { 1057 if (tccan(TCCLEAREOD)) { 1058 int ovln = vln, ovcs = vcs; 1059 REFRESH_STRING nb = nbuf[vln]; 1060 1061 nbuf[vln] = obuf[vln]; 1062 moveto(nlnct, 0); 1063 tcoutclear(TCCLEAREOD); 1064 moveto(ovln, ovcs); 1065 nbuf[vln] = nb; 1066 } else { 1067 invalidatelist(); 1068 moveto(0, 0); 1069 clearflag = 0; 1070 resetneeded = 1; 1071 } 1072 listshown = lastlistlen = 0; 1073 if (showinglist != -2) 1074 showinglist = 0; 1075 } 1076 clearlist = 0; 1077 1078#ifdef HAVE_SELECT 1079 cost = 0; /* reset */ 1080#endif 1081 1082/* Nov 96: <mason> I haven't checked how complete this is. sgtty stuff may 1083 or may not work */ 1084#if defined(SGTABTYPE) 1085 oxtabs = ((SGTTYFLAG & SGTABTYPE) == SGTABTYPE); 1086#else 1087 oxtabs = 0; 1088#endif 1089 1090 cleareol = 0; /* unset */ 1091 more_start = more_end = 0; /* unset */ 1092 if (isset(SINGLELINEZLE) || zterm_lines < 3 1093 || (termflags & (TERM_NOUP | TERM_BAD | TERM_UNKNOWN))) 1094 termflags |= TERM_SHORT; 1095 else 1096 termflags &= ~TERM_SHORT; 1097 if (resetneeded) { 1098 onumscrolls = 0; 1099 zsetterm(); 1100#ifdef TIOCGWINSZ 1101 if (winchanged) { 1102 moveto(0, 0); 1103 t0 = olnct; /* this is to clear extra lines even when */ 1104 winchanged = 0; /* the terminal cannot TCCLEAREOD */ 1105 listshown = 0; 1106 } 1107#endif 1108 /* we probably should only have explicitly set attributes */ 1109 tsetcap(TCALLATTRSOFF, 0); 1110 tsetcap(TCSTANDOUTEND, 0); 1111 tsetcap(TCUNDERLINEEND, 0); 1112 /* cheat on attribute unset */ 1113 txtunset(TXTBOLDFACE|TXTSTANDOUT|TXTUNDERLINE); 1114 1115 if (trashedzle && !clearflag) 1116 reexpandprompt(); 1117 resetvideo(); 1118 resetneeded = 0; /* unset */ 1119 oput_rpmpt = 0; /* no right-prompt currently on screen */ 1120 1121 if (!clearflag) { 1122 if (tccan(TCCLEAREOD)) 1123 tcoutclear(TCCLEAREOD); 1124 else 1125 cleareol = 1; /* request: clear to end of line */ 1126 if (listshown > 0) 1127 listshown = 0; 1128 } 1129 if (t0 > -1) 1130 olnct = (t0 < winh) ? t0 : winh; 1131 if (termflags & TERM_SHORT) 1132 vcs = 0; 1133 else if (!clearflag && lpromptbuf[0]) { 1134 zputs(lpromptbuf, shout); 1135 if (lpromptwof == winw) 1136 zputs("\n", shout); /* works with both hasam and !hasam */ 1137 } else { 1138 txtchange = pmpt_attr; 1139 settextattributes(txtchange); 1140 } 1141 if (clearflag) { 1142 zputc(&zr_cr); 1143 vcs = 0; 1144 moveto(0, lpromptw); 1145 } 1146 fflush(shout); 1147 clearf = clearflag; 1148 } else if (winw != zterm_columns || rwinh != zterm_lines) 1149 resetvideo(); 1150 1151/* now winw equals columns and winh equals lines 1152 width comparisons can be made with winw, height comparisons with winh */ 1153 1154 if (termflags & TERM_SHORT) { 1155 singlerefresh(tmpline, tmpll, tmpcs); 1156 goto singlelineout; 1157 } 1158 1159 if (tmpcs < 0) { 1160#ifdef DEBUG 1161 fprintf(stderr, "BUG: negative cursor position\n"); 1162 fflush(stderr); 1163#endif 1164 tmpcs = 0; 1165 } 1166 scs = tmpline + tmpcs; 1167 numscrolls = 0; 1168 1169/* first, we generate the video line buffers so we know what to put on 1170 the screen - also determine final cursor position (nvln, nvcs) */ 1171 1172 /* Deemed necessary by PWS 1995/05/15 due to kill-line problems */ 1173 if (!*nbuf) 1174 *nbuf = (REFRESH_STRING)zalloc((winw + 2) * sizeof(**nbuf)); 1175 1176 memset(&rpms, 0, sizeof(rpms)); 1177 rpms.nvln = -1; 1178 1179 rpms.s = nbuf[rpms.ln = 0] + lpromptw; 1180 rpms.sen = *nbuf + winw; 1181 for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) { 1182 int base_atr_on = default_atr_on, base_atr_off = 0, ireg; 1183 int all_atr_on, all_atr_off; 1184 struct region_highlight *rhp; 1185 /* 1186 * Calculate attribute based on region. 1187 */ 1188 for (ireg = 0, rhp = region_highlights; 1189 ireg < n_region_highlights; 1190 ireg++, rhp++) { 1191 int offset; 1192 if (rhp->flags & ZRH_PREDISPLAY) 1193 offset = 0; /* include predisplay in start end */ 1194 else 1195 offset = predisplaylen; /* increment over it */ 1196 if (rhp->start + offset <= tmppos && 1197 tmppos < rhp->end + offset) { 1198 if (rhp->atr & (TXTFGCOLOUR|TXTBGCOLOUR)) { 1199 /* override colour with later entry */ 1200 base_atr_on = (base_atr_on & ~TXT_ATTR_ON_VALUES_MASK) | 1201 rhp->atr; 1202 } else { 1203 /* no colour set yet */ 1204 base_atr_on |= rhp->atr; 1205 } 1206 if (tmppos == rhp->end + offset - 1 || 1207 tmppos == tmpll - 1) 1208 base_atr_off |= TXT_ATTR_OFF_FROM_ON(rhp->atr); 1209 } 1210 } 1211 if (special_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) { 1212 /* keep colours from special attributes */ 1213 all_atr_on = special_atr_on | 1214 (base_atr_on & ~TXT_ATTR_COLOUR_ON_MASK); 1215 } else { 1216 /* keep colours from standard attributes */ 1217 all_atr_on = special_atr_on | base_atr_on; 1218 } 1219 all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on); 1220 1221 if (t == scs) /* if cursor is here, remember it */ 1222 rpms.nvcs = rpms.s - nbuf[rpms.nvln = rpms.ln]; 1223 1224 if (*t == ZWC('\n')){ /* newline */ 1225 /* text not wrapped */ 1226 if (nextline(&rpms, 0)) 1227 break; 1228 } else if (*t == ZWC('\t')) { /* tab */ 1229 t0 = rpms.s - nbuf[rpms.ln]; 1230 if ((t0 | 7) + 1 >= winw) { 1231 /* text wrapped */ 1232 if (nextline(&rpms, 1)) 1233 break; 1234 } else { 1235 do { 1236 rpms.s->chr = ZWC(' '); 1237 rpms.s->atr = base_atr_on; 1238 rpms.s++; 1239 } while ((++t0) & 7); 1240 rpms.s[-1].atr |= base_atr_off; 1241 } 1242 } 1243#ifdef MULTIBYTE_SUPPORT 1244 else if ( 1245#ifdef __STDC_ISO_10646__ 1246 !ZSH_INVALID_WCHAR_TEST(*t) && 1247#endif 1248 iswprint(*t) && (width = WCWIDTH(*t)) > 0) { 1249 int ichars; 1250 if (width > rpms.sen - rpms.s) { 1251 int started = 0; 1252 /* 1253 * Too wide to fit. Insert spaces to end of current line. 1254 */ 1255 do { 1256 rpms.s->chr = ZWC(' '); 1257 if (!started) 1258 started = 1; 1259 rpms.s->atr = all_atr_on; 1260 rpms.s++; 1261 } while (rpms.s < rpms.sen); 1262 if (started) 1263 rpms.s[-1].atr |= all_atr_off; 1264 if (nextline(&rpms, 1)) 1265 break; 1266 if (t == scs) { 1267 /* Update cursor to this point */ 1268 rpms.nvcs = rpms.s - nbuf[rpms.nvln = rpms.ln]; 1269 } 1270 } 1271 if (isset(COMBININGCHARS) && IS_BASECHAR(*t)) { 1272 /* 1273 * Look for combining characters. 1274 */ 1275 for (ichars = 1; tmppos + ichars < tmpll; ichars++) { 1276 if (!IS_COMBINING(t[ichars])) 1277 break; 1278 } 1279 } else 1280 ichars = 1; 1281 if (width > rpms.sen - rpms.s || width == 0) { 1282 /* 1283 * The screen width is too small to fit even one 1284 * occurrence. 1285 */ 1286 rpms.s->chr = ZWC('?'); 1287 rpms.s->atr = all_atr_on | all_atr_off; 1288 rpms.s++; 1289 } else { 1290 /* We can fit it without reaching the end of the line. */ 1291 /* 1292 * As we don't actually output the WEOF, we attach 1293 * any off attributes to the character itself. 1294 */ 1295 rpms.s->atr = base_atr_on | base_atr_off; 1296 if (ichars > 1) { 1297 /* 1298 * Glyph includes combining characters. 1299 * Write these into the multiword buffer and put 1300 * the index into the value at the screen location. 1301 */ 1302 addmultiword(rpms.s, t, ichars); 1303 } else { 1304 /* Single wide character */ 1305 rpms.s->chr = *t; 1306 } 1307 rpms.s++; 1308 while (--width > 0) { 1309 rpms.s->chr = WEOF; 1310 /* Not used, but be consistent... */ 1311 rpms.s->atr = base_atr_on | base_atr_off; 1312 rpms.s++; 1313 } 1314 } 1315 if (ichars > 1) { 1316 /* allow for normal increment */ 1317 tmppos += ichars - 1; 1318 t += ichars - 1; 1319 } 1320 } 1321#endif 1322 else if (ZC_icntrl(*t) 1323#ifdef MULTIBYTE_SUPPORT 1324 && (unsigned)*t <= 0xffU 1325#endif 1326 ) { /* other control character */ 1327 rpms.s->chr = ZWC('^'); 1328 rpms.s->atr = all_atr_on; 1329 rpms.s++; 1330 if (rpms.s == rpms.sen) { 1331 /* text wrapped */ 1332 rpms.s[-1].atr |= all_atr_off; 1333 if (nextline(&rpms, 1)) 1334 break; 1335 } 1336 rpms.s->chr = (((unsigned int)*t & ~0x80u) > 31) ? 1337 ZWC('?') : (*t | ZWC('@')); 1338 rpms.s->atr = all_atr_on | all_atr_off; 1339 rpms.s++; 1340 } 1341#ifdef MULTIBYTE_SUPPORT 1342 else { 1343 /* 1344 * Not printable or zero width. 1345 * Resort to hackery. 1346 */ 1347 char dispchars[11]; 1348 char *dispptr = dispchars; 1349 wchar_t wc; 1350 int started = 0; 1351 1352#ifdef __STDC_ISO_10646__ 1353 if (ZSH_INVALID_WCHAR_TEST(*t)) { 1354 int c = ZSH_INVALID_WCHAR_TO_INT(*t); 1355 sprintf(dispchars, "<%.02x>", c); 1356 } else 1357#endif 1358 if ((unsigned)*t > 0xffffU) { 1359 sprintf(dispchars, "<%.08x>", (unsigned)*t); 1360 } else { 1361 sprintf(dispchars, "<%.04x>", (unsigned)*t); 1362 } 1363 while (*dispptr) { 1364 if (mbtowc(&wc, dispptr, 1) == 1 /* paranoia */) 1365 { 1366 rpms.s->chr = wc; 1367 if (!started) 1368 started = 1; 1369 rpms.s->atr = all_atr_on; 1370 rpms.s++; 1371 if (rpms.s == rpms.sen) { 1372 /* text wrapped */ 1373 if (started) { 1374 rpms.s[-1].atr |= all_atr_off; 1375 started = 0; 1376 } 1377 if (nextline(&rpms, 1)) 1378 break; 1379 } 1380 } 1381 dispptr++; 1382 } 1383 if (started) 1384 rpms.s[-1].atr |= all_atr_off; 1385 if (*dispptr) /* nextline said stop processing */ 1386 break; 1387 } 1388#else 1389 else { /* normal character */ 1390 rpms.s->chr = *t; 1391 rpms.s->atr = base_atr_on | base_atr_off; 1392 rpms.s++; 1393 } 1394#endif 1395 if (rpms.s == rpms.sen) { 1396 /* text wrapped */ 1397 if (nextline(&rpms, 1)) 1398 break; 1399 } 1400 } 1401 1402/* if we're really on the next line, don't fake it; do everything properly */ 1403 if (t == scs && 1404 (rpms.nvcs = rpms.s - (nbuf[rpms.nvln = rpms.ln])) == winw) { 1405 /* text wrapped */ 1406 (void)nextline(&rpms, 1); 1407 *rpms.s = zr_zr; 1408 rpms.nvcs = 0; 1409 rpms.nvln++; 1410 } 1411 1412 if (t != tmpline + tmpll) 1413 more_end = 1; 1414 1415 if (statusline) { 1416 int outll, outsz, all_atr_on, all_atr_off; 1417 char *statusdup = ztrdup(statusline); 1418 ZLE_STRING_T outputline = 1419 stringaszleline(statusdup, 0, &outll, &outsz, NULL); 1420 1421 all_atr_on = special_atr_on; 1422 all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on); 1423 1424 rpms.tosln = rpms.ln + 1; 1425 nbuf[rpms.ln][winw + 1] = zr_zr; /* text not wrapped */ 1426 snextline(&rpms); 1427 u = outputline; 1428 for (; u < outputline + outll; u++) { 1429#ifdef MULTIBYTE_SUPPORT 1430 if (iswprint(*u)) { 1431 int width = WCWIDTH(*u); 1432 /* Handle wide characters as above */ 1433 if (width > rpms.sen - rpms.s) { 1434 do { 1435 *rpms.s++ = zr_sp; 1436 } while (rpms.s < rpms.sen); 1437 nbuf[rpms.ln][winw + 1] = zr_nl; 1438 snextline(&rpms); 1439 } 1440 if (width > rpms.sen - rpms.s) { 1441 rpms.s->chr = ZWC('?'); 1442 rpms.s->atr = all_atr_on | all_atr_off; 1443 rpms.s++; 1444 } else { 1445 rpms.s->chr = *u; 1446 rpms.s->atr = 0; 1447 rpms.s++; 1448 while (--width > 0) { 1449 rpms.s->chr = WEOF; 1450 rpms.s->atr = 0; 1451 rpms.s++; 1452 } 1453 } 1454 } 1455 else 1456#endif 1457 if (ZC_icntrl(*u)) { /* simplified processing in the status line */ 1458 rpms.s->chr = ZWC('^'); 1459 rpms.s->atr = all_atr_on; 1460 rpms.s++; 1461 if (rpms.s == rpms.sen) { 1462 nbuf[rpms.ln][winw + 1] = zr_nl;/* text wrapped */ 1463 snextline(&rpms); 1464 } 1465 rpms.s->chr = (((unsigned int)*u & ~0x80u) > 31) 1466 ? ZWC('?') : (*u | ZWC('@')); 1467 rpms.s->atr = all_atr_on | all_atr_off; 1468 rpms.s++; 1469 } else { 1470 rpms.s->chr = *u; 1471 rpms.s->atr = 0; 1472 rpms.s++; 1473 } 1474 if (rpms.s == rpms.sen) { 1475 nbuf[rpms.ln][winw + 1] = zr_nl; /* text wrapped */ 1476 snextline(&rpms); 1477 } 1478 } 1479 if (rpms.s == rpms.sen) { 1480 /* 1481 * I suppose we don't modify nbuf[rpms.ln][winw+1] here 1482 * since we're right at the end? 1483 */ 1484 snextline(&rpms); 1485 } 1486 zfree(outputline, outsz); 1487 free(statusdup); 1488 } 1489 *rpms.s = zr_zr; 1490 1491/* insert <.... at end of last line if there is more text past end of screen */ 1492 if (more_end) { 1493#ifdef MULTIBYTE_SUPPORT 1494 int extra_ellipsis = 0; 1495#endif 1496 if (!statusline) 1497 rpms.tosln = winh; 1498 rpms.s = nbuf[rpms.tosln - 1]; 1499 rpms.sen = rpms.s + winw - 7; 1500 for (; rpms.s < rpms.sen; rpms.s++) { 1501 if (rpms.s->chr == ZWC('\0')) { 1502 ZR_memset(rpms.s, zr_sp, rpms.sen - rpms.s); 1503 /* make sure we don't trigger the WEOF test */ 1504 rpms.sen->chr = ZWC('\0'); 1505 break; 1506 } 1507 } 1508 /* rpms.s is no longer needed */ 1509#ifdef MULTIBYTE_SUPPORT 1510 /* 1511 * Ensure we don't start overwriting in the middle of a wide 1512 * character. 1513 */ 1514 while(rpms.sen > nbuf[rpms.tosln - 1] && rpms.sen->chr == WEOF) { 1515 extra_ellipsis++; 1516 rpms.sen--; 1517 } 1518#endif 1519 ZR_memcpy(rpms.sen, zr_end_ellipsis, ZR_END_ELLIPSIS_SIZE); 1520#ifdef MULTIBYTE_SUPPORT 1521 /* Extend to the end if we backed off for a wide character */ 1522 if (extra_ellipsis) { 1523 rpms.sen += ZR_END_ELLIPSIS_SIZE; 1524 ZR_memset(rpms.sen, zr_dt, extra_ellipsis); 1525 } 1526#endif 1527 nbuf[rpms.tosln - 1][winw] = nbuf[rpms.tosln - 1][winw + 1] = zr_zr; 1528 } 1529 1530/* insert <....> at end of first status line if status is too big */ 1531 if (rpms.more_status) { 1532#ifdef MULTIBYTE_SUPPORT 1533 int extra_ellipsis = 0; 1534#endif 1535 rpms.s = nbuf[rpms.tosln]; 1536 rpms.sen = rpms.s + winw - 8; 1537 for (; rpms.s < rpms.sen; rpms.s++) { 1538 if (rpms.s->chr == ZWC('\0')) { 1539 ZR_memset(rpms.s, zr_sp, rpms.sen - rpms.s); 1540 break; 1541 } 1542 } 1543 /* rpms.s is no longer needed */ 1544#ifdef MULTIBYTE_SUPPORT 1545 /* 1546 * Ensure we don't start overwriting in the middle of a wide 1547 * character. 1548 */ 1549 while(rpms.sen > nbuf[rpms.tosln - 1] && rpms.sen->chr == WEOF) { 1550 extra_ellipsis++; 1551 rpms.sen--; 1552 } 1553#endif 1554 ZR_memcpy(rpms.sen, zr_mid_ellipsis1, ZR_MID_ELLIPSIS1_SIZE); 1555 rpms.sen += ZR_MID_ELLIPSIS1_SIZE; 1556#ifdef MULTIBYTE_SUPPORT 1557 /* Extend if we backed off for a wide character */ 1558 if (extra_ellipsis) { 1559 ZR_memset(rpms.sen, zr_dt, extra_ellipsis); 1560 rpms.sen += extra_ellipsis; 1561 } 1562#endif 1563 ZR_memcpy(rpms.sen, zr_mid_ellipsis2, ZR_MID_ELLIPSIS2_SIZE); 1564 nbuf[rpms.tosln][winw] = nbuf[rpms.tosln][winw + 1] = zr_zr; 1565 } 1566 1567 nlnct = rpms.ln + 1; 1568 for (iln = nlnct; iln < winh; iln++) { 1569 zfree(nbuf[iln], (winw + 2) * sizeof(**nbuf)); 1570 nbuf[iln] = NULL; 1571 } 1572 1573/* determine whether the right-prompt exists and can fit on the screen */ 1574 if (!more_start) { 1575 if (trashedzle && opts[TRANSIENTRPROMPT]) 1576 put_rpmpt = 0; 1577 else { 1578 put_rpmpt = rprompth == 1 && rpromptbuf[0] && 1579 !strchr(rpromptbuf, '\t'); 1580 if (put_rpmpt) 1581 { 1582 rprompt_off = rprompt_indent; 1583 /* sanity to avoid horrible things happening */ 1584 if (rprompt_off < 0) 1585 rprompt_off = 0; 1586 put_rpmpt = 1587 (int)ZR_strlen(nbuf[0]) + rpromptw < winw - rprompt_off; 1588 } 1589 } 1590 } else { 1591/* insert >.... on first line if there is more text before start of screen */ 1592 ZR_memset(nbuf[0], zr_sp, lpromptw); 1593 t0 = winw - lpromptw; 1594 t0 = t0 > ZR_START_ELLIPSIS_SIZE ? ZR_START_ELLIPSIS_SIZE : t0; 1595 ZR_memcpy(nbuf[0] + lpromptw, zr_start_ellipsis, t0); 1596 ZR_memset(nbuf[0] + lpromptw + t0, zr_sp, winw - t0 - lpromptw); 1597 nbuf[0][winw] = nbuf[0][winw + 1] = zr_zr; 1598 } 1599 1600 for (iln = 0; iln < nlnct; iln++) { 1601 /* if we have more lines than last time, clear the newly-used lines */ 1602 if (iln >= olnct) 1603 cleareol = 1; 1604 1605 /* if old line and new line are different, 1606 see if we can insert/delete a line to speed up update */ 1607 1608 if (!clearf && iln > 0 && iln < olnct - 1 && 1609 !(hasam && vcs == winw) && 1610 nbuf[iln] && obuf[iln] && 1611 ZR_strncmp(obuf[iln], nbuf[iln], 16)) { 1612 if (tccan(TCDELLINE) && obuf[iln + 1] && 1613 obuf[iln + 1][0].chr && nbuf[iln] && 1614 !ZR_strncmp(obuf[iln + 1], nbuf[iln], 16)) { 1615 moveto(iln, 0); 1616 tcout(TCDELLINE); 1617 zfree(obuf[iln], (winw + 2) * sizeof(**obuf)); 1618 for (t0 = iln; t0 != olnct; t0++) 1619 obuf[t0] = obuf[t0 + 1]; 1620 obuf[--olnct] = NULL; 1621 } 1622 /* don't try to insert a line if olnct = vmaxln (vmaxln is the number 1623 of lines that have been displayed by this routine) so that we don't 1624 go off the end of the screen. */ 1625 1626 else if (tccan(TCINSLINE) && olnct < vmaxln && nbuf[iln + 1] && 1627 obuf[iln] && !ZR_strncmp(obuf[iln], nbuf[iln + 1], 16)) { 1628 moveto(iln, 0); 1629 tcout(TCINSLINE); 1630 for (t0 = olnct; t0 != iln; t0--) 1631 obuf[t0] = obuf[t0 - 1]; 1632 obuf[iln] = NULL; 1633 olnct++; 1634 } 1635 } 1636 1637 /* update the single line */ 1638 refreshline(iln); 1639 1640 /* output the right-prompt if appropriate */ 1641 if (put_rpmpt && !iln && !oput_rpmpt) { 1642 int attrchange; 1643 1644 moveto(0, winw - rprompt_off - rpromptw); 1645 zputs(rpromptbuf, shout); 1646 vcs = winw - rprompt_off; 1647 /* reset character attributes to that set by the main prompt */ 1648 txtchange = pmpt_attr; 1649 /* 1650 * Keep attributes that have actually changed, 1651 * which are ones off in rpmpt_attr and on in 1652 * pmpt_attr, and vice versa. 1653 */ 1654 attrchange = txtchange & 1655 (TXT_ATTR_OFF_FROM_ON(rpmpt_attr) | 1656 TXT_ATTR_ON_FROM_OFF(rpmpt_attr)); 1657 /* 1658 * Careful in case the colour changed. 1659 */ 1660 if (txtchangeisset(txtchange, TXTFGCOLOUR) && 1661 (!txtchangeisset(rpmpt_attr, TXTFGCOLOUR) || 1662 ((txtchange ^ rpmpt_attr) & TXT_ATTR_FG_COL_MASK))) 1663 { 1664 attrchange |= 1665 txtchange & (TXTFGCOLOUR | TXT_ATTR_FG_COL_MASK); 1666 } 1667 if (txtchangeisset(txtchange, TXTBGCOLOUR) && 1668 (!txtchangeisset(rpmpt_attr, TXTBGCOLOUR) || 1669 ((txtchange ^ rpmpt_attr) & TXT_ATTR_BG_COL_MASK))) 1670 { 1671 attrchange |= 1672 txtchange & (TXTBGCOLOUR | TXT_ATTR_BG_COL_MASK); 1673 } 1674 /* 1675 * Now feed these changes into the usual function, 1676 * if necessary. 1677 */ 1678 if (attrchange) 1679 settextattributes(attrchange); 1680 } 1681 } 1682 1683/* if old buffer had extra lines, set them to be cleared and refresh them 1684individually */ 1685 1686 if (olnct > nlnct) { 1687 cleareol = 1; 1688 for (iln = nlnct; iln < olnct; iln++) 1689 refreshline(iln); 1690 } 1691 1692/* reset character attributes */ 1693 if (clearf && postedit) { 1694 if ((txtchange = pmpt_attr ? pmpt_attr : rpmpt_attr)) 1695 settextattributes(txtchange); 1696 } 1697 clearf = 0; 1698 oput_rpmpt = put_rpmpt; 1699 1700/* move to the new cursor position */ 1701 moveto(rpms.nvln, rpms.nvcs); 1702 1703/* swap old and new buffers - better than freeing/allocating every time */ 1704 bufswap(); 1705 1706/* store current values so we can use them next time */ 1707 ovln = rpms.nvln; 1708 olnct = nlnct; 1709 onumscrolls = numscrolls; 1710 if (nlnct > vmaxln) 1711 vmaxln = nlnct; 1712singlelineout: 1713 fflush(shout); /* make sure everything is written out */ 1714 1715 if (tmpalloced) 1716 zfree(tmpline, tmpll * sizeof(*tmpline)); 1717 1718 zle_free_highlight(); 1719 1720 /* if we have a new list showing, note it; if part of the list has been 1721 overwritten, redisplay it. We have to metafy line back before calling 1722 completion code */ 1723 if (showinglist == -2 || (showinglist > 0 && showinglist < nlnct)) { 1724 if (remetafy) { 1725 metafy_line(); 1726 remetafy = 0; 1727 } 1728 inlist = 1; 1729 listmatches(); 1730 inlist = 0; 1731 zrefresh(); 1732 } 1733 if (showinglist == -1) 1734 showinglist = nlnct; 1735 1736 if (remetafy) 1737 metafy_line(); 1738} 1739 1740#define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS]) 1741#define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL]) 1742#define tc_delchars(X) (void) tcmultout(TCDEL, TCMULTDEL, (X)) 1743#define tc_inschars(X) (void) tcmultout(TCINS, TCMULTINS, (X)) 1744#define tc_upcurs(X) (void) tcmultout(TCUP, TCMULTUP, (X)) 1745#define tc_leftcurs(X) (void) tcmultout(TCLEFT, TCMULTLEFT, (X)) 1746 1747/* 1748 * Once again, in the multibyte case the arguments must be in the 1749 * order: element of old video array, element of new video array. 1750 */ 1751static int 1752wpfxlen(const REFRESH_ELEMENT *olds, const REFRESH_ELEMENT *news) 1753{ 1754 int i = 0; 1755 1756 while (olds->chr && ZR_equal(*olds, *news)) 1757 olds++, news++, i++; 1758 return i; 1759} 1760 1761/* refresh one line, using whatever speed-up tricks are provided by the tty */ 1762 1763/**/ 1764static void 1765refreshline(int ln) 1766{ 1767 REFRESH_STRING nl, ol, p1; /* line buffer pointers */ 1768 int ccs = 0, /* temporary count for cursor position */ 1769 char_ins = 0, /* number of characters inserted/deleted */ 1770 col_cleareol, /* clear to end-of-line from this column */ 1771 i, j, /* tmp */ 1772 ins_last, /* insert pushed last character off line */ 1773 nllen, ollen, /* new and old line buffer lengths */ 1774 rnllen; /* real new line buffer length */ 1775 1776/* 0: setup */ 1777 nl = nbuf[ln]; 1778 rnllen = nllen = nl ? ZR_strlen(nl) : 0; 1779 if (ln < olnct && obuf[ln]) { 1780 ol = obuf[ln]; 1781 ollen = ZR_strlen(ol); 1782 } 1783 else { 1784 static REFRESH_ELEMENT nullchr = { ZWC('\0'), 0 }; 1785 ol = &nullchr; 1786 ollen = 0; 1787 } 1788 1789/* optimisation: can easily happen for clearing old lines. If the terminal has 1790 the capability, then this is the easiest way to skip unnecessary stuff */ 1791 if (cleareol && !nllen && !(hasam && ln < nlnct - 1) 1792 && tccan(TCCLEAREOL)) { 1793 moveto(ln, 0); 1794 tcoutclear(TCCLEAREOL); 1795 return; 1796 } 1797 1798/* 1: pad out the new buffer with spaces to contain _all_ of the characters 1799 which need to be written. do this now to allow some pre-processing */ 1800 1801 if (cleareol /* request to clear to end of line */ 1802 || (!nllen && (ln != 0 || !put_rpmpt)) /* no line buffer given */ 1803 || (ln == 0 && (put_rpmpt != oput_rpmpt))) { /* prompt changed */ 1804 p1 = zhalloc((winw + 2) * sizeof(*p1)); 1805 if (nllen) 1806 ZR_memcpy(p1, nl, nllen); 1807 ZR_memset(p1 + nllen, zr_sp, winw - nllen); 1808 p1[winw] = zr_zr; 1809 if (nllen < winw) 1810 p1[winw + 1] = zr_zr; 1811 else 1812 p1[winw + 1] = nl[winw + 1]; 1813 if (ln && nbuf[ln]) 1814 ZR_memcpy(nl, p1, winw + 2); /* next time obuf will be up-to-date */ 1815 else 1816 nl = p1; /* don't keep the padding for prompt line */ 1817 nllen = winw; 1818 } else if (ollen > nllen) { /* make new line at least as long as old */ 1819 p1 = zhalloc((ollen + 1) * sizeof(*p1)); 1820 ZR_memcpy(p1, nl, nllen); 1821 ZR_memset(p1 + nllen, zr_sp, ollen - nllen); 1822 p1[ollen] = zr_zr; 1823 nl = p1; 1824 nllen = ollen; 1825 } 1826 1827/* 2: see if we can clear to end-of-line, and if it's faster, work out where 1828 to do it from - we can normally only do so if there's no right-prompt. 1829 With automatic margins, we shouldn't do it if there is another line, in 1830 case it messes up cut and paste. */ 1831 1832 if (hasam && ln < nlnct - 1 && rnllen == winw) 1833 col_cleareol = -2; /* clearing eol would be evil so don't */ 1834 else { 1835 col_cleareol = -1; 1836 if (tccan(TCCLEAREOL) && (nllen == winw || put_rpmpt != oput_rpmpt)) { 1837 for (i = nllen; i && ZR_equal(zr_sp, nl[i - 1]); i--) 1838 ; 1839 for (j = ollen; j && ZR_equal(ol[j - 1], zr_sp); j--) 1840 ; 1841 if ((j > i + tclen[TCCLEAREOL]) /* new buf has enough spaces */ 1842 || (nllen == winw && ZR_equal(zr_sp, nl[winw - 1]))) 1843 col_cleareol = i; 1844 } 1845 } 1846 1847/* 2b: first a new trick for automargin niceness - good for cut and paste */ 1848 1849 if (hasam && vcs == winw) { 1850 if (nbuf[vln] && nbuf[vln][vcs + 1].chr == ZWC('\n')) { 1851 vln++, vcs = 1; 1852 if (nbuf[vln] && nbuf[vln]->chr) { 1853 zputc(nbuf[vln]); 1854 } else 1855 zputc(&zr_sp); /* I don't think this should happen */ 1856 if (ln == vln) { /* better safe than sorry */ 1857 nl++; 1858 if (ol->chr) 1859 ol++; 1860 ccs = 1; 1861 } /* else hmmm... I wonder what happened */ 1862 } else { 1863 vln++, vcs = 0; 1864 zputc(&zr_nl); 1865 } 1866 } 1867 ins_last = 0; 1868 1869/* 2c: if we're on the first line, start checking at the end of the prompt; 1870 we shouldn't be doing anything within the prompt */ 1871 1872 if (ln == 0 && lpromptw) { 1873 i = lpromptw - ccs; 1874 j = ZR_strlen(ol); 1875 nl += i; 1876 ol += (i > j ? j : i); /* if ol is too short, point it to '\0' */ 1877 ccs = lpromptw; 1878 } 1879 1880#ifdef MULTIBYTE_SUPPORT 1881 /* 1882 * Realign to a real character after any jiggery pokery at 1883 * the start of the line. 1884 */ 1885 while (nl->chr == WEOF) { 1886 nl++, ccs++, vcs++; 1887 if (ol->chr) 1888 ol++; 1889 } 1890#endif 1891 1892/* 3: main display loop - write out the buffer using whatever tricks we can */ 1893 1894 for (;;) { 1895 int now_off; 1896 1897#ifdef MULTIBYTE_SUPPORT 1898 if ((!nl->chr || nl->chr != WEOF) && (!ol->chr || ol->chr != WEOF)) { 1899#endif 1900 if (nl->chr && ol->chr && ZR_equal(ol[1], nl[1])) { 1901 /* skip only if second chars match */ 1902#ifdef MULTIBYTE_SUPPORT 1903 int ccs_was = ccs; 1904#endif 1905 /* skip past all matching characters */ 1906 for (; nl->chr && ZR_equal(*ol, *nl); nl++, ol++, ccs++) 1907 ; 1908#ifdef MULTIBYTE_SUPPORT 1909 /* Make sure ol and nl are pointing to real characters */ 1910 while ((nl->chr == WEOF || ol->chr == WEOF) && ccs > ccs_was) { 1911 nl--; 1912 ol--; 1913 ccs--; 1914 } 1915#endif 1916 } 1917 1918 if (!nl->chr) { 1919 if (ccs == winw && hasam && char_ins > 0 && ins_last 1920 && vcs != winw) { 1921 nl--; /* we can assume we can go back here */ 1922 moveto(ln, winw - 1); 1923 zputc(nl); 1924 vcs++; 1925 return; /* write last character in line */ 1926 } 1927 if ((char_ins <= 0) || (ccs >= winw)) /* written everything */ 1928 return; 1929 if (tccan(TCCLEAREOL) && (char_ins >= tclen[TCCLEAREOL]) 1930 && col_cleareol != -2) 1931 /* we've got junk on the right yet to clear */ 1932 col_cleareol = 0; /* force a clear to end of line */ 1933 } 1934 1935 moveto(ln, ccs); /* move to where we do all output from */ 1936 1937 /* if we can finish quickly, do so */ 1938 if ((col_cleareol >= 0) && (ccs >= col_cleareol)) { 1939 tcoutclear(TCCLEAREOL); 1940 return; 1941 } 1942 1943 /* we've written out the new but yet to clear rubbish due to inserts */ 1944 if (!nl->chr) { 1945 i = (winw - ccs < char_ins) ? (winw - ccs) : char_ins; 1946 if (tccan(TCDEL) && (tcdelcost(i) <= i + 1)) 1947 tc_delchars(i); 1948 else { 1949 vcs += i; 1950 while (i-- > 0) 1951 zputc(&zr_sp); 1952 } 1953 return; 1954 } 1955 1956 /* if we've reached the end of the old buffer, then there are few tricks 1957 we can do, so we just dump out what we must and clear if we can */ 1958 if (!ol->chr) { 1959 i = (col_cleareol >= 0) ? col_cleareol : nllen; 1960 i -= vcs; 1961 if (i < 0) { 1962 /* 1963 * This shouldn't be necessary, but it's better 1964 * than a crash if there's a bug somewhere else, 1965 * so report in debug mode. 1966 */ 1967 DPUTS(1, "BUG: badly calculated old line width in refresh"); 1968 i = 0; 1969 } 1970 zwrite(nl, i); 1971 vcs += i; 1972 if (col_cleareol >= 0) 1973 tcoutclear(TCCLEAREOL); 1974 return; 1975 } 1976 1977 /* inserting & deleting chars: we can if there's no right-prompt */ 1978 if ((ln || !put_rpmpt || !oput_rpmpt) 1979#ifdef MULTIBYTE_SUPPORT 1980 && ol->chr != WEOF && nl->chr != WEOF 1981#endif 1982 && nl[1].chr && ol[1].chr && !ZR_equal(ol[1], nl[1])) { 1983 1984 /* deleting characters - see if we can find a match series that 1985 makes it cheaper to delete intermediate characters 1986 eg. oldline: hifoobar \ hopefully cheaper here to delete two 1987 newline: foobar / characters, then we have six matches */ 1988 if (tccan(TCDEL)) { 1989 int first = 1; 1990 for (i = 1; ol[i].chr; i++) { 1991 if (tcdelcost(i) < wpfxlen(ol + i, nl)) { 1992 /* 1993 * Some terminals will output the current 1994 * attributes into cells added at the end by 1995 * deletions, so turn off text attributes. 1996 */ 1997 if (first) { 1998 clearattributes(); 1999 first = 0; 2000 } 2001 tc_delchars(i); 2002 ol += i; 2003 char_ins -= i; 2004#ifdef MULTIBYTE_SUPPORT 2005 while (ol->chr == WEOF) { 2006 ol++; 2007 char_ins--; 2008 } 2009#endif 2010 i = 0; 2011 break; 2012 } 2013 } 2014 if (!i) 2015 continue; 2016 } 2017 /* 2018 * inserting characters - characters pushed off the right 2019 * should be annihilated, but we don't do this if we're on the 2020 * last line lest undesired scrolling occurs due to `illegal' 2021 * characters on screen 2022 */ 2023 if (tccan(TCINS) && (vln != zterm_lines - 1)) { 2024 /* not on last line */ 2025 for (i = 1; nl[i].chr; i++) { 2026 if (tcinscost(i) < wpfxlen(ol, nl + i)) { 2027 tc_inschars(i); 2028 zwrite(nl, i); 2029 nl += i; 2030#ifdef MULTIBYTE_SUPPORT 2031 while (nl->chr == WEOF) { 2032 nl++; 2033 i++; 2034 } 2035#endif 2036 char_ins += i; 2037 ccs = (vcs += i); 2038 /* 2039 * if we've pushed off the right, truncate 2040 * oldline 2041 */ 2042 for (i = 0; ol[i].chr && i < winw - ccs; i++) 2043 ; 2044#ifdef MULTIBYTE_SUPPORT 2045 while (ol[i].chr == WEOF) 2046 i++; 2047 if (i >= winw - ccs) { 2048 /* 2049 * Yes, we're over the right. 2050 * Make sure we truncate at the real 2051 * character, not a WEOF added to 2052 * make up the width. 2053 */ 2054 while (ol[i-1].chr == WEOF) 2055 i--; 2056 ol[i] = zr_zr; 2057 ins_last = 1; 2058 } 2059#else 2060 if (i >= winw - ccs) { 2061 ol[i] = zr_zr; 2062 ins_last = 1; 2063 } 2064#endif 2065 i = 0; 2066 break; 2067 } 2068 } 2069 if (!i) 2070 continue; 2071 } 2072 } 2073#ifdef MULTIBYTE_SUPPORT 2074 } 2075#endif 2076 /* we can't do any fancy tricks, so just dump the single character 2077 and keep on trying */ 2078#ifdef MULTIBYTE_SUPPORT 2079 /* 2080 * in case we were tidying up a funny-width character when we 2081 * reached the end of the new line... 2082 */ 2083 if (!nl->chr) 2084 break; 2085 do { 2086#endif 2087 /* 2088 * If an attribute was on here but isn't any more, 2089 * output the sequence to turn it off. 2090 */ 2091 now_off = ol->atr & ~nl->atr & TXT_ATTR_ON_MASK; 2092 if (now_off) 2093 settextattributes(TXT_ATTR_OFF_FROM_ON(now_off)); 2094 2095 /* 2096 * This is deliberately called if nl->chr is WEOF 2097 * in order to keep text attributes consistent. 2098 * We check for WEOF inside. 2099 */ 2100 zputc(nl); 2101 nl++; 2102 if (ol->chr) 2103 ol++; 2104 ccs++, vcs++; 2105#ifdef MULTIBYTE_SUPPORT 2106 /* 2107 * Make sure we always overwrite the complete width of 2108 * a character that was there before. 2109 */ 2110 } while ((ol->chr == WEOF && nl->chr) || 2111 (nl->chr == WEOF && ol->chr)); 2112#endif 2113 } 2114} 2115 2116/* move the cursor to line ln (relative to the prompt line), 2117 absolute column cl; update vln, vcs - video line and column */ 2118 2119/**/ 2120void 2121moveto(int ln, int cl) 2122{ 2123 const REFRESH_ELEMENT *rep; 2124 2125 if (vcs == winw) { 2126 if (rprompt_indent == 0 && tccan(TCLEFT)) { 2127 tc_leftcurs(1); 2128 vcs--; 2129 } else { 2130 vln++, vcs = 0; 2131 if (!hasam) { 2132 zputc(&zr_cr); 2133 zputc(&zr_nl); 2134 } else { 2135 if ((vln < nlnct) && nbuf[vln] && nbuf[vln]->chr) 2136 rep = nbuf[vln]; 2137 else 2138 rep = &zr_sp; 2139 zputc(rep); 2140 zputc(&zr_cr); 2141 if ((vln < olnct) && obuf[vln] && obuf[vln]->chr) 2142 *obuf[vln] = *rep; 2143 } 2144 } 2145 } 2146 2147 if (ln == vln && cl == vcs) 2148 return; 2149 2150/* move up */ 2151 if (ln < vln) { 2152 tc_upcurs(vln - ln); 2153 vln = ln; 2154 } 2155/* move down; if we might go off the end of the screen, use newlines 2156 instead of TCDOWN */ 2157 2158 while (ln > vln) { 2159 if (vln < vmaxln - 1) { 2160 if (ln > vmaxln - 1) { 2161 if (tc_downcurs(vmaxln - 1 - vln)) 2162 vcs = 0; 2163 vln = vmaxln - 1; 2164 } else { 2165 if (tc_downcurs(ln - vln)) 2166 vcs = 0; 2167 vln = ln; 2168 continue; 2169 } 2170 } 2171 zputc(&zr_cr), vcs = 0; /* safety precaution */ 2172 while (ln > vln) { 2173 zputc(&zr_nl); 2174 vln++; 2175 } 2176 } 2177 2178 if (cl != vcs) 2179 singmoveto(cl); 2180} 2181 2182/**/ 2183mod_export int 2184tcmultout(int cap, int multcap, int ct) 2185{ 2186 if (tccan(multcap) && (!tccan(cap) || tclen[multcap] <= tclen[cap] * ct)) { 2187 tcoutarg(multcap, ct); 2188 return 1; 2189 } else if (tccan(cap)) { 2190 while (ct--) 2191 tcout(cap); 2192 return 1; 2193 } 2194 return 0; 2195} 2196 2197/* ct: number of characters to move across */ 2198/**/ 2199static void 2200tc_rightcurs(int ct) 2201{ 2202 int cl, /* ``desired'' absolute horizontal position */ 2203 i = vcs, /* cursor position after initial movements */ 2204 j; 2205 REFRESH_STRING t; 2206 2207 cl = ct + vcs; 2208 2209/* do a multright if we can - it's the most reliable */ 2210 if (tccan(TCMULTRIGHT)) { 2211 tcoutarg(TCMULTRIGHT, ct); 2212 return; 2213 } 2214 2215/* do an absolute horizontal position if we can */ 2216 if (tccan(TCHORIZPOS)) { 2217 tcoutarg(TCHORIZPOS, cl); 2218 return; 2219 } 2220 2221/* XXX: should really check "it" in termcap and use / and % */ 2222/* try tabs if tabs are non destructive and multright is not possible */ 2223 if (!oxtabs && tccan(TCNEXTTAB) && ((vcs | 7) < cl)) { 2224 i = (vcs | 7) + 1; 2225 tcout(TCNEXTTAB); 2226 for ( ; i + 8 <= cl; i += 8) 2227 tcout(TCNEXTTAB); 2228 if ((ct = cl - i) == 0) /* number of chars still to move across */ 2229 return; 2230 } 2231 2232/* otherwise _carefully_ write the contents of the video buffer. 2233 if we're anywhere in the prompt, goto the left column and write the whole 2234 prompt out. 2235 2236 If strlen(lpromptbuf) == lpromptw, we can cheat and output 2237 the appropriate chunk of the string. This test relies on the 2238 fact that any funny business will always make the length of 2239 the string larger than the printing width, so if they're the same 2240 we have only ASCII characters or a single-byte extension of ASCII. 2241 Unfortunately this trick won't work if there are potentially 2242 characters occupying more than one column. We could flag that 2243 this has happened (since it's not that common to have characters 2244 wider than one column), but for now it's easier not to use the 2245 trick if we are using WCWIDTH() on the prompt. It's not that 2246 common to be editing in the middle of the prompt anyway, I would 2247 think. 2248 */ 2249 if (vln == 0 && i < lpromptw && !(termflags & TERM_SHORT)) { 2250#ifndef MULTIBYTE_SUPPORT 2251 if ((int)strlen(lpromptbuf) == lpromptw) 2252 fputs(lpromptbuf + i, shout); 2253 else 2254#endif 2255 if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpromptbuf))) 2256 /* it is cheaper to send TCRIGHT than reprint the whole prompt */ 2257 for (ct = lpromptw - i; ct--; ) 2258 tcout(TCRIGHT); 2259 else { 2260 if (i != 0) 2261 zputc(&zr_cr); 2262 tc_upcurs(lprompth - 1); 2263 zputs(lpromptbuf, shout); 2264 if (lpromptwof == winw) 2265 zputs("\n", shout); /* works with both hasam and !hasam */ 2266 } 2267 i = lpromptw; 2268 ct = cl - i; 2269 } 2270 2271 if (nbuf[vln]) { 2272 for (j = 0, t = nbuf[vln]; t->chr && (j < i); j++, t++); 2273 if (j == i) 2274 for ( ; t->chr && ct; ct--, t++) 2275 zputc(t); 2276 } 2277 while (ct--) 2278 zputc(&zr_sp); /* not my fault your terminal can't go right */ 2279} 2280 2281/**/ 2282mod_export int 2283tc_downcurs(int ct) 2284{ 2285 int ret = 0; 2286 2287 if (ct && !tcmultout(TCDOWN, TCMULTDOWN, ct)) { 2288 while (ct--) 2289 zputc(&zr_nl); 2290 zputc(&zr_cr), ret = -1; 2291 } 2292 return ret; 2293} 2294 2295/* 2296 * Output a termcap value using a function defined by "zle -T tc". 2297 * Loosely inspired by subst_string_by_func(). 2298 * 2299 * cap is the internal index for the capability; it will be looked up 2300 * in the table and the string passed to the function. 2301 * 2302 * arg is eithr an argument to the capability or -1 if there is none; 2303 * if it is not -1 it will be passed as an additional argument to the 2304 * function. 2305 * 2306 * outc is the output function; currently this is always putshout 2307 * but in principle it may be used to output to a string. 2308 */ 2309 2310/**/ 2311static void 2312tcout_via_func(int cap, int arg, int (*outc)(int)) 2313{ 2314 Shfunc tcout_func; 2315 int osc, osm, old_incompfunc; 2316 2317 osc = sfcontext; 2318 osm = stopmsg; 2319 old_incompfunc = incompfunc; 2320 2321 sfcontext = SFC_SUBST; 2322 incompfunc = 0; 2323 2324 if ((tcout_func = getshfunc(tcout_func_name))) { 2325 LinkList l = newlinklist(); 2326 char buf[DIGBUFSIZE], *str; 2327 2328 addlinknode(l, tcout_func_name); 2329 addlinknode(l, tccap_get_name(cap)); 2330 2331 if (arg != -1) { 2332 sprintf(buf, "%d", arg); 2333 addlinknode(l, buf); 2334 } 2335 2336 (void)doshfunc(tcout_func, l, 1); 2337 2338 str = getsparam("REPLY"); 2339 if (str) { 2340 while (*str) { 2341 int chr; 2342 if (*str == Meta) { 2343 chr = str[1] ^ 32; 2344 str += 2; 2345 } else { 2346 chr = *str++; 2347 } 2348 (void)outc(chr); 2349 } 2350 } 2351 } 2352 2353 sfcontext = osc; 2354 stopmsg = osm; 2355 incompfunc = old_incompfunc; 2356} 2357 2358/**/ 2359mod_export void 2360tcout(int cap) 2361{ 2362 if (tcout_func_name) { 2363 tcout_via_func(cap, -1, putshout); 2364 } else { 2365 tputs(tcstr[cap], 1, putshout); 2366 } 2367 SELECT_ADD_COST(tclen[cap]); 2368} 2369 2370/**/ 2371static void 2372tcoutarg(int cap, int arg) 2373{ 2374 char *result; 2375 2376 result = tgoto(tcstr[cap], arg, arg); 2377 if (tcout_func_name) { 2378 tcout_via_func(cap, arg, putshout); 2379 } else { 2380 tputs(result, 1, putshout); 2381 } 2382 SELECT_ADD_COST(strlen(result)); 2383} 2384 2385/**/ 2386mod_export int 2387clearscreen(UNUSED(char **args)) 2388{ 2389 tcoutclear(TCCLEARSCREEN); 2390 resetneeded = 1; 2391 clearflag = 0; 2392 return 0; 2393} 2394 2395/**/ 2396mod_export int 2397redisplay(UNUSED(char **args)) 2398{ 2399 moveto(0, 0); 2400 zputc(&zr_cr); /* extra care */ 2401 tc_upcurs(lprompth - 1); 2402 resetneeded = 1; 2403 clearflag = 0; 2404 return 0; 2405} 2406 2407/* 2408 * Show as much of the line buffer as we can in single line mode. 2409 * TBD: all termcap effects are turned off in this mode, so 2410 * there's no point in using character attributes. We should 2411 * decide what we're going to do and either remove the handling 2412 * from here or enable it in tsetcap(). 2413 */ 2414 2415/**/ 2416static void 2417singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) 2418{ 2419 REFRESH_STRING vbuf, vp, /* video buffer and pointer */ 2420 refreshop; /* pointer to old video buffer */ 2421 int t0, /* tmp */ 2422 vsiz, /* size of new video buffer */ 2423 nvcs = 0, /* new video cursor column */ 2424 owinpos = winpos, /* previous window position */ 2425 owinprompt = winprompt; /* previous winprompt */ 2426#ifdef MULTIBYTE_SUPPORT 2427 int width; /* width of multibyte character */ 2428#endif 2429 2430 nlnct = 1; 2431/* generate the new line buffer completely */ 2432 for (vsiz = 1 + lpromptw, t0 = 0; t0 != tmpll; t0++) { 2433 if (tmpline[t0] == ZWC('\t')) 2434 vsiz = (vsiz | 7) + 2; 2435#ifdef MULTIBYTE_SUPPORT 2436 else if (iswprint(tmpline[t0]) && ((width = WCWIDTH(tmpline[t0])) > 0)) { 2437 vsiz += width; 2438 if (isset(COMBININGCHARS) && IS_BASECHAR(tmpline[t0])) { 2439 while (t0 < tmpll-1 && IS_COMBINING(tmpline[t0+1])) 2440 t0++; 2441 } 2442 } 2443#endif 2444 else if (ZC_icntrl(tmpline[t0]) 2445#ifdef MULTIBYTE_SUPPORT 2446 && (unsigned)tmpline[t0] <= 0xffU 2447#endif 2448 ) 2449 vsiz += 2; 2450#ifdef MULTIBYTE_SUPPORT 2451 else 2452 vsiz += 10; 2453#else 2454 else 2455 vsiz++; 2456#endif 2457 } 2458 vbuf = (REFRESH_STRING)zalloc(vsiz * sizeof(*vbuf)); 2459 2460 if (tmpcs < 0) { 2461#ifdef DEBUG 2462 fprintf(stderr, "BUG: negative cursor position\n"); 2463 fflush(stderr); 2464#endif 2465 tmpcs = 0; 2466 } 2467 2468 /* prompt is not directly copied into the video buffer */ 2469 ZR_memset(vbuf, zr_sp, lpromptw); 2470 vp = vbuf + lpromptw; 2471 *vp = zr_zr; 2472 2473 for (t0 = 0; t0 < tmpll; t0++) { 2474 int base_atr_on = 0, base_atr_off = 0, ireg; 2475 int all_atr_on, all_atr_off; 2476 struct region_highlight *rhp; 2477 /* 2478 * Calculate attribute based on region. 2479 */ 2480 for (ireg = 0, rhp = region_highlights; 2481 ireg < n_region_highlights; 2482 ireg++, rhp++) { 2483 int offset; 2484 if (rhp->flags & ZRH_PREDISPLAY) 2485 offset = 0; /* include predisplay in start end */ 2486 else 2487 offset = predisplaylen; /* increment over it */ 2488 if (rhp->start + offset <= t0 && 2489 t0 < rhp->end + offset) { 2490 if (base_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) { 2491 /* keep colour already set */ 2492 base_atr_on |= rhp->atr & ~TXT_ATTR_COLOUR_ON_MASK; 2493 } else { 2494 /* no colour set yet */ 2495 base_atr_on |= rhp->atr; 2496 } 2497 if (t0 == rhp->end + offset - 1 || 2498 t0 == tmpll - 1) 2499 base_atr_off |= TXT_ATTR_OFF_FROM_ON(rhp->atr); 2500 } 2501 } 2502 if (special_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) { 2503 /* keep colours from special attributes */ 2504 all_atr_on = special_atr_on | 2505 (base_atr_on & ~TXT_ATTR_COLOUR_ON_MASK); 2506 } else { 2507 /* keep colours from standard attributes */ 2508 all_atr_on = special_atr_on | base_atr_on; 2509 } 2510 all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on); 2511 2512 if (tmpline[t0] == ZWC('\t')) { 2513 for (*vp++ = zr_sp; (vp - vbuf) & 7; ) 2514 *vp++ = zr_sp; 2515 vp[-1].atr |= base_atr_off; 2516 } else if (tmpline[t0] == ZWC('\n')) { 2517 vp->chr = ZWC('\\'); 2518 vp->atr = all_atr_on; 2519 vp++; 2520 vp->chr = ZWC('n'); 2521 vp->atr = all_atr_on | all_atr_off; 2522 vp++; 2523#ifdef MULTIBYTE_SUPPORT 2524 } else if (iswprint(tmpline[t0]) && 2525 (width = WCWIDTH(tmpline[t0])) > 0) { 2526 int ichars; 2527 if (isset(COMBININGCHARS) && IS_BASECHAR(tmpline[t0])) { 2528 /* 2529 * Look for combining characters. 2530 */ 2531 for (ichars = 1; t0 + ichars < tmpll; ichars++) { 2532 if (!IS_COMBINING(tmpline[t0+ichars])) 2533 break; 2534 } 2535 } else 2536 ichars = 1; 2537 vp->atr = base_atr_on | base_atr_off; 2538 if (ichars > 1) 2539 addmultiword(vp, tmpline+t0, ichars); 2540 else 2541 vp->chr = tmpline[t0]; 2542 vp++; 2543 while (--width > 0) { 2544 vp->chr = WEOF; 2545 vp->atr = base_atr_on | base_atr_off; 2546 vp++; 2547 } 2548 t0 += ichars - 1; 2549#endif 2550 } else if (ZC_icntrl(tmpline[t0]) 2551#ifdef MULTIBYTE_SUPPORT 2552 && (unsigned)tmpline[t0] <= 0xffU 2553#endif 2554 ) { 2555 ZLE_INT_T t = tmpline[++t0]; 2556 2557 vp->chr = ZWC('^'); 2558 vp->atr = all_atr_on; 2559 vp++; 2560 vp->chr = (((unsigned int)t & ~0x80u) > 31) ? 2561 ZWC('?') : (t | ZWC('@')); 2562 vp->atr = all_atr_on | all_atr_off; 2563 vp++; 2564 } 2565#ifdef MULTIBYTE_SUPPORT 2566 else { 2567 char dispchars[11]; 2568 char *dispptr = dispchars; 2569 wchar_t wc; 2570 int started = 0; 2571 2572 if ((unsigned)tmpline[t0] > 0xffffU) { 2573 sprintf(dispchars, "<%.08x>", (unsigned)tmpline[t0]); 2574 } else { 2575 sprintf(dispchars, "<%.04x>", (unsigned)tmpline[t0]); 2576 } 2577 while (*dispptr) { 2578 if (mbtowc(&wc, dispptr, 1) == 1 /* paranoia */) { 2579 vp->chr = wc; 2580 if (!started) 2581 started = 1; 2582 vp->atr = all_atr_on; 2583 vp++; 2584 } 2585 dispptr++; 2586 } 2587 if (started) 2588 vp[-1].atr |= all_atr_off; 2589 } 2590#else 2591 else { 2592 vp->chr = tmpline[t0]; 2593 vp->atr = base_atr_on | base_atr_off; 2594 vp++; 2595 } 2596#endif 2597 if (t0 == tmpcs) 2598 nvcs = vp - vbuf - 1; 2599 } 2600 if (t0 == tmpcs) 2601 nvcs = vp - vbuf; 2602 *vp = zr_zr; 2603 2604/* determine which part of the new line buffer we want for the display */ 2605 if (winpos == -1) 2606 winpos = 0; 2607 if ((winpos && nvcs < winpos + 1) || (nvcs > winpos + winw - 2)) { 2608 if ((winpos = nvcs - ((winw - hasam) / 2)) < 0) 2609 winpos = 0; 2610 } 2611 if (winpos) { 2612 vbuf[winpos].chr = ZWC('<'); /* line continues to the left */ 2613 vbuf[winpos].atr = 0; 2614 } 2615 if ((int)ZR_strlen(vbuf + winpos) > (winw - hasam)) { 2616 vbuf[winpos + winw - hasam - 1].chr = ZWC('>'); /* line continues to right */ 2617 vbuf[winpos + winw - hasam - 1].atr = 0; 2618 vbuf[winpos + winw - hasam] = zr_zr; 2619 } 2620 ZR_strcpy(nbuf[0], vbuf + winpos); 2621 zfree(vbuf, vsiz * sizeof(*vbuf)); 2622 nvcs -= winpos; 2623 2624 if (winpos < lpromptw) { 2625 /* skip start of buffer corresponding to prompt */ 2626 winprompt = lpromptw - winpos; 2627 } else { 2628 /* don't */ 2629 winprompt = 0; 2630 } 2631 if (winpos != owinpos && winprompt) { 2632 char *pptr; 2633 int skipping = 0, skipchars = winpos; 2634 /* 2635 * Need to output such part of the left prompt as fits. 2636 * Skip the first winpos characters, outputting 2637 * any characters marked with %{...%}. 2638 */ 2639 singmoveto(0); 2640 MB_METACHARINIT(); 2641 for (pptr = lpromptbuf; *pptr; ) { 2642 if (*pptr == Inpar) { 2643 skipping = 1; 2644 pptr++; 2645 } else if (*pptr == Outpar) { 2646 skipping = 0; 2647 pptr++; 2648 } else { 2649 convchar_t cc; 2650 int mblen = MB_METACHARLENCONV(pptr, &cc); 2651 if (skipping || skipchars == 0) 2652 { 2653 while (mblen) { 2654#ifdef MULTIBYTE_SUPPORT 2655 if (cc == WEOF) 2656 fputc('?', shout); 2657 else 2658#endif 2659 if (*pptr == Meta) { 2660 mblen--; 2661 fputc(*++pptr ^ 32, shout); 2662 } else { 2663 fputc(*pptr, shout); 2664 } 2665 pptr++; 2666 mblen--; 2667 } 2668 } else { 2669 skipchars--; 2670 pptr += mblen; 2671 } 2672 } 2673 } 2674 vcs = winprompt; 2675 } 2676 2677/* display the `visible' portion of the line buffer */ 2678 t0 = winprompt; 2679 vp = *nbuf + winprompt; 2680 refreshop = *obuf + winprompt; 2681 for (;;) { 2682 /* 2683 * Skip past all matching characters, but if there used 2684 * to be a prompt here be careful since all manner of 2685 * nastiness may be around. 2686 */ 2687 if (vp - *nbuf >= owinprompt) 2688 for (; vp->chr && ZR_equal(*refreshop, *vp); 2689 t0++, vp++, refreshop++) 2690 ; 2691 2692 if (!vp->chr && !refreshop->chr) 2693 break; 2694 2695 singmoveto(t0); /* move to where we do all output from */ 2696 2697 if (!refreshop->chr) { 2698 if ((t0 = ZR_strlen(vp))) 2699 zwrite(vp, t0); 2700 vcs += t0; 2701 break; 2702 } 2703 if (!vp->chr) { 2704 if (tccan(TCCLEAREOL)) 2705 tcoutclear(TCCLEAREOL); 2706 else 2707 for (; refreshop++->chr; vcs++) 2708 zputc(&zr_sp); 2709 break; 2710 } 2711 zputc(vp); 2712 vcs++, t0++; 2713 vp++, refreshop++; 2714 } 2715/* move to the new cursor position */ 2716 singmoveto(nvcs); 2717 2718 bufswap(); 2719} 2720 2721/**/ 2722static void 2723singmoveto(int pos) 2724{ 2725 if (pos == vcs) 2726 return; 2727 2728/* choose cheapest movements for ttys without multiple movement capabilities - 2729 do this now because it's easier (to code) */ 2730 2731 if ((!tccan(TCMULTLEFT) || pos == 0) && (pos <= vcs / 2)) { 2732 zputc(&zr_cr); 2733 vcs = 0; 2734 } 2735 2736 if (pos < vcs) 2737 tc_leftcurs(vcs - pos); 2738 else if (pos > vcs) 2739 tc_rightcurs(pos - vcs); 2740 2741 vcs = pos; 2742} 2743 2744/* Provided for loading the module in a modular fashion */ 2745 2746/**/ 2747void 2748zle_refresh_boot(void) 2749{ 2750} 2751 2752/* Provided for unloading the module in a modular fashion */ 2753 2754/**/ 2755void 2756zle_refresh_finish(void) 2757{ 2758 freevideo(); 2759 2760 if (region_highlights) 2761 { 2762 zfree(region_highlights, 2763 sizeof(struct region_highlight) * n_region_highlights); 2764 region_highlights = NULL; 2765 n_region_highlights = 0; 2766 } 2767} 2768