liuchengxu

liuchengxu 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织 www.liuchengxu.org/blog-cn 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

liuchengxu 发布了文章 · 1月27日

vim-clap: 高性能的现代化模糊查找插件

今天分享一下我至今为止写的最满意的一个 Vim 插件:https://github.com/liuchengxu/vim-clap, 它是一个用于模糊查找和搜索的 Vim 插件,在同类插件中最早同时支持 neovim 的floating_win和 vim 的popup, 这也是我造这个轮子的初衷之一。

在早期,作为一个纯 vimscript 实现的 Vim 插件,vim-clap 在进行大规模搜索时天然会有严重的性能问题,不过自从通过使用 Rust 对插件进行扩展以后,现在已经不存在有性能问题,可以轻松面对上百万的文件搜索。同时,vim-clap 也提供了二进制供直接下载,并且提供了方便的安装方式。如果使用 vim-plug:

" 本地编译 Rust 扩展,需要安装 cargo
Plug 'liuchengxu/vim-clap', { 'do': ':Clap install-binary' }

" 如果加上 !, 则当本地不存在 cargo 时, 直接下载 GitHub Release 上提供的二进制
Plug 'liuchengxu/vim-clap', { 'do': ':Clap install-binary!' }

v0.6 的一些新特性:

g:clap_layout

支持g:clap_layout控制窗口的弹出位置,现在的默认位置相对于唤出 clap 的所在窗口,大小也是相对于该窗口的大小。

g:clap_layout模拟的是 neovim 的 API, 如果希望打开位置相对于整个编辑器而不是所在窗口:

let g:clap_layout = { 'relative': 'editor' }

宽度更宽一点:

let g:clap_layout = { 'width': '95%', 'col': '5%' }

g:clap_theme

vim-clap 在 UI 上非常丰富,默认情况下是从用户的 colorscheme 中提取颜色,所以自适应于各种主题。但是即使是自适应,也无法保证对所有主题都适用,而且好像很多人不太会配置主题,所以 v0.6 内置了一个主题material_design_dark, 在自适应表现不好的情况下,可以使用内置主题:

let g:clap_theme = 'material_design_dark'

也可以改变material_design_dark的部分颜色, 比如将搜索文本改为红色:

let g:clap_theme = { 'search_text': {'guifg': 'red', 'ctermfg': 'red'} }

还有一些其他改进参见https://github.com/liuchengxu/vim-clap/releases/tag/v0.6, 比如新增loclistprovider, 很多 linter 可以将信息填充到 location list, 现在可以很方便的通过 vim-clap 进行过滤查看错误信息,同时支持预览功能:

很多其他特性就不一一介绍了,详情查看https://github.com/liuchengxu/vim-clap/blob/master/README.mdhttps://github.com/liuchengxu/vim-clap/blob/master/CHANGELOG.md

查看原文

赞 2 收藏 2 评论 0

liuchengxu 发布了文章 · 2019-04-13

使用 neovim 的浮动窗口让你再次爱上 fzf

fzf 是一个非常高效实用且美观的命令行工具,并且配置有对应的 vim 插件 fzf.vim, 相信很多人都用过。这里就不在赘述,如果你还没有用过,很推荐一试。

自从 neovim 的浮动窗口 PR https://github.com/neovim/neovim/pull/6619 被合到 master 以后,很多插件都利用了这个特性实现了很多很酷的功能,比如 coc.nvim,另外 vim-which-keyvista.vim 也利用了这一特性 。

浮动窗口的一个很大的特点就是不会像之前 split 的方式扰动你的窗口布局,晃动你的视线,而 fzf 也可以利用这一特性进一步提升体验!

比如下面这个效果图,我们可以让 fzf 在中间进行显示,有点类似于 IDEA 的搜索窗口:

fzf

fzf

要实现上面的效果,需要配置 3 个地方。首先是 2 个配置项:

    " 让输入上方,搜索列表在下方
    let $FZF_DEFAULT_OPTS = '--layout=reverse'

    " 打开 fzf 的方式选择 floating window
    let g:fzf_layout = { 'window': 'call OpenFloatingWin()' }

还有 1 个函数指定如何打开浮动窗口:

function! OpenFloatingWin()
  let height = &lines - 3
  let width = float2nr(&columns - (&columns * 2 / 10))
  let col = float2nr((&columns - width) / 2)

  " 设置浮动窗口打开的位置,大小等。
  " 这里的大小配置可能不是那么的 flexible 有继续改进的空间
  let opts = {
        \ 'relative': 'editor',
        \ 'row': height * 0.3,
        \ 'col': col + 30,
        \ 'width': width * 2 / 3,
        \ 'height': height / 2
        \ }

  let buf = nvim_create_buf(v:false, v:true)
  let win = nvim_open_win(buf, v:true, opts)

  " 设置浮动窗口高亮
  call setwinvar(win, '&winhl', 'Normal:Pmenu')

  setlocal
        \ buftype=nofile
        \ nobuflisted
        \ bufhidden=hide
        \ nonumber
        \ norelativenumber
        \ signcolumn=no
endfunction

