Posts

  • Flycheck 36

    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!

  • adoc-mode 0.8

    Almost 3 years after the rebirth of adoc-mode I’m happy to announce that adoc-mode 0.8 is finally out! This is a massive release that has been cooking for way too long, but I think it was worth the wait.

    Let me walk you through the highlights.

    Native Code Block Highlighting

    This was the flagship feature I teased at the end of my 0.7 announcement, and it’s easily the most impactful change in this release. Source code blocks now get fontified using the appropriate language major mode – Ruby code looks like it does in ruby-mode, Python code looks like python-mode, and so on.

    The feature is enabled out-of-the-box with a sensible default – only code blocks of 5000 characters or fewer are fontified natively, to avoid performance issues with very large blocks. You can set adoc-fontify-code-blocks-natively to t if you want unlimited fontification, or to nil to disable it entirely.

    Inline Image Preview

    You can now see images directly in your buffer instead of just staring at image::path/to/screenshot.png[]. Image previews are displayed automatically when you open a file (controlled by adoc-display-images), and you can toggle them on and off with adoc-toggle-images.

    Right-clicking on an image link gives you a context menu to generate or remove the preview for that specific image. Remote images are supported too – set adoc-display-remote-images to t if you want to fetch and display images from URLs.

    A couple of welcome additions here:

    • adoc-follow-thing-at-point (bound to C-c C-o and M-.) lets you follow URLs (opens in browser), include:: macros (opens the referenced file), and cross-references (jumps to the anchor). It’s one of those features that once you have it, you can’t imagine living without.
    • adoc-goto-ref-label (C-c C-a) jumps to an anchor by ID, with a smart default pulled from the xref at point.
    • The imenu index is now hierarchical – headings are nested under their parent sections, which makes navigating large documents much more pleasant.

    Asciidoctor Inline Macros

    adoc-mode now highlights Asciidoctor-specific inline macros like kbd:[], btn:[], menu:[], pass:[], stem:[], latexmath:[], and asciimath:[]. These were previously ignored by font-lock and would just blend in with regular text.

    I’m a heavy user of Antora, and I really appreciate this one.

    Bug Fixes Galore

    This release squashes a lot of long-standing bugs:

    • Fixed a noticeable lag when typing in code blocks (this one was particularly annoying).
    • Fixed an Emacs hang caused by escaped curly braces in attribute references.
    • Fixed multiline font-lock for inline formatting (bold, italic, etc. spanning multiple lines).
    • Prevented auto-fill-mode from breaking section title lines.
    • Prevented Flyspell from generating overlays for links and other non-prose regions.
    • Fixed table delimiter highlighting (was limited to 4 columns).
    • Fixed unconstrained monospace delimiters.
    • And quite a few more – check the release notes for the full list.

    Internal Improvements

    I’ve also spent some time cleaning up the internals:

    • The minimum Emacs version is now 28.1 (up from 26).
    • Deprecated AsciiDoc backtick-apostrophe quote styles (not supported by Asciidoctor) have been removed.
    • Two-line (Setext) titles are now disabled by default, since Asciidoctor has deprecated them.
    • Image display and tempo templates have been extracted into separate files (adoc-mode-image.el and adoc-mode-tempo.el), making the main file more manageable.

    The codebase is in much better shape than it was 3 years ago, but there’s still some room for improvement.

    One More Thing: asciidoc-mode

    I did eventually act on that idea I mentioned in my 0.7 post – I created asciidoc-mode, a tree-sitter-based AsciiDoc major mode for Emacs 30.1+. It’s a very different beast from adoc-mode – focused on the essentials (highlighting, navigation, folding) and leveraging tree-sitter for accurate and performant parsing.

    If you’re on Emacs 30+ and prefer a lighter-weight editing experience, asciidoc-mode might be a good fit. If you want the full kitchen sink – image previews, tempo templates, native code block highlighting – adoc-mode is still the way to go. Both packages are maintained by me and they complement each other nicely.

    Epilogue

    adoc-mode 0.8 is available on NonGNU ELPA, MELPA Stable, and MELPA. Upgrading is just a M-x package-install away.

    I’d like to thank everyone who contributed bug reports, pull requests, and feedback over the past 3 years. Open-source is a team sport and this release wouldn’t have happened without you. You rock!

    That’s all I have for you today. Keep hacking! And keep writing… in AsciiDoc, of course!

  • nREPL 1.4

    nREPL 1.4.0 is out! This month we celebrate 15 years since nREPL’s development started, so you can consider this release part of the upcoming birthday celebrations.

    So, what’s new?

    Probably the highlight is the ability to pre-configure default values for dynamic variables in all nREPL servers that are launched locally (either per project or system-wide). The most useful application for this would be to enable *warn-on-reflection* in all REPLs. To achieve this, create ~/.nrepl/nrepl.edn with this content:

    {:dynamic-vars {clojure.core/*warn-on-reflection* true}}
    

    Now, any nREPL server started from any IDE will have *warn-on-reflection* enabled.

    $ clojure -Sdeps "{:deps {nrepl/nrepl {:mvn/version \"1.4.0\"}}}" -m nrepl.cmdline -i
    user=> #(.a %)
    Reflection warning, NO_SOURCE_PATH:1:2 - reference to field a can't be resolved.
    

    Note: nREPL doesn’t support directly XDG_CONFIG_HOME yet, but you can easily override the default global config directory (~/.nrepl) with NREPL_CONFIG_DIR.

    Another new feature is the ability to specify :client-name and :client-version when creating a new nREPL session with the clone operator. This allows collecting information about the clients used, which some organizations might find useful. (I know Nubank are making use of this already)

    One notable change in nREPL 1.4 is the removal of support for Clojure 1.7. Clojure 1.7 was released way back in 2015 and I doubt anyone is using it these days, but we try to be extra conservative with the supported Clojure versions and this is only the second time nREPL’s runtime requirements were bumped in the 7 and a half years I’ve been the maintainer of the project. (early on I bumped the required Clojure from 1.2 to 1.7)

    As usual the release features also small bug-fixes and internal improvements. One such improvement was the introduction of matcher-combinators in our test suite. (which was the main motivation to bid farewell to Clojure 1.7) You can check out the release note for a complete list of changes.

    That’s all I have for you today. I hope we’ll have more exciting nREPL news to share by nREPL’s “official” birthday, October 8th.1 Big thanks to everyone who has contributed to this release and to all the people supporting my Clojure OSS work! In the REPL we trust! Keep hacking!

    1. nREPL 0.1 was released on Oct 11, 2015. 

  • Weird Ruby: Anonymous Heredocs

    Heredocs in Ruby are quite common, quite flexible, and… somewhat weird. Still, this doesn’t stop people from suggesting more features for them, like this (rejected) proposal for an anonymous heredocs syntax:

    # regular Ruby code
    Markdown.render <<~MARKDOWN
      # Hello there
    
      This is a Markdown file. See?
    
      1. This is a list
      2. With items
      3. And more items
    MARKDOWN
    
    # proposed syntax
    Markdown.render <<~
      # Hello there
    
      This is a Markdown file. See?
    
      1. This is a list
      2. With items
      3. And more items
    ~>>
    

    Even though this proposal didn’t make it, you can get pretty close by just using _ as your heredoc delimiter:

    Markdown.render <<~_
      # Hello there
    
      This is a Markdown file. See?
    
      1. This is a list
      2. With items
      3. And more items
    _
    

    Looks a bit weird, but it gets the job done.

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

  • CIDER 1.18 ("Athens")

    Great news, everyone - CIDER 1.18 (“Athens”) is out!

    This is a huge release that has an equal amount of new features, improvements to the existing ones, and also trimming down some capabilities in the name of improved efficiency and maintainability.

    I’m too lazy to write a long release announcement today, so I’ll just highlight the most important aspects of CIDER 1.18 and how they fit our broader vision for the future of CIDER.

    Let’s go!

    Reduced surface area

    • CIDER 1.18 dropped support for Boot and Emacs 26. Boot development has been frozen for many years, and it’s now a long past due to migrate to other build tools.
    • CIDER no longer bundles Puget dependency. Puget is still supported as a pretty-printer for all CIDER output, but you need to add it to dependencies explicitly.
    • Haystack is no longer included. With it, we removed some largely unknown facilities for parsing printed stacktraces and presenting them inside *cider-error* buffer.
    • Replaced the outdated thunknyc/profile dependency with a homegrown implementation in Orchard.

    I’m happy that we continue on the path of reducing the 3rd-party dependencies in cider-nrepl and rely more and more on functionality optimized for our use-cases, living in Orchard. Looking back, at some of the decisions I’ve taken in the past - I sometimes regret going overboard with the feature set (we have so many features today, that even I occasionally forget about some of them) and the dependencies needed to provide certain features. Going forward I hope to gradually reduce the feature set and the dependencies by:

    • removing features that are rarely used
    • making certain dependencies optional (instead of bundling everything with cider-nrepl)

    Inspector

    Our beloved inspector got a lot better!

    • New analytics module (orchard#329) (shows you some useful info about the data you’re inspecting)
    • Table view mode (orchard#331) (I think you’ll totally love this!)
    • Pretty-printing mode (#3813) and a command to separately pretty-print the currently inspected value (#3810)

    That’s how the analytics and the table view look:

    inspector-analytics

    table-view-mode

    Cool stuff!

    Error handling

    • In exchange for removing Haystack, CIDER now allows jumping to munged Clojure functions and Java methods anywhere from the source buffers or the REPL. This means that you can press M-. on printed frames like clojure.core$with_bindings_STAR_.doInvoke or clojure.lang.Compiler$InvokeExpr.eval within the exception, and CIDER will take you there.
    • Stacktrace processing has been greatly simplified and optimized. You may notice that the delay between an exception occuring and *cider-error* buffer popping up disappeared, especially in big projects.
    • Ex-data is now always displayed for each exception cause which has it, albeit in an abbreviated form. You can click or press RET (a.k.a. Enter) on to open it in the inspector (#3807).

    I’m guessing some of those changes might be considered slightly controversial (especially the last item), but I think they are a bit step towards simplicity and more internal consistency.

    Misc features

    • Completions got better with priority-based sorting and fuzzy-matching enabled by default (so you can complete unimported short classnames, and things like cji, rkv, etc.)
    • The middleware that powers dynamic font-locking was made tremendously faster and more memory efficient on both Clojure and Emacs sides of CIDER. Again, this effect would be more pronounced in large codebases. This optimization is well overdue, and perhaps it will encourage more editors to embrace the track-state middleware, as I think it’s one of the coolest aspects of CIDER.
    • Added support for dynamic indentation in clojure-ts-mode (#3803)

    Side note - I’ve been spending a lot of time on clojure-ts-mode lately and it’s shaping up pretty nicely. If you’re happy with clojure-mode there’s no real reason to switch yet, but if you’ve experienced performance issues with font-locking on indentation you may want to check out clojure-ts-mode.

    I’m happy to report that I’ve also finally started to clean up the numerous compilation warnings introduced in Emacs 29. Most of the meaningful problems are now addressed and the bulk of the remaining work is related to a new rule for quoting ' in docstrings, which is annoying but not particularly important.

    Epilogue

    This release is named “Athens” for a reason - Athens is one of the greatest cities in the world1 and I think that’s one of the greatest CIDER releases!

    For me that’s one of the most important CIDER releases in the past couple of years, if not the most important. We’ve tackled a lot of long-standing problems and we’ve started to simplify the internals of CIDER. The feedback we got from the “State of CIDER” survey really helped us with some of the decisions - stay tuned for a detailed analysis of all the feedback we’ve collected there.

    As usual - a huge shoutout to all the contributors and “Clojurists Together” for their support! A special thanks to Sashko Yakushev, who has been firing on all cylinders lately, and was once again the driving force behind most of the work in this release. You’re a legend, buddy!

    Sadly, the amount of financial support CIDER is receiving has dropped a lot in the past 3 years (by about 50%). I hope the situation will change, as solid and predictable financial backing is the only way to ensure the long-term future of CIDER and friends.

    This is all I have for you today. I hope you’ll have as much fun using it, as we had developing it! Keep hacking!

    1. And one of my favorite cities. I’ve got a lot of fond memories of working on CIDER there. 

Subscribe via RSS | View Older Posts