static void repl() { int argc, j; char *line; sds *argv; config.interactive = 1; linenoiseSetCompletionCallback(completionCallback); while((line = linenoise(db ? "redislite> " : "not connected> ")) != NULL) { if (line[0] != '\0') { argv = sdssplitargs(line, &argc); linenoiseHistoryAdd(line); if (config.historyfile) { linenoiseHistorySave(config.historyfile); } if (argv == NULL) { printf("Invalid argument(s)\n"); continue; } else if (argc > 0) { if (strcasecmp(argv[0], "quit") == 0 || strcasecmp(argv[0], "exit") == 0) { exit(0); } else if (argc == 1 && !strcasecmp(argv[0], "clear")) { linenoiseClearScreen(); } else { long long start_time = mstime(), elapsed; if (cliSendCommand(argc, argv, 1) != REDISLITE_OK) { cliConnect(1); /* If we still cannot send the command, * print error and abort. */ if (cliSendCommand(argc, argv, 1) != REDISLITE_OK) { cliPrintContextErrorAndExit(); } } elapsed = mstime() - start_time; if (elapsed >= 500) { printf("(%.2fs)\n", (double)elapsed / 1000); } } } /* Free the argument vector */ for (j = 0; j < argc; j++) { sdsfree(argv[j]); } redislite_free(argv); } /* linenoise() returns malloc-ed lines like readline() */ free(line); } exit(0); }
int main(int argc, char** argv) { /* Create parsers */ mpc_parser_t* Number = mpc_new("number"); mpc_parser_t* Operator = mpc_new("operator"); mpc_parser_t* Expression = mpc_new("expression"); mpc_parser_t* Lispy = mpc_new("lispy"); linenoiseClearScreen(); /* Define them with the language as follows */ mpca_lang(MPCA_LANG_DEFAULT, " number : /-?[0-9]+/ ; " " operator : '+' | '/' | '*' | '-' ; " " expression : <number> | '(' <operator> <expression>+ ')' ; " " lispy : /^/ <operator>* <expression> /$/ ; ", Number, Operator, Expression, Lispy); char *line = NULL; while((line = linenoise("Lispy> ")) != NULL ) { mpc_result_t result; if (mpc_parse("<stdin>" , line, Lispy, &result)) { mpc_ast_print(result.output); mpc_ast_delete(result.output); } else { mpc_err_print(result.output); mpc_err_delete(result.output); } free(line); } mpc_cleanup(4, Number, Operator, Expression, Lispy); return 0; }
static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; size_t len = 0; size_t cols = getColumns(); buf[0] = '\0'; buflen--; /* Make sure there is always space for the nulterm */ /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoiseHistoryAdd(""); history_index = history_len-1; if (write(1,prompt,plen) == -1) return -1; while(1) { char c = linenoiseReadChar(fd); if (c == 0) return len; if (c == (char)-1) { refreshLine(fd,prompt,buf,len,pos,cols); continue; } /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ if (c == 9 && completionCallback != NULL) { c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols); /* Return on errors */ if (c < 0) return len; /* Read next character when 0 */ if (c == 0) continue; } switch(c) { case 13: /* enter */ history_len--; free(history[history_len]); return (int)len; case 3: /* ctrl-c */ errno = EAGAIN; return -1; case 127: /* delete */ if (len > 0 && pos < len) { memmove(buf+pos,buf+pos+1,len-pos-1); len--; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } break; case 8: /* backspace or ctrl-h */ if (pos > 0 && len > 0) { memmove(buf+pos-1,buf+pos,len-pos); pos--; len--; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } break; case 4: /* ctrl-d, remove char at right of cursor */ if (len > 1 && pos < (len-1)) { memmove(buf+pos,buf+pos+1,len-pos); len--; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } else if (len == 0) { history_len--; free(history[history_len]); return -1; } break; case 20: /* ctrl-t */ if (pos > 0 && pos < len) { int aux = buf[pos-1]; buf[pos-1] = buf[pos]; buf[pos] = aux; if (pos != len-1) pos++; refreshLine(fd,prompt,buf,len,pos,cols); } break; case 2: /* ctrl-b */ /* left arrow */ if (pos > 0) { pos--; refreshLine(fd,prompt,buf,len,pos,cols); } break; case 6: /* ctrl-f */ /* right arrow */ if (pos != len) { pos++; refreshLine(fd,prompt,buf,len,pos,cols); } break; case 16: /* ctrl-p */ case 14: /* ctrl-n */ /* up and down arrow: history */ if (history_len > 1) { /* Update the current history entry before to * overwrite it with tne next one. */ free(history[history_index]); history[history_index] = strdup(buf); /* Show the new entry */ history_index += (c == 16) ? -1 : 1; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_len) { history_index = history_len-1; break; } strncpy(buf,history[history_index],buflen); buf[buflen] = '\0'; len = pos = strlen(buf); refreshLine(fd,prompt,buf,len,pos,cols); } break; case 27: /* escape sequence */ break; /* should be handled by linenoiseReadChar */ default: if (len < buflen) { if (len == pos) { buf[pos] = c; pos++; len++; buf[len] = '\0'; if (plen+len < cols) { /* Avoid a full update of the line in the * trivial case. */ if (write(1,&c,1) == -1) return -1; } else { refreshLine(fd,prompt,buf,len,pos,cols); } } else { memmove(buf+pos+1,buf+pos,len-pos); buf[pos] = c; len++; pos++; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } } break; case 21: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; pos = len = 0; refreshLine(fd,prompt,buf,len,pos,cols); break; case 11: /* Ctrl+k, delete from current to end of line. */ buf[pos] = '\0'; len = pos; refreshLine(fd,prompt,buf,len,pos,cols); break; case 1: /* Ctrl+a, go to the start of the line */ pos = 0; refreshLine(fd,prompt,buf,len,pos,cols); break; case 5: /* ctrl+e, go to the end of the line */ pos = len; refreshLine(fd,prompt,buf,len,pos,cols); break; case 12: /* ctrl+l, clear screen */ linenoiseClearScreen(); refreshLine(fd,prompt,buf,len,pos,cols); } } return len; }
static int linenoiseEdit(struct current *current) { int history_index = 0; /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoiseHistoryAdd(""); set_current(current, ""); refreshLine(current->prompt, current); while(1) { int dir = -1; int c = fd_read(current); #ifndef NO_COMPLETION /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ if (c == '\t' && current->pos == current->chars && completionCallback != NULL) { c = completeLine(current); /* Return on errors */ if (c < 0) return current->len; /* Read next character when 0 */ if (c == 0) continue; } #endif process_char: if (c == -1) return current->len; #ifdef USE_TERMIOS if (c == 27) { /* escape sequence */ c = check_special(current->fd); } #endif switch(c) { case '\r': /* enter */ history_len--; free(history[history_len]); return current->len; case ctrl('C'): /* ctrl-c */ errno = EAGAIN; return -1; case 127: /* backspace */ case ctrl('H'): if (remove_char(current, current->pos - 1) == 1) { refreshLine(current->prompt, current); } break; case ctrl('D'): /* ctrl-d */ if (current->len == 0) { /* Empty line, so EOF */ history_len--; free(history[history_len]); return -1; } /* Otherwise fall through to delete char to right of cursor */ case SPECIAL_DELETE: if (remove_char(current, current->pos) == 1) { refreshLine(current->prompt, current); } break; case SPECIAL_INSERT: /* Ignore. Expansion Hook. * Future possibility: Toggle Insert/Overwrite Modes */ break; case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */ /* eat any spaces on the left */ { int pos = current->pos; while (pos > 0 && get_char(current, pos - 1) == ' ') { pos--; } /* now eat any non-spaces on the left */ while (pos > 0 && get_char(current, pos - 1) != ' ') { pos--; } if (remove_chars(current, pos, current->pos - pos)) { refreshLine(current->prompt, current); } } break; case ctrl('R'): /* ctrl-r */ { /* Display the reverse-i-search prompt and process chars */ char rbuf[50]; char rprompt[80]; int rchars = 0; int rlen = 0; int searchpos = history_len - 1; rbuf[0] = 0; while (1) { int n = 0; const char *p = NULL; int skipsame = 0; int searchdir = -1; snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf); refreshLine(rprompt, current); c = fd_read(current); if (c == ctrl('H') || c == 127) { if (rchars) { int p = utf8_index(rbuf, --rchars); rbuf[p] = 0; rlen = strlen(rbuf); } continue; } #ifdef USE_TERMIOS if (c == 27) { c = check_special(current->fd); } #endif if (c == ctrl('P') || c == SPECIAL_UP) { /* Search for the previous (earlier) match */ if (searchpos > 0) { searchpos--; } skipsame = 1; } else if (c == ctrl('N') || c == SPECIAL_DOWN) { /* Search for the next (later) match */ if (searchpos < history_len) { searchpos++; } searchdir = 1; skipsame = 1; } else if (c >= ' ') { if (rlen >= (int)sizeof(rbuf) + 3) { continue; } n = utf8_getchars(rbuf + rlen, c); rlen += n; rchars++; rbuf[rlen] = 0; /* Adding a new char resets the search location */ searchpos = history_len - 1; } else { /* Exit from incremental search mode */ break; } /* Now search through the history for a match */ for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) { p = strstr(history[searchpos], rbuf); if (p) { /* Found a match */ if (skipsame && strcmp(history[searchpos], current->buf) == 0) { /* But it is identical, so skip it */ continue; } /* Copy the matching line and set the cursor position */ set_current(current,history[searchpos]); current->pos = utf8_strlen(history[searchpos], p - history[searchpos]); break; } } if (!p && n) { /* No match, so don't add it */ rchars--; rlen -= n; rbuf[rlen] = 0; } } if (c == ctrl('G') || c == ctrl('C')) { /* ctrl-g terminates the search with no effect */ set_current(current, ""); c = 0; } else if (c == ctrl('J')) { /* ctrl-j terminates the search leaving the buffer in place */ c = 0; } /* Go process the char normally */ refreshLine(current->prompt, current); goto process_char; } break; case ctrl('T'): /* ctrl-t */ if (current->pos > 0 && current->pos <= current->chars) { /* If cursor is at end, transpose the previous two chars */ int fixer = (current->pos == current->chars); c = get_char(current, current->pos - fixer); remove_char(current, current->pos - fixer); insert_char(current, current->pos - 1, c); refreshLine(current->prompt, current); } break; case ctrl('V'): /* ctrl-v */ if (has_room(current, 3)) { /* Insert the ^V first */ if (insert_char(current, current->pos, c)) { refreshLine(current->prompt, current); /* Now wait for the next char. Can insert anything except \0 */ c = fd_read(current); /* Remove the ^V first */ remove_char(current, current->pos - 1); if (c != -1) { /* Insert the actual char */ insert_char(current, current->pos, c); } refreshLine(current->prompt, current); } } break; case ctrl('B'): case SPECIAL_LEFT: if (current->pos > 0) { current->pos--; refreshLine(current->prompt, current); } break; case ctrl('F'): case SPECIAL_RIGHT: if (current->pos < current->chars) { current->pos++; refreshLine(current->prompt, current); } break; case SPECIAL_PAGE_UP: dir = history_len - history_index - 1; /* move to start of history */ goto history_navigation; case SPECIAL_PAGE_DOWN: dir = -history_index; /* move to 0 == end of history, i.e. current */ goto history_navigation; case ctrl('P'): case SPECIAL_UP: dir = 1; goto history_navigation; case ctrl('N'): case SPECIAL_DOWN: history_navigation: if (history_len > 1) { /* Update the current history entry before to * overwrite it with tne next one. */ free(history[history_len - 1 - history_index]); history[history_len - 1 - history_index] = strdup(current->buf); /* Show the new entry */ history_index += dir; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_len) { history_index = history_len - 1; break; } set_current(current, history[history_len - 1 - history_index]); refreshLine(current->prompt, current); } break; case ctrl('A'): /* Ctrl+a, go to the start of the line */ case SPECIAL_HOME: current->pos = 0; refreshLine(current->prompt, current); break; case ctrl('E'): /* ctrl+e, go to the end of the line */ case SPECIAL_END: current->pos = current->chars; refreshLine(current->prompt, current); break; case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */ if (remove_chars(current, 0, current->pos)) { refreshLine(current->prompt, current); } break; case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */ if (remove_chars(current, current->pos, current->chars - current->pos)) { refreshLine(current->prompt, current); } break; case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */ if (current->capture && insert_chars(current, current->pos, current->capture)) { refreshLine(current->prompt, current); } break; case ctrl('L'): /* Ctrl+L, clear screen */ linenoiseClearScreen(); /* Force recalc of window size for serial terminals */ current->cols = 0; refreshLine(current->prompt, current); break; default: /* Only tab is allowed without ^V */ if (c == '\t' || c >= ' ') { if (insert_char(current, current->pos, c) == 1) { refreshLine(current->prompt, current); } } break; } } return current->len; }
static int l_clearscreen(lua_State *L) { linenoiseClearScreen(); return handle_ln_ok(L); }
static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; size_t len = 0; size_t cols = getColumns(); int history_index = 0; #ifdef _WIN32 DWORD foo; #endif buf[0] = '\0'; buflen--; /* Make sure there is always space for the nulterm */ /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoiseHistoryAdd(""); #ifdef _WIN32 if (!WriteConsole(hOut, prompt, (DWORD)plen, &foo, NULL)) return -1; #else if (write(fd,prompt,plen) == -1) return -1; #endif while(1) { char c; int nread; char seq[2], seq2[2]; #ifdef _WIN32 nread = win32read(&c); #else nread = read(fd,&c,1); #endif if (nread <= 0) return (int)len; /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ if (c == 9 && completionCallback != NULL) { c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols); /* Return on errors */ if (c < 0) return (int)len; /* Read next character when 0 */ if (c == 0) continue; } switch(c) { case 13: /* enter */ history_len--; free(history[history_len]); return (int)len; case 3: /* ctrl-c */ errno = EAGAIN; return -1; case 127: /* backspace */ #ifdef _WIN32 /* delete in _WIN32*/ /* win32read() will send 127 for DEL and 8 for BS and Ctrl-H */ if (pos < len && len > 0) { memmove(buf+pos,buf+pos+1,len-pos); len--; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } break; #endif case 8: /* ctrl-h */ if (pos > 0 && len > 0) { memmove(buf+pos-1,buf+pos,len-pos); pos--; len--; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } break; case 4: /* ctrl-d, remove char at right of cursor */ if (len > 1 && pos < (len-1)) { memmove(buf+pos,buf+pos+1,len-pos); len--; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } else if (len == 0) { history_len--; free(history[history_len]); return -1; } break; case 20: /* ctrl-t */ if (pos > 0 && pos < len) { int aux = buf[pos-1]; buf[pos-1] = buf[pos]; buf[pos] = aux; if (pos != len-1) pos++; refreshLine(fd,prompt,buf,len,pos,cols); } break; case 2: /* ctrl-b */ goto left_arrow; case 6: /* ctrl-f */ goto right_arrow; case 16: /* ctrl-p */ seq[1] = 65; goto up_down_arrow; case 14: /* ctrl-n */ seq[1] = 66; goto up_down_arrow; break; case 27: /* escape sequence */ if (read(fd,seq,2) == -1) break; if (seq[0] == 91 && seq[1] == 68) { left_arrow: /* left arrow */ if (pos > 0) { pos--; refreshLine(fd,prompt,buf,len,pos,cols); } } else if (seq[0] == 91 && seq[1] == 67) { right_arrow: /* right arrow */ if (pos != len) { pos++; refreshLine(fd,prompt,buf,len,pos,cols); } } else if (seq[0] == 91 && (seq[1] == 65 || seq[1] == 66)) { up_down_arrow: /* up and down arrow: history */ if (history_len > 1) { /* Update the current history entry before to * overwrite it with tne next one. */ free(history[history_len-1-history_index]); history[history_len-1-history_index] = strdup(buf); /* Show the new entry */ history_index += (seq[1] == 65) ? 1 : -1; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_len) { history_index = history_len-1; break; } strncpy(buf,history[history_len-1-history_index],buflen); buf[buflen] = '\0'; len = pos = strlen(buf); refreshLine(fd,prompt,buf,len,pos,cols); } } else if (seq[0] == 91 && seq[1] > 48 && seq[1] < 55) { /* extended escape */ if (read(fd,seq2,2) == -1) break; if (seq[1] == 51 && seq2[0] == 126) { /* delete */ if (len > 0 && pos < len) { memmove(buf+pos,buf+pos+1,len-pos-1); len--; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } } } break; default: if (len < buflen) { if (len == pos) { buf[pos] = c; pos++; len++; buf[len] = '\0'; if (plen+len < cols) { /* Avoid a full update of the line in the * trivial case. */ #ifdef _WIN32 if (!WriteConsole(hOut, &c, 1, &foo, NULL)) return -1; #else if (write(fd,&c,1) == -1) return -1; #endif } else { refreshLine(fd,prompt,buf,len,pos,cols); } } else { memmove(buf+pos+1,buf+pos,len-pos); buf[pos] = c; len++; pos++; buf[len] = '\0'; refreshLine(fd,prompt,buf,len,pos,cols); } } break; case 21: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; pos = len = 0; refreshLine(fd,prompt,buf,len,pos,cols); break; case 11: /* Ctrl+k, delete from current to end of line. */ buf[pos] = '\0'; len = pos; refreshLine(fd,prompt,buf,len,pos,cols); break; case 1: /* Ctrl+a, go to the start of the line */ pos = 0; refreshLine(fd,prompt,buf,len,pos,cols); break; case 5: /* ctrl+e, go to the end of the line */ pos = len; refreshLine(fd,prompt,buf,len,pos,cols); break; case 12: /* ctrl+l, clear screen */ linenoiseClearScreen(); refreshLine(fd,prompt,buf,len,pos,cols); } } return (int)len; }
static void repl() { sds historyfile = NULL; int history = 0; char *line; int argc; sds *argv; config.interactive = 1; linenoiseSetCompletionCallback(completionCallback); /* Only use history when stdin is a tty. */ if (isatty(fileno(stdin))) { history = 1; if (getenv("HOME") != NULL) { historyfile = sdscatprintf(sdsempty(),"%s/.rediscli_history",getenv("HOME")); linenoiseHistoryLoad(historyfile); } } cliRefreshPrompt(); while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) { if (line[0] != '\0') { argv = sdssplitargs(line,&argc); if (history) linenoiseHistoryAdd(line); if (historyfile) linenoiseHistorySave(historyfile); if (argv == NULL) { printf("Invalid argument(s)\n"); free(line); continue; } else if (argc > 0) { if (strcasecmp(argv[0],"quit") == 0 || strcasecmp(argv[0],"exit") == 0) { exit(0); } else if (argc == 3 && !strcasecmp(argv[0],"connect")) { sdsfree(config.hostip); config.hostip = sdsnew(argv[1]); config.hostport = atoi(argv[2]); cliConnect(1); } else if (argc == 1 && !strcasecmp(argv[0],"clear")) { linenoiseClearScreen(); } else { long long start_time = mstime(), elapsed; int repeat, skipargs = 0; repeat = atoi(argv[0]); if (argc > 1 && repeat) { skipargs = 1; } else { repeat = 1; } while (1) { config.cluster_reissue_command = 0; if (cliSendCommand(argc-skipargs,argv+skipargs,repeat) != REDIS_OK) { cliConnect(1); /* If we still cannot send the command print error. * We'll try to reconnect the next time. */ if (cliSendCommand(argc-skipargs,argv+skipargs,repeat) != REDIS_OK) cliPrintContextError(); } /* Issue the command again if we got redirected in cluster mode */ if (config.cluster_mode && config.cluster_reissue_command) { cliConnect(1); } else { break; } } elapsed = mstime()-start_time; if (elapsed >= 500) { printf("(%.2fs)\n",(double)elapsed/1000); } } } /* Free the argument vector */ while(argc--) sdsfree(argv[argc]); zfree(argv); } /* linenoise() returns malloc-ed lines like readline() */ free(line); } exit(0); }
static int linenoiseEdit(char *buf, size_t buflen, const char *prompt) { struct linenoiseState l = { .buf = buf, .buflen = buflen, .prompt = prompt, .plen = strlen(prompt), .oldpos = 0, .pos = 0, .len = 0, .cols = 80, .maxrows = 0, .history_index = 0, }; /* Buffer starts empty. */ buf[0] = '\0'; buflen--; /* Make sure there is always space for the nulterm */ /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoiseHistoryAdd(""); serial.puts(prompt); while (1) { char c; char seq[2] = {0}; c = serial.getc(); /* Only autocomplete when the callback is set. */ if (c == 9 && completionCallback != NULL) { c = completeLine(&l); /* Return on errors */ if (c < 0) return l.len; /* Read next character when 0 */ if (c == 0) continue; } switch (c) { case ENTER: /* enter */ history_len--; free(history[history_len]); return (int)l.len; case CTRL_C: return -1; case BACKSPACE: /* backspace */ case CTRL_H: /* ctrl-h */ linenoiseEditBackspace(&l); break; case CTRL_D: /* ctrl-d, remove char at right of cursor, or of the line is empty, act as end-of-file. */ if (l.len > 0) { linenoiseEditDelete(&l); } else { history_len--; free(history[history_len]); return -1; } break; case CTRL_T: /* ctrl-t, swaps current character with previous. */ if (l.pos > 0 && l.pos < l.len) { int aux = buf[l.pos - 1]; buf[l.pos - 1] = buf[l.pos]; buf[l.pos] = aux; if (l.pos != l.len - 1) l.pos++; refreshLine(&l); } break; case CTRL_B: /* ctrl-b */ linenoiseEditMoveLeft(&l); break; case CTRL_F: /* ctrl-f */ linenoiseEditMoveRight(&l); break; case CTRL_P: /* ctrl-p */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; case CTRL_N: /* ctrl-n */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; /* escape sequence */ case ESC: seq[0] = serial.getc(); seq[1] = serial.getc(); if (seq[0] == ARROW_PREFIX && seq[1] == LEFT_ARROW) { /* Left arrow */ linenoiseEditMoveLeft(&l); } else if (seq[0] == ARROW_PREFIX && seq[1] == RIGHT_ARROW) { /* Right arrow */ linenoiseEditMoveRight(&l); } else if (seq[0] == ARROW_PREFIX && (seq[1] == UP_ARROW || seq[1] == DOWN_ARROW)) { /* Up and Down arrows */ linenoiseEditHistoryNext(&l, (seq[1] == UP_ARROW) ? LINENOISE_HISTORY_PREV : LINENOISE_HISTORY_NEXT); } //Here is also a extanded escape! break; default: linenoiseEditInsert(&l, c); break; case CTRL_U: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; l.pos = l.len = 0; refreshLine(&l); break; case CTRL_K: /* Ctrl+k, delete from current to end of line. */ buf[l.pos] = '\0'; l.len = l.pos; refreshLine(&l); break; case CTRL_A: /* Ctrl+a, go to the start of the line */ l.pos = 0; refreshLine(&l); break; case CTRL_E: /* ctrl+e, go to the end of the line */ l.pos = l.len; refreshLine(&l); break; case CTRL_L: /* ctrl+l, clear screen */ linenoiseClearScreen(); refreshLine(&l); break; case CTRL_W: /* ctrl+w, delete previous word */ linenoiseEditDeletePrevWord(&l); break; } } return l.len; } static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { int count; count = linenoiseEdit(buf, buflen, prompt); serial.puts("\n\r"); return count; }
/* This function is the core of the line editing capability of linenoise. * It expects 'fd' to be already in "raw mode" so that every key pressed * will be returned ASAP to read(). * * The resulting string is put into 'buf' when the user type enter, or * when ctrl+d is typed. * * The function returns the length of the current buffer. */ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, char *prompt) { struct linenoiseState l; /* Populate the linenoise state that we pass to functions implementing * specific editing functionalities. */ l.ifd = stdin_fd; l.ofd = stdout_fd; l.buf = buf; l.buflen = buflen; l.prompt = prompt; l.plen = strlen(prompt); l.oldpos = l.pos = 0; l.len = 0; l.cols = getColumns(stdin_fd, stdout_fd); l.maxrows = 0; l.history_index = 0; /* Buffer starts empty. */ l.buf[0] = '\0'; l.buflen--; /* Make sure there is always space for the nulterm */ /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoiseHistoryAdd(""); if (write(l.ofd,prompt,l.plen) == -1) return -1; while(1) { char c; int nread; char seq[3]; nread = read(l.ifd,&c,1); if (nread <= 0) return l.len; /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ if (c == 9 && completionCallback != NULL) { c = completeLine(&l); /* Return on errors */ if (c < 0) return l.len; /* Read next character when 0 */ if (c == 0) continue; } switch(c) { case ENTER: /* enter */ history_len--; free(history[history_len]); if (mlmode) linenoiseEditMoveEnd(&l); return (int)l.len; case CTRL_C: /* ctrl-c */ errno = EAGAIN; return -1; case BACKSPACE: /* backspace */ case 8: /* ctrl-h */ linenoiseEditBackspace(&l); break; case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the line is empty, act as end-of-file. */ if (l.len > 0) { linenoiseEditDelete(&l); } else { history_len--; free(history[history_len]); return -1; } break; case CTRL_T: /* ctrl-t, swaps current character with previous. */ if (l.pos > 0 && l.pos < l.len) { int aux = buf[l.pos-1]; buf[l.pos-1] = buf[l.pos]; buf[l.pos] = aux; if (l.pos != l.len-1) l.pos++; refreshLine(&l); } break; case CTRL_B: /* ctrl-b */ linenoiseEditMoveLeft(&l); break; case CTRL_F: /* ctrl-f */ linenoiseEditMoveRight(&l); break; case CTRL_P: /* ctrl-p */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; case CTRL_N: /* ctrl-n */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; case ESC: /* escape sequence */ /* Read the next two bytes representing the escape sequence. * Use two calls to handle slow terminals returning the two * chars at different times. */ if (read(l.ifd,seq,1) == -1) break; if (read(l.ifd,seq+1,1) == -1) break; /* ESC [ sequences. */ if (seq[0] == '[') { if (seq[1] >= '0' && seq[1] <= '9') { /* Extended escape, read additional byte. */ if (read(l.ifd,seq+2,1) == -1) break; if (seq[2] == '~') { switch(seq[1]) { case '3': /* Delete key. */ linenoiseEditDelete(&l); break; } } } else { switch(seq[1]) { case 'A': /* Up */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; case 'B': /* Down */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; case 'C': /* Right */ linenoiseEditMoveRight(&l); break; case 'D': /* Left */ linenoiseEditMoveLeft(&l); break; case 'H': /* Home */ linenoiseEditMoveHome(&l); break; case 'F': /* End*/ linenoiseEditMoveEnd(&l); break; } } } /* ESC O sequences. */ else if (seq[0] == 'O') { switch(seq[1]) { case 'H': /* Home */ linenoiseEditMoveHome(&l); break; case 'F': /* End*/ linenoiseEditMoveEnd(&l); break; } } break; default: if (linenoiseEditInsert(&l,c)) return -1; break; case CTRL_U: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; l.pos = l.len = 0; refreshLine(&l); break; case CTRL_K: /* Ctrl+k, delete from current to end of line. */ buf[l.pos] = '\0'; l.len = l.pos; refreshLine(&l); break; case CTRL_A: /* Ctrl+a, go to the start of the line */ linenoiseEditMoveHome(&l); break; case CTRL_E: /* ctrl+e, go to the end of the line */ linenoiseEditMoveEnd(&l); break; case CTRL_L: /* ctrl+l, clear screen */ linenoiseClearScreen(); refreshLine(&l); break; case CTRL_W: /* ctrl+w, delete previous word */ linenoiseEditDeletePrevWord(&l); break; } } return l.len; }
void lineedit_clear_screen() { linenoiseClearScreen(); refreshLine(&l); }
void Console::clearScreen() { linenoiseClearScreen(); }