Posts
-
copilot.el 0.4
Good news, everyone – copilot.el 0.4 is out!
But that’s just the start of it. This is the most important release for me since I assumed the project’s leadership and I hope this article will manage to make you agree with my reasoning.
Enough empty words – let me now walk you through the highlights.
A Proper Copilot Client
The single biggest change in this release is the migration from the legacy
getCompletionsAPI (reverse-engineered from copilot.vim) to the standardtextDocument/inlineCompletionLSP method provided by the official @github/copilot-language-server.This might sound like a dry and boring internal change, but it’s actually a big deal. copilot.el started its life as a port of copilot.vim – we were essentially reverse-engineering how that plugin talked to the Copilot server and replicating it in Elisp. That worked, but it was fragile and meant we were always playing catch-up with undocumented protocol changes.
Now we speak the official LSP protocol. We send proper
textDocument/didOpen,textDocument/didChange, andtextDocument/didFocusnotifications. We manage workspace folders. We handle server-to-client requests likewindow/showMessageRequestandwindow/showDocument. We perform a cleanshutdown/exitsequence instead of just killing the process. In short, copilot.el is now a proper Copilot LSP client, not a reverse-engineered hack.This release, in a way, completes the cycle – from a package born out of reverse engineering copilot.vim to a legitimate Copilot client built on the official API.1
But wait, there’s (a lot) more!
AI Model Selection
You can now choose which AI model powers your completions via
M-x copilot-select-completion-model. The command queries the server for available models on your subscription and lets you pick one interactively. The selection is persisted incopilot-completion-model.Parentheses Balancer 2.0
The parentheses balancer – the component that post-processes completions in Lisp modes to fix unbalanced delimiters – got a complete rewrite. The old implementation counted parentheses as raw characters, which meant it would “balance” parens inside comments and strings where they shouldn’t be touched. The new implementation uses
parse-partial-sexpto understand the actual syntactic structure, so it only fixes genuinely unbalanced delimiters.Whether the balancer will remain necessary in the long run is an open question – as Copilot’s models get smarter, they produce fewer unbalanced completions. But for now it still catches enough edge cases to earn its keep. You can disable it with
(setopt copilot-enable-parentheses-balancer nil)if you want to see how well the raw completions work for you.Improved Server Communication
Beyond the core API migration, we’ve improved the server communication in several ways:
- Status reporting:
didChangeStatusnotifications show Copilot’s state (Normal, Warning, Error, Inactive) in the mode-line. - Progress tracking:
$/progressnotifications display progress for long-running operations like indexing. - Request cancellation: stale completion requests are cancelled with
$/cancelRequestso the server doesn’t waste cycles on abandoned work. - User-defined handlers:
copilot-on-requestandcopilot-on-notificationlet you hook into any server message. - UTF-16 positions: position offsets now correctly use UTF-16 code units, so emoji and other supplementary-plane characters no longer confuse the server.
Tests and Documentation
This release adds a proper test suite using buttercup. We went from zero tests to over 120, covering everything from URI generation and position calculation to the balancer, overlay management, and server lifecycle. CI now runs across multiple Emacs versions (27.2 through snapshot) and on macOS and Windows in addition to Linux.
The README got a (almost) complete rewrite – it now covers installation for every popular package manager, documents all commands and customization options, includes a protocol coverage table, and has a new FAQ section addressing the most common issues people run into. Plenty of good stuff in it!
This might sound like a lot of effort for not much user-visible payoff, but when I started hacking on the project:
- I really struggled to understand how to make the best use of the package
- The lack of tests made it hard to make significant changes, as every change felt quite risky
Anyways, I hope you’ll enjoy the improved documentation and you’ll have easier time setting up copilot.el.
Bug Fixes
Too many to list individually, but here are some highlights:
copilot-completenow works withoutcopilot-modeenabled (#450)- Partial accept-by-word no longer loses trailing text when the server uses a replacement range (#448)
- JSON-RPC requests send an empty object instead of omitting
params, fixing authentication on newer server versions (#445) - The
company-modedependency is gone – no morevoid-function company--active-perrors (#243) - The completion overlay plays nice with Emacs 30’s
completion-preview-mode(#377)
See the full changelog for the complete list.
What’s Next
There’s still plenty of work ahead. We have three big feature branches in the pipeline, all open as PRs and ready for adventurous testers:
- Next Edit Suggestions (NES) – proactive edit suggestions that appear at your cursor based on your recent editing patterns, similar to the NES feature in VS Code.
- Copilot Chat – interactive chat with Copilot, right inside Emacs.
- Native installation without Node.js – use the pre-built Copilot language server binary instead of requiring a Node.js installation.
If any of these sound interesting to you, please give them a spin and report back. Your feedback is what shapes the next release.
Thanks
A big thanks to Paul Nelson for contributing several partial acceptance commands and the overlay clearing improvements – those are some of the most user-visible quality-of-life changes in this release. Thanks also to everyone who filed detailed bug reports and tested fixes – you know who you are, and this release wouldn’t be the same without you.
That’s all I have for you today. Keep hacking!
-
That’s why I dropped the word “unofficial” from the package’s description. ↩
- Status reporting:
-
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-inorg-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--batchsubprocess, which eliminates false warnings for source block languages provided by external packages.
Security
We’ve mitigated CVE-2024-53920 in the
emacs-lispchecker 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+ usingtrusted-contentis in the works.1ShellCheck Improvements
The
sh-shellcheckchecker got some love in this release:- New
flycheck-shellcheck-infer-shelloption to let ShellCheck auto-detect the shell dialect flycheck-shellcheck-argsfor passing extra command-line argumentsflycheck-shellcheck-enabled-checksto enable optional checks via--enable
Quality-of-Life Improvements
A bunch of small but welcome improvements:
flycheck-command-mapnow works as a prefix command withkeymap-setand friends – no more need for thedefine-keyworkaround- Buffers are automatically re-checked after
revert-buffer, soglobal-auto-revert-modeusers get up-to-date diagnostics without manual intervention - The mode-line indicator now includes info-level errors (format:
errors|warnings|infos) - The
python-ruffchecker 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=Cfor checker processes - Fixed the
rustchecker on Windows (no more/dev/nullerrors) - Fixed
flycheck-navigation-minimum-levelbeing ignored in some cases - Fixed compilation warnings on Emacs 30
- Fixed several issues with the
python-ruff,tex-chktex,emacs-lisp, andawk-gawkcheckers
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!
-
See https://www.flycheck.org/en/latest/languages.html for the full list. ↩
-
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 likepython-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-nativelytotif you want unlimited fontification, or tonilto 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 byadoc-display-images), and you can toggle them on and off withadoc-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-imagestotif you want to fetch and display images from URLs.Navigation
A couple of welcome additions here:
adoc-follow-thing-at-point(bound toC-c C-oandM-.) 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
imenuindex is now hierarchical – headings are nested under their parent sections, which makes navigating large documents much more pleasant.
Asciidoctor Inline Macros
adoc-modenow highlights Asciidoctor-specific inline macros likekbd:[],btn:[],menu:[],pass:[],stem:[],latexmath:[], andasciimath:[]. 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-modefrom 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.elandadoc-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-modemight be a good fit. If you want the full kitchen sink – image previews, tempo templates, native code block highlighting –adoc-modeis still the way to go. Both packages are maintained by me and they complement each other nicely.Epilogue
adoc-mode0.8 is available on NonGNU ELPA, MELPA Stable, and MELPA. Upgrading is just aM-x package-installaway.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.ednwith 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_HOMEyet, but you can easily override the default global config directory (~/.nrepl) withNREPL_CONFIG_DIR.Another new feature is the ability to specify
:client-nameand:client-versionwhen creating a new nREPL session with thecloneoperator. 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-combinatorsin 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!
-
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!
Subscribe via RSS | View Older Posts