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 struct rparams rpms; 981#ifdef MULTIBYTE_SUPPORT 982 int width; /* width of wide character */ 983#endif 984 985 986 /* If this is called from listmatches() (indirectly via trashzle()), and * 987 * that was called from the end of zrefresh(), then we don't need to do * 988 * anything. All this `inlist' code is actually unnecessary, but it * 989 * improves speed a little in a common case. */ 990 if (inlist) 991 return; 992 993 /* 994 * zrefresh() is called from all over the place, so we can't 995 * be sure if the line is metafied for completion or not. 996 */ 997 if (zlemetaline != NULL) { 998 remetafy = 1; 999 unmetafy_line(); 1000 } 1001 else 1002 remetafy = 0; 1003 1004 if (predisplaylen || postdisplaylen) { 1005 /* There is extra text to display at the start or end of the line */ 1006 tmpline = zalloc((zlell + predisplaylen + postdisplaylen)*sizeof(*tmpline)); 1007 if (predisplaylen) 1008 ZS_memcpy(tmpline, predisplay, predisplaylen); 1009 if (zlell) 1010 ZS_memcpy(tmpline+predisplaylen, zleline, zlell); 1011 if (postdisplaylen) 1012 ZS_memcpy(tmpline+predisplaylen+zlell, postdisplay, 1013 postdisplaylen); 1014 1015 tmpcs = zlecs + predisplaylen; 1016 tmpll = predisplaylen + zlell + postdisplaylen; 1017 tmpalloced = 1; 1018 } else { 1019 tmpline = zleline; 1020 tmpcs = zlecs; 1021 tmpll = zlell; 1022 tmpalloced = 0; 1023 } 1024 1025 /* this will create region_highlights if it's still NULL */ 1026 zle_set_highlight(); 1027 1028 /* check for region between point ($CURSOR) and mark ($MARK) */ 1029 if (region_active) { 1030 if (zlecs <= mark) { 1031 region_highlights[0].start = zlecs; 1032 region_highlights[0].end = mark; 1033 } else { 1034 region_highlights[0].start = mark; 1035 region_highlights[0].end = zlecs; 1036 } 1037 } else { 1038 region_highlights[0].start = region_highlights[0].end = -1; 1039 } 1040 /* check for isearch string to highlight */ 1041 if (isearch_active) { 1042 region_highlights[1].start = isearch_startpos; 1043 region_highlights[1].end = isearch_endpos; 1044 } else { 1045 region_highlights[1].start = region_highlights[1].end = -1; 1046 } 1047 /* check for an active completion suffix */ 1048 if (suffixnoinslen) { 1049 region_highlights[2].start = zlecs - suffixnoinslen; 1050 region_highlights[2].end = zlecs; 1051 } else { 1052 region_highlights[2].start = region_highlights[2].end = -1; 1053 } 1054 1055 if (clearlist && listshown > 0) { 1056 if (tccan(TCCLEAREOD)) { 1057 int ovln = vln, ovcs = vcs; 1058 REFRESH_STRING nb = nbuf[vln]; 1059 1060 nbuf[vln] = obuf[vln]; 1061 moveto(nlnct, 0); 1062 tcoutclear(TCCLEAREOD); 1063 moveto(ovln, ovcs); 1064 nbuf[vln] = nb; 1065 } else { 1066 invalidatelist(); 1067 moveto(0, 0); 1068 clearflag = 0; 1069 resetneeded = 1; 1070 } 1071 listshown = lastlistlen = 0; 1072 if (showinglist != -2) 1073 showinglist = 0; 1074 } 1075 clearlist = 0; 1076 1077#ifdef HAVE_SELECT 1078 cost = 0; /* reset */ 1079#endif 1080 1081/* Nov 96: <mason> I haven't checked how complete this is. sgtty stuff may 1082 or may not work */ 1083#if defined(SGTABTYPE) 1084 oxtabs = ((SGTTYFLAG & SGTABTYPE) == SGTABTYPE); 1085#else 1086 oxtabs = 0; 1087#endif 1088 1089 cleareol = 0; /* unset */ 1090 more_start = more_end = 0; /* unset */ 1091 if (isset(SINGLELINEZLE) || zterm_lines < 3 1092 || (termflags & (TERM_NOUP | TERM_BAD | TERM_UNKNOWN))) 1093 termflags |= TERM_SHORT; 1094 else 1095 termflags &= ~TERM_SHORT; 1096 if (resetneeded) { 1097 onumscrolls = 0; 1098 zsetterm(); 1099#ifdef TIOCGWINSZ 1100 if (winchanged) { 1101 moveto(0, 0); 1102 t0 = olnct; /* this is to clear extra lines even when */ 1103 winchanged = 0; /* the terminal cannot TCCLEAREOD */ 1104 listshown = 0; 1105 } 1106#endif 1107 /* we probably should only have explicitly set attributes */ 1108 tsetcap(TCALLATTRSOFF, 0); 1109 tsetcap(TCSTANDOUTEND, 0); 1110 tsetcap(TCUNDERLINEEND, 0); 1111 /* cheat on attribute unset */ 1112 txtunset(TXTBOLDFACE|TXTSTANDOUT|TXTUNDERLINE); 1113 1114 if (trashedzle && !clearflag) 1115 reexpandprompt(); 1116 resetvideo(); 1117 resetneeded = 0; /* unset */ 1118 oput_rpmpt = 0; /* no right-prompt currently on screen */ 1119 1120 if (!clearflag) { 1121 if (tccan(TCCLEAREOD)) 1122 tcoutclear(TCCLEAREOD); 1123 else 1124 cleareol = 1; /* request: clear to end of line */ 1125 if (listshown > 0) 1126 listshown = 0; 1127 } 1128 if (t0 > -1) 1129 olnct = (t0 < winh) ? t0 : winh; 1130 if (termflags & TERM_SHORT) 1131 vcs = 0; 1132 else if (!clearflag && lpromptbuf[0]) { 1133 zputs(lpromptbuf, shout); 1134 if (lpromptwof == winw) 1135 zputs("\n", shout); /* works with both hasam and !hasam */ 1136 } else { 1137 txtchange = pmpt_attr; 1138 settextattributes(txtchange); 1139 } 1140 if (clearflag) { 1141 zputc(&zr_cr); 1142 vcs = 0; 1143 moveto(0, lpromptw); 1144 } 1145 fflush(shout); 1146 clearf = clearflag; 1147 } else if (winw != zterm_columns || rwinh != zterm_lines) 1148 resetvideo(); 1149 1150/* now winw equals columns and winh equals lines 1151 width comparisons can be made with winw, height comparisons with winh */ 1152 1153 if (termflags & TERM_SHORT) { 1154 singlerefresh(tmpline, tmpll, tmpcs); 1155 goto singlelineout; 1156 } 1157 1158 if (tmpcs < 0) { 1159#ifdef DEBUG 1160 fprintf(stderr, "BUG: negative cursor position\n"); 1161 fflush(stderr); 1162#endif 1163 tmpcs = 0; 1164 } 1165 scs = tmpline + tmpcs; 1166 numscrolls = 0; 1167 1168/* first, we generate the video line buffers so we know what to put on 1169 the screen - also determine final cursor position (nvln, nvcs) */ 1170 1171 /* Deemed necessary by PWS 1995/05/15 due to kill-line problems */ 1172 if (!*nbuf) 1173 *nbuf = (REFRESH_STRING)zalloc((winw + 2) * sizeof(**nbuf)); 1174 1175 memset(&rpms, 0, sizeof(rpms)); 1176 rpms.nvln = -1; 1177 1178 rpms.s = nbuf[rpms.ln = 0] + lpromptw; 1179 rpms.sen = *nbuf + winw; 1180 for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) { 1181 int base_atr_on = default_atr_on, base_atr_off = 0, ireg; 1182 int all_atr_on, all_atr_off; 1183 struct region_highlight *rhp; 1184 /* 1185 * Calculate attribute based on region. 1186 */ 1187 for (ireg = 0, rhp = region_highlights; 1188 ireg < n_region_highlights; 1189 ireg++, rhp++) { 1190 int offset; 1191 if (rhp->flags & ZRH_PREDISPLAY) 1192 offset = 0; /* include predisplay in start end */ 1193 else 1194 offset = predisplaylen; /* increment over it */ 1195 if (rhp->start + offset <= tmppos && 1196 tmppos < rhp->end + offset) { 1197 if (rhp->atr & (TXTFGCOLOUR|TXTBGCOLOUR)) { 1198 /* override colour with later entry */ 1199 base_atr_on = (base_atr_on & ~TXT_ATTR_ON_VALUES_MASK) | 1200 rhp->atr; 1201 } else { 1202 /* no colour set yet */ 1203 base_atr_on |= rhp->atr; 1204 } 1205 if (tmppos == rhp->end + offset - 1 || 1206 tmppos == tmpll - 1) 1207 base_atr_off |= TXT_ATTR_OFF_FROM_ON(rhp->atr); 1208 } 1209 } 1210 if (special_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) { 1211 /* keep colours from special attributes */ 1212 all_atr_on = special_atr_on | 1213 (base_atr_on & ~TXT_ATTR_COLOUR_ON_MASK); 1214 } else { 1215 /* keep colours from standard attributes */ 1216 all_atr_on = special_atr_on | base_atr_on; 1217 } 1218 all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on); 1219 1220 if (t == scs) /* if cursor is here, remember it */ 1221 rpms.nvcs = rpms.s - nbuf[rpms.nvln = rpms.ln]; 1222 1223 if (*t == ZWC('\n')){ /* newline */ 1224 /* text not wrapped */ 1225 if (nextline(&rpms, 0)) 1226 break; 1227 } else if (*t == ZWC('\t')) { /* tab */ 1228 t0 = rpms.s - nbuf[rpms.ln]; 1229 if ((t0 | 7) + 1 >= winw) { 1230 /* text wrapped */ 1231 if (nextline(&rpms, 1)) 1232 break; 1233 } else { 1234 do { 1235 rpms.s->chr = ZWC(' '); 1236 rpms.s->atr = base_atr_on; 1237 rpms.s++; 1238 } while ((++t0) & 7); 1239 rpms.s[-1].atr |= base_atr_off; 1240 } 1241 } 1242#ifdef MULTIBYTE_SUPPORT 1243 else if ( 1244#ifdef __STDC_ISO_10646__ 1245 !ZSH_INVALID_WCHAR_TEST(*t) && 1246#endif 1247 iswprint(*t) && (width = WCWIDTH(*t)) > 0) { 1248 int ichars; 1249 if (width > rpms.sen - rpms.s) { 1250 int started = 0; 1251 /* 1252 * Too wide to fit. Insert spaces to end of current line. 1253 */ 1254 do { 1255 rpms.s->chr = ZWC(' '); 1256 if (!started) 1257 started = 1; 1258 rpms.s->atr = all_atr_on; 1259 rpms.s++; 1260 } while (rpms.s < rpms.sen); 1261 if (started) 1262 rpms.s[-1].atr |= all_atr_off; 1263 if (nextline(&rpms, 1)) 1264 break; 1265 if (t == scs) { 1266 /* Update cursor to this point */ 1267 rpms.nvcs = rpms.s - nbuf[rpms.nvln = rpms.ln]; 1268 } 1269 } 1270 if (isset(COMBININGCHARS) && IS_BASECHAR(*t)) { 1271 /* 1272 * Look for combining characters. 1273 */ 1274 for (ichars = 1; tmppos + ichars < tmpll; ichars++) { 1275 if (!IS_COMBINING(t[ichars])) 1276 break; 1277 } 1278 } else 1279 ichars = 1; 1280 if (width > rpms.sen - rpms.s || width == 0) { 1281 /* 1282 * The screen width is too small to fit even one 1283 * occurrence. 1284 */ 1285 rpms.s->chr = ZWC('?'); 1286 rpms.s->atr = all_atr_on | all_atr_off; 1287 rpms.s++; 1288 } else { 1289 /* We can fit it without reaching the end of the line. */ 1290 /* 1291 * As we don't actually output the WEOF, we attach 1292 * any off attributes to the character itself. 1293 */ 1294 rpms.s->atr = base_atr_on | base_atr_off; 1295 if (ichars > 1) { 1296 /* 1297 * Glyph includes combining characters. 1298 * Write these into the multiword buffer and put 1299 * the index into the value at the screen location. 1300 */ 1301 addmultiword(rpms.s, t, ichars); 1302 } else { 1303 /* Single wide character */ 1304 rpms.s->chr = *t; 1305 } 1306 rpms.s++; 1307 while (--width > 0) { 1308 rpms.s->chr = WEOF; 1309 /* Not used, but be consistent... */ 1310 rpms.s->atr = base_atr_on | base_atr_off; 1311 rpms.s++; 1312 } 1313 } 1314 if (ichars > 1) { 1315 /* allow for normal increment */ 1316 tmppos += ichars - 1; 1317 t += ichars - 1; 1318 } 1319 } 1320#endif 1321 else if (ZC_icntrl(*t) 1322#ifdef MULTIBYTE_SUPPORT 1323 && (unsigned)*t <= 0xffU 1324#endif 1325 ) { /* other control character */ 1326 rpms.s->chr = ZWC('^'); 1327 rpms.s->atr = all_atr_on; 1328 rpms.s++; 1329 if (rpms.s == rpms.sen) { 1330 /* text wrapped */ 1331 rpms.s[-1].atr |= all_atr_off; 1332 if (nextline(&rpms, 1)) 1333 break; 1334 } 1335 rpms.s->chr = (((unsigned int)*t & ~0x80u) > 31) ? 1336 ZWC('?') : (*t | ZWC('@')); 1337 rpms.s->atr = all_atr_on | all_atr_off; 1338 rpms.s++; 1339 } 1340#ifdef MULTIBYTE_SUPPORT 1341 else { 1342 /* 1343 * Not printable or zero width. 1344 * Resort to hackery. 1345 */ 1346 char dispchars[11]; 1347 char *dispptr = dispchars; 1348 wchar_t wc; 1349 int started = 0; 1350 1351#ifdef __STDC_ISO_10646__ 1352 if (ZSH_INVALID_WCHAR_TEST(*t)) { 1353 int c = ZSH_INVALID_WCHAR_TO_INT(*t); 1354 sprintf(dispchars, "<%.02x>", c); 1355 } else 1356#endif 1357 if ((unsigned)*t > 0xffffU) { 1358 sprintf(dispchars, "<%.08x>", (unsigned)*t); 1359 } else { 1360 sprintf(dispchars, "<%.04x>", (unsigned)*t); 1361 } 1362 while (*dispptr) { 1363 if (mbtowc(&wc, dispptr, 1) == 1 /* paranoia */) 1364 { 1365 rpms.s->chr = wc; 1366 if (!started) 1367 started = 1; 1368 rpms.s->atr = all_atr_on; 1369 rpms.s++; 1370 if (rpms.s == rpms.sen) { 1371 /* text wrapped */ 1372 if (started) { 1373 rpms.s[-1].atr |= all_atr_off; 1374 started = 0; 1375 } 1376 if (nextline(&rpms, 1)) 1377 break; 1378 } 1379 } 1380 dispptr++; 1381 } 1382 if (started) 1383 rpms.s[-1].atr |= all_atr_off; 1384 if (*dispptr) /* nextline said stop processing */ 1385 break; 1386 } 1387#else 1388 else { /* normal character */ 1389 rpms.s->chr = *t; 1390 rpms.s->atr = base_atr_on | base_atr_off; 1391 rpms.s++; 1392 } 1393#endif 1394 if (rpms.s == rpms.sen) { 1395 /* text wrapped */ 1396 if (nextline(&rpms, 1)) 1397 break; 1398 } 1399 } 1400 1401/* if we're really on the next line, don't fake it; do everything properly */ 1402 if (t == scs && 1403 (rpms.nvcs = rpms.s - (nbuf[rpms.nvln = rpms.ln])) == winw) { 1404 /* text wrapped */ 1405 (void)nextline(&rpms, 1); 1406 *rpms.s = zr_zr; 1407 rpms.nvcs = 0; 1408 rpms.nvln++; 1409 } 1410 1411 if (t != tmpline + tmpll) 1412 more_end = 1; 1413 1414 if (statusline) { 1415 int outll, outsz, all_atr_on, all_atr_off; 1416 char *statusdup = ztrdup(statusline); 1417 ZLE_STRING_T outputline = 1418 stringaszleline(statusdup, 0, &outll, &outsz, NULL); 1419 1420 all_atr_on = special_atr_on; 1421 all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on); 1422 1423 rpms.tosln = rpms.ln + 1; 1424 nbuf[rpms.ln][winw + 1] = zr_zr; /* text not wrapped */ 1425 snextline(&rpms); 1426 u = outputline; 1427 for (; u < outputline + outll; u++) { 1428#ifdef MULTIBYTE_SUPPORT 1429 if (iswprint(*u)) { 1430 int width = WCWIDTH(*u); 1431 /* Handle wide characters as above */ 1432 if (width > rpms.sen - rpms.s) { 1433 do { 1434 *rpms.s++ = zr_sp; 1435 } while (rpms.s < rpms.sen); 1436 nbuf[rpms.ln][winw + 1] = zr_nl; 1437 snextline(&rpms); 1438 } 1439 if (width > rpms.sen - rpms.s) { 1440 rpms.s->chr = ZWC('?'); 1441 rpms.s->atr = all_atr_on | all_atr_off; 1442 rpms.s++; 1443 } else { 1444 rpms.s->chr = *u; 1445 rpms.s->atr = 0; 1446 rpms.s++; 1447 while (--width > 0) { 1448 rpms.s->chr = WEOF; 1449 rpms.s->atr = 0; 1450 rpms.s++; 1451 } 1452 } 1453 } 1454 else 1455#endif 1456 if (ZC_icntrl(*u)) { /* simplified processing in the status line */ 1457 rpms.s->chr = ZWC('^'); 1458 rpms.s->atr = all_atr_on; 1459 rpms.s++; 1460 if (rpms.s == rpms.sen) { 1461 nbuf[rpms.ln][winw + 1] = zr_nl;/* text wrapped */ 1462 snextline(&rpms); 1463 } 1464 rpms.s->chr = (((unsigned int)*u & ~0x80u) > 31) 1465 ? ZWC('?') : (*u | ZWC('@')); 1466 rpms.s->atr = all_atr_on | all_atr_off; 1467 rpms.s++; 1468 } else { 1469 rpms.s->chr = *u; 1470 rpms.s->atr = 0; 1471 rpms.s++; 1472 } 1473 if (rpms.s == rpms.sen) { 1474 nbuf[rpms.ln][winw + 1] = zr_nl; /* text wrapped */ 1475 snextline(&rpms); 1476 } 1477 } 1478 if (rpms.s == rpms.sen) { 1479 /* 1480 * I suppose we don't modify nbuf[rpms.ln][winw+1] here 1481 * since we're right at the end? 1482 */ 1483 snextline(&rpms); 1484 } 1485 zfree(outputline, outsz); 1486 free(statusdup); 1487 } 1488 *rpms.s = zr_zr; 1489 1490/* insert <.... at end of last line if there is more text past end of screen */ 1491 if (more_end) { 1492#ifdef MULTIBYTE_SUPPORT 1493 int extra_ellipsis = 0; 1494#endif 1495 if (!statusline) 1496 rpms.tosln = winh; 1497 rpms.s = nbuf[rpms.tosln - 1]; 1498 rpms.sen = rpms.s + winw - 7; 1499 for (; rpms.s < rpms.sen; rpms.s++) { 1500 if (rpms.s->chr == ZWC('\0')) { 1501 ZR_memset(rpms.s, zr_sp, rpms.sen - rpms.s); 1502 /* make sure we don't trigger the WEOF test */ 1503 rpms.sen->chr = ZWC('\0'); 1504 break; 1505 } 1506 } 1507 /* rpms.s is no longer needed */ 1508#ifdef MULTIBYTE_SUPPORT 1509 /* 1510 * Ensure we don't start overwriting in the middle of a wide 1511 * character. 1512 */ 1513 while(rpms.sen > nbuf[rpms.tosln - 1] && rpms.sen->chr == WEOF) { 1514 extra_ellipsis++; 1515 rpms.sen--; 1516 } 1517#endif 1518 ZR_memcpy(rpms.sen, zr_end_ellipsis, ZR_END_ELLIPSIS_SIZE); 1519#ifdef MULTIBYTE_SUPPORT 1520 /* Extend to the end if we backed off for a wide character */ 1521 if (extra_ellipsis) { 1522 rpms.sen += ZR_END_ELLIPSIS_SIZE; 1523 ZR_memset(rpms.sen, zr_dt, extra_ellipsis); 1524 } 1525#endif 1526 nbuf[rpms.tosln - 1][winw] = nbuf[rpms.tosln - 1][winw + 1] = zr_zr; 1527 } 1528 1529/* insert <....> at end of first status line if status is too big */ 1530 if (rpms.more_status) { 1531#ifdef MULTIBYTE_SUPPORT 1532 int extra_ellipsis = 0; 1533#endif 1534 rpms.s = nbuf[rpms.tosln]; 1535 rpms.sen = rpms.s + winw - 8; 1536 for (; rpms.s < rpms.sen; rpms.s++) { 1537 if (rpms.s->chr == ZWC('\0')) { 1538 ZR_memset(rpms.s, zr_sp, rpms.sen - rpms.s); 1539 break; 1540 } 1541 } 1542 /* rpms.s is no longer needed */ 1543#ifdef MULTIBYTE_SUPPORT 1544 /* 1545 * Ensure we don't start overwriting in the middle of a wide 1546 * character. 1547 */ 1548 while(rpms.sen > nbuf[rpms.tosln - 1] && rpms.sen->chr == WEOF) { 1549 extra_ellipsis++; 1550 rpms.sen--; 1551 } 1552#endif 1553 ZR_memcpy(rpms.sen, zr_mid_ellipsis1, ZR_MID_ELLIPSIS1_SIZE); 1554 rpms.sen += ZR_MID_ELLIPSIS1_SIZE; 1555#ifdef MULTIBYTE_SUPPORT 1556 /* Extend if we backed off for a wide character */ 1557 if (extra_ellipsis) { 1558 ZR_memset(rpms.sen, zr_dt, extra_ellipsis); 1559 rpms.sen += extra_ellipsis; 1560 } 1561#endif 1562 ZR_memcpy(rpms.sen, zr_mid_ellipsis2, ZR_MID_ELLIPSIS2_SIZE); 1563 nbuf[rpms.tosln][winw] = nbuf[rpms.tosln][winw + 1] = zr_zr; 1564 } 1565 1566 nlnct = rpms.ln + 1; 1567 for (iln = nlnct; iln < winh; iln++) { 1568 zfree(nbuf[iln], (winw + 2) * sizeof(**nbuf)); 1569 nbuf[iln] = NULL; 1570 } 1571 1572/* determine whether the right-prompt exists and can fit on the screen */ 1573 if (!more_start) { 1574 if (trashedzle && opts[TRANSIENTRPROMPT]) 1575 put_rpmpt = 0; 1576 else 1577 put_rpmpt = rprompth == 1 && rpromptbuf[0] && 1578 !strchr(rpromptbuf, '\t') && 1579 (int)ZR_strlen(nbuf[0]) + rpromptw < winw - 1; 1580 } else { 1581/* insert >.... on first line if there is more text before start of screen */ 1582 ZR_memset(nbuf[0], zr_sp, lpromptw); 1583 t0 = winw - lpromptw; 1584 t0 = t0 > ZR_START_ELLIPSIS_SIZE ? ZR_START_ELLIPSIS_SIZE : t0; 1585 ZR_memcpy(nbuf[0] + lpromptw, zr_start_ellipsis, t0); 1586 ZR_memset(nbuf[0] + lpromptw + t0, zr_sp, winw - t0 - lpromptw); 1587 nbuf[0][winw] = nbuf[0][winw + 1] = zr_zr; 1588 } 1589 1590 for (iln = 0; iln < nlnct; iln++) { 1591 /* if we have more lines than last time, clear the newly-used lines */ 1592 if (iln >= olnct) 1593 cleareol = 1; 1594 1595 /* if old line and new line are different, 1596 see if we can insert/delete a line to speed up update */ 1597 1598 if (!clearf && iln > 0 && iln < olnct - 1 && 1599 !(hasam && vcs == winw) && 1600 nbuf[iln] && obuf[iln] && 1601 ZR_strncmp(obuf[iln], nbuf[iln], 16)) { 1602 if (tccan(TCDELLINE) && obuf[iln + 1] && 1603 obuf[iln + 1][0].chr && nbuf[iln] && 1604 !ZR_strncmp(obuf[iln + 1], nbuf[iln], 16)) { 1605 moveto(iln, 0); 1606 tcout(TCDELLINE); 1607 zfree(obuf[iln], (winw + 2) * sizeof(**obuf)); 1608 for (t0 = iln; t0 != olnct; t0++) 1609 obuf[t0] = obuf[t0 + 1]; 1610 obuf[--olnct] = NULL; 1611 } 1612 /* don't try to insert a line if olnct = vmaxln (vmaxln is the number 1613 of lines that have been displayed by this routine) so that we don't 1614 go off the end of the screen. */ 1615 1616 else if (tccan(TCINSLINE) && olnct < vmaxln && nbuf[iln + 1] && 1617 obuf[iln] && !ZR_strncmp(obuf[iln], nbuf[iln + 1], 16)) { 1618 moveto(iln, 0); 1619 tcout(TCINSLINE); 1620 for (t0 = olnct; t0 != iln; t0--) 1621 obuf[t0] = obuf[t0 - 1]; 1622 obuf[iln] = NULL; 1623 olnct++; 1624 } 1625 } 1626 1627 /* update the single line */ 1628 refreshline(iln); 1629 1630 /* output the right-prompt if appropriate */ 1631 if (put_rpmpt && !iln && !oput_rpmpt) { 1632 int attrchange; 1633 1634 moveto(0, winw - 1 - rpromptw); 1635 zputs(rpromptbuf, shout); 1636 vcs = winw - 1; 1637 /* reset character attributes to that set by the main prompt */ 1638 txtchange = pmpt_attr; 1639 /* 1640 * Keep attributes that have actually changed, 1641 * which are ones off in rpmpt_attr and on in 1642 * pmpt_attr, and vice versa. 1643 */ 1644 attrchange = txtchange & 1645 (TXT_ATTR_OFF_FROM_ON(rpmpt_attr) | 1646 TXT_ATTR_ON_FROM_OFF(rpmpt_attr)); 1647 /* 1648 * Careful in case the colour changed. 1649 */ 1650 if (txtchangeisset(txtchange, TXTFGCOLOUR) && 1651 (!txtchangeisset(rpmpt_attr, TXTFGCOLOUR) || 1652 ((txtchange ^ rpmpt_attr) & TXT_ATTR_FG_COL_MASK))) 1653 { 1654 attrchange |= 1655 txtchange & (TXTFGCOLOUR | TXT_ATTR_FG_COL_MASK); 1656 } 1657 if (txtchangeisset(txtchange, TXTBGCOLOUR) && 1658 (!txtchangeisset(rpmpt_attr, TXTBGCOLOUR) || 1659 ((txtchange ^ rpmpt_attr) & TXT_ATTR_BG_COL_MASK))) 1660 { 1661 attrchange |= 1662 txtchange & (TXTBGCOLOUR | TXT_ATTR_BG_COL_MASK); 1663 } 1664 /* 1665 * Now feed these changes into the usual function, 1666 * if necessary. 1667 */ 1668 if (attrchange) 1669 settextattributes(attrchange); 1670 } 1671 } 1672 1673/* if old buffer had extra lines, set them to be cleared and refresh them 1674individually */ 1675 1676 if (olnct > nlnct) { 1677 cleareol = 1; 1678 for (iln = nlnct; iln < olnct; iln++) 1679 refreshline(iln); 1680 } 1681 1682/* reset character attributes */ 1683 if (clearf && postedit) { 1684 if ((txtchange = pmpt_attr ? pmpt_attr : rpmpt_attr)) 1685 settextattributes(txtchange); 1686 } 1687 clearf = 0; 1688 oput_rpmpt = put_rpmpt; 1689 1690/* move to the new cursor position */ 1691 moveto(rpms.nvln, rpms.nvcs); 1692 1693/* swap old and new buffers - better than freeing/allocating every time */ 1694 bufswap(); 1695 1696/* store current values so we can use them next time */ 1697 ovln = rpms.nvln; 1698 olnct = nlnct; 1699 onumscrolls = numscrolls; 1700 if (nlnct > vmaxln) 1701 vmaxln = nlnct; 1702singlelineout: 1703 fflush(shout); /* make sure everything is written out */ 1704 1705 if (tmpalloced) 1706 zfree(tmpline, tmpll * sizeof(*tmpline)); 1707 1708 zle_free_highlight(); 1709 1710 /* if we have a new list showing, note it; if part of the list has been 1711 overwritten, redisplay it. We have to metafy line back before calling 1712 completion code */ 1713 if (showinglist == -2 || (showinglist > 0 && showinglist < nlnct)) { 1714 if (remetafy) { 1715 metafy_line(); 1716 remetafy = 0; 1717 } 1718 inlist = 1; 1719 listmatches(); 1720 inlist = 0; 1721 zrefresh(); 1722 } 1723 if (showinglist == -1) 1724 showinglist = nlnct; 1725 1726 if (remetafy) 1727 metafy_line(); 1728} 1729 1730#define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS]) 1731#define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL]) 1732#define tc_delchars(X) (void) tcmultout(TCDEL, TCMULTDEL, (X)) 1733#define tc_inschars(X) (void) tcmultout(TCINS, TCMULTINS, (X)) 1734#define tc_upcurs(X) (void) tcmultout(TCUP, TCMULTUP, (X)) 1735#define tc_leftcurs(X) (void) tcmultout(TCLEFT, TCMULTLEFT, (X)) 1736 1737/* 1738 * Once again, in the multibyte case the arguments must be in the 1739 * order: element of old video array, element of new video array. 1740 */ 1741static int 1742wpfxlen(const REFRESH_ELEMENT *olds, const REFRESH_ELEMENT *news) 1743{ 1744 int i = 0; 1745 1746 while (olds->chr && ZR_equal(*olds, *news)) 1747 olds++, news++, i++; 1748 return i; 1749} 1750 1751/* refresh one line, using whatever speed-up tricks are provided by the tty */ 1752 1753/**/ 1754static void 1755refreshline(int ln) 1756{ 1757 REFRESH_STRING nl, ol, p1; /* line buffer pointers */ 1758 int ccs = 0, /* temporary count for cursor position */ 1759 char_ins = 0, /* number of characters inserted/deleted */ 1760 col_cleareol, /* clear to end-of-line from this column */ 1761 i, j, /* tmp */ 1762 ins_last, /* insert pushed last character off line */ 1763 nllen, ollen, /* new and old line buffer lengths */ 1764 rnllen; /* real new line buffer length */ 1765 1766/* 0: setup */ 1767 nl = nbuf[ln]; 1768 rnllen = nllen = nl ? ZR_strlen(nl) : 0; 1769 if (ln < olnct && obuf[ln]) { 1770 ol = obuf[ln]; 1771 ollen = ZR_strlen(ol); 1772 } 1773 else { 1774 static REFRESH_ELEMENT nullchr = { ZWC('\0'), 0 }; 1775 ol = &nullchr; 1776 ollen = 0; 1777 } 1778 1779/* optimisation: can easily happen for clearing old lines. If the terminal has 1780 the capability, then this is the easiest way to skip unnecessary stuff */ 1781 if (cleareol && !nllen && !(hasam && ln < nlnct - 1) 1782 && tccan(TCCLEAREOL)) { 1783 moveto(ln, 0); 1784 tcoutclear(TCCLEAREOL); 1785 return; 1786 } 1787 1788/* 1: pad out the new buffer with spaces to contain _all_ of the characters 1789 which need to be written. do this now to allow some pre-processing */ 1790 1791 if (cleareol /* request to clear to end of line */ 1792 || (!nllen && (ln != 0 || !put_rpmpt)) /* no line buffer given */ 1793 || (ln == 0 && (put_rpmpt != oput_rpmpt))) { /* prompt changed */ 1794 p1 = zhalloc((winw + 2) * sizeof(*p1)); 1795 if (nllen) 1796 ZR_memcpy(p1, nl, nllen); 1797 ZR_memset(p1 + nllen, zr_sp, winw - nllen); 1798 p1[winw] = zr_zr; 1799 if (nllen < winw) 1800 p1[winw + 1] = zr_zr; 1801 else 1802 p1[winw + 1] = nl[winw + 1]; 1803 if (ln && nbuf[ln]) 1804 ZR_memcpy(nl, p1, winw + 2); /* next time obuf will be up-to-date */ 1805 else 1806 nl = p1; /* don't keep the padding for prompt line */ 1807 nllen = winw; 1808 } else if (ollen > nllen) { /* make new line at least as long as old */ 1809 p1 = zhalloc((ollen + 1) * sizeof(*p1)); 1810 ZR_memcpy(p1, nl, nllen); 1811 ZR_memset(p1 + nllen, zr_sp, ollen - nllen); 1812 p1[ollen] = zr_zr; 1813 nl = p1; 1814 nllen = ollen; 1815 } 1816 1817/* 2: see if we can clear to end-of-line, and if it's faster, work out where 1818 to do it from - we can normally only do so if there's no right-prompt. 1819 With automatic margins, we shouldn't do it if there is another line, in 1820 case it messes up cut and paste. */ 1821 1822 if (hasam && ln < nlnct - 1 && rnllen == winw) 1823 col_cleareol = -2; /* clearing eol would be evil so don't */ 1824 else { 1825 col_cleareol = -1; 1826 if (tccan(TCCLEAREOL) && (nllen == winw || put_rpmpt != oput_rpmpt)) { 1827 for (i = nllen; i && ZR_equal(zr_sp, nl[i - 1]); i--) 1828 ; 1829 for (j = ollen; j && ZR_equal(ol[j - 1], zr_sp); j--) 1830 ; 1831 if ((j > i + tclen[TCCLEAREOL]) /* new buf has enough spaces */ 1832 || (nllen == winw && ZR_equal(zr_sp, nl[winw - 1]))) 1833 col_cleareol = i; 1834 } 1835 } 1836 1837/* 2b: first a new trick for automargin niceness - good for cut and paste */ 1838 1839 if (hasam && vcs == winw) { 1840 if (nbuf[vln] && nbuf[vln][vcs + 1].chr == ZWC('\n')) { 1841 vln++, vcs = 1; 1842 if (nbuf[vln] && nbuf[vln]->chr) { 1843 zputc(nbuf[vln]); 1844 } else 1845 zputc(&zr_sp); /* I don't think this should happen */ 1846 if (ln == vln) { /* better safe than sorry */ 1847 nl++; 1848 if (ol->chr) 1849 ol++; 1850 ccs = 1; 1851 } /* else hmmm... I wonder what happened */ 1852 } else { 1853 vln++, vcs = 0; 1854 zputc(&zr_nl); 1855 } 1856 } 1857 ins_last = 0; 1858 1859/* 2c: if we're on the first line, start checking at the end of the prompt; 1860 we shouldn't be doing anything within the prompt */ 1861 1862 if (ln == 0 && lpromptw) { 1863 i = lpromptw - ccs; 1864 j = ZR_strlen(ol); 1865 nl += i; 1866 ol += (i > j ? j : i); /* if ol is too short, point it to '\0' */ 1867 ccs = lpromptw; 1868 } 1869 1870#ifdef MULTIBYTE_SUPPORT 1871 /* 1872 * Realign to a real character after any jiggery pokery at 1873 * the start of the line. 1874 */ 1875 while (nl->chr == WEOF) { 1876 nl++, ccs++, vcs++; 1877 if (ol->chr) 1878 ol++; 1879 } 1880#endif 1881 1882/* 3: main display loop - write out the buffer using whatever tricks we can */ 1883 1884 for (;;) { 1885 int now_off; 1886 1887#ifdef MULTIBYTE_SUPPORT 1888 if ((!nl->chr || nl->chr != WEOF) && (!ol->chr || ol->chr != WEOF)) { 1889#endif 1890 if (nl->chr && ol->chr && ZR_equal(ol[1], nl[1])) { 1891 /* skip only if second chars match */ 1892#ifdef MULTIBYTE_SUPPORT 1893 int ccs_was = ccs; 1894#endif 1895 /* skip past all matching characters */ 1896 for (; nl->chr && ZR_equal(*ol, *nl); nl++, ol++, ccs++) 1897 ; 1898#ifdef MULTIBYTE_SUPPORT 1899 /* Make sure ol and nl are pointing to real characters */ 1900 while ((nl->chr == WEOF || ol->chr == WEOF) && ccs > ccs_was) { 1901 nl--; 1902 ol--; 1903 ccs--; 1904 } 1905#endif 1906 } 1907 1908 if (!nl->chr) { 1909 if (ccs == winw && hasam && char_ins > 0 && ins_last 1910 && vcs != winw) { 1911 nl--; /* we can assume we can go back here */ 1912 moveto(ln, winw - 1); 1913 zputc(nl); 1914 vcs++; 1915 return; /* write last character in line */ 1916 } 1917 if ((char_ins <= 0) || (ccs >= winw)) /* written everything */ 1918 return; 1919 if (tccan(TCCLEAREOL) && (char_ins >= tclen[TCCLEAREOL]) 1920 && col_cleareol != -2) 1921 /* we've got junk on the right yet to clear */ 1922 col_cleareol = 0; /* force a clear to end of line */ 1923 } 1924 1925 moveto(ln, ccs); /* move to where we do all output from */ 1926 1927 /* if we can finish quickly, do so */ 1928 if ((col_cleareol >= 0) && (ccs >= col_cleareol)) { 1929 tcoutclear(TCCLEAREOL); 1930 return; 1931 } 1932 1933 /* we've written out the new but yet to clear rubbish due to inserts */ 1934 if (!nl->chr) { 1935 i = (winw - ccs < char_ins) ? (winw - ccs) : char_ins; 1936 if (tccan(TCDEL) && (tcdelcost(i) <= i + 1)) 1937 tc_delchars(i); 1938 else { 1939 vcs += i; 1940 while (i-- > 0) 1941 zputc(&zr_sp); 1942 } 1943 return; 1944 } 1945 1946 /* if we've reached the end of the old buffer, then there are few tricks 1947 we can do, so we just dump out what we must and clear if we can */ 1948 if (!ol->chr) { 1949 i = (col_cleareol >= 0) ? col_cleareol : nllen; 1950 i -= vcs; 1951 if (i < 0) { 1952 /* 1953 * This shouldn't be necessary, but it's better 1954 * than a crash if there's a bug somewhere else, 1955 * so report in debug mode. 1956 */ 1957 DPUTS(1, "BUG: badly calculated old line width in refresh"); 1958 i = 0; 1959 } 1960 zwrite(nl, i); 1961 vcs += i; 1962 if (col_cleareol >= 0) 1963 tcoutclear(TCCLEAREOL); 1964 return; 1965 } 1966 1967 /* inserting & deleting chars: we can if there's no right-prompt */ 1968 if ((ln || !put_rpmpt || !oput_rpmpt) 1969#ifdef MULTIBYTE_SUPPORT 1970 && ol->chr != WEOF && nl->chr != WEOF 1971#endif 1972 && nl[1].chr && ol[1].chr && !ZR_equal(ol[1], nl[1])) { 1973 1974 /* deleting characters - see if we can find a match series that 1975 makes it cheaper to delete intermediate characters 1976 eg. oldline: hifoobar \ hopefully cheaper here to delete two 1977 newline: foobar / characters, then we have six matches */ 1978 if (tccan(TCDEL)) { 1979 int first = 1; 1980 for (i = 1; ol[i].chr; i++) { 1981 if (tcdelcost(i) < wpfxlen(ol + i, nl)) { 1982 /* 1983 * Some terminals will output the current 1984 * attributes into cells added at the end by 1985 * deletions, so turn off text attributes. 1986 */ 1987 if (first) { 1988 clearattributes(); 1989 first = 0; 1990 } 1991 tc_delchars(i); 1992 ol += i; 1993 char_ins -= i; 1994#ifdef MULTIBYTE_SUPPORT 1995 while (ol->chr == WEOF) { 1996 ol++; 1997 char_ins--; 1998 } 1999#endif 2000 i = 0; 2001 break; 2002 } 2003 } 2004 if (!i) 2005 continue; 2006 } 2007 /* 2008 * inserting characters - characters pushed off the right 2009 * should be annihilated, but we don't do this if we're on the 2010 * last line lest undesired scrolling occurs due to `illegal' 2011 * characters on screen 2012 */ 2013 if (tccan(TCINS) && (vln != zterm_lines - 1)) { 2014 /* not on last line */ 2015 for (i = 1; nl[i].chr; i++) { 2016 if (tcinscost(i) < wpfxlen(ol, nl + i)) { 2017 tc_inschars(i); 2018 zwrite(nl, i); 2019 nl += i; 2020#ifdef MULTIBYTE_SUPPORT 2021 while (nl->chr == WEOF) { 2022 nl++; 2023 i++; 2024 } 2025#endif 2026 char_ins += i; 2027 ccs = (vcs += i); 2028 /* 2029 * if we've pushed off the right, truncate 2030 * oldline 2031 */ 2032 for (i = 0; ol[i].chr && i < winw - ccs; i++) 2033 ; 2034#ifdef MULTIBYTE_SUPPORT 2035 while (ol[i].chr == WEOF) 2036 i++; 2037 if (i >= winw - ccs) { 2038 /* 2039 * Yes, we're over the right. 2040 * Make sure we truncate at the real 2041 * character, not a WEOF added to 2042 * make up the width. 2043 */ 2044 while (ol[i-1].chr == WEOF) 2045 i--; 2046 ol[i] = zr_zr; 2047 ins_last = 1; 2048 } 2049#else 2050 if (i >= winw - ccs) { 2051 ol[i] = zr_zr; 2052 ins_last = 1; 2053 } 2054#endif 2055 i = 0; 2056 break; 2057 } 2058 } 2059 if (!i) 2060 continue; 2061 } 2062 } 2063#ifdef MULTIBYTE_SUPPORT 2064 } 2065#endif 2066 /* we can't do any fancy tricks, so just dump the single character 2067 and keep on trying */ 2068#ifdef MULTIBYTE_SUPPORT 2069 /* 2070 * in case we were tidying up a funny-width character when we 2071 * reached the end of the new line... 2072 */ 2073 if (!nl->chr) 2074 break; 2075 do { 2076#endif 2077 /* 2078 * If an attribute was on here but isn't any more, 2079 * output the sequence to turn it off. 2080 */ 2081 now_off = ol->atr & ~nl->atr & TXT_ATTR_ON_MASK; 2082 if (now_off) 2083 settextattributes(TXT_ATTR_OFF_FROM_ON(now_off)); 2084 2085 /* 2086 * This is deliberately called if nl->chr is WEOF 2087 * in order to keep text attributes consistent. 2088 * We check for WEOF inside. 2089 */ 2090 zputc(nl); 2091 nl++; 2092 if (ol->chr) 2093 ol++; 2094 ccs++, vcs++; 2095#ifdef MULTIBYTE_SUPPORT 2096 /* 2097 * Make sure we always overwrite the complete width of 2098 * a character that was there before. 2099 */ 2100 } while ((ol->chr == WEOF && nl->chr) || 2101 (nl->chr == WEOF && ol->chr)); 2102#endif 2103 } 2104} 2105 2106/* move the cursor to line ln (relative to the prompt line), 2107 absolute column cl; update vln, vcs - video line and column */ 2108 2109/**/ 2110void 2111moveto(int ln, int cl) 2112{ 2113 const REFRESH_ELEMENT *rep; 2114 2115 if (vcs == winw) { 2116 vln++, vcs = 0; 2117 if (!hasam) { 2118 zputc(&zr_cr); 2119 zputc(&zr_nl); 2120 } else { 2121 if ((vln < nlnct) && nbuf[vln] && nbuf[vln]->chr) 2122 rep = nbuf[vln]; 2123 else 2124 rep = &zr_sp; 2125 zputc(rep); 2126 zputc(&zr_cr); 2127 if ((vln < olnct) && obuf[vln] && obuf[vln]->chr) 2128 *obuf[vln] = *rep; 2129 } 2130 } 2131 2132 if (ln == vln && cl == vcs) 2133 return; 2134 2135/* move up */ 2136 if (ln < vln) { 2137 tc_upcurs(vln - ln); 2138 vln = ln; 2139 } 2140/* move down; if we might go off the end of the screen, use newlines 2141 instead of TCDOWN */ 2142 2143 while (ln > vln) { 2144 if (vln < vmaxln - 1) { 2145 if (ln > vmaxln - 1) { 2146 if (tc_downcurs(vmaxln - 1 - vln)) 2147 vcs = 0; 2148 vln = vmaxln - 1; 2149 } else { 2150 if (tc_downcurs(ln - vln)) 2151 vcs = 0; 2152 vln = ln; 2153 continue; 2154 } 2155 } 2156 zputc(&zr_cr), vcs = 0; /* safety precaution */ 2157 while (ln > vln) { 2158 zputc(&zr_nl); 2159 vln++; 2160 } 2161 } 2162 2163 if (cl != vcs) 2164 singmoveto(cl); 2165} 2166 2167/**/ 2168mod_export int 2169tcmultout(int cap, int multcap, int ct) 2170{ 2171 if (tccan(multcap) && (!tccan(cap) || tclen[multcap] <= tclen[cap] * ct)) { 2172 tcoutarg(multcap, ct); 2173 return 1; 2174 } else if (tccan(cap)) { 2175 while (ct--) 2176 tcout(cap); 2177 return 1; 2178 } 2179 return 0; 2180} 2181 2182/* ct: number of characters to move across */ 2183/**/ 2184static void 2185tc_rightcurs(int ct) 2186{ 2187 int cl, /* ``desired'' absolute horizontal position */ 2188 i = vcs, /* cursor position after initial movements */ 2189 j; 2190 REFRESH_STRING t; 2191 2192 cl = ct + vcs; 2193 2194/* do a multright if we can - it's the most reliable */ 2195 if (tccan(TCMULTRIGHT)) { 2196 tcoutarg(TCMULTRIGHT, ct); 2197 return; 2198 } 2199 2200/* do an absolute horizontal position if we can */ 2201 if (tccan(TCHORIZPOS)) { 2202 tcoutarg(TCHORIZPOS, cl); 2203 return; 2204 } 2205 2206/* XXX: should really check "it" in termcap and use / and % */ 2207/* try tabs if tabs are non destructive and multright is not possible */ 2208 if (!oxtabs && tccan(TCNEXTTAB) && ((vcs | 7) < cl)) { 2209 i = (vcs | 7) + 1; 2210 tcout(TCNEXTTAB); 2211 for ( ; i + 8 <= cl; i += 8) 2212 tcout(TCNEXTTAB); 2213 if ((ct = cl - i) == 0) /* number of chars still to move across */ 2214 return; 2215 } 2216 2217/* otherwise _carefully_ write the contents of the video buffer. 2218 if we're anywhere in the prompt, goto the left column and write the whole 2219 prompt out. 2220 2221 If strlen(lpromptbuf) == lpromptw, we can cheat and output 2222 the appropriate chunk of the string. This test relies on the 2223 fact that any funny business will always make the length of 2224 the string larger than the printing width, so if they're the same 2225 we have only ASCII characters or a single-byte extension of ASCII. 2226 Unfortunately this trick won't work if there are potentially 2227 characters occupying more than one column. We could flag that 2228 this has happened (since it's not that common to have characters 2229 wider than one column), but for now it's easier not to use the 2230 trick if we are using WCWIDTH() on the prompt. It's not that 2231 common to be editing in the middle of the prompt anyway, I would 2232 think. 2233 */ 2234 if (vln == 0 && i < lpromptw && !(termflags & TERM_SHORT)) { 2235#ifndef MULTIBYTE_SUPPORT 2236 if ((int)strlen(lpromptbuf) == lpromptw) 2237 fputs(lpromptbuf + i, shout); 2238 else 2239#endif 2240 if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpromptbuf))) 2241 /* it is cheaper to send TCRIGHT than reprint the whole prompt */ 2242 for (ct = lpromptw - i; ct--; ) 2243 tcout(TCRIGHT); 2244 else { 2245 if (i != 0) 2246 zputc(&zr_cr); 2247 tc_upcurs(lprompth - 1); 2248 zputs(lpromptbuf, shout); 2249 if (lpromptwof == winw) 2250 zputs("\n", shout); /* works with both hasam and !hasam */ 2251 } 2252 i = lpromptw; 2253 ct = cl - i; 2254 } 2255 2256 if (nbuf[vln]) { 2257 for (j = 0, t = nbuf[vln]; t->chr && (j < i); j++, t++); 2258 if (j == i) 2259 for ( ; t->chr && ct; ct--, t++) 2260 zputc(t); 2261 } 2262 while (ct--) 2263 zputc(&zr_sp); /* not my fault your terminal can't go right */ 2264} 2265 2266/**/ 2267mod_export int 2268tc_downcurs(int ct) 2269{ 2270 int ret = 0; 2271 2272 if (ct && !tcmultout(TCDOWN, TCMULTDOWN, ct)) { 2273 while (ct--) 2274 zputc(&zr_nl); 2275 zputc(&zr_cr), ret = -1; 2276 } 2277 return ret; 2278} 2279 2280/* 2281 * Output a termcap value using a function defined by "zle -T tc". 2282 * Loosely inspired by subst_string_by_func(). 2283 * 2284 * cap is the internal index for the capability; it will be looked up 2285 * in the table and the string passed to the function. 2286 * 2287 * arg is eithr an argument to the capability or -1 if there is none; 2288 * if it is not -1 it will be passed as an additional argument to the 2289 * function. 2290 * 2291 * outc is the output function; currently this is always putshout 2292 * but in principle it may be used to output to a string. 2293 */ 2294 2295/**/ 2296static void 2297tcout_via_func(int cap, int arg, int (*outc)(int)) 2298{ 2299 Shfunc tcout_func; 2300 int osc, osm, old_incompfunc; 2301 2302 osc = sfcontext; 2303 osm = stopmsg; 2304 old_incompfunc = incompfunc; 2305 2306 sfcontext = SFC_SUBST; 2307 incompfunc = 0; 2308 2309 if ((tcout_func = getshfunc(tcout_func_name))) { 2310 LinkList l = newlinklist(); 2311 char buf[DIGBUFSIZE], *str; 2312 2313 addlinknode(l, tcout_func_name); 2314 addlinknode(l, tccap_get_name(cap)); 2315 2316 if (arg != -1) { 2317 sprintf(buf, "%d", arg); 2318 addlinknode(l, buf); 2319 } 2320 2321 (void)doshfunc(tcout_func, l, 1); 2322 2323 str = getsparam("REPLY"); 2324 if (str) { 2325 while (*str) { 2326 int chr; 2327 if (*str == Meta) { 2328 chr = str[1] ^ 32; 2329 str += 2; 2330 } else { 2331 chr = *str++; 2332 } 2333 (void)outc(chr); 2334 } 2335 } 2336 } 2337 2338 sfcontext = osc; 2339 stopmsg = osm; 2340 incompfunc = old_incompfunc; 2341} 2342 2343/**/ 2344mod_export void 2345tcout(int cap) 2346{ 2347 if (tcout_func_name) { 2348 tcout_via_func(cap, -1, putshout); 2349 } else { 2350 tputs(tcstr[cap], 1, putshout); 2351 } 2352 SELECT_ADD_COST(tclen[cap]); 2353} 2354 2355/**/ 2356static void 2357tcoutarg(int cap, int arg) 2358{ 2359 char *result; 2360 2361 result = tgoto(tcstr[cap], arg, arg); 2362 if (tcout_func_name) { 2363 tcout_via_func(cap, arg, putshout); 2364 } else { 2365 tputs(result, 1, putshout); 2366 } 2367 SELECT_ADD_COST(strlen(result)); 2368} 2369 2370/**/ 2371mod_export int 2372clearscreen(UNUSED(char **args)) 2373{ 2374 tcoutclear(TCCLEARSCREEN); 2375 resetneeded = 1; 2376 clearflag = 0; 2377 return 0; 2378} 2379 2380/**/ 2381mod_export int 2382redisplay(UNUSED(char **args)) 2383{ 2384 moveto(0, 0); 2385 zputc(&zr_cr); /* extra care */ 2386 tc_upcurs(lprompth - 1); 2387 resetneeded = 1; 2388 clearflag = 0; 2389 return 0; 2390} 2391 2392/* 2393 * Show as much of the line buffer as we can in single line mode. 2394 * TBD: all termcap effects are turned off in this mode, so 2395 * there's no point in using character attributes. We should 2396 * decide what we're going to do and either remove the handling 2397 * from here or enable it in tsetcap(). 2398 */ 2399 2400/**/ 2401static void 2402singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) 2403{ 2404 REFRESH_STRING vbuf, vp, /* video buffer and pointer */ 2405 refreshop; /* pointer to old video buffer */ 2406 int t0, /* tmp */ 2407 vsiz, /* size of new video buffer */ 2408 nvcs = 0, /* new video cursor column */ 2409 owinpos = winpos, /* previous window position */ 2410 owinprompt = winprompt; /* previous winprompt */ 2411#ifdef MULTIBYTE_SUPPORT 2412 int width; /* width of multibyte character */ 2413#endif 2414 2415 nlnct = 1; 2416/* generate the new line buffer completely */ 2417 for (vsiz = 1 + lpromptw, t0 = 0; t0 != tmpll; t0++) { 2418 if (tmpline[t0] == ZWC('\t')) 2419 vsiz = (vsiz | 7) + 2; 2420#ifdef MULTIBYTE_SUPPORT 2421 else if (iswprint(tmpline[t0]) && ((width = WCWIDTH(tmpline[t0])) > 0)) { 2422 vsiz += width; 2423 if (isset(COMBININGCHARS) && IS_BASECHAR(tmpline[t0])) { 2424 while (t0 < tmpll-1 && IS_COMBINING(tmpline[t0+1])) 2425 t0++; 2426 } 2427 } 2428#endif 2429 else if (ZC_icntrl(tmpline[t0]) 2430#ifdef MULTIBYTE_SUPPORT 2431 && (unsigned)tmpline[t0] <= 0xffU 2432#endif 2433 ) 2434 vsiz += 2; 2435#ifdef MULTIBYTE_SUPPORT 2436 else 2437 vsiz += 10; 2438#else 2439 else 2440 vsiz++; 2441#endif 2442 } 2443 vbuf = (REFRESH_STRING)zalloc(vsiz * sizeof(*vbuf)); 2444 2445 if (tmpcs < 0) { 2446#ifdef DEBUG 2447 fprintf(stderr, "BUG: negative cursor position\n"); 2448 fflush(stderr); 2449#endif 2450 tmpcs = 0; 2451 } 2452 2453 /* prompt is not directly copied into the video buffer */ 2454 ZR_memset(vbuf, zr_sp, lpromptw); 2455 vp = vbuf + lpromptw; 2456 *vp = zr_zr; 2457 2458 for (t0 = 0; t0 < tmpll; t0++) { 2459 int base_atr_on = 0, base_atr_off = 0, ireg; 2460 int all_atr_on, all_atr_off; 2461 struct region_highlight *rhp; 2462 /* 2463 * Calculate attribute based on region. 2464 */ 2465 for (ireg = 0, rhp = region_highlights; 2466 ireg < n_region_highlights; 2467 ireg++, rhp++) { 2468 int offset; 2469 if (rhp->flags & ZRH_PREDISPLAY) 2470 offset = 0; /* include predisplay in start end */ 2471 else 2472 offset = predisplaylen; /* increment over it */ 2473 if (rhp->start + offset <= t0 && 2474 t0 < rhp->end + offset) { 2475 if (base_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) { 2476 /* keep colour already set */ 2477 base_atr_on |= rhp->atr & ~TXT_ATTR_COLOUR_ON_MASK; 2478 } else { 2479 /* no colour set yet */ 2480 base_atr_on |= rhp->atr; 2481 } 2482 if (t0 == rhp->end + offset - 1 || 2483 t0 == tmpll - 1) 2484 base_atr_off |= TXT_ATTR_OFF_FROM_ON(rhp->atr); 2485 } 2486 } 2487 if (special_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) { 2488 /* keep colours from special attributes */ 2489 all_atr_on = special_atr_on | 2490 (base_atr_on & ~TXT_ATTR_COLOUR_ON_MASK); 2491 } else { 2492 /* keep colours from standard attributes */ 2493 all_atr_on = special_atr_on | base_atr_on; 2494 } 2495 all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on); 2496 2497 if (tmpline[t0] == ZWC('\t')) { 2498 for (*vp++ = zr_sp; (vp - vbuf) & 7; ) 2499 *vp++ = zr_sp; 2500 vp[-1].atr |= base_atr_off; 2501 } else if (tmpline[t0] == ZWC('\n')) { 2502 vp->chr = ZWC('\\'); 2503 vp->atr = all_atr_on; 2504 vp++; 2505 vp->chr = ZWC('n'); 2506 vp->atr = all_atr_on | all_atr_off; 2507 vp++; 2508#ifdef MULTIBYTE_SUPPORT 2509 } else if (iswprint(tmpline[t0]) && 2510 (width = WCWIDTH(tmpline[t0])) > 0) { 2511 int ichars; 2512 if (isset(COMBININGCHARS) && IS_BASECHAR(tmpline[t0])) { 2513 /* 2514 * Look for combining characters. 2515 */ 2516 for (ichars = 1; t0 + ichars < tmpll; ichars++) { 2517 if (!IS_COMBINING(tmpline[t0+ichars])) 2518 break; 2519 } 2520 } else 2521 ichars = 1; 2522 vp->atr = base_atr_on | base_atr_off; 2523 if (ichars > 1) 2524 addmultiword(vp, tmpline+t0, ichars); 2525 else 2526 vp->chr = tmpline[t0]; 2527 vp++; 2528 while (--width > 0) { 2529 vp->chr = WEOF; 2530 vp->atr = base_atr_on | base_atr_off; 2531 vp++; 2532 } 2533 t0 += ichars - 1; 2534#endif 2535 } else if (ZC_icntrl(tmpline[t0]) 2536#ifdef MULTIBYTE_SUPPORT 2537 && (unsigned)tmpline[t0] <= 0xffU 2538#endif 2539 ) { 2540 ZLE_INT_T t = tmpline[++t0]; 2541 2542 vp->chr = ZWC('^'); 2543 vp->atr = all_atr_on; 2544 vp++; 2545 vp->chr = (((unsigned int)t & ~0x80u) > 31) ? 2546 ZWC('?') : (t | ZWC('@')); 2547 vp->atr = all_atr_on | all_atr_off; 2548 vp++; 2549 } 2550#ifdef MULTIBYTE_SUPPORT 2551 else { 2552 char dispchars[11]; 2553 char *dispptr = dispchars; 2554 wchar_t wc; 2555 int started = 0; 2556 2557 if ((unsigned)tmpline[t0] > 0xffffU) { 2558 sprintf(dispchars, "<%.08x>", (unsigned)tmpline[t0]); 2559 } else { 2560 sprintf(dispchars, "<%.04x>", (unsigned)tmpline[t0]); 2561 } 2562 while (*dispptr) { 2563 if (mbtowc(&wc, dispptr, 1) == 1 /* paranoia */) { 2564 vp->chr = wc; 2565 if (!started) 2566 started = 1; 2567 vp->atr = all_atr_on; 2568 vp++; 2569 } 2570 dispptr++; 2571 } 2572 if (started) 2573 vp[-1].atr |= all_atr_off; 2574 } 2575#else 2576 else { 2577 vp->chr = tmpline[t0]; 2578 vp->atr = base_atr_on | base_atr_off; 2579 vp++; 2580 } 2581#endif 2582 if (t0 == tmpcs) 2583 nvcs = vp - vbuf - 1; 2584 } 2585 if (t0 == tmpcs) 2586 nvcs = vp - vbuf; 2587 *vp = zr_zr; 2588 2589/* determine which part of the new line buffer we want for the display */ 2590 if (winpos == -1) 2591 winpos = 0; 2592 if ((winpos && nvcs < winpos + 1) || (nvcs > winpos + winw - 2)) { 2593 if ((winpos = nvcs - ((winw - hasam) / 2)) < 0) 2594 winpos = 0; 2595 } 2596 if (winpos) { 2597 vbuf[winpos].chr = ZWC('<'); /* line continues to the left */ 2598 vbuf[winpos].atr = 0; 2599 } 2600 if ((int)ZR_strlen(vbuf + winpos) > (winw - hasam)) { 2601 vbuf[winpos + winw - hasam - 1].chr = ZWC('>'); /* line continues to right */ 2602 vbuf[winpos + winw - hasam - 1].atr = 0; 2603 vbuf[winpos + winw - hasam] = zr_zr; 2604 } 2605 ZR_strcpy(nbuf[0], vbuf + winpos); 2606 zfree(vbuf, vsiz * sizeof(*vbuf)); 2607 nvcs -= winpos; 2608 2609 if (winpos < lpromptw) { 2610 /* skip start of buffer corresponding to prompt */ 2611 winprompt = lpromptw - winpos; 2612 } else { 2613 /* don't */ 2614 winprompt = 0; 2615 } 2616 if (winpos != owinpos && winprompt) { 2617 char *pptr; 2618 int skipping = 0, skipchars = winpos; 2619 /* 2620 * Need to output such part of the left prompt as fits. 2621 * Skip the first winpos characters, outputting 2622 * any characters marked with %{...%}. 2623 */ 2624 singmoveto(0); 2625 MB_METACHARINIT(); 2626 for (pptr = lpromptbuf; *pptr; ) { 2627 if (*pptr == Inpar) { 2628 skipping = 1; 2629 pptr++; 2630 } else if (*pptr == Outpar) { 2631 skipping = 0; 2632 pptr++; 2633 } else { 2634 convchar_t cc; 2635 int mblen = MB_METACHARLENCONV(pptr, &cc); 2636 if (skipping || skipchars == 0) 2637 { 2638 while (mblen) { 2639#ifdef MULTIBYTE_SUPPORT 2640 if (cc == WEOF) 2641 fputc('?', shout); 2642 else 2643#endif 2644 if (*pptr == Meta) { 2645 mblen--; 2646 fputc(*++pptr ^ 32, shout); 2647 } else { 2648 fputc(*pptr, shout); 2649 } 2650 pptr++; 2651 mblen--; 2652 } 2653 } else { 2654 skipchars--; 2655 pptr += mblen; 2656 } 2657 } 2658 } 2659 vcs = winprompt; 2660 } 2661 2662/* display the `visible' portion of the line buffer */ 2663 t0 = winprompt; 2664 vp = *nbuf + winprompt; 2665 refreshop = *obuf + winprompt; 2666 for (;;) { 2667 /* 2668 * Skip past all matching characters, but if there used 2669 * to be a prompt here be careful since all manner of 2670 * nastiness may be around. 2671 */ 2672 if (vp - *nbuf >= owinprompt) 2673 for (; vp->chr && ZR_equal(*refreshop, *vp); 2674 t0++, vp++, refreshop++) 2675 ; 2676 2677 if (!vp->chr && !refreshop->chr) 2678 break; 2679 2680 singmoveto(t0); /* move to where we do all output from */ 2681 2682 if (!refreshop->chr) { 2683 if ((t0 = ZR_strlen(vp))) 2684 zwrite(vp, t0); 2685 vcs += t0; 2686 break; 2687 } 2688 if (!vp->chr) { 2689 if (tccan(TCCLEAREOL)) 2690 tcoutclear(TCCLEAREOL); 2691 else 2692 for (; refreshop++->chr; vcs++) 2693 zputc(&zr_sp); 2694 break; 2695 } 2696 zputc(vp); 2697 vcs++, t0++; 2698 vp++, refreshop++; 2699 } 2700/* move to the new cursor position */ 2701 singmoveto(nvcs); 2702 2703 bufswap(); 2704} 2705 2706/**/ 2707static void 2708singmoveto(int pos) 2709{ 2710 if (pos == vcs) 2711 return; 2712 2713/* choose cheapest movements for ttys without multiple movement capabilities - 2714 do this now because it's easier (to code) */ 2715 2716 if ((!tccan(TCMULTLEFT) || pos == 0) && (pos <= vcs / 2)) { 2717 zputc(&zr_cr); 2718 vcs = 0; 2719 } 2720 2721 if (pos < vcs) 2722 tc_leftcurs(vcs - pos); 2723 else if (pos > vcs) 2724 tc_rightcurs(pos - vcs); 2725 2726 vcs = pos; 2727} 2728 2729/* Provided for loading the module in a modular fashion */ 2730 2731/**/ 2732void 2733zle_refresh_boot(void) 2734{ 2735} 2736 2737/* Provided for unloading the module in a modular fashion */ 2738 2739/**/ 2740void 2741zle_refresh_finish(void) 2742{ 2743 freevideo(); 2744 2745 if (region_highlights) 2746 { 2747 zfree(region_highlights, 2748 sizeof(struct region_highlight) * n_region_highlights); 2749 region_highlights = NULL; 2750 n_region_highlights = 0; 2751 } 2752} 2753