Neovim 异步缓冲区等待

Neovim asynchronous buffer waiting

我正在开发一个与终端缓冲区中的 REPL 交互的 Neovim 插件。我希望能够向 REPL 发送命令,复制响应,并以某种方式将其显示给用户。目前,在当前 vim 脚本函数终止之前,终端缓冲区似乎不会刷新输出,所以我不能有一个函数可以这样做,例如:

function! plugin#eval(str)
    call s:send_to_repl(str)
    echomsg s:get_response()
endfunction

因为 get_response 函数在更新之前正在使用终端缓冲区。

目前,我正在使用 neovim 的作业控制,不过如果这可以在 vanilla vim 中完成,那就更好了。

这是我用来初始化终端的代码:

function! s:start_buffer(height)
    set bufhidden=hide
    set noswapfile
    set buftype=nofile
    set hidden
    terminal! stack ghci --with-ghc intero
    let l:buffer_id = bufnr('%')
    let g:intero_job_id = b:terminal_job_id
endfunction

以下是我向 REPL 发送命令的方式:

function! s:send(str)
    call jobsend(g:intero_job_id, add([a:str], ''))
endfunction

我试过添加 edit 命令来刷新,但这在 REPL 中似乎不起作用。

与REPL通信的代码是here. The code for managing the process is here.

:term 缓冲区中,您可以设置一个 TextChanged 处理程序。例如。以下代码将整个 :term 缓冲区内容发送到 s:on_response:

autocmd TextChanged <buffer> call <SID>on_response(getline(1,'$'))

找出自上一个 TextChanged 事件以来哪个文本是 "new" 将需要一些自定义逻辑。 '['] 标记未在 :term 缓冲区中正确设置(我不确定 nvim 是否可以自动执行此操作,但我做了一个 bug report).

请注意 TextChanged 仅在用户处于正常模式时触发(离开插入模式时也会立即触发)。

TextChangedI(注意最后的 I)应该在插入模式下触发,但它不适用于 :term,那是 bug


另一种方法是使用用户计时器(请参阅 :help timer_start)。这是一个每秒调用 s:on_reponse(timer_id) 的计时器:

call timer_start(1000, '<SID>on_response', {'repeat':-1})

但这并不理想,因为您需要保留终端和计时器 ID 的映射(或遍历所有 :terminal 缓冲区并检查它们的内容)。


我为 jobattach() 函数创建了一个 feature request,它允许将 on_stdout 处理程序附加到现有作业(而 jobstart() 仅将处理程序添加到 个职位)。然后可以使用它附加到任何 :term 缓冲区的 b:terminal_job_id