// (term-getchar ['sym]) -> num any plisp_term_getchar(any ex) { any x, y; int temp = TERM_INPUT_WAIT, ret; // if number of args is > 0 // get value; else getchar() // will wait. if (plen(ex) > 0) { x = cdr(ex); NeedNum(ex, y = EVAL(car(x))); return ((ret = term_getch(temp = unBox(y))) == -1? Nil : box(ret)); } return ((ret = term_getch(temp)) == -1? Nil : box(ret)); }
// 'wofmt' handler static void shell_wofmt( int argc, char **argv ) { #ifndef BUILD_WOFS printf( "WOFS not enabled.\n" ); #else // #ifndef BUILD_WOFS int c; printf( "Formatting the internal WOFS will DESTROY ALL THE FILES FROM WOFS.\n" ); while( 1 ) { printf( "Are you sure you want to continue? [y/n] " ); c = term_getch( TERM_INPUT_WAIT ); printf( "%c\n", isprint( c ) ? c : ' ' ); c = tolower( c ); if( c == 'n' ) return; else if( c == 'y' ) break; } printf( "Formatting ... " ); if( !wofs_format() ) { printf( "\ni*** ERROR ***: unable to erase the internal flash. WOFS might be compromised.\n" ); printf( "It is advised to re-flash the eLua image.\n" ); } else printf( " done.\n" ); #endif // #ifndef BUILD_WOFS }
// Helper: ask yes/no // Returns 1 for yes, 0 for no int shellh_ask_yes_no( const char *prompt ) { int c; if( prompt ) printf( "%s ", prompt ); while( 1 ) { #ifdef BUILD_TERM c = term_getch( TERM_INPUT_WAIT ); #else c = platform_uart_recv( CON_UART_ID, 0 /*UNUSED*/, PLATFORM_TIMER_INF_TIMEOUT ); #endif if( c == 'y' || c == 'Y' ) { printf( "y\n" ); return 1; } if( c == 'n' || c == 'N' ) { printf( "n\n" ); return 0; } } // Will never get here return 0; }
// Lua: key = getchar( [ mode ] ) static int luaterm_getchar( lua_State* L ) { int temp = TERM_INPUT_WAIT; if( lua_isnumber( L, 1 ) ) temp = lua_tointeger( L, 1 ); lua_pushinteger( L, term_getch( temp ) ); return 1; }
// picoc: key = term_getchar(mode); static void pterm_getchar(pstate *p, val *r, val **param, int n) { int temp, res; temp = param[0]->Val->Integer; res = term_getch(temp); if (!res) { r->Val->Integer = -1; return; } r->Val->Integer = res; }
// Helper: ask yes/no // Returns 1 for yes, 0 for no int shellh_ask_yes_no( const char *prompt ) { int c; if( prompt ) printf( "%s ", prompt ); while( 1 ) { c = term_getch( TERM_INPUT_WAIT ); if( c == 'y' || c == 'Y' ) { printf( "y\n" ); return 1; } if( c == 'n' || c == 'N' ) { printf( "n\n" ); return 0; } } // Will never get here return 0; }
static int linenoisePrompt(int id, char *buf, size_t buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; size_t len = 0; size_t cols = TERM_COLS; int history_index = 0; 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. */ linenoise_internal_addhistory( id, "", LINENOISE_PUSH_EMPTY ); term_putstr( prompt, plen ); while(1) { int c; c = term_getch( TERM_INPUT_WAIT ); switch(c) { case KC_ENTER: case KC_CTRL_C: case KC_CTRL_Z: history_lengths[ id ] --; free( histories[ id ][history_lengths[ id ]] ); if( c == KC_CTRL_C ) return LINENOISE_CTRL_C; else if( c == KC_CTRL_Z ) return -1; return len; case KC_BACKSPACE: if (pos > 0 && len > 0) { memmove(buf+pos-1,buf+pos,len-pos); pos--; len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_CTRL_T: /* ctrl-t */ // bogdanm: this seems to be rather useless and also a bit buggy, // so it's not enabled /* if (pos > 0 && pos < len) { int aux = buf[pos-1]; buf[pos-1] = buf[pos]; buf[pos] = aux; if (pos != len-1) pos++; refreshLine(prompt,buf,len,pos,cols); }*/ break; case KC_LEFT: /* left arrow */ if (pos > 0) { pos--; refreshLine(prompt,buf,len,pos,cols); } break; case KC_RIGHT: /* right arrow */ if (pos != len) { pos++; refreshLine(prompt,buf,len,pos,cols); } break; case KC_UP: case KC_DOWN: /* up and down arrow: history */ if (history_lengths[ id ] > 1) { /* Update the current history entry before to * overwrite it with tne next one. */ free(histories[ id ][history_lengths[ id ]-1-history_index]); histories[ id ][history_lengths[ id ]-1-history_index] = strdup(buf); /* Show the new entry */ history_index += (c == KC_UP) ? 1 : -1; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_lengths[ id ]) { history_index = history_lengths[ id ]-1; break; } strncpy(buf,histories[ id ][history_lengths[ id ]-1-history_index],buflen); buf[buflen] = '\0'; len = pos = strlen(buf); refreshLine(prompt,buf,len,pos,cols); } break; case KC_DEL: /* delete */ if (len > 0 && pos < len) { memmove(buf+pos,buf+pos+1,len-pos-1); len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_HOME: /* Ctrl+a, go to the start of the line */ pos = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_END: /* ctrl+e, go to the end of the line */ pos = len; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_U: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; pos = len = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_K: /* Ctrl+k, delete from current to end of line. */ buf[pos] = '\0'; len = pos; refreshLine(prompt,buf,len,pos,cols); break; default: if( isprint( c ) && 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. */ term_putch( c ); } else { refreshLine(prompt,buf,len,pos,cols); } } else { memmove(buf+pos+1,buf+pos,len-pos); buf[pos] = c; len++; pos++; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } } break; } } return len; }
void main_loop() { char *cs; int index; int n_match; int scroll = 0; #ifdef USE_XSELECTION cs = check_sel(); #endif if(cs) edit_set_text(cs); n_match = myd_bsearch(myd, edit.text, &index); display(myd, index, n_match, scroll); print_prompt(edit.text, edit.cursor); while(1) { int c; c = term_getch(); if(isprint(c)) { edit_ins_char(c); n_match = myd_bsearch(myd, edit.text, &index); scroll = 0; } else { switch(c) { /* * move cursor */ case 1: /* ^A */ edit_cur_head(); move_cursor(edit.cursor); continue; case 2: /* ^B */ case KEY_LEFT: edit_cur_back(); move_cursor(edit.cursor); continue; case 5: /* ^E */ edit_cur_tail(); move_cursor(edit.cursor); continue; case 6: /* ^F */ case KEY_RIGHT: edit_cur_forward(); move_cursor(edit.cursor); continue; /* * scroll */ case 16: /* ^P */ case KEY_PPAGE: case KEY_UP: if(scroll == 0) continue; scroll -= SCROLL_STEP; if(scroll < 0) scroll = 0; break; case 14: /* ^N */ case KEY_NPAGE: case KEY_DOWN: if(scroll == n_match - 1) continue; scroll += SCROLL_STEP; if(scroll >= n_match) scroll = n_match - 1; break; /* * delete text */ case 8: /* ^H */ edit_back_space(); n_match = myd_bsearch(myd, edit.text, &index); scroll = 0; break; case 4: /* ^D */ case 0x7f: edit_del_char(); n_match = myd_bsearch(myd, edit.text, &index); scroll = 0; break; case 21: /* ^U */ case 10: /* ^J */ case 13: /* ^M */ edit_clear(); n_match = myd_bsearch(myd, edit.text, &index); scroll = 0; break; case 11: /* ^K */ edit_kill(); n_match = myd_bsearch(myd, edit.text, &index); scroll = 0; break; case 20: /* ^T */ edit_transpose(); n_match = myd_bsearch(myd, edit.text, &index); scroll = 0; break; case 12: /* ^L */ break; /* Exit */ case 24: /* ^X */ return; case ERR: /* timeout */ #ifdef USE_XSELECTION cs = check_sel(); #endif if(cs) { edit_set_text(cs); n_match = myd_bsearch(myd, edit.text, &index); scroll = 0; break; } else continue; default: break; } } display(myd, index, n_match, scroll); print_prompt(edit.text, edit.cursor); } }
//-------------------------------------------------------------------- int linenoisePrompt(int id, char *buf, int buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; size_t len = 0; size_t cols = term_num_cols; int history_index = 0; int c; int ins = 1; 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. linenoise_internal_addhistory( id, "", LINENOISE_PUSH_EMPTY ); term_putstr( prompt, plen ); term_curs(0); while(1) { c = term_getch(TERM_INPUT_WAIT); if (c < 0) continue; switch(c) { case KC_ENTER: history_lengths[ id ] --; free( histories[ id ][history_lengths[ id ]] ); return len; break; case KC_CTRL_D: if (len == 0) return LINENOISE_CTRL_D; break; case KC_CTRL_C: len = 0; pos = 0; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); break; case KC_BACKSPACE: if (pos > 0 && len > 0) { memmove(buf+pos-1,buf+pos,len-pos); pos--; len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_INS: ins ^= 1; if (ins) term_curs(0); else term_curs(4); break; case KC_CTRL_T: // bogdanm: this seems to be rather useless and also a bit buggy, // so it's not enabled /* if (pos > 0 && pos < len) { int aux = buf[pos-1]; buf[pos-1] = buf[pos]; buf[pos] = aux; if (pos != len-1) pos++; refreshLine(prompt,buf,len,pos,cols); } */ break; case KC_LEFT: // left arrow if (pos > 0) { pos--; refreshLine(prompt,buf,len,pos,cols); } break; case KC_RIGHT: // right arrow if (pos != len) { pos++; refreshLine(prompt,buf,len,pos,cols); } break; case KC_UP: case KC_DOWN: // up and down arrow: history if (history_lengths[ id ] > 1) { // Update the current history entry before to overwrite it with tne next one. free(histories[ id ][history_lengths[ id ]-1-history_index]); histories[ id ][history_lengths[ id ]-1-history_index] = strdup(buf); // Show the new entry history_index += (c == KC_UP) ? 1 : -1; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_lengths[ id ]) { history_index = history_lengths[ id ]-1; break; } strncpy(buf, histories[ id ][history_lengths[ id ]-1-history_index], buflen); buf[buflen] = '\0'; if ((strlen(buf) > 7) && (strstr(buf, "return ")) == buf) { memmove(buf+1, buf+7, strlen(buf)-6); buf[0] = '='; } len = pos = strlen(buf); refreshLine(prompt,buf,len,pos,cols); } break; case KC_DEL: // delete if (len > 0 && pos < len) { memmove(buf+pos,buf+pos+1,len-pos-1); len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_HOME: // Ctrl+a, go to the start of the line pos = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_END: // ctrl+e, go to the end of the line pos = len; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_U: // Ctrl+u, delete the whole line. buf[0] = '\0'; pos = len = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_K: // Ctrl+k, delete from current to end of line. buf[pos] = '\0'; len = pos; refreshLine(prompt,buf,len,pos,cols); break; default: if( isprint( c ) && 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. term_putch( c ); } else { refreshLine(prompt,buf,len,pos,cols); } } else { if (ins) { memmove(buf+pos+1,buf+pos,len-pos); buf[pos] = c; len++; pos++; buf[len] = '\0'; } else { buf[pos] = c; pos++; } refreshLine(prompt,buf,len,pos,cols); } } break; } } return len; }