17. Event Listeners

Event Listeners are sometimes referred to as “Event Handlers”, “Event Hooks” or “Event Callbacks”, but we will be using the term “Event Listener” because that is how the EventListener class is named inside sublime_plugin.py.

Event Listeners allow you to react to events, such as:

  • files being created, loaded, saved or closed;

  • the content of files being modified;

  • the selection changing (e.g. cursor movement);

  • the focused View changing;

  • Commands that are about to be executed;

  • Commands that have just finished executing;

  • reloads of files that changed on disk;

  • reverting to a buffer content to discard changes

  • tabs moving between windows

  • windows being created and closed

  • projects being opened and closed.

17.1. Creating an Event Listener

You create an Event Listener by creating a class that inherits from one of the 3 sublime_plugin....Listener classes below. Unlike Command- and Input Handler Classes, the class names of Event Listener classes do not matter, though a class-name suffix is recommended for code readability. (The reason the name is unimportant is that a Plugin cannot invoke an Event Handler directly, except by doing something that raises the event.)

The class’ methods are the events that get called when those events occur. The list of events is predefined. The method name matches the event name. You can include any event methods you want or need. Sublime Text will only invoke the pre-defined event methods.

See the doc-string for these sublime_plugin classes to see all the events that are available, with their documentation.

EventListener:

Global Event Listener, one Event Listener object is created that can receive all events.

ViewEventListener:

One Event Listener is created for each View to which that Listener applies (governed by is_applicable(cls, settings) method).

TextChangeListener:

One Event Listener is created for each Buffer to which that Listener applies (governed by is_applicable(cls, settings) method). (New since Build 4081.)

17.2. Example

import sublime
import sublime_plugin


class SampleEventListener(sublime_plugin.EventListener):
    """
    Sublime |nbsp| Text will only ever create ONE of these.
    You must manually filter events.
    All possible events can trigger.
    """
    def on_new(self, view):
        print('on_new() event fired.')
        #view.assign_syntax('Packages/Python/Python.sublime-syntax')
        pass

    # Normally don't do this -- event fires for every keystroke for all Views.
    # def on_modified(self, view):
    #     if view.match_selector(0, 'source.python'):
    #         print('A python file has been modified.')

class MyPythonEventListener(sublime_plugin.ViewEventListener):
    """
    Sublime |nbsp| Text will create one of these for each View for which
    `is_applicable()` returns True.
    Event filtering is more automatic.
    Gives "free" access to per-listener storage space.
    Only View-related events can trigger.
    """

    # This decorator allows this method to be called without instantiating the class.
    # This method is called every time:
    # - settings changes,
    # - a View gets focus.
    @classmethod
    def is_applicable(cls, settings):
        print('MyPythonEventListener.is_applicable() fired.')
        return 'Python.sublime-syntax' in settings.get('syntax')

    def on_close(self):
        print('on_close() View event fired.')
        filename = self.view.file_name() or 'unsaved file'
        print(f'View [{filename}] is being closed.')

    # This is more efficient than the on_modified() above, since the event
    # will only fire on Views for which `is_applicable()` returned True!
    def on_modified(self):
        print('A python file has been modified.')

17.3. Notes on on_query_context()

on_query_context() ties directly into Key Bindings (as opposed to Commands), and they provide the ability to tell Sublime Text under what situations they are relevant so that it knows that they should be applied, or skipped over in favor of another one.

on_query_context() can “sort of” be implemented by having an is_enabled() be implemented for a Command. However, there is an important nuance about on_query_context() that are important to consider: specifically that any key can be bound to multiple different Commands (or the same Command with multiple different arguments), each one with a different set of contextual rules that tell Sublime Text in what specific situation each one applies. Contexts allow Sublime Text to select from multiple Key Bindings the one that applies the best based on the current state of things.

If only a Command’s is_enabled() is used, Sublime Text will NOT select an alternate key binding either. Using on_query_context(), you can guide Sublime Text to choose the correct binding for the current situation.

See Key Bindings Documentation in the official documentation for more details.