-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement a uniform API for asynchronous processing for most ALE features #2132
Comments
I think it would be useful to make all async functions use promise like Motivation:
We can vendor something like Async.Promise as |
See the section "Why not use Promises/Futures for this." If this was JavaScript, yes. This is Vim script, so that won't happen. |
I don't buy performance argument as the overhead would be negligible compared to I/O. Still the section doesn't list the pros I listed in the comment above. |
The performance will definitely be worse because of the additional logic required for an implementation of promises in Vim script. We don't need the exception handling mechanisms. We'll be using callbacks. |
A new function is added here which will later be modified for public use in linter and fixer callbacks. All linting and fixing now goes through this new function, to prove that it works in all cases.
The new function will probably eventually be used like so. function! ChainedCallback(Done, buffer, output, data) abort
call a:Done('second command')
endfunction
function! CommandCallback(buffer, Done) abort
return ale#command#Run(a:buffer, 'first command', {
\ 'callback': function('ChainedCallback', [a:Done]),
\})
endfunction The callback is given |
With a little bit of tweaking, it can be more like this. function! ChainedCallback(buffer, output, data) abort
return 'second command'
endfunction
function! CommandCallback(buffer) abort
return ale#command#Run(a:buffer, 'first command', 'ChainedCallback')
endfunction The result of This will make the primary use case for this, finding executables to run in the background, a lot easier. function! ExecutableCallback(buffer) abort
" The deferred object is returned here.
return ale#node#FindExecutable(
\ a:buffer,
\ 'javascript_flow_ls',
\ ['node_modules/.bin/flow']
\)
endfunction |
I reverted the changes for adding the |
Problem description
This issue outlines a design for how to add more asynchronous execution support
to ALE's codebase. Currently, ALE can run the following in the background.
callback
,command_callback
)command_chain
):ALEFix
functions)chain_with
)tsserver
, etc.ALE does not support asynchronous execution in the following common scenarios, at the time this issue was written.
command_chain
isn't currently implemented for LSP commands.)If ALE did add support for all the above, it would be possible to improve on the user experience in the following ways.
--version
checks and more for LSP commands.Proposal
All of the problems above can be solved with a uniform API for signaling when results are ready with a callback. A new function will be added which returns a special Dictionary representing a deferred object and accepts a callback. The callbacks for linters, fixers, and more will be able to return one of these deferred objects to indicate that something will be run in the background, and the result of the callback will be used as the eventual result.
Here is just one example of how this API could be used.
The
_callback
forms of options forale#linter#Define
will be deprecated andlater removed, and
command_chain
will be deprecated and removed now it canbe replaced with the uniform API.
Deprecation process
There will be a long deprecation process, in the following stages.
Rationale
I will post the questions I can imagine regarding the coming implementation of this feature, and the answers I have already formulated.
Why the long deprecation process?
Thousands of people use ALE, and immediately removing support for just about anything will make a lot of people angry. Someone or other is likely to be angry when a feature is eventually removed anyway, but at least they'll be given time to update their code. Removing support for the older ways of doing things is necessary for keeping the codebase small and easy to maintain, and therefore
less prone to bugs in the future.
Why not use Promises/Futures for this?
Callbacks typically lead to better performance than promises. See here and here.
I find promises are a much cleaner API for implementing asynchronous tasks, and they are best used when a language already implements async ... await or will eventually implement
async ... await
. I do not believe thatasync ... await
will ever be implemented in VimL.Promises offer a failure mechanism like
.catch
in JavaScript, but there's no need for this for what we need for ALE. Our callbacks will only need to either respond with a result, which could be a result for cancelling a request, never an exception or other type of error.Why not rewrite the codebase in something other than VimL?
Because the only thing that's near enough to being as portable as VimL is Python code, and near total portability is a strongly desired design goal for ALE. Usage of ALE since its inception has proven the "only VimL" rule to be a good decision, and worth all of the effort.
Features to be deprecated
ale#engine#CreateDirectory
ale#command#CreateDirectory
ale#engine#CreateFile
ale#command#CreateFile
ale#engine#EscapeCommandPart
ale#command#EscapeCommandPart
ale#engine#ManageDirectory
ale#command#ManageDirectory
ale#engine#ManageFile
ale#command#ManageFile
command_chain
for linterscommand
and new async tools insteadcommand_callback
for linterscommand
with a Funcref insteadexecutable_callback
for lintersexecutable
with a Funcref insteadaddress_callback
for LSP lintersaddress
with a Funcref insteadlanguage_callback
for LSP linterslanguage
with a Funcref insteadproject_root_callback
for LSP lintersproject_root
with a Funcref insteadinitialization_options_callback
for LSP lintersinitialization_options
with a Funcref insteadlsp_config_callback
for LSP linterslsp_config
with a Funcref insteadchain_with
for fixersTo Do
Here is what remains to be done. The list will be extended as time goes on.
command.vim
.engine.vim
functions tocommand.vim
.exectuable
results for linters.command
results for linters.exectuable
results for language servers.command
results for language servers.ale#command#Run
and how to use it.engine.vim
functions to be removed later. (ManageDirectory
, etc.)_callback
linter options andcommand_chain
.chain_with
for fixers.The text was updated successfully, but these errors were encountered: