Monthly Archives: January 2025

Automatically regenerating Neovim spell files

In Neovim, when you add a new word to your spellchecking dictionary with the command “zg”, the word will be added to a “.add” file in your config directory in the subdirectory “spell”. For example, “spell/en.utf-8.add”, depending on your locale. That’s a textual file you might want to share among different machines, e.g., part of the Git repository hosting your Neovim configuration. However, the used file is “.add.spl”, e.g., “spell/en.utf-8.add.spl”. That’s a binary file you don’t want to store in the Git repository, so you typically add it to “.gitignore”.

The “.spl” file is automatically updated (through the Neovim command “mkspell”) when you add a word with “zg”. But what if you modify the “.add” file from outside Neovim? For example, when you pull the Git repository of the Neovim configuration changes on another machine. You’d have to remember to run the “mkspell” inside Neovime (more details can be found here https://neovim.io/doc/user/spell.html).

Let’s instead make everything automatic by adding an “autocmd”, e.g., in LazyVim, by adding this to the “lua/config/autocmds.lua” file:

And that’s all!

If the “.add” file is changed from outside Neovim, the corresponding “.spl” file will be automatically regenerated.

Hope you find this post useful! 🙂

Ansible tasks for installing Firefox and Thunderbird as DEB packages in Ubuntu

Ubuntu has forced the installation of Firefox and Thunderbird as snap packages for some time. I don’t like snap packages since they’re a bit slower to start, take much more space on the disk, and store the profile files into the “.snap” directory folder, while I want them in the standard place in my home folder. The procedure to revert to the traditional deb installation (through the Mozilla PPA) is well documented but takes several steps, especially to avoid the unintended update to the snap version during the Ubuntu update process.

In this blog post, I’ll document my Ansible tasks to make the whole procedure automatic. This is part of my Ansible playbook for Ubuntu.

These are the main tasks:

The check for snap being installed is required when the playbook is tested with Molecule using a Docker container (the Docker image of Ubuntu does not have snap and the corresponding installed packages).

Then, we remove the snap packages (if “snap” is installed, as said above). Note the use of the “ansible.builtin.snap” module.

I prefer to store the public keys for PPA as part of the Ansible playbook so that I don’t depend on the PGP servers, which tend to be slow and make the Molecule tests flaky. To download the public key locally, I use the link under “Signing key” on the PPA web page:

I add the key and the repository with the corresponding Ansible modules “apt_key” and “apt_repository”.

Note that I then perform a check for the existence of the preference file for the Ubuntu update process, “/etc/apt/preferences.d/mozillateamppa”. I’ll create the file later. If the file does not exist, I assume that this is the first time these Ansible tasks are executed. In that case, I’ll also remove the transitional deb packages for Firefox and Thunderbird, which Ubuntu has in its main repository, which would then force the installation of the corresponding snap packages. Removing such transitional deb packages is crucial, or the real deb packages we want from the Mozilla PPA will not be installed.

Such a preference file is then copied into the final position by using the template file of the playbook, stored in “tasks/files/mozilla/mozillateamppa.txt”:

Then, we install the deb packages from the Mozilla PPA (note the “update_cache: true”: we added a new PPA, so we must update the apt cache).

Finally, we copy another file to ensure that the versions installed from the Mozilla PPA will take precedence during Ubuntu unattended-upgrades. The template file stored in the playbook “tasks/files/mozilla/51unattended-upgrades-mozilla.txt” is:

That’s all!

Hope you find this post useful 🙂

Neovim and Java with LazyVim, part 3: Dependencies and Maven

This is the third part of a few tutorials on Java development with Neovim using the LazyVim setup.

This post assumes you already read and applied all the steps of the first part and the second part.

You need Java installed (possibly 21), while Maven is optional.

I will use this Maven example during the tutorial: https://github.com/LorenzoBettini/maven-bank-example, which is part of my TDD book.

The final result of this series of tutorials can be found here: https://github.com/LorenzoBettini/lazyvim-java. The “main” branch always points to the latest blog post.

The end of this part is still the branch “third-blog-post”.

In the first part, we saw how to enable Java LSP in the LazyVim distribution. We also saw a few interesting features for programming in Java in Neovim with such a configuration. In the second part, we saw a few of the IDE mechanisms we get from the Java LSP in LazyVim.

Let’s continue where we left off (remember, I’ll use the above-mentioned Maven project) and see how to deal with Maven dependencies.

Adding support for the pom.xml

By default, opening the pom.xml file gives only syntax highlighting but no LSP support:

We can install the XML LSP, “lemminx”, using Mason, e.g., by modifying the “extend-lsp.lua” file we saw above:

Restart Neovim and open the “pom.xml” file again. Wait some time for Mason to install the LSP, and the first thing you might notice is the status line showing the structure of the current XML element:

The XML LSP is schema-aware so that it can provide hovering support (“K”):

It also provides the symbol mechanisms shown above. It provides auto-closing of tags and rename refactoring. Moreover, it can validate what you write according to the schema (in this case, it checks that it is a valid Maven XML).

It also implements a “code action” for quick-fixing it:

Some other notes

If you add a dependency to the POM or change one of the existing dependencies version, you must run “:JdtUpdateConfig” so the Java LSP can download the new dependencies.

In general, when something is not working, “:JdtRestart” might fix things.

In case of misalignments of the workspace, e.g., if you wipe the local Maven cache (“~/.m2/repository”) when restarting an already opened project, you get errors due to unresolved dependencies:

In such a case, you can run “:JdtWipeDataAndRestart”, which wipes the Eclipse workspace (not your project) and restart the LSP, which will resolve the Maven dependencies from scratch.

That’s all for this part!

Note that for the moment, we cannot start/debug a Java program from Neovim. We’ll cover that in the next part.

We still have to cover:

  • how to run/debug Java programs (with the current configuration, this is not yet possible);
  • how to run tests
  • maybe other features

Ansible and Molecule with Fedora 41

When using Ansible and Molecule with Fedora 41, a few things must be adjusted so that Molecule can access the Docker image for Fedora 41.

This is probably due to some changes in the Python package and the new Dnf 5 package; if you use a default Docker Fedora 41 image, you get errors of the shape during the Molecule run:

To solve the problem, you must ensure that the packages “python3” and “python3-libdnf5” are installed in the Docker container used by Molecule during testing.

You can achieve that either by providing a custom Dockerfile for Molecule:

and this is an example of a Dockerfile:

Alternatively, you can specify the pre-built Docker Fedora 41 in the Molecule file:

And provide a “prepare.yml” file to install the above-mentioned required packages:

Note that we must use the built-in “raw” module and avoid gathering facts. Otherwise, we would get back to the original error message.

I hope you find this post helpful.

macOS 12: bye bye homebrew

If you use the Homebrew package manager in macOS and you have macOS 12 because your Mac is too old to update to a new version of macOS, you can say goodbye to Homebrew: if you try to update your brew packages, you get such a message:

If you continue with the update or install a new package, you’ll have to wait a while; packages will be compiled from the source!

For example, on my old MacBookAir 2016, I only had a few homebrew packages to upgrade:

After 3 hours (!) I gave up! Things like “zoxide” or “neovim” depend on “llvm”, which, after 30 minutes, wasn’t yet compiled completely! The other dependencies of “zoxide” still take a lot to compile; for example (look at “z3”):

Unless you’re willing to wait for several hours (I am not), I guess it’s time to say goodbye to Homebrew. As for me, it also means saying goodbye to macOS on this old MacBookAir (but still a capable computer) and trying to install Linux 🙂

You might want to look at the Homebrew issue https://github.com/orgs/Homebrew/discussions/5603.