Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/clui/tinput.c

    r9be9c4d r96b02eb9  
    11/*
    2  * Copyright (c) 2011 Jiri Svoboda
     2 * Copyright (c) 2010 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
    29 #include <sort.h>
    3029#include <stdio.h>
    3130#include <stdlib.h>
     
    4342#include <tinput.h>
    4443
    45 #define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols))
    46 #define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols))
    47 
    4844/** Seek direction */
    4945typedef enum {
     
    5854static void tinput_sel_all(tinput_t *);
    5955static void tinput_sel_delete(tinput_t *);
    60 static void tinput_key_ctrl(tinput_t *, kbd_event_t *);
    61 static void tinput_key_shift(tinput_t *, kbd_event_t *);
    62 static void tinput_key_ctrl_shift(tinput_t *, kbd_event_t *);
    63 static void tinput_key_unmod(tinput_t *, kbd_event_t *);
     56static void tinput_key_ctrl(tinput_t *, console_event_t *);
     57static void tinput_key_shift(tinput_t *, console_event_t *);
     58static void tinput_key_ctrl_shift(tinput_t *, console_event_t *);
     59static void tinput_key_unmod(tinput_t *, console_event_t *);
    6460static void tinput_pre_seek(tinput_t *, bool);
    6561static void tinput_post_seek(tinput_t *, bool);
    6662
    67 static void tinput_console_set_lpos(tinput_t *ti, unsigned lpos)
    68 {
    69         console_set_pos(ti->console, LIN_TO_COL(ti, lpos),
    70             LIN_TO_ROW(ti, lpos));
    71 }
    72 
    7363/** Create a new text input field. */
    7464tinput_t *tinput_new(void)
     
    7666        tinput_t *ti;
    7767       
    78         ti = calloc(1, sizeof(tinput_t));
     68        ti = malloc(sizeof(tinput_t));
    7969        if (ti == NULL)
    8070                return NULL;
     
    8777void tinput_destroy(tinput_t *ti)
    8878{
    89         if (ti->prompt != NULL)
    90                 free(ti->prompt);
    9179        free(ti);
    92 }
    93 
    94 static void tinput_display_prompt(tinput_t *ti)
    95 {
    96         tinput_console_set_lpos(ti, ti->prompt_coord);
    97 
    98         console_set_style(ti->console, STYLE_EMPHASIS);
    99         printf("%s", ti->prompt);
    100         console_flush(ti->console);
    101         console_set_style(ti->console, STYLE_NORMAL);
    10280}
    10381
     
    11088        tinput_sel_get_bounds(ti, &sa, &sb);
    11189       
    112         tinput_console_set_lpos(ti, ti->text_coord + start);
    113         console_set_style(ti->console, STYLE_NORMAL);
     90        console_set_pos(fphone(stdout), (ti->col0 + start) % ti->con_cols,
     91            ti->row0 + (ti->col0 + start) / ti->con_cols);
     92        console_set_style(fphone(stdout), STYLE_NORMAL);
    11493       
    11594        size_t p = start;
     
    122101       
    123102        if (p < sb) {
    124                 console_flush(ti->console);
    125                 console_set_style(ti->console, STYLE_SELECTED);
    126                
     103                fflush(stdout);
     104                console_set_style(fphone(stdout), STYLE_SELECTED);
    127105                memcpy(dbuf, ti->buffer + p,
    128106                    (sb - p) * sizeof(wchar_t));
     
    132110        }
    133111       
    134         console_flush(ti->console);
    135         console_set_style(ti->console, STYLE_NORMAL);
     112        fflush(stdout);
     113        console_set_style(fphone(stdout), STYLE_NORMAL);
    136114       
    137115        if (p < ti->nc) {
     
    145123                putchar(' ');
    146124       
    147         console_flush(ti->console);
     125        fflush(stdout);
    148126}
    149127
     
    155133static void tinput_position_caret(tinput_t *ti)
    156134{
    157         tinput_console_set_lpos(ti, ti->text_coord + ti->pos);
    158 }
    159 
    160 /** Update text_coord, prompt_coord in case the screen could have scrolled. */
     135        console_set_pos(fphone(stdout), (ti->col0 + ti->pos) % ti->con_cols,
     136            ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
     137}
     138
     139/** Update row0 in case the screen could have scrolled. */
    161140static void tinput_update_origin(tinput_t *ti)
    162141{
    163         unsigned end_coord = ti->text_coord + ti->nc;
    164         unsigned end_row = LIN_TO_ROW(ti, end_coord);
    165 
    166         unsigned scroll_rows;
    167 
    168         /* Update coords if the screen scrolled. */
    169         if (end_row >= ti->con_rows) {
    170                 scroll_rows = end_row - ti->con_rows + 1;
    171                 ti->text_coord -= ti->con_cols * scroll_rows;
    172                 ti->prompt_coord -= ti->con_cols * scroll_rows;
    173         }
    174 }
    175 
    176 static void tinput_jump_after(tinput_t *ti)
    177 {
    178         tinput_console_set_lpos(ti, ti->text_coord + ti->nc);
    179         console_flush(ti->console);
    180         putchar('\n');
    181 }
    182 
    183 static int tinput_display(tinput_t *ti)
    184 {
    185         sysarg_t col0, row0;
    186        
    187         if (console_get_pos(ti->console, &col0, &row0) != EOK)
    188                 return EIO;
    189        
    190         ti->prompt_coord = row0 * ti->con_cols + col0;
    191         ti->text_coord = ti->prompt_coord + str_length(ti->prompt);
    192 
    193         tinput_display_prompt(ti);
    194         tinput_display_tail(ti, 0, 0);
    195         tinput_position_caret(ti);
    196 
    197         return EOK;
     142        sysarg_t width = ti->col0 + ti->nc;
     143        sysarg_t rows = (width / ti->con_cols) + 1;
     144       
     145        /* Update row0 if the screen scrolled. */
     146        if (ti->row0 + rows > ti->con_rows)
     147                ti->row0 = ti->con_rows - rows;
    198148}
    199149
     
    203153                return;
    204154       
    205         unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
     155        sysarg_t new_width = ti->col0 + ti->nc + 1;
    206156        if (new_width % ti->con_cols == 0) {
    207157                /* Advancing to new line. */
     
    234184                return;
    235185       
    236         unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + ilen;
    237         unsigned new_height = (new_width / ti->con_cols) + 1;
     186        sysarg_t new_width = ti->col0 + ti->nc + ilen;
     187        sysarg_t new_height = (new_width / ti->con_cols) + 1;
    238188        if (new_height >= ti->con_rows) {
    239189                /* Disallow text longer than 1 page for now. */
     
    560510}
    561511
    562 /** Compare two entries in array of completions. */
    563 static int compl_cmp(void *va, void *vb, void *arg)
    564 {
    565         const char *a = *(const char **) va;
    566         const char *b = *(const char **) vb;
    567 
    568         return str_cmp(a, b);
    569 }
    570 
    571 static size_t common_pref_len(const char *a, const char *b)
    572 {
    573         size_t i;
    574         size_t a_off, b_off;
    575         wchar_t ca, cb;
    576 
    577         i = 0;
    578         a_off = 0;
    579         b_off = 0;
    580 
    581         while (true) {
    582                 ca = str_decode(a, &a_off, STR_NO_LIMIT);
    583                 cb = str_decode(b, &b_off, STR_NO_LIMIT);
    584 
    585                 if (ca == '\0' || cb == '\0' || ca != cb)
    586                         break;
    587                 ++i;
    588         }
    589 
    590         return i;
    591 }
    592 
    593 static void tinput_text_complete(tinput_t *ti)
    594 {
    595         void *state;
    596         size_t cstart;
    597         char *ctmp;
    598         char **compl;           /* Array of completions */
    599         size_t compl_len;       /* Current length of @c compl array */
    600         size_t cnum;
    601         size_t i;
    602         int rc;
    603 
    604         if (ti->compl_ops == NULL)
    605                 return;
    606 
    607         /*
    608          * Obtain list of all possible completions (growing array).
    609          */
    610 
    611         rc = (*ti->compl_ops->init)(ti->buffer, ti->pos, &cstart, &state);
    612         if (rc != EOK)
    613                 return;
    614 
    615         cnum = 0;
    616 
    617         compl_len = 1;
    618         compl = malloc(compl_len * sizeof(char *));
    619         if (compl == NULL) {
    620                 printf("Error: Out of memory.\n");
    621                 return;
    622         }
    623 
    624         while (true) {
    625                 rc = (*ti->compl_ops->get_next)(state, &ctmp);
    626                 if (rc != EOK)
    627                         break;
    628 
    629                 if (cnum >= compl_len) {
    630                         /* Extend array */
    631                         compl_len = 2 * compl_len;
    632                         compl = realloc(compl, compl_len * sizeof(char *));
    633                         if (compl == NULL) {
    634                                 printf("Error: Out of memory.\n");
    635                                 break;
    636                         }
    637                 }
    638 
    639                 compl[cnum] = str_dup(ctmp);
    640                 if (compl[cnum] == NULL) {
    641                         printf("Error: Out of memory.\n");
    642                         break;
    643                 }
    644                 cnum++;
    645         }
    646 
    647         (*ti->compl_ops->fini)(state);
    648 
    649         if (cnum > 1) {
    650                 /*
    651                  * More than one match. Determine maximum common prefix.
    652                  */
    653                 size_t cplen;
    654 
    655                 cplen = str_length(compl[0]);
    656                 for (i = 1; i < cnum; i++)
    657                         cplen = min(cplen, common_pref_len(compl[0], compl[i]));
    658 
    659                 /* Compute how many bytes we should skip. */
    660                 size_t istart = str_lsize(compl[0], ti->pos - cstart);
    661 
    662                 if (cplen > istart) {
    663                         /* Insert common prefix. */
    664 
    665                         /* Copy remainder of common prefix. */
    666                         char *cpref = str_ndup(compl[0] + istart,
    667                             str_lsize(compl[0], cplen - istart));
    668 
    669                         /* Insert it. */
    670                         tinput_insert_string(ti, cpref);
    671                         free(cpref);
    672                 } else {
    673                         /* No common prefix. Sort and display all entries. */
    674 
    675                         qsort(compl, cnum, sizeof(char *), compl_cmp, NULL);
    676 
    677                         tinput_jump_after(ti);
    678                         for (i = 0; i < cnum; i++)
    679                                 printf("%s\n", compl[i]);
    680                         tinput_display(ti);
    681                 }
    682         } else if (cnum == 1) {
    683                 /*
    684                  * We have exactly one match. Insert it.
    685                  */
    686 
    687                 /* Compute how many bytes of completion string we should skip. */
    688                 size_t istart = str_lsize(compl[0], ti->pos - cstart);
    689 
    690                 /* Insert remainder of completion string at current position. */
    691                 tinput_insert_string(ti, compl[0] + istart);
    692         }
    693 
    694         for (i = 0; i < cnum; i++)
    695                 free(compl[i]);
    696         free(compl);
    697 }
    698 
    699512/** Initialize text input field.
    700513 *
     
    703516static void tinput_init(tinput_t *ti)
    704517{
    705         ti->console = console_init(stdin, stdout);
    706518        ti->hnum = 0;
    707519        ti->hpos = 0;
    708520        ti->history[0] = NULL;
    709 }
    710 
    711 /** Set prompt string.
    712  *
    713  * @param ti            Text input
    714  * @param prompt        Prompt string
    715  *
    716  * @return              EOK on success, ENOMEM if out of memory.
    717  */
    718 int tinput_set_prompt(tinput_t *ti, const char *prompt)
    719 {
    720         if (ti->prompt != NULL)
    721                 free(ti->prompt);
    722        
    723         ti->prompt = str_dup(prompt);
    724         if (ti->prompt == NULL)
    725                 return ENOMEM;
    726        
    727         return EOK;
    728 }
    729 
    730 /** Set completion ops.
    731  *
    732  * Set pointer to completion ops structure that will be used for text
    733  * completion.
    734  */
    735 void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)
    736 {
    737         ti->compl_ops = compl_ops;
    738521}
    739522
     
    750533int tinput_read(tinput_t *ti, char **dstr)
    751534{
    752         console_flush(ti->console);
    753         if (console_get_size(ti->console, &ti->con_cols, &ti->con_rows) != EOK)
     535        fflush(stdout);
     536        if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK)
     537                return EIO;
     538       
     539        if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK)
    754540                return EIO;
    755541       
     
    761547        ti->exit_clui = false;
    762548       
    763         if (tinput_display(ti) != EOK)
    764                 return EIO;
    765        
    766549        while (!ti->done) {
    767                 console_flush(ti->console);
    768                
    769                 kbd_event_t ev;
    770                 if (!console_get_kbd_event(ti->console, &ev))
     550                fflush(stdout);
     551               
     552                console_event_t ev;
     553                if (!console_get_event(fphone(stdin), &ev))
    771554                        return EIO;
    772555               
     
    813596}
    814597
    815 static void tinput_key_ctrl(tinput_t *ti, kbd_event_t *ev)
     598static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev)
    816599{
    817600        switch (ev->key) {
     
    852635}
    853636
    854 static void tinput_key_ctrl_shift(tinput_t *ti, kbd_event_t *ev)
     637static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev)
    855638{
    856639        switch (ev->key) {
     
    872655}
    873656
    874 static void tinput_key_shift(tinput_t *ti, kbd_event_t *ev)
     657static void tinput_key_shift(tinput_t *ti, console_event_t *ev)
    875658{
    876659        switch (ev->key) {
     
    898681}
    899682
    900 static void tinput_key_unmod(tinput_t *ti, kbd_event_t *ev)
     683static void tinput_key_unmod(tinput_t *ti, console_event_t *ev)
    901684{
    902685        switch (ev->key) {
     
    929712                tinput_history_seek(ti, -1);
    930713                break;
    931         case KC_TAB:
    932                 tinput_text_complete(ti);
    933                 break;
    934714        default:
    935715                break;
Note: See TracChangeset for help on using the changeset viewer.