Tag Archives:Vim

Vim 文本过滤/文字处理插件

我经常有文本处理的需求,例如将 html 转换成纯文本,或者移除 markdown 里的所有连接,或者繁体转换简体。因此我做了一个插件来管理和执行各种外部文本过滤器。

所谓 “文本过滤器” 是一个命令行程序,它从标准输入读取文本,然后进行一些处理后写到标准输出,在 Vim 里可以用原生的:{range}! xxx 命令将选中文本发送给 xxx 命令的标准输入,然后用该命令的标准输出替换选中文本,这个命令很有用,但每次输入一长串命令略显繁琐,并且过滤器多了以后也很难管理。

因此我做了这个插件来统一管理文本过滤程序,并且提供接口来执行他们:

比如上图演示了将 HTML 转换成文本,以及去除 markdown 中的连接,使用命令:{range}TP {name} 就能调用名为{name} 的文本过滤程序了。这些程序可以用你喜欢的语言编写,放到统一的目录,加上可执行属性就行,该插件就能找到它。

Continue reading

Loading

Posted in随笔|Tagged|Leave a comment

我为什么使用 Vim?

很多人说用 Vim 是因为键位比较方便,其实这只是部分原因,不知道你思考过没,为什么今天大部分 Editor/IDE 都支持 vim keymap 的情况下,还有那么多人用 Vim 呢?如果仅仅因为键位原因,他们大可以用其他东西啊,为何还继续用原始的 Vim 呢?

也许在你看来,有的人配置 Vim 一半天最后就是类似 IDE/Vscode 的样子,既然如此,那么为啥那些人不直接去用 IDE/Vscode 呢?(二者也都支持 vim keymap),为什么他们还抱着原版的 Vim 不放呢?难道真的是他们没听过/没用过时下最先进的 Editor/IDE 么?

事实可能恰恰相反,很多 vimer 都是非常热衷尝试各种新的编辑器的,我给 vscode 写过不少高赞回答,也给 atom editor 开发过插件,不少 vimer 机器上 terminal/gui based 的 editor 加起来都有十多个,对主流 editor/ide 的熟悉程度未必比非 vimer 差。

那么究竟为啥还有人用 vim 呢?CoC 作者赵启明老兄已经回答了:”Vim 大概是世界上扩展能力最强的编辑器”。Vim 就像编辑器世界里的 MineCraft,你说 MineCraft 最终目标也就是去杀条龙,为什么那么多人不直接玩也能杀龙的黑魂/老头环,却一直迷恋 MineCraft 呢?

因为 MineCraft 每一寸土地都可以定制化,每种游戏元素都可以自己制作(除了工具武器制作外还可以制作各种玩法的副本关卡,还有人用 MC 里的红石从门电路做起,搭了个 CPU),而 Vim 里每个字符你都可以定制。

方便定制体现在两个方面:首先是能定制的地方很多,到处都能改(不像 vscode 一样对插件开发者诸多限制,连个 toolbar 按钮你想加都加不了);其次是非常容易上手修改,改的代价非常低,不用加个简单功能都要创建个插件项目,编辑 package 配置等一堆七七八八的文件,一半天才能开始写一行代码。

我用过非常多的编辑器,有一些至今我都非常喜欢,但不管我多么喜欢一款编辑器,总有一些地方是我不满意的,碰到这种时候,大部分我只能祈求开发商发慈悲哪天给我加一下,即便有些开源的,支持扩展的,很多都没达到 Vim 的扩展性,可以那么容易的让普通用户随心定制,四处定制。

用其他 Editor/IDE 的用户大部分都是下下扩展,改下按键之类的,而 vim 用过一年以上的几乎人人都可以随手扩展,举几个例子:

Continue reading

Loading

Posted in随笔|Tagged|Leave a comment

Vim2022:实时代码格式化

大部分 IDE/编辑器 都有代码格式化的功能或者插件,但都需要你主动触发格式化命令,而且每次写很多代码在保存的时候一次性格式化,总会有种不放心的感觉,需要跳过头去检查。

