zsh 자동 완성을 래퍼 함수 인수 및 기존 명령과 결합하는 방법

zsh 자동 완성을 래퍼 함수 인수 및 기존 명령과 결합하는 방법

나는 주로 gvim과 많은 터미널에서 일합니다. 처음에는 단일 vim 인스턴스에서 모든 파일을 여는 것을 선호했습니다. 이를 위해 별칭을 사용하여 현재 "vim 서버"의 터미널에서 파일을 엽니다.

alias rv="gvim --remote-silent"

하지만 단일 vim 인스턴스에서 여러 프로젝트의 많은 파일을 열면 생산성에 영향을 미치므로 별칭을 함수로 업그레이드했습니다.

# main function
rv() {
    local args options server

    options=$(getopt -o hils:t: -l "help,info,list,set:,target:" -- "$@")

    if [[ $? -ne 0 ]]; then
        echo "Failed to parse options."
        return 1
    fi

    # a little magic, necessary when using getopt
    eval set -- "$options"

    # go through the options with a case and use shift to analyze one option at a time.
    while true; do
        case "$1" in
            -h|--help)
                echo "Usage: $0 [-hil] [--help] [--info] [--list]";
                echo "       $0 {-s | --set} <name> [<file1 file2...>]";
                echo "       $0 {-t | --target} <name>] <file1 file2...>";
                return 0;;
            -i|--info)
                gvim_show_info;
                return 0;;
            -l|--list)
                gvim_list_servers;
                return 0;;
            -s|--set)
                gvim_set_server_name ${2:u};
                shift 2;;
            -t|--target)
                server="$2";
                shift 2;;
            --)
                shift;
                break;;
        esac
    done

    if [[ "$#" -eq 0 ]]; then
        # if no files specified...
        if [[ -n "$server" ]]; then
            # throw error if --target option was specified.
            echo "Error!  --target requires one or more filenames."
            return 1;
        fi
    else
        # if files were specified...
        if [[ -n "$server" ]]; then
            # if --target was specified
            gvim_run_remote $server "$@"
        else
            gvim_run_remote $(gvim_get_default_server) "$@"
        fi
    fi

    return 0;
}

이제 이 새로운 것에는 rv자체 옵션이 있습니다. 다음과 같은 용도로 사용할 수 있습니다.

  • 사용 가능한 vim 서버 나열(-l --list)
  • 현재 쉘에 대한 기본 vim 서버 설정(-s --set)
  • 기본 vim 서버 표시(-i --info)
  • 특정 vim 서버에서 파일 열기(-t --target)
  • 기본 vim 서버에서 파일을 엽니다.rv files...

rv하지만 별칭 대신 함수를 사용하고 있기 때문에 예전에 좋아했던 zsh 완성 기능이 사라졌습니다. 옵션을 _rv표시하는 완성 함수를 만드는 방법에 대해 읽었 rv지만 완성 옵션을 기존 vim 완성 옵션과 결합하고 싶습니다. rv-svim사이에 충돌이 있을 수 있다는 것을 알고 있지만 구분 기호를 사용하면 문제를 적절하게 처리 -s할 수 있을 것 같습니다 --.

너무 오래;그렇다면 및 _arguments옵션을 결합한 완성 스크립트를 어떻게 작성합니까? 가능하다면 매개변수 목록을 복사하여 ._rv_vim_vim_rv

이 내 꺼야 _rv. 2014/6/10 16:10 업데이트됨

#compdef rv

_rv() {
    typeset -A opt_args
    local alternatives

    alternatives=(
        'args:rv options:_rv_options'
        'files:file:_vim_files'
    )

    _alternative $alternatives && return 0

    return 1
}

_rv_options() {
    local arguments

    arguments=(
        '(-i -l -s -t --info --list --set --target)'{-h,--help}'[Print usage info.]'
        '(-h -l -s -t --help --list --set --target)'{-i,--info}'[Print default vim server. As stored in $GVIM_SERVER.]'
        '(-i -h -s -t --info --help --set --target)'{-l,--list}'[Print list of existing vim servers.]'
        '(-i -h -l -t --info --help --list --target)'{-s,--set}'[Set default vim server for the current shell.]:vim servers:_rv_vim_servers'
        '(-i -h -l -s --info --help --list --set)'{-t,--target}'[Open files in a particular vim server.]:vim servers:_rv_vim_servers'
        )

    _arguments -s -C $arguments && return 0

    return 1
}

_rv_vim_servers() {
    local -a servers
    servers=( ${(f)"$(_call_program servers vim --serverlist 2>/dev/null)"} )
    _wanted servers expl server compadd -M 'm:{a-z}={A-Z}' -a servers && return
}

# invoke the completion command during autoload
_rv "$@"

현재 행동

현재 _rv마감을 사용할 수 있지만 이상적이지는 않습니다.

  • 을 입력하면 rv <TAB>vim 옵션이 표시되지 않습니다. rv 옵션과 파일 경로만 표시됩니다. _vim파일 경로가 완성되었습니다. 만세!
  • 을 입력하면 rv -s <TAB>vim 서버 목록과 파일 경로도 표시됩니다. 파일은 현재 명령에 허용되지 않으며 자동 완성에 표시되어서는 안 됩니다.

예상되는 동작

  • 를 입력하면 rv <TAB>1) rv 옵션, 2) vim 옵션, 3) 파일 경로 목록이 표시될 것으로 예상됩니다.
  • 을 입력하면 rv -s <TAB>다음이 표시될 것으로 예상됩니다. 1) vim 서버 이름(이름은 _rv_vim_servers.
  • 을 입력하면서 rv /valid/file/path/<TAB>파일 경로 목록만 보고 싶습니다. 이제 _vim나는 이 능력을 이미 갖고 있으니 그것에 의지하고 싶습니다.

답변1

당신은 할 수원숭이 패치_arguments완성자를 확장하는 기능 _vim:

#compdef rv

_rv_vim_servers() {
    local expl
    _wanted servers expl server \
        compadd -- ${(f)"$( _call_program servers vim --serverlist 2>/dev/null )"}
}

_rv() {
  autoload +X -Uz _arguments             # Load the function body.
  functions -c _arguments _rv_arguments  # Make a copy.

  # Replace the original function.
  _arguments() {
    # Call the original function with additional completions.
    _rv_arguments "$@" \
        '(-i -l -s -t --info --list --set --target)'{-h,--help}'[print usage info]' \
        '(-h -l -s -t --help --list --set --target)'{-i,--info}'[print default vim server as stored in $GVIM_SERVER]' \
        '(-i -h -s -t --info --help --set --target)'{-l,--list}'[print list of existing vim servers]' \
        '(-i -h -l -t --info --help --list --target)'{-s,--set}'[set default vim server for the current shell]:vim servers:_rv_vim_servers' \
        '(-i -h -l -s --info --help --list --set)'{-t,--target}'[open files in a particular vim server]:vim servers:_rv_vim_servers'
  }

  {
    _vim "$@"
  } always {
    functions -c _rv_arguments _arguments  # Restore the original.
    unfunction _rv_arguments               # Discard our copy.
  }
}

_rv "$@"

답변2

이 클래스 이름에 대한 힌트가 있는 /usr/share/zsh/functions/Completion/Unix/_git을 찾았고 별칭에 대해 다음 함수를 정의했습니다.

_git-ls () {
  # Just return the _git-ls-files autocomplete function
  _git-ls-files
}

그런 다음 compdef g=git을 직접 실행하십시오. 자동 완성 시스템은 예를 들어 g ls가 실행 중임을 확인하고 _git-ls 자동 완성 기능을 사용합니다.

발견하다여기

관련 정보