diff --git a/completions/python b/completions/python index d06f8f28677..8bec5b875c5 100644 --- a/completions/python +++ b/completions/python @@ -44,6 +44,38 @@ _comp_cmd_python() esac local noargopts='!(-*|*[cmQWX]*)' + + # if command, module, or script is already given by [-c command | -m module + # | script], complete all kind of files. + local i has_command="" + for ((i = 1; i < cword; i++)); do + # shellcheck disable=SC2254 + case ${words[i]} in + -${noargopts}[QWX]) + ((i++)) + ;; + -${noargopts}[cm]?*) + has_command=set + break + ;; + -- | -${noargopts}[cm]) + if ((i + 1 < cword)); then + has_command=set + break + fi + ;; + -*) ;; + *) + has_command=set + break + ;; + esac + done + if [[ $has_command ]]; then + _comp_compgen_filedir + return + fi + # shellcheck disable=SC2254 case $prev in --help | --version | -${noargopts}[?hVc]) @@ -74,19 +106,10 @@ _comp_cmd_python() _comp_compgen -- -W "help off" return ;; - !(?(*/)?(micro)python*([0-9.])|?(*/)py@(py|ston)*([0-9.])|-?)) - if [[ $cword -lt 2 || ${words[cword - 2]} != -[QWX] ]]; then - _comp_compgen_filedir - return - fi - ;; esac - # if -c or -m is already given, complete all kind of files. - if [[ ${words[*]::cword} == *\ -[cm]\ * ]]; then - _comp_compgen -a filedir - elif [[ $cur != -* ]]; then - _comp_compgen -a filedir '@(py?([cowz])|zip)' + if [[ $prev == -- || $cur != -* ]]; then + _comp_compgen_filedir '@(py?([cowz])|zip)' else _comp_compgen_help - <<<"$("$1" -h | awk '{ sub("\\(-bb:","\n-bb "); print }')" diff --git a/test/fixtures/python/bar.txt b/test/fixtures/python/bar.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/fixtures/python/foo.py b/test/fixtures/python/foo.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/t/test_python.py b/test/t/test_python.py index 1344940e510..bcc566bb57c 100644 --- a/test/t/test_python.py +++ b/test/t/test_python.py @@ -45,3 +45,42 @@ def test_9(self, completion): ) def test_bb(self, completion): assert "-bb" in completion + + @pytest.mark.complete("python foo ", cwd="python") + def test_script_arg(self, completion): + assert "bar.txt" in completion + + @pytest.mark.complete("python -- foo ", cwd="python") + def test_script_arg_with_double_hyphen(self, completion): + assert "bar.txt" in completion + + @pytest.mark.complete("python -m foo bar -p ", cwd="python") + def test_module_arg(self, completion): + assert "bar.txt" in completion + + @pytest.mark.complete("python foo bar -p ", cwd="python") + def test_script_arg_after_option(self, completion): + assert "bar.txt" in completion + + @pytest.mark.complete("python -- foo bar -p ", cwd="python") + def test_script_arg_after_option_with_double_hyphen(self, completion): + assert "bar.txt" in completion + + @pytest.mark.complete("python -m foo bar -p ", cwd="python") + def test_module_arg_after_option(self, completion): + assert "bar.txt" in completion + + @pytest.mark.complete("python -mfoo bar -p ", cwd="python") + def test_module_arg_after_option_with_connected_m_arg(self, completion): + assert "bar.txt" in completion + + @pytest.mark.complete("python -- ", cwd="python") + def test_script_name(self, completion): + assert "bar.txt" not in completion + + @pytest.mark.complete("python -W -mfoo ", cwd="python") + def test_script_name_with_fake_m_arg(self, completion): + """In this case, -mfoo looks like an option to specify the module, but + it should not be treated as the module name because it is an option + argument to -W.""" + assert "bar.txt" not in completion