1. Ian Wilkinson
  2. sublime-lint-free


sublime-lint-free /

Filename Size Date modified Message
8 B
Ignore .pyc
1.4 KB
Added license file (#7)
1.3 KB
refactoring and making configurable (#6)
6.8 KB
remove mention of coverage
5.5 KB
remove accidentally committed debug
9.4 KB
remove mention of coverage
146 B
refactor and first stab at interactive list (#2)
3.0 KB
added another lint example and generalised the regex grouping
3.7 KB

Sublime Lint Free

Sublime Lint Free is an extensible Sublime Text 2 plugin for continuous lint checking and highlighting. It can also be used to show coding style issues, high code complexity, and other more arbitrary annotations of source files.

There are a number of similar plugins already in existence, so why another one? In short, because I had minor gripes with all the ones I found. Most significant were:

  • The lint mechanisms were either written into or bundled with the Python plugin. Not a good separation of concerns, but specifically it meant that the linters were not current.

  • Unnecessary use of threads (a powerful, seductive, but IMHO dangerous programming paradigm which should not be used lightly).

  • Ironically, some of the code was not very clean! I care about these things...

For the impatient...

Highlighted lines with detail of current line in status bar:

example annotations

Pop-up list of annotations ready for quick browsing and jumping to corresponding line:

example pop-up list of annotations

Example configuration file

    // Debugging mode controls level of log messages.
    "debugging": true,

    // Delay in seconds after which annotator commands are run following the
    // last load, save, or edit.
    "throttle_delay": 1000,

    // Maximum duration in seconds for an annotator command to run before it is
    // terminated because it is considered as taking too long.
    "timeout_after": 500,

    // Definition of annotators as a list of dictionaries. Each dictionary must
    // contain the following keys:
    //  name - a string to describe the annotator
    //  syntax - only run if this syntax name is in sublime's syntax string
    //  command - OS command with %s for filename substitution.
    //  output_regex - decode the output from the command. In the simple case:
    //      the first regex group provides the line number
    //      the second regex group provides the annotation message
    // The output_regex can contain more than 2 groups, in which case the
    // code attempts a match by trying each pair of regex groups until the
    // first plausible match is encounted. For example, if the values of the
    // regex groups are: (a, b, c, d) then first (a, b) is tested for a
    // plausible match against (line_number, message), then (b, c) is
    // tested, and finally (c, d) is tested. Plausible means both values are
    // non-None and the first can be cast to an integer. This is clearly a
    // degenerate form of the above special case with only two values. The
    // advantage is that multiple alternative matches can be used (which
    // precludes named groups), and the order of the line number and the
    // message can be arbitrary (e.g. by including a fixed non-numeric match
    // in the first group).
    "annotators": [
            "name": "coffeelint",
            "command": "coffeelint --csv '%s'",
            "syntax": "CoffeeScript",
            "output_regex": "^(.*,(\\d+),.*,(.*))|(.*Parse error on line (\\d+):(.*))$"
            "name": "todo",
            "command": "grep '%s' -e TODO -n",
            "syntax": "",
            "output_regex": "^(\\d+):(.*)$"
            "name": "pep8",
            "command": "pep8 '%s' --max-line-length=80",
            "syntax": "Python",
            "output_regex": "^.*:(\\d+):\\d*:(.*)$"
            "name": "pyflake",
            "command": "pyflakes '%s'",
            "syntax": "Python",
            "output_regex": "^.*:(\\d+):(.*)$"
            "name": "mccabe",
            "command": "flake8 --max-complexity=8 '%s' | grep -e 'is too complex'",
            "syntax": "Python",
            "output_regex": "^.*:(\\d+):\\d*:(.*)$"
            "name": "ruby",
            "command": "ruby -wc '%s'",
            "syntax": "Ruby",
            "output_regex": "^.*:(\\d+):(.*)$"

How it works

Annotations are generated by parsing using a regular expression the output from configurable OS processes. If any process takes too long then it is killed and the corresponding annotation generation is aborted.

The annotators are run after loading, saving, and after the file has been modified. To avoid spawning processes with abandon, the running of annotators is throttled by delaying until after a configurable quiet period.

This approach makes it is easy to use the latest version of a lint or other annotator tool without creating a dependency with this plugin. It means that any tool which can be called from the command line may be used so long as it produces a regex parsable line number and description.


For now, just clone the repository under ~/.config/sublime-text-2/Packages/. When I'm ready I will perform the necessary dance to make it available under the excellent Package Control sublime plugin.

Supported platforms

Currently only tested and used on a daily basis under Linux (more specifically, Ubuntu 12.04).

How to use it

Configure your favourite linters and more general annotators by opening the configuration file from the menu: Preferences->Package Settings->Lint Free->Settings - User. See sublime-lint-free.sublime-settings for the fully documented example configuration. Switch on debug mode to check that the commands are running properly and the output is parsable.

The lint annotations are highlighted automatically and explained in the status bar.

There is only one command: to pop-up a selectable list of annotations (or displays a status message if there are none). I bind it using the following Key Bindings - User setting:

{ "keys": ["ctrl+k", "ctrl+a"], "command": "select_lint_free_annotations" }

Note that the list of annotations starts with the first one after the current cursor position, continues to the end of the file, and then starts again at the top of the file. This means that the key sequence ctrl+k, ctrl+a, Enter will select the next problem line, and the key sequence ctrl+k, ctrl+a, Up-arrow, Enter will select the previous problem line.


Please send me feedback, raise bugs or requests using the bitbucket Issue Tracker, or clone and improve (ideally with create pull requests) as per the permissive BSD 2-Clause LICENSE.