From d74c0675f53c1a07da8092cd5aafae1c16ff99fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=D0=B0=20=D0=93=D0=BE=D1=80?= =?UTF-8?q?=D0=BD=D1=83=D1=88=D0=BA=D0=BE?= Date: Thu, 23 Nov 2023 23:49:21 +0300 Subject: [PATCH] Some changes from esp-idf --- components/console/linenoise/linenoise.c | 131 +++++++++++++++++++++-- components/console/linenoise/linenoise.h | 4 +- 2 files changed, 123 insertions(+), 12 deletions(-) diff --git a/components/console/linenoise/linenoise.c b/components/console/linenoise/linenoise.c index 997c4c7..2887995 100644 --- a/components/console/linenoise/linenoise.c +++ b/components/console/linenoise/linenoise.c @@ -107,17 +107,21 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include "linenoise.h" #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_MAX_LINE 4096 +#define LINENOISE_COMMAND_MAX_LEN 32 static linenoiseCompletionCallback *completionCallback = NULL; static linenoiseHintsCallback *hintsCallback = NULL; @@ -127,6 +131,7 @@ static void refreshLineWithFlags(struct linenoiseState *l, int flags); static int maskmode = 0; /* Show "***" instead of input. For passwords. */ 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 history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; static int history_len = 0; static char **history = NULL; @@ -180,6 +185,23 @@ void linenoiseSetMultiLine(int ml) { mlmode = ml; } +/* Set if terminal does not recognize escape sequences */ +void linenoiseSetDumbMode(int set) { + dumbmode = set; +} + +/* Returns whether the current mode is dumbmode or not. */ +bool linenoiseIsDumbMode(void) { + return dumbmode; +} + +static void flushWrite(void) { + if (__fbufsize(stdout) > 0) { + fflush(stdout); + } + fsync(fileno(stdout)); +} + /* Use the ESC [6n escape sequence to query the horizontal cursor position * and return it. On error -1 is returned, on success the position of the * cursor. */ @@ -190,6 +212,7 @@ static int getCursorPosition() { /* Report cursor location */ fprintf(stdout, "\x1b[6n"); + flushWrite(); /* Read the response: ESC [ rows ; cols R */ while (i < sizeof(buf)-1) { if (fread(buf+i, 1, 1, stdin) != 1) break; @@ -214,6 +237,7 @@ static int getColumns() { /* Go to right margin and get position. */ if (fwrite("\x1b[999C", 1, 6, stdout) != 6) goto failed; + flushWrite(); cols = getCursorPosition(); if (cols == -1) goto failed; @@ -224,6 +248,7 @@ static int getColumns() { if (fwrite(seq, 1, strlen(seq), stdout) == -1) { /* Can't recover... */ } + flushWrite(); } return cols; @@ -234,12 +259,14 @@ failed: /* Clear the screen. Used to handle ctrl+l */ void linenoiseClearScreen(void) { fprintf(stdout,"\x1b[H\x1b[2J"); + flushWrite(); } /* Beep, used for completion when there is nothing to complete or when all * the choices were already shown. */ static void linenoiseBeep(void) { fprintf(stdout, "\x7"); + flushWrite(); } /* ============================== Completion ================================ */ @@ -492,6 +519,7 @@ static void refreshSingleLine(struct linenoiseState *l, int flags) { } if (fwrite(ab.b, ab.len, 1, stdout) == -1) {} /* Can't recover from write error. */ + flushWrite(); abFree(&ab); } @@ -585,6 +613,7 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) { l->oldpos = l->pos; if (fwrite(ab.b, ab.len, 1, stdout) == -1) {} /* Can't recover from write error. */ + flushWrite(); abFree(&ab); } @@ -634,6 +663,7 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) { * trivial case. */ char d = (maskmode==1) ? '*' : c; if (fwrite(&d,1,1,stdout) == -1) return -1; + flushWrite(); } else { refreshLine(l); } @@ -745,6 +775,38 @@ void linenoiseEditDeletePrevWord(struct linenoiseState *l) { refreshLine(l); } +// TODO: try to make a non-blocking dumb mode +static char *linenoiseDumb(struct linenoiseState *l) { + /* dumb terminal, fall back to fgets */ + fputs(l->prompt, stdout); + flushWrite(); + l->len = 0; //needed? + while (l->len < l->buflen) { + int c = fgetc(stdin); + if (c == '\n') { + break; + } else if (c >= 0x1c && c <= 0x1f){ + continue; /* consume arrow keys */ + } else if (c == BACKSPACE || c == 0x8) { + if (l->len > 0) { + l->buf[l->len - 1] = 0; + l->len --; + } + fputs("\x08 ", stdout); /* Windows CMD: erase symbol under cursor */ + flushWrite(); + } else { + l->buf[l->len] = c; + l->len++; + } + fputc(c, stdout); /* echo */ + flushWrite(); + } + fputc('\n', stdout); + flushWrite(); + if (l->len == 0) return linenoiseEditMore; + return strdup(l->buf); +} + /* 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 * called by the user directly in an event driven program. It will: @@ -789,13 +851,18 @@ int linenoiseEditStart(struct linenoiseState *l, char *buf, size_t buflen, const /* The latest history entry is always our current buffer, that * initially is just an empty string. */ - linenoiseHistoryAdd(""); - - int pos1 = getCursorPosition(); - if (fwrite(prompt,l->plen,1,stdout) == -1) return -1; - int pos2 = getCursorPosition(); - if (pos1 >= 0 && pos2 >= 0) { - l->plen = pos2 - pos1; + if (!dumbmode) { + linenoiseHistoryAdd(""); + int pos1 = getCursorPosition(); + if (fwrite(prompt,l->plen,1,stdout) == -1) return -1; + flushWrite(); + int pos2 = getCursorPosition(); + if (pos1 >= 0 && pos2 >= 0) { + l->plen = pos2 - pos1; + } + } else { + if (fwrite(prompt,l->plen,1,stdout) == -1) return -1; + flushWrite(); } return 0; } @@ -821,6 +888,7 @@ char *linenoiseEditMore = "If you see this, you are misusing the API: when linen * Some other errno: I/O error. */ char *linenoiseEditFeed(struct linenoiseState *l) { + if (dumbmode) return linenoiseDumb(l); char c; int nread; char seq[3]; @@ -974,6 +1042,7 @@ char *linenoiseEditFeed(struct linenoiseState *l) { linenoiseEditDeletePrevWord(l); break; } + flushWrite(); return linenoiseEditMore; } @@ -983,9 +1052,12 @@ char *linenoiseEditFeed(struct linenoiseState *l) { * returns something different than NULL. At this point the user input * is in the buffer, and we can restore the terminal in normal mode. */ void linenoiseEditStop(struct linenoiseState *l) { - printf("\n"); + fputc('\n', stdout); + flushWrite(); } + + /* This just implements a blocking loop for the multiplexed API. * In many applications that are not event-drivern, we can just call * the blocking linenoise API, wait for the user to complete the editing @@ -998,18 +1070,55 @@ static char *linenoiseBlockingEdit(char *buf, size_t buflen, const char *prompt) errno = EINVAL; return NULL; } - - linenoiseEditStart(&l,buf,buflen,prompt); char *res; + linenoiseEditStart(&l,buf,buflen,prompt); while((res = linenoiseEditFeed(&l)) == linenoiseEditMore); linenoiseEditStop(&l); return res; } +int linenoiseProbe() { + /* Switch to non-blocking mode */ + int stdin_fileno = fileno(stdin); + int flags = fcntl(stdin_fileno, F_GETFL); + flags |= O_NONBLOCK; + int res = fcntl(stdin_fileno, F_SETFL, flags); + if (res != 0) { + return -1; + } + /* Device status request */ + fprintf(stdout, "\x1b[5n"); + flushWrite(); + + /* Try to read response */ + int timeout_ms = 200; + const int retry_ms = 10; + size_t read_bytes = 0; + while (timeout_ms > 0 && read_bytes < 4) { // response is ESC[0n or ESC[3n + usleep(retry_ms * 1000); + timeout_ms -= retry_ms; + char c; + int cb = read(stdin_fileno, &c, 1); + if (cb < 0) { + continue; + } + read_bytes += cb; + } + /* Restore old mode */ + flags &= ~O_NONBLOCK; + res = fcntl(stdin_fileno, F_SETFL, flags); + if (res != 0) { + return -1; + } + if (read_bytes < 4) { + return -2; + } + return 0; +} + /* The high level function that is the main API of the linenoise library. */ char *linenoise(const char *prompt) { char buf[LINENOISE_MAX_LINE]; - char *retval = linenoiseBlockingEdit(buf,LINENOISE_MAX_LINE,prompt); return retval; } diff --git a/components/console/linenoise/linenoise.h b/components/console/linenoise/linenoise.h index f42843a..68137a6 100644 --- a/components/console/linenoise/linenoise.h +++ b/components/console/linenoise/linenoise.h @@ -45,6 +45,7 @@ extern "C" { #endif #include /* For size_t. */ +#include extern char *linenoiseEditMore; @@ -105,7 +106,8 @@ void linenoiseHistoryFree(); /* Other utilities. */ void linenoiseClearScreen(void); void linenoiseSetMultiLine(int ml); -void linenoisePrintKeyCodes(void); +void linenoiseSetDumbMode(int set); +bool linenoiseIsDumbMode(void); void linenoiseMaskModeEnable(void); void linenoiseMaskModeDisable(void);