关于浮动窗口的更多信息,可以 :help api-floatwin.

另外,如果你的浮动窗口设置高亮无效,看看是否有设置 g:fzf_colors,这可能会重置浮动窗口的高亮,有浮动窗口的话就不用设置了。

因为还没有 release, 目前要体验这个特性的话需要自己从 neovim master 编译,macOS 用户直接 安装 HEAD 版本的 neovim 就行了。安装好 neovim,然后进行如上配置应该就可以了,对于 https://github.com/liuchengxu/space-vim 用户直接升级 space-vim 即可。

查看原文

赞 4 收藏 3 评论 0

liuchengxu 发布了文章 · 2019-02-02

Vim 主题:space-vim-theme -- 支持 dark 和 light 两种背景

自从接触过 spacemacs 以后,就非常喜欢它的主题:spacemacs-theme,后来照葫芦画瓢移植了一个深色背景下的 space-vim-dark

不过用了一段时间以后发现,如果白天光线非常好,使用黑色背景可能会出现反光的情况,所以就基于 vim-colortemplate 重新移植了 spacemacs-theme,这次同时支持深色和浅色背景。按照 vim-colortemplate 的说法,space-vim-theme 在加载速度上应该比之前快了一点,大概几毫秒 :(

项目地址:space-vim-theme
darklight
darklight

上面截图中使用的 terminal 是 kitty,字体是 Iosevka Term。

使用 vim-plug 安装 space-vim-theme:

Plug 'liuchengxu/space-vim-theme'

在 .vimrc 中启用 space-vim-theme:

colorscheme space_vim_theme

:h space_vim_theme 查看配置项说明。

查看原文

赞 1 收藏 1 评论 0

liuchengxu 发布了文章 · 2019-01-13

在 Vim 中使用 graphviz.vim 画图

本文主要介绍 graphviz.vim, fork 自 wmgraphviz.vim,但是除了复用补全数据,我几乎重写了所有内容,并做了很多改进。

可能很多人没用过 graphviz,它是一个开源的图可视化工具,使用 DOT 语言进行绘制,优点是可以自动布局,尤其适用于复杂的流程图,结构图等等。官方有很多示例,使用时也可以参考一些其他的优秀案例,比如:

From Milo Yip

本文并不会对 graphviz 本身做太多介绍,而是分享如何在 Vim 中使用 graphviz.vim 插件方便画图。

wmgraphviz.vimgraphviz.vim 的前身,提供了一些补全,一键编译,查看编译后文件等功能。但是使用起来感觉不是那么 fashion,很久以来也几乎没怎么更新,比如依然在于 ! 进行外部调用。

graphviz.vim 整个插件非常简单,本质上就是封装了一些编译,一键查看的命令而已,主要改进包括:

  • 命令更少,配置项更简单。

    只有 :Graphviz:GraphvizCompile 两个命令,:Graphviz 用于打开编译后的文件,:GraphvizCompile 用于编译当前文件。如果 :Graphviz! 则相当于 :GraphvizCompile | Graphviz。对于可选项,我采用了传入参数进行调控。

  • 支持 ncm2coc.nvim

    这个很简单,只是简单封装了下 Omni 补全以适应 ncm2 和 coc.nvim。

安装

使用 vim-plug 进行安装:

Plug 'liuchengxu/graphviz.vim'

用法

:Graphviz 打开编译后的文件,文件名取自当前文件,辅以不同后缀。默认是打开 pdf 类型,比如当前打开的文件叫 foo.dot,那么 :Graphviz 是尝试打开 foo.pdf 的文件,可以传入扩展名进行指定。

" 默认打开 pdf 文件
" 可选项: 'ps', 'pdf', 'png', 'jpg', 'gif', 'svg'
:Graphviz

" 打开 png 文件
:Graphviz png

:Graphviz! 会在目标文件不存在的情况下,尝试调用 :GraphvizCompile 进行编译然后再打开,相当于 :GraphvizCompile | Graphviz

:GraphvizCompile 用于编译当前文件,可以指定编译程序和扩展名,默认是 dot pdf

" :GraphvizCompile [exe] [format]

" 默认是用 dot 编译成 pdf
" :GraphvizCompile dot pdf
:GraphvizCompile

" 指定编译成 png 格式
:GraphvizCompile png

" 指定用 dot 编译成 gif 格式,实际上我没用过除 dot 的其他编译项:(
:GraphvizCompile dot gif

其他一些可选配置项:

" 指定打开文件的命令。默认会根据平台自动选择
" macOS 使用 open, Linux 使用 xdg-open 等
let g:graphviz_viewer = 'open'

" 默认编译生成 pdf 格式,如果想要其他格式,将 pdf 换成其他格式即可
let g:graphviz_output_format = 'pdf'

我基本只用 macOS, 所以 Windows 或者 Linux 没怎么测试过,如果遇到问题,可以到 graphviz.vim 提 issue,我会尽量解决 :(。

查看原文

赞 0 收藏 0 评论 0

liuchengxu 发布了文章 · 2018-10-12

Vim 插件:vim-which-key

emacs-which-keyvim-which-key

emacs 用户相信应该对于 emacs-which-key 很熟悉,如果你在一定时间没有输入下一个按键,它会自动显示接下来可能的所有快捷键映射,这对于常常需要多组合键的 emacs 来说很是方便。我在一开始使用 spacemacs 的时候,就被这个功能所吸引。不过一直以来 vim 中都缺少像 emacs-which-key 这样“形神兼备”的插件,这一点我在 space-vim 的 README 中也一早有提及。

vim-leader-guide 是 vim 里出现的一个比较接近的插件,它主要借鉴自 guide-key,而 guide-key 是 emacs-which-key 的前身,目前已经不更新了,上一次 commit 还是在 2015 年。emacs-which-key 作为 guide-key 的继任者对它进行了重写,并加入了一些新的特性。

因为 vim-leader-guide 之前长时间没有更新,而且在我看来不够 fancy,所以我对它进行了一个大的改造,也就是现在的 vim-which-key,主要改进的地方有:

  • 大量 UI 细节上的调整与改进,比如:

    • 底部输出当前输入的内容
    • 高亮群组
    • 每列支持按照分隔符对齐
    • 必要时更新窗口内容,而不是每一次都关闭再打开一个新窗口
    • ......
  • 使用 getchar() 而不是 input() 进行交互,快速响应用户键入的每一个字符。
  • 引入针对 vim-which-key 的 timeout 解决由于 getchar() 带来的一些不友好体验。

vim-which-key

使用要求

vim-which-key 对于 vim 的版本和特性基本没什么要求,需要注意的一点是不要关闭选项 timeout,即不要在 vimrc 中设置 set notimeout。另外可以自行设置 timeout 的时长:

" 默认超时是 1000 ms,如果不想那么长的话,你可以在 vimrc 中设置更短一些
set timeoutlen=500

安装使用

如果使用 vim-plug:

Plug 'liuchengxu/vim-which-key'

let g:mapleader = "\<Space>"
let g:maplocalleader = ","

nnoremap <silent> <leader> :WhichKey '<Space>'<CR>
nnoremap <silent> <localleader> :WhichKey ','<CR>

这是使用 vim-which-key 的最小配置,它会自动解析用户自定义的 <leader><localleader> 相关快捷键。但是通常来说,通过自动解析所展示的内容并不能起到 cheatsheet 的作用,所以一般还需要稍加一点自定义配置来实现一个比较好的效果。

自定义配置

要想实现上图中的效果,只需要再多额外两步配置。

第一步是用一个 dict 定义你要展示的信息和执行的操作,用过 vim-leader-guide 的应该都很熟悉,跟它很像,不同的地方主要有:

  • 对于用户已经定义的快捷键,可以只传入一个字符串描述该快捷键
  • 支持解析 <C-W> 等键位

更详细的样例可以参考 space-vimleader.vim, 它也是截图中的配置。

let g:which_key_map =  {}

" `name` 是一个特殊字段,如果 dict 里面的元素也是一个 dict,那么表明一个 group,比如 `+file`, 就会高亮和显示 `+file` 。默认是 `+prefix`.

" =======================================================
" 基于已经存在的快捷键映射,直接使用一个字符串说明介绍信息即可
" =======================================================
" You can pass a descriptive text to an existing mapping.

let g:which_key_map.f = { 'name' : '+file' }

nnoremap <silent> <leader>fs :update<CR>
let g:which_key_map.f.s = 'save-file'

nnoremap <silent> <leader>fd :e $MYVIMRC<CR>
let g:which_key_map.f.d = 'open-vimrc'

nnoremap <silent> <leader>oq  :copen<CR>
nnoremap <silent> <leader>ol  :lopen<CR>
let g:which_key_map.o = {
      \ 'name' : '+open',
      \ 'q' : 'open-quickfix'    ,
      \ 'l' : 'open-locationlist',
      \ }

" =======================================================
" 不存在相关的快捷键映射,需要用一个 list:
" 第一个元素表明执行的操作,第二个是该操作的介绍
" =======================================================
" Provide commands(ex-command, <Plug>/<C-W>/<C-d> mapping, etc.) and descriptions for existing mappings
let g:which_key_map.b = {
      \ 'name' : '+buffer' ,
      \ '1' : ['b1'        , 'buffer 1']        ,
      \ '2' : ['b2'        , 'buffer 2']        ,
      \ 'd' : ['bd'        , 'delete-buffer']   ,
      \ 'f' : ['bfirst'    , 'first-buffer']    ,
      \ 'h' : ['Startify'  , 'home-buffer']     ,
      \ 'l' : ['blast'     , 'last-buffer']     ,
      \ 'n' : ['bnext'     , 'next-buffer']     ,
      \ 'p' : ['bprevious' , 'previous-buffer'] ,
      \ '?' : ['Buffers'   , 'fzf-buffer']      ,
      \ }

let g:which_key_map.l = {
      \ 'name' : '+lsp'                                            ,
      \ 'f' : ['LanguageClient#textDocument_formatting()'     , 'formatting']       ,
      \ 'h' : ['LanguageClient#textDocument_hover()'          , 'hover']            ,
      \ 'r' : ['LanguageClient#textDocument_references()'     , 'references']       ,
      \ 'R' : ['LanguageClient#textDocument_rename()'         , 'rename']           ,
      \ 's' : ['LanguageClient#textDocument_documentSymbol()' , 'document-symbol']  ,
      \ 'S' : ['LanguageClient#workspace_symbol()'            , 'workspace-symbol'] ,
      \ 'g' : {
        \ 'name': '+goto',
        \ 'd' : ['LanguageClient#textDocument_definition()'     , 'definition']       ,
        \ 't' : ['LanguageClient#textDocument_typeDefinition()' , 'type-definition']  ,
        \ 'i' : ['LanguageClient#textDocument_implementation()'  , 'implementation']  ,
        \ },
      \ }

第二步是注册键位与对应的 dict,这一步比较简单,不要忘记就行。

call which_key#register('<Space>', "g:which_key_map")
nnoremap <silent> <leader> :<c-u>WhichKey '<Space>'<CR>
vnoremap <silent> <leader> :<c-u>WhichKeyVisual '<Space>'<CR>

除了 leaderlocalleader,如果想要提示其他键也可以:

nnoremap <silent> ] :<c-u>WhichKey ']'<CR>
nnoremap <silent> [ :<c-u>WhichKey '['<CR>

更多介绍请参看 vim-which-key 的 README 和 doc。

如果在使用 vim-which-key 过程中有任何问题,请到 GitHub 上的 issue 里面提,提 issue时请说明重现步骤并提供可重现的最小 vimrc,比如这样:

set nocompatible

call plug#begin()
Plug 'liuchengxu/vim-which-key'
call plug#end()

let g:mapleader="\<Space>"

nnoremap <silent> <leader>      :<c-u>WhichKey '<Space>'<CR>
nnoremap <silent> <localleader> :<c-u>WhichKey  ','<CR>

nnoremap <Leader>a<Tab> :echom "Hello, World"<cr>
nnoremap <Leader>1 :echom "THis is one"<cr>

let g:which_key_map = {}

let g:which_key_map.a = {
            \ 'name':"Test",
            \ '<Tab>':"Hello world"
            \}

let g:which_key_map.1 = "One"

call which_key#register('<Space>', "g:which_key_map")
查看原文

赞 0 收藏 0 评论 0

liuchengxu 发布了文章 · 2018-08-18

区块链技术阅读列表

有很多值得学习的区块链技术资源,在这里稍微总结了一下。因为不想再多一个 markdown repo,所以把它放在了 blockchain-tutorialwiki 。目前只有英文链接,实际上有很多内容已经有了中文翻译,有时间我会慢慢补充进来,也欢迎大家贡献,编辑 wiki 即可。

熊市更是积累技术的时候,代码强的可以直接从源码学习,GitHub 上项目很多, 从 Bitcoin, Ethereum 到 Cardano, Polkadot,都是学习的好资源。喜欢从阅读入手的,不妨看一下这个 reading list :(

插播一条广告:链池 正在招人!感兴趣的请发简历到 xuliuchengxlc@gmail.com。我们打算基于 substrate 做点事情,详情欢迎来信交流。

substrate 是一个一键起链的区块链框架,你可以理解成 react, vue 之类的前端框架,由 Gavin Wood 带领的 parity 团队打造,Gavin Wood 是前以太坊 CTO,parity 团队可能是这个世界上目前区块链技术最强的团队了(虽然之前出过多签事故+_+),值得期待。目前区块链的基础设施还很不完善,substrate 的出现是一个方向,在未来很可能会改善这一点。substrate 是 Rust 写的,Rust 小能手千万不要错过!

阅读列表 >>> Opinioned Blockchain Reading List

General

Consensus

Cryptography

Interoperability

Bitcoin

Governance

Web3

Scaling

Fundamental Concepts

Digital singatures

Fork

Ricardian Contracts

Replay Attacks

Self Mining

查看原文

赞 0 收藏 0 评论 0

liuchengxu 发布了文章 · 2018-08-11

如何让 Vim 美观又实用(1)

我学习计算机不久就开始用了 vim,到现在也三四年了,且算是对 vim 有了一定的控制力。在这里分享一下使用过程中的一些“心路历程”,说实话,要留意的小地方有很多,但是由于很多不可抗(_懒_)因素,本系列并不保证还有后续 :)

以下内容适用于对 vim 有一定使用经验的用户,相关的具体配置参见 space-vim。有些内容我虽然给出了链接,但是可能并没有完整贴出代码,需要你自行查找,理解并抽取整合对自己有用的地方。

project

vim 本身并没有 project 的概念,只有工作目录 working directory, :echo getcwd() 可以查看当前的工作目录。vim-rooter 可以给 vim 引入 project 的概念,它会自动将 vim 的工作目录切换到项目根目录。在 vim-rooter 中,所谓 project,是指符合某些“特征”的目录,比如有些目录含有 Rakefile,.git 等,这些目录就会被认为是项目的根目录。

有了项目根目录以后,我们就能够以项目为单位进行各种查找搜索等等。比如,由于 fzf 的一些命令,比如 Ag 默认是在当前目录下进行,实际就变成了在项目根目录下搜索。当然了,也可以显式参考 space-vim 的 fzf 配置 指定 fzf Ag 的搜索目录:

call fzf#vim#ag(a:query, extend({
      \ 'dir': spacevim#util#RootDirectory(),
      \ 'options': '--prompt="'.spacevim#util#RootDirectory().'> "'},
      \ g:fzf_layout))

