Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Modern on the fly syntax checking for GNU Emacs
Emacs Lisp Makefile Python Rust Ruby C++ Other

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
.gitignore
CONTRIBUTING.org
COPYING
Makefile
README.org
flycheck.el

README.org

flycheck

Flycheck is flymake reloaded with

  • an improved customization interface based on major modes (instead of file name patterns),
  • a much nicer and easier, declarative syntax for checker definitions (instead of init functions)
  • and a bunch of ready-to-use syntax checkers for various languages (instead of broken checkers using non-existing tools).

Motivation

GNU Emacs has a built-in on-the-fly syntax checker named Flymake. Flymake does a good job on the actual on-the-fly syntax checking, but its built-in checkers are out-dated and broken, and adding support for new checkers is cumbersome.

Flycheck is a new mode that aims to replace Flymake where it is broken while re-using its good parts. Hence, it features a new, declarative API to implement new syntax checkers, and an improved customization interface based on the major mode of buffers, but re-uses flymake to do the actual syntax checking.

Features

  • Provide syntax checkers for:
    • CoffeeScript
    • CSS
    • Emacs Lisp
    • HAML
    • HTML
    • Javascript
    • JSON
    • PHP
    • Python
    • Ruby
    • SASS
    • Shell scripts (Bash, Dash and Zsh)
    • TeX/LaTeX
  • Easy customization by a single variable flycheck-checkers
  • Easy declarative API to define new syntax checkers

Installation

Install the ELPA package from MELPA (bleeding edge snapshots) or Marmalade (stable releases) with M-x package-install flycheck.

Or download the latest release and install flycheck.el with M-x package-install-file.

The library is written and tested against GNU Emacs 24 and may or may not work in earlier versions of GNU Emacs.

Most checkers have dependencies against external tools that perform the checking. See Checkers for details.

Usage

Enable flycheck-mode in your init.el file.

;; Enable flymake for all files
(add-hook 'find-file-hook 'flycheck-mode)
;; Enable flymake for Python only
(add-hook 'python-mode-hook 'flycheck-mode)

Or do M-x flycheck-mode manually after visiting a file.

On-the-fly syntax checking with flycheck will then start immediately.

Warning: Flycheck is intentionally incompatible with classic Flymake. Trying to enable one while the other is active signals an error. Ideally you should not use flymake-mode anymore after you installed Flycheck.

Checkers

You need to install external utilities for the following checkers:

CoffeeScript
Install coffeelint.
CSS
Install csslint.
HAML
Install HAML.
HTML
Install Tidy.
Javascript
Install jshint or jslint. The former will automatically use a .jshintrc file in the buffer’s directory, any ancestor thereof or your $HOME directory. You may override the path to this file with the variable `flycheck-jshintrc`.
JSON
Install jsonlint.
PHP
Install the PHP command line.
Python
Install flake8, pyflakes or pylint.
Ruby
Install Ruby.
SASS
Install SASS.
Shell scripts
Install Bash or Zsh depending on the type of shell file you want to check.
TeX/LaTeX
Install chktex or lacheck. Most TeX distributions, including TeXLive and MacTeX, already do this for you.

Customization

M-x customize-variable flycheck-checkers
A list of all checkers. The checkers are tried in the order of appearance in this list. The first checker that supports the current mode and whose executable exists is used. To change the preference of checkers, change their order in this list or remove entries from this list.

Some modes have multiple checkers. For instance python-mode has three checkers using flake8, pylint or pyflakes. When doing syntax checking in python-mode, the checkers are tried in this order and the first whose executable is found is used.

To chance the order of preference or enforce a single checker, just modify the order of their appearance in flycheck-checkers or delete checkers you do not want to use. For instance, to always use pyflakes in python-mode, just remove flycheck-checker-python-flake8 and flycheck-checker-python-pylint from flycheck-checkers via customization.

Extending

In flycheck a syntax checker is a property list with the following keys (the checker properties):

