sublime_text
sublime_text copied to clipboard
[ST4] Cancel pending completion future when one of the items in auto_complete_triggers matches
Problem description
When a plugin takes a long time to prepare results for on_query_completions using the sublime.CompletionList future, it can be the case that the user has finished typing the identifier. The user then types some sort of punctuation.accessor and wants to know the properties/methods of that identifier.
However, ST ignores this event and instead presents the completion results from when the user started typing the first character of the identifier.
Preferred solution
When one of the items in view.settings().get("auto_complete_triggers") (could be a "selector") matches the position to the left of the caret, cancel the inflight future, and re-do the on_query_completions callback.
Alternatives
N/A
Additional Information
In the above GIF, you can see me typing s.. The on_query_completions is called for the s character. After the plugin is done computing the completions, we are too late in presenting the completions. The user is already wanting to see the methods of the s String.
In this GIF, you can see me typing .. The on_query_completions is called because . matches one of the items in "auto_complete_triggers". This provides the user with the desired properties/methods.
It seems to me like ST re-triggers the on_query_complitions now in that case (typing .).
Either that or behavior differs with and without the sublime.DYNAMIC_COMPLETIONS flag. I've only tried on an LSP server that doesn't set it. I guess we should have a simple test case for it that delays completions.
That said, even if fixed, that doesn't help the case when the initial request is slow (because of being very unspecific) and user expects the second request to trigger immediately on typing .. ST only triggers the second on_query_completions after first one is handled. There is no way that ST can indicate that the first request is to be canceled early.
A small plugin for testing:
import sublime_plugin
from typing import List
from sublime import AutoCompleteFlags, CompletionItem, CompletionList, set_timeout
class CompletionListener(sublime_plugin.ViewEventListener):
def on_query_completions(self, prefix, locations):
print('on_query_completions, prefix: {}'.format(prefix))
if prefix in ['a', 'aa']:
return create_delayed_completions(['aaa'], 3000)
elif prefix == '':
return create_delayed_completions(['fast'], 1)
def create_delayed_completions(completions: List[str], delay: int) -> CompletionList:
completion_list = CompletionList()
flags = AutoCompleteFlags.INHIBIT_WORD_COMPLETIONS | AutoCompleteFlags.INHIBIT_EXPLICIT_COMPLETIONS
# flags |= AutoCompleteFlags.DYNAMIC_COMPLETIONS
set_timeout(lambda: completion_list.set_completions(completions, flags=flags), delay)
return completion_list
Reproduction
- Open empty view and set syntax to
JavaScriptorPython. - Type
aa.quickly.
Expected: The completions show up immediately after the . character is typed
Actual: The completions requested when typing the first a character delay completions requested for the following . character.
Since completions requested for a are no longer relevant, those should be cancelled immediately and on_query_completions should be triggered right away.
Ideally the plugin code would also be notified when the completion request is canceled but it's probably not strictly necessary.
I've also left out disabled line that sets the DYNAMIC_COMPLETIONS flag. With it enabled there is another, possibly a separate, issue with ST not triggering on_query_completions when typing the second a character.
Reproduction
- Enable commented out
flags |= AutoCompleteFlags.DYNAMIC_COMPLETIONSline. - Open empty view and set syntax to JavaScript or Python.
- Type
aa
Expected: the on_query_completions should trigger separately both when typing the first and the second a
Actual: After typing aa, on_query_completions is only triggered once.
Fixed in build 4161.
I think this change has unintended side effect.
When I type a twice in a Python file, then on_query_completions is triggered twice. And that's without the DYNAMIC_COMPLETIONS flag. This can be seen with the plugin above since it triggers print on on_query_completions.
The expected behavior is that ST will re-trigger on_query_completions but only in cases where it would do that previously so in cases where completions should be triggered (like at the start of a word or on punctuation).