spacevim#util#RootDirectory() 对 vim-rooter 进行了简单封装,如果存在 vim-rooter 会直接进行调用,否则会进行简单探测是否是 git 仓库。

fzf

fzf 是一个命令行的模糊查找工具,用过的人应该知道,单就一个 CTRL-R 查找历史就值得强烈推荐,更不必说其他各种能够提升生产力的地方。如果使用 fzf,那么 fzf.vim 也是必不可少。

fzf.vim 提供的各种功能就不细谈了,这里谈一下可能出现的槽点:有人觉得 fzf.vim 的模糊查找太模糊了,候选项太多,有时候由于对模糊查找的依赖性,导致输入比较随性,反而比精确查找要输入更多字符。

这里提几个建议:

  1. 指定项目目录,缩小查找范围,比如 :FZF ~/.vim/plugged。不要上来就 :FZF 默认在用户目录下查找,那自然是候选项非常多。这一点只要用 vim-rooter 就可以实现,现在大都用的都是 git,一般项目都是可识别的。
  2. 指定查找内容。比如 Ag,比如不要直接 :Ag 打开 fzf 再输入想要查找的内容,交互式地查询虽然比较酷,但是一般没有在调用时就指定查找字符串更加高效。比如一个比较实用的就是用 Ag 查找当前光标下的词。
  call fzf#vim#ag(expand('<cword>'), extend({
      \ 'dir': spacevim#util#RootDirectory(),
      \ 'options': '--prompt="'.spacevim#util#RootDirectory().'> "'},
