mirror of
https://github.com/antirez/linenoise.git
synced 2025-11-16 12:34:48 +00:00
Multiplexing: API refactoring, no TTY support.
This commit is contained in:
@@ -69,8 +69,6 @@ int main(int argc, char **argv) {
|
|||||||
* using the select(2) timeout. */
|
* using the select(2) timeout. */
|
||||||
struct linenoiseState ls;
|
struct linenoiseState ls;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
char *async_retval;
|
|
||||||
int async_len = 0;
|
|
||||||
linenoiseEditStart(&ls,-1,-1,buf,sizeof(buf),"hello> ");
|
linenoiseEditStart(&ls,-1,-1,buf,sizeof(buf),"hello> ");
|
||||||
while(1) {
|
while(1) {
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
@@ -87,11 +85,11 @@ int main(int argc, char **argv) {
|
|||||||
perror("select()");
|
perror("select()");
|
||||||
exit(1);
|
exit(1);
|
||||||
} else if (retval) {
|
} else if (retval) {
|
||||||
async_retval = linenoiseEditFeed(&ls,&async_len);
|
line = linenoiseEditFeed(&ls);
|
||||||
/* A NULL return means: line editing is continuing.
|
/* A NULL return means: line editing is continuing.
|
||||||
* Otherwise the user hit enter or stopped editing
|
* Otherwise the user hit enter or stopped editing
|
||||||
* (CTRL+C/D). */
|
* (CTRL+C/D). */
|
||||||
if (async_retval != NULL) break;
|
if (line != linenoiseEditMore) break;
|
||||||
} else {
|
} else {
|
||||||
// Timeout occurred
|
// Timeout occurred
|
||||||
static int counter = 0;
|
static int counter = 0;
|
||||||
@@ -101,8 +99,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
linenoiseEditStop(&ls);
|
linenoiseEditStop(&ls);
|
||||||
if (async_len == -1) exit(0); /* Ctrl+D/C. */
|
if (line == NULL) exit(0); /* Ctrl+D/C. */
|
||||||
line = strdup(async_retval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do something with the string. */
|
/* Do something with the string. */
|
||||||
|
|||||||
83
linenoise.c
83
linenoise.c
@@ -123,6 +123,7 @@ static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
|
|||||||
static linenoiseCompletionCallback *completionCallback = NULL;
|
static linenoiseCompletionCallback *completionCallback = NULL;
|
||||||
static linenoiseHintsCallback *hintsCallback = NULL;
|
static linenoiseHintsCallback *hintsCallback = NULL;
|
||||||
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
||||||
|
static char *linenoiseNoTTY(void);
|
||||||
|
|
||||||
static struct termios orig_termios; /* In order to restore at exit.*/
|
static struct termios orig_termios; /* In order to restore at exit.*/
|
||||||
static int maskmode = 0; /* Show "***" instead of input. For passwords. */
|
static int maskmode = 0; /* Show "***" instead of input. For passwords. */
|
||||||
@@ -848,6 +849,11 @@ int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, ch
|
|||||||
l->buf[0] = '\0';
|
l->buf[0] = '\0';
|
||||||
l->buflen--; /* Make sure there is always space for the nulterm */
|
l->buflen--; /* Make sure there is always space for the nulterm */
|
||||||
|
|
||||||
|
/* If stdin is not a tty, stop here with the initialization. We
|
||||||
|
* will actually just read a line from standard input in blocking
|
||||||
|
* mode later, in linenoiseEditFeed(). */
|
||||||
|
if (!isatty(l->ifd)) return 0;
|
||||||
|
|
||||||
/* Enter raw mode. */
|
/* Enter raw mode. */
|
||||||
if (enableRawMode(l->ifd) == -1) return -1;
|
if (enableRawMode(l->ifd) == -1) return -1;
|
||||||
|
|
||||||
@@ -859,31 +865,37 @@ int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, ch
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *linenoiseEditMore = "If you see this, you are misusing the API: when linenoiseEditFeed() is called, if it returns linenoiseEditMore the user is yet editing the line. See the README file for more information.";
|
||||||
|
|
||||||
/* This function is part of the multiplexed API of linenoise, see the top
|
/* This function is part of the multiplexed API of linenoise, see the top
|
||||||
* comment on linenoiseEditStart() for more information. Call this function
|
* comment on linenoiseEditStart() for more information. Call this function
|
||||||
* each time there is some data to read from the standard input file
|
* each time there is some data to read from the standard input file
|
||||||
* descriptor. In the case of blocking operations, this function can just be
|
* descriptor. In the case of blocking operations, this function can just be
|
||||||
* called in a loop, and block.
|
* called in a loop, and block.
|
||||||
*
|
*
|
||||||
* The function returns NULL to signal that line editing is still in progress,
|
* The function returns linenoiseEditMore to signal that line editing is still
|
||||||
* that is, the user didn't yet pressed enter / CTRL-D. Otherwise the function
|
* in progress, that is, the user didn't yet pressed enter / CTRL-D. Otherwise
|
||||||
* returns the pointer to the buffer and populates '*len' with the current
|
* the function returns the pointer to the heap-allocated buffer with the
|
||||||
* buffer length. If '*len' is set to -1, some special condition occurred, and
|
* edited line, that the user should free with linenoiseFree().
|
||||||
* the caller may want to check 'errno':
|
*
|
||||||
|
* On special conditions, NULL is returned and errno is populated:
|
||||||
*
|
*
|
||||||
* EAGAIN if the user pressed Ctrl-C
|
* EAGAIN if the user pressed Ctrl-C
|
||||||
* ENOENT if the user pressed Ctrl-D
|
* ENOENT if the user pressed Ctrl-D
|
||||||
|
*
|
||||||
|
* Some other errno: I/O error.
|
||||||
*/
|
*/
|
||||||
char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
|
char *linenoiseEditFeed(struct linenoiseState *l) {
|
||||||
|
/* Not a TTY, pass control to line reading without character
|
||||||
|
* count limits. */
|
||||||
|
if (!isatty(l->ifd)) return linenoiseNoTTY();
|
||||||
|
|
||||||
char c;
|
char c;
|
||||||
int nread;
|
int nread;
|
||||||
char seq[3];
|
char seq[3];
|
||||||
|
|
||||||
nread = read(l->ifd,&c,1);
|
nread = read(l->ifd,&c,1);
|
||||||
if (nread <= 0) {
|
if (nread <= 0) return NULL;
|
||||||
if (len) *len = l->len;
|
|
||||||
return l->buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only autocomplete when the callback is set. It returns < 0 when
|
/* Only autocomplete when the callback is set. It returns < 0 when
|
||||||
* there was an error reading from fd. Otherwise it will return the
|
* there was an error reading from fd. Otherwise it will return the
|
||||||
@@ -891,12 +903,9 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
|
|||||||
if (c == 9 && completionCallback != NULL) {
|
if (c == 9 && completionCallback != NULL) {
|
||||||
c = completeLine(l);
|
c = completeLine(l);
|
||||||
/* Return on errors */
|
/* Return on errors */
|
||||||
if (c < 0) {
|
if (c < 0) return NULL;
|
||||||
if (len) *len = -1;
|
|
||||||
return l->buf;
|
|
||||||
}
|
|
||||||
/* Read next character when 0 */
|
/* Read next character when 0 */
|
||||||
if (c == 0) return NULL;
|
if (c == 0) return linenoiseEditMore;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
@@ -912,12 +921,10 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
|
|||||||
refreshLine(l);
|
refreshLine(l);
|
||||||
hintsCallback = hc;
|
hintsCallback = hc;
|
||||||
}
|
}
|
||||||
if (len) *len = l->len;
|
return strdup(l->buf);
|
||||||
return l->buf;
|
|
||||||
case CTRL_C: /* ctrl-c */
|
case CTRL_C: /* ctrl-c */
|
||||||
errno = EAGAIN;
|
errno = EAGAIN;
|
||||||
if (len) *len = -1;
|
return NULL;
|
||||||
return l->buf;
|
|
||||||
case BACKSPACE: /* backspace */
|
case BACKSPACE: /* backspace */
|
||||||
case 8: /* ctrl-h */
|
case 8: /* ctrl-h */
|
||||||
linenoiseEditBackspace(l);
|
linenoiseEditBackspace(l);
|
||||||
@@ -929,9 +936,8 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
|
|||||||
} else {
|
} else {
|
||||||
history_len--;
|
history_len--;
|
||||||
free(history[history_len]);
|
free(history[history_len]);
|
||||||
if (len) *len = -1;
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return l->buf;
|
return NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CTRL_T: /* ctrl-t, swaps current character with previous. */
|
case CTRL_T: /* ctrl-t, swaps current character with previous. */
|
||||||
@@ -1011,10 +1017,7 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (linenoiseEditInsert(l,c)) {
|
if (linenoiseEditInsert(l,c)) return NULL;
|
||||||
if (len) *len = -1;
|
|
||||||
return l->buf;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CTRL_U: /* Ctrl+u, delete the whole line. */
|
case CTRL_U: /* Ctrl+u, delete the whole line. */
|
||||||
l->buf[0] = '\0';
|
l->buf[0] = '\0';
|
||||||
@@ -1040,7 +1043,7 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
|
|||||||
linenoiseEditDeletePrevWord(l);
|
linenoiseEditDeletePrevWord(l);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return linenoiseEditMore;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is part of the multiplexed linenoise API. See linenoiseEditStart()
|
/* This is part of the multiplexed linenoise API. See linenoiseEditStart()
|
||||||
@@ -1048,6 +1051,7 @@ char *linenoiseEditFeed(struct linenoiseState *l, int *len) {
|
|||||||
* returns something different than NULL. At this point the user input
|
* returns something different than NULL. At this point the user input
|
||||||
* is in the buffer, and we can restore the terminal in normal mode. */
|
* is in the buffer, and we can restore the terminal in normal mode. */
|
||||||
void linenoiseEditStop(struct linenoiseState *l) {
|
void linenoiseEditStop(struct linenoiseState *l) {
|
||||||
|
if (!isatty(l->ifd)) return;
|
||||||
disableRawMode(l->ifd);
|
disableRawMode(l->ifd);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
@@ -1056,22 +1060,21 @@ void linenoiseEditStop(struct linenoiseState *l) {
|
|||||||
* In many applications that are not event-drivern, we can just call
|
* In many applications that are not event-drivern, we can just call
|
||||||
* the blocking linenoise API, wait for the user to complete the editing
|
* the blocking linenoise API, wait for the user to complete the editing
|
||||||
* and return the buffer. */
|
* and return the buffer. */
|
||||||
static int linenoiseBlockingEdit(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
|
static char *linenoiseBlockingEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
|
||||||
{
|
{
|
||||||
|
struct linenoiseState l;
|
||||||
|
|
||||||
/* Editing without a buffer is invalid. */
|
/* Editing without a buffer is invalid. */
|
||||||
if (buflen == 0) {
|
if (buflen == 0) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
linenoiseEditStart(l,stdin_fd,stdout_fd,buf,buflen,prompt);
|
linenoiseEditStart(&l,stdin_fd,stdout_fd,buf,buflen,prompt);
|
||||||
int len;
|
char *res;
|
||||||
while(1) {
|
while((res = linenoiseEditFeed(&l)) == linenoiseEditMore);
|
||||||
char *res = linenoiseEditFeed(l,&len);
|
linenoiseEditStop(&l);
|
||||||
if (res != NULL) break;
|
return res;
|
||||||
}
|
|
||||||
linenoiseEditStop(l);
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This special mode is used by linenoise in order to print scan codes
|
/* This special mode is used by linenoise in order to print scan codes
|
||||||
@@ -1145,7 +1148,6 @@ static char *linenoiseNoTTY(void) {
|
|||||||
* something even in the most desperate of the conditions. */
|
* something even in the most desperate of the conditions. */
|
||||||
char *linenoise(const char *prompt) {
|
char *linenoise(const char *prompt) {
|
||||||
char buf[LINENOISE_MAX_LINE];
|
char buf[LINENOISE_MAX_LINE];
|
||||||
int count;
|
|
||||||
|
|
||||||
if (!isatty(STDIN_FILENO)) {
|
if (!isatty(STDIN_FILENO)) {
|
||||||
/* Not a tty: read from file / pipe. In this mode we don't want any
|
/* Not a tty: read from file / pipe. In this mode we don't want any
|
||||||
@@ -1164,10 +1166,8 @@ char *linenoise(const char *prompt) {
|
|||||||
}
|
}
|
||||||
return strdup(buf);
|
return strdup(buf);
|
||||||
} else {
|
} else {
|
||||||
struct linenoiseState l;
|
char *retval = linenoiseBlockingEdit(STDIN_FILENO,STDOUT_FILENO,buf,LINENOISE_MAX_LINE,prompt);
|
||||||
count = linenoiseBlockingEdit(&l,-1,-1,buf,LINENOISE_MAX_LINE,prompt);
|
return retval;
|
||||||
if (count == -1) return NULL;
|
|
||||||
return strdup(buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1176,6 +1176,7 @@ char *linenoise(const char *prompt) {
|
|||||||
* created with. Useful when the main program is using an alternative
|
* created with. Useful when the main program is using an alternative
|
||||||
* allocator. */
|
* allocator. */
|
||||||
void linenoiseFree(void *ptr) {
|
void linenoiseFree(void *ptr) {
|
||||||
|
if (ptr == linenoiseEditMore) return; // Protect from API misuse.
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ extern "C" {
|
|||||||
|
|
||||||
#include <stddef.h> /* For size_t. */
|
#include <stddef.h> /* For size_t. */
|
||||||
|
|
||||||
|
extern char *linenoiseEditMore;
|
||||||
|
|
||||||
/* The linenoiseState structure represents the state during line editing.
|
/* The linenoiseState structure represents the state during line editing.
|
||||||
* We pass this state to functions implementing specific editing
|
* We pass this state to functions implementing specific editing
|
||||||
* functionalities. */
|
* functionalities. */
|
||||||
@@ -70,7 +72,7 @@ typedef struct linenoiseCompletions {
|
|||||||
|
|
||||||
/* Non blocking API. */
|
/* Non blocking API. */
|
||||||
int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt);
|
int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt);
|
||||||
char *linenoiseEditFeed(struct linenoiseState *l, int *len);
|
char *linenoiseEditFeed(struct linenoiseState *l);
|
||||||
void linenoiseEditStop(struct linenoiseState *l);
|
void linenoiseEditStop(struct linenoiseState *l);
|
||||||
void linenoiseHide(struct linenoiseState *l);
|
void linenoiseHide(struct linenoiseState *l);
|
||||||
void linenoiseShow(struct linenoiseState *l);
|
void linenoiseShow(struct linenoiseState *l);
|
||||||
|
|||||||
Reference in New Issue
Block a user