Skip to content

Commit 036e5c0

Browse files
committed
gdb: use quoted filename completion for the shell command
With the quoted filename completion work that I did last year the deprecated_filename_completer function will now only complete a single word as a filename, for example: (gdb) save breakpoints /tm<TAB> The 'save breakpoints' command uses the deprecated_filename_completer completion function. In the above '/tm' will complete to '/tmp/' as expected. However, if you try this: (gdb) save breakpoints /tmp/ /tm<TAB> The second '/tm' will not complete for GDB 16.x, but will complete with GDB 15.x as GDB 15.x is before my changes were merged. What's actually happening here is that, before my changes, the filename completion was breaking words on white space, so in the above the first '/tmp/' and the second '/tm' are seen as separate words for completion, the second word is therefore seen as the start of a new filename. After my changes, deprecated_filename_completer allows spaces to be part of the filename, so in the above, GDB is actually trying to complete a filename '/tmp/ /tm' which likely doesn't exist, and so completion stops. This change for how deprecated_filename_completer works makes sense, commands like 'save breakpoints' take their complete command arguments and treat it as a single filename, so given this: (gdb) save breakpoints /tmp/ /tm<ENTER> GDB really will try to save breakpoints to a file called '/tmp/ /tm', weird as that may seem. How GDB interprets the command arguments didn't change with my completion patches, I simply brought completion into line with how GDB interprets the arguments. The patches I'm talking about here are this set: * 4076f96 gdb: split apart two different types of filename completion * dc22ab4 gdb: deprecated filename_completer and associated functions * 3503687 gdb: improve escaping when completing filenames * 1d1df75 gdb: move display of completion results into completion_result class * bbbfe4a gdb: simplify completion_result::print_matches * 2bebc9e gdb: add match formatter mechanism for 'complete' command output * f2f866c gdb: apply escaping to filenames in 'complete' results * 8f87fcb gdb: improve gdb_rl_find_completion_word for quoted words * 67b8e30 gdb: implement readline rl_directory_rewrite_hook callback * 1be3b2e gdb: extend completion of quoted filenames to work in brkchars phase * 9dedc2a gdb: fix for completing a second filename for a command * 4339a3f gdb: fix filename completion in the middle of a line Bug PR gdb/32982 identifies a problem with the shell command; completion broke between 15.x and 16.x. The shell command also uses deprecated_filename_completer for completion. But consider a shell command line: (gdb) shell ls /tm<TAB> The arguments to the shell command are 'ls /tm' at the point <TAB> is pressed. Under the old 15.x completion GDB would split the words on white space and then try to complete '/tm' as a filename. Under the 16.x model, GDB completes all the arguments as a single filename, that is 'ls /tm', which is unlikely to match any filenames, and so completion fails. The fix is to write a custom completion function for the shell_command function (cli/cli-cmds.c), this custom completion function will skip forward to find the last word in the arguments, and then try to complete that, so in the above example, GDB will skip over 'ls ', and then tries to complete '/tm', which is exactly what we want. Given that the filenames passed to the shell command are forwarded to an actual shell, I have switched over the new quoted filename completion function for the shell command, this means that white space within a filename will be escaped with a backslash by the completion function, which is likely what the user wants, this means the filename will arrive in the (actual) shell as a single word, rather than splitting on white space and arriving as two words. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32982 Reviewed-By: Tom Tromey <[email protected]>
1 parent cbaa41b commit 036e5c0

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

gdb/cli/cli-cmds.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,21 @@ shell_command (const char *arg, int from_tty)
952952
shell_escape (arg, from_tty);
953953
}
954954

955+
/* Completion for the shell command. Currently, this just uses filename
956+
completion, but we could, potentially, complete command names from $PATH
957+
for the first word, which would make this even more shell like. */
958+
959+
static void
960+
shell_command_completer (struct cmd_list_element *ignore,
961+
completion_tracker &tracker,
962+
const char *text, const char * /* word */)
963+
{
964+
tracker.set_use_custom_word_point (true);
965+
const char *word
966+
= advance_to_filename_maybe_quoted_complete_word_point (tracker, text);
967+
filename_maybe_quoted_completer (ignore, tracker, text, word);
968+
}
969+
955970
static void
956971
edit_command (const char *arg, int from_tty)
957972
{
@@ -2803,7 +2818,7 @@ the previous command number shown."),
28032818
= add_com ("shell", class_support, shell_command, _("\
28042819
Execute the rest of the line as a shell command.\n\
28052820
With no arguments, run an inferior shell."));
2806-
set_cmd_completer (shell_cmd, deprecated_filename_completer);
2821+
set_cmd_completer_handle_brkchars (shell_cmd, shell_command_completer);
28072822

28082823
add_com_alias ("!", shell_cmd, class_support, 0);
28092824

gdb/testsuite/gdb.base/filename-completion.exp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ proc run_quoting_and_escaping_tests { root } {
385385
remove-symbol-file \
386386
"target core" "target exec" "target tfile" \
387387
"maint print c-tdesc" "save gdb-index"
388-
"save gdb-index -dwarf-5" }
388+
"save gdb-index -dwarf-5" "shell ls"}
389389
if { [allow_compile_tests] } {
390390
lappend all_cmds "compile file"
391391
}
@@ -408,6 +408,31 @@ proc run_quoting_and_escaping_tests { root } {
408408
run_quoting_and_escaping_tests_1 $root $cmd
409409
}
410410
}
411+
412+
# Some additional testing of shell command. Test 'shell' and '!'
413+
# when there are multiple filenames on the command line. This
414+
# focuses on completion of the final filename. There is also some
415+
# testing of the shell command above, this tests completion within
416+
# the line.
417+
foreach_with_prefix shell_cmd { "shell " "!" } {
418+
foreach suffix { "aaa/aa bb" "bb2/dir 1/unique file" } {
419+
set dir $root/$suffix
420+
421+
regsub -all " " "$dir" "\\ " dir_with_backslash
422+
423+
with_test_prefix "suffix='$suffix'" {
424+
with_test_prefix "with_backslash" {
425+
run_quoting_and_escaping_tests_1 $root "${shell_cmd}ls $dir_with_backslash"
426+
}
427+
with_test_prefix "with double quotes" {
428+
run_quoting_and_escaping_tests_1 $root "${shell_cmd}ls \"$dir\""
429+
}
430+
with_test_prefix "with single quotes" {
431+
run_quoting_and_escaping_tests_1 $root "${shell_cmd}ls '$dir'"
432+
}
433+
}
434+
}
435+
}
411436
}
412437

413438
# Helper for run_unquoted_tests. ROOT is the root directory as setup

0 commit comments

Comments
 (0)