\ g:fzf_layout))

fzf

  1. 升级电脑 :)。这一点我深有感触,14 款 13 寸的 MBP 我用了好几年,虽然内存 16 G,但是双核四线程还是有些捉襟见肘,使用 fzf 在用户目录下查找感觉还是要些时间的。但是换了 18 款 的 15 寸 MBP,六核十二线程就连用户目录查找都是快的飞起。

状态栏

很多人的状态栏一开始大都只是为了看起来酷而已,我也不能免俗 :)。最早的 space-vim 状态栏效果是仿 spacemacs ,里面显示了各种信息。

eleline

后来状态栏部分被提取成了一个独立的插件 eleline.vim。随着时间的推移,我越来越觉得显示的很多信息其实有点多余,于是就有了下面的精简模式。

精简模式

安装 eleline.vim 并在 .vimrc 中设置:

let g:eleline_slim = 1

就可以使用精简模式,只显示 buffer number, window number, filename 还有一些插件的信息。

let g:eleline_slim = 1

如果想要在精简模式查看多一些信息的话,可以用 CTRL-G,见 :h CTRL-G。如果对默认的 CTRL-G 不满意,也可以参考 space-vimCTRL-G 进行增强.

  nnoremap <silent> <C-G> :call spacevim#vim#file#CtrlG()<CR>

