[英]How do I get bash completion to work with aliases in Windows 10 bash?
[英]How do I get bash completion to work with aliases?
举个例子:
我在 mac 上使用 bash v3.2.17,我正在使用通过 macports 安装的 git 和 bash_completion 变体。
当我输入git checkout m<tab>
时。 例如,我把它完成到master
。
但是,我有一个别名git checkout
, gco
。 当我键入gco m<tab>
时,我没有自动完成分支名称。
理想情况下,我希望自动完成功能能够神奇地为我的所有别名工作。 是否可以? 如果做不到这一点,我想为每个别名手动自定义它。 那么,我的go怎么办呢?
正如上面的评论所述,
complete -o default -o nospace -F _git_checkout gco
将不再起作用。 但是,在 git-completion.bash 中有一个__git_complete
函数,可用于为别名设置完成,如下所示:
__git_complete gco _git_checkout
我也遇到了这个问题并想出了这个代码片段。 这将自动为您完成所有别名。 在声明所有(或任何)别名后运行它。
# wrap_alias takes three arguments:
# $1: The name of the alias
# $2: The command used in the alias
# $3: The arguments in the alias all in one string
# Generate a wrapper completion function (completer) for an alias
# based on the command and the given arguments, if there is a
# completer for the command, and set the wrapper as the completer for
# the alias.
function wrap_alias() {
[[ "$#" == 3 ]] || return 1
local alias_name="$1"
local aliased_command="$2"
local alias_arguments="$3"
local num_alias_arguments=$(echo "$alias_arguments" | wc -w)
# The completion currently being used for the aliased command.
local completion=$(complete -p $aliased_command 2> /dev/null)
# Only a completer based on a function can be wrapped so look for -F
# in the current completion. This check will also catch commands
# with no completer for which $completion will be empty.
echo $completion | grep -q -- -F || return 0
local namespace=alias_completion::
# Extract the name of the completion function from a string that
# looks like: something -F function_name something
# First strip the beginning of the string up to the function name by
# removing "* -F " from the front.
local completion_function=${completion##* -F }
# Then strip " *" from the end, leaving only the function name.
completion_function=${completion_function%% *}
# Try to prevent an infinite loop by not wrapping a function
# generated by this function. This can happen when the user runs
# this twice for an alias like ls='ls --color=auto' or alias l='ls'
# and alias ls='l foo'
[[ "${completion_function#$namespace}" != $completion_function ]] && return 0
local wrapper_name="${namespace}${alias_name}"
eval "
function ${wrapper_name}() {
let COMP_CWORD+=$num_alias_arguments
args=( \"${alias_arguments}\" )
COMP_WORDS=( $aliased_command \${args[@]} \${COMP_WORDS[@]:1} )
$completion_function
}
"
# To create the new completion we use the old one with two
# replacements:
# 1) Replace the function with the wrapper.
local new_completion=${completion/-F * /-F $wrapper_name }
# 2) Replace the command being completed with the alias.
new_completion="${new_completion% *} $alias_name"
eval "$new_completion"
}
# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias -p | sed -e 's/alias \([^=][^=]*\)='\''\([^ ][^ ]*\) *\(.*\)'\''/wrap_alias \1 \2 '\''\3'\'' /')"
unset wrap_alias
在git-completion.bash
有一行:
complete -o default -o nospace -F _git git
查看该行(和 _git 函数),您可以将此行添加到.bash_profile
:
complete -o default -o nospace -F _git_checkout gco
理想情况下,我希望自动完成功能可以神奇地为我所有的别名工作。 是否可以?
是的,完全别名项目(在 Linux 上)是可能的。 对 Mac 的支持是实验性的,但用户报告说是成功的。
我给 g='git' 取了别名,并结合我的 git 别名输入了诸如
$ g co <branchname>
对于我的特定用例,更简单的解决方法是向 git-completion 添加一行。
就在这条线的正下方:
__git_complete git _git
我添加了这一行来处理我的单个“g”别名:
__git_complete g _git
~/.bash_completion
一种选择是使用~/.bash_completion
文件。 要为git checkout
创建gco
别名,只需将其放在那里:
_xfunc git __git_complete gco _git_checkout
然后在~/.bashrc
您必须只放置别名本身:
alias gco='git checkout'
两条线。 就是这样。
解释:
~/bash_completion
位于主 bash_completion 脚本的末尾。 在 gentoo 中,我在/usr/share/bash-completion/bash_completion
找到了主脚本。
_xfunc git
bit 负责为您获取git-completion
文件,因此您无需在~/.bashrc
放入任何其他内容。
接受的答案要求您复制.git-completion.sh
并从我发现蹩脚的~/.bashrc
文件中获取它。
PS:我仍在试图弄清楚如何不将整个git-completion
脚本源到我的 bash 环境中。 如果您找到方法,请发表评论或编辑。
您也可以尝试使用 Git 别名。 例如,在我的~/.gitconfig
文件中,我有一个如下所示的部分:
[alias]
co = checkout
所以你可以输入git co m<TAB>
,这应该扩展为git co master
,这是git checkout
命令。
这个论坛页面显示了一个解决方案。
将这些行放入您的.bashrc
或.bash_profile
:
# Author.: Ole J
# Date...: 23.03.2008
# License: Whatever
# Wraps a completion function
# make-completion-wrapper <actual completion function> <name of new func.>
# <command name> <list supplied arguments>
# eg.
# alias agi='apt-get install'
# make-completion-wrapper _apt_get _apt_get_install apt-get install
# defines a function called _apt_get_install (that's $2) that will complete
# the 'agi' alias. (complete -F _apt_get_install agi)
#
function make-completion-wrapper () {
local function_name="$2"
local arg_count=$(($#-3))
local comp_function_name="$1"
shift 2
local function="
function $function_name {
((COMP_CWORD+=$arg_count))
COMP_WORDS=( "$@" \${COMP_WORDS[@]:1} )
"$comp_function_name"
return 0
}"
eval "$function"
}
# and now the commands that are specific to this SO question
alias gco='git checkout'
# we create a _git_checkout_mine function that will do the completion for "gco"
# using the completion function "_git"
make-completion-wrapper _git _git_checkout_mine git checkout
# we tell bash to actually use _git_checkout_mine to complete "gco"
complete -o bashdefault -o default -o nospace -F _git_checkout_mine gco
这个解决方案类似于balshetzer's script ,但只有这个对我有用。 (balshetzer 的脚本对我的一些别名有问题。)
您只需要找到complete
命令并复制具有别名的行。
我有alias dm="docker-machine"
。 换句话说, dm
应该是docker-machine
的别名。
所以在 Mac 上(通过 brew),完成文件在cd `brew --prefix`/etc/bash_completion.d/
。
就我而言,我编辑了名为docker-machine
的文件。
一直在底部有:
complete -F _docker_machine docker-machine
所以我只是用我的别名添加了另一行:
complete -F _docker_machine docker-machine
complete -F _docker_machine d-m
首先,查找原始完成命令。 例子:
$ complete | grep git
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main git
现在将这些添加到您的启动脚本中(例如 ~/.bashrc):
# copy the original statement, but replace the last command (git) with your alias (g)
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g
# load dynamically loaded completion functions (may not be required)
_completion_loader git
_completion_loader
行可能不需要。 但是在某些情况下,完成功能只有在您第一次键入命令并按TAB
后才会动态加载。 因此,如果您还没有使用原始命令,并尝试使用 alias + TAB
,您可能会收到类似“bash: completion: function '_docker' not found”之类的错误。
这个问题有很多答案,和我一样,我敢打赌很多困惑的读者。 就我而言,我还要求让我的 dotfiles 在具有不同 Git 版本的多个平台上工作。 我也没有alias g=git
而是将g
定义为一个函数。
为了做到这一点,我不得不将不同的答案拼凑成一个解决方案。 虽然这已经重申了答案,但我认为我船上的某个人可能会发现这个汇编很有用,就像我第一次遇到这个问题时一样。
这假设旧的和新的 Git 完成,Ubuntu 默认,并且在 MacOS 上brew install git
。 在后一种情况下,bash 没有处理 brew 安装的完成(我稍后会诊断)。
# Alias g to git
g() {
if [[ $# > 0 ]]; then
git "$@"
else
git status -sb
fi
}
# Preload git completion in Ubuntu which is normally lazy loaded but we need
# the __git_wrap__git_main function available for our completion.
if [[ -e /usr/share/bash-completion/completions/git ]]; then
source /usr/share/bash-completion/completions/git
elif [[ -e /usr/local/etc/bash_completion.d/git-completion.bash ]]; then
source /usr/local/etc/bash_completion.d/git-completion.bash
fi
if command_exists __git_complete; then
__git_complete g _git
elif command_exists __git_wrap__git_main; then
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g
fi
如果您使用alias g='git'
,我会在.bash_aliases
添加这行代码
complete -o default -o nospace -F _git g
Felipe Contreras已经非常热衷于 Git 补全功能(请参阅Git 2.30 中的 Zsh 补全)提出(对于 - 可能 - Git 2.31,2021 年第一季度)一个公共功能,这将有助于别名自动补全。
他的提议:
早在 2012 年,我就主张引入一个帮助程序,允许用户指定别名,例如:
git_complete gf git_fetch
那时有一些
_GIT_complete
,因为公共函数没有明确的指导方针(git_complete
与_git_complete
与_GIT_complete
),并且一些别名实际上不起作用。快进到 2020 年,仍然没有关于公共功能的指南,这些别名仍然不起作用(即使我发送了修复程序)。
这并没有阻止人们使用这个显然需要设置自定义别名的功能(这个页面),实际上这是推荐的方式。
但是用户必须输入很麻烦:
__git_complete gf _git_fetch
或者更糟:
__git_complete gk __gitk_main
8年的时间足以停止等待完美的到来; 让我们定义一个实际用户友好的公共函数(具有相同的名称):
__git_complete gf git_fetch __git_complete gk gitk
同时还保持向后兼容性。
逻辑是:
- 如果
$2
存在,直接使用- 如果没有,检查
__$2_main
存在- 如果没有,检查
_$2
存在- 如果没有,则失败
您可以将Tab绑定到alias-expand-line
并在~/.inputrc
complete
(其默认操作)。 为此,您首先需要将每个操作绑定到一个键,然后将它们链接在一起,如下所示:
"\M-z":alias-expand-line
"\M-x":complete
TAB:"\M-z\M-x"
您可以使用任何您喜欢的组合键,我使用 Meta 组合键,因为它是免费的。 有关更多信息,请参阅man 3 readline
。
现在,如果您打开一个新终端并输入别名:
gco m<TAB>
该行将转换为
git checkout master
当然,即使不涉及别名, Tab仍会照常工作。
我知道这个问题是关于 bash 的,但是如果你使用的是 zsh,这个对@hesky-fisher 答案的更改将会解决它。
从
# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias -p | sed -e 's/alias \([^=][^=]*\)='\''\([^ ][^ ]*\) *\(.*\)'\''/wrap_alias \1 \2 '\''\3'\'' /')"
到:
# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias | sd '^([^=]+)=(.+)' 'wrap_alias $1=$2')"
你需要有sd
(这可以用sed
代替,但我认为sd
更好)
这样做是因为 zsh 没有alias -p
和alias
output in zsh doesn't output
alias <something>=<value>
就像 bash 一样,而是
<something>=<value>
顺便说一句,我将初始化代码放在.zlogin
文件中
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.