Changes in uspace/lib/clui/tinput.c [79ae36dd:be61b8f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/clui/tinput.c
r79ae36dd rbe61b8f 1 1 /* 2 * Copyright (c) 201 0Jiri Svoboda2 * Copyright (c) 2011 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 27 27 */ 28 28 29 #include <sort.h> 29 30 #include <stdio.h> 30 31 #include <stdlib.h> … … 42 43 #include <tinput.h> 43 44 45 #define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols)) 46 #define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols)) 47 44 48 /** Seek direction */ 45 49 typedef enum { … … 61 65 static void tinput_post_seek(tinput_t *, bool); 62 66 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 63 73 /** Create a new text input field. */ 64 74 tinput_t *tinput_new(void) … … 66 76 tinput_t *ti; 67 77 68 ti = malloc(sizeof(tinput_t));78 ti = calloc(1, sizeof(tinput_t)); 69 79 if (ti == NULL) 70 80 return NULL; … … 77 87 void tinput_destroy(tinput_t *ti) 78 88 { 89 if (ti->prompt != NULL) 90 free(ti->prompt); 79 91 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); 80 102 } 81 103 … … 88 110 tinput_sel_get_bounds(ti, &sa, &sb); 89 111 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); 92 113 console_set_style(ti->console, STYLE_NORMAL); 93 114 … … 134 155 static void tinput_position_caret(tinput_t *ti) 135 156 { 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. */ 141 161 static void tinput_update_origin(tinput_t *ti) 142 162 { 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 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; 149 198 } 150 199 … … 154 203 return; 155 204 156 sysarg_t new_width = ti->col0+ ti->nc + 1;205 unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1; 157 206 if (new_width % ti->con_cols == 0) { 158 207 /* Advancing to new line. */ … … 185 234 return; 186 235 187 sysarg_t new_width = ti->col0+ ti->nc + ilen;188 sysarg_tnew_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; 189 238 if (new_height >= ti->con_rows) { 190 239 /* Disallow text longer than 1 page for now. */ … … 511 560 } 512 561 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 513 737 /** Initialize text input field. 514 738 * … … 521 745 ti->hpos = 0; 522 746 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 */ 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 text 771 * completion. 772 */ 773 void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops) 774 { 775 ti->compl_ops = compl_ops; 523 776 } 524 777 … … 539 792 return EIO; 540 793 541 if (console_get_pos(ti->console, &ti->col0, &ti->row0) != EOK)542 return EIO;543 544 794 ti->pos = 0; 545 795 ti->sel_start = 0; … … 549 799 ti->exit_clui = false; 550 800 801 if (tinput_display(ti) != EOK) 802 return EIO; 803 551 804 while (!ti->done) { 552 805 console_flush(ti->console); … … 714 967 tinput_history_seek(ti, -1); 715 968 break; 969 case KC_TAB: 970 tinput_text_complete(ti); 971 break; 716 972 default: 717 973 break;
Note:
See TracChangeset
for help on using the changeset viewer.