diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-07-12 02:50:35 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-07-12 02:50:35 +0200 |
commit | 044b18083b4380f158002ed7c00c52d362c9632c (patch) | |
tree | a2bd5c55c1be886890e82e9916b32990ff718b18 | |
parent | 1302892a14e8660b1f577f2cde710103c366d413 (diff) | |
download | busybox-w32-044b18083b4380f158002ed7c00c52d362c9632c.tar.gz busybox-w32-044b18083b4380f158002ed7c00c52d362c9632c.tar.bz2 busybox-w32-044b18083b4380f158002ed7c00c52d362c9632c.zip |
lineedit+unicode: make TAB completion work again
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | libbb/lineedit.c | 85 |
1 files changed, 57 insertions, 28 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 6e836d83e..8b7ff4f8e 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -115,6 +115,9 @@ struct lineedit_statics { | |||
115 | 115 | ||
116 | unsigned cursor; | 116 | unsigned cursor; |
117 | unsigned command_len; | 117 | unsigned command_len; |
118 | /* *int* maxsize: we want x in "if (x > S.maxsize)" | ||
119 | * to _not_ be promoted to unsigned */ | ||
120 | int maxsize; | ||
118 | CHAR_T *command_ps; | 121 | CHAR_T *command_ps; |
119 | 122 | ||
120 | const char *cmdedit_prompt; | 123 | const char *cmdedit_prompt; |
@@ -389,12 +392,12 @@ static void put_prompt(void) | |||
389 | /* draw prompt, editor line, and clear tail */ | 392 | /* draw prompt, editor line, and clear tail */ |
390 | static void redraw(int y, int back_cursor) | 393 | static void redraw(int y, int back_cursor) |
391 | { | 394 | { |
392 | if (y > 0) /* up to start y */ | 395 | if (y > 0) /* up to start y */ |
393 | printf("\033[%dA", y); | 396 | printf("\033[%uA", y); |
394 | bb_putchar('\r'); | 397 | bb_putchar('\r'); |
395 | put_prompt(); | 398 | put_prompt(); |
396 | input_end(); /* rewrite */ | 399 | input_end(); /* rewrite */ |
397 | printf("\033[J"); /* erase after cursor */ | 400 | printf("\033[J"); /* erase after cursor */ |
398 | input_backward(back_cursor); | 401 | input_backward(back_cursor); |
399 | } | 402 | } |
400 | 403 | ||
@@ -687,7 +690,7 @@ static void exe_n_cwd_tab_completion(char *command, int type) | |||
687 | memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \ | 690 | memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \ |
688 | } while (0) | 691 | } while (0) |
689 | 692 | ||
690 | static int find_match(char *matchBuf, int *len_with_quotes) | 693 | static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) |
691 | { | 694 | { |
692 | int i, j; | 695 | int i, j; |
693 | int command_mode; | 696 | int command_mode; |
@@ -922,12 +925,19 @@ static void input_tab(smallint *lastWasTab) | |||
922 | #define matchBuf (S.input_tab__matchBuf) | 925 | #define matchBuf (S.input_tab__matchBuf) |
923 | int find_type; | 926 | int find_type; |
924 | int recalc_pos; | 927 | int recalc_pos; |
928 | #if ENABLE_FEATURE_ASSUME_UNICODE | ||
929 | /* cursor pos in command converted to multibyte form */ | ||
930 | int cursor_mb; | ||
931 | #endif | ||
925 | 932 | ||
926 | *lastWasTab = TRUE; /* flop trigger */ | 933 | *lastWasTab = TRUE; /* flop trigger */ |
927 | 934 | ||
928 | /* Make a local copy of the string -- | 935 | /* Make a local copy of the string -- |
929 | * up to the position of the cursor */ | 936 | * up to the position of the cursor */ |
930 | save_string(matchBuf, cursor + 1); | 937 | save_string(matchBuf, cursor + 1); |
938 | #if ENABLE_FEATURE_ASSUME_UNICODE | ||
939 | cursor_mb = strlen(matchBuf); | ||
940 | #endif | ||
931 | tmp = matchBuf; | 941 | tmp = matchBuf; |
932 | 942 | ||
933 | find_type = find_match(matchBuf, &recalc_pos); | 943 | find_type = find_match(matchBuf, &recalc_pos); |
@@ -939,7 +949,7 @@ static void input_tab(smallint *lastWasTab) | |||
939 | /* If the word starts with `~' and there is no slash in the word, | 949 | /* If the word starts with `~' and there is no slash in the word, |
940 | * then try completing this word as a username. */ | 950 | * then try completing this word as a username. */ |
941 | if (state->flags & USERNAME_COMPLETION) | 951 | if (state->flags & USERNAME_COMPLETION) |
942 | if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) | 952 | if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) |
943 | username_tab_completion(matchBuf, NULL); | 953 | username_tab_completion(matchBuf, NULL); |
944 | #endif | 954 | #endif |
945 | /* Try to match any executable in our path and everything | 955 | /* Try to match any executable in our path and everything |
@@ -965,18 +975,20 @@ static void input_tab(smallint *lastWasTab) | |||
965 | num_matches = n + 1; | 975 | num_matches = n + 1; |
966 | } | 976 | } |
967 | /* Did we find exactly one match? */ | 977 | /* Did we find exactly one match? */ |
968 | if (!matches || num_matches > 1) { | 978 | if (!matches || num_matches > 1) { /* no */ |
969 | beep(); | 979 | beep(); |
970 | if (!matches) | 980 | if (!matches) |
971 | return; /* not found */ | 981 | return; /* not found */ |
972 | /* find minimal match */ | 982 | /* find minimal match */ |
973 | tmp1 = xstrdup(matches[0]); | 983 | tmp1 = xstrdup(matches[0]); |
974 | for (tmp = tmp1; *tmp; tmp++) | 984 | for (tmp = tmp1; *tmp; tmp++) { |
975 | for (len_found = 1; len_found < num_matches; len_found++) | 985 | for (len_found = 1; len_found < num_matches; len_found++) { |
976 | if (matches[len_found][(tmp - tmp1)] != *tmp) { | 986 | if (matches[len_found][tmp - tmp1] != *tmp) { |
977 | *tmp = '\0'; | 987 | *tmp = '\0'; |
978 | break; | 988 | break; |
979 | } | 989 | } |
990 | } | ||
991 | } | ||
980 | if (*tmp1 == '\0') { /* have unique */ | 992 | if (*tmp1 == '\0') { /* have unique */ |
981 | free(tmp1); | 993 | free(tmp1); |
982 | return; | 994 | return; |
@@ -994,29 +1006,44 @@ static void input_tab(smallint *lastWasTab) | |||
994 | tmp[len_found+1] = '\0'; | 1006 | tmp[len_found+1] = '\0'; |
995 | } | 1007 | } |
996 | } | 1008 | } |
1009 | |||
997 | len_found = strlen(tmp); | 1010 | len_found = strlen(tmp); |
998 | /* have space to placed match? */ | ||
999 | if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) { | ||
1000 | /* before word for match */ | ||
1001 | //TODO: | ||
1002 | #if !ENABLE_FEATURE_ASSUME_UNICODE | 1011 | #if !ENABLE_FEATURE_ASSUME_UNICODE |
1003 | command_ps[cursor - recalc_pos] = '\0'; | 1012 | /* have space to place the match? */ |
1004 | /* save tail line */ | 1013 | /* The result consists of three parts with these lengths: */ |
1014 | /* (cursor - recalc_pos) + len_found + (command_len - cursor) */ | ||
1015 | /* it simplifies into: */ | ||
1016 | if ((int)(len_found + command_len - recalc_pos) < S.maxsize) { | ||
1017 | /* save tail */ | ||
1005 | strcpy(matchBuf, command_ps + cursor); | 1018 | strcpy(matchBuf, command_ps + cursor); |
1006 | /* add match */ | 1019 | /* add match and tail */ |
1007 | strcat(command_ps, tmp); | 1020 | sprintf(&command_ps[cursor - recalc_pos], "%s%s", tmp, matchBuf); |
1008 | /* add tail */ | ||
1009 | strcat(command_ps, matchBuf); | ||
1010 | /* back to begin word for match */ | ||
1011 | input_backward(recalc_pos); | ||
1012 | /* new pos */ | ||
1013 | recalc_pos = cursor + len_found; | ||
1014 | /* new len */ | ||
1015 | command_len = strlen(command_ps); | 1021 | command_len = strlen(command_ps); |
1016 | /* write out the matched command */ | 1022 | /* new pos */ |
1017 | #endif | 1023 | recalc_pos = cursor - recalc_pos + len_found; |
1024 | /* write out the matched command */ | ||
1018 | redraw(cmdedit_y, command_len - recalc_pos); | 1025 | redraw(cmdedit_y, command_len - recalc_pos); |
1019 | } | 1026 | } |
1027 | #else | ||
1028 | { | ||
1029 | char command[MAX_LINELEN]; | ||
1030 | int len = save_string(command, sizeof(command)); | ||
1031 | /* have space to place the match? */ | ||
1032 | /* (cursor_mb - recalc_pos) + len_found + (len - cursor_mb) */ | ||
1033 | if ((int)(len_found + len - recalc_pos) < MAX_LINELEN) { | ||
1034 | /* save tail */ | ||
1035 | strcpy(matchBuf, command + cursor_mb); | ||
1036 | /* where do we want to have cursor after all? */ | ||
1037 | strcpy(&command[cursor_mb - recalc_pos], tmp); | ||
1038 | len = load_string(command, S.maxsize); | ||
1039 | /* add match and tail */ | ||
1040 | sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf); | ||
1041 | command_len = load_string(command, S.maxsize); | ||
1042 | /* write out the matched command */ | ||
1043 | redraw(cmdedit_y, command_len - len); | ||
1044 | } | ||
1045 | } | ||
1046 | #endif | ||
1020 | free(tmp); | 1047 | free(tmp); |
1021 | #undef matchBuf | 1048 | #undef matchBuf |
1022 | } else { | 1049 | } else { |
@@ -1024,7 +1051,8 @@ static void input_tab(smallint *lastWasTab) | |||
1024 | * just hit TAB again, print a list of all the | 1051 | * just hit TAB again, print a list of all the |
1025 | * available choices... */ | 1052 | * available choices... */ |
1026 | if (matches && num_matches > 0) { | 1053 | if (matches && num_matches > 0) { |
1027 | int sav_cursor = cursor; /* change goto_new_line() */ | 1054 | /* changed by goto_new_line() */ |
1055 | int sav_cursor = cursor; | ||
1028 | 1056 | ||
1029 | /* Go to the next line */ | 1057 | /* Go to the next line */ |
1030 | goto_new_line(); | 1058 | goto_new_line(); |
@@ -1641,6 +1669,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1641 | // FIXME: audit & improve this | 1669 | // FIXME: audit & improve this |
1642 | if (maxsize > MAX_LINELEN) | 1670 | if (maxsize > MAX_LINELEN) |
1643 | maxsize = MAX_LINELEN; | 1671 | maxsize = MAX_LINELEN; |
1672 | S.maxsize = maxsize; | ||
1644 | 1673 | ||
1645 | /* With null flags, no other fields are ever used */ | 1674 | /* With null flags, no other fields are ever used */ |
1646 | state = st ? st : (line_input_t*) &const_int_0; | 1675 | state = st ? st : (line_input_t*) &const_int_0; |