如何将zsh自动完成功能用于包装函数参数和现有命令


40

我主要在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)
  • 设置当前shell的默认vim服务器(-s --set)
  • 显示默认的vim服务器(-i --info)
  • 在特定的vim服务器中打开文件(-t --target)
  • 在默认的vim服务器中打开文件: rv files...

但是,由于我使用的是函数rv而不是别名,因此我失去了以前喜欢的zsh补全功能。我已经阅读了有关创建完成函数的信息,_rv该函数将显示rv的选项,但是我想将我的完成选项与现有的vim完成选项结合起来。我知道可能会有一些冲突与rv-svim-s,但我想我能处理的优雅与--分离。

TLDR;那么,如何创建一个完成脚本,结合了_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
compdef有一个-n选项说它“防止覆盖已经为命令或上下文定义的任何补全”。那么,您尝试过compdef _vim rv跟在后面compdev -n _rv rv吗?
Lqueryvg

3
28个投票都没有答案...这是一个关于zsh的问题...我将尝试为您调用@StéphaneChazelas^^(我尝试不滥用此功能,但这很有趣。请Stephane,告诉我是否应该执行此操作...,我将删除它,不再执行此操作)...如果这里有人知道答案,应该是他
Olivier Dulac

1
@OlivierDulac我认为只有在该主题中已发布的情况下,您才会收到通知。(允许使用重复的名称,所以这很有意义。)尽管您可能在聊天中找到他。
Sparhawk

是否可以获取原始_vim 文件,但在此之前_arguments用自定义本地函数覆盖该函数?这样,您将从中获取论据_vim。也许使用单独的zsh进程。
拉斐尔·阿伦斯

Answers:


1

我找到了/ 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自动完成功能。

如在这里找到


谢谢,但不完全是。您的解决方案假定我只希望从自动完成_git-ls-files。这个问题有一个git-ls(遵循您的约定)自己的选项,其中一些选项与重叠git-ls-files。而不是为的所有选项都编写自动完成功能git-ls,我该如何编写一个自动完成功能,该功能使用自动完成功能_git-ls-files(覆盖率达到90%)并将其与其余选项(例如10%)的自动完成功能结合在一起?
贾斯汀·C
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.