From ee462165cca420bc9d009719d4e135380a932d6d Mon Sep 17 00:00:00 2001 From: Aloxaf Date: Sat, 5 Dec 2020 16:38:07 +0800 Subject: [PATCH 1/9] Add zsh completion script --- completion/_pdm | 280 +++++++++++++++++++++++++++++++++++++++++++++++ news/188.feature | 1 + 2 files changed, 281 insertions(+) create mode 100644 completion/_pdm create mode 100644 news/188.feature diff --git a/completion/_pdm b/completion/_pdm new file mode 100644 index 0000000000..d75a5b439f --- /dev/null +++ b/completion/_pdm @@ -0,0 +1,280 @@ +#compdef pdm + +PDM_PIP_INDEXES=('https://pypi.org/simple/') + +_pdm() { + emulate -L zsh -o extended_glob + + typeset -A opt_args + local context state state_descr line + + local curcontext=$curcontext ret=1 + local -a arguments=( + {-h,--help}'[Show help message and exit]' + {-v,--verbose}'[Show detailed output]' + '-vv[Show more detailed output]' + ) + local sub_commands=( + 'add:Add package(s) to pyproject.toml and install them' + 'build:Build artifacts for distribution' + 'cache:Control the caches of PDM' + 'completion:Generate completion scripts for the given shell' + 'config:Display the current configuration' + 'export:Export the locked packages set to other formats' + 'import:Import project metadata from other formats' + 'info:Show the project information' + 'init:Initialize a pyproject.toml for PDM' + 'install:Install dependencies from lock file' + 'list:List packages installed in the current working set' + 'lock:Resolve and lock dependencies' + 'remove:Remove packages from pyproject.toml' + 'run:Run commands or scripts with local packages loaded' + 'search:Search for PyPI packages' + 'show:Show the package information' + 'sync:Synchronize the current working set with lock file' + 'update:Update package(s) in pyproject.toml' + 'use:Use the given python version or path as base interpreter' + ) + + _arguments -C -A '-*' \ + $arguments \ + {-V,--version}'[Show the version and exit]' \ + '--pep582=[Print the command line to be eval by the shell]:shell:(zsh bash fish powershell cmd tcsh csh)' \ + '*:: :->_subcmds' \ + && return 0 + + if (( CURRENT == 1 )); then + _describe -t commands 'pdm subcommand' sub_commands + return + fi + + curcontext=${curcontext%:*}:$words[1] + + case $words[1] in + add) + arguments+=( + {-g+,--global+}'[Use the global project, accepts an optional path to the project directory]:project:_files' + {-d,--dev}'[Add packages into dev dependencies]' + {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' + '--no-sync[Only write pyproject.toml and do not sync the working set]' + '--save-compatible[Save compatible version specifiers]' + '--save-wildcard[Save wildcard version specifiers]' + '--save-exact[Save exact version specifiers]' + '--update-reuse[Reuse pinned versions already present in lock file if possible]' + '--update-eager[Try to update the packages and their dependencies recursively]' + {-e+,--editables}'[Specify editable packages]:packages' + '*:packages:_pdm_pip_packages' + ) + ;; + build) + arguments+=( + "--no-sdist[Don't build source tarballs]" + "--no-wheel[Don't build wheels]" + {-d+,--dest+}'[Target directory to put artifacts]:directory:_files -/' + '--no-clean[Do not clean the target directory]' + ) + ;; + cache) + local -a actions=("clear:Clean all the files under cache directory") + _describe -t command 'pdm cache actions' actions && return 0 + ;; + config) + _arguments \ + {-g+,--global+}'[Use the global project, accepts an optional path to the project directory]:directory:_files -/' \ + {-l,--local}"[Set config in the project's local configuration filie]" \ + {-d,--delete}'[Unset a configuration key]' \ + '1:key:->keys' \ + '2:value:_files' && return 0 + if [[ $state == keys ]]; then + local l mbegin mend match keys=() + for l in ${(f)"$(command pdm config)"}; do + if [[ $l == (#b)" "#(*)" = "(*) ]]; then + keys+=("$match[1]:$match[2]") + fi + done + _describe -t key "key" keys && return 0 + fi + ;; + export) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-f+,--format+}"[Specify the export file format]:format:(pipfile poetry flit requirements)" + "--without-hashes[Don't include artifact hashes]" + {-o+,--output+}"[Write output to the given file, or print to stdout if not given]:output file:_files" + {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' + {-d,--dev}"[Include dev dependencies]" + "--no-default[Don't include dependencies from default seciton]" + ) + ;; + import) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-f+,--format+}"[Specify the export file format]:format:(pipfile poetry flit requirements)" + '1:filename:_files' + ) + ;; + info) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + '--python[Show the interpreter path]' + '--where[Show the project root path]' + '--env[Show PEP 508 environment markers]' + ) + ;; + init|lock) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + ) + ;; + install) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' + {-d,--dev}"[Include dev dependencies]" + "--no-lock[Don't do lock if lockfile is not found or outdated]" + "--no-default[Don't include dependencies from default seciton]" + ) + ;; + list) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-r,--reverse}'[Reverse the dependency graph]' + '--graph[Display a graph of dependencies]' + ) + ;; + remove) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' + {-d,--dev}"[Include dev dependencies]" + "--no-sync[Only write pyproject.toml and do not uninstall packages]" + "*:packages:_pdm_packages" + ) + ;; + run) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-l,--list}'[Show all available scripts defined in pyproject.toml]' + {-s,--site-packages}'[Load site-packages from system interpreter]' + '(-)1:command: _command_names -e' + '*::arguments: _normal ' + ) + ;; + search) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + '1:query string:' + ) + ;; + show) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + '1:package:' + ) + ;; + sync) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' + {-d,--dev}"[Include dev dependencies]" + '--dry-run[Only prints actions without actually running them]' + '--clean[Clean unused packages]' + "--no-clean[Don't clean unused packages]" + ) + ;; + update) + arguments+=( + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' + '--save-compatible[Save compatible version specifiers]' + '--save-wildcard[Save wildcard version specifiers]' + '--save-exact[Save exact version specifiers]' + '--update-reuse[Reuse pinned versions already present in lock file if possible]' + '--update-eager[Try to update the packages and their dependencies recursively]' + {-u,--unconstrained}'[Ignore the version constraint of packages]' + {-d,--dev}'[Include dev dependencies]' + "--no-default[Don't include dependencies from default seciton]" + "*:packages:_pdm_packages" + ) + ;; + use) + arguments+=( + {-f,--first}'[Select the first matched interpreter]' + '*:python:_files' + ) + ;; + esac + + _arguments $arguments && ret=0 + + return ret +} + +_pdm_sections() { + if [[ ! -f pyproject.toml ]]; then + _message "not a pdm project" + return 1 + fi + local l mbegin mend match sections=() + while IFS= read -r l; do + if [[ $l == (#b)"["tool.pdm.(*)-dependencies"]" ]]; then + sections+=$match[1] + fi + done (.+)<.*/\1/p')) + done + _store_cache pdm_packages _pdm_packages + fi +} + +_pdm_pip_packages() { + if (( ! $+commands[curl] || ! $+commands[sed] )); then + _message "package name" + return 1 + fi + + local update_policy + zstyle ":completion:${curcontext%:}:" use-cache on + zstyle -s ":completion:${curcontext%:}:" cache-policy update_policy + if [[ -z $update_policy ]]; then + zstyle ":completion:${curcontext%:}:" cache-policy _pdm_caching_policy + fi + + local -a _pdm_packages + _pdm_pip_packages_update + compadd -X packages -a _pdm_packages +} + +_pdm "$@" diff --git a/news/188.feature b/news/188.feature new file mode 100644 index 0000000000..717a41a07f --- /dev/null +++ b/news/188.feature @@ -0,0 +1 @@ +Add zsh completion script From c6b863eac7647577c07e9b0e83d4dc3d349fb7d1 Mon Sep 17 00:00:00 2001 From: Aloxaf Date: Sat, 5 Dec 2020 18:31:32 +0800 Subject: [PATCH 2/9] Change the behavior of 'pdm completion zsh' --- pdm/cli/commands/completion.py | 12 +++-- {completion => pdm/cli/completions}/_pdm | 57 ++++++++++++++++++------ 2 files changed, 52 insertions(+), 17 deletions(-) rename {completion => pdm/cli/completions}/_pdm (86%) diff --git a/pdm/cli/commands/completion.py b/pdm/cli/commands/completion.py index 588872493c..5687c66d6c 100644 --- a/pdm/cli/commands/completion.py +++ b/pdm/cli/commands/completion.py @@ -1,4 +1,5 @@ import argparse +import pathlib from pdm.cli.commands.base import BaseCommand from pdm.project import Project @@ -21,7 +22,10 @@ def handle(self, project: Project, options: argparse.Namespace) -> None: import shellingham from pycomplete import Completer - completer = Completer(project.core.parser) - project.core.ui.echo( - completer.render(options.shell or shellingham.detect_shell()[0]) - ) + shell = options.shell or shellingham.detect_shell()[0] + if shell == "zsh": + zsh_completion = pathlib.Path(__file__).parent / "../completions/_pdm" + stream.echo(zsh_completion.read_text()) + else: + completer = Completer(project.core.parser) + stream.echo(completer.render(shell)) diff --git a/completion/_pdm b/pdm/cli/completions/_pdm similarity index 86% rename from completion/_pdm rename to pdm/cli/completions/_pdm index d75a5b439f..93b1a1b9d9 100644 --- a/completion/_pdm +++ b/pdm/cli/completions/_pdm @@ -12,6 +12,7 @@ _pdm() { local -a arguments=( {-h,--help}'[Show help message and exit]' {-v,--verbose}'[Show detailed output]' + {-p,--project}'=[Specify another path as the project root]:directory:_files -/' '-vv[Show more detailed output]' ) local sub_commands=( @@ -36,10 +37,11 @@ _pdm() { 'use:Use the given python version or path as base interpreter' ) - _arguments -C -A '-*' \ + _arguments -s -C -A '-*' \ $arguments \ {-V,--version}'[Show the version and exit]' \ - '--pep582=[Print the command line to be eval by the shell]:shell:(zsh bash fish powershell cmd tcsh csh)' \ + {-I,--ignore-python}'[Ignore the Python path saved in the pdm.toml config]' \ + '--pep582=[Print the command line to be eval by the shell]:shell:(zsh bash fish tcsh csh)' \ '*:: :->_subcmds' \ && return 0 @@ -75,11 +77,35 @@ _pdm() { ) ;; cache) - local -a actions=("clear:Clean all the files under cache directory") - _describe -t command 'pdm cache actions' actions && return 0 + _arguments -C \ + $arguments \ + ': :->command' \ + '*:: :->args' && ret=0 + case $state in + command) + local -a actions=( + "clear:Clean all the files under cache directory" + "remove:Remove files matching the given pattern" + "list:List the built wheels stored in the cache" + "info:Show the info and current size of caches" + ) + _describe -t command 'pdm cache actions' actions && ret=0 + ;; + args) + case $words[1] in + clear) + compadd -X type 'hashes' 'http' 'wheels' 'metadata' && ret=0 + ;; + *) + _message "pattern" && ret=0 + ;; + esac + ;; + esac + return $ret ;; config) - _arguments \ + _arguments -s \ {-g+,--global+}'[Use the global project, accepts an optional path to the project directory]:directory:_files -/' \ {-l,--local}"[Set config in the project's local configuration filie]" \ {-d,--delete}'[Unset a configuration key]' \ @@ -152,13 +178,18 @@ _pdm() { ) ;; run) - arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" - {-l,--list}'[Show all available scripts defined in pyproject.toml]' - {-s,--site-packages}'[Load site-packages from system interpreter]' - '(-)1:command: _command_names -e' - '*::arguments: _normal ' - ) + _arguments -s \ + {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" \ + {-l,--list}'[Show all available scripts defined in pyproject.toml]' \ + {-s,--site-packages}'[Load site-packages from system interpreter]' \ + '(-)1:command:->command' \ + '*:arguments: _normal ' && return 0 + if [[ $state == command ]]; then + _command_names -e + local local_commands=(__pypackages__/3.9/bin/*(N:t)) + _describe "local command" local_commands + return 0 + fi ;; search) arguments+=( @@ -205,7 +236,7 @@ _pdm() { ;; esac - _arguments $arguments && ret=0 + _arguments -s $arguments && ret=0 return ret } From ac7cba81699f8b04cd549e432d7bd0817f4c1a1c Mon Sep 17 00:00:00 2001 From: Frost Ming Date: Thu, 1 Apr 2021 13:38:33 +0800 Subject: [PATCH 3/9] change the location of completion scripts --- pdm.lock | 12 +-- pdm/cli/commands/completion.py | 18 ++-- pdm/cli/completions/__init__.py | 0 pdm/cli/completions/pdm.bash | 127 ++++++++++++++++++++++++++ pdm/cli/completions/pdm.fish | Bin 0 -> 39604 bytes pdm/cli/completions/pdm.ps1 | Bin 0 -> 7460 bytes pdm/cli/completions/{_pdm => pdm.zsh} | 0 pyproject.toml | 2 +- 8 files changed, 139 insertions(+), 20 deletions(-) create mode 100644 pdm/cli/completions/__init__.py create mode 100644 pdm/cli/completions/pdm.bash create mode 100644 pdm/cli/completions/pdm.fish create mode 100644 pdm/cli/completions/pdm.ps1 rename pdm/cli/completions/{_pdm => pdm.zsh} (100%) diff --git a/pdm.lock b/pdm.lock index 0907ace83a..e1bf205231 100644 --- a/pdm.lock +++ b/pdm.lock @@ -370,12 +370,6 @@ sections = ["test"] version = "1.10.0" summary = "library with cross-python path, ini-parsing, io, code, log facilities" -[[package]] -name = "pycomplete" -sections = ["default"] -version = "0.3.1" -summary = "A Python library to generate static completion scripts for your CLI app" - [[package]] name = "pycparser" sections = ["default"] @@ -651,7 +645,7 @@ summary = "Backport of pathlib-compatible object wrapper for zip files" [metadata] lock_version = "2" -content_hash = "sha256:fbe7d1276b7e0b9dc837a7bc67039bb678655a2a250bf816a60f3cdfb0c6c184" +content_hash = "sha256:d7a1b535fc534c81920b4cec1e68821f920dca5e2433679e558cdf7b1b83d1ad" [metadata.files] "apipkg 1.5" = [ @@ -989,10 +983,6 @@ content_hash = "sha256:fbe7d1276b7e0b9dc837a7bc67039bb678655a2a250bf816a60f3cdfb {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] -"pycomplete 0.3.1" = [ - {file = "pycomplete-0.3.1-py3-none-any.whl", hash = "sha256:1221dad380f3930455726847df6d5743c3c0c7e35c06436e1b1d16569a4792fb"}, - {file = "pycomplete-0.3.1.tar.gz", hash = "sha256:7f7532f7e0950e4e8c8017f89acb3f3e645cce1f164020ab9792fd5100c11211"}, -] "pycparser 2.20" = [ {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, diff --git a/pdm/cli/commands/completion.py b/pdm/cli/commands/completion.py index 5687c66d6c..e7380a3133 100644 --- a/pdm/cli/commands/completion.py +++ b/pdm/cli/commands/completion.py @@ -1,7 +1,8 @@ import argparse -import pathlib +import importlib.resources from pdm.cli.commands.base import BaseCommand +from pdm.exceptions import PdmUsageError from pdm.project import Project @@ -9,6 +10,7 @@ class Command(BaseCommand): """Generate completion scripts for the given shell""" arguments = [] + SUPPORTED_SHELLS = ("bash", "zsh", "fish", "powershell") def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( @@ -20,12 +22,12 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: def handle(self, project: Project, options: argparse.Namespace) -> None: import shellingham - from pycomplete import Completer shell = options.shell or shellingham.detect_shell()[0] - if shell == "zsh": - zsh_completion = pathlib.Path(__file__).parent / "../completions/_pdm" - stream.echo(zsh_completion.read_text()) - else: - completer = Completer(project.core.parser) - stream.echo(completer.render(shell)) + if shell not in self.SUPPORTED_SHELLS: + raise PdmUsageError(f"Unsupported shell: {shell}") + suffix = "ps1" if shell == "powershell" else shell + completion = importlib.resources.read_text( + "pdm.cli.completions", f"pdm.{suffix}" + ) + project.core.ui.echo(completion) diff --git a/pdm/cli/completions/__init__.py b/pdm/cli/completions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pdm/cli/completions/pdm.bash b/pdm/cli/completions/pdm.bash new file mode 100644 index 0000000000..d8c34d2191 --- /dev/null +++ b/pdm/cli/completions/pdm.bash @@ -0,0 +1,127 @@ +# BASH completion script for pdm +# Generated by pycomplete 0.3.1 + +_pdm_74498d98b6b27a5a_complete() +{ + local cur script coms opts com + COMPREPLY=() + _get_comp_words_by_ref -n : cur words + + # for an alias, get the real script behind it + if [[ $(type -t ${words[0]}) == "alias" ]]; then + script=$(alias ${words[0]} | sed -E "s/alias ${words[0]}='(.*)'/\\1/") + else + script=${words[0]} + fi + + # lookup for command + for word in ${words[@]:1}; do + if [[ $word != -* ]]; then + com=$word + break + fi + done + + # completing for an option + if [[ ${cur} == --* ]] ; then + opts="--help --ignore-python --pep582 --verbose --version" + + case "$com" in + + (add) + opts="--dev --editable --global --help --no-sync --project --save-compatible --save-exact --save-wildcard --section --update-eager --update-reuse --verbose" + ;; + + (build) + opts="--dest --help --no-clean --no-sdist --no-wheel --project --verbose" + ;; + + (cache) + opts="--help --verbose" +;; + +(completion) +opts="--help" +;; + +(config) +opts="--delete --global --help --local --project --verbose" +;; + +(export) +opts="--dev --format --global --help --no-default --output --project --pyproject --section --verbose --without-hashes" +;; + +(import) +opts="--dev --format --global --help --project --section --verbose" +;; + +(info) +opts="--env --global --help --project --python --verbose --where" +;; + +(init) +opts="--global --help --project --verbose" +;; + +(install) +opts="--dev --global --help --no-default --no-lock --project --section --verbose" +;; + +(list) +opts="--global --graph --help --project --reverse --verbose" +;; + +(lock) +opts="--global --help --project --verbose" +;; + +(remove) +opts="--dev --global --help --no-sync --project --section --verbose" +;; + +(run) +opts="--global --help --list --project --verbose" +;; + +(search) +opts="--global --help --project --verbose" +;; + +(show) +opts="--global --help --project --verbose" +;; + +(sync) +opts="--clean --dev --dry-run --global --help --no-clean --no-default --project --section --verbose" +;; + +(update) +opts="--dev --global --help --no-default --outdated --project --save-compatible --save-exact --save-wildcard --section --top --unconstrained --update-eager --update-reuse --verbose" +;; + +(use) +opts="--first --global --help --project --verbose" +;; + +esac + + COMPREPLY=($(compgen -W "${opts}" -- ${cur})) + __ltrim_colon_completions "$cur" + + return 0; + fi + + # completing for a command + if [[ $cur == $com ]]; then + coms="add build cache completion config export import info init install list lock remove run search show sync update use" + + COMPREPLY=($(compgen -W "${coms}" -- ${cur})) + __ltrim_colon_completions "$cur" + + return 0 + fi +} + +complete -o default -F _pdm_74498d98b6b27a5a_complete pdm + diff --git a/pdm/cli/completions/pdm.fish b/pdm/cli/completions/pdm.fish new file mode 100644 index 0000000000000000000000000000000000000000..debea5e94a099870eb04928ff9fa51894e878b88 GIT binary patch literal 39604 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 YI_>NF(xqRjG&?kXwel-d=0.6.0", "pep517", "pip>=20.1", - "pycomplete<1.0.0,>=0.2.0", + "python-cfonts", "python-dotenv<1.0.0,>=0.15.0", "pythonfinder", From 4ccde291de1d425a4830f40f8fc65d00f9b5ca97 Mon Sep 17 00:00:00 2001 From: Frost Ming Date: Thu, 1 Apr 2021 22:30:10 +0800 Subject: [PATCH 4/9] Update zsh script --- pdm/cli/completions/pdm.zsh | 75 +++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/pdm/cli/completions/pdm.zsh b/pdm/cli/completions/pdm.zsh index 93b1a1b9d9..562c48de67 100644 --- a/pdm/cli/completions/pdm.zsh +++ b/pdm/cli/completions/pdm.zsh @@ -12,8 +12,6 @@ _pdm() { local -a arguments=( {-h,--help}'[Show help message and exit]' {-v,--verbose}'[Show detailed output]' - {-p,--project}'=[Specify another path as the project root]:directory:_files -/' - '-vv[Show more detailed output]' ) local sub_commands=( 'add:Add package(s) to pyproject.toml and install them' @@ -55,7 +53,7 @@ _pdm() { case $words[1] in add) arguments+=( - {-g+,--global+}'[Use the global project, accepts an optional path to the project directory]:project:_files' + {-g,--global}'[Use the global project, supply the project root with `-p` option]' {-d,--dev}'[Add packages into dev dependencies]' {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' '--no-sync[Only write pyproject.toml and do not sync the working set]' @@ -64,7 +62,7 @@ _pdm() { '--save-exact[Save exact version specifiers]' '--update-reuse[Reuse pinned versions already present in lock file if possible]' '--update-eager[Try to update the packages and their dependencies recursively]' - {-e+,--editables}'[Specify editable packages]:packages' + {-e+,--editable+}'[Specify editable packages]:packages' '*:packages:_pdm_pip_packages' ) ;; @@ -106,7 +104,7 @@ _pdm() { ;; config) _arguments -s \ - {-g+,--global+}'[Use the global project, accepts an optional path to the project directory]:directory:_files -/' \ + {-g,--global}'[Use the global project, supply the project root with `-p` option]' \ {-l,--local}"[Set config in the project's local configuration filie]" \ {-d,--delete}'[Unset a configuration key]' \ '1:key:->keys' \ @@ -123,25 +121,25 @@ _pdm() { ;; export) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" - {-f+,--format+}"[Specify the export file format]:format:(pipfile poetry flit requirements)" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' + {-f+,--format+}"[Specify the export file format]:format:(pipfile poetry flit requirements setuppy)" "--without-hashes[Don't include artifact hashes]" {-o+,--output+}"[Write output to the given file, or print to stdout if not given]:output file:_files" - {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' - {-d,--dev}"[Include dev dependencies]" + {-s+,--section+}'[(MULTIPLE) Specify section(s) of optional-dependencies or dev-dependencies(with -d)]:section:_pdm_sections' + {-d,--dev}"[Select dev dependencies]" "--no-default[Don't include dependencies from default seciton]" ) ;; import) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" - {-f+,--format+}"[Specify the export file format]:format:(pipfile poetry flit requirements)" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' + {-f+,--format+}"[Specify the file format explicitly]:format:(pipfile poetry flit requirements)" '1:filename:_files' ) ;; info) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' '--python[Show the interpreter path]' '--where[Show the project root path]' '--env[Show PEP 508 environment markers]' @@ -149,37 +147,38 @@ _pdm() { ;; init|lock) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' + {-n,--non-interactive}"Don't ask questions but use default values" ) ;; install) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" - {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' - {-d,--dev}"[Include dev dependencies]" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' + {-s+,--section+}'[(MULTIPLE) Specify section(s) of optional-dependencies or dev-dependencies(with -d)]:section:_pdm_sections' + {-d,--dev}"[Select dev dependencies]" "--no-lock[Don't do lock if lockfile is not found or outdated]" "--no-default[Don't include dependencies from default seciton]" ) ;; list) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' {-r,--reverse}'[Reverse the dependency graph]' '--graph[Display a graph of dependencies]' ) ;; remove) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" - {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' - {-d,--dev}"[Include dev dependencies]" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' + {-s+,--section+}'[Specify the section the package belongs to]:section:_pdm_sections' + {-d,--dev}"[Remove packages from dev dependencies]" "--no-sync[Only write pyproject.toml and do not uninstall packages]" "*:packages:_pdm_packages" ) ;; run) _arguments -s \ - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" \ + {-g,--global}'[Use the global project, supply the project root with `-p` option]' \ {-l,--list}'[Show all available scripts defined in pyproject.toml]' \ {-s,--site-packages}'[Load site-packages from system interpreter]' \ '(-)1:command:->command' \ @@ -193,38 +192,41 @@ _pdm() { ;; search) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" '1:query string:' ) ;; show) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' '1:package:' ) ;; sync) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" - {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' - {-d,--dev}"[Include dev dependencies]" + {-g,--global}'[Use the global project, supply the project root with `-p` option]' + {-s+,--section+}'[(MULTIPLE) Specify section(s) of optional-dependencies or dev-dependencies(with -d)]:section:_pdm_sections' + {-d,--dev}"[Select dev dependencies]" '--dry-run[Only prints actions without actually running them]' '--clean[Clean unused packages]' "--no-clean[Don't clean unused packages]" + "--no-default[Don't include dependencies from default seciton]" ) ;; update) arguments+=( - {-g+,--global+}"[Use the global project, accepts an optional path to the project directory]:directory:_files -/" - {-s+,--section+}'[Specify target section to add into]:section:_pdm_sections' + {-g,--global}'[Use the global project, supply the project root with `-p` option]' + {-s+,--section+}'[(MULTIPLE) Specify section(s) of optional-dependencies or dev-dependencies(with -d)]:section:_pdm_sections' '--save-compatible[Save compatible version specifiers]' '--save-wildcard[Save wildcard version specifiers]' '--save-exact[Save exact version specifiers]' '--update-reuse[Reuse pinned versions already present in lock file if possible]' '--update-eager[Try to update the packages and their dependencies recursively]' {-u,--unconstrained}'[Ignore the version constraint of packages]' - {-d,--dev}'[Include dev dependencies]' + {-d,--dev}'[Select dev dependencies]' "--no-default[Don't include dependencies from default seciton]" + {-t,--top}'[Only update those list in pyproject.toml]' + "--dry-run[Show the difference only without modifying the lockfile content]" + "--outdated[Show the difference only without modifying the lockfile content]" "*:packages:_pdm_packages" ) ;; @@ -246,11 +248,18 @@ _pdm_sections() { _message "not a pdm project" return 1 fi - local l mbegin mend match sections=() + local l match sections=() in_sections=0 while IFS= read -r l; do - if [[ $l == (#b)"["tool.pdm.(*)-dependencies"]" ]]; then - sections+=$match[1] - fi + case $l in + "["project.optional-dependencies"]") in_sections=1 ;; + "["tool.pdm.dev-dependencies"]") in_sections=1 ;; + "["*"]") in_sections=0 ;; + *"= [") + if (( in_sections )); then + sections+=$l[(w)1] + fi + ;; + esac done Date: Thu, 1 Apr 2021 22:49:26 +0800 Subject: [PATCH 5/9] change to what is configured index --- pdm/cli/completions/pdm.fish | Bin 39604 -> 39192 bytes pdm/cli/completions/pdm.zsh | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pdm/cli/completions/pdm.fish b/pdm/cli/completions/pdm.fish index debea5e94a099870eb04928ff9fa51894e878b88..3d88bdb867df5d190004706524aff53a4ccac773 100644 GIT binary patch delta 1761 zcmY*ZT}Yc(7(QR>TFqJ;Gk?aP0}>c zP^8;*ZSoWeyO3&chm@up?55aW^kT>m){9cc7*2LEyjdwy#wdHw`+fP662kMG_q>1S zIp_WE|6s`9Gu-UXp0_E+>{oGAC^mQu=7LM9REV_81#TPm9yE$(?KdhWg%3X&8mo+g zxiI2SLo2%X<#BtDgK?o^f$`oO3BqOc4@3#K6(iD(bxH*1_O)Twl)zS{v>#=@TQ#Wj z9peR^KY25y^XL0N)A`PU8I31VanP^v6wIb#>=WJgvSwJ1dtr|0e1C19%4?r$n8d$z zrJkxAin$WlZMdk%ZCSJ&hqSmu6!-QlpRetJQ5Z!lspS?vQp$Zej*g~5cn-&M@AOH) zZ(Vu9pP5_Vuf*DsYs|lI-bU`-zv!RAe=Yrto2|oy38aSV(LZ6v=Fv{}O|>m+SdG26 za?I}@OVkvLd&IOD7eQ*^-0@%0eLRUKhXaq=GZ<@k5pFWCKXI1#HcxCb_70RXcDtskBi&J$_WgM2K>PMHCOMX-s}%Lde;HM^^GXe-a;cy~kXtCvDaqIuGIF zGc#3Dsw%4=uzta!1`H%FV44y@XP%sW2K>s($-(Jo~v z@^D|T&Slf8-St}jagu7qeuX7owQrD50&0$gl(w$Cmxzecg$6|sE6zE5?z9zFofZYF z&RKpLIoCWk&V))z7P78A>NaO2Hz}cXe=uA+WsroY%y5rf#qV89@QnO|)0Z{~)lMWn zb31rV9qHW%>AJikKyd;5=rgG!G2$ogAzz6mK1q>NtbSc#`tD3n{0u$KY$$;BKrQ~B zH=%y)B61-=uldR}E)_1?H~iN%{!+K8H#w-Usg^#&VH%@JsuJf8bD z%`2HkBBkac)SR2%FilS3pGbp(=aCc(EKw>c@xkSi5)m4)DRCL@xO$JCIH?!c)FUic zEh6Ids=TO4T|wFnsi88Om*GEoz-un7G-dX!*oA5fC7JYEZtmca-a=x Bio5^- delta 2139 zcmZWqUu=_A6#rT!j$v`Izol3@XHg(QYK&-5urral&FKIYQD(obo7A>z({-a|W8Fjs zF08a1V-~Um`qqbK5vqjj!KB7F3ECGz;?oinAB@JuEHOb7&+p#*bze)GG{1B1x##}w z@1AqM`J2{nzO`oBEw-%JyTPW_YPRgTBwG)>7F*$f#bL47=w0g`{!dx$uOh&ueuLVu z=GV-gm^P@zwNWj`D=uxHSX+;>(T~#yJ((84Cpp7vij*3+J1t{*A%Zx~etpX3N6PX<~%4C#UR zoJO;}0U>UL*%!OU>B^f>5~!~e`GBHb>?;(zK8D=IuCui8R)-PP1JVdO@^d|R+TY;)xL->xP9)O%5 za93Tn81X88LXwuJA*tb^k#2B_=E~PQiFWF#E zIBznZKRdI&BGqC#2$RK#ltPsb1pA8k?-@_iYFW8p7e8R z#^s2c!IObdiIF5wnkliJyRcSq64sqxTvd_s>56mH)Hhe7Cca_Gi7zdtUMS8T!UG|} z<%NSx(r6S%rTBz=aZEFQhf0kNv`lorGO->*7?6{jCTAV D0^o Date: Fri, 2 Apr 2021 14:23:33 +0800 Subject: [PATCH 6/9] get package names with python script --- pdm/cli/commands/completion.py | 3 ++- pdm/cli/completions/pdm.zsh | 32 ++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/pdm/cli/commands/completion.py b/pdm/cli/commands/completion.py index e7380a3133..793f7d1d25 100644 --- a/pdm/cli/commands/completion.py +++ b/pdm/cli/commands/completion.py @@ -1,5 +1,6 @@ import argparse import importlib.resources +import sys from pdm.cli.commands.base import BaseCommand from pdm.exceptions import PdmUsageError @@ -30,4 +31,4 @@ def handle(self, project: Project, options: argparse.Namespace) -> None: completion = importlib.resources.read_text( "pdm.cli.completions", f"pdm.{suffix}" ) - project.core.ui.echo(completion) + project.core.ui.echo(completion.replace("%{python_executable}", sys.executable)) diff --git a/pdm/cli/completions/pdm.zsh b/pdm/cli/completions/pdm.zsh index 371557cda3..2a1e5d792a 100644 --- a/pdm/cli/completions/pdm.zsh +++ b/pdm/cli/completions/pdm.zsh @@ -1,6 +1,7 @@ #compdef pdm PDM_PIP_INDEXES=($(command pdm config pypi.url)) +PYTHON="%{python_executable}" _pdm() { emulate -L zsh -o extended_glob @@ -264,23 +265,30 @@ _pdm_sections() { compadd -X sections -a sections } +_get_packages_with_python() { + command ${PYTHON} - << EOF +import os, re, toml +PACKAGE_REGEX = re.compile(r'^[A-Za-z][A-Za-z0-9._-]*') +def get_packages(lines): + return [PACKAGE_REGEX.match(line).group() for line in lines] + +with open('pyproject.toml', encoding='utf8') as f: + data = toml.load(f) +packages = get_packages(data.get('project', {}).get('dependencies', [])) +for reqs in data.get('project', {}).get('optional-dependencies', {}).values(): + packages.extend(get_packages(reqs)) +for reqs in data.get('tool', {}).get('pdm', {}).get('dev-dependencies', {}).values(): + packages.extend(get_packages(reqs)) +print(*set(packages)) +EOF +} + _pdm_packages() { if [[ ! -f pyproject.toml ]]; then _message "not a pdm project" return 1 fi - local l packages=() in_dependencies=0 - while IFS= read -r l; do - case $l in - "["tool.pdm.*dependencies"]") in_dependencies=1 ;; - "["*"]") in_dependencies=0 ;; - *"="*) - if (( in_dependencies )); then - packages+=$l[(w)1] - fi - ;; - esac - done Date: Fri, 2 Apr 2021 14:30:59 +0800 Subject: [PATCH 7/9] use python to call pdm --- pdm/cli/completions/pdm.zsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdm/cli/completions/pdm.zsh b/pdm/cli/completions/pdm.zsh index 2a1e5d792a..91e9a2666d 100644 --- a/pdm/cli/completions/pdm.zsh +++ b/pdm/cli/completions/pdm.zsh @@ -1,7 +1,7 @@ #compdef pdm -PDM_PIP_INDEXES=($(command pdm config pypi.url)) PYTHON="%{python_executable}" +PDM_PIP_INDEXES=($(command ${PYTHON} -m pdm config pypi.url)) _pdm() { emulate -L zsh -o extended_glob @@ -112,7 +112,7 @@ _pdm() { '2:value:_files' && return 0 if [[ $state == keys ]]; then local l mbegin mend match keys=() - for l in ${(f)"$(command pdm config)"}; do + for l in ${(f)"$(command ${PYTHON} -m pdm config)"}; do if [[ $l == (#b)" "#(*)" = "(*) ]]; then keys+=("$match[1]:$match[2]") fi From b15bbc0341da470974e099fba03d38c14450443f Mon Sep 17 00:00:00 2001 From: Frost Ming Date: Fri, 2 Apr 2021 22:46:30 +0800 Subject: [PATCH 8/9] add for powershell --- pdm/cli/completions/pdm.bash | 4 ++-- pdm/cli/completions/pdm.fish | Bin 39192 -> 19858 bytes pdm/cli/completions/pdm.ps1 | Bin 7460 -> 8866 bytes pdm/cli/completions/pdm.zsh | 6 +++--- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pdm/cli/completions/pdm.bash b/pdm/cli/completions/pdm.bash index d8c34d2191..718de5e1ff 100644 --- a/pdm/cli/completions/pdm.bash +++ b/pdm/cli/completions/pdm.bash @@ -61,7 +61,7 @@ opts="--env --global --help --project --python --verbose --where" ;; (init) -opts="--global --help --project --verbose" +opts="--global --help --project --verbose --non-interactive" ;; (install) @@ -97,7 +97,7 @@ opts="--clean --dev --dry-run --global --help --no-clean --no-default --project ;; (update) -opts="--dev --global --help --no-default --outdated --project --save-compatible --save-exact --save-wildcard --section --top --unconstrained --update-eager --update-reuse --verbose" +opts="--dev --global --help --no-default --dry-run --outdated --project --save-compatible --save-exact --save-wildcard --section --top --unconstrained --update-eager --update-reuse --verbose" ;; (use) diff --git a/pdm/cli/completions/pdm.fish b/pdm/cli/completions/pdm.fish index 3d88bdb867df5d190004706524aff53a4ccac773..d854659031aebbf7d506867423b3b9f1e47d7434 100644 GIT binary patch literal 19858 zcmdU1ZEqVl68`RAL7)dX0kVO6ha~;lHn}?kDbBDH+?N0+m2>eHaw9u7!7Dh{5DUq2vf6kxNGkOILt48X|i7XR;(Lxqbr`2U4a+z;b zIsrVn(rcl9tBq}h-ufTa%0P(5K;;@)mZH?I5v9rRg;iU#Q^K~GyplHG2)8j0!tJYE zv~_{0i`J=58B)lqrnQy$z8h3wHt}b8;Oc?~V8nH4ma-J4CR4eKXb+L)WMz?6;_}<= zcPX+`Y*bl`tPq#1bhFXU4{eoma;*gH3|r{ta!R3kT^Xygdf#jS8Ipd@Bcj1t-1yO2 zHn61J0XSG)`T#S1*_drfi-{$gRHIteuYUL|t8!y?)v&;TD6BOg)fll5{Qb zDmj?1oK%sWvPGIaF}w=}=$5d9X`8xjcuBII|7;68iul0Pia2uU1RF{~J09#& z0dNL0Jp#+saAZpMQ4;(&a;0hxQKC^^}t!&)XYZ8JGX>#r3QNX|0f*KHEq*z(AommMAfuzD6MK>}*`v*@}N<4_1RoNPKgR+-YF~r<8mJAp|(eq^z|6`h>Ii;$k zz*?}M;We%l3bkXkl6=gOScCj?hyQzKd<2e97o!T@$YtqGa968bulAxFjJ`HXM5v~C zd83VeffYj93*p+jE`72Q!<;py@wodntA7o(*eE?l)Lu`wXJxX^v;I|KP7hY2Bt3*M zGkRe}g(>pWgu6eEC{NcQ8jyWEEU1Je%9tXCNnU)84E;hpY&1&gd?TwhVl92nI7im| zi0X?420cZ&#bVT=P|2CWd!U)_V2Cl!fWugHLdUbwD2m35RKKC5@T5!9{6FUq^nkWU zE^X1v>PDs(hY~H8kkOMHY1c@ZUHAy>0e)c`8D&Dx*qK6+XnA5EEWFpm1`NY1;DfP_ z0c{UR3r!gW8i!h@+)ts3RguSU`L|kE6|%NqVkcy2l`PN_v&vB|gRs)&lGL%PjdKLR zQMy3dh;9O62G_nrq6WVh;s)|p^8F8f=?e`@H^#3I_cLNWJ!q=Epjqj(7Xw1gOC^1J z_||i#A0U(ke0P%^IVWQ8f(igK;9FCDx@?cV;zNpp@%ec)kIxr0m%@Iqnd zA|%`ub#vrlTS?rjVeuezsY%AM6V61HSxGXH<4a@qci7Z_KrxOZvG3k~x^$s}_8*5n z9#wRDSlCPCp9kY43Xk?f->)3v4gSr8BJU1ffpm0|$}aiyzInhwrb`GBH2o7?%7-56 zps<+;I=06ps?6$fi5#Q~g<8qBJV+LFm6vTndqjPG?mL(9;gE`twRqT^B9H$!SD0Y{ zNjUkuZ(>lh<^{FUYQM>5glh^sNC_|1p8V8UP0qvhla=cVT6T>0P`vf}yJ zr5s0!RK@$?9=6H9$uu+vKr`D&Y;ED-K%am|pNboS!au@&H@{aigoXW^2P_;memVe5 z*KJFL{SGISs|GSAelB&cn}L;aBJ9|_oTxG@FDG)&gN_n~Q%;CP@MYV^zc9RWlL#E= zVA!WafmewBd{_c5m|al@&M6Y+q4t}{D9FX$M>XKHlF=iQSeOUHI5 z523WApPbL)bSssaE7Rfx3knzH_jEwFcsY>Rdjp&c5%e0TY2K-ne(92q<0@o@R6h?P z3wrM)Jh@lI%6j7|Gn|5yV$EZy%F|+e5R5x9v$91ex`Roz-fq5HY(Z@gN#XR5%a6NEA-fn66s|evae3;TTS@ zE>&r&HBOV6v1S_Yk8L%`8Qbb4*c!LpSdV!mgcH1X z8Yqd1%!`pIe7KoU>MzwqP-YVLmWDZgR)Yn>$0y>sfIvku&#L2_~HZ zGRJ6ec9uL7_J~UoQ*ZKsQ|T;rwj51u{;I(ca`SJ_#z4uRKQ;#>s?5p)iJW6NXd=FN z3hRd>MPh3Z5B79hm#WilcLJwD8yq$mME{8@aZ}@uBha6t%Xu(YV!S```q$@D=ez;- zxvcKW7iTGS;j9}0LGpKexN(=;Qi;huuv3W#iF%Fk-+;p%H$M))q%UFN#=}$Y`+ogk zVImLTc!Ztq#^U>kkkQftB;S4$t=~P;(8W3cdN6b-jqw!8J`*8 zYn}$2(m`RvIl)TX*yr-6?*!kVtL9W~pEO+I&uV|Izjbr0HfQ=}(Y$LuwXHrCS3T3w&zsMh z-|O$UI{%5T_(5l%BzJtD!NOFV^jdF!E8$i~xz(|6)I zqqS(|!&+Ub{jFZd&AC1yQ}E2>f)Rf@T1qd}V`e0yxD>^o)LUc1qNt;FcJ2W0< zZC9e1Gm*sOR%W5!<}SxM!^ZS8wFA?T`*aqKmq#o0ekFYSviY6*>|8k%&!CT4>lB(a zJD%CR28C$>0=#QKpNT)r{J%>s40*t1zXo#}>AM`U)PPBAQFEiwhC1iTQj~>0I@NE6 zx@a#by%EyfiI@D3S;ATAd7vKhxX?NI6~-$g#*y25WDAZ2Li_lZEo)d|$eByic4&#d z>mM_Z+tD;V>ay^aMvpNE8PI5kjn5=8&vn%119-F2Sl=}N&`4u%r0C$BVV0%Z(l~jw z<@^|qBdJBnSvIJ)qC%b`2bn9d!u2*4Pw<2rM@8895pspaG}|54)$PBPA* zzR!ec3*|Sht#;VFYW_O*frWIfe(Cz9>8UQmfnfU|B_^9xpmS&L(r{M-j{y1&jm10Pwp@=Yt|2#F-1 zRn4xzYPh+dG5C1q8DU|77h~s1?g=?h4l@5J$Nze)n`U>qx5My-;@7$K6aAiw-pixy&Y3sT z@DYR0QO_eFrthYVdX`%V)O*uv<X~)|H5s@{X2-S7fo) z;wyT_K7$RlNEs-bXBn)OWqP*BIeevi)}v_j2dk}~!6HXNlmlPI?iM)(P@5>H%Sb&w z2Hi$2o}Zud%WQ(jpau=ZtUcB!VV?$FN3C^>Rr|j6^t&zd`LL}Q`xsQ@xhWr+t{kIx zJ%g2dX}=NW)np)WPYt>YDL|)8R6k(if1{O_cp%q zj97h%hL#O=U!ZJPYC>Y9WI{ks;sR@Na12xu-Gu+(SICjmmi{^wia=qiJ;*|=^xNGkx`tU?_2?XSr+GAFd65J3$XK{S?@D|8b#iQ_K40r)v9?@_!Du25 zT!T@ElVCmQ?RgpVRw7E}{u%N?u8Ha=DqtJ|hvSRUHcV}T`5BS-?aSAQJLdj|#b0BV zq_ZCToiS$S!EvJ zTJ7HV*$Y5Asb=0jrV|nyI6J()i8`9T^iA9`_%K~`u2D0FQSDa#_cy-Xdq3_-M;zCy zfBK}=?-?`_amACj_>g1f8)+}l0_}CIzs=Q33+1ZMdi4*|z62fn9^tHWWy)9;^>H!E z=9gL4*k$$TUQSaEm^YvL#KiEt_Lh2de8Kc;>DhTbp6BR@QuSw_rTq!|XB&r%)3Vt` z6uHjf;q_r!U)h&#Nbeca=2^LPrlBh=I_kd;pR=p?KCL_mPp0$++|x|2;WHi&Exk&A zvp?-kjK{v~xH?y+tK;hQSX6;o#d?Vk(o$(IBKO3JRuVV)plBx2x@j&V$DXe*uZ*1+ zQSqT=JYPBG$n!V#-gB6F3yb0VEKVyiJaS9c&g(AHm2AYGh}xXC5gB-F5njs?E|fL! zRS84$WY+q-)B5!}*Uiv|#vr>uwjiv@r~&r;Zl1ACXIuBmvGQwZxyomLQ2b0QlioDn zG~cOG@lfwyw=3C7&6%I=)n3Mtw8{f(oq4>e8rTo+7HBt_Wm}IW=(Ta*HEd zoFrXW)0Zur-ZN}3lh2?pZ3W*;1Q=s&TiWNKEVXchzH+v^hIOr)TgJXK1jtBD$DQVU zpE=_?W&3U~*SRuXd$~@}Y#r?m@#`GUHT^>vk!EYlv&>RY?=VEoO?v;pz#(EkUzz%e5+I3)7}Q@3uSths5)Ke6udiR*6HU zTdJYEYxL4gSh`xnDzk+#M1F13!qc z69K&J6-DB%fhA=G=SWC7#%v~YzSjTQrmgd3+K5;i>3zunZjyAPKh|Kl4VuT4$=i7i z4=d>{d*^3GoRaF-s4~Y-WX}rQrID2|7RUBg?5En9uV2fxCIPc%+^uG;@wkjnxs=V> zuT#~EN4>zNSvtIZ;d$7;{1d-l*cAJ&lWQDdFT<7m|L{Uz37c-_#KC1m`h&pBaZu{1`GF_Cc(_^ui*aOPFZZL}T+1!S{Wf_=Hy2yo-LHb2_Ja)(yMV4LNUzM@sYzRgLWR z*cV==_ncAFBNBD4Ocy)r^vr0oJ2a_tcnp|gReAm4iQR9;lE9LZBU8qal9m}mc8MV+ zcgKJqw%d1q_+j@8{7Cm|^oUS;3@grdY3)84v(J43J#G~}_o%A(`bhTO7^?tlJ!kLI zrEF2STl26y2Eu-n@AaZKpS3x**Ca6z+Y#QMH%bLn>{7{Yz-yhwdTizot;k8*ZrDHP znQXgQd)%de-=hXyj!ao+m55?-<`hGGhUQY5wiqwU>`Mh_S0-oMW0$r^IZN-+~PTy$t10KSsHp6l*8{eln7f5^VDIt- z%5(wVJ+T=(HGO(>KYPMh#wDnlJ>`6qr|cu=l+1q6 NF8!dKx5HxL{{Zc^u4DiJ diff --git a/pdm/cli/completions/pdm.ps1 b/pdm/cli/completions/pdm.ps1 index e28ab0bb44975ecbfc30b75b14ac088cbdf6f6bf..b5f7289e0ee8ecf428fc7476f9c1b90020340006 100644 GIT binary patch literal 8866 zcmdT~TaVke5`OouAQYpKlgMcMxCaH&HZ2+yZ5G{ag9ERd(h_Z}D@!U#@1;5W-_Kk~ ziL|wjn>HJCA66F*hjaO6I2`$rIBl+#HfvQ?B5yWrrEJ;M!sNPatynf%w8dsLDwiTn z&y}&+skCeH?Y7R5?&RWJF21>GWo_VTA~IPQBC8uK28rJQuQzTL^_9#ox9wyi-i`$P z{iJHSQQ1qYHuta>1Jg%$qtW>E#Sd>z|9k%3s~^P|B6)Fg@w(BMrj@z6fCVqERDE@E zMhcmW_SUYOda7ii z+O5=b<6O=wjyK!NmJk(a>Rv48H*yjB6h@z?6Xw`0(Mjo*=%M9lyeEhe`Xa`Tx@lEz zL1A1S_3Lal2IN|Rd4VG|ah82H?}tf~pN*pNUT!pe?_!)sK4u1=PN&)D^U$)>HFwBR^$radN*#yKS7vXEAJXnMIwaSxt%nYxDx8mP+#@DSnD^A1;i3f@6mzVaE* z6ZNL(@4P_>;~c{srgkk7E&^+GbkiWg2{#<=!JgF{`W=e~(>ura>-mJ#`yfJR z0Pik}C*p2GoP4VA2|~|>EDAJYx|4HYzm1&G$AWOSM~Y57FBFP?V5L*afKggvGd&YC z%82_3F|-v6;S3Aj;k!d4-y}BuwfOkkwZ%<#I zLYW~~>L~JJ^B1VUZt7*Z`d;1ktiwX!5(Yp+lnUWEh7<_o@Fq<@5n;)aZLq|`6ba)A zQ}=;am9V2>BKb}KR>#?qV;d)A8{Fr`WAP-tFi$7q$rq19H<3UjAVP)G zr82W%|6nllfA0~b-!-tSs@~;_ut-eDsM0eLV4o{5dhu1&wLuLJ( z$Fu+aXa0DCTix_rmm3NtzwdULjd?f|B)_6@lTdr!FA;s12Z?&h%S>jU!5$dc0c^h6 zKq{r;jdsZ}l&R9K%1b4Z>`CH7*m;}g;Ubs zhQI;X57)^vSS^Eky`{S=e!fzA(HI4Im@tA!3d5lS=>q}=SK>Rz?K!YBJlzq(^l4Cu zK2L*i3;DLX`5jmv;LE~gj&P4}$PBO!Xg$Dd$uctC9;?Ja#oM;GNTk&t+fu8Isx2wj zHp*%mSpte+DpzP|o3rZ@BLt(0JcR)1k`NLk;Df}SP4LV@0S5?@6~A9q z%|cduUpJY#t#h!%vwKAzN2obK7op&Oy4VB=I;W*7N-I(40n~+=I{-^)T9^ecavK&w z^}wWlcSaV;VhhFv?^1MfAO_ytm$>tqapng@=9Q9lZ`Ps=#;(^&RcK|{0>fB=Vs=N8 z98Ozm5NBq)fW&~=C(0s0cJkIR9?SidFyDDH(j2AML+g2}7~h?F6HkSH5$5^qUVWgUGQFIGwSW=#*`g4%@tv>Sy$10GQGf1V-^x4|XA@*SQ3%8^DliK?w$w9R5;BN;w<>td1_6TGCt4xN`ecaAH z=#ak#PiQXgg_7HOx!1^}kUq7GIcQAMi39^{Pyozo@xC!g_733GQ1LvJ6$VRM zsQO6!*x(Noupbglp)J)Nua%B0Of5V-NK>~5Zn)WkH+*P@J9lt}J9pB;JJ%j4v4o~) zt}Ee|ayMSFwt%bKi}4O(7%ncu;vJ?`ykf%*t}eFljvBR*7JVG{cfrXS8bQ>h;t%d- zHj`S*Tj=AytP6GXYU$oXyUCeoBAyEFWphV{x%%&HLqFsg_;E$pM0zB?h0lG#k%%N2{U7=yz8nAm literal 7460 zcmdT}+iu%N5S?d#1tA+qT$D!Bpmvd>K#`&;3IuJ?1js|$8j3{8NouQGbv;tOF6>*7*{4Ew4O+b=R#KU25&R8 zF44ZgTZy(zCTLyYUdk9_w}jMw#`u||HpG|$J(;|gb2sX|LbX8aSF$G$@q2*zTcA8a z+kIRwFn0+GIrt-`BeXw}Q_vpaP5F5we_-4Y^na2M;9`j0<+^Vd<8#+S4s!I&F^{yn zQa)VEbtng*a{x{Y*_Us?;Xa=CA=v?bBRn0})gZW3;7P??qP*j(A@((?}1NZ@&q$i z;A7!t?gskaK`SYeN1{qs{sHs{YaI?i&)X*)ujr$N7LZqG4jgCXu1YtTw~&sS$-v`< z<8v3Qc-n^WW{u>Kf@mK(ybt8BXpJf_bo%P5VBRQnf$XJ30BA#;Q z;B5-+G6qshC88X8Wuy#8mFO)IH@=mxqxSb`UqG{Shstn<_E;o~v1y#z{W)Scb)<-) zg*9@U0#o z=FrDEbU2Dem(bPxGYUicOHii9^0nm51GIIW6F-vCh7o!dt>OEr(__dq!l;GQiMKjq zh|fVGCye%Ew>r5g@Wi;bh}MY55ILs_`+H>2hK$i>snmS{nNQc8ce5fhY$!q6CL?E8 zMw4*7*^Ab%($c;&=Q-R}g!9tYta?Rv*=Z|!0nyin;3he*vT_)2bZ^p!hdwegx=f($ zX$L9kr@DXJ+#@wxSAF*;>_?w0;p5ET?b@ryAl;2>{tU6!KmL&R1ZX;i_G15-qiqE) z`5&&4)(5jfx;Gt5s%Z4_N8>&747p%tVn!#Tm*A;8mbhcOYkgmbX8K4>-;8)(Z!FhN3JUW{cOU_!3e_~(H6Pue&0s|%}Hth)_yyo zbo21;KHOa^JgsOxZPQ0e`YA9ognu7Fr#^Nx<-Igoi8{3`Wen+TZf~#KO(p9m!{(e) z`V&M8Qn(#l_TBfU_MuminH83HX;Y|cvW>^G$6*?CoAXYLa<|Ss;PpyyGu$$RpZza5 zwbNLe$2Ol4>JfVkE1hHKvcL`|K2P+)mB#AkHQVBR+M+iR&BHTaJ2LC~>aUe_hSOc6 zol<$)@8XsIWNdZeyEuF^&mMyfw-JH$soZsd}Jl(MtAD=M# zU?7d|RCH~xEyReT43||TF6#?xY~3r3VU5w(POWNaHOIOfO`PylOg~RoAz9ljh;ICCUX z&sym1U^e6`#Bde6xBoSZzF*fEasLFdSHB*z+RN`>ti1DE2vMac8ph@+TC`TIJ@J>j YI_>NF(xqRjG&?kXwel-d Date: Sat, 3 Apr 2021 10:08:16 +0800 Subject: [PATCH 9/9] Complete powershell script --- news/367.feature.md | 1 + pdm/cli/completions/pdm.ps1 | 206 +++++++++++++++++++++++++----------- 2 files changed, 148 insertions(+), 59 deletions(-) create mode 100644 news/367.feature.md diff --git a/news/367.feature.md b/news/367.feature.md new file mode 100644 index 0000000000..c5023f188a --- /dev/null +++ b/news/367.feature.md @@ -0,0 +1 @@ +Full-featured completion scripts for Zsh and Powershell - section selection, package name autocompletion and so on. Windows is a first-class citizen! diff --git a/pdm/cli/completions/pdm.ps1 b/pdm/cli/completions/pdm.ps1 index b5f7289e0e..2a181af8bf 100644 --- a/pdm/cli/completions/pdm.ps1 +++ b/pdm/cli/completions/pdm.ps1 @@ -4,7 +4,8 @@ if ((Test-Path Function:\TabExpansion) -and -not (Test-Path Function:\_pdm_compl Rename-Item Function:\TabExpansion _pdm_completeBackup } -$PDM_PYTHON = "D:\Workspace\pdm\venv\Scripts\python.exe" +$PDM_PYTHON = "%{python_executable}" +$PDM_PIP_INDEX = (& $PDM_PYTHON -m pdm config pypi.url).Trim() class Option { [string[]] $Opts @@ -14,7 +15,7 @@ class Option { $this.Opts = $opts } - [Option] WithValues([string []] $values) { + [Option] WithValues([string[]] $values) { $this.Values = $values return $this } @@ -46,19 +47,21 @@ class Completer { $expectArg = $null $lastWord = $words[-1] $paramUsed = $false - foreach ($word in $words[0..-2]) { - if ($expectArg) { - $expectArg = $null - continue - } - if ($word.StartsWith("-")) { - $opt = $this.opts.Where( { $_.Match($word) })[0] - if ($null -ne $opt -and $opt.TakesArg()) { - $expectArg = $opt + if ($words.Length -gt 1) { + foreach ($word in $words[0..($words.Length - 2)]) { + if ($expectArg) { + $expectArg = $null + continue + } + if ($word.StartsWith("-")) { + $opt = $this.opts.Where( { $_.Match($word) })[0] + if ($null -ne $opt -and $opt.TakesArg()) { + $expectArg = $opt + } + } + elseif (-not $this.multiple) { + $paramUsed = $true } - } - elseif (-not $this.multiple) { - $paramUsed = $true } } $candidates = @() @@ -76,53 +79,114 @@ class Completer { return $candidates.Where( { $_.StartsWith($lastWord) }) } - [Completer] addOpts([Option[]] $options) { + [void] AddOpts([Option[]] $options) { $this.opts += $options - return $this } - [Completer] addParams([string[]] $params, [bool]$multiple = $false) { + [void] AddParams([string[]] $params, [bool]$multiple = $false) { $this.params = $params $this.multiple = $multiple - return $this } } function getSections() { - return @() + if (-not (Test-Path -Path "pyproject.toml")) { + return @() + } + [string[]] $sections = @() + [bool] $inSection = $false + foreach ($line in (Get-Content "pyproject.toml")) { + if (($line -match ' *\[project\.optional-dependencies\]') -or ($line -match ' *\[tool\.pdm.dev-dependencies\]')) { + $inSection = $true + } + elseif ($inSection -and ($line -match '(\S+) *= *\[')) { + $sections += $Matches[1] + } + elseif ($line -like '`[*`]') { + $inSection = $false + } + } + return $sections +} + +function _fetchPackageListFromPyPI() { + if (-not (Test-Path -Path "~/.pdm")) { + mkdir "~/.pdm" + } + (Invoke-WebRequest $PDM_PIP_INDEX).Links | ForEach-Object { $_.innerText } | Out-File -FilePath "~/.pdm/.pypiPackages" } function getPyPIPackages() { - return @() + # $cacheFile = "~/.pdm/.pypiPackages" + # if (-not (Test-Path -Path $cacheFile) -or (Get-Item $cacheFile).LastWriteTime -lt (Get-Date).AddDays(-28)) { + # _fetchPackageListFromPyPI + # } + # Get-Content $cacheFile } function getPdmPackages() { - return @() + & $PDM_PYTHON -c "import os, re, toml +PACKAGE_REGEX = re.compile(r'^[A-Za-z][A-Za-z0-9._-]*') +def get_packages(lines): + return [PACKAGE_REGEX.match(line).group() for line in lines] + +with open('pyproject.toml', encoding='utf8') as f: + data = toml.load(f) +packages = get_packages(data.get('project', {}).get('dependencies', [])) +for reqs in data.get('project', {}).get('optional-dependencies', {}).values(): + packages.extend(get_packages(reqs)) +for reqs in data.get('tool', {}).get('pdm', {}).get('dev-dependencies', {}).values(): + packages.extend(get_packages(reqs)) +print(*set(packages), sep='\n') +" } +$_cachedConfigKeys = $null function getConfigKeys() { - [string[]] $keys = @() - $config = ("& $PDM_PYTHON -m pdm config") - foreach ($line in $($config -split "`r`n")) { - if ($line -match ' *(\s+) *=') { - $keys += $Matches[1] + if ($null -eq $_cachedConfigKeys) { + [string[]] $keys = @() + $config = @(& $PDM_PYTHON -m pdm config) + foreach ($line in $config) { + if ($line -match ' *(\S+) *=') { + $keys += $Matches[1] + } } + $_cachedConfigKeys = $keys } - return $keys + return $_cachedConfigKeys } function getScripts() { - return @() + if (-not (Test-Path -Path "pyproject.toml")) { + return @() + } + [string[]] $scripts = @() + [bool] $inScripts = $false + foreach ($line in (Get-Content "pyproject.toml")) { + if ($line -match ' *\[tool\.pdm\.scripts\]') { + $inScripts = $true + } + elseif ($inScripts -and ($line -match '(\S+) *= *')) { + $scripts += $Matches[1] + } + elseif ($line -like '`[*`]') { + $inScripts = $false + } + } + return $scripts + } function TabExpansion($line, $lastWord) { $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart() if ($lastBlock -match "^pdm ") { - $words = $lastBlock.Split()[1..-1] - $commands = $words.Where( { $_ -notlike "-*" }) + [string[]]$words = $lastBlock.Split()[1..$lastBlock.Length] + [string[]]$AllCommands = ("add", "build", "cache", "config", "export", "import", "info", "init", "install", "list", "lock", "remove", "run", "search", "show", "sync", "update", "use") + [string[]]$commands = $words.Where( { $_ -notlike "-*" }) $command = $commands[0] - $completer = [Completer]::new().addOpts(([Option]::new(("-h", "--help", "-v", "--verbose")))) + $completer = [Completer]::new() + $completer.AddOpts(([Option]::new(("-h", "--help", "-v", "--verbose")))) $sectionOption = [Option]::new(@("-s", "--section")).WithValues(@(getSections)) $projectOption = [Option]::new(@("-p", "--project")).WithValues(@()) $formatOption = [Option]::new(@("-f", "--format")).WithValues(@("setuppy", "requirements", "poetry", "flit")) @@ -130,136 +194,160 @@ function TabExpansion($line, $lastWord) { Switch ($command) { "add" { - $completer.addOpts(@( + $completer.AddOpts(@( [Option]::new(("-d", "--dev", "--save-compatible", "--save-wildcard", "--save-exact", "--update-eager", "--update-reuse", "-g", "--global", "--no-sync")), $sectionOption, $projectOption, [Option]::new(@("-e", "--editable")).WithValues(@(getPyPIPackages)) - )).addParams(@(getPyPIPackages)) + )) + $completer.AddParams(@(getPyPIPackages), $true) + break } - "build" { $completer.addOpts(@([Option]::new(@("-d", "--dest", "--no-clean", "--no-sdist", "--no-wheel")), $projectOption)) } + "build" { $completer.AddOpts(@([Option]::new(@("-d", "--dest", "--no-clean", "--no-sdist", "--no-wheel")), $projectOption)) } "cache" { $subCommand = $commands[1] switch ($subCommand) { "clear" { - $completer.addParams(@("wheels", "http", "hashes", "metadata")) + $completer.AddParams(@("wheels", "http", "hashes", "metadata"), $false) $command = $subCommand + break } $null { - $completer.addParams(@("clear", "remove", "info", "list")) + $completer.AddParams(@("clear", "remove", "info", "list"), $false) + break } Default {} } } - "completion" { $completer.addParams(@("powershell", "bash", "zsh", "fish")) } - "config" { $completer.addOpts(@([Option]::new(@("--delete", "--global", "--local", "-d", "-l", "-g")), $projectOption)) } + "completion" { $completer.AddParams(@("powershell", "bash", "zsh", "fish")); break } + "config" { + $completer.AddOpts(@([Option]::new(@("--delete", "--global", "--local", "-d", "-l", "-g")), $projectOption)) + $completer.AddParams(@(getConfigKeys), $false) + break + } "export" { - $completer.addOpts(@( + $completer.AddOpts(@( [Option]::new(@("--dev", "--output", "--global", "--no-default", "-g", "-d", "-o", "--without-hashes")), $formatOption, $sectionOption, $projectOption )) + break } "import" { - $completer.addOpts(@( + $completer.AddOpts(@( [Option]::new(@("--dev", "--global", "--no-default", "-g", "-d")), $formatOption, $sectionOption, $projectOption )) + break } "info" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("--env", "--global", "-g", "--python", "--where", "--packages")), $projectOption )) + break } "init" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("-g", "--global", "--non-interactive", "-n")), $projectOption )) + break } "install" { - $completer.addOpts(@( + $completer.AddOpts(@( [Option]::new(("-d", "--dev", "-g", "--global", "--no-default", "--no-lock")), $sectionOption, $projectOption )) + break } "list" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("--graph", "--global", "-g", "--reverse", "-r")), $projectOption )) + break } "lock" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("--global", "-g")), $projectOption )) + break } "remove" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("--global", "-g", "--dev", "-d", "--no-sync")), $projectOption, $sectionOption - )).addParams(@(getPdmPackages)) + )) + $completer.AddParams(@(getPdmPackages), $true) + break } "run" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("--global", "-g", "-l", "--list")), $projectOption - )).addParams(@(getScripts)) + )) + $completer.AddParams(@(getScripts), $false) + break } - "search" { } + "search" { break } "show" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("--global", "-g")), $projectOption )) + break } "sync" { - $completer.addOpts(@( + $completer.AddOpts(@( [Option]::new(("-d", "--dev", "-g", "--global", "--no-default", "--clean", "--no-clean", "--dry-run")), $sectionOption, $projectOption )) + break } "update" { - $completer.addOpts(@( + $completer.AddOpts(@( [Option]::new(("-d", "--dev", "--save-compatible", "--save-wildcard", "--save-exact", "--update-eager", "--update-reuse", "-g", "--global", "--dry-run", "--outdated", "--top")), $sectionOption, $projectOption - )).addParams(@(getPdmPackages)) + )) + $completer.AddParams(@(getPdmPackages), $true) + break } "use" { - $completer.addOpts( + $completer.AddOpts( @( [Option]::new(@("--global", "-g", "-f", "--first")), $projectOption )) + break } default { # No command - $completer.addParams(@("add", "build", "cache", "config", "export", "import", "info", "init", "install", "list", "lock", "remove", "run", "search", "show", "sync", "update", "use")) + $command = $null + $completer.AddParams($AllCommands, $false) } } - $completer.Complete($words[[array]::IndexOf($words, $command) + 1..-1]) + $start = [array]::IndexOf($words, $command) + 1 + $completer.Complete($words[$start..$words.Length]) } elseif (Test-Path Function:\_pdm_completeBackup) { # Fall back on existing tab expansion _pdm_completeBackup $line $lastWord } } - -TabExpansion "pdm config " ""