默认的 CTRL-G:

"/usr/local/etc/profile.d/z.sh" 243 lines --65%--

增强后:

"/usr/local/etc/profile.d/z.sh" 243 lines --65%-- Cursor 159:1 8.6K TOT:2 [sh]

异步获取 git branch

eleline.vim 现在采用异步的方式获取 git branch 信息,代码参考了 chemzqm 的 statusline.vim。因为 chemzqm 在 V2EX 的一个帖子提到,通过系统调用,也就是直接依赖 vim-fugitive 获取 git branch 可能会对启动时间有几十毫秒的影响。不过他可能以 neovim 为主,并没有支持 vim8,我在他的基础上加入了 vim8 的支持 :)。

更多关于 vim 的启动优化,有兴趣可以查看 chemzqm 的这篇文章:vim 启动速度优化的一些经验

今天就先讲这么多了,下一篇可能更多讲讲如何配置更美观的一些小细节。因为我高中是学美术的,大学也在传播学院呆过一年多,所以对审美有一定要求,对死板的界面实在看不下去 :(。

总之,happy vimming :)

查看原文

赞 0 收藏 0 评论 0

liuchengxu 评论了文章 · 2018-07-14

解决 vim 报错:the imp module is deprecated in favour of importlib

问题描述

打开 vim 之后,出现如下错误:

Error detected while processing function youcompleteme#Enable[3]..<SNR>71_SetUpPython:
line   42:
/must>not&exist/foo:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses

原因:
这是 python warning
imppython3.4 之后 已经不再使用。
显然,这个问题是由 ycm 这个插件加载时引起的,可以通过修改 ycm 源码解决。

解决办法

