如何将 zsh 函数作为文件自动完成?

How do I make a zsh function autocomplete as a file?

我使用 zsh 并编写了一个函数来替换 cd 函数。在一些帮助下,我让它像我希望的那样工作(大部分)。这是 的后续。 该功能几乎按我想要的方式工作,但我在语法突出显示和自动完成方面仍然存在一些问题。

对于示例,假设您的目录如下所示:

/
    a/
        b/
        c/
            d/
        some_dir/

我还假设已获取以下代码:

cl () {
    local first=$( echo  | cut -d/ -f1 )
    if [ -d $first ]; then
        pushd  >/dev/null # If the first argument is an existing normal directory, move there
    else
        pushd ${PWD%/$first/*}/ >/dev/null # Otherwise, move to a parent directory or a child of that parent directory
    fi
}
_cl() {
    _cd
    pth=${words[2]}
    opts=""
    new=${pth##*/}
    local expl
    # Generate the visual formatting and store it in `$expl`
    _description -V ancestor-directories expl 'ancestor directories'
    [[ "$pth" != *"/"*"/"* ]] && middle="" || middle="${${pth%/*}#*/}/"
    if [[ "$pth" != *"/"* ]]; then
        # If this is the start of the path
        # In this case we should also show the parent directories
        local ancestor=$PWD:h
        while (( $#ancestor > 1 )); do
            # -f: Treat this as a file (incl. dirs), so you get proper highlighting.
            # -Q: Don't quote (escape) any of the characters.
            # -W: Specify the parent of the dir we're adding.
            # ${ancestor:h}: The parent ("head") of $ancestor.
            # ${ancestor:t}: The short name ("tail") of $ancestor.
            compadd "$expl[@]" -fQ -W "${ancestor:h}/" - "${ancestor:t}"
            # Move on to the next parent.
            ancestor=$ancestor:h
        done
    else
        # $first is the first part of the path the user typed in.
        # it it is part of the current direoctory, we know the user is trying to go back to a directory
        first=${pth%%/*}
        # $middle is the rest of the provided path
        if [ ! -d $first ]; then
            # path starts with parent directory
            dir=${PWD%/$first/*}/$first
            first=$first/
            # List all sub directories of the $dir/$middle directory
            if [ -d "$dir/$middle" ]; then
                for d in $(ls -a $dir/$middle); do
                    if [ -d $dir/$middle/$d ] && [[ "$d" != "." ]] && [[ "$d" != ".." ]]; then
                        compadd "$expl[@]" -fQ -W $dir/ - $first$middle$d
                    fi
                done
            fi
        fi
    fi
}
compdef _cl cl

问题: 返回父目录时,编译主要起作用。但是当你转到父目录的子目录时,建议是错误的(显示你键入的完整路径,而不仅仅是子目录)。

示例:

$ cd /a/c/d
$ cl a/[tab] # What it currently displays
a/b   a/c  a/some_dir
$ cl a/[tab] # What I want it to display
b     c    some_dir

如何让它显示第二个建议?

您可以通过提供带有 -d 选项的 显示字符串数组 来以任何您想要的方式显示完成:

local -a disp
# (N) gives an empty array when there are no matches, rather than an error.
# (:t) returns the last segment of each path.
for d in $dir/$middle*(N:t); do
  disp=( "$d" )  
  compadd "$expl[@]" -fQ -W $dir/ -d disp - $first$middle$d
done

文档: