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
|
||||
if has_key(g:ale_buffer_info, a:buffer)
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
|
||||
" When buffers are removed, clear all of the jobs.
|
||||
for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
|
||||
call ale#engine#ClearJob(l:job)
|
||||
|
|
|
@ -30,10 +30,14 @@ function! ale#engine#InitBufferInfo(buffer) abort
|
|||
" job_list will hold the list of jobs
|
||||
" loclist holds the loclist items after all jobs have completed.
|
||||
" 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] = {
|
||||
\ 'job_list': [],
|
||||
\ 'loclist': [],
|
||||
\ 'new_loclist': [],
|
||||
\ 'temporary_file_list': [],
|
||||
\ 'temporary_directory_list': [],
|
||||
\}
|
||||
endif
|
||||
endfunction
|
||||
|
@ -134,6 +138,40 @@ function! ale#engine#JoinNeovimOutput(output, data) abort
|
|||
endif
|
||||
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
|
||||
if a:job ==# 'no process'
|
||||
" Stop right away when the job is not valid in Vim 8.
|
||||
|
@ -178,6 +216,10 @@ function! s:HandleExit(job) abort
|
|||
return
|
||||
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.
|
||||
" We need a sorted list so we can run a binary search against it
|
||||
" 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)
|
||||
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
|
||||
endfunction
|
||||
|
||||
|
|
35
doc/ale.txt
35
doc/ale.txt
|
@ -1037,6 +1037,35 @@ ale#engine#GetLoclist(buffer) *ale#engine#GetLoclist()*
|
|||
|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()*
|
||||
Given a |String| for a filetype and a |Dictionary| Describing a linter
|
||||
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
|
||||
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
|
||||
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
|
||||
|
|
|
@ -2,8 +2,8 @@ Before:
|
|||
let g:buffer = bufnr('%')
|
||||
|
||||
let g:ale_buffer_info = {
|
||||
\ g:buffer : {},
|
||||
\ 10347: {},
|
||||
\ g:buffer : {'temporary_file_list': [], 'temporary_directory_list': []},
|
||||
\ 10347: {'temporary_file_list': [], 'temporary_directory_list': []},
|
||||
\}
|
||||
|
||||
After:
|
||||
|
@ -12,4 +12,4 @@ After:
|
|||
|
||||
Execute('ALE globals should be cleared when the buffer is closed.'):
|
||||
: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