Changeset bd5f3b7 in mainline for uspace/lib/clui/tinput.c


Ignore:
Timestamp:
2011-08-21T13:07:35Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
00aece0, f1a9e87
Parents:
86a34d3e (diff), a6480d5 (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

    r86a34d3e rbd5f3b7  
    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 {
     
    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(ti->console, (ti->col0 + start) % ti->con_cols,
    91             ti->row0 + (ti->col0 + start) / ti->con_cols);
     112        tinput_console_set_lpos(ti, ti->text_coord + start);
    92113        console_set_style(ti->console, STYLE_NORMAL);
    93114       
     
    134155static void tinput_position_caret(tinput_t *ti)
    135156{
    136         console_set_pos(ti->console, (ti->col0 + ti->pos) % ti->con_cols,
    137             ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
    138 }
    139 
    140 /** 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. */
    141161static void tinput_update_origin(tinput_t *ti)
    142162{
    143         sysarg_t width = ti->col0 + ti->nc;
    144         sysarg_t rows = (width / ti->con_cols) + 1;
    145        
    146         /* Update row0 if the screen scrolled. */
    147         if (ti->row0 + rows > ti->con_rows)
    148                 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;
    149198}
    150199
     
    154203                return;
    155204       
    156         sysarg_t new_width = ti->col0 + ti->nc + 1;
     205        unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
    157206        if (new_width % ti->con_cols == 0) {
    158207                /* Advancing to new line. */
     
    185234                return;
    186235       
    187         sysarg_t new_width = ti->col0 + ti->nc + ilen;
    188         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;
    189238        if (new_height >= ti->con_rows) {
    190239                /* Disallow text longer than 1 page for now. */
     
    511560}
    512561
     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
     593/* Print a list of completions */
     594static void tinput_show_completions(tinput_t *ti, char **compl, size_t cnum)
     595{
     596        unsigned int i;
     597        /* Determine the maximum length of the completion in chars */
     598        size_t max_length = 0;
     599        for (i = 0; i < cnum; i++)
     600                max_length = max(max_length, str_length(compl[i]));
     601       
     602        unsigned int cols = max(1, (ti->con_cols + 1) / (max_length + 1));
     603        unsigned int col_width = ti->con_cols / cols;
     604        unsigned int rows = cnum / cols + ((cnum % cols) != 0);
     605       
     606        unsigned int row, col;
     607       
     608        for (row = 0; row < rows; row++) {
     609                bool wlc = false;
     610                for (col = 0; col < cols; col++) {
     611                        size_t compl_idx = col * rows + row;
     612                        if (compl_idx >= cnum)
     613                                break;
     614                        if (col)
     615                                printf(" ");
     616                        printf("%s", compl[compl_idx]);
     617                        size_t compl_len = str_length(compl[compl_idx]);
     618                        if (col == cols -1) {
     619                                wlc = (compl_len == max_length);
     620                        }
     621                        else {
     622                                for (i = compl_len; i < col_width; i++) {
     623                                        printf(" ");
     624                                }
     625                        }
     626                }
     627                if (!wlc) printf("\n");
     628        }
     629}
     630
     631
     632static void tinput_text_complete(tinput_t *ti)
     633{
     634        void *state;
     635        size_t cstart;
     636        char *ctmp;
     637        char **compl;           /* Array of completions */
     638        size_t compl_len;       /* Current length of @c compl array */
     639        size_t cnum;
     640        size_t i;
     641        int rc;
     642
     643        if (ti->compl_ops == NULL)
     644                return;
     645
     646        /*
     647         * Obtain list of all possible completions (growing array).
     648         */
     649
     650        rc = (*ti->compl_ops->init)(ti->buffer, ti->pos, &cstart, &state);
     651        if (rc != EOK)
     652                return;
     653
     654        cnum = 0;
     655
     656        compl_len = 1;
     657        compl = malloc(compl_len * sizeof(char *));
     658        if (compl == NULL) {
     659                printf("Error: Out of memory.\n");
     660                return;
     661        }
     662
     663        while (true) {
     664                rc = (*ti->compl_ops->get_next)(state, &ctmp);
     665                if (rc != EOK)
     666                        break;
     667
     668                if (cnum >= compl_len) {
     669                        /* Extend array */
     670                        compl_len = 2 * compl_len;
     671                        compl = realloc(compl, compl_len * sizeof(char *));
     672                        if (compl == NULL) {
     673                                printf("Error: Out of memory.\n");
     674                                break;
     675                        }
     676                }
     677
     678                compl[cnum] = str_dup(ctmp);
     679                if (compl[cnum] == NULL) {
     680                        printf("Error: Out of memory.\n");
     681                        break;
     682                }
     683                cnum++;
     684        }
     685
     686        (*ti->compl_ops->fini)(state);
     687
     688        if (cnum > 1) {
     689                /*
     690                 * More than one match. Determine maximum common prefix.
     691                 */
     692                size_t cplen;
     693
     694                cplen = str_length(compl[0]);
     695                for (i = 1; i < cnum; i++)
     696                        cplen = min(cplen, common_pref_len(compl[0], compl[i]));
     697
     698                /* Compute how many bytes we should skip. */
     699                size_t istart = str_lsize(compl[0], ti->pos - cstart);
     700
     701                if (cplen > istart) {
     702                        /* Insert common prefix. */
     703
     704                        /* Copy remainder of common prefix. */
     705                        char *cpref = str_ndup(compl[0] + istart,
     706                            str_lsize(compl[0], cplen - istart));
     707
     708                        /* Insert it. */
     709                        tinput_insert_string(ti, cpref);
     710                        free(cpref);
     711                } else {
     712                        /* No common prefix. Sort and display all entries. */
     713
     714                        qsort(compl, cnum, sizeof(char *), compl_cmp, NULL);
     715
     716                        tinput_jump_after(ti);
     717                        tinput_show_completions(ti, compl, cnum);
     718                        tinput_display(ti);
     719                }
     720        } else if (cnum == 1) {
     721                /*
     722                 * We have exactly one match. Insert it.
     723                 */
     724
     725                /* Compute how many bytes of completion string we should skip. */
     726                size_t istart = str_lsize(compl[0], ti->pos - cstart);
     727
     728                /* Insert remainder of completion string at current position. */
     729                tinput_insert_string(ti, compl[0] + istart);
     730        }
     731
     732        for (i = 0; i < cnum; i++)
     733                free(compl[i]);
     734        free(compl);
     735}
     736
    513737/** Initialize text input field.
    514738 *
     
    521745        ti->hpos = 0;
    522746        ti->history[0] = NULL;
     747}
     748
     749/** Set prompt string.
     750 *
     751 * @param ti            Text input
     752 * @param prompt        Prompt string
     753 *
     754 * @return              EOK on success, ENOMEM if out of memory.
     755 */
     756int tinput_set_prompt(tinput_t *ti, const char *prompt)
     757{
     758        if (ti->prompt != NULL)
     759                free(ti->prompt);
     760       
     761        ti->prompt = str_dup(prompt);
     762        if (ti->prompt == NULL)
     763                return ENOMEM;
     764       
     765        return EOK;
     766}
     767
     768/** Set completion ops.
     769 *
     770 * Set pointer to completion ops structure that will be used for text
     771 * completion.
     772 */
     773void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)
     774{
     775        ti->compl_ops = compl_ops;
    523776}
    524777
     
    539792                return EIO;
    540793       
    541         if (console_get_pos(ti->console, &ti->col0, &ti->row0) != EOK)
    542                 return EIO;
    543        
    544794        ti->pos = 0;
    545795        ti->sel_start = 0;
     
    549799        ti->exit_clui = false;
    550800       
     801        if (tinput_display(ti) != EOK)
     802                return EIO;
     803       
    551804        while (!ti->done) {
    552805                console_flush(ti->console);
     
    714967                tinput_history_seek(ti, -1);
    715968                break;
     969        case KC_TAB:
     970                tinput_text_complete(ti);
     971                break;
    716972        default:
    717973                break;
Note: See TracChangeset for help on using the changeset viewer.