sublimetext3sublimetextsublime-text-pluginsublimelinter

Auto-run a command on saving in Sublime Text


Is it possible to run eslint automatically when I save either a .js or .jsx file in Sublime Text?

I'm using the ESLint sublime package right now but I have to manually run it each time using Cmd + Option + e.

Thanks!


Solution

  • Yes this can be done with a simple event driven plugin like the one I've written below.

    The plugin has been tested but not with the eslint command since I did not want to install that package. Clearly any command could be run instead of eslint in the plugin's run_command("eslint") line. If the desired command takes args then they can be specified like this: run_command("command", {"arg_1": val, "arg_2": val}).

    The on_post_save_async(self, view) method (in my plugin below) will be called after the view, i.e. the active buffer, has been saved - note that this includes auto-saves. on_post_save_async() runs in a separate thread and does not block the application. You could alter the plugin to use a similar method depending of whether you want eslint called before or after the file save has taken place and whether the method should block the application or be run in its own non-blocking thread. These are the 4 alternatives:

    Save the plugin below somewhere in in your Sublime Text packages hierarchy with a .py extension. e.g. ~/.config/sublime-text-3/Packages/User/AutoRunESLintOnSave.py and it should work straight away.

    import sublime, sublime_plugin
    
    class AutoRunESLintOnSave(sublime_plugin.EventListener):
        """ A class to listen for events triggered by ST. """
    
        def on_post_save_async(self, view):
            """
            This is called after a view has been saved. It runs in a separate thread
            and does not block the application.
            """
    
            file_path = view.file_name()
            if not file_path:
                return
            NOT_FOUND = -1
            pos_dot = file_path.rfind(".")
            if pos_dot == NOT_FOUND:
                return
            file_extension = file_path[pos_dot:]
            if file_extension.lower() in [".js", ".jsx"]:
                view.window().run_command("eslint")
    
                # Slight variations are needed for an ApplicationCommand,
                # a WindowCommand, or a TextCommand.
                #
                # view.run_command("text_command")
                # view.window().run_command("window_command")
                # sublime.run_command("application_command")
                #
                # Need args? Use this:
                #
                # view.run_command("command", {"arg_1": val, "arg_2": val})
    

    Instead of using file extensions to trigger running the eslint command you could use the buffer's syntax, the code is even more concise.

        def on_post_save_async(self, view):
            """ Syntax version. """
    
            current_syntax = view.settings().get("syntax")
            if ("JavaScript.sublime-syntax" in current_syntax
                    or "JSX.sublime-syntax" in current_syntax):
                view.window().run_command("eslint")
    
            # You could, of course, use an exact match:
            #
            # current_syntax = view.settings().get("syntax")
            # if current_syntax == "Packages/JavaScript/JavaScript.sublime-syntax":
            #     view.window().run_command("eslint")
            #
            # Run `view.settings().get("syntax")` in the console for the active syntax path.