Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bdsh/input.c

    r3041fef1 ref8bcc6  
    3838#include <vfs/vfs.h>
    3939#include <errno.h>
    40 #include <assert.h>
    4140#include <bool.h>
    4241
     
    4847#include "exec.h"
    4948
    50 #define HISTORY_LEN 10
    51 
    52 typedef struct {
    53         wchar_t buffer[INPUT_MAX];
    54         int col0, row0;
    55         int con_cols, con_rows;
    56         int nc;
    57         int pos;
    58 
    59         char *history[1 + HISTORY_LEN];
    60         int hnum;
    61         int hpos;
    62 } tinput_t;
    63 
    64 typedef enum {
    65         seek_backward = -1,
    66         seek_forward = 1
    67 } seek_dir_t;
    68 
    69 static tinput_t tinput;
    70 
    71 static char *tinput_read(tinput_t *ti);
     49static void read_line(char *, int);
    7250
    7351/* Tokenizes input from console, sees if the first word is a built-in, if so
     
    12199}
    122100
    123 static void tinput_display_tail(tinput_t *ti, int start, int pad)
    124 {
    125         int i;
    126 
    127         console_goto(fphone(stdout), (ti->col0 + start) % ti->con_cols,
    128             ti->row0 + (ti->col0 + start) / ti->con_cols);
    129         printf("%ls", ti->buffer + start);
    130         for (i = 0; i < pad; ++i)
    131                 putchar(' ');
    132         fflush(stdout);
    133 }
    134 
    135 static char *tinput_get_str(tinput_t *ti)
    136 {
    137         return wstr_to_astr(ti->buffer);
    138 }
    139 
    140 static void tinput_position_caret(tinput_t *ti)
    141 {
    142         console_goto(fphone(stdout), (ti->col0 + ti->pos) % ti->con_cols,
    143             ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
    144 }
    145 
    146 /** Update row0 in case the screen could have scrolled. */
    147 static void tinput_update_origin(tinput_t *ti)
    148 {
    149         int width, rows;
    150 
    151         width = ti->col0 + ti->nc;
    152         rows = (width / ti->con_cols) + 1;
    153  
    154         /* Update row0 if the screen scrolled. */
    155         if (ti->row0 + rows > ti->con_rows)
    156                 ti->row0 = ti->con_rows - rows;
    157 }
    158 
    159 static void tinput_insert_char(tinput_t *ti, wchar_t c)
    160 {
    161         int i;
    162         int new_width, new_height;
    163 
    164         if (ti->nc == INPUT_MAX)
    165                 return;
    166 
    167         new_width = ti->col0 + ti->nc + 1;
    168         if (new_width % ti->con_cols == 0) {
    169                 /* Advancing to new line. */
    170                 new_height = (new_width / ti->con_cols) + 1;
    171                 if (new_height >= ti->con_rows)
    172                         return; /* Disallow text longer than 1 page for now. */
    173         }
    174 
    175         for (i = ti->nc; i > ti->pos; --i)
    176                 ti->buffer[i] = ti->buffer[i - 1];
    177 
    178         ti->buffer[ti->pos] = c;
    179         ti->pos += 1;
    180         ti->nc += 1;
    181         ti->buffer[ti->nc] = '\0';
    182 
    183         tinput_display_tail(ti, ti->pos - 1, 0);
    184         tinput_update_origin(ti);
    185         tinput_position_caret(ti);
    186 }
    187 
    188 static void tinput_backspace(tinput_t *ti)
    189 {
    190         int i;
    191 
    192         if (ti->pos == 0)
    193                 return;
    194 
    195         for (i = ti->pos; i < ti->nc; ++i)
    196                 ti->buffer[i - 1] = ti->buffer[i];
    197         ti->pos -= 1;
    198         ti->nc -= 1;
    199         ti->buffer[ti->nc] = '\0';
    200 
    201         tinput_display_tail(ti, ti->pos, 1);
    202         tinput_position_caret(ti);
    203 }
    204 
    205 static void tinput_delete(tinput_t *ti)
    206 {
    207         if (ti->pos == ti->nc)
    208                 return;
    209 
    210         ti->pos += 1;
    211         tinput_backspace(ti);
    212 }
    213 
    214 static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir)
    215 {
    216         if (dir == seek_forward) {
    217                 if (ti->pos < ti->nc)
    218                         ti->pos += 1;
    219         } else {
    220                 if (ti->pos > 0)
    221                         ti->pos -= 1;
    222         }
    223 
    224         tinput_position_caret(ti);
    225 }
    226 
    227 static void tinput_seek_word(tinput_t *ti, seek_dir_t dir)
    228 {
    229         if (dir == seek_forward) {
    230                 if (ti->pos == ti->nc)
    231                         return;
    232 
    233                 while (1) {
    234                         ti->pos += 1;
    235 
    236                         if (ti->pos == ti->nc)
    237                                 break;
    238 
    239                         if (ti->buffer[ti->pos - 1] == ' ' &&
    240                             ti->buffer[ti->pos] != ' ')
    241                                 break;
    242                 }
    243         } else {
    244                 if (ti->pos == 0)
    245                         return;
    246 
    247                 while (1) {
    248                         ti->pos -= 1;
    249 
    250                         if (ti->pos == 0)
    251                                 break;
    252 
    253                         if (ti->buffer[ti->pos - 1] == ' ' &&
    254                             ti->buffer[ti->pos] != ' ')
    255                                 break;
    256                 }
    257 
    258         }
    259 
    260         tinput_position_caret(ti);
    261 }
    262 
    263 static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir)
    264 {
    265         if (dir == seek_forward) {
    266                 if (ti->pos + ti->con_cols <= ti->nc)
    267                         ti->pos = ti->pos + ti->con_cols;
    268         } else {
    269                 if (ti->pos - ti->con_cols >= 0)
    270                         ti->pos = ti->pos - ti->con_cols;
    271         }
    272 
    273         tinput_position_caret(ti);
    274 }
    275 
    276 static void tinput_seek_max(tinput_t *ti, seek_dir_t dir)
    277 {
    278         if (dir == seek_backward)
    279                 ti->pos = 0;
    280         else
    281                 ti->pos = ti->nc;
    282 
    283         tinput_position_caret(ti);
    284 }
    285 
    286 static void tinput_history_insert(tinput_t *ti, char *str)
    287 {
    288         int i;
    289 
    290         if (ti->hnum < HISTORY_LEN) {
    291                 ti->hnum += 1;
    292         } else {
    293                 if (ti->history[HISTORY_LEN] != NULL)
    294                         free(ti->history[HISTORY_LEN]);
    295         }
    296 
    297         for (i = ti->hnum; i > 1; --i)
    298                 ti->history[i] = ti->history[i - 1];
    299 
    300         ti->history[1] = str_dup(str);
    301 
    302         if (ti->history[0] != NULL) {
    303                 free(ti->history[0]);
    304                 ti->history[0] = NULL;
    305         }
    306 }
    307 
    308 static void tinput_set_str(tinput_t *ti, char *str)
    309 {
    310         str_to_wstr(ti->buffer, INPUT_MAX, str);
    311         ti->nc = wstr_length(ti->buffer);
    312         ti->pos = ti->nc;
    313 }
    314 
    315 static void tinput_history_seek(tinput_t *ti, int offs)
    316 {
    317         int pad;
    318 
    319         if (ti->hpos + offs < 0 || ti->hpos + offs > ti->hnum)
    320                 return;
    321 
    322         if (ti->history[ti->hpos] != NULL) {
    323                 free(ti->history[ti->hpos]);
    324                 ti->history[ti->hpos] = NULL;
    325         }
    326 
    327         ti->history[ti->hpos] = tinput_get_str(ti);
    328         ti->hpos += offs;
    329 
    330         pad = ti->nc - str_length(ti->history[ti->hpos]);
    331         if (pad < 0) pad = 0;
    332 
    333         tinput_set_str(ti, ti->history[ti->hpos]);
    334         tinput_display_tail(ti, 0, pad);
    335         tinput_update_origin(ti);
    336         tinput_position_caret(ti);
    337 }
    338 
    339 static void tinput_init(tinput_t *ti)
    340 {
    341         ti->hnum = 0;
    342         ti->hpos = 0;
    343         ti->history[0] = NULL;
    344 }
    345 
    346 static char *tinput_read(tinput_t *ti)
     101static void read_line(char *buffer, int n)
    347102{
    348103        console_event_t ev;
    349         char *str;
     104        size_t offs, otmp;
     105        wchar_t dec;
    350106
    351         fflush(stdout);
    352 
    353         if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK)
    354                 return NULL;
    355         if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK)
    356                 return NULL;
    357 
    358         ti->pos = 0;
    359         ti->nc = 0;
    360         ti->buffer[0] = '\0';
    361 
     107        offs = 0;
    362108        while (true) {
    363109                fflush(stdout);
    364110                if (!console_get_event(fphone(stdin), &ev))
    365                         return NULL;
     111                        return;
    366112               
    367113                if (ev.type != KEY_PRESS)
    368114                        continue;
    369 
    370                 if ((ev.mods & KM_CTRL) != 0 &&
    371                     (ev.mods & (KM_ALT | KM_SHIFT)) == 0) {
    372                         switch (ev.key) {
    373                         case KC_LEFT:
    374                                 tinput_seek_word(ti, seek_backward);
    375                                 break;
    376                         case KC_RIGHT:
    377                                 tinput_seek_word(ti, seek_forward);
    378                                 break;
    379                         case KC_UP:
    380                                 tinput_seek_vertical(ti, seek_backward);
    381                                 break;
    382                         case KC_DOWN:
    383                                 tinput_seek_vertical(ti, seek_forward);
    384                                 break;
     115               
     116                if (ev.key == KC_ENTER || ev.key == KC_NENTER)
     117                        break;
     118                if (ev.key == KC_BACKSPACE) {
     119                        if (offs > 0) {
     120                                /*
     121                                 * Back up until we reach valid start of
     122                                 * character.
     123                                 */
     124                                while (offs > 0) {
     125                                        --offs; otmp = offs;
     126                                        dec = str_decode(buffer, &otmp, n);
     127                                        if (dec != U_SPECIAL)
     128                                                break;
     129                                }
     130                                putchar('\b');
    385131                        }
     132                        continue;
    386133                }
    387 
    388                 if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
    389                         switch (ev.key) {
    390                         case KC_ENTER:
    391                         case KC_NENTER:
    392                                 goto done;
    393                         case KC_BACKSPACE:
    394                                 tinput_backspace(ti);
    395                                 break;
    396                         case KC_DELETE:
    397                                 tinput_delete(ti);
    398                                 break;
    399                         case KC_LEFT:
    400                                 tinput_seek_cell(ti, seek_backward);
    401                                 break;
    402                         case KC_RIGHT:
    403                                 tinput_seek_cell(ti, seek_forward);
    404                                 break;
    405                         case KC_HOME:
    406                                 tinput_seek_max(ti, seek_backward);
    407                                 break;
    408                         case KC_END:
    409                                 tinput_seek_max(ti, seek_forward);
    410                                 break;
    411                         case KC_UP:
    412                                 tinput_history_seek(ti, +1);
    413                                 break;
    414                         case KC_DOWN:
    415                                 tinput_history_seek(ti, -1);
    416                                 break;
    417                         }
    418                 }
    419 
    420134                if (ev.c >= ' ') {
    421                         tinput_insert_char(ti, ev.c);
     135                        if (chr_encode(ev.c, buffer, &offs, n - 1) == EOK)
     136                                putchar(ev.c);
    422137                }
    423138        }
    424 
    425 done:
    426         ti->pos = ti->nc;
    427         tinput_position_caret(ti);
    428139        putchar('\n');
    429 
    430         str = tinput_get_str(ti);
    431         if (str_cmp(str, "") != 0)
    432                 tinput_history_insert(ti, str);
    433 
    434         ti->hpos = 0;
    435 
    436         return str;
     140        buffer[offs] = '\0';
    437141}
    438142
     143/* TODO:
     144 * Implement something like editline() / readline(), if even
     145 * just for command history and making arrows work. */
    439146void get_input(cliuser_t *usr)
    440147{
    441         char *str;
     148        char line[INPUT_MAX];
    442149
    443150        fflush(stdout);
     
    447154        console_set_style(fphone(stdout), STYLE_NORMAL);
    448155
    449         str = tinput_read(&tinput);
     156        read_line(line, INPUT_MAX);
     157        /* Make sure we don't have rubbish or a C/R happy user */
     158        if (str_cmp(line, "") == 0 || str_cmp(line, "\n") == 0)
     159                return;
     160        usr->line = str_dup(line);
    450161
    451         /* Check for empty input. */
    452         if (str_cmp(str, "") == 0) {
    453                 free(str);
    454                 return;
    455         }
    456 
    457         usr->line = str;
    458162        return;
    459163}
    460164
    461 void input_init(void)
    462 {
    463         tinput_init(&tinput);
    464 }
Note: See TracChangeset for help on using the changeset viewer.