我正在努力编写 ZSH 自动完成功能。我的目标是使用和中列出的项目自动完成ta
和的第一个参数。tk
tmux list-sessions
tmuxinator list
以下是我目前所掌握的信息:
tmux list-sessions
输出如下数据:
dotfiles: 1 windows (created Tue Apr 15 21:54:51 2014) [123x48]
goodbye: 1 windows (created Tue Apr 15 21:51:34 2014) [123x48]
hello: 1 windows (created Tue Apr 15 21:42:03 2014) [123x48]
tmuxinator list
输出:
tmuxinator projects:
dotfiles landonschropp.com
这是我的尝试:
tmux-list-sessions-autofill() {
# get the tmux and tmuxinator sessions
TMUX_SESSIONS=$( tmux list-sessions | cut -d: -f1 )
TMUXINATOR_SESSIONS=$( tmuxinator list | tail -n +2 | gsed -e 's/\s\+/\n/g' )
# remove duplicates
SESSIONS=$( echo "$TMUX_SESSIONS\n$TMUXINATOR_SESSIONS" | sort | uniq )
# set the autocomplete values
reply=( $(echo $SESSIONS) )
}
compctl -K tmux-list-sessions-autofill ta
compctl -K tmux-list-sessions-autofill tk
tmux list-sessions | cut -d: -f1
删除除项目名称之外的所有内容。tmuxinator list | tail -n +2 | gsed -e 's/\s\+/\n/g'
删除第一行并用换行符替换空格。echo "$TMUX_SESSIONS\n$TMUXINATOR_SESSIONS" | sort | uniq
删除重复的行。- 我使用它是
gsed
因为我在用 OS X,而且sed
有点不稳定。
我的功能可以运行,但是真的很慢。我是 shell 脚本新手,所以我确信有更有效的方法来实现这一点。我的瓶颈在哪里?我该如何解决它?
答案1
要追踪延迟,您可以使用内置命令
time
,它可以列出管道中所有命令的贡献:zsh% time sleep 2 | date | sleep 1 sleep 2 0.00s user 0.00s system 0% cpu 2.003 total date 0.00s user 0.00s system 0% cpu 0.004 total sleep 1 0.00s user 0.00s system 0% cpu 1.004 total
虽然(根据您的评论)是外部命令
tmuxinator list
导致了明显的延迟,但您仍然可以优化完成功能。您使用了很多外部命令(sed
,,cut
...)来解析输出。在这里,我将展示一种仅使用 zsh 内置功能的方法。tmux-list-sessions-autofill() { local -aU SESSIONS SESSIONS=("${(@)${(f)$(tmux list-sessions)}/:*/}") SESSIONS+=("${(@)${(f)$(tmuxinator list-sessions)}[2,-1]/[ $'\t']*/}") reply=(${(i)SESSIONS}) }
乍一看这可能看起来很复杂,但是一旦你习惯了,zsh 的参数扩展就是非常功能强大。从上到下:
local -aU
声明一个本地参数SESSIONS
,它是一个数组(a
)和U
保持数组值唯一。+- 首先,获取sessions
tmux list-sessions
,从内到外进行解释:$(tmux list-sessions)
获取外部命令的输出${(f)$(tmux list-sessions)}
将结果拆分为\n
${(@)${(f)$(tmux list-sessions)}/:*/}
对每个数组元素((@)
)进行操作并执行搜索和替换/from/to
,即删除第一个冒号之后的所有内容。- 现在,
$SESSIONS
将包括(dotfiles goodbye hello)
。用于print -l $SESSIONS
在一行上打印每个数组元素。
- 接下来,对 执行几乎相同的程序
tmuxinator list
,但添加了以下内容:- 仅使用倒数第二个元素 (
[2,-1]
) space
删除 a或tab
($'\t'
) 字符之后(包括)的所有内容- 将这些元素(
+=
)添加到SESSIONS
数组中
- 仅使用倒数第二个元素 (
- 最后,返回
SESSIONS
不区分大小写的数组(i)
所有这些扩展都使用更长的通用形式,${parameter}
而不是简写符号$parameter
。man zshexpn
有关语法和所谓的参数扩展标志(喜欢(f)
)。
+根据巴特·谢弗该U
标志是不必要的,因为完成代码使其内部的完成列表唯一,因此当仅使用它们进行完成时,提前从数组中删除冗余条目并没有真正的帮助。
答案2
这是另一种选择:)
tmux-list-sessions-autofill() {
reply=( `tmux list-sessions | sed "s/:.*//g"` );
}
===== 编辑 =====
因此,我在这里重新表述我的答案,以回应@NetworkKingPin 的评论。
在@LandonSchropp 的原始帖子中,您应该将您的tmux-list-sessions-autofill()
功能更改为以下内容:
tmux-list-sessions-autofill() {
reply=( `tmux list-sessions -F '#{session_name}'` );
}
请注意,在我的原始帖子中,我使用sed
删除除会话名称之外的任何其他信息。但这次我使用了一个-F
参数来tmux
告诉仅有的打印会话名称,并跳过任何其他信息。
这对我来说很有用。希望这足够清楚了。