有没有可能让我一边写一边实时格式化呢?这样每次我都能看到最终的效果。

于是我写了个小脚本vim-rt-format,再 INSERT 下面每次按回车就能自动格式化当前行:

有了这个东西以后,写代码爽多了,释放注意力,完全专注于 “编码”,再也不用为 “格式化”这个事情花费额外的精力,变量名和运算符之间无需加空格,直接回车就自动变成干净清爽的代码了,能自动识别语法元素,并且格式化的过程无需离开 INSERT 模式。

目前支持:Python, Lua, Javascript 几种语言,使用的话,只需要 Vim 支持 +python3 特性,且 Python 安装 autopep8 模块即可,配置如下:

" 使用 vim-plug 安装插件Plug 'skywind3000/vim-rt-format'" 默认在 INSERT 模式下按 ENTER 格式化当前代码行,将下面设置" 成 1 的话,可以用 CTRL+ENTER 来格式化,ENTER 将保留原来的功能let g:rtf_ctrl_enter = 0" 离开 INSERT 模式的时候再格式化一次let g:rtf_on_insert_leave = 1

行了,保存配置并重启 Vim,随便打开一个源代码开始编辑,就是这么简单。

你会忽然发现,天空变得更加晴朗,空气变得更加的清新,多么美好的一天啊。

项目主页:

https://github.com/skywind3000/vim-rt-format

Loading

学习 Vim 的三个阶段

学习使用 vim 有三个阶段:

首先是孩童时期,刚刚开始接触 Vim,觉得非常别扭,这里也不顺畅,那里也不够高效,表现为在知乎上问,“Vim 到底好在哪里?”,或者“学完 vimtutor 以后该干嘛?”

接下来是青春期,感受到 Vim 的爽点,开始欣喜若狂的探索 Vim 的边界,表现为疯狂的尝试各种 mapping 和插件,阅读网上一切关于 Vim 的文章和内容,尝试一切可能的事情。

最后进入成熟期,开始移除所有无用的东西,真正变得高效起来。表现为开始冷静思考自己的工作流程,逐步针对性定制 vim ,让 vim 越来越顺手。

只有对编辑器足够挑剔的人,才会使用 Vim。真要尝试,你要先问问自己是不是对编辑器有很高的要求,是不是对身边的编辑器都有不满意的地方,还是只是好奇,并不希望投入多少时间:

当你真的决定入坑了,那么主要问题就是怎么完成第一个阶段到第二个阶段的切换呢。

(点击 more/continue 继续)

Continue reading

Loading

Posted in随笔|Tagged|Leave a comment

Vim2021:超轻量级代码补全系统

2121年了,应该尝试些新东西,这里介绍一个超级轻量级(169 行代码)的代码补全系统,针对:历史输入,字典,tags 等多个源提供类似 YouCompleteMe 的操作体验,并且无需安装各种后端的补全 LSP 服务器。

语义补全是很爽,但有时候,当你用某些缺乏 LSP 支持的小众语言写代码时,或者你去到一台临时的服务器上工作时,你并不想花时间编译和设置一套复杂的补全系统。

这种时候,其实 Vim 内建补全系统其实就已经足够你用了,它能从当前文件收集单词,能从 dict 文件以及 tags 文件收集单词,并且在你按下<c-n> 或者<c-x><c-k> 时弹出补全框。

这个小脚本就是在你每次输入 1-2 个字符的时候为你自动弹出补全窗口用的,并且提供类似 YouComplete 的补全体验(点击查看 GIF 动图):

特性说明:

  • 自动弹出补全框。
  • 使用 TAB 和 SHIFT+TAB 来循环选择补全内容,<c-e> 关闭补全框。
  • 提供同 YouCompleteMe 完全一致的体验(针对:buffer, dict, tags 几个源)。
  • 纯绿色,所有操作都是对当前 buffer 生效,不会影响其他 buffer。
  • 能够和其他补全系统一起共存(可以设置只对某些文件或者 buffer 生效)。
  • 无需种量级补全服务,无需编译后台 LSP 模块。
  • 轻量级,响应快,比大部分补全系统反应都要灵敏。
  • 只有一个 160 行的 apc.vim 文件,你甚至可以直接把内容拷出来粘贴到你 vimrc 里。
  • 适合作为各种大型补全系统的一个理想备份方案。

