сравнения приводят к сбою аргументов _ в некоторых случаях - PullRequest
0 голосов
/ 02 мая 2020

Я пишу сценарий завершения zsh для произвольных сценариев python (аналогично argcomplete).

Я пытаюсь заставить сценарий работать в несколько вариантов использования:

  1. Сценарий вызывается напрямую (например, ~/script.py)
  2. Сценарий вызывается через python (например, python script.py)
  3. Сценарий вызывается как модуль python (например, python -m script)

. Мне до сих пор удавалось успешно обработать первый случай, но во втором случае не удается получить какие-либо завершения. Используя zsh журнал отладки завершения, я смог увидеть, где что-то пошло не так:

Функция _arguments вызывает встроенную функцию с именем comparguments. В первом случае функция возвращает 0, и поток управления продолжается, как и ожидалось. Во втором случае происходит сбой функции, и _arguments немедленно возвращает 1. Это происходит, даже если аргументы comparguments идентичны в обоих случаях.

Здесь - ссылка на журналы отладки для обеих ситуаций. Для первого сценария comparguments вызывается в строке 199, а во втором сценарии он вызывается в строке 197.

Мой сценарий:

#compdef -p *

_python_script() {
    # Expand all words
    local -a expanded_words
    __pyzshcomplete_exapnd_tilde_in_all_words

    # Check if we should run or else quit
    __pyzshcomplete_should_run || return 1

    # Skip any other completion function
    _compskip=all

    # Retrieve valid completions and pass them to _arguments
    local arguments=(
        ${(f)"$(PYZSHCOMPLETE=1 __python_argcomplete_run ${expanded_words[@]})"}
    )
    _arguments -s -w : ${arguments[@]}

    # Always return 0 - if _arguments fails, compsys for some reason invokes
    # this script again consuming more time and gaining nothing.
    # If we are in this context there shouldn't be other completions anyways so
    # no reason to return 1 anyways...
    return 0
}


__pyzshcomplete_exapnd_tilde_in_all_words() {
    for ((i = 1; i <= $#words; i++)); do
        expanded_words[$i]=${~words[$i]}
    done
}


### The following code is taken from the argcomplete project, including
### original copyright. Changes from the original will be marked by a comment
### Starting with CHANGE.
### Original code:
### https://github.com/kislyuk/argcomplete/blob/v1.11.1/argcomplete/bash_completion.d/python-argcomplete

# Copyright 2012-2019, Andrey Kislyuk and argcomplete contributors.
# Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info.

# CHANGE: This function is a heavily refactored copy of the first part of
# _python_argcomplete_global
__pyzshcomplete_should_run() {
    local executable=${expanded_words[1]}

    if [[ $executable == python* ]] || [[ $executable == pypy* ]]; then
        # If 2nd word is the -m flag, check that the module has the magic string
        [[ ${expanded_words[2]} == -m ]] && __python_argcomplete_run \
            $executable -m argcomplete._check_module ${expanded_words[3]} && \
            return 0
        # If 2nd word is a file, check that it has the magic string
        [[ -f ${expanded_words[2]} ]] && __python_argcomplete_scan_head_noerr \
            ${expanded_words[2]} && return 0
        return 1
    fi

    # Assume the first word is a script and find its path
    local script_path
    # Search in path
    if type -p $executable > /dev/null 2>&1; then
        script_path=$(type -p $executable | sed -r "s:$executable is ::")
    # Check if it's a file
    elif [[ -f $executable ]]; then
        script_path=$executable
    fi

    # If found a path, scan for magic
    if [[ -n $script_path ]]; then
        __python_argcomplete_scan_head_noerr $script_path && return 0
        return 1
    fi

    return 1
}

# Run something, muting output or redirecting it to the debug stream
# depending on the value of _ARC_DEBUG.
__python_argcomplete_run() {
    if [[ -z "$_ARC_DEBUG" ]]; then
        "$@" 8>&1 9>&2 1>/dev/null 2>&1
    else
        "$@" 8>&1 9>&2 1>&9 2>&1
    fi
}

# Scan the beginning of an executable file ($1) for a regexp ($2). By default,
# scan for the magic string indicating that the executable supports the
# argcomplete completion protocol. Scan the first kilobyte.
__python_argcomplete_scan_head() {
    # CHANGE: the zsh read builtin has different options and behaves differently
    read -s -r -k 1024 -u 0 < "$1"
    [[ "$REPLY" =~ ${2:-PYTHON_ARGCOMPLETE_OK} ]]
}

__python_argcomplete_scan_head_noerr() {
    __python_argcomplete_scan_head "$@" 2>/dev/null
}

РЕДАКТИРОВАТЬ:

Чтобы временно обойти проблему, я попытался добавить shift words перед вызовом _arguments. Это привело к успешному завершению работы comparguments (!), Но все равно вызывает сбой _arguments с сообщением no arguments.

Я добавил журнал для этого случая в сущность, связанную выше.

...