lineedit+unicode: make TAB completion work again
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 6e836d8..8b7ff4f 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -115,6 +115,9 @@
unsigned cursor;
unsigned command_len;
+ /* *int* maxsize: we want x in "if (x > S.maxsize)"
+ * to _not_ be promoted to unsigned */
+ int maxsize;
CHAR_T *command_ps;
const char *cmdedit_prompt;
@@ -389,12 +392,12 @@
/* draw prompt, editor line, and clear tail */
static void redraw(int y, int back_cursor)
{
- if (y > 0) /* up to start y */
- printf("\033[%dA", y);
+ if (y > 0) /* up to start y */
+ printf("\033[%uA", y);
bb_putchar('\r');
put_prompt();
- input_end(); /* rewrite */
- printf("\033[J"); /* erase after cursor */
+ input_end(); /* rewrite */
+ printf("\033[J"); /* erase after cursor */
input_backward(back_cursor);
}
@@ -687,7 +690,7 @@
memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \
} while (0)
-static int find_match(char *matchBuf, int *len_with_quotes)
+static NOINLINE int find_match(char *matchBuf, int *len_with_quotes)
{
int i, j;
int command_mode;
@@ -922,12 +925,19 @@
#define matchBuf (S.input_tab__matchBuf)
int find_type;
int recalc_pos;
+#if ENABLE_FEATURE_ASSUME_UNICODE
+ /* cursor pos in command converted to multibyte form */
+ int cursor_mb;
+#endif
*lastWasTab = TRUE; /* flop trigger */
/* Make a local copy of the string --
* up to the position of the cursor */
save_string(matchBuf, cursor + 1);
+#if ENABLE_FEATURE_ASSUME_UNICODE
+ cursor_mb = strlen(matchBuf);
+#endif
tmp = matchBuf;
find_type = find_match(matchBuf, &recalc_pos);
@@ -939,7 +949,7 @@
/* If the word starts with `~' and there is no slash in the word,
* then try completing this word as a username. */
if (state->flags & USERNAME_COMPLETION)
- if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
+ if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL)
username_tab_completion(matchBuf, NULL);
#endif
/* Try to match any executable in our path and everything
@@ -965,18 +975,20 @@
num_matches = n + 1;
}
/* Did we find exactly one match? */
- if (!matches || num_matches > 1) {
+ if (!matches || num_matches > 1) { /* no */
beep();
if (!matches)
return; /* not found */
/* find minimal match */
tmp1 = xstrdup(matches[0]);
- for (tmp = tmp1; *tmp; tmp++)
- for (len_found = 1; len_found < num_matches; len_found++)
- if (matches[len_found][(tmp - tmp1)] != *tmp) {
+ for (tmp = tmp1; *tmp; tmp++) {
+ for (len_found = 1; len_found < num_matches; len_found++) {
+ if (matches[len_found][tmp - tmp1] != *tmp) {
*tmp = '\0';
break;
}
+ }
+ }
if (*tmp1 == '\0') { /* have unique */
free(tmp1);
return;
@@ -994,29 +1006,44 @@
tmp[len_found+1] = '\0';
}
}
+
len_found = strlen(tmp);
- /* have space to placed match? */
- if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) {
- /* before word for match */
-//TODO:
#if !ENABLE_FEATURE_ASSUME_UNICODE
- command_ps[cursor - recalc_pos] = '\0';
- /* save tail line */
+ /* have space to place the match? */
+ /* The result consists of three parts with these lengths: */
+ /* (cursor - recalc_pos) + len_found + (command_len - cursor) */
+ /* it simplifies into: */
+ if ((int)(len_found + command_len - recalc_pos) < S.maxsize) {
+ /* save tail */
strcpy(matchBuf, command_ps + cursor);
- /* add match */
- strcat(command_ps, tmp);
- /* add tail */
- strcat(command_ps, matchBuf);
- /* back to begin word for match */
- input_backward(recalc_pos);
- /* new pos */
- recalc_pos = cursor + len_found;
- /* new len */
+ /* add match and tail */
+ sprintf(&command_ps[cursor - recalc_pos], "%s%s", tmp, matchBuf);
command_len = strlen(command_ps);
- /* write out the matched command */
-#endif
+ /* new pos */
+ recalc_pos = cursor - recalc_pos + len_found;
+ /* write out the matched command */
redraw(cmdedit_y, command_len - recalc_pos);
}
+#else
+ {
+ char command[MAX_LINELEN];
+ int len = save_string(command, sizeof(command));
+ /* have space to place the match? */
+ /* (cursor_mb - recalc_pos) + len_found + (len - cursor_mb) */
+ if ((int)(len_found + len - recalc_pos) < MAX_LINELEN) {
+ /* save tail */
+ strcpy(matchBuf, command + cursor_mb);
+ /* where do we want to have cursor after all? */
+ strcpy(&command[cursor_mb - recalc_pos], tmp);
+ len = load_string(command, S.maxsize);
+ /* add match and tail */
+ sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf);
+ command_len = load_string(command, S.maxsize);
+ /* write out the matched command */
+ redraw(cmdedit_y, command_len - len);
+ }
+ }
+#endif
free(tmp);
#undef matchBuf
} else {
@@ -1024,7 +1051,8 @@
* just hit TAB again, print a list of all the
* available choices... */
if (matches && num_matches > 0) {
- int sav_cursor = cursor; /* change goto_new_line() */
+ /* changed by goto_new_line() */
+ int sav_cursor = cursor;
/* Go to the next line */
goto_new_line();
@@ -1641,6 +1669,7 @@
// FIXME: audit & improve this
if (maxsize > MAX_LINELEN)
maxsize = MAX_LINELEN;
+ S.maxsize = maxsize;
/* With null flags, no other fields are ever used */
state = st ? st : (line_input_t*) &const_int_0;