Skip to content

zsh completion requires pressing tab twice #2344

@Freed-Wu

Description

@Freed-Wu
❯ black --<TAB>
# Nothing will happen
❯ black --<TAB>
unsorted
--code                        Format the code passed in as a string.
...
# work after second time

Expected:

❯ black --<TAB>
unsorted
--code                        Format the code passed in as a string.
...
# work after first time
Original investigation
❯ _BLACK_COMPLETE=zsh_source black
#compdef black

_black_completion() {
    local -a completions
    local -a completions_with_descriptions
    local -a response
    (( ! $+commands[black] )) && return 1

    response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) _BLACK_COMPLETE=zsh_complete black)}")

    for type key descr in ${response}; do
        if [[ "$type" == "plain" ]]; then
            if [[ "$descr" == "_" ]]; then
                completions+=("$key")
            else
                completions_with_descriptions+=("$key":"$descr")
            fi
        elif [[ "$type" == "dir" ]]; then
            _path_files -/
        elif [[ "$type" == "file" ]]; then
            _path_files -f
        fi
    done

    if [ -n "$completions_with_descriptions" ]; then
        _describe -V unsorted completions_with_descriptions -U
    fi

    if [ -n "$completions" ]; then
        compadd -U -V unsorted -a completions
    fi
}

compdef _black_completion black;

that is equivalent to

_black() {
  _black_completion() {
      local -a completions
      local -a completions_with_descriptions
      local -a response
      (( ! $+commands[black] )) && return 1

      response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) _BLACK_COMPLETE=zsh_complete black)}")

      for type key descr in ${response}; do
          if [[ "$type" == "plain" ]]; then
              if [[ "$descr" == "_" ]]; then
                  completions+=("$key")
              else
                  completions_with_descriptions+=("$key":"$descr")
              fi
          elif [[ "$type" == "dir" ]]; then
              _path_files -/
          elif [[ "$type" == "file" ]]; then
              _path_files -f
          fi
      done

      if [ -n "$completions_with_descriptions" ]; then
          _describe -V unsorted completions_with_descriptions -U
      fi

      if [ -n "$completions" ]; then
          compadd -U -V unsorted -a completions
      fi
  }

  compdef _black_completion black;
}
compdef _black black  # because first line comment

So, in the first time, compdef _black black tell zsh the completion function is _black(), but _black() not return any completion items, only define a new function named _black_completion and compdef _black_completion black. So when the second time, it work.

The fix method is remove the nested function definition:

❯ _BLACK_COMPLETE=zsh_source black
#compdef black

local -a completions
local -a completions_with_descriptions
local -a response
(( ! $+commands[black] )) && return 1

response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) _BLACK_COMPLETE=zsh_complete black)}")

for type key descr in ${response}; do
    if [[ "$type" == "plain" ]]; then
        if [[ "$descr" == "_" ]]; then
            completions+=("$key")
        else
            completions_with_descriptions+=("$key":"$descr")
        fi
    elif [[ "$type" == "dir" ]]; then
        _path_files -/
    elif [[ "$type" == "file" ]]; then
        _path_files -f
    fi
done

if [ -n "$completions_with_descriptions" ]; then
    _describe -V unsorted completions_with_descriptions -U
fi

if [ -n "$completions" ]; then
    compadd -U -V unsorted -a completions
fi

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions