zsh 插件管理器 - Zinit

[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
    

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341