asyncrun 发布六年后的更新

2022-01-05 04:55:58 +08:00
 skywind3000

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.

Internal terminal

另外一个比有意思的更新就是对 (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/neovim 中用 :term xxx 传递包含多个单双引号,竖线,重定向符号等的复杂命令时,经常不能正确解析,特别是一些小众 shell 或者 windows 下面,而 AsyncRun 命令可以准确的传递参数。

在终端下使用 Vim 时,我个人最喜欢的内置终端位置是 -pos=TAB,和小写的 -pos=tab 不同,这个方式会在当前 tabpage 的 左边 创建新 tab 运行内置终端命令。如此,在命令结束的时候,就能刚好回到我先前工作的 tabpage ,也回到我之前编辑的文档上:

除去宏变量替换外,上面大部分行为是可以用 :term 命令搭配 2-3 条其他命令来完成,但是用 asyncrun 只需要一条唯一的命令就能搞定这些琐碎的事情,并且消除了 vim 和 neovim 的体验差别。

Summary

asyncrun.vim 提供了可以用任何方式运行命令的方式,并且为他们提供了统一的封装和诸如宏变量,工作目录指定,窗口位置和焦点控制之类的增强。你可以从项目的 wiki: 命令用法说明 查看更多用法。

PS:如果你觉得为不同的项目或者文件类型建立 asyncrun 的 keymap 很麻烦,你可以试试兄弟插件 asynctasks.vim,它使用 asyncrun 作为运行命令的后端,并且给 vim 引入了类似 vscode 任务系统的机制,不管是运行外部命令还是执行内部 vim 命令,一切行为皆可以看作 “任务”,而对于同一个任务,在不同的项目内又有不同的执行方式,asynctasks.vim 可以帮你轻松的打理这些问题。

3149 次点击
所在节点    Vim
16 条回复
icySoda
2022-01-05 09:16:33 +08:00
这标题起得好像 6 年才更新一次似的
kindjeff
2022-01-05 09:34:13 +08:00
如果用 floatterm 等 terminal 插件的话,直接启动一个 terminal 再去敲命令不是更顺手么(另外 floatterm 和很多 shell 命令有直接的集成)
kindjeff
2022-01-05 09:34:56 +08:00
floatterm->floaterm
xuboying
2022-01-05 10:15:15 +08:00
Asyncrun 应该可以理解成 vsc 的 task 吧,或者说后者是借鉴 asyncrun ?
执行 ls 这种只是演示例子,实际上应该执行一些更复杂的命令
skywind3000
2022-01-05 10:19:57 +08:00
@kindjeff 对于偶然用的命令,终端里直接敲即可,对于重复命令,显然自动化更好,比如可以 map 到 f9 或者 f10 上,一按即可。
skywind3000
2022-01-05 10:21:02 +08:00
@xuboying asynctasks.vim 才是对标 vscode 的 task ,而且更强。
haoliang
2022-01-05 23:13:51 +08:00
对 neovim 的深度支持我比较惊讶,因为结合之前在知乎看到的楼主关于 neovim 的回答,楼主给我的感觉是对 neovim 并不看好。
完整看下来,我其实没有找到适合的使用场景。tmux (popup)、rofi 、neovim (lua 、floatwin) 已经解决我可以想见的异步任务使用场景了。
可能我这回复像是单纯在刷存在感...不过我早上就看到这帖子,脑子里搁了一天,就当提供一个没有引入该工具的路人视角吧
skywind3000
2022-01-06 06:33:53 +08:00
@haoliang 这和你开发用的语言有关,比如你如果是开机启动个浏览器,然后就一直改代码,刷新浏览器,那么确实没有用武之地,你如果开发需要频繁编译,或者执行的程序,那你一看就知道用在哪里了。
xuboying
2022-01-06 10:51:10 +08:00
趁着大佬在问个问题
我现在用 vim 比较少,主要我觉得还是我不太会用。比如我想实现 git grep 以后加入到 leadf 的 quickfixwindow , 每次调用都很慢。我是这么做的:

先在 quickui 里加一个内容,然后执行这个菜单,调用命令行,补完 git 的 grep 的关键字
我觉得不满意的地方是,调用麻烦,mapping 用完了。quickui 也不能实现调用顺序重排序。操错比较慢
命令重复执行不能重新补全,比如写错一个字需要修改一下,就得全部重写
另外 quicikui 和 leadf 都很现代化了,输入筐还是老实的命令行,体验不是特别好。
不知道大佬能不能给点建议。谢谢

call quickui#menu#install("&File", [
\ ['Asyncrun (git grep)', 'call _My_UI_asyncrun("git grep -nw --column " . expand("<cword>"))', ''],

function! _My_UI_asyncrun(reply) abort
let l:my_input=input("command=> ", a:reply)
echo l:my_input
execute 'AsyncRun -strip -raw -post=call\ _My_Update_quicklist() ' .l:my_input
endfunction


function! _My_Update_quicklist() abort
let l:foo=getqflist()
let l:bar=[]
let l:skip=0
for l:aaa in l:foo
if l:aaa.valid==1
let l:skip=1
break
endif
call add(l:bar, l:aaa.text)
endfor
if l:skip == 0
cgetexpr l:bar
endif
execute 'LeaderfQuickFix'
endfunction
skywind3000
2022-01-06 12:31:27 +08:00
xuboying
2022-01-06 17:27:20 +08:00
@skywind3000 #10 感谢! quickui 让上了年纪人不用记太多复杂命令了,非常棒! Rebase 到最新的 tag 后能用这个 input 模块了。
zbinlin
2022-01-09 21:38:58 +08:00
可以实现 Bexec 插件那样的功能吗?

PS:好像之前问过类似的问题?😹
skywind3000
2022-01-12 22:50:17 +08:00
@zbinlin 更新一下,我给你加了一下,通过 asyncrun 的 “命令修改器” 机制来完成:

:AsyncRun -program=shebang -raw $(VIM_FILEPATH)
:AsyncRun -program=shebang -mode=term -pos=top $(VIM_FILEPATH)
skywind3000
2022-01-12 22:53:41 +08:00
@zbinlin 你可以定义成一个命令:

command! -nargs=0 AsyncBexec AsyncRun -program=shebang -mode=term -pos=top $(VIM_FILEPATH)

然后用 :AsyncBexec 代替你的老命了
Kaiv2
2022-01-27 11:06:35 +08:00
很好用,配合 LeaderF, floaterm 直接起飞
linuxyz
2022-06-29 13:47:50 +08:00
趕忙去 GitHub ❤👍 一個!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/826234

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX