我正在尝试创建一个模拟 cd 的脚本,其中我提供了一个路径,并且脚本 cd 通过将其附加到绝对现有路径来实现。这个想法是,无论我在哪里调用它,它总是会表现得好像我试图从项目的根目录进行 cd 一样。
我想添加的一个关键功能是用户键入时自动完成,例如 cd,它将提供路径选项,并且用户可以在键入时自动完成。
示例:
goto po
pointers/ positions/
goto pointers/
src/ lib/
这是我迄今为止制作的初始脚本:
#!/bin/zsh
# Find the root directory of the repository
find_repo_root() {
local repo_root
repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -z "$repo_root" ]; then
return 1 # Return failure if not in a Git repository
fi
echo $repo_root
}
# Change directory relative to repository root
goto() {
local repo_root=$(find_repo_root)
if [ -z "$repo_root" ]; then
echo "Error: Not in a Git repository." >&2 # Print error message to stderr
return 1
fi
# Create an absolute path using the repo root
local target_dir="$repo_root/$1"
if [ -d "$target_dir" ]; then
cd "$target_dir"
else
echo "Directory does not exist: $target_dir" >&2
return 1
fi
}
# Autocomplete function for the goto command
_goto_autocomplete() {
local repo_root=$(find_repo_root)
if [ -z "$repo_root" ]; then
return 1 # If not in a Git repo, don't suggest any autocompletions
fi
# Dynamically generate possible matches relative to the repo root
local current_input="${(Q)PREFIX}"
# Find directories relative to the repository root, not the current directory
local possible_dirs=(${(f)"$(find $repo_root -type d -not -path '*/\.*' -maxdepth 2)"})
# Filter for directories that start with the current input
local matches=()
for dir in $possible_dirs; do
# Strip the repository root from the beginning of the directory path
local rel_dir=${dir#$repo_root/}
if [[ $rel_dir == $current_input* ]]; then
matches+=$rel_dir
fi
done
# Provide autocomplete suggestions
compadd $matches
}
# Register the autocomplete function for the goto command
compdef _goto_autocomplete goto
# Ensure compinit is loaded for autocompletion to work
autoload -Uz compinit && compinit
起初我以为它可以工作,因为它开始自动完成,但后来我意识到它总是在查看我所在的当前工作目录。我不明白 compadd、compdef 和 compinit 是如何工作的。我正在阅读文档以获取更多见解,但我不知道如何使自动完成功能仅查看提供的文件路径。
在为 zsh 编写补全函数时,使用现有的实用函数几乎总是比直接调用
compadd
更好。它们以更少的代码为用户提供了更加一致和可定制的体验。我推荐这个参考指南来开始使用zsh完成,因为官方文档往往过于复杂。
对于此脚本,
_files -/ -W "$repo_root"
正是您想要的:完成相对于 -/
($repo_root
) 的目录 (-W
)。
_goto_autocomplete() {
local repo_root
if ! repo_root=$(find_repo_root); then
_message 'not in a git repository'
# Return 0 so no other completers are tried
return 0
fi
# Using _arguments here instead of just _files so it doesn't try to
# complete more than one argument
_arguments ': :_files -/ -W "$repo_root"'
}