美文网首页
zsh 插件管理器 - Zinit

zsh 插件管理器 - Zinit

作者: Whyn | 来源:发表于2020-04-21 01:49 被阅读0次

    [TOC]

    前言

    Zinit 是一个灵活快速的 zsh 插件管理器,它可以自动安装 Github 或者其他网站上的 zsh 插件。

    特性

    • Zinit 是当前唯一提供 Turbo 模式的 zsh 插件管理器,该模式可以使 zsh 启动提速 50-80%。

    • Zinit 会打印插件加载时设置的aliasesfunctionsbindkeysZle widgetszstylescompleteionsvariablesPATHFPATH。这使得用户可以更快熟悉新插件同时在不同的场合下,提供了丰富且易于显示信息等有用功能。

    • 支持插件unloading和罗列功能,支持安装/卸载,有选择的禁止/启用插件补全功能。

    • Zinit 支持加载 Oh-My-Zsh 和 Prezto 插件和库,但是其实现不基于特定框架,不会让插件管理器膨胀这类代码(更多该部分内容,可查看:Introduction)。

    • 系统不使用$FPATH,加载拥有相同入口的多个插件时,不会混乱$FPATH。设置选项通常会引起兼容性问题,除了KSH_ARRAYS

    • Zinit 支持特殊,专用的为用户卸载冗长复杂命令的packages

    • Zinit 提供了特殊的 Zinit 扩展:annexes,通过 annexes 可以为插件管理器设置新的命令,URL 预处理器,安装后(post-install)/更新后(post-update)钩子...。

    安装

    Zinit 提供了自动安装和手动安装两种方法:

    • 自动安装:方法如下:(推荐)

      sh -c "$(curl -fsSL https://raw.githubusercontent.com/zdharma/zinit/master/doc/install.sh)"
      
    • 手动安装:步骤如下:

      1. 下载源码到~/.zinit/bin
      mkdir ~/.zinit
      git clone https://github.com/zdharma/zinit.git ~/.zinit/bin
      
      1. 添加如下内容到~/.zshrc最顶端:
      source ~/.zinit/bin/zinit.zsh
      
      1. 重新加载~/.zshrc
      source ~/.zshrc
      

    核心功能

    Zinit 的涉及到的内容很多,完全了解 Zinit 提供的功能其实没有必要,我们只需理解 Zinit 最核心的一些功能点即可。

    以下是本人认为的 Zinit 的核心功能,掌握下列内容,应当就可以基本使用 Zinit

    • 插件下载及加载:作为一个 zsh 的插件管理器,其基本功能就是插件下载及加载。插件的下载 / 加载基本使用方法如下:

      zinit load zdharma/history-search-multi-word
      zinit light zsh-users/zsh-syntax-highlighting
      

      以上两个命令是 Zinit 提供的两个基础插件加载配置,其中:

      • load:表示使能插件追踪功能。使用该关键字后,Zinit 会记录相关插件启动的信息,并提供如下功能:

        • zinit report {plugin-spec}:查看插件信息
        • zinit unload {plugin-spec}:卸载插件
      • light:表示关闭插件追踪功能。当使用该关键字后,Zinit 不会对插件加载信息进行追踪,也就不具备查看和卸载插件的功能,但正如其名称一致,它提供了一个轻量级插件加载功能,加载插件速度会非常快。

      :在 Turbo 模式下,load引起的插件追踪导致的加载缓慢几乎是微不足道的。

    • ice 修饰符(Ice-Modifiers)Zinit 内置了很多ice修饰符用于为下一条zinit命令添加额外的描述信息。
      见名知意,所谓ice,表示的就是添加一些东西(比如往饮料里添加冰块(ice)),同时冰块(ice)易融化,表示使用ice修饰的信息仅仅只对下一条zinit命令起作用。

      ice修饰符提供的额外信息描述可分为如下几大项:

      • 下载选项(Cloning Options):涵盖的描述符有:protofromverbpickdepthcloneoptssvn
      • 文件选择(Selection of Files):涵盖的描述符有:picksrcmultisrc
      • 加载限定(Conditional Loading):涵盖的描述符有:waitloadunloadcloneonlyifhassubscribe / on-update-oftrigger-load
      • 插件输出(Plugin Output):涵盖的描述符有:silentlucidnotify
      • 补全(Completions):涵盖的描述符有:blockfnocompletions
      • 下载 / 更新 / 加载时的命令执行(Command Execution After Cloning, Updating or Loading):涵盖的描述符有:mvcpatcloneatpull,atinitatloadrun-atpullnocdmakecountdownreset
      • Shell 仿真(Sticky-Emulation Of Other Shells):涵盖的描述符有:sh / !shbash / !bashksh / !kshcsh / !csh
      • 其他(Others)asid-ascompilenocompileservicereset-promptbindmaptrackbindswrap-trackaliaseslight-modeextract

      完整的ice描述符相关内容可查看:Ice Modifiers

      以下简单对几个较常用的ice修饰符进行介绍:

      • as:表示下载插件的意图,通常有如下 3 个选项:

        • as"progrma":也可以写为as"command",就是将下载的插件作为命令使用。当插件下载完成后,会自动将插件脚本/命令(通常由pick指定)自动添加到系统环境变量$PATH中。
        • as"completion":表示将插件或者单文件脚本(以下划线_*开始的文件)作为补全文件。
        • as"null":即pick"/dev/null" nocompletions的简写,表示取消默认的source操作和自动补全安装。
      • from:指定插件下载网址。支持的网址有:from"github"(默认),..."github-rel"..."gitlab"..."bitbucket"..."notabug"(其各自对应的简写为:ghgh-rglbbnb),也可以是一个完整的域名。比如:

        zinit ice from"gh-r" as"program"
        zinit load junegunn/fzf-bin
        

        上述命令会到 Github-release 页面下载junegunn/fzf-bin的可执行文件,并自动解压。

        from不支持 snippet 操作。

      • bpick:用于指定在 GitHub Releases 页面下载的具体文件(依据正则表达式进行选取)。比如:

        zinit ice from"gh-r" as"program" bpick"*linux*"
        zinit load docker/compose
        

        上述命令会在 Github-release 页面下载名称符合*linux*的文件(也就是 Linux 版本的安装文件),并自动进行解压。

        :通常无需自己指定bpick选项,因为 Zinit 会自动根据当前操作系统及其 CPU 架构自动下载合适的文件。
        bpick不支持 snippet 操作。

      • pick:选择要进行source或者作为命令的文件(当使用snippet --commandas"program"时)。pick选项使用正则匹配,对下载并解压完成的文件夹内的所有文件按字母表顺序进行排序,第一个符合条件的文件即为匹配文件。比如:

        zinit ice pick"powerless.zsh"
        zinit light martinrotter/powerless
        

        上述命令会下载插件martinrotter/powerlesspick指定了下载完成后会自动进行source powerless.zsh操作。

        pick还有另一个更常用的操作就是结合as"porgram"/as"command"操作,表示将pick指定的文件增加+x权限并添加到系统环境变量$PATH中。比如:

        zinit ice as"program" pick"httpstat.sh"
        zinit light b4b4r07/httpstat
        

        上述命令会下载插件b4b4r07/httpstat,由于指定了as"program",所以会将pick选项指定的文件作为可执行文件,此时 Zinit 会自动将httpstat.sh所在的目录添加到$PATH中。

        :使用as"program"时,对pick执行的文件,就不会进行source操作,而是作为命令使用,因此,通常会结合mv/cp等选项将可执行文件重命名,方便终端简化命令调用,比如对上述代码进行修改为如下:

        zinit ice as"program" cp"httpstat.sh -> httpstat" pick"httpstat"
        zinit light b4b4r07/httpstat
        

        当下载完成后,会首先进行cp操作,将插件根目录的httpstat.sh复制一份为httpstat,然后pick选项生效,为httpstat添加可执行权限并添加到$PATH中。如此终端就可以直接使用httpstat命令了。

      • src:指定额外文件进行source。当pick指定的主文件source完成或添加到$PATH后,会对src指定的文件进行source操作。

        zinit ice pick"powerless.zsh" src"utilities.zsh"
        zinit light martinrotter/powerless
        

        上述命令在powerless.zsh进行source操作后,还会执行source utilities.zsh操作。

        src 不支持正则匹配,而是直接以原意进行匹配。

      • multisrc:支持指定多个文件进行source操作。多个文件以空格进行分割,或者以大括号进行分割。比如:

        zinit ice svn pick"completion.zsh" multisrc'git.zsh \
            functions.zsh {history,grep}.zsh'
        zinit snippet OMZ::lib
        

        上述命令在下载完成 Oh-My-Zshlib插件后,会先进行source completion.zsh操作,然后还会对git.zshfunctions.zshhistory.zshgrep.zsh进行source操作。

        multisrc 支持正则匹配。

      • load:当满足条件时,加载插件。插件只会加载一次,当下次条件再次满足时,不会触发再次加载(除非插件已被卸载unload)。

      • unload:当满足条件时,卸载插件。插件只会卸载一次,当下次条件再次满足时,不会触发再次卸载(除非插件已被再次加载load)。

        # Load when in ~/tmp
        zinit ice load'![[ $PWD = */tmp* ]]' unload'![[ $PWD != */tmp* ]]' \
            atload"!promptinit; prompt sprint3"
        zinit load psprint/zprompts
        
        # Load when NOT in ~/tmp
        zinit ice load'![[ $PWD != */tmp* ]]' unload'![[ $PWD = */tmp* ]]'
        zinit load russjohnson/angry-fly-zsh
        
      • 插件生命周期(life-cycle)Zinit 中,插件加载会经历四个生命周期:下载(clone)-> 更新(update)-> 初始化(init)-> 加载(load)。每个周期 Zinit 都为我们提供了相应的钩子(hook)方便我们在相应的插件生命周期内执行一些额外命令,具体钩子如下:

        1. atclone:插件下载完成(git clone)后,执行相应的命令。
        2. atpull:插件更新完成(git pull)后,执行相应的命令。
        3. atinit:插件加载前,执行初始化命令。
        4. atload:插件加载完成后,执行相应的命令。如果采用zinit load方式加载插件,则此时atload"!{command}"会对插件加载过程进行检测。
        zinit ice from"gh-r" as"program" bpick"*amd64*.deb" pick"usr/bin/bat" \
            atclone"echo clone"                                               \
            atpull"echo update"                                               \
            atinit"echo init"                                                 \
            atload"echo load"
        zinit light sharkdp/bat
        
      • mv:在下载(git clone)或者更新(git pull)完成后,进行mv操作。比如:mv "fzf-* -> fzf"

      • cp:在下载(git clone)或者更新(git pull)完成后,进行cp操作。比如:cp "docker-c* -> dcompose"

      • make:在下载(git clone)/ 更新(git pull)完成后,以及mvcpatpullatclone操作完成后,执行make命令,编译源码。make选项可添加参数信息,比如:make"install PREFIX=/opt"。如果make选项以!开头(make'!'),那么其会先于atclone/atpull运行。

      zinit ice as"program" atclone"rm -f src/auto/config.cache; ./configure" \
          atpull"%atclone" make pick"src/vim"
      zinit light vim/vim
      

      上述命令使用 Zinit 下载 Vim 源码并进行编译安装。当插件vim/vim下载完成后,会触发atclone钩子,此时会执行rm -f src/auto/config.cache; ./configure操作,然后执行make操作,编译 Vim 源码,此时src文件就会生成可执行文件vim,最后通过pick选项将make生成的vim添加到$PATH中。当插件更新完成后,会触发atpull操作,%atclone表示执行的命令与atclone一致,最后会再次触发make操作,对更新后的源码进行编译。

      • reset:在插件更新(git pull)前,执行git reset --hard HEAD(或者svn revert)操作,将插件恢复到上一次初始状态,目的是为了避免插件更新引起的可能冲突(conflict)。对于使用gh-r下载的插件,会执行rm -rf *操作,直接删除所有旧文件。

      • wait:用于插件(或脚本文件)延迟加载。其使用有如下几种方式:

        • wait'<number>':表示在控制台启动 number 毫秒后,加载插件。比如:

          zinit ice wait'1' 
          zinit light wfxr/forgit
          

          上述命令表示在控制台(prompt)启动 1s 后,加载插件wfxr/forgit

          :不附带数值的wait相当于wait'0',表示控制台启动后立即加载插件。

        • wait’[[ ... ]]‘/wait'(( ... ))':当满足条件时,加载插件。比如:

          zinit ice wait'[[ $PWD = */github || $PWD = */github/*  ]]'
          zinit load unixorn/git-extra-commands '
          

          上述命令在用户进入github目录时,会自动加载插件unixorn/git-extra-commands

        • wait'!...'!表示当加载插件完成后,重置控制台。通常用于主题插件的加载。

      zsh 在使用wait描述符延迟加载插件后,其启动速度可提升 80%。

    ice描述符的执行顺序为:atinit -> atpull! -> make'!!' -> mv -> cp -> make! -> atclone/atpull -> make -> (plugin script loading) -> src -> multisrc -> atload'

    • Turbo Mode (Zsh >= 5.3)Zinit 中所谓的 Turbo Mode,其实就是插件延迟加载功能,更确切的说,就是使用ice修饰符的wait选项进行插件加载。比如:

      PS1="READY > "
      zinit ice wait'!0'
      zinit load halfo/lambda-mod-zsh-theme
      

      上述命令表示终端在加载完成.zshrc文件并成功显示第一个控制台时,加载插件halfo/lambda-mod-zsh-theme。实际上插件真正进行加载大约是在提示符READY >出现后的 1ms 内。
      我们一般不会用以上方法加载提示符,但此处作为直接观察 Turbo 模式却是一个不错的方法。

    • Zinit 命令(Zinit Commands)Zinit 提供了在终端进行操作的一些命令,比如:

      # 加载插件
      $ zinit load {plg-spec}
      
      # 加载插件,不打印加载信息
      $ zinit light [-b] {plg-spec}
      
      # 加载单文件,-f 表示不使用缓存,即强制重新下载
      $ zinit snippet [-f] {url}
      
      # 卸载插件,-q 表示 quiet
      $ zinit unload [-q] {plg-spec}
      
      # 显示插件加载时间,以插件加载顺序排序。-s 表示以秒进行显示(默认毫秒),-m 表示显示插件加载时刻
      $ zinit times [-s] [-m]
      
      # 显示 Zinit 状态
      $ zinit zstatus
      
      # 显示插件加载状态,--all 表示显示所有插件
      $ zinit report {plg-spec} | --all
      
      # 显示已加载的插件(使用关键字进行过滤)
      $ zinit loaded [keyword],list [keyword]
      
      # 显示每个插件的设置的按键绑定
      $ zinit bindkeys
      
      # 编译插件
      $ zinit compile {plg-spec} | --all
      
      # 移除已编译的插件
      $ zinit uncompile {plg-spec} | --all
      
      # 显示已编译的插件
      $ zinit compiled
      
      # 更新 Zinit
      $ zinit self-update
      
      # 更新插件/脚本,--all 表示更新所有插件/脚本,-q 表示静默更新,-r | --reset 更新前执行 git reset --hard / svn revert
      $ zinit update [-q] [-r] {plg-spec} | URL | --all
      
      # 为下一条 zinit 命令添加 ice 描述符
      $ zinit ice <ice specification>
      
      # 磁盘删除插件/脚本,--all 表示清除,--clean 表示删除未加载的插件/脚本
      $ zinit delete {plg-spec} | URL | --clean | --all
      
      # 进入插件目录
      $ zinit cd {plg-spec}
      

      更多 Zinit 内置命令,请参考:zinit-commands

    其他

    以下是 Zinit 提供的另外一些有用的特性以及一些本人觉得好用的操作:

    • 单文件加载:比如对于 Oh-My-Zsh 和 Prezto 插件,可以通过snippet修饰符来指定插件的 URI,Zinit 会自动下载并加载。如下所示:
    zinit snippet 'https://github.com/robbyrussell/oh-my-zsh/raw/master/plugins/git/git.plugin.zsh'
    zinit snippet 'https://github.com/sorin-ionescu/prezto/blob/master/modules/helper/init.zsh'
    

    snippet表示通过curlwget下载的单文件脚本。
    对于 Oh-My-Zsh 和 Prezto,Zinit 提供了相应的简写方式:

    # OMZ:: 表示 Oh My Zsh 插件
    zinit snippet OMZ::plugins/git/git.plugin.zsh
    # PZT:: 表示 Prezto 插件
    zinit snippet PZT::modules/helper/init.zsh
    
    • 多文件加载snippet支持Subversion协议,Github 同样也支持该协议。因此,如果使用的是Subversion协议,那么snippet则支持 多文件加载(比如,一个 Prezto 模块可以包含两个或以上文件,比如init.zshalias.zsh)。默认会进行加载的文件为:*.plugin.zshinit.zsh*.zsh-theme
    # URL points to directory
    zinit ice svn
    zinit snippet PZT::modules/docker
    
    • 附件(Annexes)Zinit 附件即 Zinit 扩展(Zinit Extensions),其作用是为 Zinit 增加一些子命令(subcommand),增加更多新的ice修饰符选项以及注册atcloneatpullatinitatload钩子函数...比如:
    # Load a few important annexes, without Turbo
    # (this is currently required for annexes)
    zinit light-mode for           \
        zinit-zsh/z-a-patch-dl     \
        zinit-zsh/z-a-as-monitor   \
        zinit-zsh/z-a-bin-gem-node
    

    上述命令就安装了 3 个比较重要的附件:z-a-patch-dlz-a-as-monitorz-a-bin-gen-node

    • For 语法(The For-Syntax):相对于经典的ice语法,For 语法提供了更加紧凑,优化的语法结构。比如:
    zinit as"null" wait"3" lucid for              \
        sbin"recall"  Fakerr/git-recall           \
        sbin  paulirish/git-open                  \
        sbin  paulirish/git-recent                \
        sbin  davidosomething/git-my              \
        make"PREFIX=$ZPFX install"  iwata/git-now \
        make"PREFIX=$ZPFX"          tj/git-extras
    

    上述单一一条命令就安装了 6 个插件,并且所有插件共享基础ice选项:as"nullwait"3"lucid,可以看到,For 语法确实简洁许多。

    sbin描述符是由附件 z-a-bin-gem-node 提供的,sbin选项的作用在于无需更改$PATH就可以在命令行中直接使用其指定的命令。如果命令与插件名称相同,可省略不写。

    • atpull"…"atpull属性在插件更新的时候会被触发。通常在更新插件的时候,拷贝文件是安全操作:因为仓库初始文件是不会被修改的,因此 Git 不会报告冲突。但是,移动mv文件就不一定了,此时,就可结合atpull属性:

      zinit ice as"program" mv"httpstat.sh -> httpstat" \
      pick"httpstat" atpull'!git reset --hard'
      zinit light b4b4r07/httpstat
      
    • 无冲突更新:如果atpull以感叹号开头,那么它会在git pullmv命令执行之前运行。但是,atpullmvcp只在抓取到新提交commit的时候才会运行。
      因此,对于上述命令,如果用户执行zinit update b4b4r07/httpstat命令更新插件,如果该插件抓取到新的commit,那么首先就会执行git reset --hard,重新恢复初始文件httpstat.sh,然后就执行git pull,拉取新commit(使用fast-forward模式),成功后就会执行mv命令,将httpstat.sh修改为httpstat。以这种方式就可以在无须阻塞git更新的同时,使用mv命令永久更新插件内容。

    • 脚本命令(Snippets-Commands):可以将脚本的命令直接添加到$PATH中:
    zinit ice mv"httpstat.sh -> httpstat" \
    pick"httpstat" as"program"
    zinit snippet \
    https://github.com/b4b4r07/httpstat/blob/master/httpstat.sh
    
    • 编译程序(Compiling Programs):典型的场景就是从 github 下载源码进行编译,比如运行./configure/make等命令,则此时可以使用ice修饰符,通过pick选择需要添加到$PATH的二进制程序,通过make选项执行 make 操作...例子如下:
    zinit ice as"program" atclone"rm -f src/auto/config.cache; ./configure" \
        atpull"%atclone" make pick"src/vim"
    zinit light vim/vim
    

    上述命令中的各个参数含义如下:

    • as"program":表示结果为一个可执行文件(命令),因此不会进行source操作,而是直接把 Zinit 会把pick指定的二进制文件添加到$PATH中。
    • atclone"...":表示下载(git clone)完成后,需要执行的命令。
    • atpull"%atclone":表示更新(git pull)完成后,执行atclone''指定的命令。
    • make:在atcloneatpull操作后,执行make操作(:如果是make '!',那么表示的是在进行atcloneatpull之前先执行make操作)。
    • pick"src/vim":表示编译完成后生成的可执行文件为src/vim,则意味着 Zinit 会把src目录添加到$PATH中。

    如果需要执行的是make install操作,则只需将make修改为make"all install"

    如果编译(make)完成后,需要进行source操作,则使用src选项,比如:

    zinit ice as"program" make'!' atclone'./direnv hook zsh > zhook.zsh' \
        atpull'%atclone' src"zhook.zsh"
    zinit light direnv/direnv
    

    上述命令在git clonegit pull完成之前会先执行make操作,然后执行./direnv hook zsh > zhook.zsh,生成zhook.zsh目标文件,最后再进行source zhook.zsh操作。这样子就确保了命令./direnv hook zsh只在git clonegit pull时才执行,其他情况不响应,因此 zsh 可以更快启动。

    • 脚本补全(Snippets-Completions):通过使用as"completion",可以让snippet命令直接加载一个补全文件:
    zinit ice as"completion"
    zinit snippet https://github.com/docker/cli/blob/master/contrib/completion/zsh/_docker
    
    • 补全管理(Completion Management)Zinit 允许为每个插件指定各自补全的禁止/启用。比如安装一个流行的提供补全的插件:
    zinit ice blockf
    zinit light zsh-users/zsh-completions
    

    第一条命令中的blockf指令会阻断传统的补全添加方式,Zinit 会使用自己的方式(基于符号链接而不是添加多个目录到$fpath)。
    Zinit 会自动安装新下载插件的补全。如果要卸载补全然后再重新安装,方法如下:

    zinit cuninstall zsh-users/zsh-completions   # uninstall
    zinit creinstall zsh-users/zsh-completions   # install
    
    • 列举补全(Listing Completions):查看所有插件提供的补全,方法如下:
    zi clist
    

    默认情况下,上述命令每行会显示插件的 3 个补全,也可以通过为clist添加参数指定补全显示个数,比如:

    zi clist 6 # 每行显示 6 个补全
    
    • 启用/禁用补全(Enabling and Disabling Completions):启用/禁止补全只需提供补全的名字:
    $ zi cdisable cmake
    Disabled cmake completion belonging to zsh-users/zsh-completions
    $ zi cenable cmake
    Enabled cmake completion belonging to zsh-users/zsh-completions
    
    • 补全搜索zinit csearch命令会对所有插件目录进行补全搜索,列举所有可用补全,并显示其安装状态。
    zinit csearch
    • 子目录 SVN 支持(Subversion for Subdirectories):通常,如果要使用 Github 项目的某个子目录作为 snippet,那么可以为 URL 添加/trunk/{path-to-dir},比如:
    zinit ice svn
    zinit snippet https://github.com/zsh-users/zsh-completions/trunk/src
    
    # For Oh My Zsh and Prezto, the OMZ:: and PZT:: prefixes work
    # without the need to add the `/trunk/` infix (however the path
    # should point to a directory, not to a file):
    zinit ice svn; zinit snippet PZT::modules/docker
    

    snippet 也会像插件下载一样,自动安装其补全。

    • 使用 Oh-My-Zsh 主题Zinit 并没有直接提供加载 Oh-My-Zsh 框架的功能,但是我们可以通过snippet命令来加载单独的插件。
      Oh-My-Zsh 的部分插件 / 主题会依赖 Oh-My-Zsh 本身提供的一些功能,比如常用的 git 库和 git 插件,则在.zshrc中进行如下配置即可:
      # Load OMZ Git library
      zinit snippet OMZL::git.zsh
      
      # Load Git plugin from OMZ
      zinit snippet OMZP::git
      
      如果想使用 Oh-My-Zsh 主题,由于 OMZ 大多数主题都要求promptsubst选项,否则可能出现类似... $(build_prompt) ...的错误,因此,还需配置如下内容:
      setopt promptsubst
      
      如果想禁止 OMZ 的 git 插件提供的补全信息,可进行如下配置:
      zinit cdclear -q
      
      综上,如果想使用 Oh-My-Zsh 主题,完整的配置如下:
      # Load OMZ Git library
      zinit snippet OMZL::git.zsh
      
      # Load Git plugin from OMZ
      zinit snippet OMZP::git
      zinit cdclear -q # <- forget completions provided up to this moment
      
      setopt promptsubst
      
      # Load theme from OMZ
      # zinit snippet OMZT::gnzh
      
      # Load normal GitHub plugin with theme depending on OMZ Git library
      # zinit light NicoSantangelo/Alpharized
      

    参考

    相关文章

      网友评论

          本文标题:zsh 插件管理器 - Zinit

          本文链接:https://www.haomeiwen.com/subject/zaeeihtx.html