有以下几种:
1.重新安装 vim,但是采用较低版本的 python
2.修改 ycm 报错部分的代码
具体修改如下:
vim PLUG_PATH/YouCompleteMe/autoload/youcompleteme.vim
修改如下:

diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim
index 597eb020..32461fa9 100644
--- a/autoload/youcompleteme.vim
+++ b/autoload/youcompleteme.vim
@@ -180,7 +180,7 @@ endfunction


 function! s:SetUpPython() abort
-  exec s:python_until_eof
+  silent! exec s:python_until_eof
 from __future__ import unicode_literals
 from __future__ import print_function
 from __future__ import division

参考:Error message printed first time python3 (version 3.7.0) dynamic library is imported


更新:这个问题出现在使用 Python 3.7 的情况,
可以暂时在 .vimrc 中做如下配置,并等待更新 Python 3.7 来解决这个问题:

" temporary fix
" https://github.com/vim/vim/issues/3117
if has('python3')
  silent! python3 1
endif
查看原文

liuchengxu 发布了文章 · 2018-04-22

PoW 本质上是个去中心化的时钟

原文:Blockchain Proof-of-Work Is a Decentralized Clock

原文从区块链如何保持交易有序的基本问题出发,对该问题进行了详细阐述,并提出 PoW 本质上是实现了一个“时钟”的观点,这个时钟的一个滴答对应的就是 PoW 算出一次的解。

本文解释了比特币 PoW(Proof-of-Work, 工作量证明) 的关键要素,尤其对 PoW 来说不可或缺的一个特性,同时也表明关于 PoW 经常谈到的一些其他特性其实是次要作用,比如安全性,这些次要效应有用,但是非必要。

要想理解本文,首先要懂得在区块链中,PoW 是如何工作的一些有趣的属性,这些属性并不那么直观,甚至可以说相当反直觉,比如参与者如何在从来没有相互交流的情况下,共同地求解一个问题。

当理解了这些属性,你应该能够得出一个结论:PoW 的机制主要实现了一个分布式,去中心化的时间系统,即一个时钟。

注意本文并非关注 PoW 算法本身的细节,而是探究区块链如何“严丝合缝”地将 PoW 运用其中。如果你还没听过 PoW,请先阅读 这里

分布式账本时间排序问题

在讲解决方案之前,先来关注问题本身。很多 PoW 的相关资料都很令人费解,因为它们常常在没有阐明问题的情况下,就试图讲清楚解决方案。

毫无疑问,任何账本都需要有序。你不能发费还没有收到的钱,也不能花费已经花出去的钱。区块链交易(或者说包含交易的块)必须有序,无歧义,同时无需可信的第三方。

即便区块链不是一个账本,而是就像日志一样的数据,对于所有节点来说,如果要想共同保有一份完全相同的区块链副本,有序也是必不可少的。交易顺序不同,就是不同的两条链。

但是,如果交易是由全世界的匿名参与者生成,也没有中心化机构负责给交易排序,那又如何实现这一点呢?有人会说,交易(或者块)可以包含时间戳,但是这些时间戳又如何可信呢?

时间是一个人类概念,时间的任何来源,比如一个原子时钟,就是一个“可信第三方”,除此之外,由于网络延迟和相对论效应,时钟的大部分时间都有轻微误差。很遗憾,在一个去中心化系统中,不可能通过时间戳来决定事件的先后顺序。

我们所关心的“时间”并不是所熟悉的年,月,日这种概念。我们需要的是这样一种机制,它可以用来确认一个事件在另一个事件之前发生,或者可能并发发生。

首先,为了建立之前与之后的概念,首先必须要建立一个时间点的概念。理论上来说,建立一个点时间的概念似乎并不太可能,因为没有技术能够足够精确地测量 普朗克时间。但是你会看到,比特币通过创建属于自己的时间概念变相解决了这个问题,使得确立精确的时间点概念在事实上成为可能。

Leslie Lamport 1978 年的论文 “分布式系统中的时间,时钟和事件顺序” 中对这个问题有了详细描述,但是除了“正确同步的物理时钟”,实际上并没有提供一个详细的解决方案。1982 年 Lamport 同样描述了 “拜占庭将军问题”,中本聪在他早期的一封邮件中 解释 了 PoW 如何解决了这个问题,比特币白皮书 指出“为了在端到端的基础上实现一个分布式的 时间戳服务器,我们将会使用一个工作量证明系统”,也表明了它主要解决了时间戳的问题。

时间是根本问题

必须要强调的是,在分布式系统中,不可能将事件与时间点关联起来,这是一个尚不可解问题,直到中本聪找到了一个解决方案,才使得分布式账本成为可能。在区块链中还有很多其他的技术细节,但是时间是最基础也是最重要的。没有时间,就没有区块链。

PoW 回顾

简而言之,比特币的 PoW 就是 SHA-2 哈希满足特定的条件的一个解,这个解很难找到。通过要求哈希满足一个特定的数字,就确定了一个难度(difficulty),难度的值越小,满足输入的数字越少,找到解的难度就越大。

这就是所谓的“工作量证明”,因为满足哈希要求的解非常稀少,这意味着找到这样一个解需要很多试错,也就是,“工作(work)”。而工作也就是意味着时间

