Changes in uspace/lib/clui/tinput.c [be61b8f:96b02eb9] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/clui/tinput.c
rbe61b8f r96b02eb9 1 1 /* 2 * Copyright (c) 201 1Jiri Svoboda2 * Copyright (c) 2010 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 27 27 */ 28 28 29 #include <sort.h>30 29 #include <stdio.h> 31 30 #include <stdlib.h> … … 43 42 #include <tinput.h> 44 43 45 #define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols))46 #define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols))47 48 44 /** Seek direction */ 49 45 typedef enum { … … 58 54 static void tinput_sel_all(tinput_t *); 59 55 static 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 *);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 *); 64 60 static void tinput_pre_seek(tinput_t *, bool); 65 61 static void tinput_post_seek(tinput_t *, bool); 66 62 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 73 63 /** Create a new text input field. */ 74 64 tinput_t *tinput_new(void) … … 76 66 tinput_t *ti; 77 67 78 ti = calloc(1,sizeof(tinput_t));68 ti = malloc(sizeof(tinput_t)); 79 69 if (ti == NULL) 80 70 return NULL; … … 87 77 void tinput_destroy(tinput_t *ti) 88 78 { 89 if (ti->prompt != NULL)90 free(ti->prompt);91 79 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);102 80 } 103 81 … … 110 88 tinput_sel_get_bounds(ti, &sa, &sb); 111 89 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); 114 93 115 94 size_t p = start; … … 122 101 123 102 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); 127 105 memcpy(dbuf, ti->buffer + p, 128 106 (sb - p) * sizeof(wchar_t)); … … 132 110 } 133 111 134 console_flush(ti->console);135 console_set_style( ti->console, STYLE_NORMAL);112 fflush(stdout); 113 console_set_style(fphone(stdout), STYLE_NORMAL); 136 114 137 115 if (p < ti->nc) { … … 145 123 putchar(' '); 146 124 147 console_flush(ti->console);125 fflush(stdout); 148 126 } 149 127 … … 155 133 static void tinput_position_caret(tinput_t *ti) 156 134 { 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. */ 161 140 static void tinput_update_origin(tinput_t *ti) 162 141 { 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; 198 148 } 199 149 … … 203 153 return; 204 154 205 unsigned new_width = LIN_TO_COL(ti, ti->text_coord)+ ti->nc + 1;155 sysarg_t new_width = ti->col0 + ti->nc + 1; 206 156 if (new_width % ti->con_cols == 0) { 207 157 /* Advancing to new line. */ … … 234 184 return; 235 185 236 unsigned new_width = LIN_TO_COL(ti, ti->text_coord)+ ti->nc + ilen;237 unsignednew_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; 238 188 if (new_height >= ti->con_rows) { 239 189 /* Disallow text longer than 1 page for now. */ … … 560 510 } 561 511 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 /* Print a list of completions */594 static 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 632 static 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 737 512 /** Initialize text input field. 738 513 * … … 741 516 static void tinput_init(tinput_t *ti) 742 517 { 743 ti->console = console_init(stdin, stdout);744 518 ti->hnum = 0; 745 519 ti->hpos = 0; 746 520 ti->history[0] = NULL; 747 }748 749 /** Set prompt string.750 *751 * @param ti Text input752 * @param prompt Prompt string753 *754 * @return EOK on success, ENOMEM if out of memory.755 */756 int 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 text771 * completion.772 */773 void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)774 {775 ti->compl_ops = compl_ops;776 521 } 777 522 … … 788 533 int tinput_read(tinput_t *ti, char **dstr) 789 534 { 790 console_flush(ti->console); 791 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) 792 540 return EIO; 793 541 … … 799 547 ti->exit_clui = false; 800 548 801 if (tinput_display(ti) != EOK)802 return EIO;803 804 549 while (!ti->done) { 805 console_flush(ti->console);806 807 kbd_event_t ev;808 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)) 809 554 return EIO; 810 555 … … 851 596 } 852 597 853 static void tinput_key_ctrl(tinput_t *ti, kbd_event_t *ev)598 static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev) 854 599 { 855 600 switch (ev->key) { … … 890 635 } 891 636 892 static void tinput_key_ctrl_shift(tinput_t *ti, kbd_event_t *ev)637 static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev) 893 638 { 894 639 switch (ev->key) { … … 910 655 } 911 656 912 static void tinput_key_shift(tinput_t *ti, kbd_event_t *ev)657 static void tinput_key_shift(tinput_t *ti, console_event_t *ev) 913 658 { 914 659 switch (ev->key) { … … 936 681 } 937 682 938 static void tinput_key_unmod(tinput_t *ti, kbd_event_t *ev)683 static void tinput_key_unmod(tinput_t *ti, console_event_t *ev) 939 684 { 940 685 switch (ev->key) { … … 967 712 tinput_history_seek(ti, -1); 968 713 break; 969 case KC_TAB:970 tinput_text_complete(ti);971 break;972 714 default: 973 715 break;
Note:
See TracChangeset
for help on using the changeset viewer.