是否可以为菜单完成定义一个完成规范?
Is it possible to define a completion specification for menu-complete?
我有一个文件夹 ~/builds
,其中包含以下子目录:
> tree ~/builds
~/builds
├── projectA
│ ├── build_2020_04_10_ok
│ ├── build_2020_04_11_ko
│ ├── build_2020_04_12_ok
│ └── ...
└── projectB
├── build_2020_04_10_ok
├── build_2020_04_11_ok
├── build_2020_04_12_ok
└── ...
目前,当我编写一个将子文件夹之一作为参数的命令并使用自动完成时,bash
列出了所有候选者:
> mycmd ~/builds/projectA/[TAB]
> mycmd ~/builds/projectA/build_2020_04_1[TAB][TAB]
build_2020_04_10_ok build_2020_04_11_ko build_2020_04_12_ok ...
这不是我想要的行为。
我想要的是更像Windows的自动完成。我知道我可以通过修改我的 .bashrc
来使用它:
bind '"\C-g": menu-complete'
现在,当我按下 Ctrl+g
时会发生以下情况:
> mycmd ~/builds/projectA/[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_10_ok[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_11_ko[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_12_ok
这几乎就是我想要的。我想更改子文件夹的显示顺序(首先是最新的,然后是旧的)。另外,我想放弃所有 ko
构建。换句话说,我想要这个命令定义的顺序:
ls -dr build*ok
build_2020_04_12_ok/ build_2020_04_10_ok/
因此,我想为 menu-complete
定义一个完成规范,以便仅在 ~/builds
的子目录上执行我想要的行为。我看到可以为 complete
做这件事,但我在 menu-complete
.
上找不到相关信息
可能吗?
正如@chepner 所说,menu-complete
代表与 complete
相同的完成(参见 man readline
)。所以最初我认为不可能根据它是通过 complete
还是 menu-complete
来配置不同的完成。但是我检查了是否根据调用的钩子设置了任何不同的值,并且有一些突出的东西:
# Get the current set of environment variables
# the sed expression strips functions to just print variables
# There's probably a better way to do this...
bash-5.0$ get_env() {
set | sed -n '/^[^=]*$/q;p' | sort
}
# Define a function to use as a completion that simply prints the changes
# in the environment between the normal shell and from within a completion
bash-5.0$ diff_env() {
echo # extra echo's for readability
sdiff -s /tmp/env.txt <(get_env)
}
# Register it as a completion (the command doesn't actually need to exist)
bash-5.0$ complete -F diff_env foo
bash-5.0$ bind '"\C-g": menu-complete'
# Persist the initial environment
bash-5.0$ get_env > /tmp/env.txt
bash-5.0$ foo [TAB]
BASH_LINENO=([0]="12") | BASH_LINENO=([0]="1" [1]="13")
BASH_SOURCE=([0]="main") | BASH_SOURCE=([0]="main" [1]="main")
> COMP_CWORD=1
> COMP_KEY=9
> COMP_LINE='foo '
> COMP_POINT=4
> COMP_TYPE=9
> COMP_WORDS=([0]="foo" [1]="")
> _=echo
FUNCNAME=([0]="get_env") | FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env <
^C
bash-5.0$ foo [Ctrl+g]
BASH_LINENO=([0]="12") | BASH_LINENO=([0]="1" [1]="14")
BASH_SOURCE=([0]="main") | BASH_SOURCE=([0]="main" [1]="main")
> COMP_CWORD=1
> COMP_KEY=9
> COMP_LINE='foo '
> COMP_POINT=4
> COMP_TYPE=37
> COMP_WORDS=([0]="foo" [1]="")
> _=echo
FUNCNAME=([0]="get_env") | FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env <
^C
发现了吗? COMP_TYPE
不一样! man bash
解释说它根据完成行为设置为一个整数;描述有点不透明,但值是给定类型的 ASCII 代码点(tab 为 9,%
为 37)。
所以我们可以定义一个完成函数来检查这个值以改变它的行为:
bash-5.0$ clever_complete() {
case "$COMP_TYPE" in
9) COMPREPLY=("tab!") ;;
37) COMPREPLY=("ctrl-g!") ;;
# should probably behave the same as [TAB], but I split it out to demonstrate
*) COMPREPLY=("IDK... $COMP_TYPE") ;;
esac
}
bash-5.0$ complete -F clever_complete bar
bash-5.0$ bar [TAB]tab! ^C
bash-5.0$ bar [Ctrl+g]ctrl-g! ^C
希望这足以继续 :) 如果您需要帮助实际编写具有您描述的行为的 complete
函数,我建议您针对当前的实现开始一个单独的问题(使用 complete -p [command]
查看当前完成,type [function-name]
查看完成的实现),从那里调整现有行为应该很简单。
我有一个文件夹 ~/builds
,其中包含以下子目录:
> tree ~/builds
~/builds
├── projectA
│ ├── build_2020_04_10_ok
│ ├── build_2020_04_11_ko
│ ├── build_2020_04_12_ok
│ └── ...
└── projectB
├── build_2020_04_10_ok
├── build_2020_04_11_ok
├── build_2020_04_12_ok
└── ...
目前,当我编写一个将子文件夹之一作为参数的命令并使用自动完成时,bash
列出了所有候选者:
> mycmd ~/builds/projectA/[TAB]
> mycmd ~/builds/projectA/build_2020_04_1[TAB][TAB]
build_2020_04_10_ok build_2020_04_11_ko build_2020_04_12_ok ...
这不是我想要的行为。
我想要的是更像Windows的自动完成。我知道我可以通过修改我的 .bashrc
来使用它:
bind '"\C-g": menu-complete'
现在,当我按下 Ctrl+g
时会发生以下情况:
> mycmd ~/builds/projectA/[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_10_ok[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_11_ko[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_12_ok
这几乎就是我想要的。我想更改子文件夹的显示顺序(首先是最新的,然后是旧的)。另外,我想放弃所有 ko
构建。换句话说,我想要这个命令定义的顺序:
ls -dr build*ok
build_2020_04_12_ok/ build_2020_04_10_ok/
因此,我想为 menu-complete
定义一个完成规范,以便仅在 ~/builds
的子目录上执行我想要的行为。我看到可以为 complete
做这件事,但我在 menu-complete
.
可能吗?
正如@chepner 所说,menu-complete
代表与 complete
相同的完成(参见 man readline
)。所以最初我认为不可能根据它是通过 complete
还是 menu-complete
来配置不同的完成。但是我检查了是否根据调用的钩子设置了任何不同的值,并且有一些突出的东西:
# Get the current set of environment variables
# the sed expression strips functions to just print variables
# There's probably a better way to do this...
bash-5.0$ get_env() {
set | sed -n '/^[^=]*$/q;p' | sort
}
# Define a function to use as a completion that simply prints the changes
# in the environment between the normal shell and from within a completion
bash-5.0$ diff_env() {
echo # extra echo's for readability
sdiff -s /tmp/env.txt <(get_env)
}
# Register it as a completion (the command doesn't actually need to exist)
bash-5.0$ complete -F diff_env foo
bash-5.0$ bind '"\C-g": menu-complete'
# Persist the initial environment
bash-5.0$ get_env > /tmp/env.txt
bash-5.0$ foo [TAB]
BASH_LINENO=([0]="12") | BASH_LINENO=([0]="1" [1]="13")
BASH_SOURCE=([0]="main") | BASH_SOURCE=([0]="main" [1]="main")
> COMP_CWORD=1
> COMP_KEY=9
> COMP_LINE='foo '
> COMP_POINT=4
> COMP_TYPE=9
> COMP_WORDS=([0]="foo" [1]="")
> _=echo
FUNCNAME=([0]="get_env") | FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env <
^C
bash-5.0$ foo [Ctrl+g]
BASH_LINENO=([0]="12") | BASH_LINENO=([0]="1" [1]="14")
BASH_SOURCE=([0]="main") | BASH_SOURCE=([0]="main" [1]="main")
> COMP_CWORD=1
> COMP_KEY=9
> COMP_LINE='foo '
> COMP_POINT=4
> COMP_TYPE=37
> COMP_WORDS=([0]="foo" [1]="")
> _=echo
FUNCNAME=([0]="get_env") | FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env <
^C
发现了吗? COMP_TYPE
不一样! man bash
解释说它根据完成行为设置为一个整数;描述有点不透明,但值是给定类型的 ASCII 代码点(tab 为 9,%
为 37)。
所以我们可以定义一个完成函数来检查这个值以改变它的行为:
bash-5.0$ clever_complete() {
case "$COMP_TYPE" in
9) COMPREPLY=("tab!") ;;
37) COMPREPLY=("ctrl-g!") ;;
# should probably behave the same as [TAB], but I split it out to demonstrate
*) COMPREPLY=("IDK... $COMP_TYPE") ;;
esac
}
bash-5.0$ complete -F clever_complete bar
bash-5.0$ bar [TAB]tab! ^C
bash-5.0$ bar [Ctrl+g]ctrl-g! ^C
希望这足以继续 :) 如果您需要帮助实际编写具有您描述的行为的 complete
函数,我建议您针对当前的实现开始一个单独的问题(使用 complete -p [command]
查看当前完成,type [function-name]
查看完成的实现),从那里调整现有行为应该很简单。