Imitating live reload in Emacs for Perl (or any) project :)

One of my favorite parts about my frontend JS workflow is using Live Reload with Grunt/Gulp. Saving a few keystrokes a couple times a minute is pretty great, especially if I can stay on the home keys. Grunt and Gulp have a task that watches the files in your project and then you kick can off certain tasks when they change, like refreshing your display and re-running all the unit tests. In Scala, you can get a similar thing by invoking your sbt command prefixed with a ~, but I didn't have anything for my Perl projects (not to mention a general solution!).

At first, I looked for a similar tool that would watch files for changes and let me hook into that action. I found App::Prove::Watch which was a Perl-only solution. It worked swimmingly after a quick PR, but it only solved the problem for Perl projects. It wasn't until a few days later that I realized I could leverage Emacs to get a reasonably general solution, only depending on use of the *compilation* buffer (no idea why it didn't occur to me earlier!).

Of course, Emacs knows exactly when my files change, as we always eventually invoke (save-buffer) - even if it's advised with with whitespace cleanup, or if it's invoked via some sort of autosave. Instead of watching files on disk for changes, we can just use Emacs to have the (save-command) trigger our tasks - aka re-compiling the *compilation* buffer.

I used a global variable ar-auto-recompile to turn autocompilation on and off, and made a function to handle the toggling for me:

(setq ar-auto-recompile nil)
(defun ar-auto-re-compile ()
  (interactive)
  (setq ar-auto-recompile (not ar-auto-recompile))
  (message (format "Auto recompile is now %s"
                   (if ar-auto-recompile "ON" "OFF"))))

It just toggles the variable and messages us about it. Next, our advice to save-buffer should check whether the user wants auto-recompilation. I also decided I only wanted it to re-compile if the *compilation* buffer was in a visible window, which (get-buffer-window) happily tells us.

(defadvice save-buffer (after ar-auto-recompile activate)
  (when (and ar-auto-recompile
             (get-buffer-window "*compilation*"))
    (set-buffer compilation-last-buffer)
    (revert-buffer t t)))

This solution isn't quite the same as the watch behavior of the other tools, as they smartly only respond to changes in files in their own project. When turned on, this would blindly recompile any time a buffer is saved and the *compilation* buffer is open. But, I don't really mind - a few extra compilations probably won't hurt anything unless the compilation wasn't safe to repeat in the first place.

So, my workflow is now to open up my test file, toggle on the recompilation with (ar-auto-re-compile), run a test to bring up the *compilation* buffer. I keep that buffer visible and then do edits and such as usual, saving with M-s, which automatically re-runs the test. And, if I need a more complicated compilation command, it's just a C-u M-x compile away, and then that can get repeated for me. As an extra bonus, this works perfectly with projectile's compilation and test running commands (by default on C-c p c and C-c p P), as they utilize the *compilation* buffer as well. I also made a key-chord to switch the current buffer over to the compilation one, as I often accidentally close it:

(key-chord-define-global "vv" (lambda () (interactive)
                                (switch-to-buffer "*compilation*")))

Finally, if you don't want to use advice, it's simple enough to use a wrapper around (save-buffer) and update your save keybinding to use your own function. And as usual, the whole snippet is in my github somewhere.