Changeset 6a44ee4 in mainline for uspace/lib/clui/tinput.c


Ignore:
Timestamp:
2011-07-20T15:26:21Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
efcebe1
Parents:
25bef0ff (diff), a701812 (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/lib/clui/tinput.c

    r25bef0ff r6a44ee4  
    11/*
    2  * Copyright (c) 2010 Jiri Svoboda
     2 * Copyright (c) 2011 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
     29#include <sort.h>
    2930#include <stdio.h>
    3031#include <stdlib.h>
     
    4243#include <tinput.h>
    4344
     45#define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols))
     46#define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols))
     47
    4448/** Seek direction */
    4549typedef enum {
     
    5458static void tinput_sel_all(tinput_t *);
    5559static void tinput_sel_delete(tinput_t *);
    56 static void tinput_key_ctrl(tinput_t *, console_event_t *);
    57 static void tinput_key_shift(tinput_t *, console_event_t *);
    58 static void tinput_key_ctrl_shift(tinput_t *, console_event_t *);
    59 static void tinput_key_unmod(tinput_t *, console_event_t *);
     60static void tinput_key_ctrl(tinput_t *, kbd_event_t *);
     61static void tinput_key_shift(tinput_t *, kbd_event_t *);
     62static void tinput_key_ctrl_shift(tinput_t *, kbd_event_t *);
     63static void tinput_key_unmod(tinput_t *, kbd_event_t *);
    6064static void tinput_pre_seek(tinput_t *, bool);
    6165static void tinput_post_seek(tinput_t *, bool);
    6266
     67static 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
    6373/** Create a new text input field. */
    6474tinput_t *tinput_new(void)
     
    6676        tinput_t *ti;
    6777       
    68         ti = malloc(sizeof(tinput_t));
     78        ti = calloc(1, sizeof(tinput_t));
    6979        if (ti == NULL)
    7080                return NULL;
     
    7787void tinput_destroy(tinput_t *ti)
    7888{
     89        if (ti->prompt != NULL)
     90                free(ti->prompt);
    7991        free(ti);
     92}
     93
     94static 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);
    80102}
    81103
     
    88110        tinput_sel_get_bounds(ti, &sa, &sb);
    89111       
    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);
     112        tinput_console_set_lpos(ti, ti->text_coord + start);
     113        console_set_style(ti->console, STYLE_NORMAL);
    93114       
    94115        size_t p = start;
     
    101122       
    102123        if (p < sb) {
    103                 fflush(stdout);
    104                 console_set_style(fphone(stdout), STYLE_SELECTED);
     124                console_flush(ti->console);
     125                console_set_style(ti->console, STYLE_SELECTED);
     126               
    105127                memcpy(dbuf, ti->buffer + p,
    106128                    (sb - p) * sizeof(wchar_t));
     
    110132        }
    111133       
    112         fflush(stdout);
    113         console_set_style(fphone(stdout), STYLE_NORMAL);
     134        console_flush(ti->console);
     135        console_set_style(ti->console, STYLE_NORMAL);
    114136       
    115137        if (p < ti->nc) {
     
    123145                putchar(' ');
    124146       
    125         fflush(stdout);
     147        console_flush(ti->console);
    126148}
    127149
     
    133155static void tinput_position_caret(tinput_t *ti)
    134156{
    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. */
     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. */
    140161static void tinput_update_origin(tinput_t *ti)
    141162{
    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;
     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
     176static 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
     183static 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;
    148198}
    149199
     
    153203                return;
    154204       
    155         sysarg_t new_width = ti->col0 + ti->nc + 1;
     205        unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
    156206        if (new_width % ti->con_cols == 0) {
    157207                /* Advancing to new line. */
     
    184234                return;
    185235       
    186         sysarg_t new_width = ti->col0 + ti->nc + ilen;
    187         sysarg_t new_height = (new_width / ti->con_cols) + 1;
     236        unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + ilen;
     237        unsigned new_height = (new_width / ti->con_cols) + 1;
    188238        if (new_height >= ti->con_rows) {
    189239                /* Disallow text longer than 1 page for now. */
     
    510560}
    511561
     562/** Compare two entries in array of completions. */
     563static 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
     571static 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
     593static 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
    512699/** Initialize text input field.
    513700 *
     
    516703static void tinput_init(tinput_t *ti)
    517704{
     705        ti->console = console_init(stdin, stdout);
    518706        ti->hnum = 0;
    519707        ti->hpos = 0;
    520708        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 */
     718int 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 */
     735void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)
     736{
     737        ti->compl_ops = compl_ops;
    521738}
    522739
     
    533750int tinput_read(tinput_t *ti, char **dstr)
    534751{
    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)
     752        console_flush(ti->console);
     753        if (console_get_size(ti->console, &ti->con_cols, &ti->con_rows) != EOK)
    540754                return EIO;
    541755       
     
    547761        ti->exit_clui = false;
    548762       
     763        if (tinput_display(ti) != EOK)
     764                return EIO;
     765       
    549766        while (!ti->done) {
    550                 fflush(stdout);
    551                
    552                 console_event_t ev;
    553                 if (!console_get_event(fphone(stdin), &ev))
     767                console_flush(ti->console);
     768               
     769                kbd_event_t ev;
     770                if (!console_get_kbd_event(ti->console, &ev))
    554771                        return EIO;
    555772               
     
    596813}
    597814
    598 static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev)
     815static void tinput_key_ctrl(tinput_t *ti, kbd_event_t *ev)
    599816{
    600817        switch (ev->key) {
     
    635852}
    636853
    637 static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev)
     854static void tinput_key_ctrl_shift(tinput_t *ti, kbd_event_t *ev)
    638855{
    639856        switch (ev->key) {
     
    655872}
    656873
    657 static void tinput_key_shift(tinput_t *ti, console_event_t *ev)
     874static void tinput_key_shift(tinput_t *ti, kbd_event_t *ev)
    658875{
    659876        switch (ev->key) {
     
    681898}
    682899
    683 static void tinput_key_unmod(tinput_t *ti, console_event_t *ev)
     900static void tinput_key_unmod(tinput_t *ti, kbd_event_t *ev)
    684901{
    685902        switch (ev->key) {
     
    712929                tinput_history_seek(ti, -1);
    713930                break;
     931        case KC_TAB:
     932                tinput_text_complete(ti);
     933                break;
    714934        default:
    715935                break;
Note: See TracChangeset for help on using the changeset viewer.