#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/fcntl.h>
#include <unistd.h>
#include "linenoise.h"
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;
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. */
/* 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;
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;
}
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
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);
void linenoiseHistoryFree();
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
+void linenoiseSetDumbMode(int set);
void linenoisePrintKeyCodes(void);
#ifdef __cplusplus
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);