lineedit: remove pos_buf[] array (up to 16k!); fix compat bugs

pos_buf is a strange hack, easy to do without it.
This also allows lines >32k long to be handled.
Also simplified match prefix generations and made behavior more like bash.

function                                             old     new   delta
remove_chunk                                           -      43     +43
collapse_pos                                          79       -     -79
build_match_prefix                                   804     579    -225
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 0/1 up/down: 43/-304)          Total: -261 bytes

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko 2010-09-03 12:59:15 +02:00
parent 3c460b005c
commit 81254ed387

View File

@ -99,7 +99,6 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
enum { enum {
/* We use int16_t for positions, need to limit line len */
MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
? CONFIG_FEATURE_EDITING_MAX_LEN ? CONFIG_FEATURE_EDITING_MAX_LEN
: 0x7ff0 : 0x7ff0
@ -156,7 +155,6 @@ struct lineedit_statics {
#if ENABLE_FEATURE_TAB_COMPLETION #if ENABLE_FEATURE_TAB_COMPLETION
char input_tab__matchBuf[MAX_LINELEN]; char input_tab__matchBuf[MAX_LINELEN];
int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */ int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */
int16_t find_match__pos_buf[MAX_LINELEN + 1];
#endif #endif
}; };
@ -824,15 +822,16 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
*/ */
#define QUOT (UCHAR_MAX+1) #define QUOT (UCHAR_MAX+1)
#define int_buf (S.find_match__int_buf) #define int_buf (S.find_match__int_buf)
#define pos_buf (S.find_match__pos_buf)
#define dbg_bmp 0 #define dbg_bmp 0
static void collapse_pos(int beg, int end) static void remove_chunk(int beg, int end)
{ {
/* beg must be <= end */ /* beg must be <= end */
if (beg == end) if (beg == end)
return; return;
memmove(int_buf+beg, int_buf+end, (MAX_LINELEN+1-end) * sizeof(int_buf[0]));
memmove(pos_buf+beg, pos_buf+end, (MAX_LINELEN+1-end) * sizeof(pos_buf[0])); while ((int_buf[beg] = int_buf[end]) != 0)
beg++, end++;
if (dbg_bmp) { if (dbg_bmp) {
int i; int i;
for (i = 0; int_buf[i]; i++) for (i = 0; int_buf[i]; i++)
@ -846,42 +845,39 @@ static NOINLINE int build_match_prefix(char *matchBuf)
int command_mode; int command_mode;
/* Were local, but it used too much stack */ /* Were local, but it used too much stack */
/* int16_t int_buf[MAX_LINELEN + 1]; */ /* int16_t int_buf[MAX_LINELEN + 1]; */
/* int16_t pos_buf[MAX_LINELEN + 1]; */
if (dbg_bmp) printf("\n%s\n", matchBuf); if (dbg_bmp) printf("\n%s\n", matchBuf);
for (i = 0;; i++) { i = 0;
int_buf[i] = (unsigned char)matchBuf[i]; while ((int_buf[i] = (unsigned char)matchBuf[i]) != '\0')
if (int_buf[i] == 0) { i++;
pos_buf[i] = -1; /* end-of-line indicator */
break;
}
pos_buf[i] = i;
}
/* Mark every \c as "quoted c" */ /* Mark every \c as "quoted c" */
for (i = j = 0; matchBuf[i]; i++, j++) { for (i = j = 0; matchBuf[i]; i++, j++) {
if (matchBuf[i] == '\\') { if (matchBuf[i] == '\\') {
collapse_pos(j, j + 1); remove_chunk(j, j + 1);
int_buf[j] |= QUOT; int_buf[j] |= QUOT;
i++; i++;
} }
} }
/* Quote-mark "chars" and 'chars' */ /* Quote-mark "chars" and 'chars', drop delimiters */
{ {
int in_quote = 0; int in_quote = 0;
for (i = 0; int_buf[i]; i++) { i = 0;
while (int_buf[i]) {
int cur = int_buf[i]; int cur = int_buf[i];
if (!cur)
break;
if (cur == '\'' || cur == '"') { if (cur == '\'' || cur == '"') {
if (!in_quote) if (!in_quote || (cur == in_quote)) {
in_quote = cur; in_quote ^= cur;
else if (cur == in_quote) remove_chunk(i, i + 1);
in_quote = 0; continue;
else }
int_buf[i] |= QUOT;
} else if (in_quote && cur != '$') {
int_buf[i] |= QUOT;
} }
if (in_quote)
int_buf[i] = cur | QUOT;
i++;
} }
} }
@ -898,53 +894,39 @@ static NOINLINE int build_match_prefix(char *matchBuf)
} else if (cur == '|' && prev == '>') { } else if (cur == '|' && prev == '>') {
continue; continue;
} }
collapse_pos(0, i + 1 + (cur == int_buf[i + 1])); remove_chunk(0, i + 1 + (cur == int_buf[i + 1]));
i = -1; /* back to square 1 */ i = -1; /* back to square 1 */
} }
} }
/* Remove all `cmd` */ /* Remove all `cmd` */
//BUG: `cmd` should count as a word: `cmd` c<tab> should search for files c*, not commands c*
for (i = 0; int_buf[i]; i++) { for (i = 0; int_buf[i]; i++) {
if (int_buf[i] == '`') { if (int_buf[i] == '`') {
for (j = i + 1; int_buf[j]; j++) { for (j = i + 1; int_buf[j]; j++) {
if (int_buf[j] == '`') { if (int_buf[j] == '`') {
collapse_pos(i, j + 1); /* `cmd` should count as a word:
* `cmd` c<tab> should search for files c*,
* not commands c*. Therefore we don't drop
* `cmd` entirely, we replace it with single `.
*/
remove_chunk(i, j);
goto next; goto next;
} }
} }
/* No closing ` - command mode, remove all up to ` */ /* No closing ` - command mode, remove all up to ` */
collapse_pos(0, i + 1); remove_chunk(0, i + 1);
break; break;
next: next: ;
i--; /* hack increment */
} }
} }
/* Remove (command...(command...)...) and {command...{command...}...} */ /* Remove "cmd (" and "cmd {"
{ * Example: "if { c<tab>"
int paren_lvl = 0; * In this example, c should be matched as command pfx.
int curly_lvl = 0; */
for (i = 0; int_buf[i]; i++) { for (i = 0; int_buf[i]; i++) {
if (int_buf[i] == '(' || int_buf[i] == '{') { if (int_buf[i] == '(' || int_buf[i] == '{') {
if (int_buf[i] == '(') remove_chunk(0, i + 1);
paren_lvl++; i = -1; /* hack increment */
else
curly_lvl++;
collapse_pos(0, i + 1);
i = -1; /* hack increment */
}
}
for (i = 0; pos_buf[i] >= 0 && (paren_lvl > 0 || curly_lvl > 0); i++) {
if ((int_buf[i] == ')' && paren_lvl > 0)
|| (int_buf[i] == '}' && curly_lvl > 0)
) {
if (int_buf[i] == ')')
paren_lvl--;
else
curly_lvl--;
collapse_pos(0, i + 1);
i = -1; /* hack increment */
}
} }
} }
@ -952,7 +934,7 @@ static NOINLINE int build_match_prefix(char *matchBuf)
for (i = 0; int_buf[i]; i++) for (i = 0; int_buf[i]; i++)
if (int_buf[i] != ' ') if (int_buf[i] != ' ')
break; break;
collapse_pos(0, i); remove_chunk(0, i);
/* Determine completion mode */ /* Determine completion mode */
command_mode = FIND_EXE_ONLY; command_mode = FIND_EXE_ONLY;
@ -960,9 +942,9 @@ static NOINLINE int build_match_prefix(char *matchBuf)
if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
if (int_buf[i] == ' ' if (int_buf[i] == ' '
&& command_mode == FIND_EXE_ONLY && command_mode == FIND_EXE_ONLY
&& matchBuf[pos_buf[0]] == 'c' && (char)int_buf[0] == 'c'
&& matchBuf[pos_buf[1]] == 'd' && (char)int_buf[1] == 'd'
//BUG: must check "cd ", not "cd" && i == 2 /* -> int_buf[2] == ' ' */
) { ) {
command_mode = FIND_DIR_ONLY; command_mode = FIND_DIR_ONLY;
} else { } else {
@ -979,36 +961,20 @@ static NOINLINE int build_match_prefix(char *matchBuf)
for (--i; i >= 0; i--) { for (--i; i >= 0; i--) {
int cur = int_buf[i]; int cur = int_buf[i];
if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') { if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') {
collapse_pos(0, i + 1); remove_chunk(0, i + 1);
break; break;
} }
} }
/* Skip all leading unquoted ' or " */
//BUG: bash doesn't do this
for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
continue;
/* Skip quoted or unquoted // or /~ */
//BUG: bash doesn't do this
while ((char)int_buf[i] == '/'
&& ((char)int_buf[i+1] == '/' || (char)int_buf[i+1] == '~')
) {
i++;
}
/* set only match and destroy quotes */ /* Store only match prefix */
{ i = 0;
int pos = 0; while ((matchBuf[i] = int_buf[i]) != '\0')
for (j = 0; pos_buf[i] >= 0; i++) { i++;
matchBuf[j++] = matchBuf[pos_buf[i]]; if (dbg_bmp) printf("final matchBuf:'%s'\n", matchBuf);
pos = pos_buf[i] + 1;
}
matchBuf[j] = '\0';
}
return command_mode; return command_mode;
} }
#undef int_buf #undef int_buf
#undef pos_buf
/* /*
* Display by column (original idea from ls applet, * Display by column (original idea from ls applet,