1/* 2 * compresult.c - the complete module, completion result handling 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1999 Sven Wischnowsky 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 Sven Wischnowsky 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 Sven Wischnowsky and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Sven Wischnowsky 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 Sven Wischnowsky and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "complete.mdh" 31#include "compresult.pro" 32 33/* This counts how often the list of completions was invalidated. 34 * Can be used to detect if we have a new list. */ 35 36/**/ 37mod_export int invcount; 38 39#define inststr(X) inststrlen((X),1,-1) 40 41/* This cuts the cline list before the stuff that isn't worth 42 * inserting in the line. */ 43 44/**/ 45static Cline 46cut_cline(Cline l) 47{ 48 Cline q, p, e = NULL, maxp = NULL; 49 int sum = 0, max = 0, tmp, ls = 0, miss = 0; 50 51 /* If no match was added with matching, we don't really know 52 * which parts of the unambiguous string are worth keeping, 53 * so for now we keep everything (in the hope that this 54 * produces a string containing at least everything that was 55 * originally on the line). */ 56 57 if (!hasmatched) { 58 cline_setlens(l, 0); 59 return l; 60 } 61 e = l = cp_cline(l, 0); 62 63 /* First, search the last struct for which we have something on 64 * the line. Anything before that is kept. */ 65 66 for (q = NULL, p = l; p; p = p->next) { 67 if (p->orig || p->olen || !(p->flags & CLF_NEW)) 68 e = p->next; 69 if (!p->suffix && (p->wlen || p->llen || p->prefix)) 70 q = p; 71 } 72 if (!e && q && !q->orig && !q->olen && (q->flags & CLF_MISS) && 73 (!(q->flags & CLF_MATCHED) || (!q->prefix && !q->suffix)) && 74 (q->word ? q->wlen : q->llen) < 3) { 75 q->word = q->line = NULL; 76 q->wlen = q->llen = 0; 77 } 78 /* Then keep all structs without missing characters. */ 79 80 while (e && !(e->flags & CLF_MISS)) 81 e = e->next; 82 83 if (e) { 84 /* Then we see if there is another struct with missing 85 * characters. If not, we keep the whole list. */ 86 87 for (p = e->next; p && !(p->flags & CLF_MISS); p = p->next); 88 89 if (p) { 90 for (p = e; p; p = p->next) { 91 if (!(p->flags & CLF_MISS)) 92 sum += p->max; 93 else { 94 tmp = cline_sublen(p); 95 if (tmp > 2 && tmp > ((p->max + p->min) >> 1)) 96 sum += tmp - (p->max - tmp); 97 else if (tmp < p->min) 98 sum -= (((p->max + p->min) >> 1) - tmp) << (tmp < 2); 99 } 100 if (sum > max) { 101 max = sum; 102 maxp = p; 103 } 104 } 105 if (max) 106 e = maxp; 107 else { 108 int len = 0; 109 110 cline_setlens(l, 0); 111 ls = 1; 112 113 for (p = e; p; p = p->next) 114 len += p->min; 115 116 if (len > ((minmlen << 1) / 3)) 117 goto end; 118 } 119 e->line = e->word = NULL; 120 e->llen = e->wlen = e->olen = 0; 121 e->next = NULL; 122 } 123 } 124 end: 125 126 /* Sanity check. If there are no parts with missing characters but 127 * parts with joined substrings, remove those. */ 128 129 for (p = l, e = 0, tmp = 0; p; p = p->next) { 130 if (p->flags & (CLF_MISS|CLF_DIFF)) 131 miss = 1; 132 for (q = p->prefix; q; q = q->next) 133 if (q->flags & CLF_JOIN) { 134 e = p; 135 tmp = 0; 136 break; 137 } 138 for (q = p->suffix; q; q = q->next) 139 if (q->flags & CLF_JOIN) { 140 e = p; 141 tmp = 1; 142 break; 143 } 144 } 145 if (e && (!miss || cline_sublen(e) == e->min)) { 146 for (p = (tmp ? e->suffix : e->prefix); 147 p && p->next && !(p->next->flags & CLF_JOIN); p = p->next); 148 if (p) 149 p->next = NULL; 150 } 151 if (!ls) 152 cline_setlens(l, 0); 153 154 return l; 155} 156 157/* This builds the unambiguous string. If ins is one, it is immediately 158 * inserted into the line. Otherwise csp is used to return the relative 159 * cursor position in the string returned and posl contains all 160 * positions with missing or ambiguous characters. If ins is two, csp 161 * and posl contain real command line positions (including braces). */ 162 163/**/ 164static char * 165cline_str(Cline l, int ins, int *csp, LinkList posl) 166{ 167 Cline s; 168 int ocs = zlemetacs, ncs, pcs, scs, opos = -1, npos; 169 int pm, pmax, pmm, pma, sm, smax, smm, sma, d, dm, mid; 170 int i, j, li = 0, cbr, padd = (ins ? wb - ocs : -ocs); 171 Brinfo brp, brs; 172 173 METACHECK(); 174 175 l = cut_cline(l); 176 177 pmm = pma = smm = sma = dm = pcs = scs = 0; 178 pm = pmax = sm = smax = d = mid = cbr = -1; 179 brp = brs = NULL; 180 181 /* Get the information about the brace beginning and end we have 182 * to re-insert. */ 183 if (ins) { 184 Brinfo bp; 185 int olen = we - wb; 186 187 if ((brp = brbeg)) { 188 for (bp = brbeg; bp; bp = bp->next) { 189 bp->curpos = (hasunqu ? bp->pos : bp->qpos); 190 olen -= strlen(bp->str); 191 } 192 } 193 if ((brs = lastbrend)) { 194 for (bp = brend; bp; bp = bp->next) 195 olen -= strlen(bp->str); 196 197 for (bp = brend; bp; bp = bp->next) 198 bp->curpos = olen - (hasunqu ? bp->pos : bp->qpos); 199 } 200 while (brp && !brp->curpos) { 201 inststrlen(brp->str, 1, -1); 202 brp = brp->next; 203 } 204 while (brs && !brs->curpos) { 205 if (cbr < 0) 206 cbr = zlemetacs; 207 inststrlen(brs->str, 1, -1); 208 brs = brs->prev; 209 } 210 } 211 /* Walk through the top-level cline list. */ 212 while (l) { 213 /* Insert the original string if no prefix. */ 214 if (l->olen && !(l->flags & CLF_SUF) && !l->prefix) { 215 pcs = zlemetacs + l->olen; 216 inststrlen(l->orig, 1, l->olen); 217 } else { 218 /* Otherwise insert the prefix. */ 219 for (s = l->prefix; s; s = s->next) { 220 pcs = zlemetacs + s->llen; 221 if (s->flags & CLF_LINE) 222 inststrlen(s->line, 1, s->llen); 223 else 224 inststrlen(s->word, 1, s->wlen); 225 scs = zlemetacs; 226 227 if ((s->flags & CLF_DIFF) && (!dm || (s->flags & CLF_MATCHED))) { 228 d = zlemetacs; dm = s->flags & CLF_MATCHED; 229 if (posl && (npos = zlemetacs + padd) != opos) { 230 opos = npos; 231 addlinknode(posl, (void *) ((long) npos)); 232 } 233 } 234 li += s->llen; 235 } 236 } 237 if (ins) { 238 int ocs, bl; 239 240 while (brp && li >= brp->curpos) { 241 ocs = zlemetacs; 242 bl = strlen(brp->str); 243 zlemetacs = pcs - (li - brp->curpos); 244 inststrlen(brp->str, 1, bl); 245 zlemetacs = ocs + bl; 246 pcs += bl; 247 scs += bl; 248 brp = brp->next; 249 } 250 } 251 /* Remember the position if this is the first prefix with 252 * missing characters. */ 253 if ((l->flags & CLF_MISS) && !(l->flags & CLF_SUF)) { 254 if (posl && (npos = zlemetacs + padd) != opos) { 255 opos = npos; 256 addlinknode(posl, (void *) ((long) npos)); 257 } 258 if (((pmax <= (l->max - l->min) || (pma && l->max != l->min)) && 259 (!pmm || (l->flags & CLF_MATCHED))) || 260 ((l->flags & CLF_MATCHED) && !pmm)) { 261 pm = zlemetacs; pmax = l->max - l->min; pmm = l->flags & CLF_MATCHED; 262 pma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); 263 } 264 } 265 if (ins) { 266 int ocs, bl; 267 268 while (brs && li >= brs->curpos) { 269 ocs = zlemetacs; 270 bl = strlen(brs->str); 271 zlemetacs = scs - (li - brs->curpos); 272 if (cbr < 0) 273 cbr = zlemetacs; 274 inststrlen(brs->str, 1, bl); 275 zlemetacs = ocs + bl; 276 pcs += bl; 277 brs = brs->prev; 278 } 279 } 280 pcs = zlemetacs; 281 /* Insert the anchor. */ 282 if (l->flags & CLF_LINE) 283 inststrlen(l->line, 1, l->llen); 284 else 285 inststrlen(l->word, 1, l->wlen); 286 scs = zlemetacs; 287 if (ins) { 288 int ocs, bl; 289 290 li += l->llen; 291 292 while (brp && li >= brp->curpos) { 293 ocs = zlemetacs; 294 bl = strlen(brp->str); 295 zlemetacs = pcs + l->llen - (li - brp->curpos); 296 inststrlen(brp->str, 1, bl); 297 zlemetacs = ocs + bl; 298 pcs += bl; 299 scs += bl; 300 brp = brp->next; 301 } 302 } 303 /* Remember the cursor position for suffixes and mids. */ 304 if (l->flags & CLF_MISS) { 305 if (l->flags & CLF_MID) 306 mid = zlemetacs; 307 else if (l->flags & CLF_SUF) { 308 if (posl && (npos = zlemetacs + padd) != opos) { 309 opos = npos; 310 addlinknode(posl, (void *) ((long) npos)); 311 } 312 if (((smax <= (l->min - l->max) || (sma && l->max != l->min)) && 313 (!smm || (l->flags & CLF_MATCHED))) || 314 ((l->flags & CLF_MATCHED) && !smm)) { 315 sm = zlemetacs; smax = l->min - l->max; smm = l->flags & CLF_MATCHED; 316 sma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); 317 } 318 } 319 } 320 if (ins) { 321 int ocs, bl; 322 323 while (brs && li >= brs->curpos) { 324 ocs = zlemetacs; 325 bl = strlen(brs->str); 326 zlemetacs = scs - (li - brs->curpos); 327 if (cbr < 0) 328 cbr = zlemetacs; 329 inststrlen(brs->str, 1, bl); 330 zlemetacs = ocs + bl; 331 pcs += bl; 332 brs = brs->prev; 333 } 334 } 335 /* And now insert the suffix or the original string. */ 336 if (l->olen && (l->flags & CLF_SUF) && !l->suffix) { 337 pcs = zlemetacs; 338 inststrlen(l->orig, 1, l->olen); 339 if (ins) { 340 int ocs, bl; 341 342 li += l->olen; 343 344 while (brp && li >= brp->curpos) { 345 ocs = zlemetacs; 346 bl = strlen(brp->str); 347 zlemetacs = pcs + l->olen - (li - brp->curpos); 348 inststrlen(brp->str, 1, bl); 349 zlemetacs = ocs + bl; 350 pcs += bl; 351 brp = brp->next; 352 } 353 while (brs && li >= brs->curpos) { 354 ocs = zlemetacs; 355 bl = strlen(brs->str); 356 zlemetacs = pcs + l->olen - (li - brs->curpos); 357 if (cbr < 0) 358 cbr = zlemetacs; 359 inststrlen(brs->str, 1, bl); 360 zlemetacs = ocs + bl; 361 pcs += bl; 362 brs = brs->prev; 363 } 364 } 365 } else { 366 Cline js = NULL; 367 368 for (j = -1, i = 0, s = l->suffix; s; s = s->next) { 369 if (j < 0 && (s->flags & CLF_DIFF)) 370 j = i, js = s; 371 pcs = zlemetacs; 372 if (s->flags & CLF_LINE) { 373 inststrlen(s->line, 0, s->llen); 374 i += s->llen; scs = zlemetacs + s->llen; 375 } else { 376 inststrlen(s->word, 0, s->wlen); 377 i += s->wlen; scs = zlemetacs + s->wlen; 378 } 379 if (ins) { 380 int ocs, bl; 381 382 li += s->llen; 383 384 while (brp && li >= brp->curpos) { 385 ocs = zlemetacs; 386 bl = strlen(brp->str); 387 zlemetacs = pcs + (li - brp->curpos); 388 inststrlen(brp->str, 1, bl); 389 zlemetacs = ocs + bl; 390 pcs += bl; 391 scs += bl; 392 brp = brp->next; 393 } 394 while (brs && li >= brs->curpos) { 395 ocs = zlemetacs; 396 bl = strlen(brs->str); 397 zlemetacs = scs - (li - brs->curpos); 398 if (cbr < 0) 399 cbr = zlemetacs; 400 inststrlen(brs->str, 1, bl); 401 zlemetacs = ocs + bl; 402 pcs += bl; 403 brs = brs->prev; 404 } 405 } 406 } 407 zlemetacs += i; 408 if (j >= 0 && (!dm || (js->flags & CLF_MATCHED))) { 409 d = zlemetacs - j; dm = js->flags & CLF_MATCHED; 410 if (posl && (npos = zlemetacs - j + padd) != opos) { 411 opos = npos; 412 addlinknode(posl, (void *) ((long) npos)); 413 } 414 } 415 } 416 l = l->next; 417 } 418 if (posl && (npos = zlemetacs + padd) != opos) 419#if 0 420 /* This could be used to put an extra colon before the end-of-word 421 * position if there is nothing missing. */ 422 addlinknode(posl, (void *) ((long) -npos)); 423#endif 424 addlinknode(posl, (void *) ((long) npos)); 425 426 if (ins) { 427 int ocs = zlemetacs; 428 429 for (; brp; brp = brp->next) 430 inststrlen(brp->str, 1, -1); 431 for (; brs; brs = brs->prev) { 432 if (cbr < 0) 433 cbr = zlemetacs; 434 inststrlen(brs->str, 1, -1); 435 } 436 if (mid >= ocs) 437 mid += zlemetacs - ocs; 438 if (pm >= ocs) 439 pm += zlemetacs - ocs; 440 if (sm >= ocs) 441 sm += zlemetacs - ocs; 442 if (d >= ocs) 443 d += zlemetacs - ocs; 444 445 if (posl) { 446 LinkNode node; 447 long p; 448 449 for (node = firstnode(posl); node; incnode(node)) { 450 p = (long) getdata(node); 451 if (p >= ocs) 452 setdata(node, (void *) (p + zlemetacs - ocs)); 453 } 454 } 455 } 456 /* This calculates the new cursor position. If we had a mid cline 457 * with missing characters, we take this, otherwise if we have a 458 * prefix with missing characters, we take that, the same for a 459 * suffix, and finally a place where the matches differ. */ 460 ncs = (mid >= 0 ? mid : 461 (cbr >= 0 ? cbr : 462 (pm >= 0 ? pm : (sm >= 0 ? sm : (d >= 0 ? d : zlemetacs))))); 463 464 if (ins != 1) { 465 /* We always inserted the string in the line. If that was not 466 * requested, we copy it and remove from the line. */ 467 char *r = zalloc((i = zlemetacs - ocs) + 1); 468 469 memcpy(r, zlemetaline + ocs, i); 470 r[i] = '\0'; 471 zlemetacs = ocs; 472 foredel(i, CUT_RAW); 473 474 if (csp) 475 *csp = ncs - ocs; 476 477 return r; 478 } 479 lastend = zlemetacs; 480 zlemetacs = ncs; 481 482 return NULL; 483} 484 485/* Small utility function turning a list of positions into a colon 486 * separated string. */ 487 488static char * 489build_pos_string(LinkList list) 490{ 491 LinkNode node; 492 int l; 493 char buf[40], *s; 494 long p; 495 496 for (node = firstnode(list), l = 0; node; incnode(node)) { 497 p = (long) getdata(node); 498#if 0 499 /* This could be used to put an extra colon before the end-of-word 500 * position if there is nothing missing. */ 501 if (p < 0) 502 sprintf(buf, ":%ld", -p); 503 else 504#endif 505 sprintf(buf, "%ld", p); 506 setdata(node, dupstring(buf)); 507 l += 1 + strlen(buf); 508 } 509 s = (char *) zalloc(l * sizeof(char)); 510 *s = 0; 511 for (node = firstnode(list); node;) { 512 strcat(s, (char *) getdata(node)); 513 incnode(node); 514 if (node) 515 strcat(s, ":"); 516 } 517 return s; 518} 519 520/* This is a utility function using the function above to allow access 521 * to the unambiguous string and cursor position via compstate. */ 522 523/**/ 524char * 525unambig_data(int *cp, char **pp, char **ip) 526{ 527 static char *scache = NULL, *pcache = NULL, *icache = NULL; 528 static int ccache; 529 530 if (mnum && ainfo) { 531 if (mnum != unambig_mnum) { 532 LinkList list = newlinklist(); 533 534 zsfree(scache); 535 scache = cline_str((ainfo->count ? ainfo->line : fainfo->line), 536 0, &ccache, list); 537 zsfree(pcache); 538 if (empty(list)) 539 pcache = ztrdup(""); 540 else 541 pcache = build_pos_string(list); 542 543 zsfree(icache); 544 545 list = newlinklist(); 546 zsfree(cline_str((ainfo->count ? ainfo->line : fainfo->line), 547 2, NULL, list)); 548 if (empty(list)) 549 icache = ztrdup(""); 550 else 551 icache = build_pos_string(list); 552 } 553 } else if (mnum != unambig_mnum || !ainfo || !scache) { 554 zsfree(scache); 555 scache = ztrdup(""); 556 zsfree(pcache); 557 pcache = ztrdup(""); 558 zsfree(icache); 559 icache = ztrdup(""); 560 ccache = 0; 561 } 562 unambig_mnum = mnum; 563 if (cp) 564 *cp = ccache + 1; 565 if (pp) 566 *pp = pcache; 567 if (ip) 568 *ip = icache; 569 return scache; 570} 571 572/* Insert the given match. This returns the number of bytes inserted. 573 * scs is used to return the position where a automatically created suffix 574 * has to be inserted. */ 575 576/**/ 577static int 578instmatch(Cmatch m, int *scs) 579{ 580 int l, r = 0, ocs, a = zlemetacs, brb = 0, bradd, *brpos; 581 Brinfo bp; 582 583 METACHECK(); 584 585 zsfree(lastprebr); 586 zsfree(lastpostbr); 587 lastprebr = lastpostbr = NULL; 588 589 /* Ignored prefix. */ 590 if (m->ipre) { 591 char *p = m->ipre + (menuacc ? m->qipl : 0); 592 593 inststrlen(p, 1, (l = strlen(p))); 594 r += l; 595 } 596 /* -P prefix. */ 597 if (m->pre) { 598 inststrlen(m->pre, 1, (l = strlen(m->pre))); 599 r += l; 600 } 601 /* Path prefix. */ 602 if (m->ppre) { 603 inststrlen(m->ppre, 1, (l = strlen(m->ppre))); 604 r += l; 605 } 606 /* The string itself. */ 607 inststrlen(m->str, 1, (l = strlen(m->str))); 608 r += l; 609 ocs = zlemetacs; 610 /* Re-insert the brace beginnings, if any. */ 611 if (brbeg) { 612 int pcs = zlemetacs; 613 614 l = 0; 615 for (bp = brbeg, brpos = m->brpl, 616 bradd = (m->pre ? strlen(m->pre) : 0); 617 bp; bp = bp->next, brpos++) { 618 zlemetacs = a + *brpos + bradd; 619 pcs = zlemetacs; 620 l = strlen(bp->str); 621 bradd += l; 622 brpcs = zlemetacs; 623 inststrlen(bp->str, 1, l); 624 r += l; 625 ocs += l; 626 } 627 lastprebr = (char *) zalloc(pcs - a + 1); 628 memcpy(lastprebr, zlemetaline + a, pcs - a); 629 lastprebr[pcs - a] = '\0'; 630 zlemetacs = ocs; 631 } 632 /* Path suffix. */ 633 if (m->psuf) { 634 inststrlen(m->psuf, 1, (l = strlen(m->psuf))); 635 r += l; 636 } 637 /* Re-insert the brace end. */ 638 if (brend) { 639 a = zlemetacs; 640 for (bp = brend, brpos = m->brsl, bradd = 0; bp; bp = bp->next, brpos++) { 641 zlemetacs = a - *brpos; 642 ocs = brscs = zlemetacs; 643 l = strlen(bp->str); 644 bradd += l; 645 inststrlen(bp->str, 1, l); 646 brb = zlemetacs; 647 r += l; 648 } 649 zlemetacs = a + bradd; 650 if (scs) 651 *scs = ocs; 652 } else { 653 brscs = -1; 654 655 if (scs) 656 *scs = zlemetacs; 657 } 658 /* -S suffix */ 659 if (m->suf) { 660 inststrlen(m->suf, 1, (l = strlen(m->suf))); 661 r += l; 662 } 663 /* ignored suffix */ 664 if (m->isuf) { 665 inststrlen(m->isuf, 1, (l = strlen(m->isuf))); 666 r += l; 667 } 668 if (brend) { 669 lastpostbr = (char *) zalloc(zlemetacs - brb + 1); 670 memcpy(lastpostbr, zlemetaline + brb, zlemetacs - brb); 671 lastpostbr[zlemetacs - brb] = '\0'; 672 } 673 lastend = zlemetacs; 674 zlemetacs = ocs; 675 676 return r; 677} 678 679/* Check if the match has the given prefix/suffix before/after the 680 * braces. */ 681 682/**/ 683mod_export int 684hasbrpsfx(Cmatch m, char *pre, char *suf) 685{ 686 int was_meta; 687 688 if (m->flags & CMF_ALL) 689 return 1; 690 691 /* May not be metafied if calculating whether to show a list. */ 692 if (zlemetaline == NULL) { 693 was_meta = 0; 694 metafy_line(); 695 } else 696 was_meta = 1; 697 698 { 699 char *op = lastprebr, *os = lastpostbr; 700 VARARR(char, oline, zlemetall); 701 int oll = zlemetall, newll, ole = lastend; 702 int opcs = brpcs, oscs = brscs, ret; 703 704 zle_save_positions(); 705 memcpy(oline, zlemetaline, zlemetall); 706 707 lastprebr = lastpostbr = NULL; 708 709 instmatch(m, NULL); 710 711 zlemetacs = 0; 712 foredel(zlemetall, CUT_RAW); 713 spaceinline(oll); 714 memcpy(zlemetaline, oline, oll); 715 /* we do not want to restore zlemetall */ 716 newll = zlemetall; 717 zle_restore_positions(); 718 zlemetall = newll; 719 lastend = ole; 720 brpcs = opcs; 721 brscs = oscs; 722 723 ret = (((!pre && !lastprebr) || 724 (pre && lastprebr && !strcmp(pre, lastprebr))) && 725 ((!suf && !lastpostbr) || 726 (suf && lastpostbr && !strcmp(suf, lastpostbr)))); 727 728 zsfree(lastprebr); 729 zsfree(lastpostbr); 730 lastprebr = op; 731 lastpostbr = os; 732 733 if (!was_meta) 734 unmetafy_line(); 735 return ret; 736 } 737} 738 739/* Handle the case were we found more than one match. */ 740 741/**/ 742int 743do_ambiguous(void) 744{ 745 int ret = 0; 746 747 menucmp = menuacc = 0; 748 749 /* If we have to insert the first match, call do_single(). This is * 750 * how REC_EXACT takes effect. We effectively turn the ambiguous * 751 * completion into an unambiguous one. */ 752 if (ainfo && ainfo->exact == 1 && !(fromcomp & FC_LINE)) { 753 minfo.cur = NULL; 754 do_single(ainfo->exactm); 755 invalidatelist(); 756 return ret; 757 } 758 /* Setting lastambig here means that the completion is ambiguous and * 759 * AUTO_MENU might want to start a menu completion next time round, * 760 * but this might be overridden below if we can complete an * 761 * unambiguous prefix. */ 762 lastambig = 1; 763 764 if (iforcemenu != -1 && 765 (usemenu || (haspattern && comppatinsert && 766 !strcmp(comppatinsert, "menu")))) { 767 /* We are in a position to start using menu completion due to one * 768 * of the menu completion options, or due to the menu-complete- * 769 * word command, or due to using GLOB_COMPLETE which does menu- * 770 * style completion regardless of the setting of the normal menu * 771 * completion options. */ 772 do_ambig_menu(); 773 } else if (ainfo) { 774 int atend = (zlemetacs == we), la, eq, tcs; 775 VARARR(char, old, we - wb); 776 777 minfo.cur = NULL; 778 minfo.asked = 0; 779 780 fixsuffix(); 781 782 /* First remove the old string from the line. */ 783 tcs = zlemetacs; 784 zlemetacs = wb; 785 memcpy(old, zlemetaline + wb, we - wb); 786 foredel(we - wb, CUT_RAW); 787 788 /* Now get the unambiguous string and insert it into the line. */ 789 cline_str(ainfo->line, 1, NULL, NULL); 790 791 /* Sometimes the different match specs used may result in a cline 792 * that gives an empty string. If that happened, we re-insert the 793 * old string. Unless there were matches added with -U, that is. */ 794 795 if (lastend < we && !lenchanged && !hasunmatched) { 796 zlemetacs = wb; 797 foredel(lastend - wb, CUT_RAW); 798 inststrlen(old, 0, we - wb); 799 lastend = we; 800 zlemetacs = tcs; 801 } 802 if (eparq) { 803 tcs = zlemetacs; 804 zlemetacs = lastend; 805 for (eq = eparq; eq; eq--) 806 inststrlen("\"", 0, 1); 807 zlemetacs = tcs; 808 } 809 /* la is non-zero if listambiguous may be used. Copying and 810 * comparing the line looks like BFI but it is the easiest 811 * solution. Really. */ 812 la = (zlemetall != origll || strncmp(origline, zlemetaline, zlemetall)); 813 814 /* If REC_EXACT and AUTO_MENU are set and what we inserted is an * 815 * exact match, we want menu completion the next time round * 816 * so we set fromcomp, to ensure that the word on the line is not * 817 * taken as an exact match. Also we remember if we just moved the * 818 * cursor into the word. */ 819 fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) | 820 ((atend && zlemetacs != lastend) ? FC_INWORD : 0)); 821 822 /* Probably move the cursor to the end. */ 823 if (movetoend == 3) 824 zlemetacs = lastend; 825 826 /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only * 827 * if the completion is completely ambiguous') is set, and some * 828 * prefix was inserted, return now, bypassing the list-displaying * 829 * code. On the way, invalidate the list and note that we don't * 830 * want to enter an AUTO_MENU imediately. */ 831 if ((uselist == 3 || 832 (!uselist && isset(BASHAUTOLIST) && isset(LISTAMBIGUOUS))) && 833 la && iforcemenu != -1) { 834 int fc = fromcomp; 835 836 invalidatelist(); 837 fromcomp = fc; 838 lastambig = 0; 839 clearlist = 1; 840 return ret; 841 } 842 } else 843 return ret; 844 845 /* At this point, we might want a completion listing. Show the listing * 846 * if it is needed. */ 847 if (isset(LISTBEEP) && !oldlist) 848 ret = 1; 849 850 if (uselist && (usemenu != 2 || (!listshown && !oldlist)) && 851 ((!showinglist && (!listshown || !oldlist)) || 852 (usemenu == 3 && !oldlist)) && 853 (smatches >= 2 || forcelist)) 854 showinglist = -2; 855 856 return ret; 857} 858 859/* This is a stat that ignores backslashes in the filename. The `ls' * 860 * parameter says if we have to do lstat() or stat(). I think this * 861 * should instead be done by use of a general function to expand a * 862 * filename (stripping backslashes), combined with the actual * 863 * (l)stat(). * 864 * Make sure input is unmetafied */ 865 866/**/ 867mod_export int 868ztat(char *nam, struct stat *buf, int ls) 869{ 870 int ret; 871 872 nam = unmeta(nam); 873 if (!nam) 874 return -1; 875 876 if ((ret = ls ? lstat(nam, buf) : stat(nam, buf))) { 877 char *p, *q; 878 879 for (p = q = nam; *q; q++) 880 if (*q == '\\' && q[1]) 881 *p++ = *++q; 882 else 883 *p++ = *q; 884 *p = '\0'; 885 886 ret = ls ? lstat(nam, buf) : stat(nam, buf); 887 } 888 889 return ret; 890} 891 892/* Insert all matches in the command line. */ 893 894/**/ 895void 896do_allmatches(UNUSED(int end)) 897{ 898 int first = 1, nm = nmatches - 1, omc = menucmp, oma = menuacc, e; 899 Cmatch *mc; 900 struct menuinfo mi; 901 char *p = (brbeg ? ztrdup(lastbrbeg->str) : NULL); 902 903 memcpy(&mi, &minfo, sizeof(struct menuinfo)); 904 menucmp = 1; 905 menuacc = 0; 906 907 for (minfo.group = amatches; 908 minfo.group && !(minfo.group)->mcount; 909 minfo.group = (minfo.group)->next) { 910#ifdef ZSH_HEAP_DEBUG 911 if (memory_validate(minfo.group->heap_id)) { 912 HEAP_ERROR(minfo.group->heap_id); 913 } 914#endif 915 } 916 917 918 mc = (minfo.group)->matches; 919 920 while (1) { 921 if (!((*mc)->flags & CMF_ALL)) { 922 if (!first) 923 accept_last(); 924 first = 0; 925 926 if (!omc && !--nm) 927 menucmp = 0; 928 929 do_single(*mc); 930 } 931 minfo.cur = mc; 932 933 if (!*++(minfo.cur)) { 934 do { 935 if (!(minfo.group = (minfo.group)->next)) 936 break; 937 } while (!(minfo.group)->mcount); 938 if (!minfo.group) 939 break; 940 minfo.cur = minfo.group->matches; 941 } 942 mc = minfo.cur; 943 } 944 menucmp = omc; 945 menuacc = oma; 946 947 e = minfo.end; 948 memcpy(&minfo, &mi, sizeof(struct menuinfo)); 949 minfo.end = e; 950 minfo.len = e - minfo.pos; 951 952 if (p) { 953 zsfree(lastbrbeg->str); 954 lastbrbeg->str = p; 955 } 956} 957 958/* Insert a single match in the command line. */ 959 960/**/ 961mod_export void 962do_single(Cmatch m) 963{ 964 int l, sr = 0, scs; 965 int havesuff = 0; 966 int partest = (m->ripre || ((m->flags & CMF_ISPAR) && parpre)); 967 char *str = m->orig, *ppre = m->ppre, *psuf = m->psuf, *prpre = m->prpre; 968 969 if (!prpre) prpre = ""; 970 if (!ppre) ppre = ""; 971 if (!psuf) psuf = ""; 972 973 fixsuffix(); 974 975 if (!minfo.cur) { 976 /* We are currently not in a menu-completion, * 977 * so set the position variables. */ 978 minfo.pos = wb; 979 minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp) || 980 (!movetoend && zlemetacs == we)); 981 minfo.end = we; 982 } 983 /* If we are already in a menu-completion or if we have done a * 984 * glob completion, we have to delete some of the stuff on the * 985 * command line. */ 986 if (minfo.cur) 987 l = minfo.len + minfo.insc; 988 else 989 l = we - wb; 990 991 minfo.insc = 0; 992 zlemetacs = minfo.pos; 993 foredel(l, CUT_RAW); 994 995 if (m->flags & CMF_ALL) { 996 do_allmatches(0); 997 return; 998 } 999 1000 /* And then we insert the new string. */ 1001 minfo.len = instmatch(m, &scs); 1002 minfo.end = zlemetacs; 1003 zlemetacs = minfo.pos + minfo.len; 1004 1005 if (m->suf) { 1006 havesuff = 1; 1007 /* 1008 * This strlen(0 got converted to a ztrlen(), but I don't 1009 * think that's correct since it's dealing with raw bytes, 1010 * right? 1011 */ 1012 minfo.insc = strlen(m->suf); 1013 minfo.len -= minfo.insc; 1014 if (minfo.we) { 1015 minfo.end += minfo.insc; 1016 if (m->flags & CMF_REMOVE) { 1017 /* 1018 * Here we need the number of characters, not 1019 * bytes in the string. 1020 */ 1021 int len; 1022 ZLE_STRING_T wsuf = 1023 stringaszleline(m->suf, 0, &len, NULL, NULL); 1024 makesuffixstr(m->remf, m->rems, len); 1025 if (len == 1) 1026 addsuffix(SUFTYP_POSSTR, 0, wsuf, 1, 1); 1027 free(wsuf); 1028 } 1029 } 1030 } else { 1031 /* There is no user-specified suffix, * 1032 * so generate one automagically. */ 1033 zlemetacs = scs; 1034 if (partest && (m->flags & CMF_PARBR)) { 1035 int pq; 1036 1037 /*{{*/ 1038 /* Completing a parameter in braces. Add a removable `}' suffix. */ 1039 zlemetacs += eparq; 1040 for (pq = parq; pq; pq--) 1041 inststrlen("\"", 1, 1); 1042 minfo.insc += parq; 1043 inststrlen("}", 1, 1); 1044 minfo.insc++; 1045 if (minfo.we) 1046 minfo.end += minfo.insc; 1047 if (m->flags & CMF_PARNEST) 1048 havesuff = 1; 1049 } 1050 if (((m->flags & CMF_FILE) || (partest && isset(AUTOPARAMSLASH))) && 1051 zlemetacs > 0 && zlemetaline[zlemetacs - 1] != '/') { 1052 /* If we have a filename or we completed a parameter name * 1053 * and AUTO_PARAM_SLASH is set, lets see if it is a directory. * 1054 * If it is, we append a slash. */ 1055 struct stat buf; 1056 char *p; 1057 int t = 0; 1058 1059 if (m->ipre && m->ipre[0] == '~' && !m->ipre[1]) 1060 t = 1; 1061 else { 1062 /* Build the path name. */ 1063 if (partest && !*psuf && !(m->flags & CMF_PARNEST)) { 1064 int ne = noerrs, tryit = 1; 1065 1066 p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ? 1067 parpre : m->ripre) + 1068 strlen(str) + 2); 1069 sprintf(p, "%s%s%c", 1070 ((m->flags & CMF_ISPAR) ? parpre : m->ripre), str, 1071 ((m->flags & CMF_PARBR) ? '}' : '\0')); 1072 if (*p == '$') { 1073 char *n; 1074 Param pm; 1075 1076 if (p[1] == '{') { 1077 char *e; 1078 1079 n = dupstring(p + 2); 1080 e = n + strlen(n) - 1; 1081 1082 if (*e == '}') 1083 *e = '\0'; 1084 } else 1085 n = p + 1; 1086 1087 if ((pm = (Param) paramtab->getnode(paramtab, n)) && 1088 PM_TYPE(pm->node.flags) != PM_SCALAR) 1089 tryit = 0; 1090 } 1091 if (tryit) { 1092 noerrs = 1; 1093 parsestr(p); 1094 singsub(&p); 1095 errflag = 0; 1096 noerrs = ne; 1097 } 1098 } else { 1099 p = (char *) zhalloc(strlen(prpre) + strlen(str) + 1100 strlen(psuf) + 3); 1101 sprintf(p, "%s%s%s", ((prpre && *prpre) ? 1102 prpre : "./"), str, psuf); 1103 } 1104 /* And do the stat. */ 1105 t = (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode)); 1106 } 1107 if (t) { 1108 /* It is a directory, so add the slash. */ 1109 havesuff = 1; 1110 inststrlen("/", 1, 1); 1111 minfo.insc++; 1112 if (minfo.we) 1113 minfo.end++; 1114 if (!menucmp || minfo.we) { 1115 if (m->remf || m->rems) 1116 makesuffixstr(m->remf, m->rems, 1); 1117 else if (isset(AUTOREMOVESLASH)) { 1118 makesuffix(1); 1119 addsuffix(SUFTYP_POSSTR, 0, ZWS("/"), 1, 1); 1120 } 1121 } 1122 } 1123 } 1124 if (!minfo.insc) 1125 zlemetacs = minfo.pos + minfo.len - m->qisl; 1126 } 1127 /* If completing in a brace expansion... */ 1128 if (brbeg) { 1129 if (havesuff) { 1130 /*{{*/ 1131 /* If a suffix was added, and is removable, let * 1132 * `,' and `}' remove it. */ 1133 if (isset(AUTOPARAMKEYS)) 1134 addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, suffixnoinslen); 1135 } else if (!menucmp) { 1136 /*{{*/ 1137 /* Otherwise, add a `,' suffix, and let `}' remove it. */ 1138 zlemetacs = scs; 1139 havesuff = 1; 1140 inststrlen(",", 1, 1); 1141 minfo.insc++; 1142 makesuffix(1); 1143 if ((!menucmp || minfo.we) && isset(AUTOPARAMKEYS)) 1144 addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, 1); 1145 } 1146 } else if (!havesuff && (!(m->flags & CMF_FILE) || !sr)) { 1147 /* If we didn't add a suffix, add a space, unless we are * 1148 * doing menu completion or we are completing files and * 1149 * the string doesn't name an existing file. */ 1150 if (m->autoq && (!m->isuf || !strpfx(m->autoq, m->isuf))) { 1151 int al = strlen(m->autoq); 1152 inststrlen(m->autoq, 1, al); 1153 minfo.insc += al; 1154 } 1155 if (!menucmp && !(m->flags & CMF_NOSPACE) && 1156 (usemenu != 3 || insspace)) { 1157 inststrlen(" ", 1, 1); 1158 minfo.insc++; 1159 if (minfo.we) 1160 makesuffixstr(m->remf, m->rems, 1); 1161 } 1162 } 1163 if (minfo.we && partest && isset(AUTOPARAMKEYS) && minfo.insc - parq > 0) { 1164 /* the suffix code needs numbers of characters, not octets */ 1165 int outlen; 1166 char *tmpstr = dupstrpfx(zlemetaline + parq, minfo.insc - parq); 1167 ZLE_STRING_T subline = stringaszleline(tmpstr, 0, &outlen, NULL, NULL); 1168 makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), outlen); 1169 free(subline); 1170 } 1171 1172 if ((menucmp && !minfo.we) || !movetoend) { 1173 zlemetacs = minfo.end; 1174 if (zlemetacs + m->qisl == lastend) 1175 zlemetacs += minfo.insc; 1176 } 1177 { 1178 Cmatch *om = minfo.cur; 1179 struct chdata dat; 1180 1181 dat.matches = amatches; 1182#ifdef ZSH_HEAP_DEBUG 1183 if (memory_validate(dat.matches->heap_id)) { 1184 HEAP_ERROR(dat.matches->heap_id); 1185 } 1186#endif 1187 dat.num = nmatches; 1188 dat.cur = m; 1189 1190 if (menucmp) 1191 minfo.cur = &m; 1192 runhookdef(INSERTMATCHHOOK, (void *) &dat); 1193 minfo.cur = om; 1194 } 1195} 1196 1197/* Do completion, given that we are in the middle of a menu completion. We * 1198 * don't need to generate a list of matches, because that's already been * 1199 * done by previous commands. We will either list the completions, or * 1200 * insert the next completion. */ 1201 1202/**/ 1203mod_export void 1204do_menucmp(int lst) 1205{ 1206 int was_meta; 1207 1208 /* Just list the matches if the list was requested. */ 1209 if (lst == COMP_LIST_COMPLETE) { 1210 showinglist = -2; 1211 return; 1212 } 1213 1214 /* Already metafied when called from domenuselect already */ 1215 if (zlemetaline == NULL) { 1216 was_meta = 0; 1217 metafy_line(); 1218 } else 1219 was_meta = 1; 1220 1221 /* Otherwise go to the next match in the array... */ 1222 do { 1223 if (!*++(minfo.cur)) { 1224 do { 1225 if (!(minfo.group = (minfo.group)->next)) { 1226 minfo.group = amatches; 1227#ifdef ZSH_HEAP_DEBUG 1228 if (memory_validate(minfo.group->heap_id)) { 1229 HEAP_ERROR(minfo.group->heap_id); 1230 } 1231#endif 1232 } 1233 } while (!(minfo.group)->mcount); 1234 minfo.cur = minfo.group->matches; 1235 } 1236 } while ((menuacc && 1237 !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) || 1238 ((*minfo.cur)->flags & CMF_DUMMY) || 1239 (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) && 1240 (!(*minfo.cur)->str || !*(*minfo.cur)->str))); 1241 /* ... and insert it into the command line. */ 1242 do_single(*minfo.cur); 1243 1244 if (!was_meta) 1245 unmetafy_line(); 1246} 1247 1248/**/ 1249int 1250reverse_menu(UNUSED(Hookdef dummy), UNUSED(void *dummy2)) 1251{ 1252 int was_meta; 1253 1254 if (minfo.cur == NULL) 1255 return 1; 1256 1257 do { 1258 if (minfo.cur == (minfo.group)->matches) { 1259 do { 1260 if (!(minfo.group = (minfo.group)->prev)) 1261 minfo.group = lmatches; 1262 } while (!(minfo.group)->mcount); 1263 minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1; 1264 } else 1265 minfo.cur--; 1266 } while ((menuacc && 1267 !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) || 1268 ((*minfo.cur)->flags & CMF_DUMMY) || 1269 (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) && 1270 (!(*minfo.cur)->str || !*(*minfo.cur)->str))); 1271 /* May already be metafied if called from within a selection */ 1272 if (zlemetaline == NULL) { 1273 metafy_line(); 1274 was_meta = 0; 1275 } 1276 else 1277 was_meta = 1; 1278 do_single(*(minfo.cur)); 1279 if (!was_meta) 1280 unmetafy_line(); 1281 1282 return 0; 1283} 1284 1285/* Accepts the current completion and starts a new arg, * 1286 * with the next completions. This gives you a way to * 1287 * accept several selections from the list of matches. */ 1288 1289/**/ 1290mod_export int 1291accept_last(void) 1292{ 1293 /* give up trying to work out what state it should be in */ 1294 int wasmeta; 1295 if (zlemetaline != NULL) { 1296 wasmeta = 1; 1297 } else { 1298 wasmeta = 0; 1299 metafy_line(); 1300 } 1301 1302 if (!menuacc) { 1303 zsfree(minfo.prebr); 1304 minfo.prebr = ztrdup(lastprebr); 1305 zsfree(minfo.postbr); 1306 minfo.postbr = ztrdup(lastpostbr); 1307 1308 if (listshown && (lastprebr || lastpostbr)) { 1309 Cmgroup g; 1310 Cmatch *m; 1311 1312 for (g = amatches, m = NULL; g && (!m || !*m); g = g->next) { 1313#ifdef ZSH_HEAP_DEBUG 1314 if (memory_validate(g->heap_id)) { 1315 HEAP_ERROR(g->heap_id); 1316 } 1317#endif 1318 for (m = g->matches; *m; m++) 1319 if (!hasbrpsfx(*m, minfo.prebr, minfo.postbr)) { 1320 showinglist = -2; 1321 break; 1322 } 1323 } 1324 } 1325 } 1326 menuacc++; 1327 1328 if (brbeg) { 1329 int l; 1330 1331 iremovesuffix(',', 1); 1332 1333 l = (brscs >= 0 ? brscs : zlemetacs) - brpcs; 1334 1335 zsfree(lastbrbeg->str); 1336 lastbrbeg->str = (char *) zalloc(l + 2); 1337 memcpy(lastbrbeg->str, zlemetaline + brpcs, l); 1338 lastbrbeg->str[l] = ','; 1339 lastbrbeg->str[l + 1] = '\0'; 1340 } else { 1341 int l; 1342 1343 zlemetacs = minfo.pos + minfo.len + minfo.insc; 1344 iremovesuffix(' ', 1); 1345 l = zlemetacs; 1346 zlemetacs = minfo.pos + minfo.len + minfo.insc - (*(minfo.cur))->qisl; 1347 if (zlemetacs < l) 1348 foredel(l - zlemetacs, CUT_RAW); 1349 else if (zlemetacs > zlemetall) 1350 zlemetacs = zlemetall; 1351 inststrlen(" ", 1, 1); 1352 minfo.insc = minfo.len = 0; 1353 minfo.pos = zlemetacs; 1354 minfo.we = 1; 1355 } 1356 1357 if (!wasmeta) 1358 unmetafy_line(); 1359 return 0; 1360} 1361 1362/* This maps the value in v into the range [0,m-1], decrementing v 1363 * if it is non-negative and making negative values count backwards. */ 1364 1365/**/ 1366static int 1367comp_mod(int v, int m) 1368{ 1369 if (v >= 0) 1370 v--; 1371 if (v >= 0) 1372 return v % m; 1373 else { 1374 while (v < 0) 1375 v += m; 1376 return v; 1377 } 1378} 1379 1380/* This handles the beginning of menu-completion. */ 1381 1382/**/ 1383void 1384do_ambig_menu(void) 1385{ 1386 Cmatch *mc; 1387 1388 if (iforcemenu == -1) 1389 do_ambiguous(); 1390 1391 if (usemenu != 3) { 1392 menucmp = 1; 1393 menuacc = 0; 1394 minfo.cur = NULL; 1395 } else { 1396 if (oldlist) { 1397 if (oldins && minfo.cur) 1398 accept_last(); 1399 } else 1400 minfo.cur = NULL; 1401 } 1402#if 0 1403 /* group-numbers in compstate[insert] */ 1404 if (insgroup) { 1405 insgnum = comp_mod(insgnum, lastpermgnum); 1406 for (minfo.group = amatches; 1407 minfo.group && (minfo.group)->num != insgnum + 1; 1408 minfo.group = (minfo.group)->next) { 1409#ifdef ZSH_HEAP_DEBUG 1410 if (memory_validate(minfo.group->heap_id)) { 1411 HEAP_ERROR(minfo.group->heap_id); 1412 } 1413#endif 1414 } 1415 if (!minfo.group || !(minfo.group)->mcount) { 1416 minfo.cur = NULL; 1417 minfo.asked = 0; 1418 return; 1419 } 1420 insmnum = comp_mod(insmnum, (minfo.group)->mcount); 1421 } else { 1422#endif 1423 insmnum = comp_mod(insmnum, lastpermmnum); 1424 for (minfo.group = amatches; 1425 minfo.group && (minfo.group)->mcount <= insmnum; 1426 minfo.group = (minfo.group)->next) { 1427 insmnum -= (minfo.group)->mcount; 1428#ifdef ZSH_HEAP_DEBUG 1429 if (memory_validate(minfo.group->heap_id)) { 1430 HEAP_ERROR(minfo.group->heap_id); 1431 } 1432#endif 1433 } 1434 if (!minfo.group) { 1435 minfo.cur = NULL; 1436 minfo.asked = 0; 1437 return; 1438 } 1439#if 0 1440 /* group-numbers in compstate[insert] */ 1441 } 1442#endif 1443 mc = (minfo.group)->matches + insmnum; 1444 if (iforcemenu != -1) 1445 do_single(*mc); 1446 minfo.cur = mc; 1447} 1448 1449/* Return the number of screen lines needed for the list. */ 1450 1451/**/ 1452zlong 1453list_lines(void) 1454{ 1455 Cmgroup oam; 1456 1457 permmatches(0); 1458 1459 oam = amatches; 1460 amatches = pmatches; 1461 listdat.valid = 0; 1462 calclist(0); 1463 listdat.valid = 0; 1464 amatches = oam; 1465 1466 return listdat.nlines; 1467} 1468 1469/**/ 1470void 1471comp_list(char *v) 1472{ 1473 zsfree(complist); 1474 complist = v; 1475 1476 onlyexpl = (v ? ((strstr(v, "expl") ? 1 : 0) | 1477 (strstr(v, "messages") ? 2 : 0)) : 0); 1478} 1479 1480/* This skips over matches that are not to be listed. */ 1481 1482/**/ 1483mod_export Cmatch * 1484skipnolist(Cmatch *p, int showall) 1485{ 1486 int mask = (showall ? 0 : (CMF_NOLIST | CMF_MULT)) | CMF_HIDE; 1487 1488 while (*p && (((*p)->flags & mask) || 1489 ((*p)->disp && 1490 ((*p)->flags & (CMF_DISPLINE | CMF_HIDE))))) 1491 p++; 1492 1493 return p; 1494} 1495 1496/**/ 1497mod_export int 1498calclist(int showall) 1499{ 1500 static int lastinvcount = -1; 1501 1502 Cmgroup g; 1503 Cmatch *p, m; 1504 Cexpl *e; 1505 int hidden = 0, nlist = 0, nlines = 0; 1506 int max = 0, i; 1507 VARARR(int, mlens, nmatches + 1); 1508 1509 if (lastinvcount == invcount && 1510 listdat.valid && onlyexpl == listdat.onlyexpl && 1511 menuacc == listdat.menuacc && showall == listdat.showall && 1512 zterm_lines == listdat.zterm_lines && 1513 zterm_columns == listdat.zterm_columns) 1514 return 0; 1515 lastinvcount = invcount; 1516 1517 for (g = amatches; g; g = g->next) { 1518 char **pp = g->ylist; 1519 int nl = 0, l, glong = 1, gshort = zterm_columns, ndisp = 0, totl = 0; 1520 int hasf = 0; 1521 1522#ifdef ZSH_HEAP_DEBUG 1523 if (memory_validate(g->heap_id)) { 1524 HEAP_ERROR(g->heap_id); 1525 } 1526#endif 1527 g->flags |= CGF_PACKED | CGF_ROWS; 1528 1529 if (!onlyexpl && pp) { 1530 if (*pp) { 1531 if (!isset(LISTPACKED)) 1532 g->flags &= ~CGF_PACKED; 1533 if (!isset(LISTROWSFIRST)) 1534 g->flags &= ~CGF_ROWS; 1535 } 1536 1537 /* We have an ylist, lets see, if it contains newlines. */ 1538 hidden = 1; 1539 while (!nl && *pp) { 1540 if (MB_METASTRWIDTH(*pp) >= zterm_columns) 1541 nl = 1; 1542 else 1543 nl = !!strchr(*pp++, '\n'); 1544 } 1545 pp = g->ylist; 1546 if (nl || !pp[1]) { 1547 /* Yup, there are newlines, count lines. */ 1548 char *nlptr, *sptr; 1549 1550 g->flags |= CGF_LINES; 1551 hidden = 1; 1552 while ((sptr = *pp)) { 1553 while (*sptr) { 1554 if ((nlptr = strchr(sptr, '\n'))) { 1555 *nlptr = '\0'; 1556 nlines += 1 + (MB_METASTRWIDTH(sptr)-1) / 1557 zterm_columns; 1558 *nlptr = '\n'; 1559 sptr = nlptr + 1; 1560 } else { 1561 nlines += (MB_METASTRWIDTH(sptr)-1) / zterm_columns; 1562 break; 1563 } 1564 } 1565 nlines++; 1566 pp++; 1567 } 1568 /*** nlines--; */ 1569 } else { 1570 while (*pp) { 1571 l = MB_METASTRWIDTH(*pp); 1572 ndisp++; 1573 if (l > glong) 1574 glong = l; 1575 if (l < gshort) 1576 gshort = l; 1577 totl += l; 1578 nlist++; 1579 pp++; 1580 } 1581 } 1582 } else if (!onlyexpl) { 1583 for (p = g->matches; (m = *p); p++) { 1584 if (m->flags & CMF_FILE) 1585 hasf = 1; 1586 if (menuacc && !hasbrpsfx(m, minfo.prebr, minfo.postbr)) { 1587 m->flags |= CMF_HIDE; 1588 continue; 1589 } 1590 m->flags &= ~CMF_HIDE; 1591 1592 if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) { 1593 if ((m->flags & (CMF_NOLIST | CMF_MULT)) && 1594 (!m->str || !*m->str)) { 1595 m->flags |= CMF_HIDE; 1596 continue; 1597 } 1598 if (m->disp) { 1599 if (m->flags & CMF_DISPLINE) { 1600 nlines += 1 + printfmt(m->disp, 0, 0, 0); 1601 g->flags |= CGF_HASDL; 1602 } else { 1603 l = ZMB_nicewidth(m->disp); 1604 ndisp++; 1605 if (l > glong) 1606 glong = l; 1607 if (l < gshort) 1608 gshort = l; 1609 totl += l; 1610 mlens[m->gnum] = l; 1611 } 1612 nlist++; 1613 if (!(m->flags & CMF_PACKED)) 1614 g->flags &= ~CGF_PACKED; 1615 if (!(m->flags & CMF_ROWS)) 1616 g->flags &= ~CGF_ROWS; 1617 } else { 1618 l = ZMB_nicewidth(m->str) + !!m->modec; 1619 ndisp++; 1620 if (l > glong) 1621 glong = l; 1622 if (l < gshort) 1623 gshort = l; 1624 totl += l; 1625 mlens[m->gnum] = l; 1626 nlist++; 1627 if (!(m->flags & CMF_PACKED)) 1628 g->flags &= ~CGF_PACKED; 1629 if (!(m->flags & CMF_ROWS)) 1630 g->flags &= ~CGF_ROWS; 1631 } 1632 } else 1633 hidden = 1; 1634 } 1635 } 1636 if ((e = g->expls)) { 1637 while (*e) { 1638 if (((*e)->count || (*e)->always) && 1639 (!onlyexpl || 1640 (onlyexpl & ((*e)->always > 0 ? 2 : 1)))) 1641 nlines += 1 + printfmt((*e)->str, 1642 ((*e)->always ? -1 : (*e)->count), 1643 0, 1); 1644 e++; 1645 } 1646 } 1647 if (isset(LISTTYPES) && hasf) 1648 g->flags |= CGF_FILES; 1649 g->totl = totl + (ndisp * CM_SPACE); 1650 g->dcount = ndisp; 1651 g->width = glong + CM_SPACE; 1652 g->shortest = gshort + CM_SPACE; 1653 if ((g->cols = zterm_columns / g->width) > g->dcount) 1654 g->cols = g->dcount; 1655 if (g->cols) { 1656 i = g->cols * g->width - CM_SPACE; 1657 if (i > max) 1658 max = i; 1659 } 1660 } 1661 if (!onlyexpl) { 1662 char **pp; 1663 int *ws, tlines, tcols, width, glines; 1664 1665 for (g = amatches; g; g = g->next) { 1666 glines = 0; 1667 1668#ifdef ZSH_HEAP_DEBUG 1669 if (memory_validate(g->heap_id)) { 1670 HEAP_ERROR(g->heap_id); 1671 } 1672#endif 1673 zfree(g->widths, 0); 1674 g->widths = NULL; 1675 1676 if ((pp = g->ylist)) { 1677 if (!(g->flags & CGF_LINES)) { 1678 if (g->cols) { 1679 glines += (arrlen(pp) + g->cols - 1) / g->cols; 1680 if (g->cols > 1) 1681 g->width += ((max - (g->width * g->cols - 1682 CM_SPACE)) / 1683 g->cols); 1684 } else { 1685 g->cols = 1; 1686 g->width = 1; 1687 1688 while (*pp) 1689 glines += 1 + (MB_METASTRWIDTH(*pp++) / 1690 zterm_columns); 1691 } 1692 } 1693 } else { 1694 if (g->cols) { 1695 glines += (g->dcount + g->cols - 1) / g->cols; 1696 if (g->cols > 1) 1697 g->width += ((max - (g->width * g->cols - CM_SPACE)) / 1698 g->cols); 1699 } else if (!(g->flags & CGF_LINES)) { 1700 g->cols = 1; 1701 g->width = 0; 1702 1703 for (p = g->matches; (m = *p); p++) 1704 if (!(m->flags & CMF_HIDE)) { 1705 if (m->disp) { 1706 if (!(m->flags & CMF_DISPLINE)) 1707 glines += 1 + ((mlens[m->gnum] - 1) / 1708 zterm_columns); 1709 } else if (showall || 1710 !(m->flags & (CMF_NOLIST | CMF_MULT))) 1711 glines += 1 + (((mlens[m->gnum]) - 1) / 1712 zterm_columns); 1713 } 1714 } 1715 } 1716 g->lins = glines; 1717 nlines += glines; 1718 } 1719 for (g = amatches; g; g = g->next) { 1720 if (!(g->flags & CGF_PACKED)) 1721 continue; 1722 1723 ws = g->widths = (int *) zalloc(zterm_columns * sizeof(int)); 1724 memset(ws, 0, zterm_columns * sizeof(int)); 1725 tlines = g->lins; 1726 tcols = g->cols; 1727 width = 0; 1728 1729 if ((pp = g->ylist)) { 1730 if (!(g->flags & CGF_LINES)) { 1731 int yl = arrlen(pp), i; 1732 VARARR(int, ylens, yl); 1733 1734 for (i = 0; *pp; i++, pp++) 1735 ylens[i] = MB_METASTRWIDTH(*pp) + CM_SPACE; 1736 1737 if (g->flags & CGF_ROWS) { 1738 int nth, tcol, len; 1739 1740 for (tcols = zterm_columns / (g->shortest + CM_SPACE); 1741 tcols > g->cols; 1742 tcols--) { 1743 1744 memset(ws, 0, tcols * sizeof(int)); 1745 1746 for (width = nth = tcol = 0, tlines = 1; 1747 width < zterm_columns && nth < g->dcount; 1748 nth++, tcol++) { 1749 1750 m = *p; 1751 1752 if (tcol == tcols) { 1753 tcol = 0; 1754 tlines++; 1755 } 1756 len = ylens[nth]; 1757 1758 if (len > ws[tcol]) { 1759 width += len - ws[tcol]; 1760 ws[tcol] = len; 1761 } 1762 } 1763 if (width < zterm_columns) 1764 break; 1765 } 1766 } else { 1767 int nth, tcol, tline, len; 1768 1769 for (tcols = zterm_columns / (g->shortest + CM_SPACE); 1770 tcols > g->cols; 1771 tcols--) { 1772 1773 if ((tlines = (g->dcount + tcols - 1) / tcols) <= 0) 1774 tlines = 1; 1775 1776 memset(ws, 0, tcols * sizeof(int)); 1777 1778 for (width = nth = tcol = tline = 0; 1779 width < zterm_columns && nth < g->dcount; 1780 nth++, tline++) { 1781 1782 m = *p; 1783 1784 if (tline == tlines) { 1785 tcol++; 1786 tline = 0; 1787 } 1788 if (tcol == tcols) { 1789 tcol = 0; 1790 tlines++; 1791 } 1792 len = ylens[nth]; 1793 1794 if (len > ws[tcol]) { 1795 width += len - ws[tcol]; 1796 ws[tcol] = len; 1797 } 1798 } 1799 if (width < zterm_columns) 1800 break; 1801 } 1802 } 1803 } 1804 } else if (g->width) { 1805 if (g->flags & CGF_ROWS) { 1806 int nth, tcol, len; 1807 1808 for (tcols = zterm_columns / (g->shortest + CM_SPACE); 1809 tcols > g->cols; 1810 tcols--) { 1811 1812 memset(ws, 0, tcols * sizeof(int)); 1813 1814 for (width = nth = tcol = 0, tlines = 1, 1815 p = skipnolist(g->matches, showall); 1816 *p && width < zterm_columns && nth < g->dcount; 1817 nth++, p = skipnolist(p + 1, showall), tcol++) { 1818 1819 m = *p; 1820 1821 if (tcol == tcols) { 1822 tcol = 0; 1823 tlines++; 1824 } 1825 len = (mlens[m->gnum] + 1826 (tcol == tcols - 1 ? 0 : CM_SPACE)); 1827 1828 if (len > ws[tcol]) { 1829 width += len - ws[tcol]; 1830 ws[tcol] = len; 1831 } 1832 } 1833 if (width < zterm_columns) 1834 break; 1835 } 1836 } else { 1837 int nth, tcol, tline, len; 1838 1839 for (tcols = zterm_columns / (g->shortest + CM_SPACE); 1840 tcols > g->cols; 1841 tcols--) { 1842 1843 if ((tlines = (g->dcount + tcols - 1) / tcols) <= 0) 1844 tlines = 1; 1845 1846 memset(ws, 0, tcols * sizeof(int)); 1847 1848 for (width = nth = tcol = tline = 0, 1849 p = skipnolist(g->matches, showall); 1850 *p && width < zterm_columns && nth < g->dcount; 1851 nth++, p = skipnolist(p + 1, showall), tline++) { 1852 1853 m = *p; 1854 1855 if (tline == tlines) { 1856 tcol++; 1857 tline = 0; 1858 } 1859 if (tcol == tcols) { 1860 tcol = 0; 1861 tlines++; 1862 } 1863 len = (mlens[m->gnum] + 1864 (tcol == tcols - 1 ? 0 : CM_SPACE)); 1865 1866 if (len > ws[tcol]) { 1867 width += len - ws[tcol]; 1868 ws[tcol] = len; 1869 } 1870 } 1871 if (width < zterm_columns) { 1872 if (++tcol < tcols) 1873 tcols = tcol; 1874 break; 1875 } 1876 } 1877 } 1878 } 1879 if (tcols <= g->cols) 1880 tlines = g->lins; 1881 if (tlines == g->lins) { 1882 zfree(ws, zterm_columns * sizeof(int)); 1883 g->widths = NULL; 1884 } else { 1885 nlines += tlines - g->lins; 1886 g->lins = tlines; 1887 g->cols = tcols; 1888 g->totl = width; 1889 width -= CM_SPACE; 1890 if (width > max) 1891 max = width; 1892 } 1893 } 1894 for (g = amatches; g; g = g->next) { 1895 if (g->widths) { 1896 int *p, a = (max - g->totl + CM_SPACE) / g->cols; 1897 1898 for (i = g->cols, p = g->widths; i; i--, p++) 1899 *p += a; 1900 } else if (g->width && g->cols > 1) 1901 g->width += (max - (g->width * g->cols - CM_SPACE)) / g->cols; 1902 } 1903 } 1904 else 1905 for (g = amatches; g; g = g->next) 1906 { 1907#ifdef ZSH_HEAP_DEBUG 1908 if (memory_validate(g->heap_id)) { 1909 HEAP_ERROR(g->heap_id); 1910 } 1911#endif 1912 zfree(g->widths, 0); 1913 g->widths = NULL; 1914 } 1915 listdat.valid = 1; 1916 listdat.hidden = hidden; 1917 listdat.nlist = nlist; 1918 listdat.nlines = nlines; 1919 listdat.menuacc = menuacc; 1920 listdat.onlyexpl = onlyexpl; 1921 listdat.zterm_columns = zterm_columns; 1922 listdat.zterm_lines = zterm_lines; 1923 listdat.showall = showall; 1924 1925 return 1; 1926} 1927 1928/**/ 1929mod_export int 1930asklist(void) 1931{ 1932 /* Set the cursor below the prompt. */ 1933 trashzle(); 1934 showinglist = listshown = 0; 1935 1936 clearflag = (isset(USEZLE) && !termflags && dolastprompt); 1937 lastlistlen = 0; 1938 1939 /* Maybe we have to ask if the user wants to see the list. */ 1940 if ((!minfo.cur || !minfo.asked) && 1941 ((complistmax > 0 && listdat.nlist >= complistmax) || 1942 (complistmax < 0 && listdat.nlines <= -complistmax) || 1943 (!complistmax && listdat.nlines >= zterm_lines))) { 1944 int qup, l; 1945 1946 zsetterm(); 1947 l = (listdat.nlist > 0 ? 1948 fprintf(shout, "zsh: do you wish to see all %d possibilities (%d lines)? ", 1949 listdat.nlist, listdat.nlines) : 1950 fprintf(shout, "zsh: do you wish to see all %d lines? ", 1951 listdat.nlines)); 1952 qup = ((l + zterm_columns - 1) / zterm_columns) - 1; 1953 fflush(shout); 1954 if (!getzlequery()) { 1955 if (clearflag) { 1956 putc('\r', shout); 1957 tcmultout(TCUP, TCMULTUP, qup); 1958 if (tccan(TCCLEAREOD)) 1959 tcout(TCCLEAREOD); 1960 tcmultout(TCUP, TCMULTUP, nlnct); 1961 } else 1962 putc('\n', shout); 1963 minfo.asked = 2; 1964 return 1; 1965 } 1966 if (clearflag) { 1967 putc('\r', shout); 1968 tcmultout(TCUP, TCMULTUP, qup); 1969 if (tccan(TCCLEAREOD)) 1970 tcout(TCCLEAREOD); 1971 } else 1972 putc('\n', shout); 1973 settyinfo(&shttyinfo); 1974 minfo.asked = 1; 1975 } else if (minfo.asked == 2) 1976 tcmultout(TCUP, TCMULTUP, nlnct); 1977 1978 return (minfo.asked ? minfo.asked - 1 : 0); 1979} 1980 1981/**/ 1982mod_export int 1983printlist(int over, CLPrintFunc printm, int showall) 1984{ 1985 Cmgroup g; 1986 Cmatch *p, m; 1987 Cexpl *e; 1988 int pnl = 0, cl = (over ? listdat.nlines : -1); 1989 int mc = 0, ml = 0, printed = 0; 1990 1991 if (cl < 2) { 1992 cl = -1; 1993 if (tccan(TCCLEAREOD)) 1994 tcout(TCCLEAREOD); 1995 } 1996 for (g = amatches; g; g = g->next) { 1997 char **pp = g->ylist; 1998 1999#ifdef ZSH_HEAP_DEBUG 2000 if (memory_validate(g->heap_id)) { 2001 HEAP_ERROR(g->heap_id); 2002 } 2003#endif 2004 if ((e = g->expls)) { 2005 int l; 2006 2007 while (*e) { 2008 if (((*e)->count || (*e)->always) && 2009 (!listdat.onlyexpl || 2010 (listdat.onlyexpl & ((*e)->always > 0 ? 2 : 1)))) { 2011 if (pnl) { 2012 putc('\n', shout); 2013 pnl = 0; 2014 ml++; 2015 if (cl >= 0 && --cl <= 1) { 2016 cl = -1; 2017 if (tccan(TCCLEAREOD)) 2018 tcout(TCCLEAREOD); 2019 } 2020 } 2021 l = printfmt((*e)->str, 2022 ((*e)->always ? -1 : (*e)->count), 1, 1); 2023 ml += l; 2024 if (cl >= 0 && (cl -= l) <= 1) { 2025 cl = -1; 2026 if (tccan(TCCLEAREOD)) 2027 tcout(TCCLEAREOD); 2028 } 2029 pnl = 1; 2030 } 2031 e++; 2032 } 2033 } 2034 if (!listdat.onlyexpl && pp && *pp) { 2035 if (pnl) { 2036 putc('\n', shout); 2037 pnl = 0; 2038 ml++; 2039 if (cl >= 0 && --cl <= 1) { 2040 cl = -1; 2041 if (tccan(TCCLEAREOD)) 2042 tcout(TCCLEAREOD); 2043 } 2044 } 2045 if (g->flags & CGF_LINES) { 2046 char *p; 2047 2048 while ((p = *pp++)) { 2049 zputs(p, shout); 2050 if (*pp) { 2051 if (MB_METASTRWIDTH(p) % zterm_columns) 2052 putc('\n', shout); 2053 else 2054 fputs(" \010", shout); 2055 } 2056 } 2057 } else { 2058 int n = g->lcount, nl, nc, i, a; 2059 char **pq; 2060 2061 nl = nc = g->lins; 2062 2063 while (n && nl--) { 2064 i = g->cols; 2065 mc = 0; 2066 pq = pp; 2067 while (n && i--) { 2068 if (pq - g->ylist >= g->lcount) 2069 break; 2070 zputs(*pq, shout); 2071 if (i) { 2072 a = (g->widths ? g->widths[mc] : g->width) - 2073 MB_METASTRWIDTH(*pq); 2074 while (a--) 2075 putc(' ', shout); 2076 } 2077 pq += ((g->flags & CGF_ROWS) ? 1 : nc); 2078 mc++; 2079 n--; 2080 } 2081 if (n) { 2082 putc('\n', shout); 2083 ml++; 2084 if (cl >= 0 && --cl <= 1) { 2085 cl = -1; 2086 if (tccan(TCCLEAREOD)) 2087 tcout(TCCLEAREOD); 2088 } 2089 } 2090 pp += ((g->flags & CGF_ROWS) ? g->cols : 1); 2091 } 2092 } 2093 } else if (!listdat.onlyexpl && 2094 (g->lcount || (showall && g->mcount))) { 2095 int n = g->dcount, nl, nc, i, j, wid; 2096 Cmatch *q; 2097 2098 nl = nc = g->lins; 2099 2100 if (g->flags & CGF_HASDL) { 2101 for (p = g->matches; (m = *p); p++) 2102 if (m->disp && (m->flags & CMF_DISPLINE) && 2103 (showall || !(m->flags & (CMF_HIDE|CMF_NOLIST)))) { 2104 if (pnl) { 2105 putc('\n', shout); 2106 pnl = 0; 2107 ml++; 2108 if (cl >= 0 && --cl <= 1) { 2109 cl = -1; 2110 if (tccan(TCCLEAREOD)) 2111 tcout(TCCLEAREOD); 2112 } 2113 } 2114 printed++; 2115 printm(g, p, 0, ml, 1, 0); 2116 pnl = 1; 2117 } 2118 } 2119 if (n && pnl) { 2120 putc('\n', shout); 2121 pnl = 0; 2122 ml++; 2123 if (cl >= 0 && --cl <= 1) { 2124 cl = -1; 2125 if (tccan(TCCLEAREOD)) 2126 tcout(TCCLEAREOD); 2127 } 2128 } 2129 for (p = skipnolist(g->matches, showall); n && nl--;) { 2130 i = g->cols; 2131 mc = 0; 2132 q = p; 2133 while (n && i--) { 2134 wid = (g->widths ? g->widths[mc] : g->width); 2135 if (!(m = *q)) { 2136 printm(g, NULL, mc, ml, (!i), wid); 2137 break; 2138 } 2139 printm(g, q, mc, ml, (!i), wid); 2140 2141 printed++; 2142 2143 if (--n) 2144 for (j = ((g->flags & CGF_ROWS) ? 1 : nc); 2145 j && *q; j--) 2146 q = skipnolist(q + 1, showall); 2147 mc++; 2148 } 2149 while (i-- > 0) { 2150 printm(g, NULL, mc, ml, (!i), 2151 (g->widths ? g->widths[mc] : g->width)); 2152 mc++; 2153 } 2154 if (n) { 2155 putc('\n', shout); 2156 ml++; 2157 if (cl >= 0 && --cl <= 1) { 2158 cl = -1; 2159 if (tccan(TCCLEAREOD)) 2160 tcout(TCCLEAREOD); 2161 } 2162 if (nl) 2163 for (j = ((g->flags & CGF_ROWS) ? g->cols : 1); 2164 j && *p; j--) 2165 p = skipnolist(p + 1, showall); 2166 } 2167 } 2168 } else 2169 continue; 2170 if (g->lcount || (showall && g->mcount)) 2171 pnl = 1; 2172 } 2173 lastlistlen = 0; 2174 if (clearflag) { 2175 /* Move the cursor up to the prompt, if always_last_prompt * 2176 * is set and all that... */ 2177 if ((ml = listdat.nlines + nlnct - 1) < zterm_lines) { 2178 tcmultout(TCUP, TCMULTUP, ml); 2179 showinglist = -1; 2180 2181 lastlistlen = listdat.nlines; 2182 } else 2183 clearflag = 0, putc('\n', shout); 2184 } else 2185 putc('\n', shout); 2186 2187 listshown = (clearflag ? 1 : -1); 2188 2189 return printed; 2190} 2191 2192/**/ 2193mod_export void 2194bld_all_str(Cmatch all) 2195{ 2196 Cmgroup g; 2197 Cmatch *mp, m; 2198 int len = zterm_columns - 5, t, add = 0; 2199 VARARR(char, buf, zterm_columns + 1); 2200 2201 buf[0] = '\0'; 2202 2203 for (g = amatches; g && !g->mcount; g = g->next) { 2204#ifdef ZSH_HEAP_DEBUG 2205 if (memory_validate(g->heap_id)) { 2206 HEAP_ERROR(g->heap_id); 2207 } 2208#endif 2209 } 2210 2211 mp = g->matches; 2212 while (1) { 2213 m = *mp; 2214 if (!(m->flags & (CMF_ALL | CMF_HIDE)) && m->str) { 2215 t = strlen(m->str) + add; 2216 if (len >= t) { 2217 if (add) 2218 strcat(buf, " "); 2219 strcat(buf, m->str); 2220 len -= t; 2221 add = 1; 2222 } else { 2223 if (len > add + 2) { 2224 if (add) 2225 strcat(buf, " "); 2226 strncat(buf, m->str, len); 2227 } 2228 strcat(buf, "..."); 2229 break; 2230 } 2231 } 2232 if (!*++mp) { 2233 do { 2234 if (!(g = g->next)) 2235 break; 2236 } while (!g->mcount); 2237 if (!g) 2238 break; 2239 mp = g->matches; 2240 } 2241 } 2242 zsfree(all->disp); 2243 all->disp = ztrdup(buf); 2244} 2245 2246/**/ 2247static void 2248iprintm(Cmgroup g, Cmatch *mp, UNUSED(int mc), UNUSED(int ml), int lastc, int width) 2249{ 2250 Cmatch m; 2251 int len = 0; 2252 2253 if (!mp) 2254 return; 2255 2256 m = *mp; 2257 if ((m->flags & CMF_ALL) && (!m->disp || !m->disp[0])) 2258 bld_all_str(m); 2259 if (m->disp) { 2260 if (m->flags & CMF_DISPLINE) { 2261 printfmt(m->disp, 0, 1, 0); 2262 return; 2263 } 2264#ifdef MULTIBYTE_SUPPORT 2265 len = mb_niceformat(m->disp, shout, NULL, 0); 2266#else 2267 nicezputs(m->disp, shout); 2268 len = niceztrlen(m->disp); 2269#endif 2270 } else { 2271#ifdef MULTIBYTE_SUPPORT 2272 len = mb_niceformat(m->str, shout, NULL, 0); 2273#else 2274 nicezputs(m->str, shout); 2275 len = niceztrlen(m->str); 2276#endif 2277 2278 if ((g->flags & CGF_FILES) && m->modec) { 2279 putc(m->modec, shout); 2280 len++; 2281 } 2282 } 2283 if (!lastc) { 2284 len = width - len; 2285 2286 while (len-- > 0) 2287 putc(' ', shout); 2288 } 2289} 2290 2291/**/ 2292int 2293ilistmatches(UNUSED(Hookdef dummy), UNUSED(Chdata dat)) 2294{ 2295 calclist(0); 2296 2297 if (!listdat.nlines) { 2298 showinglist = listshown = 0; 2299 return 1; 2300 } 2301 if (asklist()) 2302 return 0; 2303 2304 printlist(0, iprintm, 0); 2305 2306 return 0; 2307} 2308 2309/* List the matches. Note that the list entries are metafied. */ 2310 2311/**/ 2312int 2313list_matches(UNUSED(Hookdef dummy), UNUSED(void *dummy2)) 2314{ 2315 struct chdata dat; 2316 int ret; 2317 2318#ifdef DEBUG 2319 /* Sanity check */ 2320 if (!validlist) { 2321 showmsg("BUG: listmatches called with bogus list"); 2322 return 1; 2323 } 2324#endif 2325 2326 dat.matches = amatches; 2327#ifdef ZSH_HEAP_DEBUG 2328 if (memory_validate(dat.matches->heap_id)) { 2329 HEAP_ERROR(dat.matches->heap_id); 2330 } 2331#endif 2332 dat.num = nmatches; 2333 dat.cur = NULL; 2334 ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat); 2335 2336 return ret; 2337} 2338 2339/* Invalidate the completion list. */ 2340 2341/**/ 2342mod_export int 2343invalidate_list(void) 2344{ 2345 invcount++; 2346 if (validlist) { 2347 if (showinglist == -2) { 2348 zrefresh(); 2349 } 2350 freematches(lastmatches, 1); 2351 lastmatches = NULL; 2352 hasoldlist = 0; 2353 } 2354 lastambig = menucmp = menuacc = validlist = showinglist = fromcomp = 0; 2355 listdat.valid = 0; 2356 if (listshown < 0) 2357 listshown = 0; 2358 minfo.cur = NULL; 2359 minfo.asked = 0; 2360 zsfree(minfo.prebr); 2361 zsfree(minfo.postbr); 2362 minfo.postbr = minfo.prebr = NULL; 2363 compwidget = NULL; 2364 nmatches = 0; 2365 amatches = NULL; 2366 2367 return 0; 2368} 2369