console: re-use the available REPL console API and improve linenoise

This commit is contained in:
Данила Горнушко 2023-11-24 00:40:56 +03:00
parent 13794c4c11
commit 0ca67d25a1
2 changed files with 74 additions and 13 deletions

View file

@ -120,8 +120,10 @@
#include "linenoise.h" #include "linenoise.h"
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_MAX_LINE 4096 #define LINENOISE_DEFAULT_MAX_LINE 4096
#define LINENOISE_MINIMAL_MAX_LINE 64
#define LINENOISE_COMMAND_MAX_LEN 32 #define LINENOISE_COMMAND_MAX_LEN 32
#define LINENOISE_PASTE_KEY_DELAY 30 /* Delay, in milliseconds, between two characters being pasted from clipboard */
static linenoiseCompletionCallback *completionCallback = NULL; static linenoiseCompletionCallback *completionCallback = NULL;
static linenoiseHintsCallback *hintsCallback = NULL; static linenoiseHintsCallback *hintsCallback = NULL;
@ -130,6 +132,7 @@ static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseComple
static void refreshLineWithFlags(struct linenoiseState *l, int flags); static void refreshLineWithFlags(struct linenoiseState *l, int flags);
static int maskmode = 0; /* Show "***" instead of input. For passwords. */ static int maskmode = 0; /* Show "***" instead of input. For passwords. */
static size_t max_cmdline_length = LINENOISE_DEFAULT_MAX_LINE;
static int mlmode = 0; /* Multi line mode. Default is single line. */ static int mlmode = 0; /* Multi line mode. Default is single line. */
static int dumbmode = 0; /* Dumb mode where line editing is disabled. Off by default */ static int dumbmode = 0; /* Dumb mode where line editing is disabled. Off by default */
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
@ -739,6 +742,21 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) {
return 0; return 0;
} }
int linenoiseInsertPastedChar(struct linenoiseState *l, char c) {
int fd = fileno(stdout);
if (l->len < l->buflen && l->len == l->pos) {
l->buf[l->pos] = c;
l->pos++;
l->len++;
l->buf[l->len] = '\0';
if (write(fd, &c,1) == -1) {
return -1;
}
flushWrite();
}
return 0;
}
/* Move cursor on the left. */ /* Move cursor on the left. */
void linenoiseEditMoveLeft(struct linenoiseState *l) { void linenoiseEditMoveLeft(struct linenoiseState *l) {
if (l->pos > 0) { if (l->pos > 0) {
@ -863,10 +881,16 @@ static char *linenoiseDumb(struct linenoiseState *l) {
} }
fputc('\n', stdout); fputc('\n', stdout);
flushWrite(); flushWrite();
if (l->len == 0) return linenoiseEditMore; // if (l->len == 0) return linenoiseEditMore;
return strdup(l->buf); return strdup(l->buf);
} }
uint32_t getMillis(void) {
struct timeval tv = { 0 };
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
/* This function is part of the multiplexed API of Linenoise, that is used /* This function is part of the multiplexed API of Linenoise, that is used
* in order to implement the blocking variant of the API but can also be * in order to implement the blocking variant of the API but can also be
* called by the user directly in an event driven program. It will: * called by the user directly in an event driven program. It will:
@ -949,12 +973,34 @@ char *linenoiseEditMore = "If you see this, you are misusing the API: when linen
*/ */
char *linenoiseEditFeed(struct linenoiseState *l) { char *linenoiseEditFeed(struct linenoiseState *l) {
if (dumbmode) return linenoiseDumb(l); if (dumbmode) return linenoiseDumb(l);
uint32_t t1 = 0;
char c; char c;
int nread; int nread;
char seq[3]; char seq[3];
/*
* To determine whether the user is pasting data or typing itself, we
* need to calculate how many milliseconds elapsed between two key
* presses. Indeed, if there is less than LINENOISE_PASTE_KEY_DELAY
* (typically 30-40ms), then a paste is being performed, else, the
* user is typing.
* NOTE: pressing a key down without releasing it will also spend
* about 40ms (or even more)
*/
t1 = getMillis();
nread = fread(&c, 1, 1, stdin); nread = fread(&c, 1, 1, stdin);
if (nread <= 0) return NULL; if (nread <= 0) return NULL;
// FIXME: line printed twice after pasting something
if ( (getMillis() - t1) < LINENOISE_PASTE_KEY_DELAY ) {
/* Pasting data, insert characters without formatting.
* This can only be performed when the cursor is at the end of the
* line. */
if (linenoiseInsertPastedChar(l,c)) {
errno = EIO;
return NULL;
}
return linenoiseEditMore;
}
/* 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
@ -1116,8 +1162,6 @@ void linenoiseEditStop(struct linenoiseState *l) {
flushWrite(); flushWrite();
} }
/* This just implements a blocking loop for the multiplexed API. /* This just implements a blocking loop for the multiplexed API.
* 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
@ -1178,8 +1222,9 @@ int linenoiseProbe() {
/* The high level function that is the main API of the linenoise library. */ /* The high level function that is the main API of the linenoise library. */
char *linenoise(const char *prompt) { char *linenoise(const char *prompt) {
char buf[LINENOISE_MAX_LINE]; char *buf = calloc(1, max_cmdline_length);
char *retval = linenoiseBlockingEdit(buf,LINENOISE_MAX_LINE,prompt); char *retval = linenoiseBlockingEdit(buf,max_cmdline_length,prompt);
free(buf);
return retval; return retval;
} }
@ -1293,18 +1338,33 @@ int linenoiseHistorySave(const char *filename) {
* on error -1 is returned. */ * on error -1 is returned. */
int linenoiseHistoryLoad(const char *filename) { int linenoiseHistoryLoad(const char *filename) {
FILE *fp = fopen(filename, "r"); FILE *fp = fopen(filename, "r");
char buf[LINENOISE_MAX_LINE]; if (fp == NULL) {
return -1;
if (fp == NULL) return -1; }
char *buf = calloc(1, max_cmdline_length);
while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) { if (buf == NULL) {
fclose(fp);
return -1;
}
while (fgets(buf, max_cmdline_length, fp) != NULL) {
char *p; char *p;
p = strchr(buf,'\r'); p = strchr(buf,'\r');
if (!p) p = strchr(buf,'\n'); if (!p) p = strchr(buf,'\n');
if (p) *p = '\0'; if (p) *p = '\0';
linenoiseHistoryAdd(buf); linenoiseHistoryAdd(buf);
} }
free(buf);
fclose(fp); fclose(fp);
return 0; return 0;
} }
/* Set line maximum length. If len parameter is smaller than
* LINENOISE_MINIMAL_MAX_LINE, -1 is returned
* otherwise 0 is returned. */
int linenoiseSetMaxLineLen(size_t len) {
if (len < LINENOISE_MINIMAL_MAX_LINE) {
return -1;
}
max_cmdline_length = len;
return 0;
}

View file

@ -110,6 +110,7 @@ void linenoiseSetDumbMode(int set);
bool linenoiseIsDumbMode(void); bool linenoiseIsDumbMode(void);
void linenoiseMaskModeEnable(void); void linenoiseMaskModeEnable(void);
void linenoiseMaskModeDisable(void); void linenoiseMaskModeDisable(void);
int linenoiseSetMaxLineLen(size_t len);
#ifdef __cplusplus #ifdef __cplusplus