Multiplexing: make completion non-blocking as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
diff --git a/linenoise.c b/linenoise.c
index 58c1b05..0eab3df 100644
--- a/linenoise.c
+++ b/linenoise.c
@@ -355,57 +355,57 @@ static void freeCompletions(linenoiseCompletions *lc) {
* the input was consumed by the completeLine() function to navigate the
* possible completions, and the caller should read for the next characters
* from stdin. */
-static int completeLine(struct linenoiseState *ls) {
+static int completeLine(struct linenoiseState *ls, int keypressed) {
linenoiseCompletions lc = { 0, NULL };
- int nread, nwritten;
- char c = 0;
+ int nwritten;
+ char c = keypressed;
completionCallback(ls->buf,&lc);
if (lc.len == 0) {
linenoiseBeep();
+ ls->in_completion = 0;
} else {
- size_t stop = 0, i = 0;
-
- while(!stop) {
- /* Show completion or original buffer */
- if (i < lc.len) {
- struct linenoiseState saved = *ls;
-
- ls->len = ls->pos = strlen(lc.cvec[i]);
- ls->buf = lc.cvec[i];
- refreshLine(ls);
- ls->len = saved.len;
- ls->pos = saved.pos;
- ls->buf = saved.buf;
- } else {
- refreshLine(ls);
- }
+ switch(c) {
+ case 9: /* tab */
+ if (ls->in_completion == 0) {
+ ls->in_completion = 1;
+ ls->completion_idx = 0;
+ } else {
+ ls->completion_idx = (ls->completion_idx+1) % (lc.len+1);
+ if (ls->completion_idx == lc.len) linenoiseBeep();
+ }
+ c = 0;
+ break;
+ case 27: /* escape */
+ /* Re-show original buffer */
+ if (ls->completion_idx < lc.len) refreshLine(ls);
+ ls->in_completion = 0;
+ c = 0;
+ break;
+ default:
+ /* Update buffer and return */
+ if (ls->completion_idx < lc.len) {
+ nwritten = snprintf(ls->buf,ls->buflen,"%s",
+ lc.cvec[ls->completion_idx]);
+ ls->len = ls->pos = nwritten;
+ c = 0;
+ }
+ ls->in_completion = 0;
+ break;
+ }
- nread = read(ls->ifd,&c,1);
- if (nread <= 0) {
- freeCompletions(&lc);
- return -1;
- }
+ /* Show completion or original buffer */
+ if (ls->in_completion && ls->completion_idx < lc.len) {
+ struct linenoiseState saved = *ls;
- switch(c) {
- case 9: /* tab */
- i = (i+1) % (lc.len+1);
- if (i == lc.len) linenoiseBeep();
- break;
- case 27: /* escape */
- /* Re-show original buffer */
- if (i < lc.len) refreshLine(ls);
- stop = 1;
- break;
- default:
- /* Update buffer and return */
- if (i < lc.len) {
- nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
- ls->len = ls->pos = nwritten;
- }
- stop = 1;
- break;
- }
+ ls->len = ls->pos = strlen(lc.cvec[ls->completion_idx]);
+ ls->buf = lc.cvec[ls->completion_idx];
+ refreshLine(ls);
+ ls->len = saved.len;
+ ls->pos = saved.pos;
+ ls->buf = saved.buf;
+ } else {
+ refreshLine(ls);
}
}
@@ -841,6 +841,7 @@ void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) {
/* Populate the linenoise state that we pass to functions implementing
* specific editing functionalities. */
+ l->in_completion = 0;
l->ifd = stdin_fd != -1 ? stdin_fd : STDIN_FILENO;
l->ofd = stdout_fd != -1 ? stdout_fd : STDOUT_FILENO;
l->buf = buf;
@@ -908,8 +909,8 @@ char *linenoiseEditFeed(struct linenoiseState *l) {
/* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the
* character that should be handled next. */
- if (c == 9 && completionCallback != NULL) {
- c = completeLine(l);
+ if ((l->in_completion || c == 9) && completionCallback != NULL) {
+ c = completeLine(l,c);
/* Return on errors */
if (c < 0) return NULL;
/* Read next character when 0 */
diff --git a/linenoise.h b/linenoise.h
index 6aac92d..fdb4319 100644
--- a/linenoise.h
+++ b/linenoise.h
@@ -51,6 +51,9 @@ extern char *linenoiseEditMore;
* We pass this state to functions implementing specific editing
* functionalities. */
struct linenoiseState {
+ int in_completion; /* The user pressed TAB and we are now in completion
+ * mode, so input is handled by completeLine(). */
+ size_t completion_idx; /* Index of next completion to propose. */
int ifd; /* Terminal stdin file descriptor. */
int ofd; /* Terminal stdout file descriptor. */
char *buf; /* Edited line buffer. */