如何使用?

只需要这样就行了:(点击 more/continue 继续)

Continue reading

Loading

Vim 8 中的 C/C++ 编译运行:类 vscode 的任务系统

谦卑的向大家介绍我的新插件:asynctasks.vim,一套类似 vscode 的 tasks 系统,用于解决 vim 下长期没法轻松优雅的编译/运行 C/C++ 程序的问题。这个插件我去年酝酿了很长时间了,今年打算给他做一点宣传。

最近两年 Vim/NeoVim 发展非常迅速,各种:异步补全/LSP/查错,DAP 等项目相继出现,就连vimspector 这样以前只能奢望 emacs 的项目如今都出现了。

然而 Vim 任然缺少一套优雅的通用的任务系统来加速你的内部开发循环(编辑,编译,测试)。很多人在处理这些 编译/测试/部署 类任务时,任然还在使用一些比较原始的方法,所以我创建了这个插件,将 vscode 的任务系统引入 Vim。

vscode 为每个项目的根目录下新建了一个 .vscode 目录,里面保存了一个 tasks.json 配置文件来描述针对该项目的各类:编译/运行任务。而 asynctasks.vim 采用类似的机制,在每个项目的根文件夹下面放一个 .tasks 配置文件来描述针对该项目的任务,同时维护一份 ~/.vim/tasks.ini 的全局配置,适配一些通用性很强的项目,避免每个项目重复写 tasks 配置。

说起来好像很简单?其实这是概念简单,很多好的设计从概念上来讲往往非常简单,但是用起来却十分灵活强大,这不是我设计的好,而是 vscode 的 tasks 系统设计的好,我只是大自然的搬运工,这应该是目前 Vim 下最强的构建工具,下面就试用一下:

Continue reading

Loading

Posted in随笔|Tagged|Leave a comment

用 Vim/VsCode 来写 WordPress 博客

试用过一段时间各种静态页面博客系统,Hugo 这些,虽然发展的不错,但是比起 WordPress 来还是太弱了。WordPress 毕竟是发展了 15 年的东西各种功能和插件都比较完善。

所以这次回过头来重新使用 WordPress,顺便做了升级,速度更快了(升级 PHP7,引入页面缓存等),代码高亮等各种小功能也调优了一下,又加了一些类似热门文章和访问计数等小功能。

然后我写了一个命令行工具,可以让我在喜欢的文本编辑器里用 MarkDown 写博客,然后命令行发布到 WordPress,具体见markpress 相关文档。

下面是一些调优后的效果,首先 Markdown 的代码块,使用 highlight.js 以后好看很多:

#include <stdio.h>int main(void){    printf("Hello, World !!\n");    return 0;}

这个插件支持 185 种语言(包括 Vim)的高亮,可以选择 89 种主题,是目前最强的代码高亮解决方案。

MarkPress 页面生成基本尊崇 Github 规范:

  1. 连接会被自动识别,只需要直写 URL,就会自动识别出来加上<a> 标签。
  2. 比如双波浪线包围的内容~~测试~~ 会被划掉显示为:测试
  3. 比如 Github Emoji,直接写:smile: 的 shortcode,就会变成😄

除此之外还有很多 github 没有的扩展,比如:

折叠菜单点击左边箭头打开

第一行隐藏的折叠内容
第二行隐藏的折叠内容

MathJax 的内嵌公式,被$ 符号包围住的内容会被识别成 latex 公式:

$z=\sqrt{x^2 + \sqrt{y^2}}$

得到:

$z=\sqrt{x^2 + \sqrt{y^2}}$

然后是 GraphViz 图形,现在在 MarkDown 中用viz-{引擎名称} 开头的代码块:

```viz-dotdigraph G {   A -> B   B -> C   B -> D}```

