本插件使用 Vim 8 / NeoVim 的异步机制,让你在后台运行 shell 命令,并将结果实时显示到 Vim 的 Quickfix 窗口中:
:AsyncRun {command}
即可在后台执行你的命令(和传统的 !
命令类似)。errorformat
匹配。asyncrun.vim
源文件。具体运行效果,可以看下面的 GIF 截屏。
-mode=term
在内置终端里运行你的命令,见 内置终端。:%AsyncRun cat
。-cwd=<root>
可以指定在项目的根目录运行命令,见 project-root。拷贝 asyncrun.vim
到你的 ~/.vim/plugin
目录,或者用 vim-plug/Vundle 之类的包管理工具从 skywind3000/asyncrun.vim
位置安装。
异步运行 gcc/grep 的演示,别忘记在运行前使用 :copen
命令打开 vim 的 quickfix 窗口,否则你看不到具体输出,还可以设置 g:asyncrun_open=6
来自动打开。
异步运行 gcc 编译当前的文件
:AsyncRun gcc % -o %<
:AsyncRun g++ -O3 "%" -o "%<" -lpthread
上面的命令会在后台运行 gcc 命令,并把编译输出实时显示到 quickfix 窗口中,标记 '%
' 代表当前正在编辑的文件名,而 '%<
' 代表去掉扩展名的文件名。
异步运行 make
:AsyncRun make
:AsyncRun make -f makefile
记得在执行 AsyncRun
命令前,提前使用 copen
命令打开 quickfix 窗口,不然你看不到任何内容。
Grep 关键字
:AsyncRun! grep -n -R word .
:AsyncRun! grep -n -R <cword> .
当 AsyncRun
命令后面追加一个叹号时,quickfix 将不会自动滚动,保持在第一行。<cword>
代表光标下面的单词。
编译 go 项目
:AsyncRun go build "%:p:h"
标记 '%:p:h
' 表示当前文件的所在目录。
查看 man page
:AsyncRun! man -S 3:2:1 <cword>
异步 git push
:AsyncRun git push origin master
初始化 <F7>
来编译文件
:noremap <F7> :AsyncRun gcc "$(VIM_FILEPATH)" -o "$(VIM_FILEDIR)/$(VIM_FILENAME)" <cr>
文件可能会包含空格,所以正式使用推荐用 $(...)
的宏形,后面有表格说明可用宏。
运行 Python 脚本
:AsyncRun -raw python %
使用 -raw
参数可以在 quickfix 中显示原始输出(不进行 errorformat 匹配),记得用 let $PYTHONNUNBUFFERED=1
来禁止 python 的行缓存,这样可以实时查看结果。很多程序在后台运行时都会将输出全部缓存住直到调用 flush 或者程序结束,python 可以设置该变量来禁用缓存,让你实时看到输出,而无需每次手工调用 sys.stdout.flush()
。
关于缓存的更多说明见 这里.
使用 AsyncRun 的助手
asynctasks.vim 是一个使用 asyncrun 提供任务管理的插件,帮助你管理一系列 building, testing 和 deploying 的任务,并且方便的调度他们。
本插件有且只提供了两条命令::AsyncRun
以及 :AsyncStop
来控制你的任务。
:AsyncRun[!] [options] {cmd} ...
在后台运行 shell 命令,并把结果实时输出到 quickfix 窗口,当命令后跟随一个 !
时,quickfix 将不会自动滚动。参数用空格分隔,如果某项参数包含空格,那么需要双引号引起来(unix 下面还可以使用反斜杠加空格)。
参数可以接受各种以 '%
', '#
' or '<
' 开头的文件名宏:
%:p - 当前 buffer 的文件名全路径
%:t - 当前 buffer 的文件名(没有前面的路径)
%:p:h - 当前 buffer 的文件所在路径
%:e - 当前 buffer 的扩展名
%:t:r - 当前 buffer 的主文件名(没有前面路径和后面扩展名)
% - 相对于当前路径的文件名
%:h:. - 相对于当前路径的文件路径
<cwd> - 当前路径
<cword> - 光标下的单词
<cfile> - 光标下的文件名
<root> - 当前 buffer 的项目根目录
在运行前会批量初始化一些环境变量(方便你在 shell 脚本中使用):
$VIM_FILEPATH - 当前 buffer 的文件名全路径
$VIM_FILENAME - 当前 buffer 的文件名(没有前面的路径)
$VIM_FILEDIR - 当前 buffer 的文件所在路径
$VIM_FILEEXT - 当前 buffer 的扩展名
$VIM_FILENOEXT - 当前 buffer 的主文件名(没有前面路径和后面扩展名)
$VIM_PATHNOEXT - 带路径的主文件名($VIM_FILEPATH 去掉扩展名)
$VIM_CWD - 当前 Vim 目录
$VIM_RELDIR - 相对于当前路径的文件名
$VIM_RELNAME - 相对于当前路径的文件路径
$VIM_ROOT - 当前 buffer 的项目根目录
$VIM_CWORD - 光标下的单词
$VIM_CFILE - 光标下的文件名
$VIM_GUI - 是否在 GUI 下面运行?
$VIM_VERSION - Vim 版本号
$VIM_COLUMNS - 当前屏幕宽度
$VIM_LINES - 当前屏幕高度
$VIM_SVRNAME - v:servername 的值
上面这些环境变量,可以使用 $(...)
的形式(比如 $(VIM_FILENAME)
之类)用在 AsyncRun 的参数里面,这样的用法比 %
前缀的 vim 宏要安全,因为百分号的 vim 宏是由 vim 展开的,当使用 -cwd=?
时百分号宏会失效,所以调用 AsyncRun
命令时,推荐使用 $(...)
形式的参数。
宏 $(VIM_ROOT)
或者 <root>
指代当前文件的项目根目录。
调用 AsyncRun
时,在具体的命令前面可以有一些 -
开头的参数:
参数 | 默认值 | 含义 |
---|---|---|
-mode=? |
"async" | 用 -mode=? 的形式指定运行模式可选模式有: "async" (默认模式,后台运行输出到 quickfix), "bang" (使用 ! 命令运行) 以及 "terminal" (在内建终端运行), 具体查看 运行模式。 |
-cwd=? |
未设置 |
命令初始目录(没有设置就用 vim 当前目录),比如 -cwd=<root> 就能在 项目根目录 运行命令,或者 -cwd=$(VIM_FILEDIR) 就能在当前文件所在目录运行命令。 |
-save=? |
0 | 运行命令前是否保存文件,-save=1 保存当前文件,-save=2 保存所有修改过的文件 |
-program=? |
未设置 |
设置成 make 可以用 &makeprg ,设置成 grep 可以使用 &grepprt ,而设置成 wsl 则可以在 WSL 中运行命令 (需要 Windows 10) |
-post=? |
未设置 |
命令结束后自动运行的 vimscript,如果包含空格则要用反斜杠加空格代替。 |
-auto=? |
未设置 |
出发 autocmd QuickFixCmdPre /QuickFixCmdPost 后面的名称。 |
-raw |
未设置 |
如果提供了,就输出原始内容,忽略 &errorformat 过滤。 |
-strip |
未设置 |
过滤收尾消息 (头部命令名称以及尾部 "[Finished in ...]" 信息)。 |
-pos=? |
"bottom" | 当用 -mode=term 在内置终端运行命令时, -pos 用于指定内置终端窗口位置, 可以设置成 "tab" ,"curwin" ,"top" ,"bottom" ,"left" ,"right" 和 "external" 。 |
-rows=num |
0 | 内置终端窗口的高度。 |
-cols=num |
0 | 内置终端窗口的宽度。 |
-errorformat=? |
未设置 |
用于 quickfix 中匹配错误输出的格式字符串,如果未提供,则使用当前 &errorformat 的值。注意 % 需要转写成 \% 。 |
-focus=? |
1 | 设置成 0 可以防止使用内置终端时窗口焦点切换。 |
-hidden=? |
0 | 设置成 1 可以将内置终端的 bufhidden 初始化为 hide |
所有的这些配置参数都必须放在具体 shell 命令 前面,因为没有任何 shell 命令使用 -
开头,因此很容易区分哪里是命令的开始。如果你确实有一条 shell 命令是减号开头的,那么为了明显区别参数和命令,可以在命令前面放一个 @
符号,那么 AsyncRun 在解析参数时碰到 @
就知道参数结束了,后面都是命令。
:AsyncStop[!]
没有叹号时,使用 TERM
信号尝试终止后台任务,有叹号时会使用 KILL
信号来终止。
本插件提供了函数形式的接口,方便你在 vimscript 中调用:
:call asyncrun#run(bang, opts, command)
参数说明:
bang
:空字符串或者内容是一个叹号的字符串 "!"
和 AsyncRun!
的叹号作用一样。opts
:参数字典,包含:mode
, cwd
, raw
以及 errorformat
等。command
:具体要运行的命令。&encoding
,不一致,那么在这里设置一下,具体见 编码设置。nice
。更多配置内容,见 这里.
autocmd User AsyncRunPre - 运行前触发
autocmd User AsyncRunStart - 命令成功开始了触发
autocmd User AsyncRunStop - 命令结束时触发
注意,AsyncRunPre
一般都会被触发,但是 AsyncRunStart
和 AsyncRunStop
只会在任务成功开始的情况下才会被触发。
比如当前任务未结束,AsyncRun 会失败。在这种情况下,AsyncRunPre
会被触发,但是 AsyncRunStart
和 AsyncRunStop
无法触发。
Vim 缺乏项目管理,然而日常编辑的一个个文件,大部分都会从属于某个项目。如果你缺乏项目相关的信息,你就很难针对项目做点什么事情。参考 CtrlP 插件的设计,AsyncRun 使用 root markers
的机制来识别项目的根路径,当前文件所在的项目目录是该文件的最近一级包含 root marker
的父目录(默认为.git
, .svn
, .root
以及 .project
),如果递归到根目录还没找到标识文件,那么会用当前文件所在目录代替。
在命令或者 -cwd=?
参数中使用 <root>
或者 $(VIM_ROOT)
来表示当前文件的 项目根目录,比如:
:AsyncRun make
:AsyncRun -cwd=<root> make
第一个 make
命令会在 vim 的当前路径(可以用 :pwd
命令查看)下面执行,而第二个 make
命令会在当前的项目根目录下面执行。当你要对整个项目做点什么的时候(比如 make/grep),这个特性会非常有用。
更多信息参考:Project Root.
AsyncRun 可以用 -mode=?
参数指定运行模式,不指定的话,将会用默认模式,在后台运行,并将输出实时显示到 quickfix 窗口,然而你还可以用 -mode=?
设置成下面几种运行模式:
模式 | 说明 |
---|---|
async | 默认模式,在后台运行命令,并将输出实时显示到 quickfix 窗口。 |
bang | 用 Vim 传统的 :! 命令执行。 |
term | 使用一个可复用的内部终端执行命令。 |
更多信息,见 这里.
最新版 AsyncRun 除了在 quickfix 窗口里运行程序外,还增加了对内置终端的支持,有几个目的:
:term xxx
很难裸用,Vim/NeoVim 体验不一致,参数不一致,窗口无法复用,不能指定初始位置。如果 AsyncRun
命令后加了一个 -mode=term
参数,那么将会在 Vim 内置终端中运行命令,在该模式下,还可以提供一个 -pos=?
来指定终端窗口的位置:
-pos=tab
: 在新的 tab 中打开终端。-pos=curwin
: 在当前窗口打开终端。-pos=top
: 在上方打开终端。-pos=bottom
: 在下方打开终端。-pos=left
: 在左边打开终端。-pos=right
: 在右边打开终端。-pos=hidden
: 不打开终端窗口,隐藏在后台运行。-pos=external
: 使用外部终端(仅支持 Windows)。建议 Windows 下面直接用 -pos=external
。
例子:
:AsyncRun -mode=term -pos=tab python "$(VIM_FILEPATH)"
:AsyncRun -mode=term -pos=bottom -rows=10 python "$(VIM_FILEPATH)"
:AsyncRun -mode=term -pos=right -cols=80 python "$(VIM_FILEPATH)"
:AsyncRun -mode=term -pos=curwin python "$(VIM_FILEPATH)"
:AsyncRun -mode=term -pos=curwin -hidden python "$(VIM_FILEPATH)"
当你用内置终端时,AsyncRun 会先检查是否有之前已经运行结束的终端窗口,有的话会复用,没有的话,才会新建一个 split。可以使用 -pos=TAB
,大写的 tab 表示在当前 tab 的左边打开内置终端 tab。
除了 quickfix 和内置终端外,AsyncRun 还可以在另一个 tmux 窗口或者一个新的 gnome-terminal 窗口/tab 中运行程序,感兴趣可以参考 自定义运行模式 中的例子。
默认运行模式下,AsyncRun 会在 quickfix 窗口中显示任务的输出,所以如果你事先没有用 :copen {height}
打开 quickfix 窗口,你将会看不到任何内容。方便起见,引入了一个 g:asyncrun_open
的全局配置,如果设置成非零:
:let g:asyncrun_open = 8
那么在运行命令前,会自动按照 8 行的高度打开 quickfix 窗口。
AsyncRun 可以指定一个当前 buffer 的文本范围,用作命令的 stdin 输入,比如:
:%AsyncRun cat
那么当前文件的整个内容将会作为命令 cat
的标准输入传递过去,这个命令运行后,quickfix 窗口内将会显示当前文件的所有内容。
:10,20AsyncRun python
使用当前 buffer 的第 10 行到 20 行的内容作为命令 python 的标准输入,可以用来执行一小段 python 代码,并在 quickfix 展现结果。
:'<,'>AsyncRun -raw perl
选中区域的文本 (行模式) 作为标准输入。
你可能还希望更多的执行方式,比如在新的 tmux 或者 gnore-terminal 的窗口里运行,AsyncRun 允许你自定义 runner:
function! MyRunner(opts)
echo "command to run is: " . a:opts.cmd
endfunction
let g:asyncrun_runner = get(g:, 'asyncrun_runner', {})
let g:asyncrun_runner.test = function('MyRunner')
然后试试:
:AsyncRun -mode=term -pos=test ls -la $(VIM_FILEDIR)
当 -mode
的值是 term
时,可以用 -pos
来表示自定义 runner 的名字(除了保留的几个外)。
Runner 函数只有一个参数:opts
,是一个字典,里面保存着 :AsyncRun
命令行里传过来的值,同时 opts.cmd
记录着需要运行的命令。
关于更多 tmux / gnome-terminal 的 runner 例子,以及更多运行模式,参考 自定义运行模式 。
命令修改器可以在你运行前修改你的命令内容:
let g:asyncrun_program = get(g:, 'asyncrun_program', {})
let g:asyncrun_program.nice = { opts -> 'nice -5' . opts.cmd }
上面的代码定义了一个叫做 nice
的修改器,在调用时指明 -program=nice
时:
:AsyncRun -program=nice ls -la
原先命令 ls -la
就会被替换成: nice -5 ls -la
。
这个功能其实非常有用,前面的 -program=msys
或者 -program=wsl
都是用命令修改器实现的,比如它会把 ls
命令变成:
c:\windows\sysnative\wsl.exe ls
并替换类似 $(WSL_FILENAME)
以及 $(WSL_FILEPATH)
的宏,你的命令就能在 wsl 下运行了。
Vim 7.4.1829 是最低的运行版本,如果低于此版本,运行模式将会从 async
衰退回 sync
。NeoVim 0.1.4 是最低的 nvim 版本。
推荐使用 vim 8.0 及以后的版本。
asyncrun.vim 可以同 vim-fugitive
协作,为 fugitive 提供异步支持,具体见 here.
Don't forget to read the Frequently Asked Questions.
Name | Description |
---|---|
vim-fugitive | perfect cooperation, asyncrun gets Gfetch/Gpush running in background |
errormarker | perfect cooperation, errormarker will display the signs on the error or warning lines |
airline | very well, airline will display status of background jobs |
sprint | nice plugin who uses asyncrun to provide an IDE's run button to runs your code |
netrw | netrw can save remote files on background now. Experimental, take your own risk |
See: Cooperate with famous plugins
Trying best to provide the most simply and convenience experience in the asynchronous-jobs.
Author: skywind3000 Please vote it if you like it: http://www.vim.org/scripts/script.php?script_id=5431
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。