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