能被转换为内嵌 SVG 代码,并被主流浏览器正常显示:

Continue reading

Loading

Posted in随笔|Tagged|3 Comments

VimScript 五分钟入门(翻译)

译注:折腾 Vim 当然要能看懂和改写相关脚本,而中文资料匮乏,缺一个提纲挈领的教程。本文翻译自 Andrew Scala 的 《Five Minute Vimscript》,立足于让你用最短的时间掌握 VimScript 的基础和要点,你可以把它看成一份语言速查表。

Vim有着丰富的内建文档系统,使用:h <关键词> 就可以阅读,如果你想在方便的尝试各种 vimscript ,你可以通过 NORMAL 模式下使用gQ 命令进入 VimScript 的交互式环境调试命令。

注意:下面的例子中会包含一些形如<符号> 的符号,意味着正式使用时应该被完全替换成真实的东西,包括左右两边的尖括号。而单独的<> 在 VimScript 中被用作比较符号。

变量

  • let 命令用来对变量进行初始化或者赋值。
  • unlet 命令用来删除一个变量。
  • unlet! 命令同样可以用来删除变量,但是会忽略诸如变量不存在的错误提示。

默认情况下,如果一个变量在函数体以外初始化的,那么它的作用域是全局变量;而如果它是在函数体以内初始化的,那它的作用于是局部变量。同时你可以通过变量名称前加冒号前缀明确的指明变量的作用域:

  • g:var – 全局
  • a:var – 函数参数
  • l:var – 函数局部变量
  • b:var – buffer 局部变量
  • w:var – window 局部变量
  • t:var – tab 局部变量
  • s:var – 当前脚本内可见的局部变量
  • v:var – Vim 预定义的内部变量

你可以通过 $name 的模式读取或者改写环境变量,同时可以用 &option 的方式来读写 vim 内部的设置值。

数据类型

Number:32 位有符号整数

-1230x100177

Float: 浮点数,需要编译 Vim 的时候,有+float 特性支持

123.4561.15e-6-1.1e3

String: NULL 结尾的 8位无符号字符串

"ab\txx\"--"'x-z''a,c'

Funcref: 函数引用,函数引用类型的变量名必须以大写字母开头

:let Myfunc = function("strlen"):echo Myfunc('foobar') " Call strlen on 'foobar'.6

List: 有序列表

:let mylist = [1, 2, ['a', 'b']]:echo mylist[0]1:echo mylist[2][0]a:echo mylist[-2]2:echo mylist[999]E684: list index out of range: 999:echo get(mylist, 999, "THERE IS NO 1000th ELEMENT")THERE IS NO 1000th ELEMENT

Dictionary: 无序的 Key/Value 容器

:let mydict = {'blue': "#0000ff", 'foo': {999: "baz"}}:echo mydict["blue"]#0000ff:echo mydict.foo{999: "baz"}:echo mydict.foo.999baz:let mydict.blue = "BLUE":echo mydict.blueBLUE

没有布尔类型,整数 0 被当作假,其他被当作真。字符串在比较真假前会被转换成整数,大部分字符串都会被转化为 0,除非以非零开头的字符串才会转化成非零。

Continue reading

Loading

Posted in随笔|Tagged|Leave a comment

Vim 8 下 C/C++ 开发环境搭建

挺多人问怎么在 Vim 中搭建 C/C++ 开发环境,我本来想找篇文章发给人家,结果网上看了一圈,要不就是内容太过陈旧,要不就是太过零碎,不成体系。2018 年了,Vim 8 发布已经一年半,各大 Linux 发行版和 Mac OS X自带的 Vim 都已经跟进到 8了,不少文章还在介绍一些十年前的老方法。于是有了这篇文章。

那如何高效的再 Vim 8 中开发 C/C++ 项目呢?假设你已经有一定 Vim 使用经验,并且折腾过 Vim 配置,能够相对舒适的在 Vim 中编写其他代码的时候,准备在 Vim 开始 C/C++ 项目开发,或者你已经用 Vim 编写了几年 C/C++ 代码,想要更进一步,让自己的工作更加顺畅的话,本文就是为你准备的:

