尝试替换 omz + p10k

r/unixporn has its charms, but my passion lies in simplicity.

oh-my-zsh 和「Lean style」的 powerlevel10k 一直是笔者若干年内的开箱设置,简洁但是 well-polished,未有不适之处。p10k 实现的 instant prompt 从结果上看解决了性能问题,体验不错。 但偶尔也会有一些疑虑:

发行模式? #

两者的安装方式均为直接从对应仓库的主分支检出代码,引入到 zshrc 中即可使用。这种「滚动发行」的模式是很健康的:每条提交下均处于稳定状态,最新最热特性和 regression fix 都能及时 deliver 到用户。

笔者不喜欢自更新所以一向是给关掉的,配好后大抵是再没动过,倒也未见明显 breakage;但由于纯 shell scripts 无需构建,打 -git 包远不如直接操作仓库来得方便,更何况不去审阅提交历史也未必能确认当前 revision 是否处于理想的稳定状态,实则不如按需更新,没坏就算好的。

…对吗?能用两三年而没有遇到问题,自觉只是因为日常使用仅依赖其中极小部分 feature set,而且以前有踩过坑,对于这其中 omz 的行为变更是有了解一些的。

行为变更? #

话虽如此,即便笔者并无成为 shell 中级高手的意愿,但在根源问题上却有些执念:zsh 语法与 bourne shell / bash 之异同,所使用的 keybinding 是在哪一层引入或支持,诸如此类。

以及,即便 p10k 用比较 hacky 的方式实现了 instant prompt 使得启动体验相当顺手,是否有必要为 omz 及 p10k 中不必要的特性带来的性能开销买单?归根到底,p10k 只是提供一个可用的 $PS1,所依赖的 omz 特性可以摘取对应 snippet 到自己的 zshrc 中,也便于 clarify 和固定形成确定行为,同时降低风险。

风险? #

p10k 有个令人非常不爽的行为,默认自动下载并后台运行 gitstatusd,用于显示仓库状态。虽然笔者信任 p10k 的作者并持续使用至今,也曾阅读过代码,但行为上这与恶意程式从 C2 server 下载运行 payload 别无二致。

Attempt #1 #

上次更换电脑时便有过一次尝试,基本探明了目前设置下所依赖的行为来源。列举如下:

zsh 插件 #

zsh-completion
zsh-autosuggestions
zsh-syntax-highlighting
git-extras

keybindings + completions #

debian zshrc
omz completion.zsh
omz key-bindings.zsh

word selection #

autoload -U select-word-style
select-word-style bash

pager #

export PAGER="less"
export LESS="-R"

term title #

https://superuser.com/a/1328085

chpwd() {
  [[ -t 1 ]] || return
  case $TERM in
    sun-cmd) print -Pn "\e]l%n@%m: %~\e\\"
      ;;
    *xterm*|rxvt|(dt|k|E)term) print -Pn "\e]2;%n@%m: %~\a"
      ;;
  esac
}

PS1 #

PS1='%B%F{cyan}%~ %(?.%F{green}.%F{red})>%f%b '
chpwd

最终拼凑成一份可用的 zshrc,基本能够 mimic 先前的 omz setup,但是没有想好类似 p10k 的仓库状态显示如何简单实现,因此一直搁置。

Attempt #2 #

互联网冲浪时了解到 starship,其用户出现在身边统计学中,且 DebianArch Linux 均有打包,尝试后发现确能完成最后一块拼图。

除去基本的 TOML syntax,写法上就是 format = '[$var1..$varN]($style)' 的格式,参见 Format Strings 文档。此外,format 中未使用的 module 不会被加载,因此不必逐个禁用,避免使用 $all 按需引入即可。

浪费数小时调整后形成初步配置如下,不依赖各种 fancy 的自定字体,基本保持原先风格。顺便吐槽 starship 内置一堆 presets,但就不提供显式列出所有默认配置的文件。文档本身还算全面,但是来回复制粘贴修改配置实在算不上愉快的体验 :(

"$schema" = 'https://starship.rs/config-schema.json'

add_newline = false
continuation_prompt = '[.](bright-black) '

format = '$directory$git_branch$git_state$git_status$character'
right_format = '$python$cmd_duration$status'

[cmd_duration]
format = '[$duration]($style)'
style = 'dimmed grey'

[character]
success_symbol = '[>](bold green)'
error_symbol = '[>](bold red)'
vimcmd_symbol = '[<](bold green)'
vimcmd_visual_symbol = '[<](bold yellow)'
vimcmd_replace_symbol = '[<](bold purple)'
vimcmd_replace_one_symbol = '[<](bold purple)'

[git_branch]
symbol = ''
truncation_symbol = '...'

[git_state]
rebase = 'rebase'
merge = 'merge'
revert = 'revert'
cherry_pick = 'pick'
bisect = 'bisect'
am = 'am'
am_or_rebase = 'am/rebase'
style = 'bold red'
format ="[$state( $progress_current/$progress_total)]($style) "

[git_status]
format = '$conflicted$ahead_behind$stashed$modified$staged$untracked'
conflicted = '[~${count}](red) '
ahead = '[>${count}](green) '
behind = '[<${count}](green) '
diverged = '[<${behind_count}>${ahead_count}](green) '
untracked = '[?${count}](blue) '
stashed = '[*${count}](green) '
modified = '[!${count}](yellow) '
staged = '[+${count}](yellow) '
renamed = ''
deleted = ''
style = 'bold green'
use_git_executable = true

[directory]
read_only = ' !w'
truncate_to_repo = false
truncation_length = 2
fish_style_pwd_dir_length = 1

[status]
disabled = false
symbol = ' [!](bold red)'
not_executable_symbol = 'noexec'
not_found_symbol = 'notfound'
sigint_symbol = 'sigint'
signal_symbol = 'sig'

[python]
format = '[${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'