Sublime Forum

How to detect commands run by a plugin / when an autocomplete entry is clicked on by the mouse?

#1

Does anyone know how to detect when an auto completion entry is clicked on?

One can tell when an auto completion is accepted via the keyboard by using an on_post_text_command to listen for commit_completion and/or insert_best_completion commands, but there seems to be no event when an auto complete entry is clicked on using the mouse.

I have the following scenario:

  1. auto completion is shown via the auto_complete command (whether invoked by a keypress/trigger or via plugin code)
  2. the user selects an entry (either by pressing Tab on their keyboard etc. or clicking their desired entry with the mouse)
  3. if the auto completion that was selected ends in a character that is an auto completion trigger according to the view settings and the scope (i.e. check the character immediately before the new cursor position)
  • execute the auto_complete command again to show the new completions list
  • and the process repeats

As no specific event is raised when the user clicks on an auto complete entry, I had the idea of:

  • using on_post_text_command, detect when command_name == auto_complete to know when the auto complete popup is shown
  • using on_post_text_command, detect when command_name == hide_auto_complete to know when the auto complete was cancelled
  • use on_modified or on_selection_modified to detect when an auto complete entry was accepted (i.e. if the previous command was auto_complete, and it is the first on_modified or on_selection_modified event fired since then)

but it doesn’t seem to work… Does anyone have any other ideas of how I could accomplish this?

1 Like

#2

Nevermind, using the following simple example (ignoring different views etc.):

import sublime_plugin
import sublime

class AutocompleteListener(sublime_plugin.EventListener):
    def __init__(self):
        super().__init__()
        self.previous_command = None
    
    def auto_complete_committed(self, view):
        print('auto complete committed', view.id())
    
    def on_post_text_command(self, view, command_name, args):
        self.previous_command = command_name
        if command_name in ('commit_completion', 'insert_best_completion'):
            self.auto_complete_committed(view)
    
    def on_modified_async(self, view):
        if self.previous_command == 'auto_complete':
            self.auto_complete_committed(view)
        self.previous_command = None

shows that my idea works after all :stuck_out_tongue:

2 Likes

#3

but it seems that on_text_command/on_post_test_command are not called when a plugin runs a command, hence the problem with my step 3 in the OP when I run auto_complete.

here is my attempt:

import sublime_plugin
import sublime

class AutocompleteListener(sublime_plugin.EventListener):
    def __init__(self):
        super().__init__()
        self.previous_command = None
    
    @staticmethod
    def get_applicable_auto_complete_trigger_chars(view):
        return [
            trigger['characters']
            for trigger in view.settings().get('auto_complete_triggers')
                if view.match_selector(view.sel()[0].begin(), trigger['selector'])
        ]
    
    def auto_complete_committed(self, view, how):
        if view.substr(view.sel()[0].begin() - 1) in ''.join(AutocompleteListener.get_applicable_auto_complete_trigger_chars(view)):
            print('AC: triggering new autocomplete popup...')
            view.run_command('auto_complete')
            self.previous_command = 'auto_complete'
    
    def on_post_text_command(self, view, command_name, args):
        self.previous_command = command_name
        if command_name in ('commit_completion', 'insert_best_completion'):
            self.auto_complete_committed(view, command_name)
    
    def on_modified_async(self, view):
        if self.previous_command == 'auto_complete':
            self.auto_complete_committed(view, 'click')
        self.previous_command = None

tested by, running the following in the console in a new tab:

view.settings().set('auto_complete_triggers', [{'characters': '_', 'selector': 'text.plain'}])

and then typing

abc_
abc_def_
abc_def_ghi
abc_123_
abc_123_456

and then on a new line, typing a and pressing space to bring up the auto complete menu.

Highlighting abc_ and pressing Tab, then abc_def_ and pressing Tab correctly then inserts the best completion of abc_def_ghi

But clicking abc_ and then clicking abc_def_ stops there, as does highlighting abc_ and pressing Tab, then clicking abc_def_.

so I need some other way to detect when an autocompletion entry is clicked on…and I think there is no other way :frowning: but maybe someone has some ideas? :slight_smile:

0 Likes

#4

have created an issue here which should help :thumbsup:

1 Like

#5

Can’t say I can confirm that. It just appears that the auto-opened completions popup (e.g. when typing _) does not emit a command, just like clicking an entry inside of it.

As a hint, you could check out the on_query_completions hook in order to detect when the completion popup is opened.

1 Like

#6

great idea, thank you :slight_smile:

0 Likes