插件管理

为什么把插件管理放在第一个来讲呢?这是比较基本的一个东西,如今 Vim 下熟练开发的人,基本上手都有 20-50 个插件,遥想十年前,Vim里常用的插件一只手都数得过来。过去我一直使用老牌的Vundle 来管理插件,但是随着插件越来越多,更新越来越频繁,Vundle 这种每次更新就要好几分钟的东西实在是不堪重负了,在我逐步对 Vundle 失去耐心之后,我试用了vim-plug ,用了两天以后就再也回不去 Vundle了,它支持全异步的插件安装,安装50个插件只需要一分钟不到的时间,这在 Vundle 下面根本不可想像的事情,插件更新也很快,不像原来每次更新都可以去喝杯茶去,最重要的是它支持插件延迟加载:

" 定义插件,默认用法,和 Vundle 的语法差不多Plug 'junegunn/vim-easy-align'Plug 'skywind3000/quickmenu.vim'" 延迟按需加载,使用到命令的时候再加载或者打开对应文件类型才加载Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }Plug 'tpope/vim-fireplace', { 'for': 'clojure' }" 确定插件仓库中的分支或者 tagPlug 'rdnetto/YCM-Generator', { 'branch': 'stable' }Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }

定义好插件以后一个::PlugInstall 命令就并行安装所有插件了,比 Vundle 快捷不少,关键是 vim-plug 只有单个文件,正好可以放在我 github 上的 vim 配置仓库中,每次需要更新 vim-plug 时只需要:PlugUpgrade,即可自我更新。

抛弃 Vundle 切换到 vim-plug 以后,不仅插件安装和更新快了一个数量级,大量的插件我都配置成了延迟加载,Vim 启动速度比 Vundle 时候提高了不少。使用 Vundle 的时候一旦插件数量超过30个,管理是一件很痛苦的事情,而用了 vim-plug 以后,50-60个插件都轻轻松松。

符号索引

现在有好多 ctags 的代替品,比如 gtags, etags 和 cquery。然而我并不排斥 ctags,因为他支持 50+ 种语言,没有任何一个符号索引工具有它支持的语言多。同时 Vim 和 ctags 集成的相当好,用它依赖最少,大量基础工作可以直接通过 ctags 进行,然而到现在为止,我就没见过几个人把 ctags 用对了的。

就连配置文件他们都没写对,正确的 ctags 配置应该是:

set tags=./.tags;,.tags

这里解释一下,首先我把 tag 文件的名字从tags 换成了.tags,前面多加了一个点,这样即便放到项目中也不容易污染当前项目的文件,删除时也好删除,gitignore 也好写,默认忽略点开头的文件名即可。

前半部分./.tags; 代表在文件的所在目录下(不是:pwd 返回的 Vim 当前目录)查找名字为.tags 的符号文件,后面一个分号代表查找不到的话向上递归到父目录,直到找到.tags 文件或者递归到了根目录还没找到,这样对于复杂工程很友好,源代码都是分布在不同子目录中,而只需要在项目顶层目录放一个.tags文件即可;逗号分隔的后半部分.tags 是指同时在 Vim 的当前目录(:pwd命令返回的目录,可以用:cd ..命令改变)下面查找.tags 文件。

最后请更新你的 ctags,不要再使用老旧的 Exuberant Ctags,这货停止更新快十年了,请使用最新的Universal CTags 代替之,它在 Exuberant Ctags 的基础上继续更新迭代了近十年,如今任然活跃的维护着,功能更强大,语言支持更多。

(注意最新版 universal ctags 调用时需要加一个 –output-format=e-ctags,输出格式才和老的 exuberant ctags 兼容否则会有 windows 下路径名等小问题)。

自动索引

