关于 shell-prompt
shell-prompt 是一份面向 Zsh 用户的 Shell 提示符与 Vi 模式配置指南,涵盖 Powerlevel10k 设置及性能调优。它还整理了插件选择、按模式变化的光标反馈和常见问题排查。
主要功能
- 01配置 Powerlevel10k 提示符
- 02显示 Git 状态与环境信息
- 03设置 Zsh Vi 模式及光标
- 04调整按键超时与快捷键
- 05排查性能和插件加载问题
适用场景
- 01在 Zsh 提示符中查看分支和环境状态
- 02为 Vi 编辑模式配置光标反馈
- 03缩短提示符启动和更新耗时
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ julianobarbosa/ claude-code-skills --skill shell-prompt安装后在 Claude Code 中输入/shell-prompt确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/performance-tuning.mdpowerlevel10k-config.mdstarship-config.mdtroubleshooting.mdzsh-vim-mode.mdscripts/benchmark-prompt.zsh详细介绍
Shell 提示符技能
使用 Powerlevel10k 和 Zsh Vi Mode 配置高性能 Shell 提示符。
概述
现代 Shell 提示符可提供:
- Git 状态,包括分支、工作区是否有未提交更改以及远程跟踪信息
- 环境指示器(Python 虚拟环境、Node 版本、K8s 上下文)
- 长时间运行命令的执行时间
- 退出代码可视化
- 异步更新,带来流畅响应的体验
- Vi 模式指示器和光标变化
Zsh Vi Mode
Zsh 支持 Vi 风格的行编辑,并通过光标变化和模式指示器提供视觉反馈。
快速设置(内置)
# ~/.zshrc
bindkey -v # Enable vi mode
# Reduce key timeout for faster mode switching (default 400ms)
export KEYTIMEOUT=10 # 100ms - don't go below 10
按模式设置光标样式
根据当前模式更改光标形状:
# Add to ~/.zshrc
cursor_mode() {
# Beam cursor for insert mode
cursor_beam='\e[6 q'
# Block cursor for normal mode
cursor_block='\e[2 q'
function zle-keymap-select {
if [[ ${KEYMAP} == vicmd ]] ||
[[ $1 = 'block' ]]; then
echo -ne $cursor_block
elif [[ ${KEYMAP} == main ]] ||
[[ ${KEYMAP} == viins ]] ||
[[ ${KEYMAP} = '' ]] ||
[[ $1 = 'beam' ]]; then
echo -ne $cursor_beam
fi
}
zle-line-init() {
echo -ne $cursor_beam
}
zle -N zle-keymap-select
zle -N zle-line-init
}
cursor_mode
光标转义码
| 代码 | 样式 |
|---|---|
\e[1 q | 闪烁块状光标 |
\e[2 q | 稳定块状光标 |
\e[3 q | 闪烁下划线 |
\e[4 q | 稳定下划线 |
\e[5 q | 闪烁竖线/光束 |
\e[6 q | 稳定竖线/光束 |
Vi 模式插件
Oh My Zsh vi-mode 插件
# ~/.zshrc
plugins=(... vi-mode)
# Configuration (before sourcing oh-my-zsh.sh)
VI_MODE_SET_CURSOR=true
VI_MODE_RESET_PROMPT_ON_MODE_CHANGE=true
# Cursor styles (0-6)
VI_MODE_CURSOR_NORMAL=2 # Solid block
VI_MODE_CURSOR_INSERT=6 # Solid beam
VI_MODE_CURSOR_VISUAL=6 # Solid beam
VI_MODE_CURSOR_OPPEND=0 # Blinking block
# Mode indicators
MODE_INDICATOR="%F{red}<<<NORMAL%f"
INSERT_MODE_INDICATOR="%F{green}<<<INSERT%f"
softmoth/zsh-vim-mode
功能全面的 Vi 模式,支持文本对象和环绕绑定。
安装:
# Clone
git clone https://github.com/softmoth/zsh-vim-mode.git ~/.zsh/zsh-vim-mode
# Source in .zshrc (after other plugins)
source ~/.zsh/zsh-vim-mode/zsh-vim-mode.plugin.zsh
加载顺序很重要: zsh-autosuggestions -> zsh-syntax-highlighting -> zsh-vim-mode
配置:
# Cursor styles (supports colors!)
MODE_CURSOR_VIINS="#00ff00 blinking bar"
MODE_CURSOR_VICMD="green block"
MODE_CURSOR_REPLACE="red block"
MODE_CURSOR_SEARCH="#ff00ff steady underline"
MODE_CURSOR_VISUAL="$MODE_CURSOR_VICMD steady bar"
MODE_CURSOR_VLINE="$MODE_CURSOR_VISUAL #00ffff"
# Mode indicators (auto-added to RPS1 if unset)
MODE_INDICATOR_VIINS='%F{15}<%F{8}INSERT>%f'
MODE_INDICATOR_VICMD='%F{10}<%F{2}NORMAL>%f'
MODE_INDICATOR_REPLACE='%F{9}<%F{1}REPLACE>%f'
MODE_INDICATOR_SEARCH='%F{13}<%F{5}SEARCH>%f'
MODE_INDICATOR_VISUAL='%F{12}<%F{4}VISUAL>%f'
MODE_INDICATOR_VLINE='%F{12}<%F{4}V-LINE>%f'
# Other options
VIM_MODE_VICMD_KEY='^[' # Default escape key
VIM_MODE_TRACK_KEYMAP=true # Enable mode tracking
VIM_MODE_INITIAL_KEYMAP=viins # Start in insert mode
功能:
- 文本对象:
ci"、da(、vi[ - 环绕:
cs"'(将外围的 " 改为 ') - 可视模式选择
- 插入模式下的 Emacs 绑定(Ctrl-A、Ctrl-E)
jeffreytse/zsh-vi-mode
支持运算符待定模式的现代 Vi 模式。
安装:
# With zinit
zinit ice depth=1
zinit light jeffreytse/zsh-vi-mode
# Manual
git clone https://github.com/jeffreytse/zsh-vi-mode.git ~/.zsh/zsh-vi-mode
source ~/.zsh/zsh-vi-mode/zsh-vi-mode.plugin.zsh
配置:
# Cursor styles
ZVM_NORMAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK
ZVM_INSERT_MODE_CURSOR=$ZVM_CURSOR_BEAM
ZVM_VISUAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK
ZVM_VISUAL_LINE_MODE_CURSOR=$ZVM_CURSOR_BLOCK
ZVM_OPPEND_MODE_CURSOR=$ZVM_CURSOR_UNDERLINE
# Mode indicator in prompt
function zvm_after_select_vi_mode() {
case $ZVM_MODE in
$ZVM_MODE_NORMAL)
# Update prompt for normal mode
;;
$ZVM_MODE_INSERT)
# Update prompt for insert mode
;;
$ZVM_MODE_VISUAL)
# Update prompt for visual mode
;;
esac
}
# Disable cursor style changes (if using another method)
ZVM_CURSOR_STYLE_ENABLED=false
按键绑定参考
模式切换
| 按键 | 操作 |
|---|---|
ESC 或 Ctrl-[ | 进入普通模式 |
i | 在光标前插入 |
a | 在光标后追加 |
I | 在行首插入 |
A | 在行尾追加 |
v | 进入可视模式 |
V | 进入可视行模式 |
导航(普通模式)
| 按键 | 操作 |
|---|---|
h/l | 左/右 |
j/k | 在历史记录中向下/向上 |
w/W | 向前移动一个单词 |
b/B | 向后移动一个单词 |
e/E | 移至单词末尾 |
0 | 移至行首 |
^ | 移至首个非空白字符 |
$ | 移至行尾 |
f{char} | 向前查找字符 |
F{char} | 向后查找字符 |
t{char} | 向前移至字符前 |
T{char} | 向后移至字符前 |
编辑(普通模式)
| 按键 | 操作 |
|---|---|
x | 删除字符 |
dd | 删除整行 |
D | 删除至行尾 |
cc | 修改整行 |
C | 修改至行尾 |
yy | 复制整行 |
p/P | 在后方/前方粘贴 |
u | 撤销 |
Ctrl-r | 重做 |
文本对象
| 按键 | 操作 |
|---|---|
ciw | 修改单词内部 |
daw | 删除一个单词(包括空格) |
ci" | 修改引号内的内容 |
da( | 删除括号及其内容 |
vi[ | 选择方括号内的内容 |
KEYTIMEOUT 注意事项
KEYTIMEOUT 变量会影响多键序列:
# Default is 40 (400ms)
export KEYTIMEOUT=10 # 100ms - good balance
# Too low (<10) breaks multi-key bindings
# Too high (>40) feels sluggish on ESC
消除转义延迟的方法:
# Option 1: Use Ctrl-[ instead of Escape
# (Ctrl-[ sends ESC immediately)
# Option 2: Bind jk or jj to escape
bindkey -M viins 'jk' vi-cmd-mode
bindkey -M viins 'jj' vi-cmd-mode
Powerlevel10k
安装
# With Oh My Zsh
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
# Set in .zshrc
ZSH_THEME="powerlevel10k/powerlevel10k"
# Run configuration wizard
p10k configure
即时提示设置
在 ~/.zshrc 的最顶部(其他任何内容之前)添加:
# Enable Powerlevel10k instant prompt
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
在 ~/.zshrc 的末尾添加:
# Source Powerlevel10k config
[[ -f ~/.p10k.zsh ]] && source ~/.p10k.zsh
配置选项
~/.p10k.zsh 中的关键设置:
# Left prompt segments
typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(
os_icon
dir
vcs
newline
prompt_char
)
# Right prompt segments
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(
status
command_execution_time
background_jobs
virtualenv
kubecontext
azure
aws
vi_mode # Show vi mode indicator!
context
time
)
# Transient prompt (clean up previous prompts)
typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=always
# Directory truncation
typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_unique
typeset -g POWERLEVEL9K_SHORTEN_DIR_LENGTH=3
# Vi mode indicator styling
typeset -g POWERLEVEL9K_VI_INSERT_MODE_STRING=''
typeset -g POWERLEVEL9K_VI_COMMAND_MODE_STRING='NORMAL'
typeset -g POWERLEVEL9K_VI_MODE_NORMAL_FOREGROUND=0
typeset -g POWERLEVEL9K_VI_MODE_NORMAL_BACKGROUND=2
性能调优
# Disable slow segments
typeset -g POWERLEVEL9K_DISABLE_GITSTATUS=false # Keep enabled!
# Large repo optimization
typeset -g POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY=1000
# Async git status (default, don't change)
typeset -g POWERLEVEL9K_VCS_BACKENDS=(git)
# Reduce segment count for speed
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(status command_execution_time vi_mode)
性能总结
基准测试结果(zsh-bench)
| 指标 | 目标 | Powerlevel10k |
|---|---|---|
| 首次提示延迟 | <50ms | 24ms |
| 命令延迟 | <10ms | 15ms |
| Git 状态(小型) | <30ms | <10ms |
| Git 状态(大型) | <100ms | 异步/即时 |
架构
Powerlevel10k(gitstatus 守护进程):
┌─────────────┐ pipes ┌─────────────┐
│ Zsh │ <============> │ gitstatusd │
│ (prompt) │ │ (C++ daemon)
└─────────────┘ └─────────────┘
│ │
│ async │ keeps state
│ never blocks │ in memory
▼ ▼
Instant prompt Fast git queries
对设置进行基准测试
使用 zsh-bench
# Install
git clone https://github.com/romkatv/zsh-bench ~/zsh-bench
# Run benchmark
~/zsh-bench/zsh-bench
# Key metrics to watch:
# - first_prompt_lag_ms: <50ms ideal
# - command_lag_ms: <10ms ideal
手动计时
# Zsh startup time
time zsh -i -c exit
# Per-command timing
TIMEFMT='%*E seconds'
time (for i in {1..10}; do zsh -i -c 'print -P "$PROMPT"' >/dev/null; done)
故障排除
提示符缓慢
# Check segment timing
zsh -xv # Verbose trace
# Common culprits:
# - git_status in large repos
# - python/node version detection
# - cloud context (aws/azure/gcloud)
P10k:gitstatus 失败
# Reinstall gitstatusd
rm -rf ~/.cache/gitstatus
# Restart zsh
exec zsh
Vi 模式无法使用
# Verify vi mode is enabled
bindkey -l | grep vi
# Check current keymap
echo $KEYMAP
# Reset bindings
bindkey -v
光标未变化
- 确认终端支持光标转义码
- 检查是否定义了
zle-keymap-select:whence -f zle-keymap-select - 某些终端(如 Apple Terminal)对光标的支持有限
- 尝试使用 iTerm2 或 Alacritty,以获得完整支持
参考资料
- references/powerlevel10k-config.md - 完整的 P10k 配置
- references/zsh-vim-mode.md - softmoth/zsh-vim-mode 详情
- references/performance-tuning.md - 高级优化
- references/troubleshooting.md - 常见问题和解决方法
外部链接
- Powerlevel10k: https://github.com/romkatv/powerlevel10k
- softmoth/zsh-vim-mode: https://github.com/softmoth/zsh-vim-mode
- jeffreytse/zsh-vi-mode: https://github.com/jeffreytse/zsh-vi-mode
- Oh My Zsh vi-mode: https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/vi-mode
- zsh-bench: https://github.com/romkatv/zsh-bench
- gitstatus: https://github.com/romkatv/gitstatus
注意事项
- P10k 即时提示必须放在
.zshrc的最顶部,且前面不能有任何输出: 即使是echo或未加保护的command -v也会产生警告并禁用即时提示。将所有会输出到 stdout 的代码移到即时提示代码块之后,或用&>/dev/null包裹。 KEYTIMEOUT=1会导致jk这类多键绑定无法触发退出模式: 小于 10(100ms)时,zsh 无法区分先后输入的j、k和多字节 ESC 序列。表现为:在普通模式下,提示符会将j和k作为普通字符输入。bindkey -v会重置所有之前的绑定: 在bindkey -v之前创建的自定义绑定会被静默清除。应先设置 vi 模式,再调用所有自定义bindkey。- 在 tmux 中,光标转义码(
\e[6 q)必须启用透传才能生效: tmux 默认会剥除 DECSCUSR——在.tmux.conf中添加set -ga terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[ q',否则光标会一直显示为块状。 - gitstatusd 会按仓库缓存:在 zsh 外运行
git reset --hard会导致提示符显示过期信息: P10k 的守护进程尚未检测到变更。等待约 2 秒、手动运行git status,或运行p10k reload强制刷新。 - 插件加载顺序:zsh-vim-mode 应在 autosuggestions 和 syntax-highlighting 之后加载: 顺序颠倒会导致 vim-mode 覆盖 zle 小部件——表现可能包括光标变更失效或 ESC 无法使用。使用
zle -lL | grep widget-name检查。
评论
支持 Markdown