Re: complete command doesn't work for files...

Daniel Jacobowitz
2004-01-19T16:22:56Z

First of all, sorry about the long delay. I've been meaning to look at
this.

On Wed, Sep 24, 2003 at 04:14:05PM -0700, Jim Ingham wrote:
> I was looking at this for some other reason (I want to add an
> "interpreter-complete console" type command), and I noticed that
> "complete" and the complete_line function that it relies on don't work
> when the input text is a filename, and contains more that just the
> filename. You can see this easily, do:
>
> (gdb) file /usr/<TAB><TAB>
> X11R6 etc info local
> share
> bin games kerberos lost+found
> src
> dict i386-glibc21-linux lib man
> tmp
> doc include libexec sbin
> (gdb) complete file /usr/
> (gdb)
>
> That isn't right, you should get:
>
> (gdb) complete file /usr/
> file /usr/X11R6
> file /usr/bin
> file /usr/dict
> file /usr/doc
> file /usr/etc
> file /usr/games
> file /usr/i386-glibc21-linux
> file /usr/include
> file /usr/info
> file /usr/kerberos
> file /usr/lib
> file /usr/libexec
> file /usr/local
> file /usr/lost+found
> file /usr/man
> file /usr/sbin
> file /usr/share
> file /usr/src
> file /usr/tmp
>
> The attached patch fixes the bug.
>
> The <TAB><TAB> case works because readline advances the first argument
> of complete_line past the initial command. But "complete" always
> passes both TEXT and LINE_BUFFER as the whole command. This patch
> actually does what the comment about file completers above it says it
> intends, namely that we should go to the cursor, and then back up to
> the first file-wordbreak we find. The old code clearly didn't do
> that... Both the <TAB> case and the complete case work now. This also
> makes emacs behave a little better when you try to complete files.
>
> I added a test case for this failure.

I disagree with your analysis. The expectation is that readline may
have broken words prematurely for filenames - which it does, sometimes,
see my mail to gdb@ yesterday - but not failed to break words. So the
caller of complete_line is in error for passing arg. I imagine it
messes up some of the other completers too. Also, you didn't fix
"complete file "; it was right next to the comment in question and had
the same problem.

Here's an alternative patch; tested, no regressions, fixes the problem.
I'll commit it in a few days if no one objects.

--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2004-01-19 Daniel Jacobowitz <drow@mvista.com>

* cli/cli-cmds.c: Include readline.h.
(complete_command): Pass the start of the last word to
complete_line.

2004-01-19 Daniel Jacobowitz <drow@mvista.com>

* gdb.base/completion.exp: Kill a stray backslash.

2004-01-19 Jim Ingham <jingham@apple.com>

* gdb.base/completion.exp: Test that "complete file ./gdb.base/compl"
agrees with the result from sending a tab.

Index: cli/cli-cmds.c
===================================================================
RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v
retrieving revision 1.37
diff -u -p -r1.37 cli-cmds.c
--- cli/cli-cmds.c 17 Dec 2003 21:47:47 -0000 1.37
+++ cli/cli-cmds.c 19 Jan 2004 16:13:31 -0000
@@ -1,6 +1,6 @@
/* GDB CLI commands.

- Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.

This file is part of GDB.

@@ -20,6 +20,7 @@
Boston, MA 02111-1307, USA. */

#include "defs.h"
+#include <readline/readline.h>
#include <readline/tilde.h>
#include "completer.h"
#include "target.h" /* For baud_rate, remote_debug and remote_timeout */
@@ -224,7 +225,7 @@ complete_command (char *arg, int from_tt
{
int i;
int argpoint;
- char **completions;
+ char **completions, *point, *arg_prefix;

dont_repeat ();

@@ -232,7 +233,23 @@ complete_command (char *arg, int from_tt
arg = "";
argpoint = strlen (arg);

- completions = complete_line (arg, arg, argpoint);
+ /* complete_line assumes that its first argument is somewhere within,
+ and except for filenames at the beginning of, the word to be completed.
+ The following crude imitation of readline's word-breaking tries to
+ accomodate this. */
+ point = arg + argpoint;
+ while (point > arg)
+ {
+ if (strchr (rl_completer_word_break_characters, point[-1]) != 0)
+ break;
+ point--;
+ }
+
+ arg_prefix = alloca (point - arg + 1);
+ memcpy (arg_prefix, arg, point - arg);
+ arg_prefix[point - arg] = 0;
+
+ completions = complete_line (point, arg, argpoint);

if (completions)
{
@@ -248,7 +265,7 @@ complete_command (char *arg, int from_tt
while (item < size)
{
int next_item;
- printf_unfiltered ("%s\n", completions[item]);
+ printf_unfiltered ("%s%s\n", arg_prefix, completions[item]);
next_item = item + 1;
while (next_item < size
&& ! strcmp (completions[item], completions[next_item]))
Index: testsuite/gdb.base/completion.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/completion.exp,v
retrieving revision 1.20
diff -u -p -r1.20 completion.exp
--- testsuite/gdb.base/completion.exp 13 Jan 2004 23:39:54 -0000 1.20
+++ testsuite/gdb.base/completion.exp 19 Jan 2004 16:13:31 -0000
@@ -657,6 +657,15 @@ gdb_test "cd ${fullsrcdir}" \
"Working directory [string_to_regexp ${fullsrcdir}].*" \
"cd to \${srcdir}"

+send_gdb "complete file ./gdb.base/compl\n"
+sleep 1
+gdb_expect {
+ -re "file ./gdb.base/completion\\.exp.*$gdb_prompt $"
+ { pass "complete-command 'file ./gdb.base/compl'"}
+ -re ".*$gdb_prompt $" { fail "complete-command 'file ./gdb.base/compl'" }
+ timeout { fail "(timeout) complete-command 'file ./gdb.base/compl'" }
+}
+
send_gdb "file ./gdb.base/complet\t"
sleep 1
gdb_expect {
@@ -664,7 +673,6 @@ gdb_expect {
{ send_gdb "\n"
gdb_expect {
-re "\r\nA program is being debugged already\\. Kill it\\? \\(y or n\\) $"
-\
{ send_gdb "n\n"
gdb_expect {
-re "\r\nProgram not killed\\.\r\n$gdb_prompt $"\