过去写几行代码又需要运行一下 ctags 来生成索引,每次生成耗费不少时间。如今 Vim 8 下面自动异步生成 tags 的工具有很多,这里推荐最好的一个:vim-gutentags,这个插件主要做两件事情:

  • 确定文件所属的工程目录,即文件当前路径向上递归查找是否有.git,.svn,.project 等标志性文件(可以自定义)来确定当前文档所属的工程目录。
  • 检测同一个工程下面的文件改动,能会自动增量更新对应工程的.tags 文件。每次改了几行不用全部重新生成,并且这个增量更新能够保证.tags 文件的符号排序,方便 Vim 中用二分查找快速搜索符号。

vim-gutentags 需要简单配置一下:

" gutentags 搜索工程目录的标志,碰到这些文件/目录名就停止向上一级目录递归let g:gutentags_project_root = ['.root', '.svn', '.git', '.hg', '.project']" 所生成的数据文件的名称let g:gutentags_ctags_tagfile = '.tags'" 将自动生成的 tags 文件全部放入 ~/.cache/tags 目录中,避免污染工程目录let s:vim_tags = expand('~/.cache/tags')let g:gutentags_cache_dir = s:vim_tags" 配置 ctags 的参数let g:gutentags_ctags_extra_args = ['--fields=+niazS', '--extra=+q']let g:gutentags_ctags_extra_args += ['--c++-kinds=+px']let g:gutentags_ctags_extra_args += ['--c-kinds=+px']

有了上面的设置,你平时基本感觉不到 tags 文件的生成过程了,只要文件修改过,gutentags 都在后台为你默默打点是否需要更新数据文件,你根本不用管,还会帮你:

setlocal tags+=...

为当前文件添加上对应的 tags 文件的路劲而不影响其他文件。得益于 Vim 8 的异步机制,你可以任意随时使用 ctags 相关功能,并且数据库都是最新的。需要注意的是,gutentags 需要靠上面定义的 project_root 里的标志,判断文件所在的工程,如果一个文件没有托管在 .git/.svn 中,gutentags 找不到工程目录的话,就不会为该野文件生成 tags,这也很合理。想要避免的话,你可以在你的野文件目录中放一个名字为.root 的空白文件,主动告诉 gutentags 这里就是工程目录。

最后啰嗦两句,少用CTRL-] 直接在当前窗口里跳转到定义,多使用CTRL-W ] 用新窗口打开并查看光标下符号的定义,或者CTRL-W } 使用 preview 窗口预览光标下符号的定义。

我自己还写过不少关于 ctags 的 vimscript,例如在最下面命令行显示函数的原型而不用急着跳转,或者重复按ALT+; 在 preview 窗口中轮流查看多个定义,不切走当前窗口,不会出一个很长的列表让你选择,有兴趣可以刨我的vim dotfiles

编译运行

再 Vim 8 以前,编译和运行程序要么就让 vim 傻等着结束,不能做其他事情,要么切到一个新的终端下面去单独运行编译命令和执行命令,要么开个 tmux 左右切换。如今新版本的异步模式可以让这个流程更加简化,这里我们使用AsyncRun 插件,简单设置下:

Plug 'skywind3000/asyncrun.vim'" 自动打开 quickfix window ,高度为 6let g:asyncrun_open = 6" 任务结束时候响铃提醒let g:asyncrun_bell = 1" 设置 F10 打开/关闭 Quickfix 窗口nnoremap <F10> :call asyncrun#quickfix_toggle(6)<cr>

该插件可以在后台运行 shell 命令,并且把结果输出到 quickfix 窗口:

最简单的编译单个文件,和 sublime 的默认 build system 差不多,我们定义 F9 为编译单文件:

Continue reading

Loading

Posted in随笔|Tagged|21 Comments

Vim 中文速查表/Cheatsheet(全网最完善)

春节期间整理了一份 Vim 中文速查表,免得经常东搜索西搜索的:

https://github.com/skywind3000/awesome-cheatsheets/blob/master/editors/vim.txt

看了一下,应该是现在 Vim 所有中英文速查表里最完善的一份,有时候速查表比看书搜网页高效多了。

Loading

Posted in随笔|Tagged|Leave a comment