summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Wooding <kjell@cvs.openbsd.org>2005-11-11 18:40:02 +0000
committerKjell Wooding <kjell@cvs.openbsd.org>2005-11-11 18:40:02 +0000
commitc1749f7ff4b250d02c61a4ffd9d96d0e79189af3 (patch)
treea2cd9576055a3257ac94cb57df5b9cff5b479807
parent813f43d85161abd7f1d3819c4a1a8782d0751bf7 (diff)
Enable some of the more common editing keybindings in the minibuffer.
i.e. left, right, ^B, ^F, ^Y, ^K, ^A, ^E Also, make completions work as you would expect them to i.e. a *Completions* buffer pops up with your choices in it when you hit a second TAB or SP. It's ugly, but it works. ok deraadt.
-rw-r--r--usr.bin/mg/echo.c258
1 files changed, 213 insertions, 45 deletions
diff --git a/usr.bin/mg/echo.c b/usr.bin/mg/echo.c
index bfcc7b09276..cbf0f7c1320 100644
--- a/usr.bin/mg/echo.c
+++ b/usr.bin/mg/echo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: echo.c,v 1.37 2005/10/11 00:46:46 kjell Exp $ */
+/* $OpenBSD: echo.c,v 1.38 2005/11/11 18:40:01 kjell Exp $ */
/* This file is in the public domain. */
@@ -18,9 +18,10 @@
#include "funmap.h"
#include <stdarg.h>
+#include <term.h>
static char *veread(const char *, char *, size_t, int, va_list);
-static int complt(int, int, char *, size_t, int);
+static int complt(int, int, char *, size_t, int, int *);
static int complt_list(int, int, char *, int);
static void eformat(const char *, va_list);
static void eputi(int, int);
@@ -141,8 +142,19 @@ eread(const char *fmt, char *buf, size_t nbuf, int flag, ...)
static char *
veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
{
- int cpos, dynbuf = (buf == NULL);
- int c, i;
+ int dynbuf = (buf == NULL);
+ int cpos, epos; /* cursor, end position in buf */
+ int c, i, y;
+ int cplflag = FALSE; /* display completion list */
+ int cwin = FALSE; /* completion list created */
+ int mr = 0; /* match left arrow */
+ int ml = 0; /* match right arrow */
+ int esc = 0; /* position in esc pattern */
+ BUFFER *bp; /* completion list buffer */
+ MGWIN *wp; /* window for compl list */
+ int match; /* esc match found */
+ int cc, rr; /* saved ttcol, ttrow */
+ char *ret; /* return value */
#ifndef NO_MACRO
if (inmacro) {
@@ -157,7 +169,10 @@ veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
return (buf);
}
#endif /* !NO_MACRO */
- cpos = 0;
+ epos = cpos = 0;
+ ml = mr = esc = 0;
+ cplflag = FALSE;
+
if ((flag & EFNEW) != 0 || ttrow != nrow - 1) {
ttcolor(CTEXT);
ttmove(nrow - 1, 0);
@@ -169,38 +184,156 @@ veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
if (buf == NULL)
return (NULL);
eputs(buf);
- cpos += strlen(buf);
+ epos = cpos += strlen(buf);
}
tteeol();
ttflush();
for (;;) {
c = getkey(FALSE);
if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
- cpos += complt(flag, c, buf, nbuf, cpos);
+ if (cplflag == TRUE) {
+ complt_list(flag, c, buf, cpos);
+ cwin = TRUE;
+ } else if (complt(flag, c, buf, nbuf, epos, &i) == TRUE) {
+ cplflag = TRUE;
+ epos += i;
+ cpos = epos;
+ }
continue;
}
- if ((flag & EFAUTO) != 0 && c == '?') {
- complt_list(flag, c, buf, cpos);
- continue;
+ cplflag = FALSE;
+
+ if (esc > 0) { /* ESC sequence started */
+ match = 0;
+ if (ml == esc && key_left[ml] && c == key_left[ml]) {
+ match++;
+ if (key_left[++ml] == '\0') {
+ c = CCHR('B');
+ esc = 0;
+ }
+ }
+ if (mr == esc && key_right[mr] && c == key_right[mr]) {
+ match++;
+ if (key_right[++mr] == '\0') {
+ c = CCHR('F');
+ esc = 0;
+ }
+ }
+ if (match == 0) {
+ esc = 0;
+ continue;
+ /* hack. how do we know esc pattern is done? */
+ }
+ if (esc > 0) {
+ esc++;
+ continue;
+ }
}
- switch (c) {
+ switch (c) {
+ case CCHR('A'): /* start of line */
+ while (cpos > 0) {
+ if (ISCTRL(buf[--cpos]) != FALSE) {
+ ttputc('\b');
+ --ttcol;
+ }
+ ttputc('\b');
+ --ttcol;
+ }
+ ttflush();
+ break;
+ case CCHR('D'):
+ if (cpos != epos) {
+ tteeol();
+ y = buf[cpos];
+ epos--;
+ rr = ttrow;
+ cc = ttcol;
+ for (i = cpos; i < epos; i++) {
+ buf[i] = buf[i + 1];
+ eputc(buf[i]);
+ }
+ ttmove(rr, cc);
+ ttflush();
+ }
+ break;
+ case CCHR('E'): /* end of line */
+ while (cpos < epos) {
+ eputc(buf[cpos++]);
+ }
+ ttflush();
+ break;
+ case CCHR('B'): /* back */
+ if (cpos > 0) {
+ if (ISCTRL(buf[--cpos]) != FALSE) {
+ ttputc('\b');
+ --ttcol;
+ }
+ ttputc('\b');
+ --ttcol;
+ ttflush();
+ }
+ break;
+ case CCHR('F'): /* forw */
+ if (cpos < epos) {
+ eputc(buf[cpos++]);
+ ttflush();
+ }
+ break;
+ case CCHR('Y'): /* yank from kill buffer */
+ i = 0;
+ while ((y = kremove(i++)) >= 0 && y != '\n') {
+ int t;
+ if (dynbuf && epos + 1 >= nbuf) {
+ void *newp;
+ size_t newsize = epos + epos + 16;
+ if ((newp = realloc(buf, newsize))
+ == NULL)
+ goto fail;
+ buf = newp;
+ nbuf = newsize;
+ }
+ for (t = epos; t > cpos; t--)
+ buf[t] = buf[t - 1];
+ buf[cpos++] = (char)y;
+ epos++;
+ eputc((char)y);
+ cc = ttcol;
+ rr = ttrow;
+ for (t = cpos; t < epos; t++)
+ eputc(buf[t]);
+ ttmove(rr, cc);
+ }
+ ttflush();
+ break;
+ case CCHR('K'): /* copy here-EOL to kill buffer */
+ kdelete();
+ for (i = cpos; i < epos; i++)
+ kinsert(buf[i], KFORW);
+ tteeol();
+ epos = cpos;
+ ttflush();
+ break;
+ case CCHR('['):
+ ml = mr = esc = 1;
+ break;
case CCHR('J'):
c = CCHR('M');
/* FALLTHROUGH */
case CCHR('M'): /* return, done */
/* if there's nothing in the minibuffer, abort */
- if (cpos == 0 && !(flag & EFNUL)) {
+ if (epos == 0 && !(flag & EFNUL)) {
(void)ctrlg(FFRAND, 0);
ttflush();
return (NULL);
}
if ((flag & EFFUNC) != 0) {
- if ((i = complt(flag, c, buf, nbuf, cpos)) == 0)
+ if (complt(flag, c, buf, nbuf, epos, &i)
+ == FALSE)
continue;
if (i > 0)
- cpos += i;
+ epos += i;
}
- buf[cpos] = '\0';
+ buf[epos] = '\0';
if ((flag & EFCR) != 0) {
ttputc(CCHR('M'));
ttflush();
@@ -223,25 +356,38 @@ veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
bcopy(buf, lp->l_text, cpos);
}
#endif /* !NO_MACRO */
+ ret = buf;
goto done;
case CCHR('G'): /* bell, abort */
eputc(CCHR('G'));
(void)ctrlg(FFRAND, 0);
ttflush();
- return (NULL);
+ ret = NULL;
+ goto done;
case CCHR('H'): /* rubout, erase */
case CCHR('?'):
if (cpos != 0) {
+ y = buf[--cpos];
+ epos--;
ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE) {
+ ttcol--;
+ if (ISCTRL(y) != FALSE) {
ttputc('\b');
+ ttcol--;
+ }
+ rr = ttrow;
+ cc = ttcol;
+ for (i = cpos; i < epos; i++) {
+ buf[i] = buf[i + 1];
+ eputc(buf[i]);
+ }
+ ttputc(' ');
+ if (ISCTRL(y) != FALSE) {
ttputc(' ');
ttputc('\b');
- --ttcol;
}
+ ttputc('\b');
+ ttmove(rr, cc);
ttflush();
}
break;
@@ -258,6 +404,7 @@ veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
ttputc('\b');
--ttcol;
}
+ epos--;
}
ttflush();
break;
@@ -293,35 +440,53 @@ veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
c = getkey(FALSE);
/* FALLTHROUGH */
default:
- /* all the rest */
- if (dynbuf && cpos + 1 >= nbuf) {
+ if (dynbuf && epos + 1 >= nbuf) {
void *newp;
- size_t newsize = cpos + cpos + 16;
-
- if ((newp = realloc(buf, newsize)) == NULL) {
- ewprintf("Out of memory");
- free(buf);
- return (NULL);
- }
+ size_t newsize = epos + epos + 16;
+ if ((newp = realloc(buf, newsize)) == NULL)
+ goto fail;
buf = newp;
nbuf = newsize;
}
- if (cpos < nbuf - 1) {
- buf[cpos++] = (char)c;
- eputc((char)c);
- ttflush();
- }
+ for (i = epos; i > cpos; i--)
+ buf[i] = buf[i - 1];
+ buf[cpos++] = (char)c;
+ epos++;
+ eputc((char)c);
+ cc = ttcol;
+ rr = ttrow;
+ for (i = cpos; i < epos; i++)
+ eputc(buf[i]);
+ ttmove(rr, cc);
+ ttflush();
}
}
+ ret = buf;
done:
- return (buf);
+ if (cwin == TRUE) {
+ /* blow away cpltion window */
+ bp = bfind("*Completions*", TRUE);
+ if ((wp = popbuf(bp)) != NULL) {
+ curwp = wp;
+ delwind(FFRAND, 1);
+ }
+ }
+ return (ret);
+fail:
+ ewprintf("Out of memory");
+ free(buf);
+ return (NULL);
}
/*
* Do completion on a list of objects.
+ * c is SPACE, TAB, or CR
+ * return TRUE if matched (or partially matched)
+ * FALSE is result is ambiguous,
+ * ABORT on error.
*/
static int
-complt(int flags, int c, char *buf, size_t nbuf, int cpos)
+complt(int flags, int c, char *buf, size_t nbuf, int cpos, int *nx)
{
LIST *lh, *lh2;
LIST *wholelist = NULL;
@@ -357,7 +522,7 @@ complt(int flags, int c, char *buf, size_t nbuf, int cpos)
lh2 = lh;
++nhits;
if (lh->l_name[cpos] == '\0')
- nxtra = -1;
+ nxtra = -1; /* exact match */
else {
bxtra = getxtra(lh, lh2, cpos, wflag);
if (bxtra < nxtra)
@@ -375,16 +540,18 @@ complt(int flags, int c, char *buf, size_t nbuf, int cpos)
* autocompleted have known types/lengths.
*/
if (nxtra < 0 && nhits > 1 && c == ' ')
- nxtra = 1;
+ nxtra = 1; /* ??? */
for (i = 0; i < nxtra && cpos < nbuf; ++i) {
buf[cpos] = lh2->l_name[cpos];
eputc(buf[cpos++]);
}
+ /* XXX should grow nbuf */
ttflush();
free_file_list(wholelist);
- if (nxtra < 0 && c != CCHR('M'))
- return (0);
- return (nxtra);
+ *nx = nxtra;
+ if (nxtra < 0 && c != CCHR('M')) /* exact */
+ *nx = 0;
+ return (TRUE);
}
/*
@@ -408,7 +575,8 @@ complt(int flags, int c, char *buf, size_t nbuf, int cpos)
ttcol -= (i = nshown); /* update ttcol on BS's */
while (i--)
ttputc('\b'); /* update ttcol again! */
- return (0);
+ *nx = nxtra;
+ return ((nhits > 0) ? TRUE : FALSE);
}
/*
@@ -433,8 +601,8 @@ complt_list(int flags, int c, char *buf, int cpos)
ttflush();
- /* The results are put into a help buffer. */
- bp = bfind("*help*", TRUE);
+ /* The results are put into a completion buffer. */
+ bp = bfind("*Completions*", TRUE);
if (bclear(bp) == FALSE)
return (FALSE);