Run a language-specific formatter on save in Sublime
The Hooks package for Sublime Text
provides a hook called on_post_save_async_language
, which you can use to run a
Sublime Text command (mind, not directly an executable on disk) after a file is
saved.
So, for example, to run the hindent
formatter for Haskell code, you
could put this in the “Settings - Syntax Specific” file for Haskell.
Note the $file
variable, which is intended to indicate the current
file.
"on_post_save_async_language": [
{
"command": "exec",
"args": { "cmd": ["hindent", "$file"] },
"scope": "window",
},
],
Unfortunately, this doesn’t work. The $file
variable isn’t expanded by the
Sublime Text command exec
. (As a side note, though exec
will not expand
variables, Sublime’s build system process supports expansion in case that’s
useful to you for whatever else.)
A working alternative is to write a custom command that can run
hindent
with the current view’s file. Place the following in a .py
file in Sublime’s Packages/User
directory.
import sublime
import sublime_plugin
class HindentCommand(sublime_plugin.WindowCommand):
def run(self):
filename = self.window.active_view().file_name()
if not filename:
print("hindent: no usable file_name(); not running")
return
self.window.run_command("exec", {
"cmd": ["hindent", filename],
"quiet": True
})
It sets up a Sublime Text command named “hindent”, which calls the
hindent
binary, still using exec like in the earlier code block. But
here, we can obtain the filename programmatically with the
file_name()
API, instead of relying on the $file
variable
expansion.
Now all that’s left is to call this custom command on save:
"on_post_save_async_language": [
{
"command": "hindent",
"scope": "window",
},
],
Update one: A better working alternative: use this custom
command. It’s a stand-in replacement for exec
, except that it
expands variables.
Update two: For Haskell specifically, you may be better off using LSP for formatting in Sublime.