From 204e3ca36b6af4bcaafedbc6d57dfa436f7cd6f3 Mon Sep 17 00:00:00 2001 From: w0rp Date: Fri, 12 May 2017 21:43:34 +0100 Subject: [PATCH] Automatically remove jobs from the internal map after they are done --- autoload/ale/engine.vim | 12 +------- autoload/ale/job.vim | 68 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index 299d37df..c778f253 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -396,17 +396,7 @@ function! s:RunJob(options) abort let l:read_buffer = 0 endif - " The command will be executed in a subshell. This fixes a number of - " issues, including reading the PATH variables correctly, %PATHEXT% - " expansion on Windows, etc. - " - " NeoVim handles this issue automatically if the command is a String, - " but we'll do this explicitly, so we use thes same exact command for both - " versions. - let l:command = has('win32') - \ ? 'cmd /c ' . l:command - \ : split(&shell) + split(&shellcmdflag) + [l:command] - + let l:command = ale#job#PrepareCommand(l:command) let l:job_options = { \ 'mode': 'nl', \ 'exit_cb': function('s:HandleExit'), diff --git a/autoload/ale/job.vim b/autoload/ale/job.vim index a9965444..379d3c3a 100644 --- a/autoload/ale/job.vim +++ b/autoload/ale/job.vim @@ -57,31 +57,72 @@ function! s:NeoVimCallback(job, data, event) abort \ a:data, \) else - call ale#util#GetFunction(l:job_info.exit_cb)(a:job, a:data) + try + call ale#util#GetFunction(l:job_info.exit_cb)(a:job, a:data) + finally + " Automatically forget about the job after it's done. + if has_key(s:job_map, a:job) + call remove(s:job_map, a:job) + endif + endtry endif endfunction function! s:VimOutputCallback(channel, data) abort let l:job = ch_getjob(a:channel) let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) - call ale#util#GetFunction(s:job_map[l:job_id].out_cb)(l:job_id, a:data) + + " Only call the callbacks for jobs which are valid. + if l:job_id > 0 + call ale#util#GetFunction(s:job_map[l:job_id].out_cb)(l:job_id, a:data) + endif endfunction function! s:VimErrorCallback(channel, data) abort let l:job = ch_getjob(a:channel) let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) - call ale#util#GetFunction(s:job_map[l:job_id].err_cb)(l:job_id, a:data) + + " Only call the callbacks for jobs which are valid. + if l:job_id > 0 + call ale#util#GetFunction(s:job_map[l:job_id].err_cb)(l:job_id, a:data) + endif endfunction function! s:VimCloseCallback(channel) abort - " Call job_status, which will trigger the exit callback below. - " This behaviour is described in :help job-status - call job_status(ch_getjob(a:channel)) + let l:job = ch_getjob(a:channel) + let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) + let l:info = s:job_map[l:job_id] + + " job_status() can trigger the exit handler. + " The channel can close before the job has exited. + if job_status(l:job) ==# 'dead' + try + call ale#util#GetFunction(l:info.exit_cb)(l:job_id, l:info.exit_code) + finally + " Automatically forget about the job after it's done. + if has_key(s:job_map, l:job_id) + call remove(s:job_map, l:job_id) + endif + endtry + endif endfunction function! s:VimExitCallback(job, exit_code) abort let l:job_id = ale#job#ParseVim8ProcessID(string(a:job)) - call ale#util#GetFunction(s:job_map[l:job_id].exit_cb)(l:job_id, a:exit_code) + let l:info = s:job_map[l:job_id] + let l:info.exit_code = a:exit_code + + " The program can exit before the data has finished being read. + if ch_status(job_getchannel(a:job)) ==# 'closed' + try + call ale#util#GetFunction(l:info.exit_cb)(l:job_id, a:exit_code) + finally + " Automatically forget about the job after it's done. + if has_key(s:job_map, l:job_id) + call remove(s:job_map, l:job_id) + endif + endtry + endif endfunction function! ale#job#ParseVim8ProcessID(job_string) abort @@ -94,6 +135,19 @@ function! ale#job#ValidateArguments(command, options) abort endif endfunction +function! ale#job#PrepareCommand(command) abort + " The command will be executed in a subshell. This fixes a number of + " issues, including reading the PATH variables correctly, %PATHEXT% + " expansion on Windows, etc. + " + " NeoVim handles this issue automatically if the command is a String, + " but we'll do this explicitly, so we use thes same exact command for both + " versions. + return has('win32') + \ ? 'cmd /c ' . a:command + \ : split(&shell) + split(&shellcmdflag) + [a:command] +endfunction + " Start a job with options which are agnostic to Vim and NeoVim. " " The following options are accepted: