It’s been a while since Flycheck 35, but Flycheck 36 is finally here! This is a pretty big release with a lot of new features, bug fixes, and some much-needed cleanup of legacy checkers.

In fact, I’d say it’s the biggest and most important Flycheck release since I became the project’s primary maintainer a couple of years ago. For a while I had mostly gone with the flow (adding/improving linters and fixing bugs), but by now I feel more confident to make bigger and bolder changes.

Anyways, you’re probably interested to learn more about Flycheck 36, so let me walk you through the highlights.

New Checkers

We’ve added a couple of new checkers:

  • javascript-oxlint – a checker using oxlint, the blazing-fast JavaScript/TypeScript linter written in Rust. If you haven’t tried oxlint yet, you really should – it’s impressively fast.
  • org-lint – an Org mode checker using Emacs’ built-in org-lint. It detects issues like invalid links, dead links, and duplicate IDs. This one went through a rewrite mid-cycle to run in the current Emacs process instead of a --batch subprocess, which eliminates false warnings for source block languages provided by external packages.

Security

We’ve mitigated CVE-2024-53920 in the emacs-lisp checker by disabling local eval directives and restricting local variables to safe values during byte-compilation. This was an important fix – byte-compilation involves macro expansion, which means untrusted Elisp files could potentially execute arbitrary code during syntax checking. A follow-up fix for Emacs 30+ using trusted-content is in the works.1

ShellCheck Improvements

The sh-shellcheck checker got some love in this release:

  • New flycheck-shellcheck-infer-shell option to let ShellCheck auto-detect the shell dialect
  • flycheck-shellcheck-args for passing extra command-line arguments
  • flycheck-shellcheck-enabled-checks to enable optional checks via --enable

Quality-of-Life Improvements

A bunch of small but welcome improvements:

  • flycheck-command-map now works as a prefix command with keymap-set and friends – no more need for the define-key workaround
  • Buffers are automatically re-checked after revert-buffer, so global-auto-revert-mode users get up-to-date diagnostics without manual intervention
  • The mode-line indicator now includes info-level errors (format: errors|warnings|infos)
  • The python-ruff checker got an error explainer, so you can quickly look up what a rule means
  • Pyright rule names (like reportGeneralTypeIssues) now show up as error IDs

Bug Fixes

This release includes a massive number of bug fixes – over 25 of them. Some highlights:

  • Fixed error pattern matching in non-English locales by forcing LC_ALL=C for checker processes
  • Fixed the rust checker on Windows (no more /dev/null errors)
  • Fixed flycheck-navigation-minimum-level being ignored in some cases
  • Fixed compilation warnings on Emacs 30
  • Fixed several issues with the python-ruff, tex-chktex, emacs-lisp, and awk-gawk checkers

Check the release notes for the full list.

Spring Cleaning

We’ve removed a number of checkers for tools that have been dead or deprecated for years:

  • typescript-tslint (deprecated since 2019, use ESLint with typescript-eslint)
  • sass, scss, sass/scss-sass-lint, scss-lint (Ruby Sass is dead, use Stylelint)
  • eruby-erubis, eruby-ruumba (Erubis abandoned since 2011)
  • css-csslint (abandoned since ~2017, use Stylelint)
  • coffee-coffeelint, protobuf-prototool, nix-linter

If you’re still using any of these tools… well, it’s probably time to upgrade!

Documentation Site

flycheck.org got a visual refresh – we’ve switched from the old Alabaster Sphinx theme to Furo, which gives the site a clean, modern look with proper dark mode support and better mobile responsiveness. We’ve also added prominent GitHub links at the top of every page, making it easier to jump to the source or file issues.

I hate the old theme, so this one is a major win in my book! I’ve also took some effort to make sure the documentation accurately reflects the current state of project, as here and there things were out-of-sync.

Flycheck is Alive and Well

I know that many people wrote Flycheck off when Flymake got tight integration with Eglot (they share a maintainer, after all), and I understand why – it’s hard to compete with something that’s built into Emacs and “just works” out of the box. But Flycheck continues to advance and evolve. We have excellent Eglot support via flycheck-eglot, a massive library of built-in checkers,2 and a feature set that Flymake still can’t match in many areas.

More importantly, Flycheck’s biggest strength has always been that it’s community-driven and easy to contribute to. Adding a new checker is straightforward, PRs get reviewed quickly, and you don’t have to go through the FSF copyright assignment process. That matters, and it’s why the project keeps growing.

Epilogue

I’m pretty happy with this release. The combination of new features, security hardening, and cleanup of dead checkers puts Flycheck in a much healthier state. Looking ahead to Flycheck 37, I’m thinking about tree-sitter integration, more new checkers (OCaml and Swift are already in the pipeline), and potentially dropping support for Emacs 27 so we can take advantage of newer APIs. The plan is still hazy, but it’s starting to take some shape…

As always, contributions are very welcome! If there’s a lint tool you use that Flycheck doesn’t support yet, PRs are the fastest way to make it happen. As mentioned above, Flycheck’s biggest strength remains its community, and are the community.

That’s all I have for you today. Keep hacking!