Ignore:
File:
1 edited

Legend:

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

    r9be9c4d r79ae36dd  
    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 {
     
    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);
     90        console_set_pos(ti->console, (ti->col0 + start) % ti->con_cols,
     91            ti->row0 + (ti->col0 + start) / ti->con_cols);
    11392        console_set_style(ti->console, STYLE_NORMAL);
    11493       
     
    155134static void tinput_position_caret(tinput_t *ti)
    156135{
    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. */
     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. */
    161141static void tinput_update_origin(tinput_t *ti)
    162142{
    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;
     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;
    198149}
    199150
     
    203154                return;
    204155       
    205         unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
     156        sysarg_t new_width = ti->col0 + ti->nc + 1;
    206157        if (new_width % ti->con_cols == 0) {
    207158                /* Advancing to new line. */
     
    234185                return;
    235186       
    236         unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + ilen;
    237         unsigned new_height = (new_width / ti->con_cols) + 1;
     187        sysarg_t new_width = ti->col0 + ti->nc + ilen;
     188        sysarg_t new_height = (new_width / ti->con_cols) + 1;
    238189        if (new_height >= ti->con_rows) {
    239190                /* Disallow text longer than 1 page for now. */
     
    560511}
    561512
    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 
    699513/** Initialize text input field.
    700514 *
     
    707521        ti->hpos = 0;
    708522        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;
    738523}
    739524
     
    754539                return EIO;
    755540       
     541        if (console_get_pos(ti->console, &ti->col0, &ti->row0) != EOK)
     542                return EIO;
     543       
    756544        ti->pos = 0;
    757545        ti->sel_start = 0;
     
    761549        ti->exit_clui = false;
    762550       
    763         if (tinput_display(ti) != EOK)
    764                 return EIO;
    765        
    766551        while (!ti->done) {
    767552                console_flush(ti->console);
     
    929714                tinput_history_seek(ti, -1);
    930715                break;
    931         case KC_TAB:
    932                 tinput_text_complete(ti);
    933                 break;
    934716        default:
    935717                break;
Note: See TracChangeset for help on using the changeset viewer.