:command (mandatory)
A list containing the executable of the syntax checking tool (in the car of the list) and its arguments (in the cdr). Before enabling a checker the executable is checked for existence with executable-find. If this check fails the checker is not used. In arguments the special symbol source is replaced with a temporary copy of the source file[fn:1], created in the system temporary directory. Use source-inplace instead to force the copy being created in the same directory as the original source file.
:error-patterns (optional)
A single error pattern or a list of error patterns to parse the output of :command. Each pattern has the form (REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX). The patterns are tried in order of declaration. If omitted all patterns defined in flymake-err-line-patterns are tried.
:modes (optional)
A single major mode symbol or a list thereof. If given the checker will only be used in any of these modes.
:predicate (optional)
A form that if present is evaluated to determine whether the checker is to be used. The checker is only used if the form evaluates to non-nil.

At least one of :modes and :predicate must be present. If both are present, both must match for the checker to be used.

Checkers are registered via flycheck-checkers, which is a list of symbols. Each symbol in this list must either be a variable bound to a checker property list, or be a function returning one. In the former case, the variables value is retrieved anew on each syntax check. In the latter case the function is invoked on each syntax check with no arguments.

Example

Let’s see this in action by explaining the definition of the CoffeeScript checker included in flycheck. This checker uses the CoffeeLint utility to perform the actual syntax check.

First we declare the checker properties:

(defvar flycheck-checker-coffee
  '(:command
    '("coffeelint" "--csv" source)
    :error-patterns
    (("SyntaxError: \\(.*\\) on line \\([0-9]+\\)" nil 2 nil 1)
     ("\\(.+\\),\\([0-9]+\\),\\(?:warn\\|error\\),\\(.+\\)" 1 2 nil 3))
    :modes coffee-mode))

As you can see, we declare via :modes that this checker it is to be enabled in coffee-mode. More complicated predicates for enabled checkers can be implemented via the :predicate property.

We specify the command to execute in this mode in :command. It is a straight-forward list with the executable name as first element and some subsequent arguments. The symbol source is automatically replaced with the name of the file to check. Note that a checker is not enabled if its executable does not exist (as by executable-find).

Since coffeelint outputs errors in a CSV format, which is rather unusual, we also need custom :error-patterns to extract the error location and message from the coffeelint output. An error pattern is a list containing a regular expression that matches the error, and indexes of groups that match the file name, the line number, the column number and the error message respectively. :error-patterns allows for a single error pattern, or a list of such error patterns, in case the checker outputs messages in various formats.

If :error-patterns is omitted, all patterns defined in flymake-err-line-patterns are tried. This variable contains patterns for a wide range of error format, including all those from compile.el. Thus, if your checker works with M-x compile, there is a good chance that predefined patterns already understand this output.

Now we only need to register this error checker for use with

(add-to-list 'flycheck-checkers 'flycheck-checker-coffee)

Assuming that flycheck-mode is enabled (see Usage), CoffeeScript will now be syntax-checked on the fly in coffee-mode.

Some checkers have more complicated conditions for whether they are to be used or not. For instance, syntax checking in sh-mode needs to use different shells depending on the value of sh-shell. Hence in the checkers for this mode we also give a :predicate that determines whether the right shell is active:

(defvar flycheck-checker-zsh
  '(:command
    ("zsh" "-n" "-d" "-f" source)
    :modes sh-mode
    :predicate (eq sh-shell 'zsh)))

As you can see we declare that the checker is to be used in sh-mode, but we also give a :predicate that checks the value of sh-shell. The predicate is simply a form that is evaluated whenever a syntax check is to be performed. Thus this checker will only be enabled if the current mode is sh-mode and sh-shell is bound to the symbol zsh.

Further help

  • C-h f flycheck-mode
  • C-h f flycheck-checkers

Credits

The Vim library syntastic by Martin Grenfell inspired this library and many of its checkers.

Steve Purcell implemented many checkers, contributed important ideas to the design of the checker API and engaged in worthwhile discussion to shape this project.

Jimmy Yuen Ho Wong added the HTML syntax checker and the jshint Javascript checker, and did valuable testing and bug fixing.

License

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

See COPYING for details.

Footnotes

[fn:1] These temporary copies are necessary to allow for syntax checks of modified, but not yet saved buffers.

Something went wrong with that request. Please try again.