Sam's Blog
Perl and PHP continuous static analysis with Emacs Flymake
Date: Monday, 25 July 2011, 09:54.
Categories: perl, ironman, php, emacs, flymake, static-analysis, php-codesniffer, perl-critic, emacs-flymake, emacs-flymake-perlcritic, emacs-flymake-phpcs.
I followed with interest the discussion and excitement last month in a few Perl blogs about people discovering Emacs Flymake.
Being a long-time Emacs user this seemed really interesting to me, but I don't tend to waste a huge amount of time making outright syntax errors.
What I really wanted was something like the static analysis that a modern IDE does for you while you type.
So I hooked up Perl::Critic and PHP_CodeSniffer to Flymake, and here's how you can too.
Installing your PHP or Perl static analysis tool
First things first, you'll need to install your static analysis program, if you're a Perl user that's easy:
cpan Perl::Critic
If you're a PHP user, you either need to have PEAR installed, and grab PHP_CodeSniffer with:
pear install PHP_CodeSniffer
Or grab the latest version of PHP_CodeSniffer from SVN:
svn checkout http://svn.php.net/repository/pear/packages/PHP_CodeSniffer/trunk
Both Perl::Critic and PHP_CodeSniffer are highly configurable, and their out-of-the-box install is likely to nag you about many things you don't care about, so read the documentation and figure out how to tailor them to your own needs - I will add a shameless plug for my own extension to PHP_CodeSniffer: PHP_Codesniffer-VariableAnalysis, which adds undefined variable and unused variable warnings.
You might want to test that your install works by playing with the
perlcritic
or phpcs
commands on a few Perl or PHP files.
Install my patched flymake.el
Flymake is really good, but if you're someone who regularly uses desktop.el and has hundreds of buffers open, Flymake will bring your computer to its knees. It also writes temporary files into the same directory as the files being analysed, which plays merry havok with file-change watchers.
I've fixed both these issues in my GitHub fork of Flymake, so until I submit and have these patches accepted upstream you'll want to grab my copy (especially since some of the patched changes are needed later).
Either checkout with git and symlink into your ~/.emacs.d/site-lisp/
:
# Tweak to suit your directory structure cd ~/projects git clone git://github.com/illusori/emacs-flymake.git ln -s ~/projects/emacs-flymake/flymake.el ~/.emacs.d/site-lisp/flymake.el
Or just fetch via wget directly into your ~/.emacs.d/site-lisp
:
(cd ~/.emacs.d/site-lisp/ && \ wget --no-check-certificate \ https://raw.github.com/illusori/emacs-flymake/master/flymake.el)
Next step is to adjust your .emacs
file to configure Flymake, I
use the following settings:
;; If you haven't added ~/.emacs.d/site-lisp to your load-path, do it with this.
(add-to-list 'load-path "~/.emacs.d/site-lisp/")
;; Require flymake.
(require 'flymake)
;; If you're a TTY emacs user, flymake-cursor is a must-have.
;; Grab it with apt-get or ports or whatever your OS package manager is.
(require 'flymake-cursor)
;; Static analysis can be slow, so only run flymake if I've not been typing for 5 seconds.
;; It will still run on save or hitting return.
(setq flymake-no-changes-timeout 5)
;; Disable in-place checking, and tell it to use ~/.emacs.d/tmp/ for the temp files.
(setq temporary-file-directory "~/.emacs.d/tmp/")
(setq flymake-run-in-place nil)
;; Only need these two if you plan to debug Flymake.
(setq flymake-log-file-name (concat temporary-file-directory "flymake.log"))
(setq flymake-log-level -1)
;; Tune how many checks can run in parallel, default of 4 should be fine.
;;(setq flymake-max-parallel-syntax-checks 1)
Gluing the two together
You now have a static analysis tool and flymake installed, the next stage is to
get them to talk to each other, for this you'll need
flymake-perlcritic.el
and/or
flymake-phpcs.el,
both available from GitHub, this time you also need the script from the bin
dir
of the project.
Using git:
# Perl cd ~/projects git clone git://github.com/illusori/emacs-flymake-perlcritic.git ln -s ~/projects/emacs-flymake/flymake-perlcritic.el ~/.emacs.d/site-lisp/flymake-perlcritic.el # PHP cd ~/projects git clone git://github.com/illusori/emacs-flymake-phpcs.git ln -s ~/projects/emacs-flymake/flymake-phpcs.el ~/.emacs.d/site-lisp/flymake-phpcs.el
or wget:
# Perl (cd ~/.emacs.d/site-lisp/ && \ wget --no-check-certificate \ https://raw.github.com/illusori/emacs-flymake-perlcritic/master/flymake-perlcritic.el) (cd ~/bin/ && \ wget --no-check-certificate \ https://raw.github.com/illusori/emacs-flymake-perlcritic/master/bin/flymake_perlcritic && \ chmod a+x flymake_perlcritic) # PHP (cd ~/.emacs.d/site-lisp/ && \ wget --no-check-certificate \ https://raw.github.com/illusori/emacs-flymake-phpcs/master/flymake-phpcs.el) (cd ~/bin/ && \ wget --no-check-certificate \ https://raw.github.com/illusori/emacs-flymake-phpcs/master/bin/flymake_phpcs && \ chmod a+x flymake_phpcs)
Once you've installed these, you can add another section to your .emacs
and
adjust to suit:
;; flymake-perlcritic stuff
(setq flymake-perlcritic-severity 5)
;; If flymake_perlcritic isn't in your $PATH you'll need to give the full path here
(setq flymake-perlcritic-command "~/projects/emacs-flymake-perlcritic/bin/flymake_perlcritic")
(require 'flymake-perlcritic)
;; flymake-phpcs stuff
;; This gets supplied literally as the --standard arg to phpcs, read the phpcs docs for details.
(setq flymake-phpcs-standard "/Users/illusori/projects/MyPHPCodeSnifferStandard")
;; If flymake_phpcs isn't in your $PATH you'll need to give the full path here
(setq flymake-phpcs-command "~/projects/emacs-flymake-phpcs/bin/flymake_phpcs")
(require 'flymake-phpcs)
At this point you should be done, whenever a buffer is in perl-mode
or
php-mode
it should automatically run the static analysis shortly after
you make changes.