块间无变化

链的状态由块所反映,每个新的块产生一个新的状态。区块链的状态每次向前推动一个块,平均每个块 10 分钟,是区块链里面最小的时间度量单位。

SHA 无记忆,无进展

SHA(Secure Hash Algorithm) 在统计学和概率上以无记忆性(memoryless) 闻名。对于我们人类而言,无记忆性有点反直觉。所谓无记忆性,就是无论之前发生了什么,都不影响这一次事件发生的概率。

关于无记忆性,最好的例子就是抛硬币。如果一个硬币连续 10 次都是正面,那么下一次是反面的可能性会不会更大呢?我们的直觉是会,但是实际上,无论上一次的结果是什么,每次抛硬币正反面都是一半一半的概率。

而对于需要无进展(progress-free)的问题,无记忆性又是必要条件。progress-free 意味着当矿工试图通过对 nonces 进行迭代解决难题时,每一次尝试都是一个独立事件,无论之前已经算过了多少次,每次尝试找到答案的概率是固定的。换句话来说,每次尝试,参与者都不会离“答案”越近,或者说有任何进展(progress)。就下一次尝试而言,一个已经算了一年的矿工,与上一秒刚开始算的矿工,算出来的概率是一样的。

在指定时间内,给定一个难度,找到答案的概率唯一地由所有参与者能够迭代哈希的速度决定。与之前的历史无关,与数据无关,只跟算力有关。

因此,算力是一个与参与者数量,和那些用来计算哈希设备的速度相关的函数。

SHA 与输入无关

在比特币中,输入的是区块头。但是如果给它随机传入一些值,找到一个合适哈希的概率仍然是一样的。无论输入是一个有效的块头,还是 /dev/random 中随机的一些字节,都要花费平均 10 分钟来找到一个解。

如果你找到了一个合适的哈希,但是输入却不是一个有效的块头,虽然无法将块上链,但是它仍然是一个工作量证明(即使没啥用)。

难度属于银河系

令人惊奇的是,难度是universe(全宇宙,或者说通用的),也就是说它充满了整个宇宙,无处不在。火星上的矿工也同样能参与挖矿,但是他们不需要感知到地球矿工的存在,也不需要与地球上的矿工有交流,仍然是每 10 分钟就会解决一个“难题”。(好吧,当他们解出难题时,需要告诉地球上的矿工,否则我们永远也不知道)。

了不起的是,远距离参与者不需要通过真正的相互交流进行沟通,因为他们在共同地求解同一个统计学问题,并且他们甚至互相感知不到对方的存在。

“通用属性(universal property)”一开始看起来很神奇,实际上很容易解释。我用了“通用”一词,因为就这一个词即可表达到位,但是它实际指的是“所有参与者都知道(这个难度)”。

SHA-256 的输入可以是 0 到 2 的 256 方之间的任何一个整数(因为输出是 32 字节,也就是在 0 到 2^256,任何超过该范围的数将会导致冲突,也就是多余)。即使这个集合已经非常大了(比已知宇宙里所有原子总数都大),不过每个参与者都知道这个集合,并且只能从这个集合里选取一个数。

如果输入的集合全世界都知道,SHA-256 全世界都知道,难度要求也是全世界都知道了,那么找到一个解的概率自然也就是“全世界都知道(universe)”。

计算 SHA 即参与

如果所述问题是找到一个合适的哈希,那么要想解出这个问题,只需要去试一次,但是,哪怕就试一次,你就已经影响了整个算力。就这次尝试而言,你就已经成为了一个帮助其他人解决问题的参与者。虽然你不需要告诉其他人你“做了”(除非你找到了答案),其他人也不需要知道,但是想要找到解的这次尝试真真切切地影响到了结果。对于全宇宙而言,也是如此。

如果上面这段话看起来仍然不是那么令人信服,一个很好的类比就是寻找大素数问题。找到最大的素数很难,并且一旦找到,它就是“被发现”或者“已知的”。有无数的素数,但是在全宇宙中,每个数只有一个实例。因此无论是谁试图找到最大素数,就是在解同一个问题,而不是这个问题另一个单独的实例。你不需要告诉其他人你已经打算寻找最大素数,你只需要在找到时通知其他人。如果从来没有人寻找最大素数,那么它永远也不会被找到。因此,只要参与(也就是试图找到素数),即使它正在秘密进行,仍会影响结果,只要公布最后的发现(如果找到)。

这就是中本聪设计的精妙之处,他利用了这个令人难以置信的统计学现象,即任何参与都会影响结果,即使秘密进行,即使尚未成功。

值得注意的是,因为 SHA 是 progress-free,每一次尝试都可以被认为是一个参与者加入其中,然后立即退出。因此可以这么理解,矿工们来了又走,每秒无数次轮回。

参与度由统计学揭示

这个神奇的秘密参与(secret participation)属性反过来也成立。很多网站上显示的全球算力,并非是由每个矿工在某个“矿工注册办公室”注册,并定期汇报他们的算力而来。并不存在这种事情。

