1
0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-11-19 13:33:52 +01:00
zsh/Src/Zle/complist.c

3041 lines
69 KiB
C

/*
* complist.c - completion listing enhancements
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1999 Sven Wischnowsky
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Sven Wischnowsky or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Sven Wischnowsky and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Sven Wischnowsky and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
#include "complist.mdh"
#include "complist.pro"
/* We use the parameters ZLS_COLORS and ZLS_COLOURS in the same way as
* the color ls does. It's just that we don't support the `or' file
* type. */
static Widget w_menuselect;
static Keymap mskeymap, lskeymap;
/* Indixes into the terminal string arrays. */
#define COL_NO 0
#define COL_FI 1
#define COL_DI 2
#define COL_LN 3
#define COL_PI 4
#define COL_SO 5
#define COL_BD 6
#define COL_CD 7
#define COL_EX 8
#define COL_MI 9
#define COL_LC 10
#define COL_RC 11
#define COL_EC 12
#define COL_TC 13
#define COL_SP 14
#define COL_MA 15
#define COL_HI 16
#define COL_DU 17
#define NUM_COLS 18
/* Maximum number of in-string colours supported. */
#define MAX_POS 11
/* Names of the terminal strings. */
static char *colnames[] = {
"no", "fi", "di", "ln", "pi", "so", "bd", "cd", "ex", "mi",
"lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", NULL
};
/* Default values. */
static char *defcols[] = {
"0", "0", "1;31", "1;36", "33", "1;35", "1;33", "1;33", "1;32", NULL,
"\033[", "m", NULL, "0", "0", "7", NULL, NULL
};
/* This describes a terminal string for a file type. */
typedef struct filecol *Filecol;
struct filecol {
Patprog prog; /* group pattern */
char *col; /* color string */
Filecol next; /* next one */
};
/* This describes a terminal string for a pattern. */
typedef struct patcol *Patcol;
struct patcol {
Patprog prog;
Patprog pat; /* pattern for match */
char *cols[MAX_POS + 1];
Patcol next;
};
/* This describes a terminal string for a filename extension. */
typedef struct extcol *Extcol;
struct extcol {
Patprog prog; /* group pattern or NULL */
char *ext; /* the extension */
char *col; /* the terminal color string */
Extcol next; /* the next one in the list */
};
/* This holds all terminal strings. */
typedef struct listcols *Listcols;
struct listcols {
Filecol files[NUM_COLS]; /* strings for file types */
Patcol pats; /* strings for patterns */
Extcol exts; /* strings for extensions */
};
/* Combined length of LC and RC, maximum length of capability strings. */
static int lr_caplen, max_caplen;
/* This parses the value of a definition (the part after the `=').
* The return value is a pointer to the character after it. */
static char *
getcolval(char *s, int multi)
{
char *p, *o = s;
for (p = s; *s && *s != ':' && (!multi || *s != '='); p++, s++) {
if (*s == '\\' && s[1]) {
switch (*++s) {
case 'a': *p = '\007'; break;
case 'n': *p = '\n'; break;
case 'b': *p = '\b'; break;
case 't': *p = '\t'; break;
case 'v': *p = '\v'; break;
case 'f': *p = '\f'; break;
case 'r': *p = '\r'; break;
case 'e': *p = '\033'; break;
case '_': *p = ' '; break;
case '?': *p = '\177'; break;
default:
if (*s >= '0' && *s <= '7') {
int i = STOUC(*s);
if (*++s >= '0' && *s <= '7') {
i = (i * 8) + STOUC(*s);
if (*++s >= '0' && *s <= '7')
i = (i * 8) + STOUC(*s);
}
*p = (char) i;
} else
*p = *s;
}
} else if (*s == '^') {
if ((s[1] >= '@' && s[1] <= '_') ||
(s[1] >= 'a' && s[1] <= 'z'))
*p = (char) (STOUC(*s) & ~0x60);
else if (s[1] == '?')
*p = '\177';
else {
*p++ = *s;
*p = s[1];
}
s++;
} else
*p = *s;
}
if (p != s)
*p = '\0';
if ((s - o) > max_caplen)
max_caplen = s - o;
return s;
}
/* This parses one definition. Return value is a pointer to the
* character after it. */
static char *
getcoldef(Listcols c, char *s)
{
Patprog gprog = NULL;
if (*s == '(') {
char *p;
int l = 0;
for (p = s + 1, l = 0; *p && (*p != ')' || l); p++)
if (*p == '\\' && p[1])
p++;
else if (*p == '(')
l++;
else if (*p == ')')
l--;
if (*p == ')') {
char sav = p[1];
p[1] = '\0';
tokenize(s);
gprog = patcompile(s, 0, NULL);
p[1] =sav;
s = p + 1;
}
}
if (*s == '*') {
Extcol ec, eo;
char *n, *p;
/* This is for an extension. */
n = ++s;
while (*s && *s != '=')
s++;
if (!*s)
return s;
*s++ = '\0';
p = getcolval(s, 0);
ec = (Extcol) zhalloc(sizeof(*ec));
ec->prog = gprog;
ec->ext = n;
ec->col = s;
ec->next = NULL;
if ((eo = c->exts)) {
while (eo->next)
eo = eo->next;
eo->next = ec;
} else
c->exts = ec;
if (*p)
*p++ = '\0';
return p;
} else if (*s == '=') {
char *p = ++s, *t, *cols[MAX_POS];
int ncols = 0;
Patprog prog;
/* This is for a pattern. */
while (*s && *s != '=')
s++;
if (!*s)
return s;
*s++ = '\0';
while (1) {
t = getcolval(s, 1);
if (ncols < MAX_POS)
cols[ncols++] = s;
s = t;
if (*s != '=')
break;
*s++ = '\0';
}
tokenize(p);
if ((prog = patcompile(p, 0, NULL))) {
Patcol pc, po;
int i;
pc = (Patcol) zhalloc(sizeof(*pc));
pc->prog = gprog;
pc->pat = prog;
for (i = 0; i < ncols; i++)
pc->cols[i] = cols[i];
pc->cols[i] = NULL;
pc->next = NULL;
if ((po = c->pats)) {
while (po->next)
po = po->next;
po->next = pc;
} else
c->pats = pc;
}
if (*t)
*t++ = '\0';
return t;
} else {
char *n = s, *p, **nn;
int i;
/* This is for a file type. */
while (*s && *s != '=')
s++;
if (!*s)
return s;
*s++ = '\0';
for (i = 0, nn = colnames; *nn; i++, nn++)
if (!strcmp(n, *nn))
break;
p = getcolval(s, 0);
if (*nn) {
Filecol fc, fo;
fc = (Filecol) zhalloc(sizeof(*fc));
fc->prog = (i == COL_EC || i == COL_LC || i == COL_RC ?
NULL : gprog);
fc->col = s;
fc->next = NULL;
if ((fo = c->files[i])) {
while (fo->next)
fo = fo->next;
fo->next = fc;
} else
c->files[i] = fc;
}
if (*p)
*p++ = '\0';
return p;
}
}
static Filecol
filecol(char *col)
{
Filecol fc;
fc = (Filecol) zhalloc(sizeof(*fc));
fc->prog = NULL;
fc->col = col;
fc->next = NULL;
return fc;
}
/* This initializes the given terminal color structure. */
static void
getcols(Listcols c)
{
char *s;
int i, l;
max_caplen = lr_caplen = 0;
queue_signals();
if (!(s = getsparam("ZLS_COLORS")) &&
!(s = getsparam("ZLS_COLOURS"))) {
for (i = 0; i < NUM_COLS; i++)
c->files[i] = filecol("");
c->pats = NULL;
c->exts = NULL;
if ((s = tcstr[TCSTANDOUTBEG]) && s[0]) {
c->files[COL_MA] = filecol(s);
c->files[COL_EC] = filecol(tcstr[TCSTANDOUTEND]);
} else
c->files[COL_MA] = filecol(defcols[COL_MA]);
lr_caplen = 0;
if ((max_caplen = strlen(c->files[COL_MA]->col)) <
(l = strlen(c->files[COL_EC]->col)))
max_caplen = l;
unqueue_signals();
return;
}
/* We have one of the parameters, use it. */
memset(c, 0, sizeof(*c));
s = dupstring(s);
while (*s)
if (*s == ':')
s++;
else
s = getcoldef(c, s);
unqueue_signals();
/* Use default values for those that aren't set explicitly. */
for (i = 0; i < NUM_COLS; i++) {
if (!c->files[i] || !c->files[i]->col)
c->files[i] = filecol(defcols[i]);
if (c->files[i] && c->files[i]->col &&
(l = strlen(c->files[i]->col)) > max_caplen)
max_caplen = l;
}
lr_caplen = strlen(c->files[COL_LC]->col) + strlen(c->files[COL_RC]->col);
/* Default for missing files. */
if (!c->files[COL_MI] || !c->files[COL_MI]->col)
c->files[COL_MI] = c->files[COL_FI];
return;
}
/* Information about the list shown. */
static int noselect, mselect, inselect, mcol, mline, mcols, mlines, mmlen;
static int selected, mlbeg = -1, mlend = 9999999, mscroll, mrestlines;
static int mnew, mlastcols, mlastlines, mhasstat, mfirstl, mlastm;
static int mlprinted, molbeg = -2, mocol = 0, moline = 0, mstatprinted;
static char *mstatus, *mlistp;
static Cmatch **mtab, **mmtabp;
static int mtab_been_reallocated;
static Cmgroup *mgtab, *mgtabp;
static struct listcols mcolors;
/* Used in mtab/mgtab, for explanations. */
#define MMARK ((unsigned long) 1)
#define mmarked(v) (((unsigned long) (v)) & MMARK)
#define mtmark(v) ((Cmatch *) (((unsigned long) (v)) | MMARK))
#define mtunmark(v) ((Cmatch *) (((unsigned long) (v)) & ~MMARK))
#define mgmark(v) ((Cmgroup) (((unsigned long) (v)) | MMARK))
#define mgunmark(v) ((Cmgroup) (((unsigned long) (v)) & ~MMARK))
/* Information for in-string colours. */
static int nrefs;
static int begpos[MAX_POS], curisbeg;
static int endpos[MAX_POS];
static int sendpos[MAX_POS], curissend; /* sorted end positions */
static char **patcols, *curiscols[MAX_POS];
static int curiscol;
/* The last color used. */
static char *last_cap;
static void
zlrputs(Listcols c, char *cap)
{
if (!*last_cap || strcmp(last_cap, cap)) {
VARARR(char, buf, lr_caplen + max_caplen + 1);
strcpy(buf, c->files[COL_LC]->col);
strcat(buf, cap);
strcat(buf, c->files[COL_RC]->col);
tputs(buf, 1, putshout);
strcpy(last_cap, cap);
}
}
static void
zcputs(Listcols c, char *group, int colour)
{
Filecol fc;
for (fc = c->files[colour]; fc; fc = fc->next)
if (fc->col &&
(!fc->prog || !group || pattry(fc->prog, group))) {
zlrputs(c, fc->col);
return;
}
zlrputs(c, "0");
}
/* Turn off colouring. */
static void
zcoff(void)
{
if (mcolors.files[COL_EC] && mcolors.files[COL_EC]->col) {
tputs(mcolors.files[COL_EC]->col, 1, putshout);
*last_cap = '\0';
} else
zcputs(&mcolors, NULL, COL_NO);
}
static void
initiscol(Listcols c)
{
int i;
zlrputs(c, patcols[0]);
curiscols[curiscol = 0] = *patcols++;
curisbeg = curissend = 0;
for (i = 0; i < nrefs; i++)
sendpos[i] = 0xfffffff;
for (; i < MAX_POS; i++)
begpos[i] = endpos[i] = sendpos[i] = 0xfffffff;
}
static void
doiscol(Listcols c, int pos)
{
int fi;
while (pos > sendpos[curissend]) {
curissend++;
if (curiscol) {
zcputs(c, NULL, COL_NO);
zlrputs(c, curiscols[--curiscol]);
}
}
while (((fi = (endpos[curisbeg] < begpos[curisbeg] ||
begpos[curisbeg] == -1)) ||
pos == begpos[curisbeg]) && *patcols) {
if (!fi) {
int i, j, e = endpos[curisbeg];
/* insert e in sendpos */
for (i = curissend; sendpos[i] <= e; ++i)
;
for (j = MAX_POS - 1; j > i; --j)
sendpos[j] = sendpos[j-1];
sendpos[i] = e;
zcputs(c, NULL, COL_NO);
zlrputs(c, *patcols);
curiscols[++curiscol] = *patcols;
}
++patcols;
++curisbeg;
}
}
/* Stripped-down version of printfmt(). But can do in-string colouring. */
static int
clprintfmt(Listcols c, char *p, int ml)
{
int cc = 0, i = 0, ask, beg;
initiscol(c);
for (; *p; p++) {
doiscol(c, i++);
cc++;
if (*p == '\n') {
if (mlbeg >= 0 && tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
cc = 0;
}
if (ml == mlend - 1 && (cc % columns) == columns - 1)
return 0;
putc(*p, shout);
if ((beg = !(cc % columns)))
ml++;
if (mscroll && !(cc % columns) &&
!--mrestlines && (ask = asklistscroll(ml)))
return ask;
}
if (mlbeg >= 0 && tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
return 0;
}
/* Local version of nicezputs() with in-string colouring. */
static int
clnicezputs(Listcols c, char *s, int ml)
{
int cc, i = 0, col = 0, ask, oml = ml;
char *t;
initiscol(c);
while ((cc = *s++)) {
doiscol(c, i++);
if (itok(cc)) {
if (cc <= Comma)
cc = ztokens[cc - Pound];
else
continue;
}
if (cc == Meta)
cc = *s++ ^ 32;
for (t = nicechar(cc); *t; t++) {
if (ml == mlend - 1 && col == columns - 1) {
mlprinted = ml - oml;
return 0;
}
putc(*t, shout);
if (++col == columns) {
ml++;
if (mscroll && !--mrestlines && (ask = asklistscroll(ml))) {
mlprinted = ml - oml;
return ask;
}
col = 0;
fputs(" \010", shout);
}
}
}
mlprinted = ml - oml;
return 0;
}
/* Get the terminal color string for the given match. */
static int
putmatchcol(Listcols c, char *group, char *n)
{
Patcol pc;
nrefs = MAX_POS - 1;
for (pc = c->pats; pc; pc = pc->next)
if ((!pc->prog || !group || pattry(pc->prog, group)) &&
pattryrefs(pc->pat, n, -1, -1, 0, &nrefs, begpos, endpos)) {
if (pc->cols[1]) {
patcols = pc->cols;
return 1;
}
zlrputs(c, pc->cols[0]);
return 0;
}
zcputs(c, group, COL_NO);
return 0;
}
/* Get the terminal color string for the file with the given name and
* file modes. */
static int
putfilecol(Listcols c, char *group, char *n, mode_t m)
{
int colour;
Extcol ec;
Patcol pc;
for (ec = c->exts; ec; ec = ec->next)
if (strsfx(ec->ext, n) &&
(!ec->prog || !group || pattry(ec->prog, group))) {
zlrputs(c, ec->col);
return 0;
}
nrefs = MAX_POS - 1;
for (pc = c->pats; pc; pc = pc->next)
if ((!pc->prog || !group || pattry(pc->prog, group)) &&
pattryrefs(pc->pat, n, -1, -1, 0, &nrefs, begpos, endpos)) {
if (pc->cols[1]) {
patcols = pc->cols;
return 1;
}
zlrputs(c, pc->cols[0]);
return 0;
}
if (S_ISDIR(m))
colour = COL_DI;
else if (S_ISLNK(m))
colour = COL_LN;
else if (S_ISFIFO(m))
colour = COL_PI;
else if (S_ISSOCK(m))
colour = COL_SO;
else if (S_ISBLK(m))
colour = COL_BD;
else if (S_ISCHR(m))
colour = COL_CD;
else if (S_ISREG(m) && (m & S_IXUGO))
colour = COL_EX;
else
colour = COL_FI;
zcputs(c, group, colour);
return 0;
}
static Cmgroup last_group;
/**/
static int
asklistscroll(int ml)
{
Thingy cmd;
int i, ret = 0;
compprintfmt(NULL, 1, 1, 1, ml, NULL);
fflush(shout);
zsetterm();
selectlocalmap(lskeymap);
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak))
ret = 1;
else if (cmd == Th(z_acceptline) ||
cmd == Th(z_downhistory) ||
cmd == Th(z_downlineorhistory) ||
cmd == Th(z_downlineorsearch) ||
cmd == Th(z_vidownlineorhistory))
mrestlines = 1;
else if (cmd == Th(z_completeword) ||
cmd == Th(z_expandorcomplete) ||
cmd == Th(z_expandorcompleteprefix) ||
cmd == Th(z_menucomplete) ||
cmd == Th(z_menuexpandorcomplete) ||
!strcmp(cmd->nam, "menu-select") ||
!strcmp(cmd->nam, "complete-word") ||
!strcmp(cmd->nam, "expand-or-complete") ||
!strcmp(cmd->nam, "expand-or-complete-prefix") ||
!strcmp(cmd->nam, "menu-complete") ||
!strcmp(cmd->nam, "menu-expand-or-complete"))
mrestlines = lines - 1;
else {
ungetkeycmd();
ret = 1;
}
selectlocalmap(NULL);
settyinfo(&shttyinfo);
putc('\r', shout);
for (i = columns - 1; i--; )
putc(' ', shout);
putc('\r', shout);
return ret;
}
#define dolist(X) ((X) >= mlbeg && (X) < mlend)
#define dolistcl(X) ((X) >= mlbeg && (X) < mlend + 1)
#define dolistnl(X) ((X) >= mlbeg && (X) < mlend - 1)
/**/
static int
compprintnl(int ml)
{
int ask;
if (mlbeg >= 0 && tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
putc('\n', shout);
if (mscroll && !--mrestlines && (ask = asklistscroll(ml)))
return ask;
return 0;
}
/* This is used to print the strings (e.g. explanations). *
* It returns the number of lines printed. */
/**/
static int
compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
{
char *p, nc[2*DIGBUFSIZE + 12], nbuf[2*DIGBUFSIZE + 12];
int l = 0, cc = 0, b = 0, s = 0, u = 0, m, ask, beg, stat;
if ((stat = !fmt)) {
if (mlbeg >= 0) {
if (!(fmt = mstatus)) {
mlprinted = 0;
return 0;
}
cc = -1;
} else
fmt = mlistp;
}
for (p = fmt; *p; p++) {
if (doesc && *p == '%') {
if (*++p) {
m = 0;
switch (*p) {
case '%':
if (dopr == 1)
putc('%', shout);
cc++;
break;
case 'n':
if (!stat) {
sprintf(nc, "%d", n);
if (dopr == 1)
fputs(nc, shout);
cc += strlen(nc);
}
break;
case 'B':
b = 1;
if (dopr)
tcout(TCBOLDFACEBEG);
break;
case 'b':
b = 0; m = 1;
if (dopr)
tcout(TCALLATTRSOFF);
break;
case 'S':
s = 1;
if (dopr)
tcout(TCSTANDOUTBEG);
break;
case 's':
s = 0; m = 1;
if (dopr)
tcout(TCSTANDOUTEND);
break;
case 'U':
u = 1;
if (dopr)
tcout(TCUNDERLINEBEG);
break;
case 'u':
u = 0; m = 1;
if (dopr)
tcout(TCUNDERLINEEND);
break;
case '{':
for (p++; *p && (*p != '%' || p[1] != '}'); p++)
if (dopr)
putc(*p, shout);
if (*p)
p++;
else
p--;
break;
case 'm':
if (stat) {
sprintf(nc, "%d/%d", (n ? mlastm : mselect),
listdat.nlist);
m = 2;
}
break;
case 'M':
if (stat) {
sprintf(nbuf, "%d/%d", (n ? mlastm : mselect),
listdat.nlist);
sprintf(nc, "%-9s", nbuf);
m = 2;
}
break;
case 'l':
if (stat) {
sprintf(nc, "%d/%d", ml + 1, listdat.nlines);
m = 2;
}
break;
case 'L':
if (stat) {
sprintf(nbuf, "%d/%d", ml + 1, listdat.nlines);
sprintf(nc, "%-9s", nbuf);
m = 2;
}
break;
case 'p':
if (stat) {
if (ml == listdat.nlines - 1)
strcpy(nc, "Bottom");
else if (n ? mfirstl : (mlbeg > 0 || ml != mfirstl))
sprintf(nc, "%d%%",
((ml + 1) * 100) / listdat.nlines);
else
strcpy(nc, "Top");
m = 2;
}
break;
case 'P':
if (stat) {
if (ml == listdat.nlines - 1)
strcpy(nc, "Bottom");
else if (n ? mfirstl : (mlbeg > 0 || ml != mfirstl))
sprintf(nc, "%2d%% ",
((ml + 1) * 100) / listdat.nlines);
else
strcpy(nc, "Top ");
m = 2;
}
break;
}
if (m == 2 && dopr == 1) {
int l = strlen(nc);
if (l + cc > columns - 2)
nc[l -= l + cc - (columns - 2)] = '\0';
fputs(nc, shout);
cc += l;
} else if (dopr && m == 1) {
if (b)
tcout(TCBOLDFACEBEG);
if (s)
tcout(TCSTANDOUTBEG);
if (u)
tcout(TCUNDERLINEBEG);
}
} else
break;
} else {
if ((++cc == columns - 2 || *p == '\n') && stat)
dopr = 2;
if (*p == '\n') {
if (dopr == 1 && mlbeg >= 0 && tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
l += 1 + ((cc - 1) / columns);
cc = 0;
}
if (dopr == 1) {
if (ml == mlend - 1 && (cc % columns) == columns - 1) {
dopr = 0;
continue;
}
putc(*p, shout);
if ((beg = !(cc % columns)) && !stat) {
ml++;
fputs(" \010", shout);
}
if (mscroll && beg && !--mrestlines && (ask = asklistscroll(ml))) {
*stop = 1;
if (stat && n)
mfirstl = -1;
return (mlprinted = l + (cc / columns));
}
}
}
}
if (dopr) {
if (!(cc % columns))
fputs(" \010", shout);
if (mlbeg >= 0 && tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
}
if (stat && n)
mfirstl = -1;
return (mlprinted = l + (cc / columns));
}
/* This is like zputs(), but allows scrolling. */
/**/
static int
compzputs(char const *s, int ml)
{
int c, col = 0, ask;
while (*s) {
if (*s == Meta)
c = *++s ^ 32;
else if(itok(*s)) {
s++;
continue;
} else
c = *s;
s++;
putc(c, shout);
if (c == '\n' && mlbeg >= 0 && tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
if (mscroll && (++col == columns || c == '\n')) {
ml++;
if (!--mrestlines && (ask = asklistscroll(ml)))
return ask;
col = 0;
}
}
return 0;
}
/* This is like nicezputs(), but allows scrolling. */
/**/
static int
compnicezputs(char *s, int ml)
{
int c, col = 0, ask, oml = ml;
char *t;
while ((c = *s++)) {
if (itok(c)) {
if (c <= Comma)
c = ztokens[c - Pound];
else
continue;
}
if (c == Meta)
c = *s++ ^ 32;
for (t = nicechar(c); *t; t++) {
if (ml == mlend - 1 && col == columns - 1) {
mlprinted = ml - oml;
return 0;
}
putc(*t, shout);
if (++col == columns) {
ml++;
if (mscroll && !--mrestlines && (ask = asklistscroll(ml))) {
mlprinted = ml - oml;
return ask;
}
col = 0;
}
}
}
mlprinted = ml - oml;
return 0;
}
/**/
static int
compprintlist(int showall)
{
static int lasttype = 0, lastbeg = 0, lastml = 0, lastinvcount = -1;
static int lastn = 0, lastnl = 0, lastnlnct = -1;
static Cmgroup lastg = NULL;
static Cmatch *lastp = NULL;
static Cexpl *lastexpl = NULL;
Cmgroup g;
Cmatch *p, m;
Cexpl *e;
int pnl = 0, cl, mc = 0, ml = 0, printed = 0, stop = 0, asked = 1;
int lastused = 0;
mfirstl = -1;
if (mnew || lastinvcount != invcount || lastbeg != mlbeg || mlbeg < 0) {
lasttype = 0;
lastg = NULL;
lastexpl = NULL;
lastml = 0;
lastnlnct = -1;
}
cl = (listdat.nlines > lines - nlnct - mhasstat ?
lines - nlnct - mhasstat : listdat.nlines) - (lastnlnct > nlnct);
lastnlnct = nlnct;
mrestlines = lines - 1;
lastinvcount = invcount;
if (cl < 2) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
} else if (mlbeg >= 0 && !tccan(TCCLEAREOL) && tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
g = ((lasttype && lastg) ? lastg : amatches);
while (g) {
char **pp = g->ylist;
if ((e = g->expls)) {
int l;
if (!lastused && lasttype == 1) {
e = lastexpl;
ml = lastml;
lastused = 1;
}
while (*e) {
if (((*e)->count || (*e)->always) &&
(!listdat.onlyexpl ||
(listdat.onlyexpl & ((*e)->always > 0 ? 2 : 1)))) {
if (pnl) {
if (dolistnl(ml) && compprintnl(ml))
goto end;
pnl = 0;
ml++;
if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
}
if (mlbeg < 0 && mfirstl < 0)
mfirstl = ml;
l = compprintfmt((*e)->str,
((*e)->always ? -1 : (*e)->count),
dolist(ml), 1, ml, &stop);
if (mselect >= 0) {
int mm = (mcols * ml), i;
for (i = mcols; i--; ) {
mtab[mm + i] = mtmark(NULL);
mgtab[mm + i] = mgmark(NULL);
}
}
if (stop)
goto end;
if (!lasttype && ml >= mlbeg) {
lasttype = 1;
lastg = g;
lastbeg = mlbeg;
lastml = ml;
lastexpl = e;
lastp = NULL;
lastused = 1;
}
ml += mlprinted;
if (dolistcl(ml) && cl >= 0 && (cl -= mlprinted) <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
pnl = 1;
}
e++;
if (!mnew && ml > mlend)
goto end;
}
}
if (!listdat.onlyexpl && mlbeg < 0 && pp && *pp) {
if (pnl) {
if (dolistnl(ml) && compprintnl(ml))
goto end;
pnl = 0;
ml++;
if (cl >= 0 && --cl <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
}
if (mlbeg < 0 && mfirstl < 0)
mfirstl = ml;
if (g->flags & CGF_LINES) {
while (*pp) {
if (compzputs(*pp, ml))
goto end;
if (*++pp && compprintnl(ml))
goto end;
}
} else {
int n = g->lcount, nl, nc, i, a;
char **pq;
nl = nc = g->lins;
while (n && nl--) {
i = g->cols;
mc = 0;
pq = pp;
while (n && i--) {
if (pq - g->ylist >= g->lcount)
break;
if (compzputs(*pq, mscroll))
goto end;
if (i) {
a = (g->widths ? g->widths[mc] : g->width) -
strlen(*pq);
while (a--)
putc(' ', shout);
}
pq += ((g->flags & CGF_ROWS) ? 1 : nc);
mc++;
n--;
}
if (n) {
if (compprintnl(ml))
goto end;
ml++;
if (cl >= 0 && --cl <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
}
pp += ((g->flags & CGF_ROWS) ? g->cols : 1);
}
}
} else if (!listdat.onlyexpl &&
(g->lcount || (showall && g->mcount))) {
int n = g->dcount, nl, nc, i, j, wid;
Cmatch *q;
nl = nc = g->lins;
if ((g->flags & CGF_HASDL) &&
(lastused || !lasttype || lasttype == 2)) {
if (!lastused && lasttype == 2) {
p = lastp;
ml = lastml;
n = lastn;
nl = lastnl;
lastused = 1;
pnl = 0;
} else
p = g->matches;
for (; (m = *p); p++) {
if (m->disp && (m->flags & CMF_DISPLINE) &&
(showall || !(m->flags & (CMF_HIDE|CMF_NOLIST)))) {
if (pnl) {
if (dolistnl(ml) && compprintnl(ml))
goto end;
pnl = 0;
ml++;
if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
}
if (!lasttype && ml >= mlbeg) {
lasttype = 2;
lastg = g;
lastbeg = mlbeg;
lastml = ml;
lastp = p;
lastn = n;
lastnl = nl;
lastused = 1;
}
if (mfirstl < 0)
mfirstl = ml;
if (dolist(ml))
printed++;
if (clprintm(g, p, 0, ml, 1, 0))
goto end;
ml += mlprinted;
if (dolistcl(ml) && (cl -= mlprinted) <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
pnl = 1;
}
if (!mnew && ml > mlend)
goto end;
}
}
if (n && pnl) {
if (dolistnl(ml) && compprintnl(ml))
goto end;
pnl = 0;
ml++;
if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
}
if (!lastused && lasttype == 3) {
p = lastp;
n = lastn;
nl = lastnl;
ml = lastml;
lastused = 1;
} else
p = skipnolist(g->matches, showall);
while (n && nl--) {
if (!lasttype && ml >= mlbeg) {
lasttype = 3;
lastg = g;
lastbeg = mlbeg;
lastml = ml;
lastp = p;
lastn = n;
lastnl = nl + 1;
lastused = 1;
}
i = g->cols;
mc = 0;
q = p;
while (n && i--) {
wid = (g->widths ? g->widths[mc] : g->width);
if (!(m = *q)) {
if (clprintm(g, NULL, mc, ml, (!i), wid))
goto end;
break;
}
if (clprintm(g, q, mc, ml, (!i), wid))
goto end;
if (dolist(ml))
printed++;
ml += mlprinted;
if (dolistcl(ml) && (cl -= mlprinted) < 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
if (mfirstl < 0)
mfirstl = ml;
if (--n)
for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
j && *q; j--)
q = skipnolist(q + 1, showall);
mc++;
}
while (i-- > 0) {
if (clprintm(g, NULL, mc, ml, (!i),
(g->widths ? g->widths[mc] : g->width)))
goto end;
mc++;
}
if (n) {
if (dolistnl(ml) && compprintnl(ml))
goto end;
ml++;
if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
cl = -1;
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
}
if (nl)
for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
j && *p; j--)
p = skipnolist(p + 1, showall);
}
if (!mnew && ml > mlend)
goto end;
}
}
if (g->lcount || (showall && g->mcount))
pnl = 1;
g = g->next;
}
asked = 0;
end:
mstatprinted = 0;
lastlistlen = 0;
if (nlnct <= 1)
mscroll = 0;
if (clearflag) {
int nl;
/* Move the cursor up to the prompt, if always_last_prompt *
* is set and all that... */
if (mlbeg >= 0) {
if ((nl = listdat.nlines + nlnct) >= lines) {
if (mhasstat) {
putc('\n', shout);
compprintfmt(NULL, 0, 1, 1, mline, NULL);
mstatprinted = 1;
}
nl = lines - 1;
} else
nl--;
tcmultout(TCUP, TCMULTUP, nl);
showinglist = -1;
lastlistlen = listdat.nlines;
} else if ((nl = listdat.nlines + nlnct - 1) < lines) {
if (mlbeg >= 0 && tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
tcmultout(TCUP, TCMULTUP, nl);
showinglist = -1;
lastlistlen = listdat.nlines;
} else {
clearflag = 0;
if (!asked) {
mrestlines = (ml + nlnct > lines);
compprintnl(ml);
}
}
} else if (!asked) {
mrestlines = (ml + nlnct > lines);
compprintnl(ml);
}
listshown = (clearflag ? 1 : -1);
mnew = 0;
return printed;
}
/**/
static int
clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width)
{
Cmatch m;
int len, subcols = 0, stop = 0, ret = 0;
if (g != last_group)
*last_cap = '\0';
last_group = g;
if (!mp) {
if (dolist(ml)) {
zcputs(&mcolors, g->name, COL_SP);
len = width - 2;
while (len-- > 0)
putc(' ', shout);
zcoff();
}
mlprinted = 0;
return 0;
}
m = *mp;
if ((m->flags & CMF_ALL) && (!m->disp || !m->disp[0]))
bld_all_str(m);
mlastm = m->gnum;
if (m->disp && (m->flags & CMF_DISPLINE)) {
if (mselect >= 0) {
int mm = (mcols * ml), i;
if (m->flags & CMF_DUMMY) {
for (i = mcols; i--; ) {
mtab[mm + i] = mtmark(mp);
mgtab[mm + i] = mgmark(g);
}
} else {
for (i = mcols; i--; ) {
mtab[mm + i] = mp;
mgtab[mm + i] = g;
}
}
}
if (!dolist(ml)) {
mlprinted = printfmt(m->disp, 0, 0, 0) / columns;
return 0;
}
if (m->gnum == mselect) {
int mm = (mcols * ml);
mline = ml;
mcol = 0;
mmtabp = mtab + mm;
mgtabp = mgtab + mm;
mmlen = mcols;
zcputs(&mcolors, g->name, COL_MA);
} else if ((m->flags & CMF_NOLIST) &&
mcolors.files[COL_HI] && mcolors.files[COL_HI]->col)
zcputs(&mcolors, g->name, COL_HI);
else if (mselect >= 0 && (m->flags & (CMF_MULT | CMF_FMULT)) &&
mcolors.files[COL_DU] && mcolors.files[COL_DU]->col)
zcputs(&mcolors, g->name, COL_DU);
else
subcols = putmatchcol(&mcolors, g->name, m->disp);
if (subcols)
ret = clprintfmt(&mcolors, m->disp, ml);
else {
compprintfmt(m->disp, 0, 1, 0, ml, &stop);
if (stop)
ret = 1;
}
zcoff();
} else {
int mx;
if (g->widths) {
int i;
for (i = mx = 0; i < mc; i++)
mx += g->widths[i];
} else
mx = mc * g->width;
if (mselect >= 0) {
int mm = mcols * ml, i;
if (m->flags & CMF_DUMMY) {
for (i = (width ? width : mcols); i--; ) {
mtab[mx + mm + i] = mtmark(mp);
mgtab[mx + mm + i] = mgmark(g);
}
} else {
for (i = (width ? width : mcols); i--; ) {
mtab[mx + mm + i] = mp;
mgtab[mx + mm + i] = g;
}
}
}
if (!dolist(ml)) {
mlprinted = niceztrlen(m->disp ? m->disp : m->str) / columns;
return 0;
}
if (m->gnum == mselect) {
int mm = mcols * ml;
mcol = mx;
mline = ml;
mmtabp = mtab + mx + mm;
mgtabp = mgtab + mx + mm;
mmlen = width;
zcputs(&mcolors, g->name, COL_MA);
} else if (m->flags & CMF_NOLIST)
zcputs(&mcolors, g->name, COL_HI);
else if (mselect >= 0 && (m->flags & (CMF_MULT | CMF_FMULT)))
zcputs(&mcolors, g->name, COL_DU);
else if (m->mode)
subcols = putfilecol(&mcolors, g->name, m->str, m->mode);
else
subcols = putmatchcol(&mcolors, g->name, (m->disp ? m->disp : m->str));
if (subcols)
ret = clnicezputs(&mcolors, (m->disp ? m->disp : m->str), ml);
else
ret = compnicezputs((m->disp ? m->disp : m->str), ml);
if (ret) {
zcoff();
return 1;
}
len = niceztrlen(m->disp ? m->disp : m->str);
mlprinted = len / columns;
if ((g->flags & CGF_FILES) && m->modec) {
if (m->gnum != mselect) {
zcoff();
zcputs(&mcolors, g->name, COL_TC);
}
putc(m->modec, shout);
len++;
}
if ((len = width - len - 2) > 0) {
if (m->gnum != mselect) {
zcoff();
zcputs(&mcolors, g->name, COL_SP);
}
while (len-- > 0)
putc(' ', shout);
}
zcoff();
if (!lastc) {
zcputs(&mcolors, g->name, COL_SP);
fputs(" ", shout);
zcoff();
}
}
return ret;
}
static int
singlecalc(int *cp, int l, int *lcp)
{
int c = *cp, n, j, first = 1;
Cmatch **p, *op, *mp = mtab[l * columns + c];
for (n = 0, j = c, p = mtab + l * columns + c, op = NULL; j >= 0; j--, p--) {
if (*p == mp)
c = j;
if (!first && *p != op)
n++;
op = *p;
first = 0;
}
*cp = c;
*lcp = 1;
for (p = mtab + l * columns + c; c < columns; c++, p++)
if (*p && mp != *p)
*lcp = 0;
return n;
}
static void
singledraw()
{
Cmgroup g;
int mc1, mc2, ml1, ml2, md1, md2, mcc1, mcc2, lc1, lc2, t1, t2;
t1 = mline - mlbeg;
t2 = moline - molbeg;
if (t2 < t1) {
mc1 = mocol; ml1 = moline; md1 = t2;
mc2 = mcol; ml2 = mline; md2 = t1;
} else {
mc1 = mcol; ml1 = mline; md1 = t1;
mc2 = mocol; ml2 = moline; md2 = t2;
}
mcc1 = singlecalc(&mc1, ml1, &lc1);
mcc2 = singlecalc(&mc2, ml2, &lc2);
if (md1)
tc_downcurs(md1);
if (mc1)
tcmultout(TCRIGHT, TCMULTRIGHT, mc1);
g = mgtab[ml1 * columns + mc1];
clprintm(g, mtab[ml1 * columns + mc1], mcc1, ml1, lc1,
(g->widths ? g->widths[mcc1] : g->width));
putc('\r', shout);
if (md2 != md1)
tc_downcurs(md2 - md1);
if (mc2)
tcmultout(TCRIGHT, TCMULTRIGHT, mc2);
g = mgtab[ml2 * columns + mc2];
clprintm(g, mtab[ml2 * columns + mc2], mcc2, ml2, lc2,
(g->widths ? g->widths[mcc2] : g->width));
putc('\r', shout);
if (mstatprinted) {
int i = lines - md2 - nlnct;
tc_downcurs(i - 1);
compprintfmt(NULL, 0, 1, 1, mline, NULL);
tcmultout(TCUP, TCMULTUP, lines - 1);
} else
tcmultout(TCUP, TCMULTUP, md2 + nlnct);
showinglist = -1;
listshown = 1;
}
static int
complistmatches(UNUSED(Hookdef dummy), Chdata dat)
{
static int onlnct = -1;
Cmgroup oamatches = amatches;
amatches = dat->matches;
noselect = 0;
if ((minfo.asked == 2 && mselect < 0) || nlnct >= lines) {
showinglist = 0;
amatches = oamatches;
return (noselect = 1);
}
getcols(&mcolors);
mnew = ((calclist(mselect >= 0) || mlastcols != columns ||
mlastlines != listdat.nlines) && mselect >= 0);
if (!listdat.nlines || (mselect >= 0 &&
!(isset(USEZLE) && !termflags &&
complastprompt && *complastprompt))) {
showinglist = listshown = 0;
noselect = 1;
amatches = oamatches;
return 1;
}
if (inselect || mlbeg >= 0)
clearflag = 0;
mscroll = 0;
mlistp = NULL;
queue_signals();
if (mselect >= 0 || mlbeg >= 0 ||
(mlistp = dupstring(getsparam("LISTPROMPT")))) {
unqueue_signals();
if (mlistp && !*mlistp)
mlistp = "%SAt %p: Hit TAB for more, or the character to insert%s";
trashzle();
showinglist = listshown = 0;
lastlistlen = 0;
if (mlistp) {
clearflag = (isset(USEZLE) && !termflags && dolastprompt);
mscroll = 1;
} else {
clearflag = 1;
minfo.asked = (listdat.nlines + nlnct <= lines);
}
} else {
unqueue_signals();
mlistp = NULL;
if (asklist()) {
amatches = oamatches;
return (noselect = 1);
}
}
if (mlbeg >= 0) {
mlend = mlbeg + lines - nlnct - mhasstat;
while (mline >= mlend)
mlbeg++, mlend++;
} else
mlend = 9999999;
if (mnew) {
int i;
mtab_been_reallocated = 1;
i = columns * listdat.nlines;
free(mtab);
mtab = (Cmatch **) zalloc(i * sizeof(Cmatch **));
memset(mtab, 0, i * sizeof(Cmatch **));
free(mgtab);
mgtab = (Cmgroup *) zalloc(i * sizeof(Cmgroup));
memset(mgtab, 0, i * sizeof(Cmgroup));
mlastcols = mcols = columns;
mlastlines = mlines = listdat.nlines;
}
last_cap = (char *) zhalloc(max_caplen + 1);
*last_cap = '\0';
if (!mnew && inselect && onlnct == nlnct && mlbeg >= 0 && mlbeg == molbeg)
singledraw();
else if (!compprintlist(mselect >= 0) || !clearflag)
noselect = 1;
onlnct = nlnct;
molbeg = mlbeg;
mocol = mcol;
moline = mline;
amatches = oamatches;
return noselect;
}
static int
adjust_mcol(int wish, Cmatch ***tabp, Cmgroup **grp)
{
Cmatch **tab = *tabp;
int p, n, c;
tab -= mcol;
for (p = wish; p >= 0 && (!tab[p] || mmarked(tab[p])); p--);
for (n = wish; n < mcols && (!tab[n] || mmarked(tab[n])); n++);
if (n == mcols)
n = -1;
if (p < 0) {
if (n < 0)
return 1;
c = n;
} else if (n < 0)
c = p;
else
c = ((mcol - p) < (n - mcol) ? p : n);
*tabp = tab + c;
if (grp)
*grp = *grp + c - mcol;
mcol = c;
return 0;
}
typedef struct menustack *Menustack;
struct menustack {
Menustack prev;
char *line;
Brinfo brbeg;
Brinfo brend;
int nbrbeg, nbrend;
int cs, acc, nmatches, mline, mlbeg, nolist;
struct menuinfo info;
Cmgroup amatches, pmatches, lastmatches, lastlmatches;
/*
* Status for how line looked like previously.
*/
char *origline;
int origcs, origll;
/*
* Status for interactive mode. status is the line
* printed above the matches saying what the interactive
* completion prefix is. mode says whether we are in
* interactive or some search mode.
* typed.
*/
char *status;
int mode;
};
typedef struct menusearch *Menusearch;
struct menusearch {
Menusearch prev;
char *str;
int line;
int col;
int back;
int state;
Cmatch **ptr;
};
#define MS_OK 0
#define MS_FAILED 1
#define MS_WRAPPED 2
#define MAX_STATUS 128
static char *
setmstatus(char *status, char *sline, int sll, int scs,
int *csp, int *llp, int *lenp)
{
char *p, *s, *ret = NULL;
int pl, sl, max;
METACHECK();
if (csp) {
*csp = zlemetacs;
*llp = zlemetall;
*lenp = lastend - wb;
ret = dupstring((char *) zlemetaline);
p = (char *) zhalloc(zlemetacs - wb + 1);
strncpy(p, (char *) zlemetaline + wb, zlemetacs - wb);
p[zlemetacs - wb] = '\0';
if (lastend < zlemetacs)
s = "";
else {
s = (char *) zhalloc(lastend - zlemetacs + 1);
strncpy(s, (char *) zlemetaline + zlemetacs, lastend - zlemetacs);
s[lastend - zlemetacs] = '\0';
}
zlemetacs = 0;
foredel(zlemetall);
spaceinline(sll);
memcpy(zlemetaline, sline, sll);
zlemetacs = scs;
} else {
p = complastprefix;
s = complastsuffix;
}
pl = strlen(p);
sl = strlen(s);
max = (columns < MAX_STATUS ? columns : MAX_STATUS) - 14;
if (max > 12) {
int h = (max - 2) >> 1;
strcpy(status, "interactive: ");
if (pl > h - 3) {
strcat(status, "...");
strcat(status, p + pl - h - 3);
} else
strcat(status, p);
strcat(status, "[]");
if (sl > h - 3) {
strncat(status, s, h - 3);
strcat(status, "...");
} else
strcat(status, s);
}
return ret;
}
static Menusearch msearchstack;
static char *msearchstr = NULL;
static int msearchstate;
static void
msearchpush(Cmatch **p, int back)
{
Menusearch s = (Menusearch) zhalloc(sizeof(struct menusearch));
s->prev = msearchstack;
msearchstack = s;
s->str = dupstring(msearchstr);
s->line = mline;
s->col = mcol;
s->back = back;
s->state = msearchstate;
s->ptr = p;
}
static Cmatch **
msearchpop(int *backp)
{
Menusearch s = msearchstack;
if (s->prev)
msearchstack = s->prev;
msearchstr = s->str;
mline = s->line;
mcol = s->col;
msearchstate = s->state;
*backp = s->back;
return s->ptr;
}
static Cmatch **
msearch(Cmatch **ptr, int ins, int back, int rep, int *wrapp)
{
#ifdef ZLE_UNICODE_SUPPORT
/* MB_CUR_MAX may not be constant */
VARARR(char, s, MB_CUR_MAX+1);
#else
char s[2];
#endif
Cmatch **p, *l = NULL, m;
int x = mcol, y = mline;
int ex, ey, wrap = 0, owrap = (msearchstate & MS_WRAPPED);
msearchpush(ptr, back);
if (ins) {
#ifdef ZLE_UNICODE_SUPPORT
if (lastchar_wide_valid)
{
int len = wctomb(s, lastchar_wide);
if (len < 0)
len = 0;
s[len] = '\0';
} else
#endif
{
s[0] = lastchar;
s[1] = '\0';
}
msearchstr = dyncat(msearchstr, s);
}
if (back) {
ex = mcols - 1;
ey = -1;
} else {
ex = 0;
ey = listdat.nlines;
}
p = mtab + (mline * mcols) + mcol;
if (rep)
l = *p;
while (1) {
if (!rep && mtunmark(*p) && *p != l) {
l = *p;
m = *mtunmark(*p);
if (strstr((m->disp ? m->disp : m->str), msearchstr)) {
mcol = x;
mline = y;
return p;
}
}
rep = 0;
if (back) {
p--;
if (--x < 0) {
x = mcols - 1;
y--;
}
} else {
p++;
if (++x == mcols) {
x = 0;
y++;
}
}
if (x == ex && y == ey) {
if (wrap) {
msearchstate = MS_FAILED | owrap;
break;
}
msearchstate |= MS_WRAPPED;
if (back) {
x = mcols - 1;
y = listdat.nlines - 1;
p = mtab + (y * mcols) + x;
} else {
x = y = 0;
p = mtab;
}
ex = mcol;
ey = mline;
wrap = 1;
*wrapp = 1;
}
}
return NULL;
}
/*
* Values to assign to mode: interactive, etc.
*/
#define MM_INTER 1
#define MM_FSEARCH 2
#define MM_BSEARCH 3
static int
domenuselect(Hookdef dummy, Chdata dat)
{
static Chdata fdat = NULL;
static char *lastsearch = NULL;
Cmatch **p;
Cmgroup *pg;
Thingy cmd = 0;
int do_last_key = 0;
Menustack u = NULL;
int i = 0, acc = 0, wishcol = 0, setwish = 0, oe = onlyexpl, wasnext = 0;
int space, lbeg = 0, step = 1, wrap, pl = nlnct, broken = 0, first = 1;
int nolist = 0, mode = 0, modecs, modell, modelen, wasmeta;
char *s;
char status[MAX_STATUS], *modeline = NULL;
msearchstack = NULL;
msearchstr = "";
msearchstate = MS_OK;
status[0] = '\0';
queue_signals();
if (fdat || (dummy && (!(s = getsparam("MENUSELECT")) ||
(dat && dat->num < atoi(s))))) {
if (fdat) {
fdat->matches = dat->matches;
fdat->num = dat->num;
fdat->nmesg = dat->nmesg;
}
unqueue_signals();
return 0;
}
/*
* Lots of the logic here doesn't really make sense if the
* line isn't metafied, but the evidence was that only used
* to be metafied locally in a couple of places.
* It's horrifically difficult to work out where the line
* is metafied, so I've resorted to the following.
* Unfortunately we need to unmetatfy in zrefresh() when
* we want to display something. Maybe this function can
* be done better.
*/
if (zlemetaline != NULL)
wasmeta = 1;
else {
wasmeta = 0;
metafy_line();
}
if ((s = getsparam("MENUSCROLL"))) {
if (!(step = mathevali(s)))
step = (lines - nlnct) >> 1;
else if (step < 0)
if ((step += lines - nlnct) < 0)
step = 1;
}
if ((s = getsparam("MENUMODE"))) {
if (!strcmp(s, "interactive")) {
int l = strlen(origline);
/*
* In interactive completion mode we don't insert
* the completion onto the command line, instead
* we show just what the user has typed and
* the match so far underneath (stored in "status").
* So put the command line back to how it
* was before completion started.
*/
mode = MM_INTER;
zlemetacs = 0;
foredel(zlemetall);
spaceinline(l);
strncpy((char *) zlemetaline, origline, l);
zlemetacs = origcs;
setmstatus(status, NULL, 0 , 0, NULL, NULL, NULL);
} else if (strpfx("search", s)) {
mode = (strstr(s, "back") ? MM_BSEARCH : MM_FSEARCH);
}
}
if ((mstatus = dupstring(getsparam("MENUPROMPT"))) && !*mstatus)
mstatus = "%SScrolling active: current selection at %p%s";
unqueue_signals();
mhasstat = (mstatus && *mstatus);
fdat = dat;
selectlocalmap(mskeymap);
noselect = 1;
while ((menuacc &&
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
((*minfo.cur)->flags & CMF_DUMMY) ||
(((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
(!(*minfo.cur)->str || !*(*minfo.cur)->str)))
do_menucmp(0);
mselect = (*(minfo.cur))->gnum;
mline = 0;
mlines = 999999;
mlbeg = 0;
molbeg = -42;
for (;;) {
mtab_been_reallocated = 0;
if (mline < 0) {
int x, y;
Cmatch **p = mtab;
for (y = 0; y < mlines; y++) {
for (x = mcols; x; x--, p++)
if (*p && !mmarked(*p) && **p && mselect == (**p)->gnum)
break;
if (x) {
mcol = mcols - x;
break;
}
}
if (y < mlines)
mline = y;
}
while (mline < mlbeg)
if ((mlbeg -= step) < 0)
mlbeg = 0;
if (mlbeg && lbeg != mlbeg) {
Cmatch **p = mtab + ((mlbeg - 1) * columns), **q;
int c;
while (mlbeg) {
for (q = p, c = columns; c; q++, c--)
if (*q && !mmarked(*q))
break;
if (c)
break;
p -= columns;
mlbeg--;
}
}
if ((space = lines - pl - mhasstat))
while (mline >= mlbeg + space)
if ((mlbeg += step) + space > mlines)
mlbeg = mlines - space;
if (lbeg != mlbeg) {
Cmatch **p = mtab + (mlbeg * columns), **q;
int c;
while (mlbeg < mlines) {
for (q = p, c = columns; c; q++, c--)
if (*q)
break;
if (c)
break;
p += columns;
mlbeg++;
}
}
lbeg = mlbeg;
onlyexpl = 0;
showinglist = -2;
if (first && !listshown && isset(LISTBEEP))
zbeep();
if (first) {
/*
* remember the original data that we will use when
* performing interactive completion to restore the
* command line when a menu completion is inserted.
* this is because menu completion will insert
* the next match in the loop; for interactive
* completion we don't want that, we always want to
* be able to type the next character.
*/
modeline = dupstring((char *)zlemetaline);
modecs = zlemetacs;
modell = zlemetall;
modelen = minfo.len;
}
first = 0;
if (mode == MM_INTER) {
statusline = stringaszleline((unsigned char *)status, 0,
&statusll, NULL, NULL);
} else if (mode) {
int l = sprintf(status, "%s%sisearch%s: ",
((msearchstate & MS_FAILED) ? "failed " : ""),
((msearchstate & MS_WRAPPED) ? "wrapped " : ""),
(mode == MM_FSEARCH ? "" : " backward"));
strncat(status, msearchstr, MAX_STATUS - l - 1);
statusline = stringaszleline((unsigned char *)status, 0,
&statusll, NULL, NULL);
} else {
statusline = NULL;
statusll = 0;
}
zrefresh();
if (statusline) {
free(statusline);
statusline = NULL;
statusll = 0;
}
inselect = 1;
if (noselect) {
broken = 1;
break;
}
selected = 1;
if (!i) {
i = mcols * mlines;
while (i--)
if (mtab[i])
break;
if (!i)
break;
i = 1;
}
p = mmtabp;
pg = mgtabp;
minfo.cur = *p;
minfo.group = *pg;
if (setwish)
wishcol = mcol;
else if (mcol > wishcol) {
while (mcol > 0 && p[-1] == minfo.cur)
mcol--, p--, pg--;
} else if (mcol < wishcol) {
while (mcol < mcols - 1 && p[1] == minfo.cur)
mcol++, p++, pg++;
}
setwish = wasnext = 0;
getk:
if (!do_last_key) {
cmd = getkeycmd();
if (mtab_been_reallocated) {
do_last_key = 1;
continue;
}
}
do_last_key = 0;
if (!cmd || cmd == Th(z_sendbreak)) {
zbeep();
molbeg = -1;
break;
} else if (nolist && cmd != Th(z_undo) &&
(!mode || (cmd != Th(z_backwarddeletechar) &&
cmd != Th(z_selfinsert) &&
cmd != Th(z_selfinsertunmeta)))) {
ungetkeycmd();
break;
} else if (cmd == Th(z_acceptline)) {
if (mode == MM_FSEARCH || mode == MM_BSEARCH) {
mode = 0;
continue;
}
acc = 1;
break;
} else if (cmd == Th(z_viinsert)) {
if (mode == MM_INTER)
mode = 0;
else {
int l = strlen(origline);
/*
* Entering interactive completion mode:
* same code as when we enter it on menu selection
* start.
*/
mode = MM_INTER;
zlemetacs = 0;
foredel(zlemetall);
spaceinline(l);
strncpy((char *) zlemetaline, origline, l);
zlemetacs = origcs;
setmstatus(status, NULL, 0, 0, NULL, NULL, NULL);
continue;
}
} else if (cmd == Th(z_acceptandinfernexthistory) ||
(mode == MM_INTER && (cmd == Th(z_selfinsert) ||
cmd == Th(z_selfinsertunmeta)))) {
char *saveline = NULL;
int savell = 0;
int savecs = 0;
Menustack s = (Menustack) zhalloc(sizeof(*s));
s->prev = u;
u = s;
s->line = dupstring((char *) zlemetaline);
s->cs = zlemetacs;
s->mline = mline;
s->mlbeg = mlbeg;
memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
s->amatches = amatches;
s->pmatches = pmatches;
s->lastmatches = lastmatches;
s->lastlmatches = lastlmatches;
s->nolist = nolist;
s->acc = menuacc;
s->brbeg = dupbrinfo(brbeg, NULL, 1);
s->brend = dupbrinfo(brend, NULL, 1);
s->nbrbeg = nbrbeg;
s->nbrend = nbrend;
s->nmatches = nmatches;
s->origline = origline;
s->origcs = origcs;
s->origll = origll;
s->status = dupstring(status);
s->mode = mode;
menucmp = menuacc = hasoldlist = 0;
minfo.cur = NULL;
fixsuffix();
handleundo();
validlist = 0;
amatches = pmatches = lastmatches = NULL;
invalidate_list();
iforcemenu = 1;
comprecursive = 1;
if (cmd != Th(z_acceptandinfernexthistory)) {
int l = strlen(origline);
/*
* Interactive mode: we need to restore the
* line, add the character, then remember how
* this new line looks in order to keep
* the command line as it is with just the
* characters typed by the user.
*/
zlemetacs = 0;
foredel(zlemetall);
spaceinline(l);
strncpy((char *) zlemetaline, origline, l);
zlemetacs = origcs;
if (cmd == Th(z_selfinsert))
selfinsert(zlenoargs);
else
selfinsertunmeta(zlenoargs);
saveline = (char *) zhalloc(zlemetall);
memcpy(saveline, zlemetaline, zlemetall);
savell = zlemetall;
savecs = zlemetacs;
iforcemenu = -1;
} else
mode = 0;
/* Nested completion assumes line is unmetafied */
unmetafy_line();
menucomplete(zlenoargs);
metafy_line();
iforcemenu = 0;
if (cmd != Th(z_acceptandinfernexthistory))
modeline = setmstatus(status, saveline, savell, savecs,
&modecs, &modell, &modelen);
if (nmatches < 1 || !minfo.cur || !*(minfo.cur)) {
nolist = 1;
if (mode == MM_INTER) {
statusline = stringaszleline((unsigned char *)status, 0,
&statusll, NULL, NULL);
} else {
/* paranoia */
statusline = NULL;
statusll = 0;
}
if (nmessages) {
showinglist = -2;
zrefresh();
} else {
trashzle();
zsetterm();
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
fputs("no matches\r", shout);
fflush(shout);
tcmultout(TCUP, TCMULTUP, nlnct);
showinglist = clearlist = 0;
clearflag = 1;
zrefresh();
showinglist = clearlist = 0;
}
if (statusline) {
free(statusline);
statusline = NULL;
statusll = 0;
}
goto getk;
}
clearlist = listshown = 1;
mselect = (*(minfo.cur))->gnum;
setwish = wasnext = 1;
mline = 0;
molbeg = -42;
continue;
} else if (cmd == Th(z_acceptandhold) ||
cmd == Th(z_acceptandmenucomplete)) {
Menustack s = (Menustack) zhalloc(sizeof(*s));
int ol;
mode = 0;
s->prev = u;
u = s;
s->line = dupstring((char *) zlemetaline);
s->cs = zlemetacs;
s->mline = mline;
s->mlbeg = mlbeg;
memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
s->amatches = s->pmatches =
s->lastmatches = s->lastlmatches = NULL;
s->nolist = nolist;
s->acc = menuacc;
s->brbeg = dupbrinfo(brbeg, NULL, 1);
s->brend = dupbrinfo(brend, NULL, 1);
s->nbrbeg = nbrbeg;
s->nbrend = nbrend;
s->nmatches = nmatches;
s->origline = origline;
s->origcs = origcs;
s->origll = origll;
s->status = dupstring(status);
s->mode = mode;
accept_last();
handleundo();
comprecursive = 1;
do_menucmp(0);
mselect = (*(minfo.cur))->gnum;
p -= mcol;
mcol = 0;
ol = mline;
do {
for (mcol = 0; mcol < mcols; mcol++, p++)
if (*p == minfo.cur)
break;
if (mcol != mcols)
break;
if (++mline == mlines) {
mline = 0;
p -= mlines * mcols;
}
} while (mline != ol);
if (*p != minfo.cur) {
noselect = clearlist = listshown = 1;
onlyexpl = 0;
zrefresh();
break;
}
setwish = 1;
continue;
} else if (cmd == Th(z_undo) ||
(mode == MM_INTER && cmd == Th(z_backwarddeletechar))) {
int l;
if (!u)
break;
handleundo();
zlemetacs = 0;
foredel(zlemetall);
spaceinline(l = strlen(u->line));
strncpy((char *) zlemetaline, u->line, l);
zlemetacs = u->cs;
menuacc = u->acc;
memcpy(&minfo, &(u->info), sizeof(struct menuinfo));
p = &(minfo.cur);
mline = u->mline;
mlbeg = u->mlbeg;
if (u->lastmatches && lastmatches != u->lastmatches) {
if (lastmatches)
freematches(lastmatches, 0);
amatches = u->amatches;
pmatches = u->pmatches;
lastmatches = u->lastmatches;
lastlmatches = u->lastlmatches;
nmatches = u->nmatches;
hasoldlist = validlist = 1;
}
freebrinfo(brbeg);
freebrinfo(brend);
brbeg = dupbrinfo(u->brbeg, &lastbrbeg, 0);
brend = dupbrinfo(u->brend, &lastbrend, 0);
nbrbeg = u->nbrbeg;
nbrend = u->nbrend;
origline = u->origline;
origcs = u->origcs;
origll = u->origll;
strcpy(status, u->status);
mode = u->mode;
nolist = u->nolist;
u = u->prev;
clearlist = 1;
setwish = 1;
listdat.valid = 0;
molbeg = -42;
if (nolist) {
if (mode == MM_INTER) {
statusline = stringaszleline((unsigned char *)status, 0,
&statusll, NULL, NULL);
} else {
/* paranoia */
statusline = NULL;
statusll = 0;
}
zrefresh();
if (statusline) {
free(statusline);
statusline = NULL;
statusll = 0;
}
goto getk;
}
if (mode)
continue;
} else if (cmd == Th(z_redisplay)) {
redisplay(zlenoargs);
molbeg = -42;
continue;
} else if (cmd == Th(z_clearscreen)) {
clearscreen(zlenoargs);
molbeg = -42;
continue;
} else if (cmd == Th(z_downhistory) ||
cmd == Th(z_downlineorhistory) ||
cmd == Th(z_downlineorsearch) ||
cmd == Th(z_vidownlineorhistory)) {
int omline;
Cmatch **op;
mode = 0;
wrap = 0;
down:
omline = mline;
op = p;
do {
if (mline == mlines - 1) {
if (wrap & 2) {
mline = omline;
p = op;
break;
}
p -= mline * mcols;
mline = 0;
wrap |= 1;
} else {
mline++;
p += mcols;
}
if (adjust_mcol(wishcol, &p, NULL))
continue;
} while (!*p || mmarked(*p));
if (wrap == 1)
goto right;
} else if (cmd == Th(z_uphistory) ||
cmd == Th(z_uplineorhistory) ||
cmd == Th(z_uplineorsearch) ||
cmd == Th(z_viuplineorhistory)) {
int omline;
Cmatch **op;
mode = 0;
wrap = 0;
up:
omline = mline;
op = p;
do {
if (!mline) {
if (wrap & 2) {
mline = omline;
p = op;
break;
}
mline = mlines - 1;
p += mline * mcols;
wrap |= 1;
} else {
mline--;
p -= mcols;
}
if (adjust_mcol(wishcol, &p, NULL))
continue;
} while (!*p || mmarked(*p));
if (wrap == 1) {
if (mcol == wishcol)
goto left;
wishcol = mcol;
}
} else if (cmd == Th(z_emacsforwardword) ||
cmd == Th(z_viforwardword) ||
cmd == Th(z_viforwardwordend) ||
cmd == Th(z_forwardword)) {
int i = lines - pl - 1, oi = i, ll = 0;
Cmatch **lp = NULL;
mode = 0;
if (mline == mlines - 1)
goto top;
while (i > 0) {
if (mline == mlines - 1) {
if (i != oi && lp)
break;
goto top;
} else {
mline++;
p += mcols;
}
if (adjust_mcol(wishcol, &p, NULL))
continue;
if (*p && !mmarked(*p)) {
i--;
lp = p;
ll = mline;
}
}
p = lp;
mline = ll;
} else if (cmd == Th(z_emacsbackwardword) ||
cmd == Th(z_vibackwardword) ||
cmd == Th(z_backwardword)) {
int i = lines - pl - 1, oi = i, ll = 0;
Cmatch **lp = NULL;
mode = 0;
if (!mline)
goto bottom;
while (i > 0) {
if (!mline) {
if (i != oi && lp)
break;
goto bottom;
} else {
mline--;
p -= mcols;
}
if (adjust_mcol(wishcol, &p, NULL))
continue;
if (*p || !mmarked(*p)) {
i--;
lp = p;
ll = mline;
}
}
p = lp;
mline = ll;
} else if (cmd == Th(z_beginningofhistory)) {
int ll;
Cmatch **lp;
mode = 0;
top:
ll = mline;
lp = p;
while (mline) {
mline--;
p -= mcols;
if (adjust_mcol(wishcol, &p, NULL))
continue;
if (*p && !mmarked(*p)) {
lp = p;
ll = mline;
}
}
mline = ll;
p = lp;
} else if (cmd == Th(z_endofhistory)) {
int ll;
Cmatch **lp;
mode = 0;
bottom:
ll = mline;
lp = p;
while (mline < mlines - 1) {
mline++;
p += mcols;
if (adjust_mcol(wishcol, &p, NULL))
continue;
if (*p && !mmarked(*p)) {
lp = p;
ll = mline;
}
}
mline = ll;
p = lp;
} else if (cmd == Th(z_forwardchar) || cmd == Th(z_viforwardchar)) {
int omcol;
Cmatch **op;
mode = 0;
wrap = 0;
right:
omcol = mcol;
op = p;
do {
if (mcol == mcols - 1) {
if (wrap & 1) {
p = op;
mcol = omcol;
break;
}
p -= mcol;
mcol = 0;
wrap |= 2;
} else {
mcol++;
p++;
}
} while (!*p || mmarked(*p) || (mcol != omcol && *p == *op));
wishcol = mcol;
if (wrap == 2)
goto down;
} else if (cmd == Th(z_backwardchar) || cmd == Th(z_vibackwardchar)) {
int omcol;
Cmatch **op;
mode = 0;
wrap = 0;
left:
omcol = mcol;
op = p;
do {
if (!mcol) {
if (wrap & 1) {
p = op;
mcol = omcol;
break;
}
mcol = mcols - 1;
p += mcol;
wrap |= 2;
} else {
mcol--;
p--;
}
} while (!*p || mmarked(*p) || (mcol != omcol && *p == *op));
wishcol = mcol;
if (wrap == 2) {
p += mcols - 1 - mcol;
wishcol = mcol = mcols - 1;
adjust_mcol(wishcol, &p, NULL);
goto up;
}
} else if (cmd == Th(z_beginningofbufferorhistory) ||
cmd == Th(z_beginningofline) ||
cmd == Th(z_beginningoflinehist) ||
cmd == Th(z_vibeginningofline)) {
mode = 0;
p -= mcol;
mcol = 0;
while (!*p || mmarked(*p)) {
mcol++;
p++;
}
wishcol = 0;
} else if (cmd == Th(z_endofbufferorhistory) ||
cmd == Th(z_endofline) ||
cmd == Th(z_endoflinehist) ||
cmd == Th(z_viendofline)) {
mode = 0;
p += mcols - mcol - 1;
mcol = mcols - 1;
while (!*p || mmarked(*p)) {
mcol--;
p--;
}
wishcol = mcols - 1;
} else if (cmd == Th(z_viforwardblankword) ||
cmd == Th(z_viforwardblankwordend)) {
Cmgroup g = *pg;
int ol = mline;
mode = 0;
do {
if (mline == mlines - 1) {
p -= mline * mcols;
pg -= mline * mcols;
mline = 0;
} else {
mline++;
p += mcols;
pg += mcols;
}
if (adjust_mcol(wishcol, &p, &pg))
continue;
} while (ol != mline && (*pg == g || !*pg || mmarked(*pg)));
} else if (cmd == Th(z_vibackwardblankword)) {
Cmgroup g = *pg;
int ol = mline;
mode = 0;
do {
if (!mline) {
mline = mlines - 1;
p += mline * mcols;
pg += mline * mcols;
} else {
mline--;
p -= mcols;
pg -= mcols;
}
if (adjust_mcol(wishcol, &p, &pg))
continue;
} while (ol != mline && (*pg == g || !*pg || mmarked(*pg)));
} else if (cmd == Th(z_completeword) ||
cmd == Th(z_expandorcomplete) ||
cmd == Th(z_expandorcompleteprefix) ||
cmd == Th(z_menucomplete) ||
cmd == Th(z_menuexpandorcomplete) ||
!strcmp(cmd->nam, "menu-select") ||
!strcmp(cmd->nam, "complete-word") ||
!strcmp(cmd->nam, "expand-or-complete") ||
!strcmp(cmd->nam, "expand-or-complete-prefix") ||
!strcmp(cmd->nam, "menu-complete") ||
!strcmp(cmd->nam, "menu-expand-or-complete")) {
if (mode == MM_INTER) {
/*
* do_menucmp() has inserted the completion onto
* the command line. In interactive mode we
* don't want that, just what the user typed,
* so restore the information.
*/
origline = modeline;
origcs = modecs;
origll = modell;
zlemetacs = 0;
foredel(zlemetall);
spaceinline(origll);
strncpy((char *) zlemetaline, origline, origll);
zlemetacs = origcs;
minfo.len = modelen;
} else {
mode = 0;
comprecursive = 1;
do_menucmp(0);
mselect = (*(minfo.cur))->gnum;
setwish = 1;
mline = -1;
}
continue;
} else if (cmd == Th(z_reversemenucomplete) ||
!strcmp(cmd->nam, "reverse-menu-complete")) {
mode = 0;
comprecursive = 1;
reversemenucomplete(zlenoargs);
mselect = (*(minfo.cur))->gnum;
setwish = 1;
mline = -1;
continue;
} else if (cmd == Th(z_historyincrementalsearchforward) ||
cmd == Th(z_historyincrementalsearchbackward) ||
((mode == MM_FSEARCH || mode == MM_BSEARCH) &&
(cmd == Th(z_selfinsert) ||
cmd == Th(z_selfinsertunmeta)))) {
Cmatch **np, **op = p;
int was = (mode == MM_FSEARCH || mode == MM_BSEARCH);
int ins = (cmd == Th(z_selfinsert) || cmd == Th(z_selfinsertunmeta));
int back = (cmd == Th(z_historyincrementalsearchbackward));
int wrap;
do {
if (was) {
p += wishcol - mcol;
mcol = wishcol;
}
if (!ins) {
if (was) {
if (!*msearchstr && lastsearch) {
msearchstr = dupstring(lastsearch);
mode = 0;
}
} else {
msearchstr = "";
msearchstack = NULL;
}
}
if (cmd == Th(z_selfinsertunmeta)) {
fixunmeta();
}
wrap = 0;
np = msearch(p, ins, (ins ? (mode == MM_BSEARCH) : back),
(was && !ins), &wrap);
if (!ins)
mode = (back ? MM_BSEARCH : MM_FSEARCH);
if (*msearchstr) {
zsfree(lastsearch);
lastsearch = ztrdup(msearchstr);
}
if (np) {
wishcol = mcol;
p = np;
}
adjust_mcol(wishcol, &p, NULL);
} while ((back || cmd == Th(z_historyincrementalsearchforward)) &&
np && !wrap && was && **p == **op);
} else if ((mode == MM_FSEARCH || mode == MM_BSEARCH) &&
cmd == Th(z_backwarddeletechar)) {
int back;
Cmatch **np = msearchpop(&back);
mode = (back ? MM_BSEARCH : MM_FSEARCH);
wishcol = mcol;
if (np) {
p = np;
adjust_mcol(wishcol, &p, NULL);
}
} else if (cmd == Th(z_undefinedkey)) {
mode = 0;
continue;
} else {
ungetkeycmd();
if (cmd->widget && (cmd->widget->flags & WIDGET_NCOMP)) {
acc = 0;
broken = 2;
} else
acc = 1;
break;
}
do_single(**p);
mselect = (**p)->gnum;
}
if (u)
for (; u; u = u->prev)
if (u->lastmatches != lastmatches)
freematches(u->lastmatches, 0);
selectlocalmap(NULL);
mselect = mlastcols = mlastlines = -1;
mstatus = NULL;
inselect = mhasstat = 0;
if (nolist)
clearlist = listshown = 1;
if (acc && validlist && minfo.cur) {
menucmp = lastambig = hasoldlist = 0;
do_single(*(minfo.cur));
}
if (wasnext || broken) {
menucmp = 2;
showinglist = ((validlist && !nolist) ? -2 : 0);
minfo.asked = 0;
if (!noselect) {
int nos = noselect;
zrefresh();
noselect = nos;
}
}
if (!noselect && (!dat || acc)) {
showinglist = ((validlist && !nolist) ? -2 : 0);
onlyexpl = oe;
if (!smatches)
clearlist = listshown = 1;
zrefresh();
}
mlbeg = -1;
fdat = NULL;
if (!wasmeta)
unmetafy_line();
return (broken == 2 ? 3 :
((dat && !broken) ? (acc ? 1 : 2) : (!noselect ^ acc)));
}
/* The widget function. */
static int
menuselect(char **args)
{
int d = 0;
if (!minfo.cur) {
selected = 0;
menucomplete(args);
if ((minfo.cur && minfo.asked == 2) || selected)
return 0;
d = 1;
}
if (minfo.cur && (minfo.asked == 2 || domenuselect(NULL, NULL)) && !d)
menucomplete(args);
return 0;
}
/**/
int
setup_(UNUSED(Module m))
{
return 0;
}
/**/
int
boot_(Module m)
{
mtab = NULL;
mgtab = NULL;
mselect = -1;
inselect = 0;
w_menuselect = addzlefunction("menu-select", menuselect,
ZLE_MENUCMP|ZLE_KEEPSUFFIX|ZLE_ISCOMP);
if (!w_menuselect) {
zwarnnam(m->nam, "name clash when adding ZLE function `menu-select'",
NULL, 0);
return -1;
}
addhookfunc("comp_list_matches", (Hookfn) complistmatches);
addhookfunc("menu_start", (Hookfn) domenuselect);
mskeymap = newkeymap(NULL, "menuselect");
linkkeymap(mskeymap, "menuselect", 1);
bindkey(mskeymap, "\t", refthingy(t_completeword), NULL);
bindkey(mskeymap, "\n", refthingy(t_acceptline), NULL);
bindkey(mskeymap, "\r", refthingy(t_acceptline), NULL);
bindkey(mskeymap, "\33[A", refthingy(t_uplineorhistory), NULL);
bindkey(mskeymap, "\33[B", refthingy(t_downlineorhistory), NULL);
bindkey(mskeymap, "\33[C", refthingy(t_forwardchar), NULL);
bindkey(mskeymap, "\33[D", refthingy(t_backwardchar), NULL);
bindkey(mskeymap, "\33OA", refthingy(t_uplineorhistory), NULL);
bindkey(mskeymap, "\33OB", refthingy(t_downlineorhistory), NULL);
bindkey(mskeymap, "\33OC", refthingy(t_forwardchar), NULL);
bindkey(mskeymap, "\33OD", refthingy(t_backwardchar), NULL);
lskeymap = newkeymap(NULL, "listscroll");
linkkeymap(lskeymap, "listscroll", 1);
bindkey(lskeymap, "\t", refthingy(t_completeword), NULL);
bindkey(lskeymap, " ", refthingy(t_completeword), NULL);
bindkey(lskeymap, "\n", refthingy(t_acceptline), NULL);
bindkey(lskeymap, "\r", refthingy(t_acceptline), NULL);
bindkey(lskeymap, "\33[B", refthingy(t_downlineorhistory), NULL);
bindkey(lskeymap, "\33OB", refthingy(t_downlineorhistory), NULL);
return 0;
}
/**/
int
cleanup_(UNUSED(Module m))
{
free(mtab);
free(mgtab);
deletezlefunction(w_menuselect);
deletehookfunc("comp_list_matches", (Hookfn) complistmatches);
deletehookfunc("menu_start", (Hookfn) domenuselect);
unlinkkeymap("menuselect", 1);
unlinkkeymap("listscroll", 1);
return 0;
}
/**/
int
finish_(UNUSED(Module m))
{
return 0;
}