Home

Awesome

<!-- vim-markdown-toc GFM --> <!-- vim-markdown-toc -->

Intro

job util for vim8 and neovim

features / why another remake:

plugins that based on this plugin:

if you like my work, check here for a list of my vim plugins, or buy me a coffee

Workflow

                      ZFJobStart - \
                           ^        \
                           |         \
                    ZFJobPoolStart    \
                           ^           \
ZFAsyncRun  \              |            \                       / ZFStatuslineLog
ZFAutoScript - => - ZFGroupJobStart ----- => - ZFJobOutput - => - ZFLogWin
                                                                \ ZFPopup

the job control is fully modularized, and can be combined easily to achieve complex logic

it may hard to config for first time, but trust me, it changes the life

How to use

  1. use Vundle or any other plugin manager you like to install

    Plugin 'ZSaberLv0/ZFVimJob'
    Plugin 'ZSaberLv0/ZFVimPopup' " optional, support show job output as popup
    
  2. start the job

    function! s:onOutput(jobStatus, textList, type)
    endfunction
    function! s:onExit(jobStatus, exitCode)
    endfunction
    let jobId = ZFJobStart({
            \   'jobCmd' : 'your job cmd',
            \   'onOutput' : function('s:onOutput'),
            \   'onExit' : function('s:onExit'),
            \   'jobEncoding' : '',
            \   'jobTimeout' : 0,
            \ })
    

    onExit would be called when:

    • job finished successfully, exitCode would be 0
    • job failed, exitCode would be the job's exitCode (ensured string type)
    • stopped manually by ZFJobStop(jobId), exitCode would be g:ZFJOBSTOP
    • failed to start job, exitCode would be g:ZFJOBERROR
  3. start multiple jobs

    function! s:group1_job1(jobStatus)
        " note you may chain vim functions by setting `jobCmd` to vim function
        " no async support for vim functions, though
        call doSomeHeavyWork()
    endfunction
    
    function! s:groupJobOnExit(groupJobStatus, exitCode)
    endfunction
    let groupJobId = ZFGroupJobStart({
            \   'jobList' : [
            \     [
            \       {'jobCmd' : 'group0_job0'},
            \       {'jobCmd' : 'group0_job1'},
            \       ...
            \     ],
            \     [
            \       {'jobCmd' : 'group1_job0'},
            \       {'jobCmd' : function('s:group1_job1')},
            \     ],
            \     ...
            \   ],
            \   'onExit' : function('s:groupJobOnExit'),
            \   'jobTimeout' : 0,
            \ })
    

    group1_xxx would start only after previous group0_xxx's jobs all finished with 0 exitCode

    group's onExit would be called when:

    • all child job finished successfully, group job's exitCode would be 0
    • any child failed with none 0 exitCode, group job's exitCode would be the child's exitCode
    • stopped manually by ZFGroupJobStop(groupJobId), group job's exitCode would be g:ZFJOBSTOP

Fallback Limitations

by default, we would fallback to system() if not job impl available (!ZFJobAvailable()), but there are some limitations you should concern:

API

Jobs

Group jobs

Job Pool

job pool is similar thread pool of other language, you can run as many jobs up to g:ZFJobPoolSize, when exceeds g:ZFJobPoolSize, new jobs would be put to wait until other jobs stopped

job pool has same APIs as ZFJobStart() series, and all of the behaviors are ensured the same:

Utils

Util functions

since low version vim doesn't support function(func, argList), we supply a wrapper to simulate:

and for timers:

and for interval (require ZFJobTimerAvailable()):

Job output

abstract job output is done by default

typically, what you needs to care is the outputTo option in your job option

you may also supply your own onOutput, though

functions:

Statusline log

Log window

Popup

use ZSaberLv0/ZFVimPopup to show job output, see g:ZFAutoScript_outputTo for how to config

Async run

options:

Auto script

options:

Other

verbose log

if any weird things happen, you may enable verbose log by:

let g:ZFJobVerboseLogEnable = 1

and dump the log to file:

:call writefile(g:ZFJobVerboseLog, 'log.txt')

custom impl

job

by default, we support vim8's job_start() and neovim's jobstart(), you may supply your own job impl by:

function! s:jobStart(jobStatus, onOutput, onExit)
    let jobImplId = yourJobStart(...)
    " store impl data if necessary
    let a:jobStatus['jobImplData']['yourJobImplId'] = jobImplId
    " return 1 if success or 0 if failed
    return 1
endfunction
function! s:jobStop(jobStatus)
endfunction
function! s:jobSend(extraArgs0, extraArgs1, jobStatus, text)
endfunction
let g:ZFJobImpl = {
        \   'jobStart' : function('s:jobStart'),
        \   'jobStop' : function('s:jobStop'),
        \   'jobSend' : ZFJobFunc(function('s:jobSend'), [extraArgs0, extraArgs1]),
        \ }

timer

by default, we support by vim's has('timers')

also, we bundled a default fallback impl by CursorHold (which can be disabled by let g:ZFJobTimerFallback = 0), the fallback impl has these limitations:

you may also supply your own timer impl by:

function! s:timerStart(delay, jobFunc)
    let timerId = xxx
    ...
    return timerId
endfunction
function! s:timerStop(timerId)
    ...
endfunction
let g:ZFJobTimerImpl = {
        \   'timerStart' : function('s:timerStart'),
        \   'timerStop' : function('s:timerStop'),
        \ }