1/* 2 * zle_utils.c - miscellaneous line editor utilities 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#include "zle_utils.pro" 32 33/* Primary cut buffer */ 34 35/**/ 36struct cutbuffer cutbuf; 37 38/* Emacs-style kill buffer ring */ 39 40/**/ 41struct cutbuffer *kring; 42/**/ 43int kringsize, kringnum; 44 45/* Vi named cut buffers. 0-25 are the named buffers "a to "z, and * 46 * 26-34 are the numbered buffer stack "1 to "9. */ 47 48/**/ 49struct cutbuffer vibuf[35]; 50 51/* the line before last mod (for undo purposes) */ 52 53/**/ 54ZLE_STRING_T lastline; 55/**/ 56int lastlinesz, lastll, lastcs; 57 58/* size of line buffer */ 59 60/**/ 61int linesz; 62 63/* make sure that the line buffer has at least sz chars */ 64 65/**/ 66void 67sizeline(int sz) 68{ 69 int cursz = (zlemetaline != NULL) ? metalinesz : linesz; 70 71 while (sz > cursz) { 72 if (cursz < 256) 73 cursz = 256; 74 else 75 cursz *= 4; 76 77 if (zlemetaline != NULL) { 78 /* One spare character for the NULL */ 79 zlemetaline = realloc(zlemetaline, cursz + 1); 80 } else { 81 /* One spare character for the NULL, one for the newline */ 82 zleline = 83 (ZLE_STRING_T)realloc(zleline, 84 (cursz + 2) * ZLE_CHAR_SIZE); 85 } 86 } 87 88 if (zlemetaline != NULL) 89 metalinesz = cursz; 90 else 91 linesz = cursz; 92} 93 94/* 95 * Insert a character, called from main shell. 96 * Note this always operates on the metafied multibyte version of the 97 * line. 98 */ 99 100/**/ 101mod_export void 102zleaddtoline(int chr) 103{ 104 spaceinline(1); 105 zlemetaline[zlemetacs++] = chr; 106} 107 108/* 109 * Convert a line editor character to a possibly multibyte character 110 * in a metafied string. To be safe buf should have space for at least 111 * 2 * MB_CUR_MAX chars for multibyte mode and 2 otherwise. Returns the 112 * length of the string added. 113 */ 114 115/**/ 116int 117zlecharasstring(ZLE_CHAR_T inchar, char *buf) 118{ 119#ifdef MULTIBYTE_SUPPORT 120 size_t ret; 121 char *ptr; 122 123#ifdef __STDC_ISO_10646__ 124 if (ZSH_INVALID_WCHAR_TEST(inchar)) { 125 buf[0] = ZSH_INVALID_WCHAR_TO_CHAR(inchar); 126 ret = 1; 127 } else 128#endif 129 { 130 ret = wctomb(buf, inchar); 131 if (ret <= 0) { 132 /* Ick. */ 133 buf[0] = '?'; 134 return 1; 135 } 136 } 137 ptr = buf + ret - 1; 138 for (;;) { 139 if (imeta(*ptr)) { 140 char *ptr2 = buf + ret - 1; 141 for (;;) { 142 ptr2[1] = ptr2[0]; 143 if (ptr2 == ptr) 144 break; 145 ptr2--; 146 } 147 *ptr = Meta; 148 ptr[1] ^= 32; 149 ret++; 150 } 151 152 if (ptr == buf) 153 return ret; 154 ptr--; 155 } 156#else 157 if (imeta(inchar)) { 158 buf[0] = Meta; 159 buf[1] = inchar ^ 32; 160 return 2; 161 } else { 162 buf[0] = inchar; 163 return 1; 164 } 165#endif 166} 167 168/* 169 * Input a line in internal zle format, possibly using wide characters, 170 * possibly not, together with its length and the cursor position. 171 * The length must be accurate and includes all characters (no NULL 172 * termination is expected). The input cursor position is only 173 * significant if outcs is non-NULL. 174 * 175 * Output an ordinary NULL-terminated string, using multibyte characters 176 * instead of wide characters where appropriate and with the contents 177 * metafied. 178 * 179 * If outllp is non-NULL, assign the new length. This is the conventional 180 * string length, without the NULL byte. 181 * 182 * If outcsp is non-NULL, assign the new character position. 183 * If outcsp is &zlemetacs, update the positions in the region_highlight 184 * array, too. This is a bit of a hack. 185 * 186 * If useheap is 1, memory is returned from the heap, else is allocated 187 * for later freeing. 188 */ 189 190/**/ 191mod_export char * 192zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, 193 int *outcsp, int useheap) 194{ 195 int outcs, outll, sub; 196 struct region_highlight *rhp; 197 198#ifdef MULTIBYTE_SUPPORT 199 char *s; 200 int i, j; 201 size_t mb_len = 0; 202 mbstate_t mbs; 203 204 s = zalloc(inll * MB_CUR_MAX + 1); 205 206 outcs = 0; 207 memset(&mbs, 0, sizeof(mbs)); 208 for (i=0; i < inll; i++) { 209 if (incs == 0) 210 outcs = mb_len; 211 incs--; 212 if (region_highlights && outcsp == &zlemetacs) { 213 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 214 rhp < region_highlights + n_region_highlights; 215 rhp++) { 216 if (rhp->flags & ZRH_PREDISPLAY) 217 sub = predisplaylen; 218 else 219 sub = 0; 220 if (rhp->start - sub == 0) 221 rhp->start_meta = sub + mb_len; 222 rhp->start--; 223 if (rhp->end - sub == 0) 224 rhp->end_meta = sub + mb_len; 225 rhp->end--; 226 } 227 } 228#ifdef __STDC_ISO_10646__ 229 if (ZSH_INVALID_WCHAR_TEST(instr[i])) { 230 s[mb_len++] = ZSH_INVALID_WCHAR_TO_CHAR(instr[i]); 231 } else 232#endif 233 { 234 j = wcrtomb(s + mb_len, instr[i], &mbs); 235 if (j == -1) { 236 /* invalid char */ 237 s[mb_len++] = ZWC('?'); 238 memset(&mbs, 0, sizeof(mbs)); 239 } else { 240 mb_len += j; 241 } 242 } 243 } 244 if (incs == 0) 245 outcs = mb_len; 246 if (region_highlights && outcsp == &zlemetacs) { 247 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 248 rhp < region_highlights + n_region_highlights; 249 rhp++) { 250 if (rhp->flags & ZRH_PREDISPLAY) 251 sub = predisplaylen; 252 else 253 sub = 0; 254 if (rhp->start - sub == 0) 255 rhp->start_meta = sub + mb_len; 256 if (rhp->end - sub == 0) 257 rhp->end_meta = sub + mb_len; 258 } 259 } 260 s[mb_len] = '\0'; 261 262 outll = mb_len; 263#else 264 outll = inll; 265 outcs = incs; 266 if (region_highlights && outcsp == &zlemetacs) { 267 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 268 rhp < region_highlights + n_region_highlights; 269 rhp++) { 270 rhp->start_meta = rhp->start; 271 rhp->end_meta = rhp->end; 272 } 273 } 274#endif 275 276 /* 277 * *outcsp and *outllp are to be indexes into the final string, 278 * not character offsets, so we need to take account of any 279 * metafiable characters. 280 */ 281 if (outcsp != NULL || outllp != NULL) { 282#ifdef MULTIBYTE_SUPPORT 283 char *strp = s; 284#else 285 char *strp = instr; 286#endif 287 char *stopcs = strp + outcs; 288 char *stopll = strp + outll; 289 char *startp = strp; 290 291 if (region_highlights && outcsp == &zlemetacs) { 292 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 293 rhp < region_highlights + n_region_highlights; 294 rhp++) { 295 /* Used as temporary storage */ 296 rhp->start = rhp->start_meta; 297 rhp->end = rhp->end_meta; 298 } 299 } 300 while (strp < stopll) { 301 if (imeta(*strp)) { 302 if (strp < stopcs) 303 outcs++; 304 if (region_highlights && outcsp == &zlemetacs) { 305 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 306 rhp < region_highlights + n_region_highlights; 307 rhp++) { 308 if (rhp->flags & ZRH_PREDISPLAY) 309 sub = predisplaylen; 310 else 311 sub = 0; 312 if (strp < startp + rhp->start - sub) { 313 rhp->start_meta++; 314 } 315 if (strp < startp + rhp->end - sub) { 316 rhp->end_meta++; 317 } 318 } 319 } 320 outll++; 321 } 322 strp++; 323 } 324 if (outcsp != NULL) 325 *outcsp = outcs; 326 if (outllp != NULL) 327 *outllp = outll; 328 } 329 330#ifdef MULTIBYTE_SUPPORT 331 if (useheap) { 332 char *ret = metafy(s, mb_len, META_HEAPDUP); 333 334 zfree(s, inll * MB_CUR_MAX + 1); 335 336 return ret; 337 } 338 return metafy(s, mb_len, META_REALLOC); 339#else 340 return metafy(instr, inll, useheap ? META_HEAPDUP : META_DUP); 341#endif 342} 343 344 345/* 346 * Input a NULL-terminated metafied string instr. 347 * Output a line in internal zle format, together with its length 348 * in the appropriate character units. Note that outll may not be NULL. 349 * 350 * If outsz is non-NULL, the number of allocated characters in the 351 * string is written there. For compatibility with use of the linesz 352 * variable (allocate size of zleline), at least two characters are 353 * allocated more than needed for immediate use. (The extra characters 354 * may take a newline and a null at a later stage.) These are not 355 * included in *outsz. 356 * 357 * If outcs is non-NULL, the character position in the original 358 * string incs (a standard string offset, i.e. incremented 2 for 359 * each metafied character) is converted into the corresponding 360 * character position in *outcs. 361 * 362 * If, further, outcs is &zlecs, we update the positions in the 363 * region_highlight array, too. (This is a bit of a hack.) 364 * 365 * Note that instr is modified in place, hence should be copied 366 * first if necessary; 367 * 368 * Memory for the returned string is permanently allocated. *outsz may 369 * be longer than the *outll returned. Hence it should be freed with 370 * zfree(outstr, *outsz) or free(outstr), not zfree(outstr, *outll). 371 */ 372 373/**/ 374mod_export ZLE_STRING_T 375stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) 376{ 377 ZLE_STRING_T outstr; 378 int ll, sz, sub; 379 struct region_highlight *rhp; 380#ifdef MULTIBYTE_SUPPORT 381 mbstate_t mbs; 382#endif 383 384 if (outcs) { 385 /* 386 * Take account of Meta characters in the input string 387 * before we unmetafy it. This does not yet take account 388 * of multibyte characters. If there are none, this 389 * is all the processing required to calculate outcs. 390 */ 391 char *inptr = instr, *cspos = instr + incs; 392 if (region_highlights && outcs == &zlecs) { 393 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 394 rhp < region_highlights + n_region_highlights; 395 rhp++) { 396 rhp->start = rhp->start_meta; 397 rhp->end = rhp->end_meta; 398 } 399 } 400 while (*inptr) { 401 if (*inptr == Meta) { 402 if (inptr < cspos) { 403 incs--; 404 } 405 if (region_highlights && outcs == &zlecs) { 406 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 407 rhp < region_highlights + n_region_highlights; 408 rhp++) { 409 if (rhp->flags & ZRH_PREDISPLAY) 410 sub = predisplaylen; 411 else 412 sub = 0; 413 if (inptr - instr < rhp->start - sub) { 414 rhp->start_meta--; 415 } 416 if (inptr - instr < rhp->end - sub) { 417 rhp->end_meta--; 418 } 419 } 420 } 421 inptr++; 422 } 423 inptr++; 424 } 425 } 426 unmetafy(instr, &ll); 427 428 /* 429 * ll is the maximum number of characters there can be in 430 * the output string; the closer to ASCII the string, the 431 * better the guess. For the 2 see above. 432 */ 433 sz = (ll + 2) * ZLE_CHAR_SIZE; 434 if (outsz) 435 *outsz = ll; 436 outstr = (ZLE_STRING_T)zalloc(sz); 437 438#ifdef MULTIBYTE_SUPPORT 439 if (ll) { 440 char *inptr = instr; 441 wchar_t *outptr = outstr; 442 443 /* Reset shift state to input complete string */ 444 memset(&mbs, '\0', sizeof mbs); 445 446 while (ll > 0) { 447 size_t cnt = mbrtowc(outptr, inptr, ll, &mbs); 448 449#ifdef __STDC_ISO_10646__ 450 if (cnt == MB_INCOMPLETE || cnt == MB_INVALID) { 451 /* Use private encoding for invalid single byte */ 452 *outptr = ZSH_CHAR_TO_INVALID_WCHAR(*inptr); 453 cnt = 1; 454 } 455#else 456 /* 457 * At this point we don't handle either incomplete (-2) or 458 * invalid (-1) multibyte sequences. Use the current length 459 * and return. 460 */ 461 if (cnt == MB_INCOMPLETE || cnt == MB_INVALID) 462 break; 463#endif 464 465 if (cnt == 0) { 466 /* Converting '\0' returns 0, but a '\0' is a real 467 * character for us, so we should consume 1 byte 468 * (certainly true for Unicode and unlikely to be false 469 * in any non-pathological multibyte representation). */ 470 cnt = 1; 471 } else if (cnt > (size_t)ll) { 472 /* 473 * Some multibyte implementations return the 474 * full length of a previous incomplete character 475 * instead of the remaining length. 476 * This is paranoia: it only applies if we start 477 * midway through a multibyte character, which 478 * presumably can't happen. 479 */ 480 cnt = ll; 481 } 482 483 if (outcs) { 484 int offs = inptr - instr; 485 if (offs <= incs && incs < offs + (int)cnt) 486 *outcs = outptr - outstr; 487 if (region_highlights && outcs == &zlecs) { 488 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 489 rhp < region_highlights + n_region_highlights; 490 rhp++) { 491 if (rhp->flags & ZRH_PREDISPLAY) 492 sub = predisplaylen; 493 else 494 sub = 0; 495 if (offs <= rhp->start_meta - sub && 496 rhp->start_meta - sub < offs + (int)cnt) { 497 rhp->start = outptr - outstr + sub; 498 } 499 if (offs <= rhp->end_meta - sub && 500 rhp->end_meta - sub < offs + (int)cnt) { 501 rhp->end = outptr - outstr + sub; 502 } 503 } 504 } 505 } 506 507 inptr += cnt; 508 outptr++; 509 ll -= cnt; 510 } 511 if (outcs && inptr <= instr + incs) 512 *outcs = outptr - outstr; 513 *outll = outptr - outstr; 514 } else { 515 *outll = 0; 516 if (outcs) 517 *outcs = 0; 518 } 519#else 520 memcpy(outstr, instr, ll); 521 *outll = ll; 522 if (outcs) 523 *outcs = incs; 524 if (region_highlights && outcs == &zlecs) { 525 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 526 rhp < region_highlights + n_region_highlights; 527 rhp++) { 528 rhp->start = rhp->start_meta; 529 rhp->end = rhp->end_meta; 530 } 531 } 532#endif 533 534 return outstr; 535} 536 537/* 538 * This function is called when we are playing very nasty tricks 539 * indeed: see bufferwords in hist.c. Consequently we can make 540 * absolutely no assumption about the state whatsoever, except 541 * that it has one. 542 */ 543 544/**/ 545mod_export char * 546zlegetline(int *ll, int *cs) 547{ 548 if (zlemetaline != NULL) { 549 *ll = zlemetall; 550 *cs = zlemetacs; 551 return ztrdup(zlemetaline); 552 } 553 if (zleline) 554 return zlelineasstring(zleline, zlell, zlecs, ll, cs, 0); 555 *ll = *cs = 0; 556 return ztrdup(""); 557} 558 559 560/* Forward reference */ 561struct zle_region; 562 563/* A non-special entry in region_highlight */ 564struct zle_region { 565 struct zle_region *next; 566 /* Entries of region_highlight, as needed */ 567 int atr; 568 int start; 569 int end; 570 int flags; 571}; 572 573/* Forward reference */ 574struct zle_position; 575 576/* A saved set of position information */ 577struct zle_position { 578 /* Link pointer */ 579 struct zle_position *next; 580 /* Cursor position */ 581 int cs; 582 /* Mark */ 583 int mk; 584 /* Line length */ 585 int ll; 586 struct zle_region *regions; 587}; 588 589/* LIFO stack of positions */ 590struct zle_position *zle_positions; 591 592/* 593 * Save positions including cursor, end-of-line and 594 * (non-special) region highlighting. 595 * 596 * Must be matched by a subsequent zle_restore_positions(). 597 */ 598 599/**/ 600mod_export void 601zle_save_positions(void) 602{ 603 struct region_highlight *rhp; 604 struct zle_position *newpos; 605 struct zle_region **newrhpp, *newrhp; 606 607 newpos = (struct zle_position *)zalloc(sizeof(*newpos)); 608 609 newpos->mk = mark; 610 if (zlemetaline) { 611 /* Use metafied information */ 612 newpos->cs = zlemetacs; 613 newpos->ll = zlemetall; 614 } else { 615 /* Use unmetafied information */ 616 newpos->cs = zlecs; 617 newpos->ll = zlell; 618 619 } 620 621 newrhpp = &newpos->regions; 622 *newrhpp = NULL; 623 if (region_highlights) { 624 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 625 rhp < region_highlights + n_region_highlights; 626 rhp++) { 627 /* 628 * This is a FIFO stack, so we preserve the order 629 * of entries when we restore region_highlights. 630 */ 631 newrhp = *newrhpp = (struct zle_region *)zalloc(sizeof(**newrhpp)); 632 newrhp->next = NULL; 633 newrhp->atr = rhp->atr; 634 newrhp->flags = rhp->flags; 635 if (zlemetaline) { 636 newrhp->start = rhp->start_meta; 637 newrhp->end = rhp->end_meta; 638 } else { 639 newrhp->start = rhp->start; 640 newrhp->end = rhp->end; 641 } 642 newrhpp = &newrhp->next; 643 } 644 } 645 646 newpos->next = zle_positions; 647 zle_positions = newpos; 648} 649 650/* 651 * Restore positions previously saved. 652 * Relies on zlemetaline being restored correctly beforehand, 653 * so that it can tell whether to use metafied positions or not. 654 */ 655 656/**/ 657mod_export void 658zle_restore_positions(void) 659{ 660 struct zle_position *oldpos = zle_positions; 661 struct zle_region *oldrhp; 662 struct region_highlight *rhp; 663 int nreg; 664 665 zle_positions = oldpos->next; 666 667 mark = oldpos->mk; 668 if (zlemetaline) { 669 /* Use metafied information */ 670 zlemetacs = oldpos->cs; 671 zlemetall = oldpos->ll; 672 } else { 673 /* Use unmetafied information */ 674 zlecs = oldpos->cs; 675 zlell = oldpos->ll; 676 } 677 678 /* Count number of regions and see if the array needs resizing */ 679 for (nreg = 0, oldrhp = oldpos->regions; 680 oldrhp; 681 nreg++, oldrhp = oldrhp->next) 682 ; 683 if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) { 684 n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS; 685 region_highlights = (struct region_highlight *) 686 zrealloc(region_highlights, 687 sizeof(struct region_highlight) * n_region_highlights); 688 } 689 oldrhp = oldpos->regions; 690 rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 691 while (oldrhp) { 692 struct zle_region *nextrhp = oldrhp->next; 693 694 rhp->atr = oldrhp->atr; 695 rhp->flags = oldrhp->flags; 696 if (zlemetaline) { 697 rhp->start_meta = oldrhp->start; 698 rhp->end_meta = oldrhp->end; 699 } else { 700 rhp->start = oldrhp->start; 701 rhp->end = oldrhp->end; 702 } 703 704 zfree(oldrhp, sizeof(*oldrhp)); 705 oldrhp = nextrhp; 706 rhp++; 707 } 708 709 zfree(oldpos, sizeof(*oldpos)); 710} 711 712/* 713 * Basic utility functions for adding to line or removing from line. 714 * At this level the counts supplied are raw character counts, so 715 * the calling code must be aware of combining characters where 716 * necessary, e.g. if we want to delete a + combing grave forward 717 * from the cursor, then shiftchars() gets the count 2 (not 1). 718 * 719 * This is necessary because these utility functions don't know about 720 * zlecs, and we need to count combined characters from there. 721 */ 722 723/* insert space for ct chars at cursor position */ 724 725/**/ 726mod_export void 727spaceinline(int ct) 728{ 729 int i, sub; 730 struct region_highlight *rhp; 731 732 if (zlemetaline) { 733 sizeline(ct + zlemetall); 734 for (i = zlemetall; --i >= zlemetacs;) 735 zlemetaline[i + ct] = zlemetaline[i]; 736 zlemetall += ct; 737 zlemetaline[zlemetall] = '\0'; 738 739 if (mark > zlemetacs) 740 mark += ct; 741 742 if (region_highlights) { 743 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 744 rhp < region_highlights + n_region_highlights; 745 rhp++) { 746 if (rhp->flags & ZRH_PREDISPLAY) 747 sub = predisplaylen; 748 else 749 sub = 0; 750 if (rhp->start_meta - sub >= zlemetacs) { 751 rhp->start_meta += ct; 752 } 753 if (rhp->end_meta - sub >= zlemetacs) { 754 rhp->end_meta += ct; 755 } 756 } 757 } 758 } else { 759 sizeline(ct + zlell); 760 for (i = zlell; --i >= zlecs;) 761 zleline[i + ct] = zleline[i]; 762 zlell += ct; 763 zleline[zlell] = ZWC('\0'); 764 765 if (mark > zlecs) 766 mark += ct; 767 768 if (region_highlights) { 769 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 770 rhp < region_highlights + n_region_highlights; 771 rhp++) { 772 if (rhp->flags & ZRH_PREDISPLAY) 773 sub = predisplaylen; 774 else 775 sub = 0; 776 if (rhp->start - sub >= zlecs) { 777 rhp->start += ct; 778 } 779 if (rhp->end - sub >= zlecs) { 780 rhp->end += ct; 781 } 782 } 783 } 784 } 785 region_active = 0; 786} 787 788/* 789 * Within the ZLE line, cut the "cnt" characters from position "to". 790 */ 791 792/**/ 793void 794shiftchars(int to, int cnt) 795{ 796 struct region_highlight *rhp; 797 int sub; 798 799 if (mark >= to + cnt) 800 mark -= cnt; 801 else if (mark > to) 802 mark = to; 803 804 if (zlemetaline) { 805 /* before to is updated... */ 806 if (region_highlights) { 807 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 808 rhp < region_highlights + n_region_highlights; 809 rhp++) { 810 if (rhp->flags & ZRH_PREDISPLAY) 811 sub = predisplaylen; 812 else 813 sub = 0; 814 if (rhp->start_meta - sub > to) { 815 if (rhp->start_meta - sub > to + cnt) 816 rhp->start_meta -= cnt; 817 else 818 rhp->start_meta = to; 819 } 820 if (rhp->end_meta - sub > to) { 821 if (rhp->end_meta - sub > to + cnt) 822 rhp->end_meta -= cnt; 823 else 824 rhp->end_meta = to; 825 } 826 } 827 } 828 829 while (to + cnt < zlemetall) { 830 zlemetaline[to] = zlemetaline[to + cnt]; 831 to++; 832 } 833 zlemetaline[zlemetall = to] = '\0'; 834 } else { 835 /* before to is updated... */ 836 if (region_highlights) { 837 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; 838 rhp < region_highlights + n_region_highlights; 839 rhp++) { 840 if (rhp->flags & ZRH_PREDISPLAY) 841 sub = predisplaylen; 842 else 843 sub = 0; 844 if (rhp->start - sub > to) { 845 if (rhp->start - sub > to + cnt) 846 rhp->start -= cnt; 847 else 848 rhp->start = to; 849 } 850 if (rhp->end - sub > to) { 851 if (rhp->end - sub > to + cnt) 852 rhp->end -= cnt; 853 else 854 rhp->end = to; 855 } 856 } 857 } 858 859 while (to + cnt < zlell) { 860 zleline[to] = zleline[to + cnt]; 861 to++; 862 } 863 zleline[zlell = to] = ZWC('\0'); 864 } 865 region_active = 0; 866} 867 868/* 869 * Put the ct characters starting at zleline + i into the 870 * cutbuffer, circling the kill ring if necessary (it's 871 * not if we're dealing with vi buffers, which is detected 872 * internally). The text is not removed from zleline. 873 * 874 * dir indicates how the text is to be added to the cutbuffer, 875 * if the cutbuffer wasn't zeroed (this depends on the last 876 * command being a kill). If dir is 1, the new text goes 877 * to the front of the cut buffer. If dir is -1, the cutbuffer 878 * is completely overwritten. 879 */ 880 881/**/ 882void 883cut(int i, int ct, int flags) 884{ 885 cuttext(zleline + i, ct, flags); 886} 887 888/* 889 * As cut, but explicitly supply the text together with its length. 890 */ 891 892/**/ 893void 894cuttext(ZLE_STRING_T line, int ct, int flags) 895{ 896 if (!ct) 897 return; 898 899 UNMETACHECK(); 900 if (zmod.flags & MOD_VIBUF) { 901 struct cutbuffer *b = &vibuf[zmod.vibuf]; 902 903 if (!(zmod.flags & MOD_VIAPP) || !b->buf) { 904 free(b->buf); 905 b->buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE); 906 ZS_memcpy(b->buf, line, ct); 907 b->len = ct; 908 b->flags = vilinerange ? CUTBUFFER_LINE : 0; 909 } else { 910 int len = b->len; 911 912 if(vilinerange) 913 b->flags |= CUTBUFFER_LINE; 914 b->buf = (ZLE_STRING_T) 915 realloc((char *)b->buf, 916 (ct + len + !!(b->flags & CUTBUFFER_LINE)) 917 * ZLE_CHAR_SIZE); 918 if (b->flags & CUTBUFFER_LINE) 919 b->buf[len++] = ZWC('\n'); 920 ZS_memcpy(b->buf + len, line, ct); 921 b->len = len + ct; 922 } 923 return; 924 } else { 925 /* Save in "1, shifting "1-"8 along to "2-"9 */ 926 int n; 927 free(vibuf[34].buf); 928 for(n=34; n>26; n--) 929 vibuf[n] = vibuf[n-1]; 930 vibuf[26].buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE); 931 ZS_memcpy(vibuf[26].buf, line, ct); 932 vibuf[26].len = ct; 933 vibuf[26].flags = vilinerange ? CUTBUFFER_LINE : 0; 934 } 935 if (!cutbuf.buf) { 936 cutbuf.buf = (ZLE_STRING_T)zalloc(ZLE_CHAR_SIZE); 937 cutbuf.buf[0] = ZWC('\0'); 938 cutbuf.len = cutbuf.flags = 0; 939 } else if (!(lastcmd & ZLE_KILL) || (flags & CUT_REPLACE)) { 940 Cutbuffer kptr; 941 if (!kring) { 942 kringsize = KRINGCTDEF; 943 kring = (Cutbuffer)zshcalloc(kringsize * sizeof(struct cutbuffer)); 944 } else 945 kringnum = (kringnum + 1) % kringsize; 946 kptr = kring + kringnum; 947 if (kptr->buf) 948 free(kptr->buf); 949 *kptr = cutbuf; 950 cutbuf.buf = (ZLE_STRING_T)zalloc(ZLE_CHAR_SIZE); 951 cutbuf.buf[0] = ZWC('\0'); 952 cutbuf.len = cutbuf.flags = 0; 953 } 954 if (flags & (CUT_FRONT|CUT_REPLACE)) { 955 ZLE_STRING_T s = (ZLE_STRING_T)zalloc((cutbuf.len + ct)*ZLE_CHAR_SIZE); 956 957 ZS_memcpy(s, line, ct); 958 ZS_memcpy(s + ct, cutbuf.buf, cutbuf.len); 959 free(cutbuf.buf); 960 cutbuf.buf = s; 961 cutbuf.len += ct; 962 } else { 963 cutbuf.buf = realloc((char *)cutbuf.buf, 964 (cutbuf.len + ct) * ZLE_CHAR_SIZE); 965 ZS_memcpy(cutbuf.buf + cutbuf.len, line, ct); 966 cutbuf.len += ct; 967 } 968 if(vilinerange) 969 cutbuf.flags |= CUTBUFFER_LINE; 970 else 971 cutbuf.flags &= ~CUTBUFFER_LINE; 972} 973 974/* 975 * Now we're back in the world of zlecs where we need to keep 976 * track of whether we're on a combining character. 977 */ 978 979/**/ 980mod_export void 981backkill(int ct, int flags) 982{ 983 UNMETACHECK(); 984 if (flags & CUT_RAW) { 985 zlecs -= ct; 986 } else { 987 int origcs = zlecs; 988 while (ct--) 989 DECCS(); 990 ct = origcs - zlecs; 991 } 992 993 cut(zlecs, ct, flags); 994 shiftchars(zlecs, ct); 995 CCRIGHT(); 996} 997 998/**/ 999mod_export void 1000forekill(int ct, int flags) 1001{ 1002 int i = zlecs; 1003 1004 UNMETACHECK(); 1005 if (!(flags & CUT_RAW)) { 1006 int n = ct; 1007 while (n--) 1008 INCCS(); 1009 ct = zlecs - i; 1010 zlecs = i; 1011 } 1012 1013 cut(i, ct, flags); 1014 shiftchars(i, ct); 1015 CCRIGHT(); 1016} 1017 1018/**/ 1019mod_export void 1020backdel(int ct, int flags) 1021{ 1022 if (flags & CUT_RAW) { 1023 if (zlemetaline != NULL) { 1024 shiftchars(zlemetacs -= ct, ct); 1025 } else { 1026 shiftchars(zlecs -= ct, ct); 1027 CCRIGHT(); 1028 } 1029 } else { 1030 int n = ct, origcs = zlecs; 1031 DPUTS(zlemetaline != NULL, "backdel needs CUT_RAW when metafied"); 1032 while (n--) 1033 DECCS(); 1034 shiftchars(zlecs, origcs - zlecs); 1035 CCRIGHT(); 1036 } 1037} 1038 1039/**/ 1040mod_export void 1041foredel(int ct, int flags) 1042{ 1043 if (flags & CUT_RAW) { 1044 if (zlemetaline != NULL) { 1045 shiftchars(zlemetacs, ct); 1046 } else if (flags & CUT_RAW) { 1047 shiftchars(zlecs, ct); 1048 CCRIGHT(); 1049 } 1050 } else { 1051 int origcs = zlecs; 1052 int n = ct; 1053 DPUTS(zlemetaline != NULL, "foredel needs CUT_RAW when metafied"); 1054 while (n--) 1055 INCCS(); 1056 ct = zlecs - origcs; 1057 zlecs = origcs; 1058 shiftchars(zlecs, ct); 1059 CCRIGHT(); 1060 } 1061} 1062 1063/**/ 1064void 1065setline(char *s, int flags) 1066{ 1067 char *scp; 1068 1069 UNMETACHECK(); 1070 if (flags & ZSL_COPY) 1071 scp = ztrdup(s); 1072 else 1073 scp = s; 1074 /* 1075 * TBD: we could make this more efficient by passing the existing 1076 * allocated line to stringaszleline. 1077 */ 1078 free(zleline); 1079 1080 zleline = stringaszleline(scp, 0, &zlell, &linesz, NULL); 1081 1082 if ((flags & ZSL_TOEND) && (zlecs = zlell) && invicmdmode()) 1083 DECCS(); 1084 else if (zlecs > zlell) 1085 zlecs = zlell; 1086 CCRIGHT(); 1087 if (flags & ZSL_COPY) 1088 free(scp); 1089} 1090 1091/**/ 1092int 1093findbol(void) 1094{ 1095 int x = zlecs; 1096 1097 while (x > 0 && zleline[x - 1] != ZWC('\n')) 1098 x--; 1099 return x; 1100} 1101 1102/**/ 1103int 1104findeol(void) 1105{ 1106 int x = zlecs; 1107 1108 while (x != zlell && zleline[x] != ZWC('\n')) 1109 x++; 1110 return x; 1111} 1112 1113/**/ 1114void 1115findline(int *a, int *b) 1116{ 1117 *a = findbol(); 1118 *b = findeol(); 1119} 1120 1121/* 1122 * Query the user, and return 1 for yes, 0 for no. The question is assumed to 1123 * have been printed already, and the cursor is left immediately after the 1124 * response echoed. (Might cause a problem if this takes it onto the next 1125 * line.) <Tab> is interpreted as 'y'; any other control character is 1126 * interpreted as 'n'. If there are any characters in the buffer, this is 1127 * taken as a negative response, and no characters are read. Case is folded. 1128 */ 1129 1130/**/ 1131mod_export int 1132getzlequery(void) 1133{ 1134 ZLE_INT_T c; 1135#ifdef FIONREAD 1136 int val; 1137 1138 /* check for typeahead, which is treated as a negative response */ 1139 ioctl(SHTTY, FIONREAD, (char *)&val); 1140 if (val) { 1141 putc('n', shout); 1142 return 0; 1143 } 1144#endif 1145 1146 /* get a character from the tty and interpret it */ 1147 c = getfullchar(0); 1148 if (c == ZWC('\t')) 1149 c = ZWC('y'); 1150 else if (ZC_icntrl(c) || c == ZLEEOF) 1151 c = ZWC('n'); 1152 else 1153 c = ZC_tolower(c); 1154 /* echo response and return */ 1155 if (c != ZWC('\n')) { 1156 REFRESH_ELEMENT re; 1157 re.chr = c; 1158 re.atr = 0; 1159 zwcputc(&re, NULL); 1160 } 1161 return c == ZWC('y'); 1162} 1163 1164/* Format a string, keybinding style. */ 1165 1166/**/ 1167char * 1168bindztrdup(char *str) 1169{ 1170 int c, len = 1; 1171 char *buf, *ptr, *ret; 1172 1173 for(ptr = str; *ptr; ptr++) { 1174 c = *ptr == Meta ? STOUC(*++ptr) ^ 32 : STOUC(*ptr); 1175 if(c & 0x80) { 1176 len += 3; 1177 c &= 0x7f; 1178 } 1179 if(c < 32 || c == 0x7f) { 1180 len++; 1181 c ^= 64; 1182 } 1183 len += c == '\\' || c == '^'; 1184 len++; 1185 } 1186 ptr = buf = zalloc(len); 1187 for(; *str; str++) { 1188 c = *str == Meta ? STOUC(*++str) ^ 32 : STOUC(*str); 1189 if(c & 0x80) { 1190 *ptr++ = '\\'; 1191 *ptr++ = 'M'; 1192 *ptr++ = '-'; 1193 c &= 0x7f; 1194 } 1195 if(c < 32 || c == 0x7f) { 1196 *ptr++ = '^'; 1197 c ^= 64; 1198 } 1199 if(c == '\\' || c == '^') 1200 *ptr++ = '\\'; 1201 *ptr++ = c; 1202 } 1203 *ptr = 0; 1204 ret = dquotedztrdup(buf); 1205 zsfree(buf); 1206 return ret; 1207} 1208 1209/* Display a metafied string, keybinding-style. */ 1210 1211/**/ 1212int 1213printbind(char *str, FILE *stream) 1214{ 1215 char *b = bindztrdup(str); 1216 int ret = zputs(b, stream); 1217 1218 zsfree(b); 1219 return ret; 1220} 1221 1222/* 1223 * Display a message where the completion list normally goes. 1224 * The message must be metafied. 1225 * 1226 * TODO: there's some advantage in using a ZLE_STRING_T array here, 1227 * together with improvements in other places, but messages don't 1228 * need to be particularly efficient. 1229 */ 1230 1231/**/ 1232mod_export void 1233showmsg(char const *msg) 1234{ 1235 char const *p; 1236 int up = 0, cc = 0; 1237 ZLE_CHAR_T c; 1238#ifdef MULTIBYTE_SUPPORT 1239 char *umsg; 1240 int ulen, eol = 0; 1241 size_t width; 1242 mbstate_t mbs; 1243#endif 1244 1245 trashzle(); 1246 clearflag = isset(USEZLE) && !termflags && isset(ALWAYSLASTPROMPT); 1247 1248#ifdef MULTIBYTE_SUPPORT 1249 umsg = ztrdup(msg); 1250 p = unmetafy(umsg, &ulen); 1251 memset(&mbs, 0, sizeof mbs); 1252 1253 mb_metacharinit(); 1254 while (ulen > 0) { 1255 char const *n; 1256 if (*p == '\n') { 1257 ulen--; 1258 p++; 1259 1260 putc('\n', shout); 1261 up += 1 + cc / zterm_columns; 1262 cc = 0; 1263 } else { 1264 /* 1265 * Extract the next wide character from the multibyte string. 1266 */ 1267 size_t cnt = eol ? MB_INVALID : mbrtowc(&c, p, ulen, &mbs); 1268 1269 switch (cnt) { 1270 case MB_INCOMPLETE: 1271 eol = 1; 1272 /* FALL THROUGH */ 1273 case MB_INVALID: 1274 /* 1275 * This really shouldn't be happening here, but... 1276 * Treat it as a single byte character; it may get 1277 * prettified. 1278 */ 1279 memset(&mbs, 0, sizeof mbs); 1280 n = nicechar(*p); 1281 cnt = 1; 1282 width = strlen(n); 1283 break; 1284 case 0: 1285 cnt = 1; 1286 /* FALL THROUGH */ 1287 default: 1288 /* 1289 * Paranoia: only needed if we start in the middle 1290 * of a multibyte string and only in some implementations. 1291 */ 1292 if (cnt > (size_t)ulen) 1293 cnt = ulen; 1294 n = wcs_nicechar(c, &width, NULL); 1295 break; 1296 } 1297 ulen -= cnt; 1298 p += cnt; 1299 1300 zputs(n, shout); 1301 cc += width; 1302 } 1303 } 1304 1305 free(umsg); 1306#else 1307 for(p = msg; (c = *p); p++) { 1308 if(c == Meta) 1309 c = *++p ^ 32; 1310 if(c == '\n') { 1311 putc('\n', shout); 1312 up += 1 + cc / zterm_columns; 1313 cc = 0; 1314 } else { 1315 char const *n = nicechar(c); 1316 zputs(n, shout); 1317 cc += strlen(n); 1318 } 1319 } 1320#endif 1321 up += cc / zterm_columns; 1322 1323 if (clearflag) { 1324 putc('\r', shout); 1325 tcmultout(TCUP, TCMULTUP, up + nlnct); 1326 } else 1327 putc('\n', shout); 1328 showinglist = 0; 1329} 1330 1331/* handle the error flag */ 1332 1333/**/ 1334int 1335handlefeep(UNUSED(char **args)) 1336{ 1337 zbeep(); 1338 region_active = 0; 1339 return 0; 1340} 1341 1342/* user control of auto-suffixes -- see iwidgets.list */ 1343 1344/**/ 1345int 1346handlesuffix(UNUSED(char **args)) 1347{ 1348 return 0; 1349} 1350 1351/***************/ 1352/* undo system */ 1353/***************/ 1354 1355/* head of the undo list, and the current position */ 1356 1357static struct change *changes, *curchange; 1358 1359/* list of pending changes, not yet in the undo system */ 1360 1361static struct change *nextchanges, *endnextchanges; 1362 1363/* incremented to provide a unique change number */ 1364 1365static zlong undo_changeno; 1366 1367/* If non-zero, the last increment to undo_changeno was for the variable */ 1368 1369static int undo_set_by_variable; 1370 1371/**/ 1372void 1373initundo(void) 1374{ 1375 nextchanges = NULL; 1376 changes = curchange = zalloc(sizeof(*curchange)); 1377 curchange->prev = curchange->next = NULL; 1378 curchange->del = curchange->ins = NULL; 1379 curchange->dell = curchange->insl = 0; 1380 curchange->changeno = undo_changeno = 0; 1381 undo_set_by_variable = 0; 1382 lastline = zalloc((lastlinesz = linesz) * ZLE_CHAR_SIZE); 1383 ZS_memcpy(lastline, zleline, (lastll = zlell)); 1384 lastcs = zlecs; 1385} 1386 1387/**/ 1388void 1389freeundo(void) 1390{ 1391 freechanges(changes); 1392 freechanges(nextchanges); 1393 zfree(lastline, lastlinesz); 1394} 1395 1396/**/ 1397static void 1398freechanges(struct change *p) 1399{ 1400 struct change *n; 1401 1402 for(; p; p = n) { 1403 n = p->next; 1404 free(p->del); 1405 free(p->ins); 1406 zfree(p, sizeof(*p)); 1407 } 1408} 1409 1410/* register pending changes in the undo system */ 1411 1412/**/ 1413mod_export void 1414handleundo(void) 1415{ 1416 int remetafy; 1417 1418 /* 1419 * Yuk: we call this from within the completion system, 1420 * so we need to convert back to the form which can be 1421 * copied into undo entries. 1422 */ 1423 if (zlemetaline != NULL) { 1424 unmetafy_line(); 1425 remetafy = 1; 1426 } else 1427 remetafy = 0; 1428 1429 mkundoent(); 1430 if(nextchanges) { 1431 setlastline(); 1432 if(curchange->next) { 1433 freechanges(curchange->next); 1434 curchange->next = NULL; 1435 free(curchange->del); 1436 free(curchange->ins); 1437 curchange->del = curchange->ins = NULL; 1438 curchange->dell = curchange->insl = 0; 1439 } 1440 nextchanges->prev = curchange->prev; 1441 if(curchange->prev) 1442 curchange->prev->next = nextchanges; 1443 else 1444 changes = nextchanges; 1445 curchange->prev = endnextchanges; 1446 endnextchanges->next = curchange; 1447 nextchanges = endnextchanges = NULL; 1448 } 1449 1450 if (remetafy) 1451 metafy_line(); 1452} 1453 1454/* add an entry to the undo system, if anything has changed */ 1455 1456/**/ 1457void 1458mkundoent(void) 1459{ 1460 int pre, suf; 1461 int sh = zlell < lastll ? zlell : lastll; 1462 struct change *ch; 1463 1464 UNMETACHECK(); 1465 if(lastll == zlell && !ZS_memcmp(lastline, zleline, zlell)) { 1466 lastcs = zlecs; 1467 return; 1468 } 1469 for(pre = 0; pre < sh && zleline[pre] == lastline[pre]; ) 1470 pre++; 1471 for(suf = 0; suf < sh - pre && 1472 zleline[zlell - 1 - suf] == lastline[lastll - 1 - suf]; ) 1473 suf++; 1474 ch = zalloc(sizeof(*ch)); 1475 ch->next = NULL; 1476 ch->hist = histline; 1477 ch->off = pre; 1478 ch->old_cs = lastcs; 1479 ch->new_cs = zlecs; 1480 if(suf + pre == lastll) { 1481 ch->del = NULL; 1482 ch->dell = 0; 1483 } else { 1484 ch->dell = lastll - pre - suf; 1485 ch->del = (ZLE_STRING_T)zalloc(ch->dell * ZLE_CHAR_SIZE); 1486 ZS_memcpy(ch->del, lastline + pre, ch->dell); 1487 } 1488 if(suf + pre == zlell) { 1489 ch->ins = NULL; 1490 ch->insl = 0; 1491 } else { 1492 ch->insl = zlell - pre - suf; 1493 ch->ins = (ZLE_STRING_T)zalloc(ch->insl * ZLE_CHAR_SIZE); 1494 ZS_memcpy(ch->ins, zleline + pre, ch->insl); 1495 } 1496 if(nextchanges) { 1497 ch->flags = CH_PREV; 1498 ch->prev = endnextchanges; 1499 endnextchanges->flags |= CH_NEXT; 1500 endnextchanges->next = ch; 1501 } else { 1502 nextchanges = ch; 1503 ch->flags = 0; 1504 ch->prev = NULL; 1505 } 1506 ch->changeno = ++undo_changeno; 1507 undo_set_by_variable = 0; 1508 endnextchanges = ch; 1509} 1510 1511/* set lastline to match line */ 1512 1513/**/ 1514void 1515setlastline(void) 1516{ 1517 UNMETACHECK(); 1518 if(lastlinesz != linesz) 1519 lastline = realloc(lastline, (lastlinesz = linesz) * ZLE_CHAR_SIZE); 1520 ZS_memcpy(lastline, zleline, (lastll = zlell)); 1521 lastcs = zlecs; 1522} 1523 1524/* move backwards through the change list */ 1525 1526/**/ 1527int 1528undo(char **args) 1529{ 1530 zlong last_change; 1531 1532 if (*args) 1533 last_change = zstrtol(*args, NULL, 0); 1534 else 1535 last_change = (zlong)-1; 1536 1537 handleundo(); 1538 do { 1539 struct change *prev = curchange->prev; 1540 if(!prev) 1541 return 1; 1542 if (prev->changeno < last_change) 1543 break; 1544 if (unapplychange(prev)) 1545 curchange = prev; 1546 else 1547 break; 1548 } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV)); 1549 setlastline(); 1550 return 0; 1551} 1552 1553/**/ 1554static int 1555unapplychange(struct change *ch) 1556{ 1557 if(ch->hist != histline) { 1558 zle_setline(quietgethist(ch->hist)); 1559 zlecs = ch->new_cs; 1560 return 0; 1561 } 1562 zlecs = ch->off; 1563 if(ch->ins) 1564 foredel(ch->insl, CUT_RAW); 1565 if(ch->del) { 1566 spaceinline(ch->dell); 1567 ZS_memcpy(zleline + zlecs, ch->del, ch->dell); 1568 zlecs += ch->dell; 1569 } 1570 zlecs = ch->old_cs; 1571 return 1; 1572} 1573 1574/* move forwards through the change list */ 1575 1576/**/ 1577int 1578redo(UNUSED(char **args)) 1579{ 1580 handleundo(); 1581 do { 1582 if(!curchange->next) 1583 return 1; 1584 if (applychange(curchange)) 1585 curchange = curchange->next; 1586 else 1587 break; 1588 } while(curchange->prev->flags & CH_NEXT); 1589 setlastline(); 1590 return 0; 1591} 1592 1593/**/ 1594static int 1595applychange(struct change *ch) 1596{ 1597 if(ch->hist != histline) { 1598 zle_setline(quietgethist(ch->hist)); 1599 zlecs = ch->old_cs; 1600 return 0; 1601 } 1602 zlecs = ch->off; 1603 if(ch->del) 1604 foredel(ch->dell, CUT_RAW); 1605 if(ch->ins) { 1606 spaceinline(ch->insl); 1607 ZS_memcpy(zleline + zlecs, ch->ins, ch->insl); 1608 zlecs += ch->insl; 1609 } 1610 zlecs = ch->new_cs; 1611 return 1; 1612} 1613 1614/* vi undo: toggle between the end of the undo list and the preceding point */ 1615 1616/**/ 1617int 1618viundochange(char **args) 1619{ 1620 handleundo(); 1621 if(curchange->next) { 1622 do { 1623 applychange(curchange); 1624 curchange = curchange->next; 1625 } while(curchange->next); 1626 setlastline(); 1627 return 0; 1628 } else 1629 return undo(args); 1630} 1631 1632/* 1633 * Call a ZLE hook: a user-defined widget called at a specific point 1634 * within the line editor. 1635 * 1636 * A single argument arg is passed to the function (in addition to the 1637 * function name). It may be NULL. 1638 */ 1639 1640/**/ 1641void 1642zlecallhook(char *name, char *arg) 1643{ 1644 Thingy thingy = rthingy_nocreate(name); 1645 int saverrflag, savretflag; 1646 char *args[2]; 1647 1648 if (!thingy) 1649 return; 1650 1651 saverrflag = errflag; 1652 savretflag = retflag; 1653 1654 args[0] = arg; 1655 args[1] = NULL; 1656 execzlefunc(thingy, args, 1); 1657 unrefthingy(thingy); 1658 1659 errflag = saverrflag; 1660 retflag = savretflag; 1661} 1662 1663/* 1664 * Return the number corresponding to the last change made. 1665 */ 1666 1667/**/ 1668zlong 1669get_undo_current_change(UNUSED(Param pm)) 1670{ 1671 if (undo_set_by_variable) { 1672 /* We were the last to increment this, doesn't need another one. */ 1673 return undo_changeno; 1674 } 1675 undo_set_by_variable = 1; 1676 /* 1677 * Increment the number in case a change is in progress; 1678 * we don't want to back off what's already been done when 1679 * we return to this change number. This eliminates any 1680 * problem about the point where a change is numbered. 1681 */ 1682 return ++undo_changeno; 1683} 1684