Sublime Forum

Run command after saving file

#1

After saving an .rb (ruby) file I would like to run rubocop -a ‘filename’
Is that possible in Sublime Text 3?
Linting works fine with existing plugins, but none of them support auto-correct.

0 Likes

#2

I created a quick plugin.
Not sure if this is the correct way since this is my first plugin, but it seems to work fine.

import sublime
import sublime_plugin
import os

class RubocopOnSave(sublime_plugin.EventListener):
    def on_post_save_async(self, view):
        filename = view.file_name()
        view.window().run_command('exec', {
            'cmd': ['rubocop', '-a', filename],
            'working_dir': os.path.dirname(filename),
        })

Update:

An other version that doesn’t open the console every time:
(and the extra Ruby check as suggested by OdatNurd)

import sublime
import sublime_plugin
import os
import subprocess

class RubocopOnSave(sublime_plugin.EventListener):
    def on_post_save_async(self, view):
        filename = view.file_name()
        if view.match_selector(0, "source.ruby"):
        	subprocess.call(['rubocop', '-a', filename], cwd=os.path.dirname(filename))

1 Like

#3

What you’ve got here is a pretty good solution to the problem (and is what I was going to recommend, but you answered your own question before my day of meetings ended :smile:).

The only thing I would add to what you’ve got here is the realization that as outlined above this will always trigger the command for any file you save, regardless of the type of file that it is, which may or may not be problematic unless you literally only ever edit ruby files.

You could augment either plugin to only trigger the action for files of the appropriate type:

if view.match_selector(0, "source.ruby"):
    subprocess.call(...)
0 Likes

#4

Thanks, I will add that.

0 Likes

#5

Here’s a similar plugin I wrote. Put your shell command at the top of the file in a line comment.

If it’s a Javascript file, the line should be “//onsave {your command here}”. For a Python file it would begin with “#onsave”. You can edit the extensions dict to support any extension/prefix you like.

import sublime_plugin
import re
import os

extensions = {"js" : "//onsave", "py" : "#onsave"}

class runOnSave(sublime_plugin.EventListener):
    def on_post_save(self, view):
      filepath = view.file_name()
      if not filepath:
        return 0

      file_extension = os.path.splitext(filepath)[1][1:]

      if file_extension in extensions:
        prefix = extensions[file_extension]
        file = open(filepath, "r")
        match = re.search('(?:^|\A)' + prefix + ' ([^\n]+)', file.read())
        if match and match.group(1):
          fullCommand = match.group(1)
          print("Running " + fullCommand)
          print(os.popen(fullCommand).read())
0 Likes