dotnet / command-line-api

Command line parsing, invocation, and rendering of terminal output.
https://github.com/dotnet/command-line-api/wiki
MIT License
3.37k stars 378 forks source link

zsh completion shim does not work as expected #1849

Open Blackclaws opened 2 years ago

Blackclaws commented 2 years ago

As the title says the zsh completion shim doesn't work as expected or rather doesn't work at all in some cases.

The problem stems from the fact that dotnet-suggest on my system gives the following for dotnet-suggest list

dotnet-ef
dotnet ef
security-scan
dotnet-grpc-cli
dotnet grpc-cli
dotnet-suggest
dotnet suggest
dotnet-grpc
dotnet grpc
reportgenerator

So for all the dotnet prefixed global commands there is always the one with a space included as well. This leads to the situation where dotnet-suggest is registered as a completion provider for dotnet.

Resulting in this issue:

_values:compvalues:11: not enough arguments

Because there is no completion returned by dotnet-suggest for dotnet

If I understand the issue correctly this stems from this line: https://github.com/dotnet/command-line-api/blob/1d98a75ce2b109a2d7c18d81fac3f279be095e4e/src/System.CommandLine.Suggest/dotnet-suggest-shim.zsh#L32

In general if there is no completion returned there shouldn't even be a _values object that is set as far as I understand.

lonix1 commented 2 years ago

I also have this issue, I thought it was "just me".

mars-low commented 1 year ago

It can be slightly improved by enabling completion for the dotnet command separately as described in https://github.com/dotnet/docs/blob/main/docs/core/tools/enable-tab-autocomplete.md#zsh. It is based on dotnet complete command in contrast to dotnet suggest. Both configurations can be merged together and put in ~/.zshrc file.

# zsh parameter completion for the dotnet CLI
_dotnet_zsh_complete() 
{
  local completions=("$(dotnet complete "$words")")

  # If the completion list is empty, just continue with filename selection
  if [ -z "$completions" ]
  then
    _arguments '*::arguments: _normal'
    return
  fi

  # This is not a variable assignment, don't remove spaces!
  _values = "${(ps:\n:)completions}"
}

_dotnet_suggest_zsh_complete()
{
    # debug lines, uncomment to get state variables passed to this function
    # echo "\n\n\nstate:\t'$state'"
    # echo "line:\t'$line'"
    # echo "words:\t$words"

    # Get full path to script because dotnet-suggest needs it
    # NOTE: this requires a command registered with dotnet-suggest be
    # on the PATH
    full_path=`which ${words[1]}` # zsh arrays are 1-indexed
    # Get the full line
    # $words array when quoted like this gets expanded out into the full line
    full_line="$words"

    # Get the completion results, will be newline-delimited
    completions=$(dotnet suggest get --executable "$full_path" -- "$full_line")
    # explode the completions by linefeed instead of by spaces into the descriptions for the
    # _values helper function.

    # If the completion list is empty, just continue with filename selection
    if [ -z "$completions" ]
    then
      _arguments '*::arguments: _normal'
      return
    fi

    exploded=(${(f)completions})
    # for later - once we have descriptions from dotnet suggest, we can stitch them
    # together like so:
    # described=()
    # for i in {1..$#exploded}; do
    #     argument="${exploded[$i]}"
    #     description="hello description $i"
    #     entry=($argument"["$description"]")
    #     described+=("$entry")
    # done
    _values 'suggestions' $exploded
}

compdef _dotnet_suggest_zsh_complete $(dotnet-suggest list)
compdef _dotnet_zsh_complete dotnet

export DOTNET_SUGGEST_SCRIPT_VERSION="1.0.0"

_dotnet_suggest_zsh_complete() is just renamed _dotnet_zsh_complete() function from: https://github.com/dotnet/command-line-api/blob/3e0d47c1f468ad7047302d00d56c916bf303f636/src/System.CommandLine.Suggest/dotnet-suggest-shim.zsh#L2

The order of compdef calls is important:

compdef _dotnet_suggest_zsh_complete $(dotnet-suggest list)
compdef _dotnet_zsh_complete dotnet

It should allow to get rid off errors:

_values:compvalues:11: not enough arguments

but to get meaningful completion for dotnet prefixed commands it is necessary to use commands with hyphen, e.g. dotnet-ef instead of dotnet ef, because dotnet ef is overtook by dotnet complete based completion.

jonsequitur commented 1 year ago

but to get meaningful completion for dotnet prefixed commands it is necessary to use commands with hyphen, e.g. dotnet-ef instead of dotnet ef, because dotnet ef is overtook by dotnet complete based completion.

This is a long-standing issue: #343.