因为对于在 10 分钟找到一个指定难度的解,所需算力是已知的,一个人平均必须尝试这么多次(截止成文之时大概 10^21)才能找到答案,无论这个人是谁,他在哪儿。

我们不知道这些参与者是谁,他们也从来都不会说我正在参与其中,没有找到解的人(实际上他们都是)从来不会告诉其他人他们正在进行计算,他们可能在世界上任何一个地方,但是我们肯定他们必然存在。因为生活还要继续,问题(找到满足条件的哈希)始终还是要被解决。

工作(work)是一个时钟(clock)

关键之处在于:找到满足条件的哈希的难度,就类似于一个时钟的角色。一个宇宙(universe)时钟,因为全宇宙只有一个这样的时钟,不需要同步,任何人都能“看”到这个时钟。

即使这个时钟不精确也没关系。重要的是,对所有人来说,它都是同一个时钟,链的状态与这个时钟的滴答(tick)无歧义地绑定到一起。

这个时钟由遍布地球上的未知数量的参与者共同操作,参与者相互之间完全独立。

谜题的最后一部分

解决方案必须是块哈希(准确来说,是块头)。上面已经提到,对于 SHA 来说,输入的内容并不重要,但是如果它是真实的块,那么无论何时找到一个解,它都发生在 PoW 这个时钟的滴答处。没有早一点,没有晚一点,而是恰好在这个点。我们知道这是毫无歧义的,因为块是整个机制的一部分。

换句话来说,如果块不是 SHA256 函数的输入,我们仍然有一个分布式时钟,但是我们无法将块绑定到这个时钟的滴答上。将块作为输入就解决了这个问题。

值得注意的是,我们的 PoW 时钟只提供了滴答。但是我们没办法从滴答中分出顺序,于是就引入了哈希链(hash chain)。

分布式共识

共识(consensus)意味着意见一致(agreement)。所有参与者别无选择,只能同意“时钟已然滴答”。并且每个人都知道滴答和附加的数据。正如中本聪在邮件里面所解释的,这确实解决了拜占庭将军问题,。

在一个罕见却又常见的情况下,会出现共识分离,有两个连续的滴答与一个块有关联,这就发生了冲突。通过哪个块与下一个滴答相关联解决了这个冲突,同时将有争议的块变为“孤儿块(orphan)”。链如何继续是个概率问题(a matter of chance),这也可能间接地归因于 PoW 的时钟。

就这样

这就是区块链的 PoW(工作量证明)。它并不是一个为了让矿工赢得出块权的“乐透”,也不是为了将实际能源转换成一个有价值的概念,这些都偏离了本质。

比如矿工奖励的角度来看,虽然这些奖励激励了矿工参与,但是这并不是区块链诞生的必要因素。块哈希形成一条链,但是这与工作量并没什么关系,它是从密码学上强制保证了块的顺序。哈希链使得前一个滴答“更确定”,“更加不可抵赖”,或者简单来说,更安全。

PoW 也能使块不可更改,这是一种好的副作用,也使得隔离见证(Segregated Witness)成为可能,但是隔离见证也能通过保留签名(见证,witness)实现,所以这也是次要的。

结论

比特被的 PoW 只是一个分布式,去中心化的时钟。

如果你理解了这个解释,那么你应该能够更好地理解 PoW 与 PoS 的异同。显然,两者不具有可比性:PoS 是有关于(随机分布的)权力(authority),而 PoW 是一个时钟。

在区块链的背景下,PoW 这个名字可能是个误用,起的并不太好。这个词来源于 Hashcash 项目,它确实用于证实工作(work)。在区块链中,它主要关于可验证的花费时间。当一个人发现满足难度的哈希时,我们知道它必然会花费一些时间。实现时间延迟的方法就是“工作”,而哈希就是这段时间的证明。

PoW 是关于 time 而非 work 的事实也表明,可能存在一些其他的统计学问题,这些问题同样消耗时间,但却需要更少的能源。这也可能意味着比特币算力有些“过分”,因为我们在上面所描述的比特币时钟,在只有部分算力的情况下,也是可信的,这是这种激励结构推动了能源消耗。

如果你找到了一个方法能够同步滴答,并且需要更少的工作,这是一个价值万亿美元的问题,请一定要告诉我!

P.S. 特别感谢 UChicago StatisticsSasha Trubetskoy 对上述文字的 review 和建议。

查看原文

赞 5 收藏 6 评论 0

liuchengxu 回答了问题 · 2018-04-11

shell 脚本几行代码的意思

有个网站可以解释 shell 命令:https://explainshell.com

write down a command-line to see the help text that matches each argument

比如把你脚本里面的 if [ -f /etc/bash.bashrc ]; then . /etc/bash.bashrc; fi 放到 explainshell 里面:

https://explainshell.com/expl...

clipboard.png

如上图,-f 有明确的解释。如此类推,可自行查看其它内容。

关注 4 回答 2

认证与成就

  • 获得 116 次点赞
  • 获得 8 枚徽章 获得 1 枚金徽章, 获得 3 枚银徽章, 获得 4 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

注册于 2016-12-02
个人主页被 3.6k 人浏览