26763: fix problem on failed cd -s to relative path
[zsh.git] / Src / Zle / compresult.c
blobe595802dd648bf5e8b4ada26049523301e197050
1 /*
2 * compresult.c - the complete module, completion result handling
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1999 Sven Wischnowsky
7 * All rights reserved.
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.
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.
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.
30 #include "complete.mdh"
31 #include "compresult.pro"
33 /* This counts how often the list of completions was invalidated.
34 * Can be used to detect if we have a new list. */
36 /**/
37 mod_export int invcount;
39 #define inststr(X) inststrlen((X),1,-1)
41 /* This cuts the cline list before the stuff that isn't worth
42 * inserting in the line. */
44 /**/
45 static Cline
46 cut_cline(Cline l)
48 Cline q, p, e = NULL, maxp = NULL;
49 int sum = 0, max = 0, tmp, ls = 0, miss = 0;
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). */
57 if (!hasmatched) {
58 cline_setlens(l, 0);
59 return l;
61 e = l = cp_cline(l, 0);
63 /* First, search the last struct for which we have something on
64 * the line. Anything before that is kept. */
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;
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;
78 /* Then keep all structs without missing characters. */
80 while (e && !(e->flags & CLF_MISS))
81 e = e->next;
83 if (e) {
84 /* Then we see if there is another struct with missing
85 * characters. If not, we keep the whole list. */
87 for (p = e->next; p && !(p->flags & CLF_MISS); p = p->next);
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);
100 if (sum > max) {
101 max = sum;
102 maxp = p;
105 if (max)
106 e = maxp;
107 else {
108 int len = 0;
110 cline_setlens(l, 0);
111 ls = 1;
113 for (p = e; p; p = p->next)
114 len += p->min;
116 if (len > ((minmlen << 1) / 3))
117 goto end;
119 e->line = e->word = NULL;
120 e->llen = e->wlen = e->olen = 0;
121 e->next = NULL;
124 end:
126 /* Sanity check. If there are no parts with missing characters but
127 * parts with joined substrings, remove those. */
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;
138 for (q = p->suffix; q; q = q->next)
139 if (q->flags & CLF_JOIN) {
140 e = p;
141 tmp = 1;
142 break;
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;
151 if (!ls)
152 cline_setlens(l, 0);
154 return l;
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). */
163 /**/
164 static char *
165 cline_str(Cline l, int ins, int *csp, LinkList posl)
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;
173 METACHECK();
175 l = cut_cline(l);
177 pmm = pma = smm = sma = dm = pcs = scs = 0;
178 pm = pmax = sm = smax = d = mid = cbr = -1;
179 brp = brs = NULL;
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;
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);
193 if ((brs = lastbrend)) {
194 for (bp = brend; bp; bp = bp->next)
195 olen -= strlen(bp->str);
197 for (bp = brend; bp; bp = bp->next)
198 bp->curpos = olen - (hasunqu ? bp->pos : bp->qpos);
200 while (brp && !brp->curpos) {
201 inststrlen(brp->str, 1, -1);
202 brp = brp->next;
204 while (brs && !brs->curpos) {
205 if (cbr < 0)
206 cbr = zlemetacs;
207 inststrlen(brs->str, 1, -1);
208 brs = brs->prev;
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;
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));
234 li += s->llen;
237 if (ins) {
238 int ocs, bl;
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;
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));
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));
265 if (ins) {
266 int ocs, bl;
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;
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;
290 li += l->llen;
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;
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));
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));
320 if (ins) {
321 int ocs, bl;
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;
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;
342 li += l->olen;
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;
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;
365 } else {
366 Cline js = NULL;
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;
379 if (ins) {
380 int ocs, bl;
382 li += s->llen;
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;
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;
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));
416 l = l->next;
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));
426 if (ins) {
427 int ocs = zlemetacs;
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);
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;
445 if (posl) {
446 LinkNode node;
447 long p;
449 for (node = firstnode(posl); node; incnode(node)) {
450 p = (long) getdata(node);
451 if (p >= ocs)
452 setdata(node, (void *) (p + zlemetacs - ocs));
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)))));
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);
469 memcpy(r, zlemetaline + ocs, i);
470 r[i] = '\0';
471 zlemetacs = ocs;
472 foredel(i, CUT_RAW);
474 if (csp)
475 *csp = ncs - ocs;
477 return r;
479 lastend = zlemetacs;
480 zlemetacs = ncs;
482 return NULL;
485 /* Small utility function turning a list of positions into a colon
486 * separated string. */
488 static char *
489 build_pos_string(LinkList list)
491 LinkNode node;
492 int l;
493 char buf[40], *s;
494 long p;
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);
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, ":");
517 return s;
520 /* This is a utility function using the function above to allow access
521 * to the unambiguous string and cursor position via compstate. */
523 /**/
524 char *
525 unambig_data(int *cp, char **pp, char **ip)
527 static char *scache = NULL, *pcache = NULL, *icache = NULL;
528 static int ccache;
530 if (mnum && ainfo) {
531 if (mnum != unambig_mnum) {
532 LinkList list = newlinklist();
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);
543 zsfree(icache);
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);
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;
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;
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. */
576 /**/
577 static int
578 instmatch(Cmatch m, int *scs)
580 int l, r = 0, ocs, a = zlemetacs, brb = 0, bradd, *brpos;
581 Brinfo bp;
583 METACHECK();
585 zsfree(lastprebr);
586 zsfree(lastpostbr);
587 lastprebr = lastpostbr = NULL;
589 /* Ignored prefix. */
590 if (m->ipre) {
591 char *p = m->ipre + (menuacc ? m->qipl : 0);
593 inststrlen(p, 1, (l = strlen(p)));
594 r += l;
596 /* -P prefix. */
597 if (m->pre) {
598 inststrlen(m->pre, 1, (l = strlen(m->pre)));
599 r += l;
601 /* Path prefix. */
602 if (m->ppre) {
603 inststrlen(m->ppre, 1, (l = strlen(m->ppre)));
604 r += l;
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;
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;
627 lastprebr = (char *) zalloc(pcs - a + 1);
628 memcpy(lastprebr, zlemetaline + a, pcs - a);
629 lastprebr[pcs - a] = '\0';
630 zlemetacs = ocs;
632 /* Path suffix. */
633 if (m->psuf) {
634 inststrlen(m->psuf, 1, (l = strlen(m->psuf)));
635 r += l;
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;
649 zlemetacs = a + bradd;
650 if (scs)
651 *scs = ocs;
652 } else {
653 brscs = -1;
655 if (scs)
656 *scs = zlemetacs;
658 /* -S suffix */
659 if (m->suf) {
660 inststrlen(m->suf, 1, (l = strlen(m->suf)));
661 r += l;
663 /* ignored suffix */
664 if (m->isuf) {
665 inststrlen(m->isuf, 1, (l = strlen(m->isuf)));
666 r += l;
668 if (brend) {
669 lastpostbr = (char *) zalloc(zlemetacs - brb + 1);
670 memcpy(lastpostbr, zlemetaline + brb, zlemetacs - brb);
671 lastpostbr[zlemetacs - brb] = '\0';
673 lastend = zlemetacs;
674 zlemetacs = ocs;
676 return r;
679 /* Check if the match has the given prefix/suffix before/after the
680 * braces. */
682 /**/
683 mod_export int
684 hasbrpsfx(Cmatch m, char *pre, char *suf)
686 int was_meta;
688 if (m->flags & CMF_ALL)
689 return 1;
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;
699 char *op = lastprebr, *os = lastpostbr;
700 VARARR(char, oline, zlemetall);
701 int oll = zlemetall, ocs = zlemetacs, ole = lastend, opcs = brpcs, oscs = brscs, ret;
703 memcpy(oline, zlemetaline, zlemetall);
705 lastprebr = lastpostbr = NULL;
707 instmatch(m, NULL);
709 zlemetacs = 0;
710 foredel(zlemetall, CUT_RAW);
711 spaceinline(oll);
712 memcpy(zlemetaline, oline, oll);
713 zlemetacs = ocs;
714 lastend = ole;
715 brpcs = opcs;
716 brscs = oscs;
718 ret = (((!pre && !lastprebr) ||
719 (pre && lastprebr && !strcmp(pre, lastprebr))) &&
720 ((!suf && !lastpostbr) ||
721 (suf && lastpostbr && !strcmp(suf, lastpostbr))));
723 zsfree(lastprebr);
724 zsfree(lastpostbr);
725 lastprebr = op;
726 lastpostbr = os;
728 if (!was_meta)
729 unmetafy_line();
730 return ret;
734 /* Handle the case were we found more than one match. */
736 /**/
738 do_ambiguous(void)
740 int ret = 0;
742 menucmp = menuacc = 0;
744 /* If we have to insert the first match, call do_single(). This is *
745 * how REC_EXACT takes effect. We effectively turn the ambiguous *
746 * completion into an unambiguous one. */
747 if (ainfo && ainfo->exact == 1 && !(fromcomp & FC_LINE)) {
748 minfo.cur = NULL;
749 do_single(ainfo->exactm);
750 invalidatelist();
751 return ret;
753 /* Setting lastambig here means that the completion is ambiguous and *
754 * AUTO_MENU might want to start a menu completion next time round, *
755 * but this might be overridden below if we can complete an *
756 * unambiguous prefix. */
757 lastambig = 1;
759 if (iforcemenu != -1 &&
760 (usemenu || (haspattern && comppatinsert &&
761 !strcmp(comppatinsert, "menu")))) {
762 /* We are in a position to start using menu completion due to one *
763 * of the menu completion options, or due to the menu-complete- *
764 * word command, or due to using GLOB_COMPLETE which does menu- *
765 * style completion regardless of the setting of the normal menu *
766 * completion options. */
767 do_ambig_menu();
768 } else if (ainfo) {
769 int atend = (zlemetacs == we), la, eq, tcs;
770 VARARR(char, old, we - wb);
772 minfo.cur = NULL;
773 minfo.asked = 0;
775 fixsuffix();
777 /* First remove the old string from the line. */
778 tcs = zlemetacs;
779 zlemetacs = wb;
780 memcpy(old, zlemetaline + wb, we - wb);
781 foredel(we - wb, CUT_RAW);
783 /* Now get the unambiguous string and insert it into the line. */
784 cline_str(ainfo->line, 1, NULL, NULL);
786 /* Sometimes the different match specs used may result in a cline
787 * that gives an empty string. If that happened, we re-insert the
788 * old string. Unless there were matches added with -U, that is. */
790 if (lastend < we && !lenchanged && !hasunmatched) {
791 zlemetacs = wb;
792 foredel(lastend - wb, CUT_RAW);
793 inststrlen(old, 0, we - wb);
794 lastend = we;
795 zlemetacs = tcs;
797 if (eparq) {
798 tcs = zlemetacs;
799 zlemetacs = lastend;
800 for (eq = eparq; eq; eq--)
801 inststrlen("\"", 0, 1);
802 zlemetacs = tcs;
804 /* la is non-zero if listambiguous may be used. Copying and
805 * comparing the line looks like BFI but it is the easiest
806 * solution. Really. */
807 la = (zlemetall != origll || strncmp(origline, zlemetaline, zlemetall));
809 /* If REC_EXACT and AUTO_MENU are set and what we inserted is an *
810 * exact match, we want menu completion the next time round *
811 * so we set fromcomp, to ensure that the word on the line is not *
812 * taken as an exact match. Also we remember if we just moved the *
813 * cursor into the word. */
814 fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) |
815 ((atend && zlemetacs != lastend) ? FC_INWORD : 0));
817 /* Probably move the cursor to the end. */
818 if (movetoend == 3)
819 zlemetacs = lastend;
821 /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
822 * if the completion is completely ambiguous') is set, and some *
823 * prefix was inserted, return now, bypassing the list-displaying *
824 * code. On the way, invalidate the list and note that we don't *
825 * want to enter an AUTO_MENU imediately. */
826 if ((uselist == 3 ||
827 (!uselist && isset(BASHAUTOLIST) && isset(LISTAMBIGUOUS))) &&
828 la && iforcemenu != -1) {
829 int fc = fromcomp;
831 invalidatelist();
832 fromcomp = fc;
833 lastambig = 0;
834 clearlist = 1;
835 return ret;
837 } else
838 return ret;
840 /* At this point, we might want a completion listing. Show the listing *
841 * if it is needed. */
842 if (isset(LISTBEEP) && !oldlist)
843 ret = 1;
845 if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
846 ((!showinglist && (!listshown || !oldlist)) ||
847 (usemenu == 3 && !oldlist)) &&
848 (smatches >= 2 || forcelist))
849 showinglist = -2;
851 return ret;
854 /* This is a stat that ignores backslashes in the filename. The `ls' *
855 * parameter says if we have to do lstat() or stat(). I think this *
856 * should instead be done by use of a general function to expand a *
857 * filename (stripping backslashes), combined with the actual *
858 * (l)stat(). *
859 * Make sure input is unmetafied */
861 /**/
862 mod_export int
863 ztat(char *nam, struct stat *buf, int ls)
865 int ret;
867 nam = unmeta(nam);
868 if (!nam)
869 return -1;
871 if ((ret = ls ? lstat(nam, buf) : stat(nam, buf))) {
872 char *p, *q;
874 for (p = q = nam; *q; q++)
875 if (*q == '\\' && q[1])
876 *p++ = *++q;
877 else
878 *p++ = *q;
879 *p = '\0';
881 ret = ls ? lstat(nam, buf) : stat(nam, buf);
884 return ret;
887 /* Insert all matches in the command line. */
889 /**/
890 void
891 do_allmatches(UNUSED(int end))
893 int first = 1, nm = nmatches - 1, omc = menucmp, oma = menuacc, e;
894 Cmatch *mc;
895 struct menuinfo mi;
896 char *p = (brbeg ? ztrdup(lastbrbeg->str) : NULL);
898 memcpy(&mi, &minfo, sizeof(struct menuinfo));
899 menucmp = 1;
900 menuacc = 0;
902 for (minfo.group = amatches;
903 minfo.group && !(minfo.group)->mcount;
904 minfo.group = (minfo.group)->next);
906 mc = (minfo.group)->matches;
908 while (1) {
909 if (!((*mc)->flags & CMF_ALL)) {
910 if (!first)
911 accept_last();
912 first = 0;
914 if (!omc && !--nm)
915 menucmp = 0;
917 do_single(*mc);
919 minfo.cur = mc;
921 if (!*++(minfo.cur)) {
922 do {
923 if (!(minfo.group = (minfo.group)->next))
924 break;
925 } while (!(minfo.group)->mcount);
926 if (!minfo.group)
927 break;
928 minfo.cur = minfo.group->matches;
930 mc = minfo.cur;
932 menucmp = omc;
933 menuacc = oma;
935 e = minfo.end;
936 memcpy(&minfo, &mi, sizeof(struct menuinfo));
937 minfo.end = e;
938 minfo.len = e - minfo.pos;
940 if (p) {
941 zsfree(lastbrbeg->str);
942 lastbrbeg->str = p;
946 /* Insert a single match in the command line. */
948 /**/
949 mod_export void
950 do_single(Cmatch m)
952 int l, sr = 0, scs;
953 int havesuff = 0;
954 int partest = (m->ripre || ((m->flags & CMF_ISPAR) && parpre));
955 char *str = m->orig, *ppre = m->ppre, *psuf = m->psuf, *prpre = m->prpre;
957 if (!prpre) prpre = "";
958 if (!ppre) ppre = "";
959 if (!psuf) psuf = "";
961 fixsuffix();
963 if (!minfo.cur) {
964 /* We are currently not in a menu-completion, *
965 * so set the position variables. */
966 minfo.pos = wb;
967 minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp) ||
968 (!movetoend && zlemetacs == we));
969 minfo.end = we;
971 /* If we are already in a menu-completion or if we have done a *
972 * glob completion, we have to delete some of the stuff on the *
973 * command line. */
974 if (minfo.cur)
975 l = minfo.len + minfo.insc;
976 else
977 l = we - wb;
979 minfo.insc = 0;
980 zlemetacs = minfo.pos;
981 foredel(l, CUT_RAW);
983 if (m->flags & CMF_ALL) {
984 do_allmatches(0);
985 return;
988 /* And then we insert the new string. */
989 minfo.len = instmatch(m, &scs);
990 minfo.end = zlemetacs;
991 zlemetacs = minfo.pos + minfo.len;
993 if (m->suf) {
994 havesuff = 1;
996 * This strlen(0 got converted to a ztrlen(), but I don't
997 * think that's correct since it's dealing with raw bytes,
998 * right?
1000 minfo.insc = strlen(m->suf);
1001 minfo.len -= minfo.insc;
1002 if (minfo.we) {
1003 minfo.end += minfo.insc;
1004 if (m->flags & CMF_REMOVE) {
1006 * Here we need the number of characters, not
1007 * bytes in the string.
1009 int len;
1010 ZLE_STRING_T wsuf =
1011 stringaszleline(m->suf, 0, &len, NULL, NULL);
1012 makesuffixstr(m->remf, m->rems, len);
1013 if (len == 1)
1014 addsuffix(SUFTYP_POSSTR, wsuf, 1, 1);
1015 free(wsuf);
1018 } else {
1019 /* There is no user-specified suffix, *
1020 * so generate one automagically. */
1021 zlemetacs = scs;
1022 if (partest && (m->flags & CMF_PARBR)) {
1023 int pq;
1025 /*{{*/
1026 /* Completing a parameter in braces. Add a removable `}' suffix. */
1027 zlemetacs += eparq;
1028 for (pq = parq; pq; pq--)
1029 inststrlen("\"", 1, 1);
1030 minfo.insc += parq;
1031 inststrlen("}", 1, 1);
1032 minfo.insc++;
1033 if (minfo.we)
1034 minfo.end += minfo.insc;
1035 if (m->flags & CMF_PARNEST)
1036 havesuff = 1;
1038 if (((m->flags & CMF_FILE) || (partest && isset(AUTOPARAMSLASH))) &&
1039 zlemetacs > 0 && zlemetaline[zlemetacs - 1] != '/') {
1040 /* If we have a filename or we completed a parameter name *
1041 * and AUTO_PARAM_SLASH is set, lets see if it is a directory. *
1042 * If it is, we append a slash. */
1043 struct stat buf;
1044 char *p;
1045 int t = 0;
1047 if (m->ipre && m->ipre[0] == '~' && !m->ipre[1])
1048 t = 1;
1049 else {
1050 /* Build the path name. */
1051 if (partest && !*psuf && !(m->flags & CMF_PARNEST)) {
1052 int ne = noerrs, tryit = 1;
1054 p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ?
1055 parpre : m->ripre) +
1056 strlen(str) + 2);
1057 sprintf(p, "%s%s%c",
1058 ((m->flags & CMF_ISPAR) ? parpre : m->ripre), str,
1059 ((m->flags & CMF_PARBR) ? '}' : '\0'));
1060 if (*p == '$') {
1061 char *n;
1062 Param pm;
1064 if (p[1] == '{') {
1065 char *e;
1067 n = dupstring(p + 2);
1068 e = n + strlen(n) - 1;
1070 if (*e == '}')
1071 *e = '\0';
1072 } else
1073 n = p + 1;
1075 if ((pm = (Param) paramtab->getnode(paramtab, n)) &&
1076 PM_TYPE(pm->node.flags) != PM_SCALAR)
1077 tryit = 0;
1079 if (tryit) {
1080 noerrs = 1;
1081 parsestr(p);
1082 singsub(&p);
1083 errflag = 0;
1084 noerrs = ne;
1086 } else {
1087 p = (char *) zhalloc(strlen(prpre) + strlen(str) +
1088 strlen(psuf) + 3);
1089 sprintf(p, "%s%s%s", ((prpre && *prpre) ?
1090 prpre : "./"), str, psuf);
1092 /* And do the stat. */
1093 t = (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode));
1095 if (t) {
1096 /* It is a directory, so add the slash. */
1097 havesuff = 1;
1098 inststrlen("/", 1, 1);
1099 minfo.insc++;
1100 if (minfo.we)
1101 minfo.end++;
1102 if (!menucmp || minfo.we) {
1103 if (m->remf || m->rems)
1104 makesuffixstr(m->remf, m->rems, 1);
1105 else if (isset(AUTOREMOVESLASH)) {
1106 makesuffix(1);
1107 addsuffix(SUFTYP_POSSTR, ZWS("/"), 1, 1);
1112 if (!minfo.insc)
1113 zlemetacs = minfo.pos + minfo.len - m->qisl;
1115 /* If completing in a brace expansion... */
1116 if (brbeg) {
1117 if (havesuff) {
1118 /*{{*/
1119 /* If a suffix was added, and is removable, let *
1120 * `,' and `}' remove it. */
1121 if (isset(AUTOPARAMKEYS))
1122 addsuffix(SUFTYP_POSSTR, ZWS(",}"), 2, suffixnoinslen);
1123 } else if (!menucmp) {
1124 /*{{*/
1125 /* Otherwise, add a `,' suffix, and let `}' remove it. */
1126 zlemetacs = scs;
1127 havesuff = 1;
1128 inststrlen(",", 1, 1);
1129 minfo.insc++;
1130 makesuffix(1);
1131 if ((!menucmp || minfo.we) && isset(AUTOPARAMKEYS))
1132 addsuffix(SUFTYP_POSSTR, ZWS(",}"), 2, 1);
1134 } else if (!havesuff && (!(m->flags & CMF_FILE) || !sr)) {
1135 /* If we didn't add a suffix, add a space, unless we are *
1136 * doing menu completion or we are completing files and *
1137 * the string doesn't name an existing file. */
1138 if (m->autoq && (!m->isuf || !strpfx(m->autoq, m->isuf))) {
1139 int al = strlen(m->autoq);
1140 inststrlen(m->autoq, 1, al);
1141 minfo.insc += al;
1143 if (!menucmp && !(m->flags & CMF_NOSPACE) &&
1144 (usemenu != 3 || insspace)) {
1145 inststrlen(" ", 1, 1);
1146 minfo.insc++;
1147 if (minfo.we)
1148 makesuffixstr(m->remf, m->rems, 1);
1151 if (minfo.we && partest && isset(AUTOPARAMKEYS) && minfo.insc - parq > 0) {
1152 /* the suffix code needs numbers of characters, not octets */
1153 int outlen;
1154 char *tmpstr = dupstrpfx(zlemetaline + parq, minfo.insc - parq);
1155 ZLE_STRING_T subline = stringaszleline(tmpstr, 0, &outlen, NULL, NULL);
1156 makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), outlen);
1157 free(subline);
1160 if ((menucmp && !minfo.we) || !movetoend) {
1161 zlemetacs = minfo.end;
1162 if (zlemetacs + m->qisl == lastend)
1163 zlemetacs += minfo.insc;
1166 Cmatch *om = minfo.cur;
1167 struct chdata dat;
1169 dat.matches = amatches;
1170 dat.num = nmatches;
1171 dat.cur = m;
1173 if (menucmp)
1174 minfo.cur = &m;
1175 runhookdef(INSERTMATCHHOOK, (void *) &dat);
1176 minfo.cur = om;
1180 /* Do completion, given that we are in the middle of a menu completion. We *
1181 * don't need to generate a list of matches, because that's already been *
1182 * done by previous commands. We will either list the completions, or *
1183 * insert the next completion. */
1185 /**/
1186 mod_export void
1187 do_menucmp(int lst)
1189 int was_meta;
1191 /* Just list the matches if the list was requested. */
1192 if (lst == COMP_LIST_COMPLETE) {
1193 showinglist = -2;
1194 return;
1197 /* Already metafied when called from domenuselect already */
1198 if (zlemetaline == NULL) {
1199 was_meta = 0;
1200 metafy_line();
1201 } else
1202 was_meta = 1;
1204 /* Otherwise go to the next match in the array... */
1205 do {
1206 if (!*++(minfo.cur)) {
1207 do {
1208 if (!(minfo.group = (minfo.group)->next))
1209 minfo.group = amatches;
1210 } while (!(minfo.group)->mcount);
1211 minfo.cur = minfo.group->matches;
1213 } while ((menuacc &&
1214 !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
1215 ((*minfo.cur)->flags & CMF_DUMMY) ||
1216 (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
1217 (!(*minfo.cur)->str || !*(*minfo.cur)->str)));
1218 /* ... and insert it into the command line. */
1219 do_single(*minfo.cur);
1221 if (!was_meta)
1222 unmetafy_line();
1225 /**/
1227 reverse_menu(UNUSED(Hookdef dummy), UNUSED(void *dummy2))
1229 int was_meta;
1231 if (minfo.cur == NULL)
1232 return 1;
1234 do {
1235 if (minfo.cur == (minfo.group)->matches) {
1236 do {
1237 if (!(minfo.group = (minfo.group)->prev))
1238 minfo.group = lmatches;
1239 } while (!(minfo.group)->mcount);
1240 minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
1241 } else
1242 minfo.cur--;
1243 } while ((menuacc &&
1244 !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
1245 ((*minfo.cur)->flags & CMF_DUMMY) ||
1246 (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
1247 (!(*minfo.cur)->str || !*(*minfo.cur)->str)));
1248 /* May already be metafied if called from within a selection */
1249 if (zlemetaline == NULL) {
1250 metafy_line();
1251 was_meta = 0;
1253 else
1254 was_meta = 1;
1255 do_single(*(minfo.cur));
1256 if (!was_meta)
1257 unmetafy_line();
1259 return 0;
1262 /* Accepts the current completion and starts a new arg, *
1263 * with the next completions. This gives you a way to *
1264 * accept several selections from the list of matches. */
1266 /**/
1267 mod_export int
1268 accept_last(void)
1270 /* give up trying to work out what state it should be in */
1271 int wasmeta;
1272 if (zlemetaline != NULL) {
1273 wasmeta = 1;
1274 } else {
1275 wasmeta = 0;
1276 metafy_line();
1279 if (!menuacc) {
1280 zsfree(minfo.prebr);
1281 minfo.prebr = ztrdup(lastprebr);
1282 zsfree(minfo.postbr);
1283 minfo.postbr = ztrdup(lastpostbr);
1285 if (listshown && (lastprebr || lastpostbr)) {
1286 Cmgroup g;
1287 Cmatch *m;
1289 for (g = amatches, m = NULL; g && (!m || !*m); g = g->next)
1290 for (m = g->matches; *m; m++)
1291 if (!hasbrpsfx(*m, minfo.prebr, minfo.postbr)) {
1292 showinglist = -2;
1293 break;
1297 menuacc++;
1299 if (brbeg) {
1300 int l;
1302 iremovesuffix(',', 1);
1304 l = (brscs >= 0 ? brscs : zlemetacs) - brpcs;
1306 zsfree(lastbrbeg->str);
1307 lastbrbeg->str = (char *) zalloc(l + 2);
1308 memcpy(lastbrbeg->str, zlemetaline + brpcs, l);
1309 lastbrbeg->str[l] = ',';
1310 lastbrbeg->str[l + 1] = '\0';
1311 } else {
1312 int l;
1314 zlemetacs = minfo.pos + minfo.len + minfo.insc;
1315 iremovesuffix(' ', 1);
1316 l = zlemetacs;
1317 zlemetacs = minfo.pos + minfo.len + minfo.insc - (*(minfo.cur))->qisl;
1318 if (zlemetacs < l)
1319 foredel(l - zlemetacs, CUT_RAW);
1320 else if (zlemetacs > zlemetall)
1321 zlemetacs = zlemetall;
1322 inststrlen(" ", 1, 1);
1323 minfo.insc = minfo.len = 0;
1324 minfo.pos = zlemetacs;
1325 minfo.we = 1;
1328 if (!wasmeta)
1329 unmetafy_line();
1330 return 0;
1333 /* This maps the value in v into the range [0,m-1], decrementing v
1334 * if it is non-negative and making negative values count backwards. */
1336 /**/
1337 static int
1338 comp_mod(int v, int m)
1340 if (v >= 0)
1341 v--;
1342 if (v >= 0)
1343 return v % m;
1344 else {
1345 while (v < 0)
1346 v += m;
1347 return v;
1351 /* This handles the beginning of menu-completion. */
1353 /**/
1354 void
1355 do_ambig_menu(void)
1357 Cmatch *mc;
1359 if (iforcemenu == -1)
1360 do_ambiguous();
1362 if (usemenu != 3) {
1363 menucmp = 1;
1364 menuacc = 0;
1365 minfo.cur = NULL;
1366 } else {
1367 if (oldlist) {
1368 if (oldins && minfo.cur)
1369 accept_last();
1370 } else
1371 minfo.cur = NULL;
1373 #if 0
1374 /* group-numbers in compstate[insert] */
1375 if (insgroup) {
1376 insgnum = comp_mod(insgnum, lastpermgnum);
1377 for (minfo.group = amatches;
1378 minfo.group && (minfo.group)->num != insgnum + 1;
1379 minfo.group = (minfo.group)->next);
1380 if (!minfo.group || !(minfo.group)->mcount) {
1381 minfo.cur = NULL;
1382 minfo.asked = 0;
1383 return;
1385 insmnum = comp_mod(insmnum, (minfo.group)->mcount);
1386 } else {
1387 #endif
1388 insmnum = comp_mod(insmnum, lastpermmnum);
1389 for (minfo.group = amatches;
1390 minfo.group && (minfo.group)->mcount <= insmnum;
1391 minfo.group = (minfo.group)->next)
1392 insmnum -= (minfo.group)->mcount;
1393 if (!minfo.group) {
1394 minfo.cur = NULL;
1395 minfo.asked = 0;
1396 return;
1398 #if 0
1399 /* group-numbers in compstate[insert] */
1401 #endif
1402 mc = (minfo.group)->matches + insmnum;
1403 if (iforcemenu != -1)
1404 do_single(*mc);
1405 minfo.cur = mc;
1408 /* Return the number of screen lines needed for the list. */
1410 /**/
1411 zlong
1412 list_lines(void)
1414 Cmgroup oam;
1416 permmatches(0);
1418 oam = amatches;
1419 amatches = pmatches;
1420 listdat.valid = 0;
1421 calclist(0);
1422 listdat.valid = 0;
1423 amatches = oam;
1425 return listdat.nlines;
1428 /**/
1429 void
1430 comp_list(char *v)
1432 zsfree(complist);
1433 complist = v;
1435 onlyexpl = (v ? ((strstr(v, "expl") ? 1 : 0) |
1436 (strstr(v, "messages") ? 2 : 0)) : 0);
1439 /* This skips over matches that are not to be listed. */
1441 /**/
1442 mod_export Cmatch *
1443 skipnolist(Cmatch *p, int showall)
1445 int mask = (showall ? 0 : (CMF_NOLIST | CMF_MULT)) | CMF_HIDE;
1447 while (*p && (((*p)->flags & mask) ||
1448 ((*p)->disp &&
1449 ((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
1450 p++;
1452 return p;
1455 /**/
1456 mod_export int
1457 calclist(int showall)
1459 static int lastinvcount = -1;
1461 Cmgroup g;
1462 Cmatch *p, m;
1463 Cexpl *e;
1464 int hidden = 0, nlist = 0, nlines = 0;
1465 int max = 0, i;
1466 VARARR(int, mlens, nmatches + 1);
1468 if (lastinvcount == invcount &&
1469 listdat.valid && onlyexpl == listdat.onlyexpl &&
1470 menuacc == listdat.menuacc && showall == listdat.showall &&
1471 lines == listdat.lines && columns == listdat.columns)
1472 return 0;
1473 lastinvcount = invcount;
1475 for (g = amatches; g; g = g->next) {
1476 char **pp = g->ylist;
1477 int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
1478 int hasf = 0;
1480 g->flags |= CGF_PACKED | CGF_ROWS;
1482 if (!onlyexpl && pp) {
1483 if (*pp) {
1484 if (!isset(LISTPACKED))
1485 g->flags &= ~CGF_PACKED;
1486 if (!isset(LISTROWSFIRST))
1487 g->flags &= ~CGF_ROWS;
1490 /* We have an ylist, lets see, if it contains newlines. */
1491 hidden = 1;
1492 while (!nl && *pp) {
1493 if (MB_METASTRWIDTH(*pp) >= columns)
1494 nl = 1;
1495 else
1496 nl = !!strchr(*pp++, '\n');
1498 pp = g->ylist;
1499 if (nl || !pp[1]) {
1500 /* Yup, there are newlines, count lines. */
1501 char *nlptr, *sptr;
1503 g->flags |= CGF_LINES;
1504 hidden = 1;
1505 while ((sptr = *pp)) {
1506 while (*sptr) {
1507 if ((nlptr = strchr(sptr, '\n'))) {
1508 *nlptr = '\0';
1509 nlines += 1 + (MB_METASTRWIDTH(sptr)-1) / columns;
1510 *nlptr = '\n';
1511 sptr = nlptr + 1;
1512 } else {
1513 nlines += (MB_METASTRWIDTH(sptr)-1) / columns;
1514 break;
1517 nlines++;
1518 pp++;
1520 /*** nlines--; */
1521 } else {
1522 while (*pp) {
1523 l = MB_METASTRWIDTH(*pp);
1524 ndisp++;
1525 if (l > glong)
1526 glong = l;
1527 if (l < gshort)
1528 gshort = l;
1529 totl += l;
1530 nlist++;
1531 pp++;
1534 } else if (!onlyexpl) {
1535 for (p = g->matches; (m = *p); p++) {
1536 if (m->flags & CMF_FILE)
1537 hasf = 1;
1538 if (menuacc && !hasbrpsfx(m, minfo.prebr, minfo.postbr)) {
1539 m->flags |= CMF_HIDE;
1540 continue;
1542 m->flags &= ~CMF_HIDE;
1544 if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) {
1545 if ((m->flags & (CMF_NOLIST | CMF_MULT)) &&
1546 (!m->str || !*m->str)) {
1547 m->flags |= CMF_HIDE;
1548 continue;
1550 if (m->disp) {
1551 if (m->flags & CMF_DISPLINE) {
1552 nlines += 1 + printfmt(m->disp, 0, 0, 0);
1553 g->flags |= CGF_HASDL;
1554 } else {
1555 l = ZMB_nicewidth(m->disp);
1556 ndisp++;
1557 if (l > glong)
1558 glong = l;
1559 if (l < gshort)
1560 gshort = l;
1561 totl += l;
1562 mlens[m->gnum] = l;
1564 nlist++;
1565 if (!(m->flags & CMF_PACKED))
1566 g->flags &= ~CGF_PACKED;
1567 if (!(m->flags & CMF_ROWS))
1568 g->flags &= ~CGF_ROWS;
1569 } else {
1570 l = ZMB_nicewidth(m->str) + !!m->modec;
1571 ndisp++;
1572 if (l > glong)
1573 glong = l;
1574 if (l < gshort)
1575 gshort = l;
1576 totl += l;
1577 mlens[m->gnum] = l;
1578 nlist++;
1579 if (!(m->flags & CMF_PACKED))
1580 g->flags &= ~CGF_PACKED;
1581 if (!(m->flags & CMF_ROWS))
1582 g->flags &= ~CGF_ROWS;
1584 } else
1585 hidden = 1;
1588 if ((e = g->expls)) {
1589 while (*e) {
1590 if (((*e)->count || (*e)->always) &&
1591 (!onlyexpl ||
1592 (onlyexpl & ((*e)->always > 0 ? 2 : 1))))
1593 nlines += 1 + printfmt((*e)->str,
1594 ((*e)->always ? -1 : (*e)->count),
1595 0, 1);
1596 e++;
1599 if (isset(LISTTYPES) && hasf)
1600 g->flags |= CGF_FILES;
1601 g->totl = totl + (ndisp * CM_SPACE);
1602 g->dcount = ndisp;
1603 g->width = glong + CM_SPACE;
1604 g->shortest = gshort + CM_SPACE;
1605 if ((g->cols = columns / g->width) > g->dcount)
1606 g->cols = g->dcount;
1607 if (g->cols) {
1608 i = g->cols * g->width - CM_SPACE;
1609 if (i > max)
1610 max = i;
1613 if (!onlyexpl) {
1614 char **pp;
1615 int *ws, tlines, tcols, width, glines;
1617 for (g = amatches; g; g = g->next) {
1618 glines = 0;
1620 zfree(g->widths, 0);
1621 g->widths = NULL;
1623 if ((pp = g->ylist)) {
1624 if (!(g->flags & CGF_LINES)) {
1625 if (g->cols) {
1626 glines += (arrlen(pp) + g->cols - 1) / g->cols;
1627 if (g->cols > 1)
1628 g->width += ((max - (g->width * g->cols -
1629 CM_SPACE)) /
1630 g->cols);
1631 } else {
1632 g->cols = 1;
1633 g->width = 1;
1635 while (*pp)
1636 glines += 1 + (MB_METASTRWIDTH(*pp++) / columns);
1639 } else {
1640 if (g->cols) {
1641 glines += (g->dcount + g->cols - 1) / g->cols;
1642 if (g->cols > 1)
1643 g->width += ((max - (g->width * g->cols - CM_SPACE)) /
1644 g->cols);
1645 } else if (!(g->flags & CGF_LINES)) {
1646 g->cols = 1;
1647 g->width = 0;
1649 for (p = g->matches; (m = *p); p++)
1650 if (!(m->flags & CMF_HIDE)) {
1651 if (m->disp) {
1652 if (!(m->flags & CMF_DISPLINE))
1653 glines += 1 + ((mlens[m->gnum] - 1) / columns);
1654 } else if (showall ||
1655 !(m->flags & (CMF_NOLIST | CMF_MULT)))
1656 glines += 1 + (((mlens[m->gnum]) - 1) / columns);
1660 g->lins = glines;
1661 nlines += glines;
1663 for (g = amatches; g; g = g->next) {
1664 if (!(g->flags & CGF_PACKED))
1665 continue;
1667 ws = g->widths = (int *) zalloc(columns * sizeof(int));
1668 memset(ws, 0, columns * sizeof(int));
1669 tlines = g->lins;
1670 tcols = g->cols;
1671 width = 0;
1673 if ((pp = g->ylist)) {
1674 if (!(g->flags & CGF_LINES)) {
1675 int yl = arrlen(pp), i;
1676 VARARR(int, ylens, yl);
1678 for (i = 0; *pp; i++, pp++)
1679 ylens[i] = MB_METASTRWIDTH(*pp) + CM_SPACE;
1681 if (g->flags & CGF_ROWS) {
1682 int nth, tcol, len;
1684 for (tcols = columns / (g->shortest + CM_SPACE);
1685 tcols > g->cols;
1686 tcols--) {
1688 memset(ws, 0, tcols * sizeof(int));
1690 for (width = nth = tcol = 0, tlines = 1;
1691 width < columns && nth < g->dcount;
1692 nth++, tcol++) {
1694 m = *p;
1696 if (tcol == tcols) {
1697 tcol = 0;
1698 tlines++;
1700 len = ylens[nth];
1702 if (len > ws[tcol]) {
1703 width += len - ws[tcol];
1704 ws[tcol] = len;
1707 if (width < columns)
1708 break;
1710 } else {
1711 int nth, tcol, tline, len;
1713 for (tcols = columns / (g->shortest + CM_SPACE);
1714 tcols > g->cols;
1715 tcols--) {
1717 if ((tlines = (g->dcount + tcols - 1) / tcols) <= 0)
1718 tlines = 1;
1720 memset(ws, 0, tcols * sizeof(int));
1722 for (width = nth = tcol = tline = 0;
1723 width < columns && nth < g->dcount;
1724 nth++, tline++) {
1726 m = *p;
1728 if (tline == tlines) {
1729 tcol++;
1730 tline = 0;
1732 if (tcol == tcols) {
1733 tcol = 0;
1734 tlines++;
1736 len = ylens[nth];
1738 if (len > ws[tcol]) {
1739 width += len - ws[tcol];
1740 ws[tcol] = len;
1743 if (width < columns)
1744 break;
1748 } else if (g->width) {
1749 if (g->flags & CGF_ROWS) {
1750 int nth, tcol, len;
1752 for (tcols = columns / (g->shortest + CM_SPACE);
1753 tcols > g->cols;
1754 tcols--) {
1756 memset(ws, 0, tcols * sizeof(int));
1758 for (width = nth = tcol = 0, tlines = 1,
1759 p = skipnolist(g->matches, showall);
1760 *p && width < columns && nth < g->dcount;
1761 nth++, p = skipnolist(p + 1, showall), tcol++) {
1763 m = *p;
1765 if (tcol == tcols) {
1766 tcol = 0;
1767 tlines++;
1769 len = (mlens[m->gnum] +
1770 (tcol == tcols - 1 ? 0 : CM_SPACE));
1772 if (len > ws[tcol]) {
1773 width += len - ws[tcol];
1774 ws[tcol] = len;
1777 if (width < columns)
1778 break;
1780 } else {
1781 int nth, tcol, tline, len;
1783 for (tcols = columns / (g->shortest + CM_SPACE);
1784 tcols > g->cols;
1785 tcols--) {
1787 if ((tlines = (g->dcount + tcols - 1) / tcols) <= 0)
1788 tlines = 1;
1790 memset(ws, 0, tcols * sizeof(int));
1792 for (width = nth = tcol = tline = 0,
1793 p = skipnolist(g->matches, showall);
1794 *p && width < columns && nth < g->dcount;
1795 nth++, p = skipnolist(p + 1, showall), tline++) {
1797 m = *p;
1799 if (tline == tlines) {
1800 tcol++;
1801 tline = 0;
1803 if (tcol == tcols) {
1804 tcol = 0;
1805 tlines++;
1807 len = (mlens[m->gnum] +
1808 (tcol == tcols - 1 ? 0 : CM_SPACE));
1810 if (len > ws[tcol]) {
1811 width += len - ws[tcol];
1812 ws[tcol] = len;
1815 if (width < columns) {
1816 if (++tcol < tcols)
1817 tcols = tcol;
1818 break;
1823 if (tcols <= g->cols)
1824 tlines = g->lins;
1825 if (tlines == g->lins) {
1826 zfree(ws, columns * sizeof(int));
1827 g->widths = NULL;
1828 } else {
1829 nlines += tlines - g->lins;
1830 g->lins = tlines;
1831 g->cols = tcols;
1832 g->totl = width;
1833 width -= CM_SPACE;
1834 if (width > max)
1835 max = width;
1838 for (g = amatches; g; g = g->next) {
1839 if (g->widths) {
1840 int *p, a = (max - g->totl + CM_SPACE) / g->cols;
1842 for (i = g->cols, p = g->widths; i; i--, p++)
1843 *p += a;
1844 } else if (g->width && g->cols > 1)
1845 g->width += (max - (g->width * g->cols - CM_SPACE)) / g->cols;
1848 else
1849 for (g = amatches; g; g = g->next)
1851 zfree(g->widths, 0);
1852 g->widths = NULL;
1854 listdat.valid = 1;
1855 listdat.hidden = hidden;
1856 listdat.nlist = nlist;
1857 listdat.nlines = nlines;
1858 listdat.menuacc = menuacc;
1859 listdat.onlyexpl = onlyexpl;
1860 listdat.columns = columns;
1861 listdat.lines = lines;
1862 listdat.showall = showall;
1864 return 1;
1867 /**/
1868 mod_export int
1869 asklist(void)
1871 /* Set the cursor below the prompt. */
1872 trashzle();
1873 showinglist = listshown = 0;
1875 clearflag = (isset(USEZLE) && !termflags && dolastprompt);
1876 lastlistlen = 0;
1878 /* Maybe we have to ask if the user wants to see the list. */
1879 if ((!minfo.cur || !minfo.asked) &&
1880 ((complistmax > 0 && listdat.nlist >= complistmax) ||
1881 (complistmax < 0 && listdat.nlines <= -complistmax) ||
1882 (!complistmax && listdat.nlines >= lines))) {
1883 int qup, l;
1885 zsetterm();
1886 l = (listdat.nlist > 0 ?
1887 fprintf(shout, "zsh: do you wish to see all %d possibilities (%d lines)? ",
1888 listdat.nlist, listdat.nlines) :
1889 fprintf(shout, "zsh: do you wish to see all %d lines? ",
1890 listdat.nlines));
1891 qup = ((l + columns - 1) / columns) - 1;
1892 fflush(shout);
1893 if (!getzlequery()) {
1894 if (clearflag) {
1895 putc('\r', shout);
1896 tcmultout(TCUP, TCMULTUP, qup);
1897 if (tccan(TCCLEAREOD))
1898 tcout(TCCLEAREOD);
1899 tcmultout(TCUP, TCMULTUP, nlnct);
1900 } else
1901 putc('\n', shout);
1902 minfo.asked = 2;
1903 return 1;
1905 if (clearflag) {
1906 putc('\r', shout);
1907 tcmultout(TCUP, TCMULTUP, qup);
1908 if (tccan(TCCLEAREOD))
1909 tcout(TCCLEAREOD);
1910 } else
1911 putc('\n', shout);
1912 settyinfo(&shttyinfo);
1913 minfo.asked = 1;
1914 } else if (minfo.asked == 2)
1915 tcmultout(TCUP, TCMULTUP, nlnct);
1917 return (minfo.asked ? minfo.asked - 1 : 0);
1920 /**/
1921 mod_export int
1922 printlist(int over, CLPrintFunc printm, int showall)
1924 Cmgroup g;
1925 Cmatch *p, m;
1926 Cexpl *e;
1927 int pnl = 0, cl = (over ? listdat.nlines : -1);
1928 int mc = 0, ml = 0, printed = 0;
1930 if (cl < 2) {
1931 cl = -1;
1932 if (tccan(TCCLEAREOD))
1933 tcout(TCCLEAREOD);
1935 for (g = amatches; g; g = g->next) {
1936 char **pp = g->ylist;
1938 if ((e = g->expls)) {
1939 int l;
1941 while (*e) {
1942 if (((*e)->count || (*e)->always) &&
1943 (!listdat.onlyexpl ||
1944 (listdat.onlyexpl & ((*e)->always > 0 ? 2 : 1)))) {
1945 if (pnl) {
1946 putc('\n', shout);
1947 pnl = 0;
1948 ml++;
1949 if (cl >= 0 && --cl <= 1) {
1950 cl = -1;
1951 if (tccan(TCCLEAREOD))
1952 tcout(TCCLEAREOD);
1955 l = printfmt((*e)->str,
1956 ((*e)->always ? -1 : (*e)->count), 1, 1);
1957 ml += l;
1958 if (cl >= 0 && (cl -= l) <= 1) {
1959 cl = -1;
1960 if (tccan(TCCLEAREOD))
1961 tcout(TCCLEAREOD);
1963 pnl = 1;
1965 e++;
1968 if (!listdat.onlyexpl && pp && *pp) {
1969 if (pnl) {
1970 putc('\n', shout);
1971 pnl = 0;
1972 ml++;
1973 if (cl >= 0 && --cl <= 1) {
1974 cl = -1;
1975 if (tccan(TCCLEAREOD))
1976 tcout(TCCLEAREOD);
1979 if (g->flags & CGF_LINES) {
1980 char *p;
1982 while ((p = *pp++)) {
1983 zputs(p, shout);
1984 if (*pp) {
1985 if (MB_METASTRWIDTH(p) % columns)
1986 putc('\n', shout);
1987 else
1988 fputs(" \010", shout);
1991 } else {
1992 int n = g->lcount, nl, nc, i, a;
1993 char **pq;
1995 nl = nc = g->lins;
1997 while (n && nl--) {
1998 i = g->cols;
1999 mc = 0;
2000 pq = pp;
2001 while (n && i--) {
2002 if (pq - g->ylist >= g->lcount)
2003 break;
2004 zputs(*pq, shout);
2005 if (i) {
2006 a = (g->widths ? g->widths[mc] : g->width) -
2007 MB_METASTRWIDTH(*pq);
2008 while (a--)
2009 putc(' ', shout);
2011 pq += ((g->flags & CGF_ROWS) ? 1 : nc);
2012 mc++;
2013 n--;
2015 if (n) {
2016 putc('\n', shout);
2017 ml++;
2018 if (cl >= 0 && --cl <= 1) {
2019 cl = -1;
2020 if (tccan(TCCLEAREOD))
2021 tcout(TCCLEAREOD);
2024 pp += ((g->flags & CGF_ROWS) ? g->cols : 1);
2027 } else if (!listdat.onlyexpl &&
2028 (g->lcount || (showall && g->mcount))) {
2029 int n = g->dcount, nl, nc, i, j, wid;
2030 Cmatch *q;
2032 nl = nc = g->lins;
2034 if (g->flags & CGF_HASDL) {
2035 for (p = g->matches; (m = *p); p++)
2036 if (m->disp && (m->flags & CMF_DISPLINE) &&
2037 (showall || !(m->flags & (CMF_HIDE|CMF_NOLIST)))) {
2038 if (pnl) {
2039 putc('\n', shout);
2040 pnl = 0;
2041 ml++;
2042 if (cl >= 0 && --cl <= 1) {
2043 cl = -1;
2044 if (tccan(TCCLEAREOD))
2045 tcout(TCCLEAREOD);
2048 printed++;
2049 printm(g, p, 0, ml, 1, 0);
2050 pnl = 1;
2053 if (n && pnl) {
2054 putc('\n', shout);
2055 pnl = 0;
2056 ml++;
2057 if (cl >= 0 && --cl <= 1) {
2058 cl = -1;
2059 if (tccan(TCCLEAREOD))
2060 tcout(TCCLEAREOD);
2063 for (p = skipnolist(g->matches, showall); n && nl--;) {
2064 i = g->cols;
2065 mc = 0;
2066 q = p;
2067 while (n && i--) {
2068 wid = (g->widths ? g->widths[mc] : g->width);
2069 if (!(m = *q)) {
2070 printm(g, NULL, mc, ml, (!i), wid);
2071 break;
2073 printm(g, q, mc, ml, (!i), wid);
2075 printed++;
2077 if (--n)
2078 for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
2079 j && *q; j--)
2080 q = skipnolist(q + 1, showall);
2081 mc++;
2083 while (i-- > 0) {
2084 printm(g, NULL, mc, ml, (!i),
2085 (g->widths ? g->widths[mc] : g->width));
2086 mc++;
2088 if (n) {
2089 putc('\n', shout);
2090 ml++;
2091 if (cl >= 0 && --cl <= 1) {
2092 cl = -1;
2093 if (tccan(TCCLEAREOD))
2094 tcout(TCCLEAREOD);
2096 if (nl)
2097 for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
2098 j && *p; j--)
2099 p = skipnolist(p + 1, showall);
2102 } else
2103 continue;
2104 if (g->lcount || (showall && g->mcount))
2105 pnl = 1;
2107 lastlistlen = 0;
2108 if (clearflag) {
2109 /* Move the cursor up to the prompt, if always_last_prompt *
2110 * is set and all that... */
2111 if ((ml = listdat.nlines + nlnct - 1) < lines) {
2112 tcmultout(TCUP, TCMULTUP, ml);
2113 showinglist = -1;
2115 lastlistlen = listdat.nlines;
2116 } else
2117 clearflag = 0, putc('\n', shout);
2118 } else
2119 putc('\n', shout);
2121 listshown = (clearflag ? 1 : -1);
2123 return printed;
2126 /**/
2127 mod_export void
2128 bld_all_str(Cmatch all)
2130 Cmgroup g;
2131 Cmatch *mp, m;
2132 int len = columns - 5, t, add = 0;
2133 VARARR(char, buf, columns + 1);
2135 buf[0] = '\0';
2137 for (g = amatches; g && !g->mcount; g = g->next);
2139 mp = g->matches;
2140 while (1) {
2141 m = *mp;
2142 if (!(m->flags & (CMF_ALL | CMF_HIDE)) && m->str) {
2143 t = strlen(m->str) + add;
2144 if (len >= t) {
2145 if (add)
2146 strcat(buf, " ");
2147 strcat(buf, m->str);
2148 len -= t;
2149 add = 1;
2150 } else {
2151 if (len > add + 2) {
2152 if (add)
2153 strcat(buf, " ");
2154 strncat(buf, m->str, len);
2156 strcat(buf, "...");
2157 break;
2160 if (!*++mp) {
2161 do {
2162 if (!(g = g->next))
2163 break;
2164 } while (!g->mcount);
2165 if (!g)
2166 break;
2167 mp = g->matches;
2170 zsfree(all->disp);
2171 all->disp = ztrdup(buf);
2174 /**/
2175 static void
2176 iprintm(Cmgroup g, Cmatch *mp, UNUSED(int mc), UNUSED(int ml), int lastc, int width)
2178 Cmatch m;
2179 int len = 0;
2181 if (!mp)
2182 return;
2184 m = *mp;
2185 if ((m->flags & CMF_ALL) && (!m->disp || !m->disp[0]))
2186 bld_all_str(m);
2187 if (m->disp) {
2188 if (m->flags & CMF_DISPLINE) {
2189 printfmt(m->disp, 0, 1, 0);
2190 return;
2192 #ifdef MULTIBYTE_SUPPORT
2193 len = mb_niceformat(m->disp, shout, NULL, 0);
2194 #else
2195 nicezputs(m->disp, shout);
2196 len = niceztrlen(m->disp);
2197 #endif
2198 } else {
2199 #ifdef MULTIBYTE_SUPPORT
2200 len = mb_niceformat(m->str, shout, NULL, 0);
2201 #else
2202 nicezputs(m->str, shout);
2203 len = niceztrlen(m->str);
2204 #endif
2206 if ((g->flags & CGF_FILES) && m->modec) {
2207 putc(m->modec, shout);
2208 len++;
2211 if (!lastc) {
2212 len = width - len;
2214 while (len-- > 0)
2215 putc(' ', shout);
2219 /**/
2221 ilistmatches(UNUSED(Hookdef dummy), UNUSED(Chdata dat))
2223 calclist(0);
2225 if (!listdat.nlines) {
2226 showinglist = listshown = 0;
2227 return 1;
2229 if (asklist())
2230 return 0;
2232 printlist(0, iprintm, 0);
2234 return 0;
2237 /* List the matches. Note that the list entries are metafied. */
2239 /**/
2241 list_matches(UNUSED(Hookdef dummy), UNUSED(void *dummy2))
2243 struct chdata dat;
2244 int ret;
2246 #ifdef DEBUG
2247 /* Sanity check */
2248 if (!validlist) {
2249 showmsg("BUG: listmatches called with bogus list");
2250 return 1;
2252 #endif
2254 dat.matches = amatches;
2255 dat.num = nmatches;
2256 dat.cur = NULL;
2257 ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
2259 return ret;
2262 /* Invalidate the completion list. */
2264 /**/
2265 mod_export int
2266 invalidate_list(void)
2268 invcount++;
2269 if (validlist) {
2270 if (showinglist == -2) {
2271 zrefresh();
2273 freematches(lastmatches, 1);
2274 lastmatches = NULL;
2275 hasoldlist = 0;
2277 lastambig = menucmp = menuacc = validlist = showinglist = fromcomp = 0;
2278 listdat.valid = 0;
2279 if (listshown < 0)
2280 listshown = 0;
2281 minfo.cur = NULL;
2282 minfo.asked = 0;
2283 zsfree(minfo.prebr);
2284 zsfree(minfo.postbr);
2285 minfo.postbr = minfo.prebr = NULL;
2286 compwidget = NULL;
2288 return 0;