asyncrun.vim 是个发布于今六年前的老插件了,常常被大家用来在 quickfix 中异步运行 shell 命令,当时 vim 还是 7.4.1829 ,+job
特性刚刚能用,因为做这个插件给 bram 提了十几个关于 +job
和 quickfix 的 issue ,都被他快速修正了,并在 8.1 时变得稳定可用。
应该说这个插件是伴随 vim 8.0 一路成长稳定起来的,在修改了多年 bug 的同时,也通过收集到的有价值的反馈来不断的打磨自己。乘着新年之际,给大家分享一些该插件最近两年的主要更新,或许能够对大家提高工作效率有所帮助。
不论 Vim 还是 NeoVim 引入内置终端都好多年了,但仍然有一些人习惯在系统终端或者 tmux 之类的地方执行任务。asyncrun 提供了一个 User-Defined Runners 的机制,可以让你按想要的方式运行命令,并同时发布了一些预置的 runner 让你可以方便的用外置终端运行特定命令:
Runner | 描述 | 依赖 |
---|---|---|
gnome |
在新的 gnome-terminal 窗口里运行 | GNOME |
gnome_tab |
在 gnome-terminal 的新 tab 里运行 | GNOME |
tmux |
在 tmux pane 里运行 | Vimux |
xfce |
在新的 xfce 的 terminal 窗口里运行 | xfce4-terminal |
konsole |
在新的 konsole 终端里运行 | KDE |
macos |
在新的 macOS 系统 terminal 里运行 | macOS |
iterm |
在一个新的 iterm2 tab 里运行 | macOS + iTerm2 |
external |
在一个新的 cmd 窗口里运行 | Windows |
当使用 -mode=term
参数调用 asyncrun 命令时,可以用 -pos={runner}
参数来指定 runner 名字:
:AsyncRun -mode=term -pos=gnome ls -la
:AsyncRun -mode=term -pos=floaterm ls -la
:AsyncRun -mode=term -pos=tmux ls -la
当你在 GVim 里使用 gnome
, konsole
, external
或者 xfce
这些 runner 运行命令时,你将会得到同 IDE 里运行命令行程序一模一样的体验:
如果你在终端下使用 Vim ,那么一个新的 gnome-terminal 或者 iterm2 的 tab 是个很恰当的方式:
或者,在一个 tmux 的分屏里运行命令:
除去外部终端外,还有不少 runner 可以和各种著名的 Vim/NeoVim 内置终端增强插件们打交道:
Runner | 描述 | 依赖 |
---|---|---|
floaterm |
在一个新的 floaterm 窗口里 | floaterm |
floaterm_reuse |
在一个可复用的 floaterm 窗口里 | floaterm |
quickui |
在一个 quickui 的 popup 终端里 | vim-quickui |
toggleterm |
再一个 toggleterm 的窗口里 | toggleterm.nvim |
termhelp |
在 terminal-help 的窗口里(可复用) | vim-terminal-help |
使用 floaterm
这个 runner 的效果:
Terminal-help:
所有 Runner 皆可定制,可以修改或者定义新的 runner ,见项目 wiki customize runner.
另外一个比有意思的更新就是对 (neo)vim 内置终端的封装,可以用内置终端运行命令:
" run command in the internal-terminal in a new tab
:AsyncRun -mode=term -pos=tab ls -la
:AsyncRun -mode=term -pos=TAB ls -la
" open on the left/right/top/bottom side
:AsyncRun -mode=term -pos=left ls -la
:AsyncRun -mode=term -pos=right ls -la
:AsyncRun -mode=term -pos=top ls -la
:AsyncRun -mode=term -pos=bottom ls -la
你也许会奇怪,这和直接用内置的 :term xxx
运行 shell 命令有什么区别呢?为什么要用 asyncrun 来调度内置终端呢?理由很简单,便利性:
命令里支持类似 $(VIM_FILENAME)
或者 $(VIM_ROOT)
的宏变量替换:
:AsyncRun -mode=term -pos=TAB ls -la $(VIM_FILEDIR)
可以用 -cwd=
参数指定运行路径:
:AsyncRun -mode=term -pos=TAB -cwd=~/github ls -la
更容易的指定终端窗口的位置和尺寸(非 tab 模式):
:AsyncRun -mode=term -pos=bottom -rows=8 ls -la
:AsyncRun -mode=term -pos=right -cols=40 ls -la
可以用 -focus=0
参数进行无干扰模式(避免切换焦点到新的终端窗口上带来的分心):
:AsyncRun -mode=term -pos=tab -focus=0 ls -la
可以用 -close
来指定程序结束后自动关闭终端窗口:
:AsyncRun -mode=term -pos=tab -focus=0 -close ls -la
可以在任务结束时触发 vim 命令提醒你任务结束:
:AsyncRun -mode=term -post=echo\ 'notify' ls -la
还有其他一些额外好处:
$VIM_FILENAME
之类的会同时初始化。-listed=0
来避免在 buffer-list 里列入 terminal buffer 。-hidden=1
来将 terminal buffer 的 bufhidden
设置为 hide
。-reuse
来指定复用已经结束的内置终端窗口。最重要的是 vim/neovim 中用 :term xxx
传递包含多个单双引号,竖线,重定向符号等的复杂命令时,经常不能正确解析,特别是一些小众 shell 或者 windows 下面,而 AsyncRun 命令可以准确的传递参数。
在终端下使用 Vim 时,我个人最喜欢的内置终端位置是 -pos=TAB
,和小写的 -pos=tab
不同,这个方式会在当前 tabpage 的 左边 创建新 tab 运行内置终端命令。如此,在命令结束的时候,就能刚好回到我先前工作的 tabpage ,也回到我之前编辑的文档上:
除去宏变量替换外,上面大部分行为是可以用 :term
命令搭配 2-3 条其他命令来完成,但是用 asyncrun 只需要一条唯一的命令就能搞定这些琐碎的事情,并且消除了 vim 和 neovim 的体验差别。
asyncrun.vim 提供了可以用任何方式运行命令的方式,并且为他们提供了统一的封装和诸如宏变量,工作目录指定,窗口位置和焦点控制之类的增强。你可以从项目的 wiki: 命令用法说明 查看更多用法。
PS:如果你觉得为不同的项目或者文件类型建立 asyncrun 的 keymap 很麻烦,你可以试试兄弟插件 asynctasks.vim,它使用 asyncrun 作为运行命令的后端,并且给 vim 引入了类似 vscode 任务系统的机制,不管是运行外部命令还是执行内部 vim 命令,一切行为皆可以看作 “任务”,而对于同一个任务,在不同的项目内又有不同的执行方式,asynctasks.vim 可以帮你轻松的打理这些问题。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.