mirror of https://github.com/dense-analysis/ale
Add support for managing temporary files/directories
This commit is contained in:
parent
8ad85858b8
commit
88192e8662
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
function! ale#cleanup#Buffer(buffer) abort
|
function! ale#cleanup#Buffer(buffer) abort
|
||||||
if has_key(g:ale_buffer_info, a:buffer)
|
if has_key(g:ale_buffer_info, a:buffer)
|
||||||
|
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||||
|
|
||||||
" When buffers are removed, clear all of the jobs.
|
" When buffers are removed, clear all of the jobs.
|
||||||
for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
|
for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
|
||||||
call ale#engine#ClearJob(l:job)
|
call ale#engine#ClearJob(l:job)
|
||||||
|
|
|
@ -30,10 +30,14 @@ function! ale#engine#InitBufferInfo(buffer) abort
|
||||||
" job_list will hold the list of jobs
|
" job_list will hold the list of jobs
|
||||||
" loclist holds the loclist items after all jobs have completed.
|
" loclist holds the loclist items after all jobs have completed.
|
||||||
" new_loclist holds loclist items while jobs are being run.
|
" new_loclist holds loclist items while jobs are being run.
|
||||||
|
" temporary_file_list holds temporary files to be cleaned up
|
||||||
|
" temporary_directory_list holds temporary directories to be cleaned up
|
||||||
let g:ale_buffer_info[a:buffer] = {
|
let g:ale_buffer_info[a:buffer] = {
|
||||||
\ 'job_list': [],
|
\ 'job_list': [],
|
||||||
\ 'loclist': [],
|
\ 'loclist': [],
|
||||||
\ 'new_loclist': [],
|
\ 'new_loclist': [],
|
||||||
|
\ 'temporary_file_list': [],
|
||||||
|
\ 'temporary_directory_list': [],
|
||||||
\}
|
\}
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -134,6 +138,40 @@ function! ale#engine#JoinNeovimOutput(output, data) abort
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" Register a temporary file to be managed with the ALE engine for
|
||||||
|
" a current job run.
|
||||||
|
function! ale#engine#ManageFile(buffer, filename) abort
|
||||||
|
call add(g:ale_buffer_info[a:buffer].temporary_file_list, a:filename)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Same as the above, but manage an entire directory.
|
||||||
|
function! ale#engine#ManageDirectory(buffer, directory) abort
|
||||||
|
call add(g:ale_buffer_info[a:buffer].temporary_directory_list, a:directory)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#engine#RemoveManagedFiles(buffer) abort
|
||||||
|
if !has_key(g:ale_buffer_info, a:buffer)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Delete files with a call akin to a plan `rm` command.
|
||||||
|
for l:filename in g:ale_buffer_info[a:buffer].temporary_file_list
|
||||||
|
call delete(l:filename)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
let g:ale_buffer_info[a:buffer].temporary_file_list = []
|
||||||
|
|
||||||
|
" Delete directories like `rm -rf`.
|
||||||
|
" Directories are handled differently from files, so paths that are
|
||||||
|
" intended to be single files can be set up for automatic deletion without
|
||||||
|
" accidentally deleting entire directories.
|
||||||
|
for l:directory in g:ale_buffer_info[a:buffer].temporary_directory_list
|
||||||
|
call delete(l:directory, 'rf')
|
||||||
|
endfor
|
||||||
|
|
||||||
|
let g:ale_buffer_info[a:buffer].temporary_directory_list = []
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! s:HandleExit(job) abort
|
function! s:HandleExit(job) abort
|
||||||
if a:job ==# 'no process'
|
if a:job ==# 'no process'
|
||||||
" Stop right away when the job is not valid in Vim 8.
|
" Stop right away when the job is not valid in Vim 8.
|
||||||
|
@ -178,6 +216,10 @@ function! s:HandleExit(job) abort
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" Automatically remove all managed temporary files and directories
|
||||||
|
" now that all jobs have completed.
|
||||||
|
call ale#engine#RemoveManagedFiles(l:buffer)
|
||||||
|
|
||||||
" Sort the loclist again.
|
" Sort the loclist again.
|
||||||
" We need a sorted list so we can run a binary search against it
|
" We need a sorted list so we can run a binary search against it
|
||||||
" for efficient lookup of the messages in the cursor handler.
|
" for efficient lookup of the messages in the cursor handler.
|
||||||
|
@ -424,6 +466,10 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||||
|
|
||||||
if !empty(l:options)
|
if !empty(l:options)
|
||||||
call s:RunJob(l:options)
|
call s:RunJob(l:options)
|
||||||
|
elseif empty(g:ale_buffer_info[a:buffer].job_list)
|
||||||
|
" If we cancelled running a command, and we have no jobs in progress,
|
||||||
|
" then delete the managed temporary files now.
|
||||||
|
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
35
doc/ale.txt
35
doc/ale.txt
|
@ -1037,6 +1037,35 @@ ale#engine#GetLoclist(buffer) *ale#engine#GetLoclist()*
|
||||||
|setqflist()|.
|
|setqflist()|.
|
||||||
|
|
||||||
|
|
||||||
|
ale#engine#ManageFile(buffer, filename) *ale#engine#ManageFile()*
|
||||||
|
|
||||||
|
Given a buffer number for a buffer currently running some linting tasks
|
||||||
|
and a filename, register a filename with ALE for automatic deletion after
|
||||||
|
linting is complete, or when Vim exits.
|
||||||
|
|
||||||
|
If Vim exits suddenly, ALE will try its best to remove temporary files, but
|
||||||
|
ALE cannot guarantee with absolute certainty that the files will be removed.
|
||||||
|
It is advised to create temporary files in the operating system's managed
|
||||||
|
temporary file directory, such as with |tempname()|.
|
||||||
|
|
||||||
|
Directory names should not be given to this function. ALE will only delete
|
||||||
|
files and symlinks given to this function. This is to prevent entire
|
||||||
|
directories from being accidentally deleted, say in cases of writing
|
||||||
|
`dir . '/' . filename` where `filename` is actually `''`, etc. ALE instead
|
||||||
|
manages directories separetly with the |ale#engine#ManageDirectory| function.
|
||||||
|
|
||||||
|
|
||||||
|
ale#engine#ManageDirectory(buffer, directory) *ale#engine#ManageDirectory()*
|
||||||
|
|
||||||
|
Like |ale#engine#ManageFile()|, but directories and all of their contents
|
||||||
|
will be deleted, akin to `rm -rf directory`, which could lead to loss of
|
||||||
|
data if mistakes are made. This command will also delete any temporary
|
||||||
|
filenames given to it.
|
||||||
|
|
||||||
|
It is advised to use |ale#engine#ManageFile()| instead for deleting single
|
||||||
|
files.
|
||||||
|
|
||||||
|
|
||||||
ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
||||||
Given a |String| for a filetype and a |Dictionary| Describing a linter
|
Given a |String| for a filetype and a |Dictionary| Describing a linter
|
||||||
configuration, add a linter for the given filetype. The dictionaries each
|
configuration, add a linter for the given filetype. The dictionaries each
|
||||||
|
@ -1151,6 +1180,12 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
||||||
`command_chain` is recommended where any system calls need to be made to
|
`command_chain` is recommended where any system calls need to be made to
|
||||||
retrieve some kind of information before running the final command.
|
retrieve some kind of information before running the final command.
|
||||||
|
|
||||||
|
If temporary files or directories are created for commands run with
|
||||||
|
`command_callback` or `command_chain`, then these tempoary files or
|
||||||
|
directories can be managed by ALE, for automatic deletion.
|
||||||
|
See |ale#engine#ManageFile()| and |ale#engine#ManageDirectory| for more
|
||||||
|
information.
|
||||||
|
|
||||||
Some programs for checking for errors are not capable of receiving input
|
Some programs for checking for errors are not capable of receiving input
|
||||||
from stdin, as is required by ALE. To remedy this, a wrapper script is
|
from stdin, as is required by ALE. To remedy this, a wrapper script is
|
||||||
provided named in the variable |g:ale#util#stdin_wrapper|. This variable
|
provided named in the variable |g:ale#util#stdin_wrapper|. This variable
|
||||||
|
|
|
@ -2,8 +2,8 @@ Before:
|
||||||
let g:buffer = bufnr('%')
|
let g:buffer = bufnr('%')
|
||||||
|
|
||||||
let g:ale_buffer_info = {
|
let g:ale_buffer_info = {
|
||||||
\ g:buffer : {},
|
\ g:buffer : {'temporary_file_list': [], 'temporary_directory_list': []},
|
||||||
\ 10347: {},
|
\ 10347: {'temporary_file_list': [], 'temporary_directory_list': []},
|
||||||
\}
|
\}
|
||||||
|
|
||||||
After:
|
After:
|
||||||
|
@ -12,4 +12,4 @@ After:
|
||||||
|
|
||||||
Execute('ALE globals should be cleared when the buffer is closed.'):
|
Execute('ALE globals should be cleared when the buffer is closed.'):
|
||||||
:q!
|
:q!
|
||||||
AssertEqual {10347: {}}, g:ale_buffer_info
|
AssertEqual {10347: {'temporary_file_list': [], 'temporary_directory_list': []}}, g:ale_buffer_info
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
Before:
|
||||||
|
let g:command = 'echo test'
|
||||||
|
let g:filename = tempname()
|
||||||
|
let g:directory = tempname()
|
||||||
|
let g:preserved_directory = tempname()
|
||||||
|
|
||||||
|
function! TestCommandCallback(buffer) abort
|
||||||
|
" We are registering a temporary file, so we should delete it.
|
||||||
|
call writefile(['foo'], g:filename)
|
||||||
|
call ale#engine#ManageFile(a:buffer, g:filename)
|
||||||
|
|
||||||
|
" We are registering this directory appropriately, so we should delete
|
||||||
|
" the whole thing.
|
||||||
|
call mkdir(g:directory)
|
||||||
|
call writefile(['foo'], g:directory . '/bar')
|
||||||
|
call ale#engine#ManageDirectory(a:buffer, g:directory)
|
||||||
|
|
||||||
|
" We are registering this directory as temporary file, so we
|
||||||
|
" shouldn't delete it.
|
||||||
|
call mkdir(g:preserved_directory)
|
||||||
|
call writefile(['foo'], g:preserved_directory . '/bar')
|
||||||
|
call ale#engine#ManageFile(a:buffer, g:preserved_directory)
|
||||||
|
|
||||||
|
return g:command
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! TestCallback(buffer, output) abort
|
||||||
|
return []
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call ale#linter#Define('foobar', {
|
||||||
|
\ 'name': 'testlinter',
|
||||||
|
\ 'executable': 'echo',
|
||||||
|
\ 'callback': 'TestCallback',
|
||||||
|
\ 'command_callback': 'TestCommandCallback',
|
||||||
|
\})
|
||||||
|
|
||||||
|
After:
|
||||||
|
call delete(g:preserved_directory, 'rf')
|
||||||
|
|
||||||
|
unlet! g:command
|
||||||
|
unlet! g:filename
|
||||||
|
unlet! g:directory
|
||||||
|
unlet! g:preserved_directory
|
||||||
|
delfunction TestCommandCallback
|
||||||
|
delfunction TestCallback
|
||||||
|
call ale#linter#Reset()
|
||||||
|
|
||||||
|
Given foobar (Some imaginary filetype):
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
baz
|
||||||
|
|
||||||
|
Execute(ALE should delete managed files/directories appropriately after linting):
|
||||||
|
AssertEqual 'foobar', &filetype
|
||||||
|
|
||||||
|
call ale#Lint()
|
||||||
|
call ale#engine#WaitForJobs(2000)
|
||||||
|
|
||||||
|
Assert !filereadable(g:filename), 'The tempoary file was not deleted'
|
||||||
|
Assert !isdirectory(g:directory), 'The tempoary directory was not deleted'
|
||||||
|
Assert isdirectory(g:preserved_directory), 'The tempoary directory was not kept'
|
||||||
|
|
||||||
|
Execute(ALE should delete managed files even if no command is run):
|
||||||
|
AssertEqual 'foobar', &filetype
|
||||||
|
|
||||||
|
let g:command = ''
|
||||||
|
|
||||||
|
call ale#Lint()
|
||||||
|
call ale#engine#WaitForJobs(2000)
|
||||||
|
|
||||||
|
Assert !filereadable(g:filename), 'The tempoary file was not deleted'
|
||||||
|
Assert !isdirectory(g:directory), 'The tempoary directory was not deleted'
|
||||||
|
Assert isdirectory(g:preserved_directory), 'The tempoary directory was not kept'
|
||||||
|
|
||||||
|
Execute(ALE should delete managed files when the buffer is removed):
|
||||||
|
call ale#engine#InitBufferInfo(bufnr('%'))
|
||||||
|
call TestCommandCallback(bufnr('%'))
|
||||||
|
call ale#cleanup#Buffer(bufnr('%'))
|
||||||
|
|
||||||
|
Assert !filereadable(g:filename), 'The tempoary file was not deleted'
|
||||||
|
Assert !isdirectory(g:directory), 'The tempoary directory was not deleted'
|
||||||
|
Assert isdirectory(g:preserved_directory), 'The tempoary directory was not kept'
|
Loading…
Reference in New Issue