_command_offset: Restore compopts used by called command.

This fixes completions that rely on their compopts, most notably mount(8).
Fixes bash-completion bug #313183.
This commit is contained in:
Igor Murzov 2011-09-26 00:22:05 +04:00
parent b9a5f508e2
commit 5051b1787a
3 changed files with 79 additions and 14 deletions

View File

@ -1543,8 +1543,7 @@ _command()
# A meta-command completion function for commands like sudo(8), which need to # A meta-command completion function for commands like sudo(8), which need to
# first complete on a command, then complete according to that command's own # first complete on a command, then complete according to that command's own
# completion definition - currently not quite foolproof (e.g. mount and umount # completion definition.
# don't work properly), but still quite useful.
# #
_command_offset() _command_offset()
{ {
@ -1606,18 +1605,18 @@ _command_offset()
$func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}"
fi fi
# remove any \: generated by a command that doesn't # restore initial compopts
# default to filenames or dirnames (e.g. sudo chown) local opt t
# FIXME: I'm pretty sure this does not work! while true; do
if [ "${cspec#*-o }" != "$cspec" ]; then # FIXME: should we take "+o opt" into account?
cspec=${cspec#*-o } t=${cspec#*-o }
cspec=${cspec%% *} if [ "$t" == "$cspec" ]; then
if [[ "$cspec" != @(dir|file)names ]]; then break
COMPREPLY=("${COMPREPLY[@]//\\\\:/:}")
else
compopt -o filenames
fi fi
fi opt=${t%% *}
compopt -o $opt
cspec=${t#$opt}
done
else else
cspec=${cspec#complete} cspec=${cspec#complete}
cspec=${cspec%%$compcmd} cspec=${cspec%%$compcmd}

View File

@ -30,7 +30,7 @@ proc setup {} {
proc teardown {} { proc teardown {} {
teardown_dummy_mnt teardown_dummy_mnt
assert_env_unmodified assert_env_unmodified {/OLDPWD/d}
} }
@ -49,6 +49,13 @@ assert_complete_any "mount -t "
sync_after_int sync_after_int
set test "mount /dev/sda1 def should complete directory name"
assert_complete_dir "default/" "mount /dev/sda1 def" $::srcdir/fixtures/shared $test -nospace
sync_after_int
set test "Check completing nfs mounts" set test "Check completing nfs mounts"
set expected [list /test/path /test/path2 /second/path] set expected [list /test/path /test/path2 /second/path]
set cmd "mount mocksrv:/" set cmd "mount mocksrv:/"

View File

@ -24,4 +24,63 @@ assert_complete_dir fixtures/ "sudo sh fix" $::srcdir "" -nospace
sync_after_int sync_after_int
# test that `mount` and `sudo mount` behave the same way
set test "sudo mount /dev/sda1 def should complete directory name"
assert_complete_dir "default/" "sudo mount /dev/sda1 def" $::srcdir/fixtures/shared $test -nospace
sync_after_int
# Find user/group suitable for testing.
set failed_find_unique_completion 0
foreach ug {user group} {
# compgen -A is used because it's a bash builtin and available everywhere.
# The || true part prevents exec from throwing an exception if nothing is
# found (very very unlikely).
set list [split [exec bash -c "compgen -A $ug || true"] "\n"]
if {![find_unique_completion_pair $list part$ug full$ug]} {
untested "Not running complex chown tests; no suitable test $ug found."
set failed_find_unique_completion 1
}
}
# These tests require an unique completion.
if {!$failed_find_unique_completion} {
assert_complete $fulluser "sudo chown $partuser"
sync_after_int
assert_complete $fulluser:$fullgroup "sudo chown $fulluser:$partgroup"
sync_after_int
assert_complete "dot.user:$fullgroup" "sudo chown dot.user:$partgroup"
sync_after_int
foreach prefix {
"funky\\ user:" "funky.user:" "funky\\.user:" "fu\\ nky.user:"
"f\\ o\\ o\\.\\bar:" "foo\\_b\\ a\\.r\\ :"
} {
set test "Check preserve special chars in $prefix$partgroup<TAB>"
#assert_complete_into "chown $prefix$partgroup" "chown $prefix$fullgroup " $test
assert_complete $prefix$fullgroup "sudo chown $prefix$partgroup" $test
sync_after_int
}
# Check that we give up in degenerate cases instead of spewing various junk.
assert_no_complete "sudo chown $fulluser\\\\:$partgroup"
sync_after_int
assert_no_complete "sudo chown $fulluser\\\\\\:$partgroup"
sync_after_int
assert_no_complete "sudo chown $fulluser\\\\\\\\:$partgroup"
sync_after_int
# Colons in user/groupnames are not usually allowed.
assert_no_complete "sudo chown foo:bar:$partgroup"
sync_after_int
}
teardown teardown