Search code examples
luaeditorneovim

How to run commands sequentially via Neovim's jobstart in Lua?


Given a series of commands to run, where each subsequent command depends on the completion of the previous, how can one execute these commands sequentially in Lua via Neovim's job control functionality?

As an example, when compiling .tex files, one often needs to run pdflatex twice, followed by biber, and then a final run of pdflatex in order to resolve all references/hyperlinks within the document.

When attempting to do this with multiple jobstart calls as shown below, the calls are made in separate spawned jobs, which means that (in effect) they are happening "simultaneously", leading to compilation errors:

local pdflatex_cmd = "pdflatex file.tex"
local biber_cmd = "biber file.tex"

vim.fn.jobstart(pdflatex_cmd)
vim.fn.jobstart(pdflatex_cmd)
vim.fn.jobstart(biber_cmd)
vim.fn.jobstart(pdflatex_cmd)

Attempts to use job_running = vim.fn.jobwait({job_id}, 0)[0] == -1 in between each vim.fn.jobstart() call with the corresponding job ID to iteratively check the status of a job (i.e. wait) fails to work.

Is there a way to ensure that the previous command issued with jobstart has completed, either by using vim.fn.jobwait() or by some other means?


Solution

  • Instead of attempting to run multiple commands separately, one can concatenate them with ; as a separator and pass the result to jobstart. For example:

    local pdflatex_cmd = "pdflatex file.tex"
    local biber_cmd = "biber file.tex"
    local multiple_cmds = pdflatex_cmd .. "; " .. pdflatex_cmd .. "; " .. biber_cmd .. "; " .. pdflatex_cmd
    
    vim.fn.jobstart(multiple_cmds)
    

    On Linux, separating commands with ; (e.g. cmd1; cmd2; cmd3) allows one to run each command after the previous regardless of whether the previous command executed successfully, or with errors. For completeness:

    • If the subsequent command must only run when the previous command executed successfully, then && can be used. For example, when issuing cmd1 && cmd2 && cmd3, if cmd1 fails, cmd2 won't be executed. Using this option would be ideal for compiling .tex documents as one doesn't need subsequent commands to run if the previous failed.
    • If the subsequent command must only run when the previous command executes with errors, then || can be used. For example, when issuing cmd1 || cmd2 || cmd3, if cmd1 fails, cmd2 will be executed.