diff --git a/beets/ui/completion_base.sh b/beets/ui/completion_base.sh index bcc066041..23887e715 100644 --- a/beets/ui/completion_base.sh +++ b/beets/ui/completion_base.sh @@ -60,8 +60,7 @@ _beet_dispatch() { local cur prev COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" + _get_comp_words_by_ref cur prev # Look for the beets subcommand local arg cmd= @@ -103,7 +102,7 @@ _beet_complete() { completions="${flags___common} ${opts} ${flags}" COMPREPLY+=( $(compgen -W "$completions" -- $cur) ) else - _beet_complete_filedir + _filedir fi } @@ -118,12 +117,12 @@ _beet_complete_global() { ;; -l|--library|-c|--config) # Filename completion - _beet_complete_filedir + _filedir return ;; -d|--directory) # Directory completion - _beet_complete_filedir -d + _filedir -d return ;; esac @@ -140,63 +139,6 @@ _beet_complete_global() { fi } -# This function performs file and directory completion. It's better than -# simply using 'compgen -f', because it honours spaces in filenames. -# @param $1 If `-d', complete only on directories. Otherwise filter/pick only -# completions with `.$1' and the uppercase version of it as file -# extension. -# -# This function is based on code from debian's bash-completion package. -# -# Copyright the Bash Completion Maintainers -# -# -_beet_complete_filedir() { - local IFS=$'\n' - local tmp quoted_cur opt="$1" - - _beet_quote_for_readline "$cur" quoted_cur - - if [[ "$opt" != -d ]]; then - opt=-f - fi - - while read -r tmp; do - COMPREPLY+=( "$tmp" ) - done <<< "$(compgen "$opt" -- "$quoted_cur")" -} - -# This function quotes the argument in a way so that readline dequoting -# results in the original argument. This is necessary for at least -# `compgen' which requires its arguments quoted/escaped: -# $ ls "a'b/" -# c -# $ compgen -f "a'b/" # Wrong, doesn't return output -# $ compgen -f "a\'b/" # Good -# a\'b/c -# -# @param $1 Argument to quote -# @param $2 Name of variable to return result to -# -# This function was copied from debian's bash-completion package. -# -# Copyright the Bash Completion Maintainers -# -# -_beet_quote_for_readline() -{ - if [[ $1 == \'* ]]; then - # Leave out first character - printf -v $2 %s "${1:1}" - elif [[ -z $1 ]]; then - # Do not quote the empty string - printf -v $2 %s "$1" - else - printf -v $2 %q "$1" - fi - [[ ${!2} == \$* ]] && eval $2=${!2} -} - # Returns true if the space separated list $1 includes $2 _list_include_item() { [[ " $1 " == *[[:space:]]$2[[:space:]]* ]] diff --git a/test/test_completion.sh b/test/test_completion.sh index 442d77810..6576adb04 100644 --- a/test/test_completion.sh +++ b/test/test_completion.sh @@ -1,10 +1,8 @@ -#!/bin/bash - -. /etc/bash_completion - initcli() { COMP_WORDS=( "beet" "$@" ) let COMP_CWORD=${#COMP_WORDS[@]}-1 + COMP_LINE="${COMP_WORDS[@]}" + let COMP_POINT=${#COMP_LINE} _beet } @@ -64,17 +62,20 @@ test_global_opts() { test_global_file_opts() { + # FIXME somehow file completion only works when the completion + # function is called by the shell completion utilities. So we can't + # test it here initcli --library '' && - completes $(compgen -f) && + completes $(compgen -d) && initcli -l '' && - completes $(compgen -f) && + completes $(compgen -d) && initcli --config '' && - completes $(compgen -f) && + completes $(compgen -d) && initcli -c '' && - completes $(compgen -f) && + completes $(compgen -d) && true } @@ -94,20 +95,20 @@ test_fields_command() { completes -h --help && initcli fields '' && - completes $(compgen -f) && + completes $(compgen -d) && true } test_import_files() { initcli import '' && - completes $(compgen -f) && + completes $(compgen -d) && initcli import --copy -P '' && - completes $(compgen -f) && + completes $(compgen -d) && initcli import --log '' && - completes $(compgen -f) && + completes $(compgen -d) && true } diff --git a/test/test_ui.py b/test/test_ui.py index efe0f0dee..d8b34d529 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -748,12 +748,17 @@ class CompletionTest(_common.TestCase): def test_completion(self): test_script = os.path.join(os.path.dirname(__file__), 'test_completion.sh') + bash_completion = '/etc/bash_completion' # Tests run in bash shell = os.environ.get('BEETS_TEST_SHELL', '/bin/bash --norc') tester = subprocess.Popen(shell.split(' '), stdin=subprocess.PIPE, stdout=subprocess.PIPE) + # Load bash_completion + with open(bash_completion, 'r') as bash_completion: + tester.stdin.writelines(bash_completion) + # Load complection script self.io.install() ui._raw_main(['completion']) @@ -765,8 +770,9 @@ class CompletionTest(_common.TestCase): with open(test_script, 'r') as test_script: tester.stdin.writelines(test_script) (out, err) = tester.communicate() - self.assertEqual(tester.returncode, 0) - self.assertEqual(out, "completion tests passed\n") + if tester.returncode != 0 or out != "completion tests passed\n": + print(out) + self.fail('test/test_completion.sh did not execute properly') def suite(): return unittest.TestLoader().loadTestsFromName(__name__)