Hi,
Post by Ilya KalimanHi!
The tab-autocomplete does not seem to work for some strings in ksh.
mkdir "a a" "(bbb)" "(c c)"
cd a\ a && mkdir abc{1,2,3} && cd ..
cd \(bbb\) && mkdir abc{1,2,3} && cd ..
cd \(c\ c\) && mkdir abc{1,2,3} && cd ..
type "cd a\ a/" hit tab -> auto-completes to abc, offers abc1 abc2 abc3
type "cd \(bbb\)/" hit tab -> auto-completes to abc, offers abc1 abc2 abc3
type "cd \(c\ c\)/" hit tab -> does not autocomplete; expected - same
as previous.
Nice catch. As I see it, the bug you're seeing happens inside
do_complete() while comparing the length of the input buffer and the
results from the completion. Since the completions are passed through
expand() causing escaped characters to be unescaped to their literal
form while the input buffer remains escaped. You managed to find the
perfect set of input causing the condition to when a completion
succeeded to be invalidated:
olen = strlen("\(c\ c\)/") = 9;
nlen = strlen("(c c)/abc") = 9;
Since `olen == nlen` no completion is performed. Please try out the diff
below in which slashes are discarded when comparing the length. I don't
know if any other character should be discarded as well, if true then it
might be worth passing the input buffer through ksh's own lexer and
parser in order to properly handle special characters, just like in
x_file_glob().
Comments? OK?
Index: emacs.c
===================================================================
RCS file: /cvs/src/bin/ksh/emacs.c,v
retrieving revision 1.70
diff -u -p -r1.70 emacs.c
--- emacs.c 25 Jun 2017 17:28:39 -0000 1.70
+++ emacs.c 2 Jul 2017 20:43:00 -0000
@@ -1754,6 +1754,7 @@ do_complete(int flags, /* XCF_{COMMAND,F
char **words;
int nwords;
int start, end, nlen, olen;
+ int i, ndiscard;
int is_command;
int completed = 0;
@@ -1773,9 +1774,13 @@ do_complete(int flags, /* XCF_{COMMAND,F
}
olen = end - start;
+ ndiscard = 0;
+ for (i = start; i < end; i++)
+ if (xbuf[i] == '\\')
+ ndiscard++;
nlen = x_longest_prefix(nwords, words);
/* complete */
- if (nwords == 1 || nlen > olen) {
+ if (nwords == 1 || nlen > olen - ndiscard) {
x_goto(xbuf + start);
x_delete(olen, false);
x_escape(words[0], nlen, x_do_ins);