Changeset fbcfc4da in mainline for uspace/app/bdsh/input.c


Ignore:
Timestamp:
2009-12-03T19:25:17Z (14 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9510be2
Parents:
cb3d641a (diff), 22e6802 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

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

    rcb3d641a rfbcfc4da  
    3838#include <vfs/vfs.h>
    3939#include <errno.h>
     40#include <assert.h>
    4041#include <bool.h>
    4142
     
    4748#include "exec.h"
    4849
    49 static void read_line(char *, int);
     50#define HISTORY_LEN 10
     51
     52typedef 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
     64typedef enum {
     65        seek_backward = -1,
     66        seek_forward = 1
     67} seek_dir_t;
     68
     69static tinput_t tinput;
     70
     71static char *tinput_read(tinput_t *ti);
    5072
    5173/* Tokenizes input from console, sees if the first word is a built-in, if so
     
    99121}
    100122
    101 static void read_line(char *buffer, int n)
     123static 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
     135static char *tinput_get_str(tinput_t *ti)
     136{
     137        return wstr_to_astr(ti->buffer);
     138}
     139
     140static 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. */
     147static 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
     159static 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
     188static 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
     205static 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
     214static 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
     227static 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
     263static 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
     276static 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
     286static 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
     308static 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
     315static 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
     339static void tinput_init(tinput_t *ti)
     340{
     341        ti->hnum = 0;
     342        ti->hpos = 0;
     343        ti->history[0] = NULL;
     344}
     345
     346static char *tinput_read(tinput_t *ti)
    102347{
    103348        console_event_t ev;
    104         size_t offs, otmp;
    105         wchar_t dec;
    106 
    107         offs = 0;
     349        char *str;
     350
     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
    108362        while (true) {
    109363                fflush(stdout);
    110364                if (!console_get_event(fphone(stdin), &ev))
    111                         return;
     365                        return NULL;
    112366               
    113367                if (ev.type != KEY_PRESS)
    114368                        continue;
    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');
     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;
    131385                        }
    132                         continue;
    133386                }
     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
    134420                if (ev.c >= ' ') {
    135                         if (chr_encode(ev.c, buffer, &offs, n - 1) == EOK)
    136                                 putchar(ev.c);
     421                        tinput_insert_char(ti, ev.c);
    137422                }
    138423        }
     424
     425done:
     426        ti->pos = ti->nc;
     427        tinput_position_caret(ti);
    139428        putchar('\n');
    140         buffer[offs] = '\0';
    141 }
    142 
    143 /* TODO:
    144  * Implement something like editline() / readline(), if even
    145  * just for command history and making arrows work. */
     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;
     437}
     438
    146439void get_input(cliuser_t *usr)
    147440{
    148         char line[INPUT_MAX];
     441        char *str;
    149442
    150443        fflush(stdout);
     
    154447        console_set_style(fphone(stdout), STYLE_NORMAL);
    155448
    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)
     449        str = tinput_read(&tinput);
     450
     451        /* Check for empty input. */
     452        if (str_cmp(str, "") == 0) {
     453                free(str);
    159454                return;
    160         usr->line = str_dup(line);
    161 
     455        }
     456
     457        usr->line = str;
    162458        return;
    163459}
    164460
     461void input_init(void)
     462{
     463        tinput_init(&tinput);
     464}
Note: See TracChangeset for help on using the changeset viewer.