console: add support for terminal probing and dumb terminal mode
This commit is contained in:
parent
1e4587a09f
commit
10f0543080
3 changed files with 137 additions and 31 deletions
|
@ -112,6 +112,7 @@
|
|||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "linenoise.h"
|
||||
|
||||
|
@ -123,6 +124,7 @@ static linenoiseHintsCallback *hintsCallback = NULL;
|
|||
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
||||
|
||||
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;
|
||||
|
@ -194,6 +196,11 @@ void linenoiseSetMultiLine(int ml) {
|
|||
mlmode = ml;
|
||||
}
|
||||
|
||||
/* Set if terminal does not recognize escape sequences */
|
||||
void linenoiseSetDumbMode(int set) {
|
||||
dumbmode = set;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
@ -204,6 +211,7 @@ static int getCursorPosition() {
|
|||
|
||||
/* Report cursor location */
|
||||
fprintf(stdout, "\x1b[6n");
|
||||
|
||||
/* Read the response: ESC [ rows ; cols R */
|
||||
while (i < sizeof(buf)-1) {
|
||||
if (fread(buf+i, 1, 1, stdin) != 1) break;
|
||||
|
@ -875,6 +883,38 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
|
|||
return l.len;
|
||||
}
|
||||
|
||||
int linenoiseProbe() {
|
||||
/* Switch to non-blocking mode */
|
||||
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");
|
||||
|
||||
/* Try to read response */
|
||||
int timeout_ms = 200;
|
||||
size_t read_bytes = 0;
|
||||
while (timeout_ms > 0 && read_bytes < 4) { // response is ESC[0n or ESC[3n
|
||||
usleep(1000);
|
||||
char c;
|
||||
int cb = fread(&c, 1, 1, stdin);
|
||||
read_bytes += cb;
|
||||
timeout_ms--;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
||||
int count;
|
||||
|
@ -885,18 +925,65 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
|||
}
|
||||
|
||||
count = linenoiseEdit(buf, buflen, prompt);
|
||||
printf("\n");
|
||||
fputc('\n', stdout);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int linenoiseDumb(char* buf, size_t buflen, const char* prompt) {
|
||||
/* dumb terminal, fall back to fgets */
|
||||
fputs(prompt, stdout);
|
||||
int count = 0;
|
||||
while (count < 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 (count > 0) {
|
||||
buf[count - 1] = 0;
|
||||
count --;
|
||||
}
|
||||
fputs("\x08 ", stdout); /* Windows CMD: erase symbol under cursor */
|
||||
} else {
|
||||
buf[count] = c;
|
||||
++count;
|
||||
}
|
||||
fputc(c, stdout); /* echo */
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void sanitize(char* src) {
|
||||
char* dst = src;
|
||||
for (int c = *src; c != 0; src++, c = *src) {
|
||||
if (isprint(c)) {
|
||||
*dst = c;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
/* The high level function that is the main API of the linenoise library. */
|
||||
char *linenoise(const char *prompt) {
|
||||
char buf[LINENOISE_MAX_LINE];
|
||||
int count;
|
||||
|
||||
count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
|
||||
if (count == -1) return NULL;
|
||||
return strdup(buf);
|
||||
char *buf = calloc(1, LINENOISE_MAX_LINE);
|
||||
int count = 0;
|
||||
if (!dumbmode) {
|
||||
count = linenoiseRaw(buf, LINENOISE_MAX_LINE, prompt);
|
||||
} else {
|
||||
count = linenoiseDumb(buf, LINENOISE_MAX_LINE, prompt);
|
||||
}
|
||||
if (count > 0) {
|
||||
sanitize(buf);
|
||||
count = strlen(buf);
|
||||
}
|
||||
if (count <= 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* This is just a wrapper the user may want to call in order to make sure
|
||||
|
|
|
@ -56,6 +56,7 @@ void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
|||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||
|
||||
int linenoiseProbe(void);
|
||||
char *linenoise(const char *prompt);
|
||||
void linenoiseFree(void *ptr);
|
||||
int linenoiseHistoryAdd(const char *line);
|
||||
|
@ -65,6 +66,7 @@ int linenoiseHistoryLoad(const char *filename);
|
|||
void linenoiseHistoryFree();
|
||||
void linenoiseClearScreen(void);
|
||||
void linenoiseSetMultiLine(int ml);
|
||||
void linenoiseSetDumbMode(int set);
|
||||
void linenoisePrintKeyCodes(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -105,41 +105,58 @@ void app_main()
|
|||
register_system();
|
||||
register_wifi();
|
||||
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
const char* prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
|
||||
|
||||
printf("\n"
|
||||
"This is an example of ESP-IDF console component.\n"
|
||||
"Type 'help' to get the list of commands.\n"
|
||||
"Use UP/DOWN arrows to navigate through command history.\n"
|
||||
"Press TAB when typing command name to auto-complete.\n");
|
||||
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
const char* prompt = LOG_COLOR_I "[esp32]> " LOG_RESET_COLOR;
|
||||
/* Figure out if the terminal supports escape sequences */
|
||||
int probe_status = linenoiseProbe();
|
||||
if (probe_status) { /* zero indicates success */
|
||||
printf("\n"
|
||||
"Your terminal application does not support escape sequences.\n"
|
||||
"Line editing and history features are disabled.\n"
|
||||
"On Windows, try using Putty instead.\n");
|
||||
linenoiseSetDumbMode(1);
|
||||
#if CONFIG_LOG_COLORS
|
||||
/* Since the terminal doesn't support escape sequences,
|
||||
* don't use color codes in the prompt.
|
||||
*/
|
||||
prompt = "esp32> ";
|
||||
#endif //CONFIG_LOG_COLORS
|
||||
}
|
||||
|
||||
/* Main loop */
|
||||
char *line;
|
||||
/* Get a line using linenoise.
|
||||
* The line is returned when ENTER is pressed.
|
||||
*/
|
||||
while((line = linenoise(prompt)) != NULL) {
|
||||
if (strlen(line) > 0) { /* Ignore empty lines */
|
||||
/* Add the command to the history */
|
||||
linenoiseHistoryAdd(line);
|
||||
while(true) {
|
||||
/* Get a line using linenoise.
|
||||
* The line is returned when ENTER is pressed.
|
||||
*/
|
||||
char* line = linenoise(prompt);
|
||||
if (line == NULL) { /* Ignore empty lines */
|
||||
continue;
|
||||
}
|
||||
/* Add the command to the history */
|
||||
linenoiseHistoryAdd(line);
|
||||
#if CONFIG_STORE_HISTORY
|
||||
/* Save command history to filesystem */
|
||||
linenoiseHistorySave(HISTORY_PATH);
|
||||
/* Save command history to filesystem */
|
||||
linenoiseHistorySave(HISTORY_PATH);
|
||||
#endif
|
||||
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
printf("Unrecognized command\n");
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
printf("Command returned non-zero error code: 0x%x\n", ret);
|
||||
} else if (err != ESP_OK) {
|
||||
printf("Internal error: 0x%x\n", err);
|
||||
}
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
printf("Unrecognized command\n");
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
printf("Command returned non-zero error code: 0x%x\n", ret);
|
||||
} else if (err != ESP_OK) {
|
||||
printf("Internal error: 0x%x\n", err);
|
||||
}
|
||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||
linenoiseFree(line);
|
||||
|
|
Loading…
Reference in a new issue